Accessing any feature of Pretrained Net (by Name)

username: mmcm
cooked: <p>This is sort of an extended version of the question in <a href="https://discuss.pytorch.org/t/accessing-intermediate-layers-of-a-pretrained-network-forward/12113/9">Accessing intermediate layers of a pretrained network forward?</a>.</p>
<p>Coming from tensorflow (and liking it here, this is a great community!) I am probably just approaching this the wrong way.<br>
I am trying to write a really simple feature extraction script.<br>
Given an input image (or a stack of images) I just want to compute some features using a pretrained vgg19 and dump them into a binary file. No backprop, no bells or whistles, really.</p>
<p>Thing is, <em>which</em> features exactly is a parameter to my script.<br>
Now, in tensorflow, this would essentially be something along the lines of</p>
<pre><code class="lang-python">logits, end_points = vgg19(inputs)
return [end_points[k] for k in targets]
</code></pre>
<p>where <code>targets</code> are <code>conv1_1</code> or <code>fc6</code> for example.<br>
How do I do something similar in pytorch?</p>
<p>What I have inferred so far would be possible:</p>
<ul>
<li>create a subclass of <code>nn.Module</code>
</li>
<li>inside that module, load vgg19</li>
<li>essentially re-build the entirety of the original vgg19 model using the submodules of the normal vgg19, and adding names to the submodule keys to be able to address them by those names later</li>
<li>define <code>forward()</code> to do the forward pass until the last target, keeping the intermediate results in a list and returning them.</li>
</ul>
<p>This seems <em>awfully</em> complicated for what I’m trying to achieve, so I’m probably approaching this the wrong way… help, please? <img src="https://discuss.pytorch.org/images/emoji/apple/slight_smile.png?v=5" title=":slight_smile:" class="emoji" alt=":slight_smile:"></p>

username: mmcm
cooked: <p>This is what I came up with now:</p>
<pre><code class="lang-python">class VGG19FeatureExtractor(nn.Module):
  def __init__(self, net, targets):
    super(VGG19FeatureExtractor, self).__init__()
    self.features = net.features
    self.classifier = net.classifier
    if isinstance(targets, int):
      self.targets = {targets}  # TODO: make this nice strings
      self.is_list = False
    else:
      self.targets = set(targets)  # TODO: make this nice strings
      self.is_list = True
    max_index = len(self.features) + len(self.classifier)
    for t in targets:
      if not 0 &lt;= t &lt; max_index:
        raise ValueError(f'Invalid target index {t}. Should be within [0, {max_index})')

  def forward(self, x):
    results = list()
    for i, module in enumerate(self.features):
      x = module(x)
      if i in self.targets:
        print(f'{i}\t{module}')
        results.append(x.clone())
        if len(results) == len(self.targets):
          if self.is_list:
            return results
          else:
            return results[0]
    x = x.view(x.shape[0], -1)
    
    i_ = len(self.features)  # classifier numbers are numbered starting from this
    for i, module in enumerate(self.classifier):
      x = module(x)
      if i + i_ in self.targets:
        results.append(x.clone())
        print(f'{i+i_}\t{module}')
        if len(results) == len(self.targets):
          if self.is_list:
            return results
          else:
            return results[0]
    raise RuntimeError('should have returned before here. what happened?!')
</code></pre>
<p>This class takes a vgg19 network as input, as well as a single target or a collection of targets (integers).<br>
It computes the target(s) and returns them as a list if appropriate.</p>
<p>While this seems to be doing what I want, I have several issues with it:</p>
<ul>
<li>it is <em>incredibly</em> verbose for what it does.</li>
<li>it uses integers as the targets instead of e.g. <code>conv1_2</code> or <code>pool5</code>
</li>
<li>it relies on the <code>self.features</code> and <code>self.classifier</code> attributes of the vgg networks (won’t work with e.g. ResNet)</li>
<li>the double <code>for</code>-loop makes my heart hurt. This might be mitigated somewhat with a simple <code>Flatten</code> module though.</li>
</ul>
<p>EDIT:</p>
<p>and yes, I put that string interpolation in there out of principle. Change it if you want to use it in python2 <img src="https://discuss.pytorch.org/images/emoji/apple/stuck_out_tongue.png?v=5" title=":stuck_out_tongue:" class="emoji" alt=":stuck_out_tongue:"></p>

username: mmcm
cooked: <p>I finally ended up doing this somewhat properly:</p>
<p><a href="https://discuss.pytorch.org/t/easy-vgg-feature-extraction-module/45780/2">https://discuss.pytorch.org/t/easy-vgg-feature-extraction-module/45780/2</a></p>

username: sebamenabar
cooked: <p>Hi, I made a python package to get the intermediate outputs of a model’s submodules, check it out. <a href="https://pypi.org/project/torch-intermediate-layer-getter/" rel="nofollow noopener">Pypi link</a></p>