It can be a bit difficult to vet the timing code without a snippet (e.g., are there appropriate torch.cuda.synchronize calls in appropriate places?). It does look like the dataloader time is still significant, as it is expected to be effectively zero to minimize overhead (it is expected to be zero as it can run independently of and ahead of the current training iteration).