Hi.
I’ve just changed from Keras to Pytorch, and I have tried to follow some tutorials. And most of it makes sense. But all the tutorials I could find are on multiclass problems like mnist, cifar-10 or transfer learning. But today I want to try the good old dog vs. cat problem from scratch. Last time I worked with Keras on this specific problem, I got an acc>90%, but when I am trying in Pytorch, it gives me an accuracy of 50 - if i am lucky. So assume that I’m doing something wrong
I have all the images saved in the folder ‘Cat_Dog_data’ folder with subfolders test and train. Which each contains the folder cat and dog. I have tried to make the network simpler, remove dropout, shuffle the dataset, change the loss, changed the way I measure the loss/accuracy, etc. - but it doesn’t help
data_dir = 'Cat_Dog_data'
transforms = transforms.Compose([transforms.Resize(128),
transforms.CenterCrop(128),
transforms.ToTensor()]
)
train_data = datasets.ImageFolder(data_dir + '/train', transform = transforms)
test_data = datasets.ImageFolder(data_dir + '/test', transform= transforms)
train_loader = torch.utils.data.DataLoader(train_data, batch_size=32, shuffle=True)
test_loader = torch.utils.data.DataLoader(test_data, batch_size=32, shuffle=True)
# check if CUDA is available
train_on_gpu = torch.cuda.is_available()
import torch.nn as nn
import torch.nn.functional as F
# define the CNN architecture
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv1 = nn.Conv2d(3, 32, 3, padding=1)
self.conv2 = nn.Conv2d(32, 32, 3, padding=1)
self.conv3 = nn.Conv2d(32, 64, 3, padding=1)
self.pool = nn.MaxPool2d(2, 2)
self.fc1 = nn.Linear(64*4*4*4*4, 64)
self.fc2 = nn.Linear(64, 1)
self.dropout = nn.Dropout(0.1)
def forward(self, x):
# add sequence of convolutional and max pooling layers
x = self.pool(F.relu(self.conv1(x)))
x = self.pool(F.relu(self.conv2(x)))
x = self.pool(F.relu(self.conv3(x)))
x = x.view(-1, 64 * 4 * 4*4*4)
x = self.dropout(x)
x = F.relu(self.fc1(x))
x = self.dropout(x)
x = F.relu(self.fc2(x))
x = F.sigmoid(x)
return x
model = Net()
print(model)
# move tensors to GPU if CUDA is available
if train_on_gpu:
model.cuda()
def weight_init(m):
if isinstance(m, nn.Conv2d) or isinstance(m, nn.ConvTranspose2d):
nn.init.xavier_uniform_(m.weight, gain=nn.init.calculate_gain('relu'))
nn.init.zeros_(m.bias)
model.apply(weight_init)
n_epochs = 5 # you may increase this number to train a final model
valid_loss_min = np.Inf # track change in validation loss
from torch.autograd import Variable
for epoch in range(1, n_epochs+1):
# keep track of training and validation loss
train_loss = 0.0
valid_loss = 0.0
accuracy = 0.0
###################
# train the model #
###################
model.train()
for data, target in train_loader:
# move tensors to GPU if CUDA is available
target = target.float()
if train_on_gpu:
data, target = data.cuda(), target.cuda()
# clear the gradients of all optimized variables
optimizer.zero_grad()
# forward pass: compute predicted outputs by passing inputs to the model
output = model(data)
# calculate the batch loss
loss = criterion(output, target)
# backward pass: compute gradient of the loss with respect to model parameters
loss.backward()
# perform a single optimization step (parameter update)
optimizer.step()
# update training loss
train_loss += loss.item()*data.size(0)
# print(((output.squeeze() > 0.5) == target.byte()).sum().item() / target.shape[0])
######################
# validate the model #
######################
model.eval()
for data, target in test_loader:
# move tensors to GPU if CUDA is available
if train_on_gpu:
data, target = data.cuda(), target.cuda()
# forward pass: compute predicted outputs by passing inputs to the model
target = target.float()
output = model(data)
# calculate the batch loss
loss = criterion(output, target.view_as(output))
# update average validation loss
valid_loss += loss.item()*data.size(0)
t = Variable(torch.FloatTensor([0.5])) # threshold
out = (output > t.cuda(async=True)).float() * 1
# print(out)
equals = target.float() == out.t()
# print(equals)
#print(torch.sum(equals))
accuracy += (torch.sum(equals).cpu().numpy())
# print(equals)
# print(target)
# calculate average losses
train_loss = train_loss/len(train_loader.dataset)
valid_loss = valid_loss/len(test_loader.dataset)
accuracy = accuracy/len(test_loader.dataset)
# print training/validation statistics
print('Epoch: {} \tTraining Loss: {:.6f} \tValidation Loss: {:.6f} \tAccuracy: {:.6f} ' .format(
epoch, train_loss, valid_loss, accuracy))
# save model if validation loss has decreased
if valid_loss <= valid_loss_min:
print('Validation loss decreased ({:.6f} --> {:.6f}). Saving model ...'.format(
valid_loss_min,
valid_loss))
torch.save(model.state_dict(), 'my:model.pt')
valid_loss_min = valid_loss