RuntimeError: removing the last layer of pretrained inceptionV3 model

chgermann: <p>Dear all,</p>
<p>I am trying to implement an inceptionV3 model for image classification.</p>
<p>Following the code snippet where I import the model and remove the last layer:</p>
<pre><code class="lang-auto">import torch
import torch.nn as nn
from torchvision import models

class CustomModel(nn.Module):
    def __init__(self, num_classes):
        super(CustomModel, self).__init__()
        self.num_classes = num_classes
        
        # Load the pretrained model
        self.base_model = models.inception_v3(weights=models.Inception_V3_Weights.DEFAULT, aux_logits=True)
            
        # drop the last classification layer and get the number of input_features for the custom classifier
        self.features = nn.Sequential(*(list(self.base_model.children())[:-1]))

def forward(self, x):
        x, _ = self.features(x)
        return x

if __name__ == '__main__':
    inc3 = CustomModel(num_classes=2)
    input_tensor = torch.randn(5, 3, 299, 299)
    output = inc3(input_tensor)
</code></pre>
<p>When I run this code, the following error occurs, although I removed the last classification layer:</p>
<p>RuntimeError: Expected 3D (unbatched) or 4D (batched) input to conv2d, but got input of size: [5, 1000]</p>
<p>I receive the same error up to <code>nn.Sequential(*(list(self.base_model.children())[:-6]))</code>,</p>
<p>Do you have any idea how I could solve this problem so that I can add a classifier to the features model?</p>

Soumya_Kundu: <pre><code class="lang-auto">import torch

import torch.nn as nn

from torchvision import models

model = models.inception_v3(weights=models.Inception_V3_Weights.DEFAULT, aux_logits=True)

num_classes = 2

num_ftrs = model.fc.in_features

model.fc = nn.Linear(num_ftrs, num_classes)
</code></pre>
<p>This code allows you to change the number of classes for the classifier. Is this what you are looking for?</p>

chgermann: <p>Dear <a class="mention" href="/u/soumya_kundu">@Soumya_Kundu</a></p>
<p>Thank you for your answer.</p>
<p>Not quite. My main goal is to divide my model into a <code>self.features</code> and a ‘self.classifier’ part, where self.features is the pretrained model architecture of inceptionV3 and the classifier is a combination of fc layers to further process the feature vector of inceptionV3.</p>
<p>My whole code looks like this:</p>
<pre><code class="lang-auto">import torch
import torch.nn as nn
from torchvision import models

class CustomModel(nn.Module):
    def __init__(self, pretrained_model, num_classes):
        super(CustomModel, self).__init__()
        self.pretrained_model = pretrained_model
        self.num_classes = num_classes
        
        # Load the pretrained model
        if self.pretrained_model.lower() == 'inceptionv3':
            self.base_model = models.inception_v3(weights=models.Inception_V3_Weights.DEFAULT, aux_logits=True)
            
        elif self.pretrained_model.lower() == 'resnet18':
            self.base_model = models.resnet18(weights=models.ResNet18_Weights.DEFAULT)
            
        elif self.pretrained_model.lower() == 'resnet34':
            self.base_model = models.resnet34(weights=models.ResNet34_Weights.DEFAULT) 
            
        elif self.pretrained_model.lower() == 'resnet152':
            self.base_model = models.resnet152(weights=models.ResNet152_Weights.DEFAULT)
        
        # drop the last classification layer and get the number of input_features for the custom classifier
        self.features = nn.Sequential(*list(self.base_model.children())[:-1])
        num_in_features = self.base_model.fc.in_features
        
        layer_length = [int(num_in_features/(2**idx)) for idx in range(4)]
        
        # Add custom dense layers for classification
        self.classifier = nn.Sequential(
            nn.Flatten(),
            nn.Linear(layer_length[0], layer_length[1]),
            nn.ReLU(),
            nn.Dropout(0.5),
            nn.Linear(layer_length[1], layer_length[2]),
            nn.ReLU(),
            nn.Dropout(0.5),
            nn.Linear(layer_length[2], layer_length[3]),
            nn.ReLU(),
            nn.Dropout(0.5),
            nn.Linear(layer_length[3], self.num_classes)
        )
        
    def forward(self, x):
        x = self.features(x)
        x = self.classifier(x)
        return x
            
        
    
    
    
if __name__ == '__main__':
    inc3 = CustomModel('inceptionV3', 2)
    input_tensor = torch.randn(2, 3, 299, 299)
    output = inc3(input_tensor)
</code></pre>
<p>The problem is if I try to run this code, the error mentioned above occurs, which says I give as an input to a convolutional layer in the inceptionV3 architecture a tensor of shape (2,1000).</p>
<p>The error lies within the inceptionV3 architecture, because if I print the shape after every layer I get the following:</p>
<pre><code class="lang-auto">output shape of layer 0: torch.Size([2, 32, 149, 149])
 output shape of layer 1: torch.Size([2, 32, 147, 147])
 output shape of layer 2: torch.Size([2, 64, 147, 147])
 output shape of layer 3: torch.Size([2, 64, 73, 73])
 output shape of layer 4: torch.Size([2, 80, 73, 73])
 output shape of layer 5: torch.Size([2, 192, 71, 71])
 output shape of layer 6: torch.Size([2, 192, 35, 35])
 output shape of layer 7: torch.Size([2, 256, 35, 35])
 output shape of layer 8: torch.Size([2, 288, 35, 35])
 output shape of layer 9: torch.Size([2, 288, 35, 35])
 output shape of layer 10: torch.Size([2, 768, 17, 17])
 output shape of layer 11: torch.Size([2, 768, 17, 17])
 output shape of layer 12: torch.Size([2, 768, 17, 17])
 output shape of layer 13: torch.Size([2, 768, 17, 17])
 output shape of layer 14: torch.Size([2, 768, 17, 17])
 output shape of layer 15: torch.Size([2, 1000])
</code></pre>
<p>Followed by the error message:</p>
<p>RuntimeError: Expected 3D (unbatched) or 4D (batched) input to conv2d, but got input of size: [2, 1000]</p>
<p>Does this clarify my problem?</p>