My loss updated but my accuracy not

Dear all.

When i trained my images with Resnet model, my loss in both val and train was updated while my train, val accuracy did not, they stay in the same number. What happens, please help me?

Thank you a lot.

Finished training epoch 0: Train loss: 0.6814049482345581, Train Acc: 59.35077667236328. Val loss: 0.7146084308624268, Val Acc: 60.75581359863281
Finished training epoch 1: Train loss: 0.6787809729576111, Train Acc: 59.35077667236328.  Val loss: 0.7859861254692078, Val Acc: 60.75581359863281
...

Here is my code:

#Create model
model = resnet50(
    num_seg_classes=2,
    no_cuda=False)
 
model = nn.DataParallel(model, device_ids=[0,1,2,3]).cuda()
net_dict = model.state_dict() 

pretrain_path = os.path.join("H:\MinhBPL\ADNIDatabase\MedicalNet_pytorch_files2",
                            "resnet_50.pth")
print ('loading pretrained model {}'.format(pretrain_path))
pretrain = torch.load(pretrain_path)
pretrain_dict = {k: v for k, v in pretrain['state_dict'].items() if k in net_dict.keys()}
net_dict.update(pretrain_dict)
model.load_state_dict(net_dict)

class AverageMeter(object):
    """Computes and stores the average and current value
       Imported from https://github.com/pytorch/examples/blob/master/imagenet/main.py#L247-L262
    """
    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 accuracy(output, target, topk=(1,)):
    """Computes the precision@k for the specified values of k"""
    maxk = max(topk)
    batch_size = target.size(0)

    _, pred = output.topk(maxk, 1, True, True)
    pred = pred.t()
    correct = pred.eq(target.view(1, -1).cuda().expand_as(pred))

    res = []
    for k in topk:
        correct_k = correct[:k].view(-1).float().sum(0)
        res.append(correct_k.mul_(100.0 / batch_size))
    return res

def train(trainloader, model, criterion, optimizer, epoch, use_cuda):
    model.train()
    batch_time = AverageMeter()
    data_time = AverageMeter()
    losses = AverageMeter()
    top = AverageMeter()
    end = time.time()
    print(f'Start training epoch {epoch}')
    for (inputs, targets) in tqdm(trainloader):
        data_time.update(time.time() - end)
        if use_cuda:
            inputs, targets = inputs.cuda(), targets.cuda()
        inputs, targets = torch.autograd.Variable(inputs), torch.autograd.Variable(targets)
        outputs = model(inputs)
        loss = criterion(outputs, targets)
        prec= accuracy(outputs.data, targets.data, topk=(1,))
        losses.update(loss, inputs.size(0))
        top.update(prec[0], inputs.size(0))
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        batch_time.update(time.time() - end)
        end = time.time()
        
    print(f'Finished training epoch {epoch}: Train loss: {losses.avg}, Train Acc: {top.avg}, Batch time: {batch_time} ')
    return (losses.avg, top.avg)

def test(testloader, model, criterion, epoch, use_cuda):
    batch_time = AverageMeter()
    data_time = AverageMeter()
    losses = AverageMeter()
    top = AverageMeter()    
    
    model.eval()
    
    end = time.time()
    print(f'Start val epoch {epoch}')
    with torch.no_grad():
        for (inputs, targets) in tqdm(testloader):
            data_time.update(time.time() - end)
            if use_cuda:
                inputs, targets = inputs.cuda(), targets.cuda()
            inputs, targets = torch.autograd.Variable(inputs, volatile=True), torch.autograd.Variable(targets)
            outputs = model(inputs)
            loss = criterion(outputs, targets)
            prec= accuracy(outputs.data, targets.data, topk=(1,))
            losses.update(loss, inputs.size(0))
            top.update(prec[0], inputs.size(0))
            batch_time.update(time.time() - end)
            end = time.time()
        print(f'Finished training epoch {epoch}: Val loss: {losses.avg}, Val Acc: {top.avg}, Batch time: {batch_time} ')
        return (losses.avg, top.avg)

use_cuda = True
graph_loss = {}
graph_acc = {}
graph_loss['train'] = []
graph_loss['val'] = []
graph_acc['train'] = []
graph_acc['val'] = []

best_acc = 0
for epoch in range(100):
    optimizer = torch.optim.SGD(model.parameters(), lr=0.00001)
    criterion = nn.CrossEntropyLoss()
    train_loss, train_acc = train(train_dataloader, model, criterion, optimizer, epoch, use_cuda)
    test_loss, test_acc = test(val_dataloader, model, criterion, epoch, use_cuda)
    graph_loss['train'].append(train_loss)
    graph_loss['val'].append(test_loss)
    graph_acc['val'].append(train_acc)
    graph_acc['val'].append(test_acc)
    is_best = test_acc > best_acc
    if is_best:
        best_acc = max(test_acc, best_acc)
        saveModel('savedModel')```

Generally speaking if loss and acc for trainning improve but for validation they do not, then somekind of overfitting is happenning. Check that the val dataset is of the same distribution as training set. Also I noticed a very small learning rate, do they suggest that one!? Maybe increasing it can help train faster and validation performance can also improve.

In my case, the loss is reduced but the accuracy is stay at exactly the same value.

That can happen, right? Accuracy is “quantized”: any given prediction is either 0 or 1 (assuming a binary classification). Suppose for a particular sample the label is 1 and your \hat{y} value is 0.61. If you run 10 more iterations and the \hat{y} value becomes 0.70, the loss value will decrease but the accuracy stays the same.

It can happen but in this case, as you could see the accuracy is 59.35077667236328 which is very detailed. So I don’t think the problem is because of that.

That’s your theory. You could prove it by saving and comparing the predictions in the two cases. They’re either the same or they’re not, right? Or you could have switched the same number of samples in each direction. Just count the number of false negatives and false positives in the two cases.