class Sampler(): def __init__(self, inputDim=1, outputDim=1, optimizer=Adam()): self.inputDim = inputDim self.outputDim = outputDim self.mean = Dense(self.inputDim, self.outputDim, activation=Identity(), optimizer=copy.copy(optimizer)) self.logVar = Dense(self.inputDim, self.outputDim, activation=Identity(), optimizer=copy.copy(optimizer)) def feedforward(self, input): self.latentMean = self.mean.feedforward(input) self.latentLogVar = self.logVar.feedforward(input) self.epsilon = np.random.standard_normal(size=(self.outputDim, input.shape[1])) self.sample = self.latentMean + np.exp( self.latentLogVar / 2.) * self.epsilon return self.sample def backpropagate(self, lastGradient): gradLogVar = {} gradMean = {} tmp = self.outputDim * lastGradient.shape[1] # KL divergence gradients gradLogVar["KL"] = (np.exp(self.latentLogVar) - 1) / (2 * tmp) gradMean["KL"] = self.latentMean / tmp # MSE gradients gradLogVar["MSE"] = 0.5 * lastGradient * self.epsilon * np.exp( self.latentLogVar / 2.) gradMean["MSE"] = lastGradient # backpropagate gradients thorugh self.mean and self.logVar return self.mean.backward(gradMean["KL"] + gradMean["MSE"]) + self.logVar.backward( gradLogVar["KL"] + gradLogVar["MSE"]) def getKLDivergence(self, output): # output.shape[1] == batchSize return -np.sum(1 + self.latentLogVar - np.square(self.latentMean) - np.exp(self.latentLogVar)) / (2 * self.outputDim * output.shape[1])