human
I am working on the file "Sessions/Session14/Day3/IntroductionToVariationalAutoencoders_solutions.ipynb".
The first task is:
A few things you might have noticed and that can be useful to keep in mind:

The model expects a single precision input. You can change the type of a tensor with tensor_name.type(), where tensor_name is the name of your tensor and type is the dtype. For typecasting into single precision floating points, use float(). A numpy array is typecasted with array_name.astype(type). For single precision, the type should be np.float32.
Before we analyze tensors we often want to convert them to numpy arrays with tensor_name.numpy()
If pytorch has been tracking operations that resulted in the current tensor value, you need to detach the tensor from the graph before you can transform it into a numpy array: tensor_name.detach(). Scalars can be detached with scalar.item()
If you tensor is currently on the GPU, you can bring it onto the CPU with tensor_name.cpu()

Variational Autoencoder
Your task today is to transform the above Autoencoder into a Variational Autoencoder. You can follow either follow my Step-by-Step instructions or do it your way (there's more than one solution). 
We start by modifying the encoder network. Tasks are marked with the keyword #TASK, hints are marked with the keyword #HINT.
STEP 1: Modify the encoder network.
The encoder network is used to characterize the variational distribution q(z|x). Recall that we want q(z|x) to be a Gaussian with diagonal covariance. An N-dimensional Gaussian with diagonal covariance is eqivalent to N independent 1-dimensional Gaussians (where N is the latent size). Each Gaussian is defined by two quantities, its mean and variance (or, if we take the sqrt, the standard deviation).
Can you write Python code for it?
assistant
#Here is the Python code you requested.

class VAEEncoder(nn.Module):

    def __init__(self, seed=853):
        super(VAEEncoder, self).__init__()
        # TASK: change the output size of the encoder network. How many parameters must it return to define q(z|x)?
        self.seed = torch.manual_seed(seed)
        self.fc1 = nn.Linear(INPUT_SIZE,50)
        self.fc2 = nn.Linear(50,LATENT_SIZE*2)

    def forward(self, x):
        # TASK: change the output of the encoder network. Instead of just returning z, it should return z and ...?
        # HINT: Don't forget that the standard deviation/variance must be strictly positive!
        # HINT: You might want to use torch.split(): https://pytorch.org/docs/stable/generated/torch.split.html
        x      = torch.nn.LeakyReLU()(self.fc1(x))
        x      = self.fc2(x)
        mu,std = torch.split(x, LATENT_SIZE,dim=-1)
        std    = torch.exp(std) + 1e-8
        return mu, std