* The custom loss function for VAE. * * @param {tf.tensor} inputs the encoder inputs a batched image tensor * @param {[tf.tensor]} outputs the vae outputs, [decoderOutput, * ...encoderOutputs] * @param {number} vaeOpts.originalDim number of dimensions in the original data
(inputs, outputs)
| 177 | * @param {number} vaeOpts.originalDim number of dimensions in the original data |
| 178 | */ |
| 179 | function vaeLoss(inputs, outputs) { |
| 180 | return tf.tidy(() => { |
| 181 | const originalDim = inputs.shape[1]; |
| 182 | const decoderOutput = outputs[0]; |
| 183 | const zMean = outputs[1]; |
| 184 | const zLogVar = outputs[2]; |
| 185 | |
| 186 | // First we compute a 'reconstruction loss' terms. The goal of minimizing |
| 187 | // this term is to make the model outputs match the input data. |
| 188 | const reconstructionLoss = |
| 189 | tf.losses.meanSquaredError(inputs, decoderOutput).mul(originalDim); |
| 190 | |
| 191 | // binaryCrossEntropy can be used as an alternative loss function |
| 192 | // const reconstructionLoss = |
| 193 | // tf.metrics.binaryCrossentropy(inputs, decoderOutput).mul(originalDim); |
| 194 | |
| 195 | // Next we compute the KL-divergence between zLogVar and zMean, minimizing |
| 196 | // this term aims to make the distribution of latent variable more normally |
| 197 | // distributed around the center of the latent space. |
| 198 | let klLoss = zLogVar.add(1).sub(zMean.square()).sub(zLogVar.exp()); |
| 199 | klLoss = klLoss.sum(-1).mul(-0.5); |
| 200 | |
| 201 | return reconstructionLoss.add(klLoss).mean(); |
| 202 | }); |
| 203 | } |
| 204 | |
| 205 | module.exports = { |
| 206 | vae, |
no outgoing calls
no test coverage detected