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

shrbrh: <p>I have a class ‘Feature_Extractor’ where I use the pre-trained VGG model for feature extraction. Below is a snippet of my code:</p>
<pre><code class="lang-auto">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
</code></pre>
<p>I have another class ‘Generate’ that calls the encode method of the ‘Feature_Extractor’ class in the following manner:</p>
<pre><code class="lang-auto">Encoded_features = Feature_Extractor.encode(self, image)
</code></pre>
<p>But for some reason my code keeps looking for the encode method in the Generate class and is throwing the error:<br>
AttributeError: ‘Generate’ object has no attribute ‘layer_1’</p>
<p>What am I doing wrong?</p>

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

shrbrh: <p>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:</p>
<pre><code class="lang-auto">vgg = model.vgg
vgg.load_state_dict(torch.load(args.vgg))
vgg = nn.Sequential(*list(vgg.children())[:31])
P = Feature_Extractor(vgg)
</code></pre>
<p>Here is my class definition in model.py:</p>
<pre><code class="lang-auto">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])  
</code></pre>
<p>I made encode a class method because getattr() requires an instance of the class.<br>
But when calling the encode method from ‘Generate’ class I don’t want to create an instance because then I get the error:<br>
TypeError: <strong>init</strong>() missing 1 required positional argument: ‘feature_extractor’<br>
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.<br>
Is it possible to create an instance without having to load the VGG model everytime?</p>

ptrblck: <aside class="quote no-group" data-username="shrbrh" data-post="3" data-topic="168596">
<div class="title">
<div class="quote-controls"></div>
<img loading="lazy" alt="" width="24" height="24" src="https://discuss.pytorch.org/letter_avatar_proxy/v4/letter/s/b5e925/48.png" class="avatar"> shrbrh:</div>
<blockquote>
<p>I made encode a class method because getattr() requires an instance of the class.<br>
But when calling the encode method from ‘Generate’ class I don’t want to create an instance because then I get the error:<br>
TypeError: <strong>init</strong>() missing 1 required positional argument: ‘feature_extractor’<br>
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.</p>
</blockquote>
</aside>
<p>I don’t understand this workflow. <code>def encode</code> 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 <code>__init__</code> method (I assume so).</p>

shrbrh: <p>Sorry for the confusion. The correct flow is:</p>
<pre><code class="lang-auto">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)
</code></pre>
<p>I understand that I need to create an instance of the Feature_Extractor class in order to access the method <code>encode</code> as it is a class method. But since the class takes a parameter <code>feature_extractor</code> , so creating an instance like <code>fe = Feature_Extractor()</code> throws an error:<br>
TypeError: <strong>init</strong>() missing 1 required positional argument: ‘feature_extractor’<br>
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?<br>
Because I am assuming I have to initialize something like this:<br>
<code>fe = Feature_Extractor(vgg)</code></p>

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