Hi,
I’m working on a 3-class classifier, and a s a base i started with a simple 2 class one. I’ve been having strange performances when trying to use Sigmoid (i think that is used for binary classification), and errors while trying nn.LogSoftmax(dim=-1).
Anyways, i’d like to know what exactly are the things i’ll have to change and how to adapt the 2 class classifier into a 3 class one.
Here’s my model
model = nn.Sequential(
nn.Conv2d(3, 64, kernel_size=3),
nn.ReLU(),
nn.MaxPool2d(2),
nn.Conv2d(64, 128, kernel_size=3),
nn.ReLU(),
nn.MaxPool2d(2),
nn.Conv2d(128, 256, kernel_size=3),
nn.ReLU(),
nn.MaxPool2d(2),
nn.Conv2d(256, 256, kernel_size=3),
nn.ReLU(),
nn.MaxPool2d(2),
nn.Flatten(),
nn.Linear(7 * 7 * 256, 512),
nn.ReLU(),
nn.Linear(512, 2),
nn.LogSoftmax
)
model.to(device)
optimizer = optim.Adam(model.parameters(), lr=0.001)
loss_fn = nn.BCELoss()
transform = transforms.Compose([
transforms.Resize(150), # Resize the short side of the image to 150 keeping aspect ratio
transforms.CenterCrop(150), # Crop a square in the center of the image
transforms.ToTensor(), # Convert the image to a tensor with pixels in the range [0, 1]
])
batch_size = 64
class AverageMeter(object):
"""Computes and stores the average and current value"""
def __init__(self):
self.reset()
def reset(self):
self.val = 0
self.avg = 0
self.sum = 0
self.count = 0
def update(self, val, n=1):
self.val = val
self.sum += val * n
self.count += n
self.avg = self.sum / self.count
def train_model(model, optimizer, loss_fn, train_loader, val_loader, epochs):
train_accuracies, train_losses, val_accuracies, val_losses = [], [], [], []
val_loss = AverageMeter()
val_accuracy = AverageMeter()
train_loss = AverageMeter()
train_accuracy = AverageMeter()
for epoch in range(epochs):
# train
model.train()
train_loss.reset()
train_accuracy.reset()
train_loop = tqdm(train_loader, unit=" batches") # For printing the progress bar
for data, target in train_loop:
train_loop.set_description('[TRAIN] Epoch {}/{}'.format(epoch + 1, epochs))
data, target = data.float().to(device), target.float().to(device)
target = target.unsqueeze(-1)
optimizer.zero_grad()
output = model(data)
loss = loss_fn(output, target)
loss.backward()
optimizer.step()
train_loss.update(loss.item(), n=len(target))
pred = output.round() # get the prediction
acc = pred.eq(target.view_as(pred)).sum().item() / len(target)
train_accuracy.update(acc, n=len(target))
train_loop.set_postfix(loss=train_loss.avg, accuracy=train_accuracy.avg)
train_losses.append(train_loss.avg)
train_accuracies.append(train_accuracy.avg)
# validation
model.eval()
val_loss.reset()
val_accuracy.reset()
val_loop = tqdm(val_loader, unit=" batches") # For printing the progress bar
with torch.no_grad():
for data, target in val_loop:
val_loop.set_description('[VAL] Epoch {}/{}'.format(epoch + 1, epochs))
data, target = data.float().to(device), target.float().to(device)
target = target.unsqueeze(-1)
output = model(data)
loss = loss_fn(output, target)
val_loss.update(loss.item(), n=len(target))
pred = output.round() # get the prediction
acc = pred.eq(target.view_as(pred)).sum().item() / len(target)
val_accuracy.update(acc, n=len(target))
val_loop.set_postfix(loss=val_loss.avg, accuracy=val_accuracy.avg)
val_losses.append(val_loss.avg)
val_accuracies.append(val_accuracy.avg)
return train_accuracies, train_losses, val_accuracies, val_losses
epochs = 60
train_accuracies, train_losses, val_accuracies, val_losses = train_model(model, optimizer, loss_fn, train_loader, val_loader, epochs)
torch.save(model.state_dict(), 'Types_of_lane_small_3_class.pt')
np.savez('history_Types_of_lane_small_3_class.npz', train_accuracies=train_accuracies, train_losses=train_losses, val_accuracies=val_accuracies, val_losses=val_losses)
epochs = range(len(train_accuracies))
plt.plot(epochs, train_accuracies, 'b', label='Training acc')
plt.plot(epochs, val_accuracies, 'r', label='Validation acc')
plt.title('Training and validation accuracy')
plt.legend()
plt.figure()
plt.plot(epochs, train_losses, 'b', label='Training loss')
plt.plot(epochs, val_losses, 'r', label='Validation loss')
plt.title('Training and validation loss')
plt.legend()
plt.show()
I’m getting this error:
/home/env2/lib/python3.6/site-packages/torch/nn/modules/container.py:100: UserWarning: Implicit dimension choice for log_softmax has been deprecated. Change the call to include dim=X as an argument.
input = module(input)
/home/env2/lib/python3.6/site-packages/torch/nn/modules/loss.py:498: UserWarning: Using a target size (torch.Size([64, 1])) that is different to the input size (torch.Size([64, 2])) is deprecated. Please ensure they have the same size.
return F.binary_cross_entropy(input, target, weight=self.weight, reduction=self.reduction)
Traceback (most recent call last):
File "Model3class.py", line 264, in <module>
train_accuracies, train_losses, val_accuracies, val_losses = train_model(model, optimizer, loss_fn, train_loader, val_loader, epochs)
File "Model3class.py", line 226, in train_model
loss = loss_fn(output, target)
File "/home/env2/lib/python3.6/site-packages/torch/nn/modules/module.py", line 532, in __call__
result = self.forward(*input, **kwargs)
File "/home/env2/lib/python3.6/site-packages/torch/nn/modules/loss.py", line 498, in forward
return F.binary_cross_entropy(input, target, weight=self.weight, reduction=self.reduction)
File "/home/env2/lib/python3.6/site-packages/torch/nn/functional.py", line 2070, in binary_cross_entropy
"!= input nelement ({})".format(target.numel(), input.numel()))
ValueError: Target and input must have the same number of elements. target nelement (64) != input nelement (128)