Understanding how to compute shape of input to Linear() layer

newbieatpytorch: <p>Hi,</p>
<p>I’m trying to walk through by hand the size of input at each layer of my CNN network.</p>
<pre><code class="lang-auto">class Model(nn.Module):
  def __init__(self):
    super(Model, self).__init__()
    self.conv1 = nn.Conv2d(1, 10, 3)
    self.pool1 = nn.MaxPool2d(2)
    self.conv2 = nn.Conv2d(10, 20, 3)
    self.pool2 = nn.MaxPool2d(2)
    self.conv3 = nn.Conv2d(20, 32, 3)
    self.pool3 = nn.MaxPool2d(2)
    self.linear1 = nn.Linear(32, 10)
  
  def forward(self, x):
    x = self.conv1(x)
    x = self.pool1(x)
    x = F.relu(x)
    x = self.conv2(x)
    x = self.pool3(x)
    x = F.relu(x)
    x = self.conv3(x)
    x = self.pool3(x)
    x = F.relu(x)
    print(x.shape)
    x = self.linear1(x)
    return F.softmax(x)
</code></pre>
<p>I’m using the MNIST dataset as input<br>
Input size: 28x28<br>
Size After conv1 layer: 26x26<br>
Size After Pool1 layer: 13x13<br>
Size After conv2 layer: 11x11<br>
Size After Pool2 layer: 5x5<br>
Size After conv3 layer: 3x3<br>
Size After Pool3 layer: 1x1<br>
So number of channels at input of linear is 32x1x1=32</p>
<p>But I get an error</p>
<pre><code class="lang-auto">from torch.autograd import Variable
maxPoolLayer = nn.MaxPool2d(2)
conv2dLayer = nn.Conv2d(1, 10, 3)
mA = Variable(torch.randn(1, 1, 25, 25))
mA.size()
mC = conv2dLayer(mA)
print(mC.size())
mB = maxPoolLayer(mC)
print(mB.size())
</code></pre>
<p>Output:<br>
torch.Size([1, 10, 23, 23])<br>
torch.Size([1, 10, 11, 11])</p>
<p>So default conv2d layer will reduce the size on input by 2 for both dimensions and maxpooling will floor-half the input</p>

beaupreda: <aside class="quote no-group" data-username="newbieatpytorch" data-post="1" data-topic="62432">
<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/n/dc4da7/48.png" class="avatar"> newbieatpytorch:</div>
<blockquote>
<p>So default conv2d layer will reduce the size on input by 2 for both dimensions and maxpooling will floor-half the input</p>
</blockquote>
</aside>
<p>Yes, that is correct, if your <code>Conv2d</code> has a stride of one a 0 padding.</p>
<p>What you need to do to resolve your problem is <code>x = torch.squeeze(x)</code> just before your call to <code>self.linear1(x)</code>. This is because <code>x</code>, before the squeeze, has a shape of <code>B x 32 x 1 x 1</code> and by squeezing it, the shape will become <code>B x 32</code> which will be compatible with your <code>Linear</code> layer (<code>B</code> being the batch size).</p>
<p>Also, (this does not change anything), but you use <code>self.pool3(x)</code> 2 times during your forward pass <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>

newbieatpytorch: <p>Thank you for your help!<br>
I tried using it but for some reason it was not working as you have explained. I’m not sure if my calculations in the original post are correct.<br>
I did some search and finally I came across the <code>torch.flatten()</code> function. I had to use it as <code>torch.flatten(x, 1, 3)</code>. Please let me know your thoughts on the same.</p>
<p>Also you have said that we use <code>self.pool3(x)</code> 2 times. Any specific reason for this.</p>

beaupreda: <p>Ok, it worked when I tested with <code>torch.squeeze</code>, but yes in this case, <code>torch.flatten(x, 1, 3)</code> does the same thing <em>i.e.</em> it eliminates the dimensions of size 1.</p>
<aside class="quote no-group" data-username="newbieatpytorch" data-post="3" data-topic="62432">
<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/n/dc4da7/48.png" class="avatar"> newbieatpytorch:</div>
<blockquote>
<p>Also you have said that we use <code>self.pool3(x)</code> 2 times. Any specific reason for this.</p>
</blockquote>
</aside>
<pre><code class="lang-auto">    x = self.conv2(x)
    x = self.pool3(x)
    x = F.relu(x)
    x = self.conv3(x)
    x = self.pool3(x)
</code></pre>
<p>It does not change anything, but <code>self.pool3</code> is used after <code>self.conv2</code> which means that <code>self.pool2</code> is never used, that’s all!</p>