As noted above, you can create an nn.Sequential from an OrderedDict with keys as module names (conv0, conv1, …, conv14) and nn.Conv layers as the values.
However, if you want to make a more complicated forward pass with conditions on how to dispatch to the various convolutional layers, or make residual connections, etc. then your module must define that behavior.
You could mix the approaches where you construct the various layers from a collection, and then still refer to them by their name in the forward method:
class AGoodModule(nn.Module):
    def __init__(self):
        super(AGoodModule, self).__init__()

        self.main = nn.Sequential()

        layers = [
            ("conv{}".format(n), nn.Conv2d(4, 4, (3, 3), 1, 1)) for n in range(3)
        ]

        [self.main.add_module(n, l) for n, l in layers]
    
    def forward(self, x):
        x0 = self.conv0(x)
        x1 = self.conv1(x0) + x0
        x2 = self.conv2(x1) + x1
        return x2