At this point.
One question you may ask yourself is we are having this, um, outputs which are being generated from
the making use of this Z vector right here.
But how does the Z vector this Z vector here?
Of the different images vary with the particular digits in those images.
So how does a vector in say let's take this for example in six vary with that of zero uh, with two,
uh, and all other digits.
To experiment with this would copy out this code we had already and then get back here and now try to
pass in the different digits into our encoder and then plot out the positions of.
Z vectors and then see whether there is some correlation with the Z vector position and the input we
have here.
Write your other specific input digit.
That said, we're going to now make use of this.
So we have that.
And then here we're going to have our Y train.
So this time around we'll be needing the Y train because we need to know exactly what digit we're dealing
with, unlike here, where we just needed to have the input images.
Okay, so that's it.
We have X train, y train, we're going to reload this and then we do the usual pre-processing.
From here, we run the cell and then we move straight away to pass in this images in our encoder.
Now similar to what we had here.
Now we're going to be making use of our layers and then picking out the first index.
So here we have our output.
We could call this or basically we have Z, then we have the mean and the variance and then this is
equal.
Let's copy this here.
Um, there we go.
We have that.
Then this is now one.
See that?
And then from here we pass in this x train.
So that's it.
We pass in the X train and then we could go ahead to start with the plotting, uh, plot figure.
Specify the figure size.
Figure size equals 12 by 12.
There we go.
And then we do a scatter plot.
Now, the scatter plot will show us the different positions of the values of Z.
That's the.
Z points in a two dimensional space.
Let's take this off.
This different Z points.
And then also we're going to color this such that.
Digits belonging to the same level.
Have the same color.
There we go.
We're going to plot this as our X and then our Y.
So we have that.
And then now we specify this Y train as our labels.
So that's it.
And then we can now go ahead to plot out this color bar and show.
Let's run that.
And here's what we get.
As you could see.
The labels here go from zero right up to nine.
And then you could notice this different clusters we have in here.
See these different clusters?
See that?
This shows that.
The encoder part of our variational auto encoder has been trained such that now it's able to generate
values of Z where.
This point.
Is output at such that two inputs belonging to the same digit will be closer to each other as compared
to two inputs belonging to two different digits.
So what we've been doing so far is we've been training the variational autoencoder model with our own
custom training block.
You see right here, we make use of this gradient tape and we carry out the gradient descent manually
as compared to when you just have, say, model fit and then you pass in your train data set.
And basically, uh, this takes care of doing the training.
Now the advantage of working with this fit method is that it's quite simple to use, but uh, compared
to this custom training loops, it doesn't give you that much freedom.
And that's why we're making use of this, um, gradient tape here to train our model.
Now, with TensorFlow, it's possible to actually get the best of both worlds.
Now, this means that we can be able to train or get this custom training right here and then still
make use of the fit method.
The way this is done is by overriding the trainstep method of our model, which we shall define.
So that said, let's get right here and define this VA model.
Then we go ahead and define this model as we would do with a usual Keras model.
But just as we had done right here, that's in this model we had built here, we need to take into consideration
in our take us argument here the encoder model and the decoder model.
So that's it.
Now, once we have this two models we have here our encoder, which is our encoder model, and we do
the same for the decoder.
Now, once we're done with this decoder, let's type this out.
We have your decoder, Uh, as we're saying, once we're done with this decoder, the next thing we
want to do is define some loss.
So here we have our loss.
Um, it's actually a loss tracker.
Now, we'll get to understand better why we're calling this a loss tracker.
So here we have the average or the mean of the different losses which you shall get.
And then from here, we'll go ahead to this main section where we shall override the Trainstep method.
So, uh, just like, let's add this here, just like we used to working with methods like model, like
the compile method, like the fit method.
Here we have this Trainstep method, which is called each time we call on this fit method right here.
But since we are now going to make use of the default, um, fit or the default trainstep method, we'll
have to override this and write out our own training block, which is basically this block we have here.
So what we could do here is copy this out so we could simply copy this out and then paste it out here.
Now let's just copy all this.
There we go.
And, uh, that's it.
We paste this out.
So here we have our training block.
We'll call this, um, trainstep.
So we override this Trainstep method, which is a keras model method.
So here we have our trainstep.
We're taking in our batch.
Uh, there we go.
And then.
Is going to be similar to what we've had already in the training block.
So you see here we have our Z mean log VAR, which is gotten from the encoder model.
And from here we pass Z and then we obtain Y pred.
We have our Y.
True, we obtain our loss.
We've already defined our custom loss method and that's it.
Then from here, we're going to update our loss metric.
So here we have, um, loss tracker, which we defined already here.
We're going to update its state.
So we update our loss state with the value of this loss.
So that's it.
Now we are going to return the result.
So we have this dictionary, we have loss and then we have our loss tracker dot result.
See that?
We have that.
So there we go.
We have updated our loss, we output the loss.
But one important method we need to call again is the metrics method.
So here we have metrics.
You could define several metrics, but here we just have this loss and then we return our loss tracker.
So we have loss tracker returned.
Now notice how this is actually a list.
So you see, this is a list because we could have, um, say different losses which we could return.
And then we have the property decorator which will place right here.
So once we have this set, you see, we do not need anymore to make use of this or to write this as,
as it was reading.
And so this means that we, we are not going to be writing out, for example, training start for epoch.
This, uh, the training loss is this and all of that.
Now all we need to do is just call on our model.fit method.
So right here, let's do, uh, let's run this first.
Let's run this right here.
There we go.
And then we go ahead.
We're getting an error Now from here we define our var.
So it's quite similar to to what we had already seen here.
See that?
Now we have this Var, which is now this which we've created here.
So let's have that equal var E, and then it takes in the encoder model, encoder model and the decoder
model.
That's it.
So once we have this now we could do just as we are used to doing.
Let's, let's even say model, let's just say model.
And then here we have model.compile as usual, and then here we're going to pass in our optimizer.
So here we have Optimizer.
Uh, guess we define this optimizer already.
So let's check here.
Yeah, we have defined this optimizer.
So here we just have optimizer, um, equal Optimizer, which we've defined already, and then we do
our model.fit.
See that?
So that's all.
We just need to, um, now make or call this fit method.
And then we have our train data set which we pass in the number of epochs.
We'll define this to be 20 and then the batch size, um, equal say 128.
So that's it.
So here, um, unlike before, where we needed, for example, to specify the optimizer in this way
and then actually, uh, get in-depth to understand that this, uh, gradient descent process needs,
for example, the partial derivatives and the trainable weights.
Now you'll see that unlike before, where if you were, for example, needing to make use of some callbacks,
you would have to write that or include that in your with some custom code.
But now all you need to do is just have callbacks.
So we, we, we both will.
Now how to write our own custom training loops while still taking advantage of everything that comes
with the fit method.
So right here you could have some callbacks and that will be it.
Anyway, let's take this off and then let's get back here where there's this slight error.
You see here we have this v dot trainable weights and that.
Now this was in the case where we had defined our this way, we had this model and then get it into
our custom training loop right here.
Let's get down here.
We had to actually, uh, we, the way we got the trainable weights was from our model, which we had
defined.
Now, given that we have this model right here, the way we access this trainable weights is by using
self.
So we have self dot trainable weights.
And then here we have soft, dot trainable weights.
And this is simply possible because we are inheriting from a Keras model which already has this different
attributes which have been defined.
Now, that said, let's run this.
That should be fine.
Training are complete.
You can see that.
Um.
We getting our usual outputs when we making use of the fit method?
And then we could go ahead and start with the testing.
So we run the cells and then in here we have some modifications to make.
So right here or previously we had this layers and the predict and we took in the inputs and we got
some output.
Now here we have our model model dot predict, see that?
But this model is, is a whole model.
So since we want to make use of our decoder, we're going to say model dot, decoder model.
There we go.
Model dot decoder actually dot decoder because here you've defined this decoder attribute.
So we have model dot decoder.
There we go.
Dot predict and that should be fine.
Okay, so let's run this and then see what we get.
There we go.
You see, we have exact same kind of output as when we were having our own custom training loop right
here.
And that's it for this section.
Hope you enjoyed it.
See you in the next section.