At least your training curve seems more consistent now, which is a good news! I don’t understand the validation curve, when you do this (your snipped of code, no modification from my side here):
for idx in range(EPOCHS):
  
  model.train()
  
  # Get images and transfer to GPU
  image   = image
  heatmap = heatmap
  
  optimizer.zero_grad()
  output = model(image)
  loss   = criterion(output,heatmap)
  loss.backward()
  optimizer.step()
  
  curr_trloss = loss.item()
  # Print losses 
  print(f"Training loss {idx}:",curr_trloss/1)
        

# Evaluation loop
  model.eval()
  with torch.no_grad():
    # Get images and transfer to GPU
    image   = image
    heatmap = heatmap
    
    output = model(image)
    loss   = criterion(output,heatmap)
    curr_valoss = loss.item()
    
  print(f"Validation loss {idx}:",curr_valoss/1)
  print(" ")
  tr_losses.append(curr_trloss/1)
  val_losses.append(curr_valoss/1)

The during both the training phase and evaluation phase you are using the same input image and target heatmap. So I don’t get why the validation loss is not equal to the training loss … Are you using this snipped, or running something different?