Why doesnt Pytorch provide properties for Class names?

Shisho_Sama: <p>Hi everyone.<br>
I come from a C++/C# background and this has made me thinking for sometime now! Here is my question :<br>
Since <code>Pytorch</code> has a dynamic nature, there will be many situations in which you’d be dealing with different classes on the fly and checking for which classes you are dealing with.</p>
<p>Currently one way to access the class names is through <code>__class__</code> and <code>__class__.__name__</code> (class attributes) .</p>
<p>My question is, knowing that names with __, mean they are supposed to be <strong>private</strong> and not be accessed by the developer, Why doesn’t <code>Pytorch</code> provide a simple property to access them?</p>
<p>Simple things such as :</p>
<pre><code class="lang-auto">for m in model.modules():
    if (m.__class__.__name__ == torch.nn.Linear.__class__.__name__):
         ...
</code></pre>
<p>become very long and ugly needlessly! let alone more complex ones.</p>
<p>I could ask this about the Python langauge, but thought maybe, due to compatibility reasons, they can not do that there, but nothing stops a library to provide its own set of utility methods, properties.<br>
So What is stopping you from providing such things that would make life easier and codes much more readable.</p>
<p>Thanks in advance</p>

albanD: <p>Hi,</p>
<p>I think the point is that comparing names should not be used?<br>
For what you want, <code>isinstance(m, torch.nn.Linear)</code> is the pythonic way to do it I think.</p>

Shisho_Sama: <p>Hi, Thank you very much.<br>
The example was given in the Udacity Pytorch course and I just gave that as an example.<br>
But how do you get the type of any class?<br>
It seems type() only works on tensors, and I couldnt findy any ways to query and get a class type!</p>

Shisho_Sama: <p>I was actually trying to finetune a <code>resnet18</code>. I wanted to set the gradients of all layers to zero except the last linear layer! the <code>isinstance</code> simply doesn’t work!<br>
I wrote :</p>
<pre><code class="lang-auto">resnet18 = models.resnet18(pretrained=True)
resnet18.fc = nn.Linear(512, 10) 
  
for module in resnet18.modules():
    if not isinstance(module, nn.Linear):
        for param in module.parameters():
            param.requires_grad = False
</code></pre>
<p>What seems to work is to compare the names which is :</p>
<pre><code class="lang-auto">for module in resnet18.modules():
    if module._get_name() != 'Linear':
        print('layer: ',module._get_name())
        for param in module.parameters():
            param.requires_grad_(False)
    elif module._get_name() == 'Linear':
        for param in module.parameters():
            param.requires_grad_(True)
</code></pre>
<p>something like <code>nn.Linear.__class__.__name__</code> doesnt have the proper name! it contains <code>type</code> as the name which is weird!<br>
Thats why I’m asking.</p>
<p><strong>on a side note :</strong><br>
Something weird happens, if I omit the second elseif block, the resnet18.fc parameters gradient will be False! while they are initially True, and the first if clause clearly checks for all layers except ‘Linear’.<br>
I’d like to know why this is happening as well, and if this is a bug!?</p>

ptrblck: <p>The <code>isinstance</code> comparison is working:</p>
<pre><code class="lang-python">resnet18 = models.resnet18(pretrained=True)
resnet18.fc = nn.Linear(512, 10) 

for module in resnet18.modules():
    if isinstance(module, nn.Linear):
        print(module)

&gt; Linear(in_features=512, out_features=10, bias=True)
</code></pre>
<p>as it returns the only <code>nn.Linear</code> layer in the model.</p>
<p>However, note that <code>modules</code> will be called recursively on your main model.<br>
E.g. the first result will be the parent <code>ResNet</code> class.<br>
If you call <code>module.parameters()</code> you will get all parameters of the model, including the parameters of the linear layer.</p>

SimonW: <p>also <code>__name__</code> and <code>__class__</code> are special attributes defined by Python (not specific to PyTorch) and they aren’t really private and you can expect they to always be there: <a href="https://docs.python.org/3/reference/datamodel.html" rel="nofollow noopener">https://docs.python.org/3/reference/datamodel.html</a></p>

Shisho_Sama: <aside class="quote no-group" data-username="Shisho_Sama" data-post="4" data-topic="47220">
<div class="title">
<div class="quote-controls"></div>
<img loading="lazy" alt="" width="24" height="24" src="https://discuss.pytorch.org/user_avatar/discuss.pytorch.org/shisho_sama/48/6926_2.png" class="avatar"> Shisho_Sama:</div>
<blockquote>
<p><code>nn.Linear.__class__.__name__</code></p>
</blockquote>
</aside>
<p>Thanks, but do you know why <code>nn.Linear.__class__.__name__</code> doesnt have a proper name in it (it returns <code>type</code>? should it not return ‘Linear’?</p>

SimonW: <p>Because <code>obj.__class__</code> accesses the class (type) of the object. Classes are also objects in Python. Most classes are just instances of the <code>type</code> metaclass. Hence, if you do <code>A_Class.__class__</code> or <code>type(A_Class)</code> you (often) get the <code>type</code> metaclass.</p>
<p>On the other hand, an instance of <code>nn.Linear</code>, e.g., <code>nn.Linear(3, 4)</code> has class <code>nn.Linear</code> so you get <code>nn.Linear(3, 4).__class__ == nn.Linear</code> and <code>type(nn.Linear(3, 4)) == nn.Linear</code>.</p>
<p>You probably now realize that if you want to get the name of <code>nn.Linear</code>, you should instead use <code>nn.Linear.__name__</code> rather than <code>nn.Linear.__class__.__name__</code> which returns the name of the metaclass <code>type</code>.</p>

Shisho_Sama: <p>Aha ! that was great! Thanks a gazillion times sir, your explanation was great <img src="https://discuss.pytorch.org/images/emoji/apple/slight_smile.png?v=9" title=":slight_smile:" class="emoji" alt=":slight_smile:"></p>