How to add a custom class attribute to a subclass of nn.Module?

I’ve created a module that is a subclass of nn.Module and I cannot add a single attribute to it that is not in the superclass.

class net(nn.Module):
    def __init__(self, input_nc, output_nc, ngf, norm_type = 'batch', act_type='selu', use_dropout=False, n_blocks=6, padding_type='reflect', gpu_ids=[]):
        assert(n_blocks >= 0)
        super(net, self).__init__()

        self.name = 'net'
        self.input_nc = input_nc
        self.output_nc = output_nc
        self.ngf = ngf
        self.gpulist = gpu_ids
        self.num_gpus = len(self.gpulist)

        self.initialization_counter = 0 # I want to add this attribute

But when I call net.initialization_counter in my script it throws an error:

AttributeError: 'net' object has no attribute 'initialization_counter'

How can I register this attribute to be accessible?

It’s working for me:

model = net(1, 1, 1)
print(model.initialization_counter)
# 0

It seems that I cannot call any additional functions or attributes. Would packaging (init.py) have anything to do with this? Seems weird that I cannot access any function or attribute besides the ones from superclass.

I don’t know which __init__.py you mean and since I cannot reproduce the issue, could you post a minimal, executable code which would raise the error?

Thanks for the response.

What I am ultimately trying to do is to have different weight initialization every time I create a model. That is why I tried to add the attribute. Since I cannot, I tried creating a global variable. However, I cannot import this variable in the main script and increment it.

For that I have weights_init() in my model script my_model.py

def weights_init(m, act_type='relu'):
    global initialization_counter

    classname = m.__class__.__name__

    # 0: normal_
    # 1: xavier_uniform_
    
    if initialization_counter == 0:
        print("Initializing weights using normal distribution.")
        if classname.find('Conv') != -1:
            if act_type == 'selu':
                n = float(m.in_channels * m.kernel_size[0] * m.kernel_size[1])
                m.weight.data.normal_(0.0, 1.0 / math.sqrt(n))
            else:
                m.weight.data.normal_(0.0, 0.02)        
            if hasattr(m.bias, 'data'):
                m.bias.data.fill_(0)
        elif classname.find('BatchNorm2d') != -1:
            m.weight.data.normal_(1.0, 0.02)
            m.bias.data.fill_(0)
    
    if initialization_counter == 1:
        print("Initializing weights using xavier uniform distribution.")
        if classname.find('Conv') != -1:
            init.xavier_uniform_(m.weight, gain=nn.init.calculate_gain('relu'))
            if hasattr(m.bias, 'data'):
                m.bias.data.fill_(0)
        elif classname.find('BatchNorm2d') != -1:
            m.weight.data.normal_(1.0, 0.02)
            m.bias.data.fill_(0)

Executing this script by itself is working (I mean in the main method of this script).

However, in the learn.py I cannot import this global variable. Getting this error:

from models.my_model import net, weights_init, initialization_counter
ImportError: cannot import name 'initialization_counter' from 'models.my_model'

my file structure is:

my_folder
     - learning
          - learn.py
     - models
          - __init__.py
          - my_model.py

On the other hand, when I had self.initialization_counter called as print(model.initialization_counter) I would get the no attribute error.

Based on your initial description this was the original issue while you are now trying to include global variables from other scripts if I understand your last description correctly.
Why don’t you use the model attribute as it seems to work?

Because I get the attribute error that I do not know why I get.

I create an instance of a model and then call model.initialization_counter. I do not know why it throws the no attribute error.

Then I tried introducing the global variable from the same script (my_model.py), and I get “cannot import name” error…

I am very confused…

@ptrblck I did not update my #PYTHONPATH variable, when I made a copy of the project and it was still pointing to the old directory…

I am sorry about the confusion. It works now as expected.