Lesson 3: Practical Deep Learning for Coders 2022
Disclaimer: The transcript on this page is for the YouTube video titled "Lesson 3: Practical Deep Learning for Coders 2022" from "Jeremy Howard". All rights to the original content belong to their respective owners. This transcript is provided for educational, research, and informational purposes only. This website is not affiliated with or endorsed by the original content creators or platforms.
Watch the original video here: https://www.youtube.com/watch?v=hBBOjCiFcuo&list=PLfYUBJiXbdtSvpQjSnJJ_PmDQB_VyT5iU&index=3
Hi everybody, and welcome to lesson three of Practical Deep Learning for Coders. We did a quick survey this week to see how people feel that the course is tracking, and over half of you think it's about the right pace. Of the rest, some of you think it's a bit slow and some of you think it's a bit fast. So, hopefully that's about the best we can do generally speaking.
The first two lessons are a little more easy-pacing for anybody who's already familiar with the basic technology pieces, and then the later lessons get more into some of the foundations. Today we're going to be talking about things like matrix multiplications, gradients, calculus, and stuff like that. So, for those of you who are more mathy and less computery, you might find this one more comfortable, and vice versa.
Remember that there is an official course updates thread where you can see all the up-to-date info about everything you need to know, and of course the course website as well. By the time you watch the video of the lesson, it's pretty likely that if you come across a question or an issue, somebody else will have as well. So definitely search the forum and check the FAQs first, and then feel free to ask a question yourself on the forum if you can't find your answer.
One thing I did want to point out, which you'll see in the lesson thread and the course website, is there is also a Lesson Zero. Lesson Zero is based heavily on Radek’s book *Meta Learning*, which internally is based heavily on all the things that I've said over the years about how to learn fast.ai. We try to make the course full of tidbits about the science of learning itself and put them into the course. It's a different course than probably any other you've taken, and I strongly recommend watching Lesson Zero as well. The last bit of Lesson Zero is about how to set up a Linux box from scratch—which you can happily skip over unless that’s of interest—but the rest of it is full of juicy information that I think you'll find useful.
The basic idea of what to do for a fast.ai lesson is to watch the lecture. On video, I generally recommend watching it all the way through without stopping once, and then go back and watch it with lots of pauses, running the notebook as you go. Otherwise, you're kind of running the notebook without really knowing where it's heading, if that makes sense.
When going through the notebooks, there are a few you could try—obviously, there's the book! Going through chapter one and chapter two of the book as notebooks, running every code cell, and experimenting with inputs and outputs helps you understand what's going on. Then try to reproduce those results, and repeat the whole thing with a different dataset. If you can do that last step, that's quite a stretch goal, particularly at the start of the course because there are so many new concepts, but that really shows that you've got it sorted.
For the "reproduce results" step, in the fastbook repository, there is a special folder called `clean`. `clean` contains all of the same chapters of the book, but with all of the text removed—except for headings—and all the outputs removed. This is a great way for you to test your understanding of the chapter: before you run each cell, try to say to yourself, "Okay, what's this for and what's it going to output, if anything?" If you work through that slowly, it's a great approach. Any time you're not sure, you can jump back to the version of the notebook with the text to remind yourself, and then head back over to the clean version.
That's an idea for self-study that a lot of people find really useful. As we've mentioned before, the best kind of study is done, to some extent, with others for most people. Research shows that you're more likely to stick with things if you're doing it as a bit of a social activity. The forums are a great place to find and create study groups, and you'll also find a link on the forums to our Discord server where there are study groups as well. In-person study groups or virtual study groups are a great way to make good progress and find other people at a similar level to you. If there's not a study group going at your level in your area or time zone, create one! Just post something saying, "Hey, let's create a study group."
This week there's been a lot of fantastic activity. I can't show all of it, so I used the summary functionality in the forums to grab all of the things with the highest votes, and I'll quickly show a few of those: - We have a Marvel Detector created this week to identify your favorite Marvel character. - A rock, paper, scissors game where you use pictures of rock, paper, and scissors symbols—and apparently the computer always loses, which is my favorite kind of game. - There is a lot of Elon around, so it's very handy to have an Elon Detector to either find more of him or maybe less of him. - I thought this one was very interesting: can you predict the average temperature of an area based on an aerial photograph? Apparently the answer is yeah, actually you can predict it pretty well! Here in Brisbane, it was predicted to within 1.5°C. I think this student is actually a genuine meteorologist if I remember correctly; he built a cloud detector. - Building on top of the Marvel character theme, my daughter loves this one: "What dinosaur is this?" I feel like there are 10 times more dinosaurs than when I was a kid, so this is very handy. - A "choose your own adventure" game where you choose your path using facial expressions. - A music genre classification project, which is also really cool. - Brian Smith created a Microsoft Power App application that actually runs on a mobile phone. That's pretty cool! Wouldn't be surprised to hear that Brian actually works at Microsoft, so it was also an opportunity to promote his own stuff there. - An art movement classifier that sparked a really interesting discussion on the forum about similarities between different art movements. - A redaction detector project that had a whole tweet thread and blog post—a particularly great piece of work.
Okay, so I'm going to quickly show you a couple of little tips before we jump into the mechanics of what's behind a neural network. I was playing a little bit with how to make your neural network more accurate during the week, and I created this Pet Detector. This pet detector is not just predicting dogs or cats, but what breed it is, which is obviously a much more difficult exercise.
Because I put this out on Hugging Face Spaces, you can download and look at my code. If you click "Files and versions" on the space—which you can find a link to on the forum and the course website—you can see them all and download them to your own computer.
Today I'm using a different platform. In the past, I've shown you Colab, Kaggle, and running stuff on your own computer. Paperspace is another website, but in particular, they have a product called Gradient Notebooks, which is—at least as I speak—by far the best platform for running this course and doing experimentation.
It's a real computer you're using, not like that kind of weird virtual version of things that Kaggle or Colab has. If you click on the button down at the bottom, you get a full version of JupyterLab, or you can switch over to classic Jupyter Notebooks. I'm going to do stuff in JupyterLab today because it's a pretty good environment for beginners who are not familiar with the terminal. You can do everything graphically: file browser, Git repository integration (pull and push), open up a terminal, create new notebooks, and so forth.
They have free GPUs, and there are two key features: you can pay around $8 or $9 a month to get better GPUs for as many hours as you want, and they have persistent storage. With Colab, you have to muck around with saving things to Google Drive, and Kaggle doesn't have a persistent environment. On Paperspace, whatever you save in your storage is going to be there the next time you come back.
The main thing I wanted you to take away from Lesson Two isn't necessarily all the details of how to use a particular platform, but the key concept. There are really two pieces: the training piece, and the deployment piece. At the end of the training piece, you end up with a `model.pkl` file. Once you've got that, you feed it inputs and it spits out outputs based on that model. Because inference happens pretty fast, you generally don't need a GPU once it's trained.
Let me show you how I trained my pet classifier. You can see I've got two IPython notebooks: one is `app.ipynb` for inference in production, and one is where I train the model. I create my `ImageDataLoaders`, check the data with `show_batch`, train a ResNet34, and get 7% error rate—so that's pretty good.
There's a link here to a notebook I created (most of the work was done by Ross Wightman) where we can try to improve this by finding a better architecture. In the PyTorch Image Models (`timm`) library, there are over 500 architectures. Broadly speaking, they are all mathematical functions based on matrix multiplications and non-linearities such as ReLUs.
Most of the time those details don't matter. What we care about are three things: How fast are they? How much memory do they use? And how accurate are they?
Ross and I grabbed all the models from PyTorch Image Models and plotted them. On the x-axis, we have seconds per sample (faster to the left), and on the y-axis, we have ImageNet accuracy (higher is better). You want models that are up towards the top-left.
We've been mainly working with ResNet. ResNet18 is a particularly small and fast version for prototyping, and ResNet34 is classic, but nowadays it isn't state-of-the-art anymore. Looking higher up, the LeVit models are very fast and accurate, though they didn't work particularly well on my pet dataset. Next, I tried ConvNeXt models. ConvNeXt was super interesting—it's super high accuracy for 0.001 seconds inference time.
To try it out using `timm`: ```python import timm timm.list_models('*convnext*') ``` When creating `vision_learner`, you just pass the model name as a string: `vision_learner(dls, 'convnext_tiny', metrics=error_rate)`. When I trained that, epoch time went from 20 seconds to 27 seconds (a little slower), but the error rate dropped from 7.2% down to 5.5%—about a 30% relative improvement! If you're not sure what architecture to use, try ConvNeXt architectures.
Model names like `tiny`, `small`, or `large` indicate model size and memory usage. Names containing `in22ft1k` mean they were pre-trained on ImageNet-22k (22,000 categories) and fine-tuned on 1k categories, making them generally more accurate on standard photos of natural objects.
From there, I exported my model using `learn.export()`. Now I'm all done with training.
Once we load the learner and call `predict()`, it spits out a list of 37 probabilities corresponding to the 37 breeds of dogs and cats. Fast.ai always stores category information in the `vocab` object inside the data loaders (`dls.vocab`). By zipping categories and probabilities into a dictionary, we get exact predictions for each class.
What actually is this `model.pkl` file? It's an object type called a `Learner` containing two main things: 1. The list of pre-processing steps done to turn images into model inputs. 2. The trained PyTorch model (`learn.model`).
If we inspect `learn.model`, we see layers organized in a tree structure (e.g., `TimmBody`, `Sequential`, `stem`, `stages`). We can access specific submodules using PyTorch's `get_submodule()` method, such as `m.get_submodule('0.model.stem.1')`. Each layer consists of mathematical functions and parameters—large arrays of numbers.
To answer where these numbers come from, let me take you through a Kaggle notebook titled *"How does a neural network really work?"* Machine learning models fit functions to data. We start with an infinitely flexible function (a neural network) and tune it to recognize patterns in data.
Let's do a much simpler example than a neural network: a quadratic equation. $$f(x) = 3x^2 + 2x + 1$$ We can plot $f(x)$ with LaTeX formatting. Imagine we don't know this true mathematical function and want to reconstruct it from data.
To easily construct quadratics with coefficients $a$, $b$, and $c$: $$f(x, a, b, c) = ax^2 + bx + c$$ We can use Python's `functools.partial` to fix $a$, $b$, and $c$: ```python from functools import partial def quad(x, a, b, c): return a * x**2 + b * x + c f = partial(quad, a=3, b=2, c=1) ``` Now $f(x)$ only requires $x$ as an argument because $a$, $b$, and $c$ are fixed.
Real data always has noise. We can generate synthetic data around our quadratic by adding Gaussian noise. We create a rank-1 tensor (a 1D vector) of $x$ values from -2 to 2 with 20 steps, and calculate $y = f(x) + \text{noise}$.
How do we find $a$, $b$, and $c$ matching the noisy points? We can write a `plot_quadratic` function and attach Jupyter's `@interact` decorator to create interactive sliders for $a$, $b$, and $c$. By adjusting sliders one by one, we manually move parameters until the curve fits the points.
Instead of visual guessing, we need a single number measuring how good or bad our model is: a **loss function**. A simple loss function is Mean Squared Error ($MSE$): $$MSE = \text{mean}((\text{predictions} - \text{actuals})^2)$$
With $MSE$ displayed in the title, we systematically adjust sliders to minimize loss. If moving $a$ right reduces $MSE$, we keep moving it right until loss stops improving, then move to $b$ and $c$.
To automate this, for each parameter we need to know: if we increase the parameter slightly, does the loss go up or down? That quantity is the **derivative** (or gradient / slope). PyTorch calculates derivatives automatically.
Let's define a loss function that accepts a tensor of parameters `params`: ```python def quad_mse(params): f = partial(quad, *params) preds = f(x) return mean_squared_error(preds, y) ```
We construct a rank-1 tensor `abc = tensor([1.5, 1.5, 1.5])` and tell PyTorch to track gradients using `abc.requires_grad_()`. When we compute `loss = quad_mse(abc)`, PyTorch builds a computation graph. Calling `loss.backward()` computes gradients with respect to `abc`, stored in `abc.grad`.
A negative gradient means increasing the parameter decreases the loss. Therefore, we update parameters in the opposite direction of the gradient: ```python with torch.no_grad(): abc -= abc.grad * 0.01 ``` We wrap parameter updates in `with torch.no_grad():` so PyTorch doesn't track the gradient step itself as part of the loss calculation.
Repeating this optimization loop 5 times steadily lowers $MSE$, driving parameters towards $a=3, b=2, c=1$. This procedure is **gradient descent**.
What mathematical function can represent arbitrary patterns beyond quadratics? The answer is a **Rectified Linear Unit (ReLU)** combined with linear transformations: $$y = \max(0, mx + b)$$ In code, this is a line $mx + b$ followed by `torch.clip(y, min=0)`.
A single ReLU gives a line with a bend at zero. Adding two ReLUs together ("double ReLU") allows us to create shapes with multiple slopes and bends. By adding enough ReLUs together across multiple dimensions, we can approximate any continuous, squiggly function with arbitrary precision.
To summarize deep learning: 1. Arbitrarily flexible function (sum of ReLUs / neural network). 2. Loss function measuring performance ($MSE$, cross-entropy). 3. Gradient descent optimizing parameters.
People often reference the "draw the rest of the owl" meme. But in deep learning, there are no missing intermediate steps! When you combine ReLUs, gradient descent, and data, the computer draws the owl.
Okay, so we've got some questions on the forum.
Is there perhaps a way to try out all the different models automatically and find the best performing one?
Yes, absolutely you can do that. You can iterate through `timm.list_models()` in a loop. However, trying 500+ models takes a long time. In practice, I start every project with a fast model like ResNet18 to iterate rapidly on data augmentation and cleaning. Trying better architectures is the very last step.
How do I know if I have enough data? What are some signs that indicate my problem needs more data?
You can't know until you train a model. Always train a quick baseline model on day one. If accuracy isn't sufficient, explore data augmentation, semi-supervised learning, or acquiring more unlabeled or labeled data.
In the quadratic example, where we calculated initial derivatives for $a$, $b$, and $c$, we got values like -10.8 and -2.4. What units are these expressed in, and why don't we adjust parameters by these values directly instead of multiplying by 0.01?
The derivative represents the slope—how much loss changes per unit change in the parameter. If we adjust parameters by full gradient values, we risk jumping far past the optimal point. Multiplying gradients by a small scalar (e.g., 0.01) prevents overshooting. That scalar is the **learning rate**—a crucial hyperparameter.
Based on survey feedback, we'll take a 10-minute break here. Let's come back at 7:25.
Okay, hope you had a good rest—have a good break, I should say. So I want to now show you a really, really important mathematical computational trick, which is: we want to do a whole bunch of ReLUs.
All right, so we're going to be wanting to do a whole lot of $m \times x + b$. And we don't just want to do $m \times x + b$; we're going to want to have lots of variables. So, for example, every single pixel of an image would be a separate variable, so we're going to multiply every single one of those times some coefficient, and then add them all together, and then do the ReLU. And then we're going to do it a second time with a second bunch of parameters, and then a third time, and a fourth time, and a fifth time. It's going to be pretty inconvenient to write out 100 million ReLUs, but it so happens there's a single mathematical operation that does all of those things for us, except for the final replace negatives with zeros, and it's called matrix multiplication.
I expect everybody at some point did matrix multiplication at high school. I suspect also a lot of you have forgotten how it works. When people talk about linear algebra in deep learning, they give the impression you need years of graduate school study to learn all this linear algebra. You don't! Actually, all you need almost all the time is matrix multiplication, and it couldn't be simpler.
I'm going to show you a couple of different ways. The first is, there's a really cool site called matrixmultiplication.xyz. You can put in any matrix you want, so I'm going to put in (oops) this one.
So this matrix is saying I've got three rows of data with three variables, so maybe they're tiny, tiny images of three pixels, and the value of the first one is 1 2 1, the second is 0 1 1, and the third is 2 3 1. So those are our three rows of data.
These are our three sets of coefficients, so we've got $a, b, c$ in our data, so I guess you'd call it $x_1, x_2, x_3$. And then here's our first set of coefficients $a, b, c$: 2 6 1. And then our second set is 5 7 8. So here's what happens when we do matrix multiplication: that second matrix here of coefficients gets flipped around, and we do... this is the multiplications and additions that I mentioned, right? Multiply, add, multiply, add, multiply, add.
So that's going to give you the first number because that is the left-hand column of the second matrix times the first row, so that gives you the top-left result. So the next one is going to give us two results, right? So we've got now the right-hand one with the top row and the left-hand one with the second row. Keep going down, keep going down, and that's it! That's what matrix multiplication is—it's multiplying things together and adding them up.
So there'd be one more step to do to make this a layer of a neural network, which is if this had any negatives, we would replace them with zeros. That's why matrix multiplication is *the* critical foundational mathematical operation in basically all of deep learning.
So the GPUs that we use—the thing that they are good at is this: matrix multiplication. They have special cores called Tensor Cores, which can basically only do one thing, which is to multiply together two $4 \times 4$ matrices, and then they do that lots of times for bigger matrices.
So I'm going to show you an example of this. We're actually going to build a complete machine learning model on real data in the spreadsheet.
fastai has become kind of famous for a number of things, and one of them is using spreadsheets to create deep learning models. We haven't done it for a couple of years, so I'm pretty pumped to show this to you.
What I've done is I went over to Kaggle, where there's a competition I actually helped create many years ago called Titanic. It's an ongoing competition, so 14,000 people or 14,000 teams have entered it so far. It's just a competition for a bit of fun, there's no end date, and the data for it is the data about who survived and who didn't from the real Titanic disaster.
And so I clicked here on the download button to grab it on my computer. That gave me a CSV, which I opened up in Excel. The first thing I did then was I just removed a few columns that clearly were not going to be important things, like the name of the passengers or the passenger ID, just to try to make it a bit simpler.
And so I've ended up with each row of this being one passenger. The first column is the dependent variable. The dependent variable is the thing we're trying to predict: Did they survive? And the remaining are some information, such as what class on the boat (first, second, or third class), their sex, their age, how many siblings in the family. "Parch", I think, is parents or children... So you should always look for a data dictionary, right? To find out what's what—number of parents and children, okay. What was their fare? And which of the three cities did they embark on (Cherbourg, Queenstown, Southampton)?
Okay, so there's our data. Now, when I first grabbed it, I noticed that there were some people with no age. Now, there's all kinds of things we could do for that, but for this purpose, I just decided to remove them. And I found the same thing for `Embarked`—I removed the blanks as well. But that left me with nearly all of the data.
Okay, so then I've put that over here. Here's our data with those rows removed, and those are the columns that came directly from Kaggle. So basically, what we now want to do is we're going to multiply each of these by a coefficient. How do you multiply the word "Male" by a coefficient? And how do you multiply "S" by a coefficient? You can't. So I converted all of these to numbers.
Male and female were very easy. I created a column called `isMale`, and as you can see, there's just an `IF` statement that says if sex is male, then it's 1, otherwise it's 0. And we can do something very similar for `Embarked`. We can have one column called "did they embark in Southampton?", same deal, and another column for Cherbourg: "did they embark in Cherbourg?".
And now `Pclass` is 1, 2, or 3, which is a number, but it's not really a continuous measurement of something. They're different levels. So I decided to turn those into similar binary variables. These are called binary categorical variables. So, are they first class? And are they second class?
Okay, so that's all that. The other thing that I was thinking... well, you know, then I kind of tried it and checked out what happened, and what happened was... so I created some random numbers. To create the random numbers, I just went `=RAND()`, right? And I copied those to the right, and then I just went copy and paste values. So that gave me some random numbers.
Before I said: for all $a, b$, and $c$, let me start them at 1.5, 1.5, 1.5. What we do in real life is we start our parameters at random numbers that are a bit more or a bit less than zero. So these are random numbers. Actually, sorry, I slightly lied—I didn't use `RAND`, I used `RAND() - 0.5`, and that way I got small numbers that were on either side of zero.
So then, when I took each of these and I multiplied them by our fares, and ages, and so forth, what happened was that these numbers here are way bigger than these numbers here. And so, in the end, all that mattered was what was their fare. That's because they were just bigger than everything else.
So I wanted everything to basically go from zero to one. These numbers were too big. So what I did up here is I just grabbed the maximum of this column. The maximum of all the fares is $512. And so then—actually, I do age first—I did maximum of age, because similar thing, right? There's 80-year-olds and there's 2-year-olds. And so then over here, I just did, okay, well, what's their age divided by the maximum? And so that way, all of these are between zero and one, just like all of these are between zero and one.
So that's how I fixed... this is called normalizing the data. Now, we haven't done any of these things when we've done stuff with fastai. That's because fastai does all of these things for you, and we'll learn about how, right? But all these things are being done behind the scenes.
For `Fare`, I did something a bit more, which is I noticed there's lots of very small fares, and there's also a few very big fares, like seventy dollars, and then seven dollars, seven dollars. Generally speaking, when you have lots of really small numbers and a few really big numbers—this is really common with money, because money kind of follows this relationship where a few people have lots of it and spend huge amounts of it, and most people don't have heaps. If you take the log of something that has that kind of extreme distribution, you end up with something that's much more evenly distributed. So I've added this here called `Log_Fare`, as you can see. And these are all around one, which isn't bad. I could have normalized that as well, but I was too lazy, I didn't bother, because it seemed okay.
So at this point, you can now see that if we start from here, all of these are all around the same kind of level, right? So none of these columns are going to saturate the others.
So now I've got my coefficients, which are, just as I said, random. Okay, and so now I need to basically calculate $a x_1 + b x_2 + c x_3 + \dots$. Okay, and so to do that, you can use `SUMPRODUCT` in Excel. I could have typed it out by hand, which would be very boring, but `SUMPRODUCT` is just going to multiply each of these. This one will be multiplied by `SibSp`, this one will be multiplied by this one, and so forth, and then they get all added together.
Now, one thing, if you're eagle-eyed, you might be wondering is, in a linear equation, we have $y = mx + b$. At the end, there's this constant term. And I do not have any constant term—I've got something here called `Const`, but I don't have any plus at the end. How's that working? Well, there's a nice trick that we pretty much always use in machine learning, which is to add a column of data just containing the number 1 every time. If you have a column of data containing the number 1 every time, then that parameter becomes your constant term. So you don't have to have a special constant term, and so it makes our code a little bit simpler when you do it that way. It's just a trick, but everybody does it.
Okay, so this is now the result of our linear model. So this is not... I'm not even going to do ReLU, right? I'm just going to do a plain regression, right? Now if you've done regression before, you might have learned about it as something you kind of solve with various matrix things. But in fact, you can solve a regression using gradient descent.
So I've just gone ahead and created a loss for each row, and so the loss is going to be equal to $(\text{prediction} - \text{survived})^2$. So this is going to be our squared error, and here they all are, our squared errors. And so here I've just summed them up. I could have taken the mean. I guess that would have been a bit easier to think about, but sum is going to give us the same result. So here's our loss, and so now we need to optimize that using gradient descent.
So Microsoft Excel has a gradient descent optimizer in it called Solver. So I'll click Solver, and I just say, okay, what are you trying to optimize? It's this one here, and I'm going to do it by changing these cells here. And I'm trying to minimize it, and so we're starting at a loss of 55.78. Actually, let's change it to mean as well. Have we got mean or average? Probably average.
All right, so start at 1.03. So optimize that. And there we go! So it's gone from 1.03 to 0.1.
And so we can check the predictions. So the first one gets predicted correctly: it was "they didn't survive", and we predicted "they wouldn't survive". Ditto for this one, it's very close.
And you can start to see a few issues here, which is like sometimes it's predicting less than zero, and sometimes it's predicting more than one. Wouldn't it be cool if we had some way of constraining it to between zero and one? And that's an example of some of the things we're going to learn about that make this stuff work a little bit better, right? But you can see it's doing an okay job.
So this is not deep learning, this is not a neural net yet. This is just a regression. So to make it into a neural net, we need to do it multiple times. So I'm just going to do it twice. So now, rather than one set of coefficients, I've got two sets. And again, I just put in random numbers. Other than that, all the data's the same.
And so now I'm going to have my `SUMPRODUCT` again. So the first `SUMPRODUCT` is with my first set of coefficients, and my second `SUMPRODUCT` is with my second set of coefficients. So I'm just calling them `linear-one` and `linear-two`.
Now, there's no point adding those up together, because if you add up two linear functions together, you get another linear function. We want to get all those wiggles, right? So that's why we have to do our ReLU.
So in Microsoft Excel, ReLU looks like this: if the number is less than zero, use zero; otherwise, use the number. So that's how we're going to replace the negatives with zeros.
And then finally, if you remember from our spreadsheet, we have to add them together. So we add the ReLUs together. So that's going to be our prediction, and then our loss is the same as the other sheet—it's just $(\text{survived} - \text{prediction})^2$. And let's change that to mean... not mean, average. Okay, so let's try solving that.
Optimize `$AH\$1$`, and this time we're changing all of those. Solved!
So this is using gradient descent. Excel Solver is not the fastest thing, but it gets the job done. Okay, let's see how we went. 0.08 for our deep learning model versus 0.1 for our regression, so it's a bit better.
So there you go. We've now created our first deep learning neural network from scratch, and we did it in Microsoft Excel, everybody's favorite artificial intelligence tool!
So that was a bit slow and painful. It'd be a bit faster and easier if we used matrix multiplication, so let's finally do that.
So this next one is going to be exactly the same as the last one, but with matrix multiplication. So all our data looks the same. You'll notice the key difference now is our parameters have been transposed. So before, I had the parameters matching the data in terms of being in columns. For matrix multiplication, the expectation, the way matrix multiplication works, is that you have to transpose this. So the $x$ and $y$ is kind of the opposite way around; the rows and columns are the opposite way around.
Other than that, it's the same. I just copied and pasted the random numbers so we had exactly the same starting point. And so now this entire thing here is a single function which is matrix multiply all of this by all of this. And so when I run that, it fills in exactly the same numbers.
Make this average. And so now we can optimize that. Okay, make that a minimum by changing these. Solve. You should get the same number, 0.08, wasn't it? Yep, now we do.
Okay, so that's just another way of doing the same thing. So you can see that matrix multiplication... it takes a surprisingly long time, at least for me, to get an intuitive feel for matrix multiplication as a single mathematical operation. So I still find it helpful to kind of remind myself it's just doing these sum products and additions.
Okay, so that is a deep learning neural network in Microsoft Excel. And the Titanic Kaggle competition, by the way, is a pretty fun learning competition. If you haven't done much machine learning before, then it's certainly worth trying out just to get the feel for how these all get put together.
So the chapter of the book that this lesson goes with is Chapter 4. And Chapter 4 of the book is the chapter where we lose the most people, because, to be honest, it's hard. But part of the reason it's hard is I couldn't put this into a book.
So we're teaching it in a very different way in the course to what's in the book, and you can use the two together. But if you've tried to read the book and been a bit disheartened, yeah, try following through the spreadsheet instead. Maybe try creating, like if you use Numbers or Google Sheets or something, you could try to create your own kind of version of it on whatever spreadsheet platform you prefer. Or you could try to do it yourself from scratch in Python, you know, if you want to really test yourself. So there's some suggestions.
Question from Victor Guerrero: "In the Excel exercise, when Jeremy is doing some feature engineering, he comes up with two new columns, `Pclass_1` and `Pclass_2`. That is true, `Pclass_1` and `Pclass_2`. Why is there no `Pclass_3` column? Is it because if `Pclass_1` is zero and `Pclass_2` is zero, then `Pclass_3` must be one? So, in a way, two columns are enough to encode the input with the original column?"
Yes! That's exactly the reason. So, there's no need to tell the computer about things it can kind of figure out for itself. So when you create—these are called dummy variables. So when you create dummy variables for a categorical variable with three levels, like this one, you need two dummy variables. So, in general, a categorical variable with $n$ levels needs $n-1$ columns. Thanks, that's a good question.
So what we're going to be doing in our next lesson is looking at natural language processing. So far we've looked at some computer vision, and just now we've looked at some of what we call tabular data, so kind of spreadsheet-type data. Next up, we're going to be looking at natural language processing.
So I'll give you a taste of it. You might want to open up the "Getting Started with NLP for Absolute Beginners" notebook. So here's the "Getting Started with NLP for Absolute Beginners" notebook.
I will say, as a notebook author, I may sound a bit lame, but I always see when people have uploaded it, it always makes me really happy, and it also helps other people find it. So remember to upvote these notebooks or any other notebooks you like. I also always read all the comments, so if you want to ask any questions or make any comments, I enjoy those as well.
So natural language processing is about, rather than taking, for example, image data and making predictions, we take text data. That text data most of the time is in the form of prose, so like plain English text. English is the most common language used for NLP, but there's NLP models in dozens of different languages nowadays.
And if you're a non-English speaker, you'll find that for many languages there's less resources in non-English languages, and there's a great opportunity to provide NLP resources in your language. This has actually been one of the things that the fastai community has been fantastic at, in the global community, is building NLP resources.
For example, the first Farsi NLP resource was created by a student from the very first fast.ai course. For the Indic languages, some of the best resources have come out of fastai alumni and so forth. So that's a particularly valuable thing you could look at. So if your language is not well represented, that's an opportunity, not a problem.
So some examples of things you could use NLP for? Well, perhaps the most common and practically useful in my opinion is classification. Classification means you take a document—now when I say a document, that could just be one or two words, it could be a book, it could be a Wikipedia page, so it could be any length. We use the word "document", it sounds like that's a specific kind of length, but it can be a very short thing or a very long thing. We take a document and we try to figure out a category for it.
Now that can cover many, many different kinds of applications. So one common one that we'll look at a bit is sentiment analysis. So, for example, is this movie review positive or negative? Sentiment analysis is very helpful for things like marketing and product development. In big companies, there's lots and lots of information coming in about your product. It's very nice to quickly sort it out and to kind of track metrics from week to week.
Something like figuring out what author wrote the document would be an example of a classification exercise because you're trying to put it in a category—in this case, which author. It gives a lot of opportunity in legal discovery. There's already some products in this area, where in this case the category is: is this legal document in scope or out of scope in the court case? Just organizing documents, triaging inbound emails—so like, which part of the organization should it be sent to, was it urgent or not, stuff like that. So these are examples of categories of classification.
What you'll find is, when we look at classification tasks in NLP, it's going to look very, very similar to images. But what we're going to do is we're going to use a different library. The library we're going to use is called Hugging Face `transformers` rather than `fastai`, and there's two reasons for that. The main reason why is because I think it's really helpful to see how things are done in more than one library.
And Hugging Face `transformers`... fastai has a very layered architecture, so you can do things at a very high level with very little code, or you can dig deeper and deeper, getting more and more fine-grained. Hugging Face `transformers` doesn't have the same high-level API at all that fastai has, so you have to do more stuff manually. And so at this point of the course, we're going to actually intentionally use a library which is a little bit less user-friendly in order to see what extra steps you have to go through to use other libraries.
Having said that, the reason I picked this particular library is it is particularly good. It has really good models in it, it has a lot of really good techniques in it—not at all surprising because they have hired lots and lots of fastai alumni, so they have very high-quality people working on it.
So before the next lesson, yeah, if you've got time, take a look at this notebook and take a look at the data. The data we're going to be working with is quite interesting. It's from a Kaggle competition which is trying to figure out, in patents, whether two concepts are referring to the same thing or not, where those concepts are represented as English text.
And when you think about it, that is a classification task, because the document is basically "text one blah, text two blah", and then the category is "similar" or "not similar". And in fact, in this case, they actually have scores: it's either going to be basically 0, 0.25, 0.5, 0.75, or 1 of how similar it is. But it's basically a classification task when you think of it that way.
So yeah, you can have a look at the data, and next week we're going to go step-by-step through this notebook. And we're going to take advantage of that as an opportunity also to talk about the really important topics of validation sets and metrics, which are two of the most important topics in not just deep learning, but machine learning more generally.
All right, thanks, everybody. I'll see you next week. Bye!