Flatten layer of PyTorch build by sequential container

ngap_wei_Tham: <p>I am trying to build a cnn by sequential container of PyTorch, my problem is I cannot figure out how to flatten the layer.</p>
<pre><code>main = nn.Sequential()
self._conv_block(main, 'conv_0', 3, 6, 5)
main.add_module('max_pool_0_2_2', nn.MaxPool2d(2,2))
self._conv_block(main, 'conv_1', 6, 16, 3)
main.add_module('max_pool_1_2_2', nn.MaxPool2d(2,2)) 
main.add_module('flatten', make_it_flatten)
</code></pre>
<p>What should I put in the “make_it_flatten”? I tried to flatten the main but it do not work, main do not exist something call view</p>
<p><code>main = main.view(-1, 16*3*3)</code></p>

fmassa: <p>In this case we would prefer to write the module with a class, and let <code>nn.Sequential</code> only for very simple functions.<br>
But if you definitely want to flatten your result inside a Sequential, you could define a module such as</p>
<pre><code class="lang-python">class Flatten(nn.Module):
    def forward(self, input):
        return input.view(input.size(0), -1)
</code></pre>
<p>and use <code>Flatten</code> in your model</p>

ngap_wei_Tham: <aside class="quote no-group" data-username="fmassa" data-post="2" data-topic="5983">
<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/fmassa/48/58_2.png" class="avatar"> fmassa:</div>
<blockquote>
<p>But if you definitely want to flatten your result inside a Sequential, you could define a module such as</p>
</blockquote>
</aside>
<p>Thanks, but this do not wok. it give me error messages</p>
<p><strong>RuntimeError: size mismatch, m1: [4 x 784], m2: [144 x 120] at /b/wheel/pytorch-src/torch/lib/TH/generic/THTensorMath.c:1237</strong></p>
<p>If I change Flatten to</p>
<p>class Flatten(nn.Module):<br>
def forward(self, x):<br>
x = x.view(-1, 16<em>3</em>3)<br>
return x</p>
<p>It give me error messages</p>
<p><strong>RuntimeError: size ‘[-1 x 144]’ is invalid for input of with 3136 elements at /b/wheel/pytorch-src/torch/lib/TH/THStorage.c:55</strong></p>
<p>gist of codes</p>
<pre><code>class Flatten(nn.Module):
    def forward(self, x):
        x = x.view(x.size()[0], -1)
        return x

class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        
        main = nn.Sequential()
        
        self._conv_block(main, 'conv_0', 3, 6, 5)
        main.add_module('max_pool_0_2_2', nn.MaxPool2d(2,2))
        
        self._conv_block(main, 'conv_1', 6, 16, 3)        
        main.add_module('max_pool_1_2_2', nn.MaxPool2d(2,2))
        
        main.add_module('flatten', Flatten())
        self._linear_block(main, 'linear_0', 16*3*3, 120)        
        self._linear_block(main, 'linear_1', 120, 84)
        main.add_module('linear_2-84-10.linear', nn.Linear(84, 10))
        
        self._main = main
        
    def forward(self, x):
        for module in self._modules.values():
            x = module(x)
        return x
        
    def _conv_block(self, main, name, inp_filter_size, out_filter_size, kernal_size):        
        main.add_module('{}-{}.{}.conv'.format(name, inp_filter_size, out_filter_size), 
                        nn.Conv2d(inp_filter_size, out_filter_size, kernal_size, 1, 1))
        main.add_module('{}-{}.batchnorm'.format(name, out_filter_size), nn.BatchNorm2d(out_filter_size))
        main.add_module('{}-{}.relu'.format(name, out_filter_size), nn.ReLU())                
        
    def _linear_block(self, main, name, inp_filter_size, out_filter_size):
        main.add_module('{}-{}.{}.linear'.format(name, inp_filter_size, out_filter_size), 
                        nn.Linear(inp_filter_size, out_filter_size))
        main.add_module('{}-{}'.format(name, out_filter_size), nn.ReLU())
</code></pre>
<p>Complete codes are place at <a href="https://pastebin.com/ANcJGhC0" rel="noopener nofollow ugc">pastebin</a>, 90 lines</p>
<aside class="quote no-group" data-username="fmassa" data-post="2" data-topic="5983">
<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/fmassa/48/58_2.png" class="avatar"> fmassa:</div>
<blockquote>
<p>In this case we would prefer to write the module with a class, and let nn.Sequential only for very simple functions.</p>
</blockquote>
</aside>
<p>I guess I would follow this advices, I pick sequential container because I do not know how to group several layer together(conv-&gt;batch-&gt;relu, define a residual block etc), until I <a href="https://github.com/pytorch/examples/blob/master/fast_neural_style/neural_style/transformer_net.py" rel="noopener nofollow ugc">find this example</a>.</p>

fmassa: <p>The bug is probably in</p>
<aside class="quote no-group quote-modified" data-username="ngap_wei_Tham" data-post="3" data-topic="5983">
<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/ngap_wei_tham/48/8558_2.png" class="avatar"> ngap_wei_Tham:</div>
<blockquote>
<p>self._linear_block(main, ‘linear_0’, 16<em>3</em>3, 120)</p>
</blockquote>
</aside>
<p>You have the wrong size for the linear block, it should probably not be <code>16*3*3</code>, but something else.</p>
<p>Also, you are overcomplicating the definition of your model. If your model is just a sequential, you can construct it with an <code>OrderedDict</code>, so that you don’t need to create a <code>Net</code> class for it.</p>
<p>Something like</p>
<pre data-code-wrap="python"><code class="lang-python">def _conv_block(l, name, inp_filter_size, out_filter_size, kernal_size):
    l['{}-{}.{}.conv'.format(name, inp_filter_size, out_filter_size)] =  
                    nn.Conv2d(inp_filter_size, out_filter_size, kernal_size, 1, 1))
    l['{}-{}.batchnorm'.format(name, out_filter_size)] = nn.BatchNorm2d(out_filter_size))
    l['{}-{}.relu'.format(name, out_filter_size)] = nn.ReLU())

def _linear_block(l, name, inp_filter_size, out_filter_size):
        l[('{}-{}.{}.linear'.format(name, inp_filter_size, out_filter_size)] = 
                        nn.Linear(inp_filter_size, out_filter_size))
        l[('{}-{}'.format(name, out_filter_size)] = nn.ReLU())

l = OrderedDict()
_conv_block(l, 'conv_0', 3, 6, 5)
l['max_pool_0_2_2'] = nn.MaxPool2d(2,2)
...

model = nn.Sequential(l)
</code></pre>
<p>And that can still be cleaned up a bit</p>

ngap_wei_Tham: <aside class="quote no-group quote-modified" data-username="fmassa" data-post="4" data-topic="5983">
<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/fmassa/48/58_2.png" class="avatar"> fmassa:</div>
<blockquote>
<p>You have the wrong size for the linear block, it should probably not be 16<em>3</em>3, but something else.</p>
</blockquote>
</aside>
<p>You are correct, it should be 16 * 6 * 6.</p>
<aside class="quote no-group" data-username="fmassa" data-post="4" data-topic="5983">
<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/fmassa/48/58_2.png" class="avatar"> fmassa:</div>
<blockquote>
<p>you can construct it with an OrderedDict, so that you don’t need to create a Net class for it.</p>
</blockquote>
</aside>
<p>Thanks for the tips of OrderedDict <img src="https://discuss.pytorch.org/images/emoji/apple/slight_smile.png?v=12" title=":slight_smile:" class="emoji" alt=":slight_smile:" loading="lazy" width="20" height="20"></p>
<p>Do PyTorch have any plan to provide layers without a need to specify input size?</p>

fmassa: <p>I don’t think it is in the plans to provide any functionality like that, because it depends on the input size, and pytorch has dynamic graphs so you don’t compile your graph beforehand.<br>
But, there are workarounds for that.<br>
Check for example <a href="https://discuss.pytorch.org/t/inferring-shape-via-flatten-operator/138/4?u=fmassa">Inferring shape via flatten operator</a></p>

synchro: <p>Has this been included in official modules?</p>
<p>It could be useful because you decouple your module from the forward method. I mean, if I wanna convert FC to conv layers on a pre-trained model, and the forward method includes the x.view call, I can’t, right?</p>
<p>With the flatten operator inside the model, I can just unplug it and put a conv before. Does this make sense or am I looking at it from the wrong side?</p>

Brando_Miranda: <aside class="quote no-group" data-username="fmassa" data-post="2" data-topic="5983">
<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/fmassa/48/58_2.png" class="avatar"> fmassa:</div>
<blockquote>
<p>class Flatten(nn.Module):<br>
def forward(self, input):<br>
return input.view(input.size(0), -1)</p>
</blockquote>
</aside>
<p>so the flatten module is not planned to be included in the pytorch library then?</p>

guyko: <p>Doesn’t this solution work for any shape?</p>
<pre><code>class Flatten(nn.Module):

    def __init__(self):
        super(Flatten, self).__init__()

    def forward(self, x):
        shape = torch.prod(torch.tensor(x.shape[1:])).item()
        return x.view(-1, shape)</code></pre>

Pranavan_Theivendira: <p>Hi Everyone,</p>
<p>In torch 1.2.0 - Flatten module is included. <img src="https://discuss.pytorch.org/images/emoji/apple/grinning.png?v=9" title=":grinning:" class="emoji" alt=":grinning:"> I attached small code snippet.</p>
<pre><code class="lang-auto">import torch.nn as nn
import torch

f = nn.Flatten()
x = torch.randn((2, 2, 3))
print('Before flatten shape : ', x.shape)
print('After flatten shape : ', f(x).shape)
</code></pre>
<p>Thanks</p>

anantguptadbl: <p>Thank you <a class="mention" href="/u/fmassa">@fmassa</a>. This is awesome as I can keep wrapping preprocessing ( important but not grad affecting tasks )  into these classes</p>

Joycechidi: <p>Thank you so much. This has saved me from a torturous rabbit-hole of debugging. I have been struggling for 3 days to fix this shape problem. I appreciate your answer.</p>

adarsh_pandey: <p>can anyone of you please explain me the view() function and what are the parameters it takes please&gt;&gt;<br>
very urgent<br>
Thanks</p>

ptrblck: <p>Answered <a href="https://discuss.pytorch.org/t/which-parameter-is-pass-in-view-function/38655/8">here</a>.</p>