In this lecture, we are going to begin discussing code preparation in preparation for our CNN notebook,
this lecture will focus specifically on how we're going to build a model since as we move to more and
more complicated architectures, we'll need more and more sophisticated ways of building models.
There will be two major components of this lecture.
First, as you know, the critical new piece of math that makes an Anand into a CNN is convolution.
So we'll see how to use the convolution module in.
Second, we'll need to integrate this convolution module into the neural network.
I'm going to show you two ways of doing this, but the highlight will be the object oriented method
of building pocketwatch models.
So if you don't remember your object oriented programming from your first year programming class, now
would be the time to crack open your old textbook and reacquaint yourself with those concepts.
So, number one, we want to look at the convolution module, the module we need is called confused.
And on this slide, what I want to do is highlight its arguments and relate them to the math that we
already learned.
As you know, the main parameter in convolution is the filter or the kernel, which is a four dimensional
tensor composed of the number of input channels, the number of output channels and the kernel height
and width.
Recall that the number of channels is also known as the number of feature maps.
In case you're using different terminology.
Because we usually have the colonel height equal to the colonel with we can just specify it as a single
number, which we usually do, OK, when we talk about it in math.
If you wanted to have your colonel height different from your colonel with, you could also specify
it as a tuple.
In modern, deep learning, most of the time, you'll see kernels of size three, although in the old
days you'd also see kernels of size seven and kernels of size five.
Notice how the size is typically odd.
You'll be able to deduce why that is the case after the next lecture.
So that takes care of the first three arguments.
The last relevant argument for us is the stride which controls the step size when you move the kernel
across the input image.
So why don't we use continuity and not kind of one, your kind of 3D, as you know, color images are
three dimensional, eight by with by color?
Well, it's tudy because of the color dimension of an image is not a spatial dimension.
The signal doesn't flow in that direction.
It's also possible to have one de convolutions and three convolutions using the common one B and the
con three delayers, respectively.
So, for example, if you're looking at a signal that varies with time, that would be a one B convolution.
If you're looking at a video, for example, that would be a 3D convolution.
That's because height and width are the first two spatial dimensions and time is a third dimension.
It's also possible to have objects that have three spatial dimensions, height with and depth instead
of pixels.
We have voxels.
You might encounter these.
If you look at something like medical imaging data, by the way, you might be wondering where the word
voxel comes from.
Well, it's pretty obvious that it's analogous to the word pixel by pixel is actually a short form of
the phrase picture element, and thus voxel is the short form of the phrase volume element in any case.
Now we can say that we fully understand at the confused layer so we can move on to asking how do we
include this in a neural network?
Let's now talk about the concept of inheritance pie, which models are all based on modules, and I've
probably used that word a few times throughout the course without really explaining what they are.
Well, a module is the base class that all other modules inherit from inheritance implies an is a relationship.
For example, the linear module, which is the first one we saw in this course, inherits from the module
class.
That means it is a module.
Similarly, the rescue module is also a module.
Similarly, the sequential module is also a module.
This might strike you as surprising because these three things are kind of very different from each
other.
So even though sequential looks like a wrapper around a list of modules, it was also itself a module.
So when you combine a bunch of modules to build a model, that model is itself a module.
This implies that when we create our own custom models, they are also going to be modules and we are
going to inherit from the module class.
So when I said earlier that pie talk is all about composing models from building blocks, well, modules
are those building blocks.
One interesting consequence of everything being a module and models being modules is that there this
hierarchical structure, the first model we saw in this course was just a linear module.
Then we saw that we could stack linear layers together in a sequential object, which is a module of
modules.
That's also a model.
Later, you'll see that we can repeat this pattern so that our model is a module of modules of modules.
So what we've learned is that a module is a model, but a module of modules can also be a model, as
can a module of modules of modules and so on.
By taking the perspective that everything is a module building complex, things becomes easier because
you only have to look at your current level of abstraction.
And no matter how high level that may be, you're still just working with modules.
So why might we want to build a custom model instead of just doing what we've been doing so far?
Well, sometimes we need to do an operation that is not a module.
For example, you know that the interface between the convolution layers and the dense layers in a neural
network is a flatten.
So after all the convolutions and before all the dense layers, we must flatten the data so that it
fits into those respective layers at the boundary between these two different kinds of layers.
The output of a convolution is an image, while a dense layer expects an input vector.
Now, although PI does have a flattened layer, you might wonder what if it didn't exist or what if
some other operation you wanted to do it didn't exist.
In that case, you could build a custom model in the case of flattened.
We know that we can always just use the view function to reshape an image back into a batch of vectors.
In fact, not even one year ago, counting from the time this course was being made, there was no flattened
layer and pi tausche.
So you had to build a custom model.
So you're lucky in that sense today, a flattened layer exists, which makes things easier for you,
but at the same time there are still many things you might want to do, whether it does not exist.
A Pribyl layer for you.
As a side note, I commonly referred to these objects as layers, even though in pie Tahj they are technically
called modules.
Layer is a better visual term in my opinion, since a neural network is made of layers.
It's just easier to understand and see it in your mind.
So please don't get confused when I use the words layer and module interchangeably in the context of
PI talk.
In any case, I hope it's clear why we need custom models when we have all the layers or modules we
need and they all occur sequentially in our model, which is not always the case, by the way, then
we can wrap them up in a sequential, as we've been doing so far.
But if we want to do something more complex, then we need to build a custom model that inherits from
the module class.
Introducing this idea early in the context of CNN is nice because it allows you to compare both approaches,
the easy approach is to do what we've already been doing, which is to build a sequential model that
wraps up all the layers we want to apply in sequential order.
The less easy approach is to build a custom model, but doing it both ways allows you to see the equivalence
between the two and hopefully that makes building custom models less intimidating than it would be otherwise.
In addition, it's also a nice history lesson because less than just one year ago, you wouldn't have
had this luxury.
OK, so let's start by looking at a simple model we've already seen, and again, just to recap the
simplest CNN we can make looks like this.
We have a linear layer followed by a rescue, followed by another linear layer.
No final activation function is needed, as you know.
So what does this look like if we wanted to build a custom model?
So first, we define a class that inherits from an individual inside the constructor, we define all
of our sub modules or layers.
These are the two linear layers and the role.
You notice that all the layers in the sequential model are still defined in the constructor of the custom
model.
We assign these to instance variables so that they can be accessed from other methods, specifically
the forward function, as you can see, the forward function is where we actually apply the operations
defined by the layers we created.
This is just like the simple linear regression model, when we create the linear regression model,
we say variable equals and not linear.
Then when we want to use that model to compute some output, we call that variable object as if it were
a function.
Similarly, inside the Ford function, when we want to compute the output of each of those layers.
We simply call the module objects we created in the constructor.
As an exercise, I would recommend trying to implement your own version of the sequential object using
what you just learned, this would be a great exercise to test your understanding of module inheritance
and building custom models.
So please give it a try.
So at this point, I hope it's easy to see the correspondence between a sequential model and a custom
model that inherits from the module class.
The next thing we're going to do is apply what we learned to build a more complex model, specifically
a convolutional neural network.
As you can see, it's pretty much the same thing just with more layers and different kinds of layers,
as we discussed in the three lectures.
What we have is a sequence of convolution layers, followed by a sequence of dense layers, conveniently
because everything in PI Torture's a module.
We can wrap all the convolution layers in a single sequential object and all the dense layers in a second
sequential object.
That will make it easier to call each of the layers from inside the forward function instead of having
to call each of the layers one at a time, since there might be hundreds of layers, we can just make
a few calls to the sequential objects in addition and note the view function in between the two sequentially.
This helps flatten the data from an image into a feature vector.
You realize something strange about the previous code, which is that I didn't specify the input size
for the first linear layer, to be clear, this is not correct PI syntax.
I'm using this as a placeholder until I explain these concepts in a future lecture.
Remember that in PI Torch there is a level of redundancy when specifying input, size and output size
of each layer, the input size of one layer must match the output size of the incoming layer.
But in the case of convolution, how do we calculate the size of the first linear layer's input?
The answer is we'll have to manually calculate the size of the image as it passes through each convolution.
Then when we flatten the final image, the feature vector dimensionality will simply be the product
of each of the dimensions of the image.
For example, ten by ten by three would become 300.
It's a contrast with our custom model.
I also want to show you how we would build a CNN using the newly created flat layer, which allows us
to make use of the sequential module.
It's pretty easy to see that all the same layers appear.
And the only thing that's different is that instead of explicitly calling the view function, we can
use a flat layer instead.
There is, however, still this small issue of how we calculate the initial input size for the first
linear layer.
We'll discuss that in the next lecture.
So just hold that thought for now.
So what you may have assumed earlier is that building custom models is hard, so maybe it's just better
to use the sequential method for CNN, but in fact, they are nearly equal.
In fact, the hardest part is figuring out this question mark.
What is the initial input size of the first linear layer?
And you can see that either way, whether you build a custom model or just use sequential, you still
have to do this work.
I want to mention one small addition we sometimes make use of in convolutional neural networks, which
is dropout regularisation.
If you've studied machine learning before, you may have heard of concepts such as L2 and L1 Regularisation,
which aren't really used that often in deep learning anymore.
Instead, dropout regularisation is used more commonly.
My goal isn't to get in-depth about dropout in this course because I already have a course for that.
That describes it in detail.
Instead, I'll give you a one line summary, which is that by dropping random notes in a neural network
during training, we make the neuron network less dependent on any particular input feature, which
helps to spread out the influence of each input.
This is similar to what L1 and L2 regularisation try to do.
In Pittsburgh, using dropout is as simple as including a dropout layer and specifying the probability
of dropping a note during training, usually dropout is used between dense layers, but not with convolutions.
Sometimes you'll see them used in Arnon's as well, which you'll learn about in another section.
One interesting discussion I've seen pop up here and there is whether or not you should use dropout
regularisation in the convolutional leers.
While the Torch API lets you do this, it might not necessarily be a good idea, remember that Convolution
is Paddon finding it's looking for a specific stroke or edge.
If you suddenly remove half the pixels from an image, is the stroke still visible?
Can it still be considered the stroke that we are looking for?
Personally, I lean more towards no, but I've seen a few people use drop out in their convolution letters.
Even if it doesn't hurt, if it also doesn't help, then there's no point in using it.
As always, I recommend experimentation or guessing.
So if you're interested in trying it, I would strongly suggest doing so.
OK, so one small note about how to use drop out.
Now the details are outside the scope of this course, but if you're interested in learning more about
how Drop-Out works, please see extra reading in the course repo.
One thing you'll just have to accept on faith for now is that it works differently when you are training
your neural network compared to when you were using it for predictions.
So because of this pie, George has two modes for your model train mode and EVAR mode.
Basically, before you do any training, you should make sure your model is in train mode by calling
model train.
Before you do predictions, you can switch to either mode by calling model eval and note that this also
applies to other layers which behave differently during training, such as Bache Norm, which will be
discussed later.
As a final note for this lecture, I want to give you some foresight into why learning about how to
build custom models is so useful.
We went over one major reason previously, which is that you might need to build a model that contains
operations which are not storage modules.
But so far we've only seen one basic kind of neuron that work in this course, one that encompasses
linear models and ends.
And CNN's that is these models always have one input and one output, and each layer is stacked on top
of the last.
Have you ever considered what if I want my model to have branches?
This by definition is not sequential.
So you can't use and not sequential.
What if I want my model to have multiple inputs?
Same story, can't you?
Sequential because this is not sequential.
What if I want my model to have multiple outputs?
Same story can't use and in that sequential.
Now, you might scoff and say, I will never need these types of models, lazy programmers, just showing
off that he knows all these complicated things, but in fact, you are wrong.
We will be looking at such models later in this course.