How to modify the final FC layer based on the torch.model

zhongtao93: Hi, everyone. I want to use the VGG19 in my own dataset, which has 8 classes.Ｓo I want to change the output of the last fc layer  to 8. So what should I do to change the last fc layer to fit it. Thank you very much!

panovr: 

Ismail_Elezi: Something like: <SCODE>model = torchvision.models.vgg19(pretrained=True)
for param in model.parameters():
    param.requires_grad = False
    # Replace the last fully-connected layer
    # Parameters of newly constructed modules have requires_grad=True by default
model.fc = nn.Linear(512, 8) # assuming that the fc7 layer has 512 neurons, otherwise change it 
model.cuda()<ECODE>

zhongtao93: Thank you, I’ll try it!

Ismail_Elezi: Don’t forget to retrain the last layer though. At the moment the weights of it have just random numbers, so you must retrain it. You can do the retraining the same way as normal, the only change is that now the weights of the other layers won’t change because I set the requires_grad to False. If you have enough data to do a full training, then simply remove the line which does that, but it will surely take much longer to train.

zhongtao93: <SCODE>---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-9-cbf958b7f4be> in <module>()
      3 import torch.nn as nn
      4 import torch.nn.functional as F
----> 5 model = torchvision.models.vgg19(pretrained=True)
      6 for param in model.parameters():
      7     param.requires_grad = False

TypeError: vgg19() takes no arguments (1 given)<ECODE>

Crazyai: 

Ismail_Elezi: Hmm, I didn’t try the code yesterday and just changed the line from a residual network. Now I tried it, and got the same error as you. It seems that you can get just the model, but not the weights of it. Which actually contradicts the documentation when it is written that you can give the pretrained argument.

apaszke: 

zhongtao93: I uninstalled the current torchvision, and rebulid the newest version, and it worked. Thank you very much!

zhongtao93: My network initialized as below: <SCODE>#VGG19
import torchvision
import torch.nn as nn
import torch.nn.functional as F
vgg19 = torchvision.models.vgg19(pretrained=True)
for param in vgg19.parameters():
    param.requires_grad = False
requires_grad=True by default
vgg19.fc = nn.Linear(1000, 8) neurons, otherwise change it 
vgg19.cuda()
import torch.optim as optim
criterion = nn.CrossEntropyLoss() 
optimizer = optim.SGD(vgg19.fc.parameters(), lr=0.001, momentum=0.9)#lr 0.001
<ECODE> <SCODE>        inputs, labels = Variable(inputs.cuda()), Variable(labels.cuda())
        # zero the parameter gradients
        optimizer.zero_grad()
        # forward + backward + optimize
        outputs = vgg19(inputs)
        #print(type(outputs),type(inputs))
        loss = criterion(outputs, labels)
        #loss = F.nll_loss(outputs, labels)
        loss.backward()        
        optimizer.step()
        step += 1
        # print statistics
        running_loss += loss.data[0]
<ECODE> error RuntimeError: there are no graph nodes that require computing gradients

Cysu: <SCODE>  (classifier): Sequential (
    (0): Dropout (p = 0.5)
    (1): Linear (25088 -> 4096)
    (2): ReLU (inplace)
    (3): Dropout (p = 0.5)
    (4): Linear (4096 -> 4096)
    (5): ReLU (inplace)
    (6): Linear (4096 -> 100)
  )
<ECODE> To replace the last linear layer, a temporary solution would be <SCODE>vgg19.classifier._modules['6'] = nn.Linear(4096, 8)
<ECODE>

zhongtao93: 

Cysu: 

micklexqg: thank you. what should I change if I want to  add dropout in ‘fc’? the last classifier layer has been changed in terms of the number of classes and I want to add dropout before it.

chenglu: There’s already a dropout layer before the final FC layer, the code is <SCODE>        self.classifier = nn.Sequential(
            nn.Linear(512 * 7 * 7, 4096),
            nn.ReLU(True),
            nn.Dropout(),
            nn.Linear(4096, 4096),
            nn.ReLU(True),
            nn.Dropout(),
            nn.Linear(4096, num_classes),
        )
<ECODE> you only need to replace the last 4096, num_classes to your own fc layer.

Praveen_raja_sekar: i am trying to convert the classification network to regression netowork by replacing the last layer with number of outputs as one can you please suggest any solution ay help would be greatly appreciated i am new to pytorch

ptrblck: You can just do exactly this by setting the last layer as: <SCODE>nn.Linear(4096, 1)
<ECODE>

Praveen_raja_sekar: <SCODE>class FineTuneModel(nn.Module):
    def __init__(self, original_model, num_classes):
        super(FineTuneModel, self).__init__()
        # Everything except the last linear layer
        self.features = nn.Sequential(*list(original_model.children())[:-1])
        self.classifier = nn.Sequential(
            nn.Linear(512, 1)
        )
        self.modelName = 'LightCNN-29'
        # Freeze those weights
        for p in self.features.parameters():
            p.requires_grad = False


    def forward(self, x):
        f = self.features(x)        
        f = f.view(f.size(0), -1)
        y = self.classifier(f)
        return y

model = FineTuneModel(original_model, args.num_classes)
print(model)
<ECODE> Output: <SCODE>FineTuneModel(
  (features): Sequential()
  (classifier): Sequential(
    (0): Linear(in_features=512, out_features=1, bias=True)
  )
)
<ECODE> original model is pretrained resnet model

Praveen_raja_sekar: <SCODE>class FineTuneModel(nn.Module):
    def __init__(self, original_model, num_classes):
        super(FineTuneModel, self).__init__()
        # Everything except the last linear layer
        self.features = nn.Sequential(*list(original_model.children())[:-1])
        self.classifier = nn.Sequential(
            nn.Linear(512, 1)
        )
        self.modelName = 'LightCNN-29'
        # Freeze those weights
        for p in self.features.parameters():
            p.requires_grad = False


    def forward(self, x):
        f = self.features(x)        
        f = f.view(f.size(0), -1)
        y = self.classifier(f)
        return y
<ECODE>