In the last post, we took a look at a simple autoencoder. The autoencoder is a deep learning model that takes in an image and, (through an encoder and decoder), works to produce the same image. In short:
Autoencoder: image -> image
For a discriminator, we are going to focus on only the first half on the autoencoder.
Why only half? We want a different transformation. We are going to want to take an image as input and then do some discrimination of the image and classify what type of image it is. In our case, the model is going to input an image of a handwritten digit and attempt to decide which number it is.
Discriminator: image -> label
As always, with deep learning. To do anything, we need data.
MNIST Data
Nothing changes here from the autoencoder code. We are still using the MNIST dataset for handwritten digits.
The model will change since we want a different output.
The Model
We are still taking in the image as input, and using the same encoder layers from the autoencoder model. However, at the end, we use a fully connected layer that has 10 hidden nodes - one for each label of the digits 0-9. Then we use a softmax for the classification output.
1234567891011121314151617
(def input(sym/variable"input"))(def output(sym/variable"input_"))(defn get-symbol[](as->inputdata;; encode(sym/fully-connected"encode1"{:datadata:num-hidden100})(sym/activation"sigmoid1"{:datadata:act-type"sigmoid"});; encode(sym/fully-connected"encode2"{:datadata:num-hidden50})(sym/activation"sigmoid2"{:datadata:act-type"sigmoid"});;; this last bit changed from autoencoder;;output(sym/fully-connected"result"{:datadata:num-hidden10})(sym/softmax-output{:datadata:labeloutput})))
In the autoencoder, we were never actually using the label, but we will certainly need to use it this time. It is reflected in the model’s bindings with the data and label shapes.
For the evaluation metric, we are also going to use an accuracy metric vs a mean squared error (mse) metric
1
(def my-metric(eval-metric/accuracy))
With these items in place, we are ready to train the model.
Training
The training from the autoencoder needs to changes to use the real label for the the forward pass and updating the metric.
12345678910111213141516
(defn train[num-epochs](doseq [epoch-num(range 0num-epochs)](println "starting epoch "epoch-num)(mx-io/do-batchestrain-data(fn [batch];;; here we make sure to use the label;;; now for forward and update-metric(-> model(m/forward{:data(mx-io/batch-databatch):label(mx-io/batch-labelbatch)})(m/update-metricmy-metric(mx-io/batch-labelbatch))(m/backward)(m/update))))(println {:epochepoch-num:metric(eval-metric/get-and-resetmy-metric)})))
Let’s Run Things
It’s always a good idea to take a look at things before you start training.