Transfer learning shape mismatch

I am pretty new to deep learning so please bear with me if i commit some errors.

I have an MLP classifier with 4 layers, fc1, fc2, fc3 and outputLayer.

This is what I want to do. I want to slice the MLP model from fc1, fc2 to fc3 and then add a new layer which is fc4 before the outputLayer. This becomes my new TransferMLP.

However, I am facing come shape mismatch. I know where the problem is just that I dont know how to fix it. I want the new model (TranferMLP ) to start from fc3 but the model end up picking the output layer instead.

Please direct me on how to fix it.

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

import torch
import torch.nn as nn
import torch.optim as optim
from torch.autograd import Variable


# Original MLP classifier
class MLP(nn.Module):
    def __init__(self, input_dim, hidden_dim1, hidden_dim2, hidden_dim3, output_dim, device):
        super(MLP, self).__init__()
        self.device = device
        self.fc1 = nn.Linear(input_dim, hidden_dim1)
        self.relu1 = nn.ReLU()
        self.drop1 = nn.Dropout(0.5)
        self.fc2 = nn.Linear(hidden_dim1, hidden_dim2)
        self.relu2 = nn.ReLU()
        self.drop2 = nn.Dropout(0.5)
        self.fc3 = nn.Linear(hidden_dim2, hidden_dim3)
        self.relu3 = nn.ReLU()
        self.drop3 = nn.Dropout(0.5)
        self.outputLayer = nn.Linear(hidden_dim3, output_dim)
        self.out_act = nn.Sigmoid()

    def forward(self, x):
        out = self.fc1(x)
        out = self.relu1(out)
        out = self.drop1(out)
        out = self.fc2(out)
        out = self.relu2(out)
        out = self.drop2(out)
        out = self.fc3(out)
        out = self.relu3(out)
        out = self.drop3(out)
        out = self.outputLayer(out)
        out = self.out_act(out)
        return out


# Transfer learning model
class TransferMLP(nn.Module):
    def __init__(self, pretrained_model, hidden_dim3, hidden_dim4, output_dim, device): #hidden_dim1, hidden_dim2, 
        super(TransferMLP, self).__init__()
        self.device = device
        self.pretrained_model = pretrained_model
        self.fc3 = nn.Linear(pretrained_model.fc3.in_features, hidden_dim3)
        self.relu3 = nn.ReLU()
        self.drop3 = nn.Dropout(0.5)
        self.fc4 = nn.Linear(hidden_dim3, hidden_dim4)
        self.relu4 = nn.ReLU()
        self.drop4 = nn.Dropout(0.5)
        self.outputLayer = nn.Linear(hidden_dim4, output_dim)
        self.out_act = nn.Sigmoid()

    def forward(self, x):
        out = self.pretrained_model(x)
        out = self.fc3(out)
        out = self.relu3(out)
        out = self.drop3(out)
        out = self.fc4(out)
        out = self.relu4(out)
        out = self.drop4(out)
        out = self.outputLayer(out)
        out = self.out_act(out)
        return out


def train(input_dim, hidden_dim1, hidden_dim2, hidden_dim3, output_dim, learning_rate, num_epochs, trainData, trainLabel,
          device):
    dnn_model = MLP(input_dim, hidden_dim1, hidden_dim2, hidden_dim3, output_dim, device=device)
    dnn_model.to(device)

    # Loss and optimizer
    criterion = nn.BCELoss()
    optimizer = optim.SGD(dnn_model.parameters(), lr=learning_rate)

    trainX_batch = Variable(trainData.float()).to(device)
    trainY_batch = Variable(trainLabel.float()).to(device)

    # Train the network
    for epoch in range(num_epochs):
        outputs = dnn_model(trainX_batch)
        tot_loss = criterion(outputs, trainY_batch)

        optimizer.zero_grad()
        tot_loss.backward()
        optimizer.step()

    return dnn_model


def transferMLP_train(pretrained_model, hidden_dim3, hidden_dim4, output_dim, learning_rate, num_epochs, trainData,
                   trainLabel, device):
    model = TransferMLP(pretrained_model, hidden_dim3, hidden_dim4, output_dim, device=device)
    model.to(device)

    # Freeze pre-trained model parameters
    for param in model.pretrained_model.parameters():
        param.requires_grad = False

    # Loss and optimizer
    criterion = nn.BCELoss()
    optimizer = optim.SGD(model.parameters(), lr=learning_rate)

    trainX_batch = Variable(trainData.float()).to(device)
    trainY_batch = Variable(trainLabel.float()).to(device)

    # Train the network
    for epoch in range(num_epochs):
        outputs = model(trainX_batch)
        tot_loss = criterion(outputs, trainY_batch)

        optimizer.zero_grad()
        tot_loss.backward()
        optimizer.step()

    return model

Please see the error below:

real_input_dim :  103
real_input_label_dim:  torch.Size([3015, 1])
input_dim:  103
input_label_dim:  torch.Size([59264, 1])
MLP(
  (fc1): Linear(in_features=103, out_features=60, bias=True)
  (relu1): ReLU()
  (drop1): Dropout(p=0.5, inplace=False)
  (fc2): Linear(in_features=60, out_features=30, bias=True)
  (relu2): ReLU()
  (drop2): Dropout(p=0.5, inplace=False)
  (fc3): Linear(in_features=30, out_features=15, bias=True)
  (relu3): ReLU()
  (drop3): Dropout(p=0.5, inplace=False)
  (outputLayer): Linear(in_features=15, out_features=1, bias=True)
  (out_act): Sigmoid()
)
TransferMLP(
  (pretrained_model): MLP(
    (fc1): Linear(in_features=103, out_features=60, bias=True)
    (relu1): ReLU()
    (drop1): Dropout(p=0.5, inplace=False)
    (fc2): Linear(in_features=60, out_features=30, bias=True)
    (relu2): ReLU()
    (drop2): Dropout(p=0.5, inplace=False)
    (fc3): Linear(in_features=30, out_features=15, bias=True)
    (relu3): ReLU()
    (drop3): Dropout(p=0.5, inplace=False)
    (outputLayer): Linear(in_features=15, out_features=1, bias=True)
    (out_act): Sigmoid()
  )
  (fc3): Linear(in_features=30, out_features=15, bias=True)
  (relu3): ReLU()
  (drop3): Dropout(p=0.5, inplace=False)
  (fc4): Linear(in_features=15, out_features=5, bias=True)
  (relu4): ReLU()
  (drop4): Dropout(p=0.5, inplace=False)
  (outputLayer): Linear(in_features=5, out_features=1, bias=True)
  (out_act): Sigmoid()
)
---------------------------------------------------------------------------
RuntimeError                              Traceback (most recent call last)
Cell In[9], line 90
     88 t_mlp = TransferMLP(mlp, hidden_dim3, hidden_dim4, output_dim, device)
     89 print(t_mlp)
---> 90 final_mlp = transferMLP_train(mlp, hidden_dim3, hidden_dim4, output_dim, learning_rate, 
     91                               num_epochs, real_trainData, real_trainLabel, device)
     93 # Test the model
     94 with torch.no_grad():

File /RAID5/DataStorage/davidd/experiments/pb1_july/models/classifer_transfer.py:113, in transferMLP_train(pretrained_model, hidden_dim3, hidden_dim4, output_dim, learning_rate, num_epochs, trainData, trainLabel, device)
    111 # Train the network
    112 for epoch in range(num_epochs):
--> 113     outputs = model(trainX_batch)
    114     tot_loss = criterion(outputs, trainY_batch)
    116     optimizer.zero_grad()

File /RAID5/DataStorage/davidd/apps/anaconda/envs/pt2.0.1/lib/python3.10/site-packages/torch/nn/modules/module.py:1194, in Module._call_impl(self, *input, **kwargs)
   1190 # If we don't have any hooks, we want to skip the rest of the logic in
   1191 # this function, and just call forward.
   1192 if not (self._backward_hooks or self._forward_hooks or self._forward_pre_hooks or _global_backward_hooks
   1193         or _global_forward_hooks or _global_forward_pre_hooks):
-> 1194     return forward_call(*input, **kwargs)
   1195 # Do not call functions when jit is used
   1196 full_backward_hooks, non_full_backward_hooks = [], []

File /RAID5/DataStorage/davidd/experiments/pb1_july/models/classifer_transfer.py:60, in TransferMLP.forward(self, x)
     58 def forward(self, x):
     59     out = self.pretrained_model(x)
---> 60     out = self.fc3(out)
     61     out = self.relu3(out)
     62     out = self.drop3(out)

File /RAID5/DataStorage/davidd/apps/anaconda/envs/pt2.0.1/lib/python3.10/site-packages/torch/nn/modules/module.py:1194, in Module._call_impl(self, *input, **kwargs)
   1190 # If we don't have any hooks, we want to skip the rest of the logic in
   1191 # this function, and just call forward.
   1192 if not (self._backward_hooks or self._forward_hooks or self._forward_pre_hooks or _global_backward_hooks
   1193         or _global_forward_hooks or _global_forward_pre_hooks):
-> 1194     return forward_call(*input, **kwargs)
   1195 # Do not call functions when jit is used
   1196 full_backward_hooks, non_full_backward_hooks = [], []

File /RAID5/DataStorage/davidd/apps/anaconda/envs/pt2.0.1/lib/python3.10/site-packages/torch/nn/modules/linear.py:114, in Linear.forward(self, input)
    113 def forward(self, input: Tensor) -> Tensor:
--> 114     return F.linear(input, self.weight, self.bias)

RuntimeError: mat1 and mat2 shapes cannot be multiplied (3015x1 and 30x15)