Using a single CNN to make inference on my dataset trains as expected with around 85% accuracy. I wanted to implement a siamese network to see if this could make any improvements on the accuracy. However, the training accuracy just fluctuates from 45% top 59% and neither the training loss or test loss seem to move from the initial value.
I tried using contrastive loss, but didn’t know how to get an accuracy with this method, so I switched to using BCELoss. The motivation for using BCE, instead of constrastive loss, came from here. Below is my CNN model I modified for the siamese network
class ConvNet(nn.Module):
def __init__(self):
super(ConvNet, self).__init__()
self.conv1 = nn.Conv2d(in_channels = 1, out_channels = 32, kernel_size = 5)
self.pool = nn.MaxPool2d(2,2)
self.conv2 = nn.Conv2d(in_channels = 32, out_channels = 64, kernel_size = 3)
self.conv3 = nn.Conv2d(in_channels = 64, out_channels = 128, kernel_size = 3)
self.fc_drop = nn.Dropout(p = 0.5)
#global average pooling layer
self.gap = nn.AdaptiveAvgPool2d((20,1))
self.fc1 = nn.Linear(128*20, 512)
self.fc2 = nn.Linear(512, 128)
self.fc3 = nn.Linear(256, 1)
def forward_once(self, x):
x = self.pool(F.relu(self.conv1(x)))
x = self.pool(F.relu(self.conv2(x)))
x = self.pool(F.relu(self.conv3(x)))
# prep for linear layer
# flattening
# x = x.view(x.size(0), -1)
x = self.gap(x)
x = x.view(x.size(0), -1)
# two linear layers with dropout in between
x = F.relu(self.fc1(x))
x = self.fc_drop(x)
x = F.relu(self.fc2(x))
# x = self.fc_drop(x)
# x = self.fc3(x)
return x
def forward(self, in1, in2):
out1 = self.forward_once(in1)
out2 = self.forward_once(in2)
out1 = self.fc_drop(out1)
out2 = self.fc_drop(out2)
x = torch.cat((out1,out2),1)
x = self.fc3(x)
x = torch.sigmoid(x)
return x
## TRAINING
model = ConvNet()
# Loss and optimizer
# criterion = ContrastiveLoss()
criterion = nn.BCELoss()
optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate, momentum = 0.9)
# Train the model
for epoch in range(num_epochs):
accuracy = 0
running_loss = 0
for images1, images2, labels in train_loader:
# Run the forward pass
outputs = model(images1, images2)
labels = labels.float()
labels = labels.unsqueeze(1)
loss = criterion(outputs, labels)
loss_list.append(loss.item())
# Backprop and perform SGD optimisation
optimizer.zero_grad()
loss.backward()
optimizer.step()
running_loss += loss.item()
else:
test_loss = 0
accuracy = 0
correct = 0
with torch.no_grad():
model.eval()
for images1, images2, labels in test_loader:
outputs = model(images1, images2)
labels = labels.float()
labels = labels.unsqueeze(1)
total = labels.size(0)
test_loss += criterion(outputs, labels)
for j in range(outputs.size()[0]):
if outputs[j] <= 0.5 and labels[j] == 0:
correct += 1
if outputs[j] > 0.5 and labels[j] == 1:
correct += 1
accuracy += correct/total
correct = 0
acc_list.append(correct / total)
model.train()
And the output is:
Epoch: 1/500… Training Loss: 0.693… Test Loss: 0.692… Test Accuracy: 0.562
Epoch: 2/500… Training Loss: 0.694… Test Loss: 0.693… Test Accuracy: 0.508
Epoch: 3/500… Training Loss: 0.694… Test Loss: 0.694… Test Accuracy: 0.453
Epoch: 4/500… Training Loss: 0.694… Test Loss: 0.692… Test Accuracy: 0.535
Epoch: 5/500… Training Loss: 0.694… Test Loss: 0.693… Test Accuracy: 0.480
Epoch: 6/500… Training Loss: 0.694… Test Loss: 0.692… Test Accuracy: 0.535
Epoch: 7/500… Training Loss: 0.694… Test Loss: 0.693… Test Accuracy: 0.480
Epoch: 8/500… Training Loss: 0.694… Test Loss: 0.692… Test Accuracy: 0.535
Epoch: 9/500… Training Loss: 0.693… Test Loss: 0.692… Test Accuracy: 0.535
Epoch: 10/500… Training Loss: 0.693… Test Loss: 0.692… Test Accuracy: 0.562
Epoch: 11/500… Training Loss: 0.693… Test Loss: 0.693… Test Accuracy: 0.480
Is there any glaringly obvious mistakes in my code or my approach that you can see? Any input is greatly appreciated. Apologies for any formatting errors. First time using this discussion board.