AttributeError: 'Generate' object has no attribute 'layer_1'

I have a class ‘Feature_Extractor’ where I use the pre-trained VGG model for feature extraction. Below is a snippet of my code:

vgg = nn.Sequential(*list(vgg.children())[:31])
feature_extractor  = list(vgg.children())
 self.layer_1 = nn.Sequential(*feature_extractor[:4])  
 self.layer_2 = nn.Sequential(*feature_extractor[4:11])  
 self.layer_3 = nn.Sequential(*feature_extractor[11:18])  
 self.layer_4 = nn.Sequential(*feature_extractor[18:31])  
 # fix the encoder 
 for name in ['layer_1', 'layer_2', 'layer_3', 'layer_4']:
     for param in getattr(self, name).parameters():
         param.requires_grad = False
#method to extract features
def encode(self, input):
        for i in range(4):
            input = getattr(self, 'layer_{:d}'.format(i + 1))(input)
        return input

I have another class ‘Generate’ that calls the encode method of the ‘Feature_Extractor’ class in the following manner:

Encoded_features = Feature_Extractor.encode(self, image)

But for some reason my code keeps looking for the encode method in the Generate class and is throwing the error:
AttributeError: ‘Generate’ object has no attribute ‘layer_1’

What am I doing wrong?

I’m a bit confused about the function definition of encode as it seems to be a class method (die to the usage of the self attribute) while it seems you are trying to use it as a static method. Could you describe how self is defined in your global scope?

I have a train.py file where I pass the VGG-model to my Feature_Extractor class which is defined in another python file model.py:

vgg = model.vgg
vgg.load_state_dict(torch.load(args.vgg))
vgg = nn.Sequential(*list(vgg.children())[:31])
P = Feature_Extractor(vgg)

Here is my class definition in model.py:

class Feature_Extractor(nn.Module):
    def __init__(self, feature_extractor):
        super(Feature_Extractor, self).__init__()
        feature_extractor  = list(feature_extractor.children())
        self.layer_1 = nn.Sequential(*feature_extractor[:4])  
        self.layer_2 = nn.Sequential(*feature_extractor[4:11])  
        self.layer_3 = nn.Sequential(*feature_extractor[11:18])  
        self.layer_4 = nn.Sequential(*feature_extractor[18:31])  

I made encode a class method because getattr() requires an instance of the class.
But when calling the encode method from ‘Generate’ class I don’t want to create an instance because then I get the error:
TypeError: init() missing 1 required positional argument: ‘feature_extractor’
And I can’t load the VGG model everytime I create an instance of the ‘Feature_Extractor’ class. So I tried to access the method directly.
Is it possible to create an instance without having to load the VGG model everytime?

I don’t understand this workflow. def encode is now in the global scope unless your formatting in the first post is wrong. If it’s indeed defined as a class method, you would need to create the object first before being able to call this method. This makes sense, because you are trying to access internal attributes of the object which are create in the __init__ method (I assume so).

Sorry for the confusion. The correct flow is:

class Feature_Extractor(nn.Module):
    def __init__(self, feature_extractor):
        super(Feature_Extractor, self).__init__()
        feature_extractor  = list(feature_extractor.children())
        self.layer_1 = nn.Sequential(*feature_extractor[:4])  
        self.layer_2 = nn.Sequential(*feature_extractor[4:11])  
        self.layer_3 = nn.Sequential(*feature_extractor[11:18])  
        self.layer_4 = nn.Sequential(*feature_extractor[18:31])
       # fix the encoder 
       for name in ['layer_1', 'layer_2', 'layer_3', 'layer_4']:
            for param in getattr(self, name).parameters():
                 param.requires_grad = False
    def encode(self, input):
        for i in range(4):
            input = getattr(self, 'layer_{:d}'.format(i + 1))(input)
        return input

class Generate(nn.Module):
    .....
    .....
    Encoded_features = Feature_Extractor.encode(self, image)

I understand that I need to create an instance of the Feature_Extractor class in order to access the method encode as it is a class method. But since the class takes a parameter feature_extractor , so creating an instance like fe = Feature_Extractor() throws an error:
TypeError: init() missing 1 required positional argument: ‘feature_extractor’
So do I have to import the VGG model from the file train.py and load its weights everytime I create an instance of Feature_Extractor?
Because I am assuming I have to initialize something like this:
fe = Feature_Extractor(vgg)

Yes, you need to initialize the Feature_Extractor with the needed input argument, since the internal self.layer_X modules are created based on feature_extractor. In encode these self.layer_X modules are then used to create the output so indeed the initialization of self.layer_X via feature_extractor is needed.