Overfitting with pre-trained network

SamuGC: <p>Hi guys, i am working with a small dataset of Renal Ultrasound images (1985 images). In this case i am using a pretrained resnet152, fine tuning and data augmentation to do a binary classification between healthy and pathological kidneys. In addition, the dataset is unbalanced and there is 1400 images with the pathological label and the rest for healthy kidneys.</p>
<p>The problem is that when i try to get good results, i have overfitting and i don’t know what else to do. This is my code:</p>
<p>import random<br>
from natsort import natsorted, ns<br>
import <a href="http://skimage.io" rel="noopener nofollow ugc">skimage.io</a> as io<br>
import <a href="http://scipy.io" rel="noopener nofollow ugc">scipy.io</a> as sio<br>
from torchvision.transforms import Compose, ToTensor, Resize , Grayscale, RandomHorizontalFlip,RandomRotation,Normalize,CenterCrop<br>
from ClaseEcografia import *<br>
from BuclesTrValTest import *</p>
<p>import matplotlib.pyplot as plt</p>
<p>import torch<br>
from torch.utils.data import DataLoader<br>
from torchvision import datasets, transforms</p>
<p>import os<br>
from time import time<br>
from tqdm import tqdm<br>
import numpy</p>
<p>from torch.nn import Linear, CrossEntropyLoss<br>
from torch.optim import Adam</p>
<p>import torchvision<br>
from torchvision.models import resnet152,ResNet152_Weights<br>
import torch.nn.functional as F<br>
import torch.nn as nn<br>
import numpy as np</p>
<p>Transformacion_compuesta = Compose([            #[1]<br>
Resize(256),                    #[2]<br>
CenterCrop(224),                #[3]<br>
ToTensor(),                     #[4]<br>
Normalize(                      #[5]<br>
mean=[0.485, 0.456, 0.406],                #[6]<br>
std=[0.229, 0.224, 0.225]                  #[7]<br>
)])</p>
<p>Transformacion_compuesta_train = Compose([            #[1]<br>
Resize(256),                    #[2]<br>
CenterCrop(224),                #[3]<br>
RandomHorizontalFlip(p=0.5),<br>
RandomRotation(degrees=10),<br>
ToTensor(),                     #[4]<br>
Normalize(                      #[5]<br>
mean=[0.485, 0.456, 0.406],                #[6]<br>
std=[0.229, 0.224, 0.225]                  #[7]<br>
)])</p>
<p>root = ‘bbdd_kidney’ <span class="hashtag-raw">#Esta</span> es la ruta relativa para nuestra base de datos</p>
<p>trainDataset = Ecografias(root, mode=‘train’,transform=Transformacion_compuesta_train)<br>
testDataset = Ecografias(root, mode=‘test’,transform=Transformacion_compuesta)<br>
validationDataset = Ecografias(root, mode=‘validation’,transform=Transformacion_compuesta)</p>
<p>print(“-------------------\n”)<br>
print(“La longitud del conjunto de ‘Train’ es de " + str(len(trainDataset))+”\n")<br>
print(“-------------------\n”)<br>
print(“La longitud del conjunto de ‘Validation’ es de " + str(len(validationDataset))+”\n")<br>
print(“-------------------\n”)<br>
print(“La longitud del conjunto de ‘Test’ es de " + str(len(testDataset))+”\n")<br>
print(“-------------------\n”)</p>
<h1><a name="device-cuda-if-torchcudais_available-else-cpu-1" class="anchor" href="#device-cuda-if-torchcudais_available-else-cpu-1"></a>device = ‘cuda’ if torch.cuda.is_available() else ‘cpu’</h1>
<h1><a name="printfusing-device-device-2" class="anchor" href="#printfusing-device-device-2"></a>print(f’Using {device} device’)</h1>
<p>train_dataloader = DataLoader(trainDataset, batch_size = 32, shuffle=True)<br>
validation_dataloader = DataLoader(validationDataset, batch_size = 32, shuffle=False)<br>
test_loader = DataLoader(testDataset, batch_size=32, shuffle = False)</p>
<p>model = resnet152(weights=ResNet152_Weights.DEFAULT)</p>
<p>for param in model.parameters():<br>
param.requires_grad = True</p>
<p>model.fc = Linear(in_features=2048, out_features=2)</p>
<p>model = model.to(device)</p>
<p>for name, param in model.named_parameters():<br>
print('Name: ', name, "Requires_Grad: ", param.requires_grad)</p>
<p>optimizer = Adam(model.parameters(), lr=1e-4)</p>
<p>loss_fn = CrossEntropyLoss()</p>
<p>epochs = 35</p>
<p>tr_loss = np.zeros(epochs)<br>
val_loss = np.zeros(epochs)</p>
<p>tr_acc = np.zeros(epochs)<br>
val_acc = np.zeros(epochs)</p>
<p>best_val_loss = 10e10<br>
best_model = model</p>
<p>for t in range(epochs):<br>
print(f"Epoch {t+1}\n----------------")<br>
avg_tr_loss_e, tr_acc_e=train_loop_return(train_dataloader, model ,loss_fn, optimizer)<br>
<span class="hashtag-raw">#avg_tr_loss_e</span>, tr_acc_e=train_loop_return_scheduler(train_dataloader, model ,loss_fn, optimizer,scheduler)<br>
<span class="hashtag-raw">#avg_train_loss_e</span>, train_acc_e,train_prob_mask =validation_loop_return(train_loader, model ,loss_fn)<br>
avg_val_loss_e, val_acc_e,val_prob_mask =validation_loop_return(validation_dataloader, model ,loss_fn)<br>
<span class="hashtag-raw">#break</span>;<br>
if (avg_val_loss_e &lt; best_val_loss):<br>
best_model = model <span class="hashtag-raw">#Comprobar</span></p>
<p>tr_loss[t]= avg_tr_loss_e<br>
val_loss[t]= avg_val_loss_e<br>
tr_acc[t] =tr_acc_e<br>
val_acc[t] =val_acc_e</p>
<p>print(“Done!”)</p>
<p>import matplotlib.pyplot as plt</p>
<p>fig = plt.figure(1, figsize=(15,5))</p>
<p>plt.subplot(1,2,1)<br>
plt.plot(range(epochs), tr_loss)<br>
plt.plot(range(epochs), val_loss)<br>
plt.xlabel(‘epoch’)<br>
plt.ylabel(‘loss’)<br>
plt.legend([‘tr_loss’, ‘val_loss’])<br>
plt.title(‘Train Loss vs Val Loss’)</p>
<p>plt.subplot(1,2,2)<br>
plt.plot(range(epochs), tr_acc)<br>
plt.plot(range(epochs), val_acc)<br>
plt.xlabel(‘epoch’)<br>
plt.ylabel(‘accuracy’)<br>
plt.legend([‘tr_acc’, ‘val_acc’])<br>
plt.title(‘Train Accuracy vs Val Accuracy’)</p>
<p>def train_loop_return(dataloader, model, loss_fn, optimizer):</p>
<pre><code>size = len(dataloader.dataset)
num_batches = len(dataloader)
train_loss, correct = 0,0

for batch, (X,y) in enumerate(dataloader):

  #Movemos los datos a la CPU para acelerar el proceso
  X = X.to(device)
  y = y.to(device)
  
  
  # print(y)

  #Calculamos la predicción y la pérdida
  pred = model(X)
  loss = loss_fn(pred,y)

  # Propagación hacia atrás
  optimizer.zero_grad() #Inicializa a cero el valor de los gradientes de los parámetros del modelo
  loss.backward() #Propagación el error de la función de pérdida para estimar el gradiente de cada parámetro con respecto del error de predicción
  optimizer.step() #Una vez tenemos nuestros gradientes llamamos a optimizer.step() para ajustar los parámetros con los gradientes calculados en el paso anterior.

  train_loss += loss.item()
  correct += (pred.argmax(1)==y).type(torch.float).sum().item()
  
  
  if batch % 100 == 0: #Imprimimos cada 100 batches
        loss, current = loss.item(), batch * len(X)
        print(f"loss: {loss:&gt;7f}  [{current:&gt;5d}/{size:&gt;5d}]")

avg_train_loss = train_loss / num_batches
train_accuracy = correct/size


print(f"Train Error: \n Accuracy: {(100*train_accuracy):&gt;0.1f}%, Avg loss: {avg_train_loss:&gt;8f} \n")

return avg_train_loss, train_accuracy
</code></pre>
<p>def validation_loop_return(dataloader, model, loss_fn):<br>
size = len(dataloader.dataset)<br>
num_batches = len(dataloader)<br>
validation_loss, correct = 0,0<br>
bs = dataloader.batch_size<br>
probs = torch.zeros(size,2)</p>
<p>with torch.no_grad():<br>
for nb, (X,y) in enumerate(dataloader):</p>
<pre><code>  X = X.to(device)
  y = y.to(device)
  pred = model(X)
  validation_loss +=loss_fn(pred,y).item()
  correct += (pred.argmax(1) == y).type(torch.float).sum().item() #Va almacenando todas las muestras que han sido correctas.
  
  pred_probab = nn.Softmax(dim=1)(pred)

  probs[nb*bs:nb*bs+bs] = pred_probab
  #print(nb)
</code></pre>
<p>avg_validation_loss = validation_loss / num_batches<br>
validation_accuracy = correct/size<br>
print(f"Validation Error: \n Accuracy: {(100*validation_accuracy):&gt;0.1f}%, Avg loss: {avg_validation_loss:&gt;8f} \n")</p>
<p>return avg_validation_loss, validation_accuracy, probs[:,1]</p>
<p>These are the graphic results for train and validation. I would really appreciate the help</p>
<p><img src="https://discuss.pytorch.org/uploads/default/original/3X/7/5/7504c10984e2f9f19acf1378b7d095fea251af3a.png" alt="image" data-base62-sha1="gHc34tmMvEGAqjXXcKHmVABgfXA" width="624" height="231"></p>