Saving validation time inferences

Hi,

I am trying to save images at validation time after almost every epoch to see how my network is learning but I am getting this error.
Here is my code to save images.

def test(epoch, test_loss_list):
		model.eval()
		for batch_idx, (subject) in enumerate(validation_loader):
			image = subject['image_data']
			mask = subject['gt_data']
			if params['cuda']:
				image, mask = image.cuda(), mask.cuda()		  #Loading images into the GPU and ignore the affine.
			with torch.no_grad():
				output = model(image)
#				loss = criterion(output, mask)
				loss = dice_loss(output, mask)
				test_loss_list.append(loss.data.item())
				
#			Saving the image and its mask in its own folder
			save_image(subject['image_name'], image.cpu().detach().numpy(), np.array(list(subject['affine'])), epoch, params['epoch_dir'])
			save_image(subject['image_name'], mask.cpu().detach().numpy(), np.array(list(subject['affine'])), epoch, params['epoch_dir'], mask = True)

			if batch_idx % int(params['log_interval']) == 0:
				print('Test Epoch: {} [{}/{} ({:.0f}%)]\tAverage DICE Loss: {:.6f}'.format(
					epoch, batch_idx * len(image), len(validation_loader.dataset),
					100. * batch_idx / len(validation_loader), loss.data.item()))
		for param_group in optimizer.param_groups:
			print("Learning rate: ", param_group['lr'])
		sys.stdout.flush()

	def save_image(image_name, image, affine, epoch, folder, mask = False):
		"""
		parameters:
		image_name : takes in a string of the image name
		image : expecting a numpy array
		affine : expecting a numpy affine
		epoch : the epoch count whichever you're running from
		folder : the epoch where stuff is gonna be stored in
		"""
		c = nib.Nifti1Image(image, affine)
		os.mkdir(os.path.join(folder, epoch, image_name))
		if mask == True:
			c = np.array(c, dtype = np.int8)
			nib.save(c, os.path.join(folder, epoch, image_name, image_name + '_mask.nii.gz'))
		else:
			nib.save(c, os.path.join(folder, epoch, image_name, image_name + '.nii.gz'))

		return

This is the error generated

save_image(subject['image_name'], image.cpu().detach().numpy(), np.array(list(subject['affine'])), epoch, params['epoch_dir'])

ValueError: only one element tensors can be converted to Python scalars

Can anyone tell me where I may be going wrong?

Could you post the whole stack trace so that we can have a look?

The stack trace

    runfile('/somestuff/pytorch_projects/trainer.py', wdir='/somestuff/pytorch_projects')

  File "/home/someone/anaconda3/envs/pytorch/lib/python3.6/site-packages/spyder_kernels/customize/spydercustomize.py", line 786, in runfile
    execfile(filename, namespace)

  File "/home/someone/anaconda3/envs/pytorch/lib/python3.6/site-packages/spyder_kernels/customize/spydercustomize.py", line 110, in execfile
    exec(compile(f.read(), filename, 'exec'), namespace)

  File "/somestuff/pytorch_projects/trainer.py", line 318, in <module>
    main()

  File "/somestuff/pytorch_projects/trainer.py", line 298, in main
    test(i, test_loss_list)

  File "/somestuff/pytorch_projects/trainer.py", line 252, in test
    save_image(subject['image_name'], image.cpu().detach().numpy(), np.array(list(subject['affine'])), epoch, params['epoch_dir'])

ValueError: only one element tensors can be converted to Python scalars

Thanks for the information!
That doesn’t really clear things up, so could you please print the shapes and values of each argument you are passing?

print(subject['image_name'])
print(image.cpu().detach().numpy().shape)
...
subject['image_name']  #this is a string, at least that's what my dataloader is returning
image                  #this is a tensor object of shape [1, 128, 128, 128]

I am new to Pytorch so it is hard to figure this out on how to detach and save it.
Here is my dataloader object

class SomethingDataset(Dataset):
    def __init__(self, csv_file, root_dir):
        self.df = pd.read_csv(csv_file, header = None)
        self.root = root_dir
        
    def __len__(self):
        return len(self.df)
    
    def __getitem__(self, subejct_id):
#        folder_path = self.df[subject_id, 0]
        image_name = self.df.iloc[subject_id, 0]
        image_path = os.path.join(self.df.iloc[subject_id, 1])
        gt_path = os.path.join(self.df.iloc[subject_id, 2])
        image = nib.load(image_path)
        gt = nib.load(gt_path)
        image_data = np.reshape(image.get_fdata().astype(np.float32), (1, 128, 128, 128))
        gt_data = np.reshape(gt.get_data().astype(np.float32), (1, 128, 128, 128))
        affine = image.affine
        sample = {'image_name':image_name, 'image_data':image_data, 'gt_data':gt_data, 'affine':affine}
        return sample

What do the other arguments print out ( np.array(list(subject['affine'])), epoch, params['epoch_dir'])?
Although your image dimension look strange, I assume nib.Nifti1Image should handle it.
Could you try to debug your code line by line? E.g. I’m not sure if nib.Nifti1Image takes images in this shape or without the batch dimension, so you could try to call image = image.squeeze() before casting it.

1 Like

The Batch Dimension is such a big problem while saving the images. Thank you for the hint. I will try to run this and update soon.