Draw a Similar Image to Do Anomaly Detection

Use Keras to implement GANomaly

Autoencoder is usually used to reduce the data’s dimensions. Data would pass a neural network called an encoder and be projected to lower space, and then pass to another network called a decoder to the original space. By making the decoded output the same as input data, we can verify that the encoded data retains enough information.

However, unlike most statistical methods, autoencoders have a drawback: they only do well when the test data is similar to training data. Instead, GANomaly uses this drawback as an advantage to detect anomalies.

GANomaly trains an autoencoder using the major data, which we call normal data. Thus, when the autoencoder processes data unseen by the model, it will generate, as we expected, data quite different from the original ones. That’s how GANormaly detects data as anomalies.

— Keras Implementation —

Models

First, we use Keras to build models used in GANomaly.

The figure above is GANomaly’s architecture. It has 3 sub-networks, and the first one is an autoencoder, which is used to compress the image to a latent vector in the lower dimension and then extract it to the original size. We would separate the encoder from the autoencoder to simplify the calculation of loss functions.

When we implement an encoder, we have to notice that we should compress images to a space that is small enough. Otherwise, it would be too easy to generate origin images back, then we cannot implement GANomaly successfully.

Then, we build a complete generator. First, pass the input layer to the encoder and then build the layers of the decoder.

Then, we build the second encoder which has the same structure as the one in the generator. It is used to encode images from the generator. We would like the latent vector of origin images and generated images to be as similar as possible.

The last one is the feature extractor using convolution layers to get features of images.

Loss

After we build models, we can build loss functions now. GANomaly uses 3 loss functions to update the generator. The first one is Adversarial loss to fool the discriminator. However, it is different from general GAN. It makes the discriminator extract the same features from the original and generated images instead of predicting generated images as real images.

Thus, Adversarial loss is the L2 distance between features of the original and generated images.

Keras’s custom layer implements this loss using the following codes: The layer accepts 2 inputs: the training data x[0], and the generated result x[1].

The second is the Content loss, the L1 loss between original and generated images. Although Adversarial loss can help the generator generate images similar to training data, we want the generated images to be similar to the corresponding original images. Thus, we also add Content loss as below to update generator.

The third one is Encoder loss, which is L2 loss between latent vectors. Since we would use the distance between latent vectors to compute scores, we’d like to minimize the distance between original and generated images of normal data during training.

It can be written using the following codes:

Finally, we can combine these losses to train the generator.

Because the output is already lost, we must implement a custom loss function to return y_pred directly.

Discriminator

The goal of the discriminator is to make the autoencoder generate images that look like normal data. Even images decoded from encoded abnormal data will look like normal data, so it would differ from the original data.

To implement it, we have to connect a one-node dense layer to the feature extractor network and use sigmoid to output the probability of whether the image is normal. We use binary_crossentropy as the loss function, which is the same as general GANs.

Training

Since we don’t need any labels, we can implement a data generator to return 3 groups of dummy labels whose length is the same as the batch size of the training data.

As general GANs, we use train_on_batch to train the generator and discriminator by turns.

In each iteration, we first call __next__ of the data generator to obtain a batch of x and y, then train the discriminator. When training the discriminator, we first get generated images, fake_x, and create labels for the discriminator. Then, we pass them to the train_on_batch function of the discriminator.

To train the generator, we pass what we obtain from the data generator.

Evaluation

After hundreds of iterations, we can predict whether the new image from test data is normal by the following formula.

The formula is the L1 distance between the original image encoded by the first encoder and the encoded generated image by the second encoder. Then, we use MinMaxScale to scale scores between 0 and 1 as the probability of anomalies.

However, we found that we can not get good results if we use the formula directly. Even though the generated image differs greatly from the origin, the distance between them is still small. Thus, we use the first encoder to get the latent vectors from both images instead.

— Result —

These are the scores when we use the MNIST dataset. We only use handwriting of 1 as training data and test the model with 1000 images, including 1 and 7. The blue points are 1, and the pink points are 7. We can get good results when the threshold is around 0.25.

Let’s show the images before (left) and after (right) autoencoder. We can see that the 7 will look like 1 after being decoded by the autoencoder. That’s why we can use the difference between the 2 images to determine which is an anomaly.

GANomaly is a simple method to detect anomalies by adjusting how to compute scores. We only need normal data to train the model.

— Code—

https://github.com/leafinity/keras_ganomaly/blob/master/ganomaly.ipynb

— Reference —

[1] GANomaly: Semi-Supervised Anomaly Detection via Adversarial Training

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top