Hello.
Today I was performing some experiments using a variational autoencoder. I realized about something quite surprising that I did not expect. Hope someone can help me.
I was sampling from the posterior distribution and wanted to save an image of the latent space. The image on the latent space (which comes from a gaussian distribution) is normalized to fit in range 0-1. I use this code:
mean_p,logvar_p=variatonal.forward(x_test)#encode params
z_lat=sampler([mean_p,logvar_p],'gaussian',mean_p.shape)#sample from gaussian distribution
z_=normalize(z_lat)#normalize latent code
save_image(z_)#save latent code
mean,logvar=reconstruction.sample(z_lat)#decoder parameters
x_=sampler([mean,logvar],decoder_type,mean.shape)#sample from decoder 
x_=normalize(x_)
save_image(x_)	

Normalize is a function that does this (assume batch=100)
def normalize(x_):
	min_val_aux,ind=torch.min(x_.data,1)   
	max_val_aux,ind=torch.max(x_.data,1)
	min_val = torch.zeros(100,1).cuda()
	max_val = torch.zeros(100,1).cuda()                                                     
	min_val[:,0]=min_val_aux                                                          
	max_val[:,0]=max_val_aux 
	a,b=x_.shape
	min_val=min_val.expand(100,b)
	max_val=max_val.expand(100,b)
	
	x_.data=(x_.data-min_val)/(max_val-min_val)
	return x_.data.cpu()

What is incredible is that the function normalize is modifying the content of z_lat!!! so when decoding z_lat I observed mode collapse. At the beginning I though it was because a FC VAE encoder is not expressive enough, however I realized that by taking out the call to z_=normalize(z_lat)#normalize latent code everything works find. Moreover if normalize acts directly on z_lat.data instead of z_lat everything works so it seems something related to autograd. Should not a call to a python function pass the data instead of a pointer to a variable? It seems that autograd pass variable references to functions instead of actually copying data.
I am impressed by this fact.