One-hot encoded targets wouldn’t work with nn.CrossEntropyLoss, so I’m not sure why
loss = criterion(outputs, labels)

doesn’t raise an error.
Could you print the shapes of both tensors before passing them to the criterion?
Also, check the shapes and values of epoch_loss and epoch_acc to avoid accidental broadcasting etc.
How did you define dataloaders, if you are not using the built-in DataLoader class?