Hello,
I am doing a homemade project in order to better learn the details of PyTorch and be able to write my own networks, training routine, …
As part of this project, I am creating a replica of LeNet-5 neural network.
The code for custom-made layer looks like this :
from collections import Sequence
import torch.nn as nn
import torch.nn.functional as F
import numpy as np

class conv2DAveragePool(nn.Module):
    def __init__(self, in_channels, out_channels, kernel_size, stride, padding,
                 activation=nn.Tanh()):
        super().__init__()

        def parse_2Length_Sequence(x):
            if isinstance(x, (Sequence, np.ndarray)):
                if len(x)==2:
                    item1 = x[0]
                    item2 = x[1]
                else:
                    raise ValueError('activation parameter has an unexpected'
                                    ' sequence length of ' + 
                                    len(x) + ' while one expects'
                                    'either a str or a 2-length sequence') #TODO is this correct way to catch such mistakes i.e. the if and the raise ? and the type of raise ?
                                                                            #TODO is this the correct kind of error message to send to the user ?
            else:
                item1 = item2 = x

            return item1, item2
        
        # Parameters
        self.in_channels = in_channels
        self.kernel_size = list(parse_2Length_Sequence(kernel_size)) #TODO if I have to check all arguments ... It this usually the case?? good practice ??
        self.out_channels = out_channels
        self.kernel_size = list(parse_2Length_Sequence(kernel_size))
        self.stride = list(parse_2Length_Sequence(stride))
        self.padding = list(parse_2Length_Sequence(padding))
        self.activation = list(parse_2Length_Sequence(activation))

        self.layers = nn.Sequential(
            nn.Conv2d(self.in_channels, self.out_channels, 
                      self.kernel_size[0], self.stride[0], 
                      self.padding[0], bias=True), 
            self.activation[0],
            nn.AvgPool2d(self.kernel_size[1], 
                          self.stride[1], self.padding[1]),
            self.activation[1]
                                         )
    
    def forward(self, x):
        return self.layers(x)

while the code for the LeNet-5 network looks like this :
class LeNet5(nn.Module):
    def __init__(self, in_channels=1):
        super().__init__()
        self.in_channels = in_channels

        self.layers = OrderedDict([('convLayers',nn.Sequential(
                                                layers.conv2DAveragePool(self.in_channels,6, 
                                                                        [5,2], [1,2], 0),
                                                layers.conv2DAveragePool(6, 16, 
                                                                        [5, 2], [1, 2], 0),
                                                nn.Conv2d(16, 120, 5,  1, 0),
                                                nn.Tanh()
                                                                )
                                    ) ,
                                    ('fcLayers',nn.Sequential(
                                                nn.Linear(120, 84),
                                                nn.Tanh(),
                                                nn.Linear(84,10),
                                                nn.Softmax(dim=0)
                                                            )
                                    )
                                    ])

    def forward(self, x):
        out = self.layers['convLayers'](x)
        out = out.view(-1, out.shape[1]*out.shape[2]*out.shape[3])
        out = self.layers['fcLayers'](out)
        return out

The network works as expected regarding forward function. However, I am now trying to build the training step. And in the training step, most tutorial from PyTorch I see uses the .parameters() method of nn.module class to get the optimizer parameters so for me I would for example use :
optimizer = optim.SGD(arch.parameters(), lr=0.001, momentum=0.9)
where arch is an instance of my homemade LeNet5 class. However, calling the list(arch.parameters()) returns an empty list [].
So somehow, I assume I miss a step in the definition of my network and I could not find this specifically discuss in the tutorials. Any help would be appreciated