Okay, welcome to lesson four. We are going to finish our journey through these kind of key applications. We've already looked at a range of vision applications. We've looked at classification, localization, image regression. We've briefly touched on NLP. We're gonna do a deeper dive into NLP transfer learning today. We're going to then look at tabular data and we're going to look at collaborative filtering, which are both super useful applications. And then we're gonna take a complete U-turn. We're gonna take that collaborative filtering example and dive deeply into it to understand exactly what's happening mathematically, exactly what's happening in the computer. And we're gonna use that to gradually go back in reverse order through the applications again in order to understand exactly what's going on behind the scenes of all of those applications. Before we do, somebody on the forum was kind enough to point out that when we compared ourselves to what we think might be the state of the art or was recently the state of the art for Canvaud, it wasn't a fair comparison because the paper actually used a small subset of the classes and we used all of the classes. So Jason in our study group was kind enough to rerun the experiments with the correct subset of classes from the paper and our accuracy went up to 94% compared to 91.5% in the paper. So I think that's a really cool result and a great example of how some pretty much, just using the defaults nowadays can get you far beyond what was the best of a year or two ago. Certainly the best last year when we were doing this course because we started it quite intensely. So that's really exciting. So what I wanted to start with is going back over NLP a little bit to understand really what was going on there. So first of all, a quick review. So remember NLP is natural language processing. It's about taking text and doing something with it and text classification is a particularly useful, kind of practically useful applications. So that's what we're gonna start off focusing on. Because classifying a text, classifying a document can be used for anything from span prevention to identifying fake news, to finding a diagnosis for medical reports, finding mentions of your product in Twitter, so on and so forth. So it's pretty interesting. And actually there was a great example during the week from one of our students who is a lawyer and he mentioned on the forum that he had really great results from classifying legal texts using this NLP approach. And I thought this was a great example. So this is the poster that they presented at an academic conference this week describing the approach. And actually this series of three steps that you see here, and I'm sure you recognize this classification matrix, this series of three steps here is what we're gonna start by digging into. So we're gonna start out with a movie review, like this one, and gonna decide whether it's positive or negative sentiment about the movie. That is the problem. We have in the training set 25,000 movie reviews. So we've got 25,000 movie reviews and for each one, we have like one bit of information. They liked it or they didn't like it. And as we're gonna look into it in a lot more detail today and in the current lessons, our neural networks, remember they're just a bunch of matrix multiplies and simple nonlinearities, particularly replacing negatives with zeros. Those weight matrices start out random. And so if you start out with some random parameters and try to train those parameters to learn how to recognize positive versus negative movie reviews, you only have literally 25,000 ones and zeros to actually tell you, I like this one, I don't like that one. That's clearly not enough information to learn basically how to speak English, well enough to recognize they liked this or they didn't like this. And sometimes that can be pretty nuanced, right? The English language, often particularly with like movie reviews, people, cause these are like online movie reviews and IMDB, people can often like use sarcasm. It could be really quite tricky. So for a long time, in fact until very recently, like this year, neural nets didn't do a good job at all of this kind of classification problem. And that was why there's not enough information available. So the trick, hopefully you can all guess, it's to use transfer learning, it's always the trick. So last year in this course, I tried something crazy, which was I thought, what if I try transfer and learning to demonstrate that it can work for an LP as well. And I tried it out and it worked extraordinarily well. And so here we are a year later and transfer learning in NLP is absolutely the hit thing now.  The key thing is we're gonna start with the same kind of thing that we used for computer vision, a pre-trained model that's been trained to do something different to what we're doing with it. And so for ImageNet, that was originally built as a model to predict which of a thousand categories each photo falls into. And people then fine-tuned that for all kinds of different things, as you've seen. So we're gonna start with a pre-trained model that's gonna do something else, not movie review classification. We're gonna start with a pre-trained model, which is called a language model. A language model is a very specific meaning in NLP and it's this. A language model is a model that learns to predict the next word of a sentence. And to predict the next word of a sentence, you actually have to know quite a lot about English, assuming you're doing it in English, and quite a lot of world knowledge. By world knowledge, I'll give you an example. Here's your language model.  Obviously, dog, right? It was a hot, what? Probably day, right? Now, previous approaches to NLP use something called n-grams, largely, which is basically saying how often do these pairs or triplets of words tend to appear next to each other? And n-grams are terrible at this kind of thing. As you can see, there's not enough information here to decide what the next word probably is. But with a neural net, you absolutely can. So here's the nice thing. If you train a neural net to predict the next word of a sentence, then you actually have a lot of information rather than having a single bit for every 2,000 word movie review, liked it or didn't like it. Every single word, you can try and predict the next word. So in a 2,000 word movie review, there are 1,999 opportunities to predict the next word. Better still, you don't just have to look at movie reviews. Because really, the hard thing isn't so much, does this person like the movie or not, but how do you speak English, right? So you can learn how do you speak English, roughly, from some much bigger set of documents. And so what we did was we started with Wikipedia. And Stephen Merity and some of his colleagues built something called the WikiText 103 dataset, which is simply a subset of most of the largest articles from Wikipedia, with a little bit of pre-processing that's available for download. And so you're basically grabbing Wikipedia, and then I built a language model on all of Wikipedia. So I just built a neural net which would predict the next word in every significantly sized Wikipedia article. And that's a lot of information. If I remember correctly, it's something like a billion tokens. So we've got a billion separate things to predict. Every time we make a mistake on one of those predictions, we get the loss, we get gradients from that, and we can update our weights and make them better and better until we can get pretty good at predicting the next word of Wikipedia. Why is that useful? Because at that point, I've got a model that knows probably how to complete sentences like this. And so it knows quite a lot about English and quite a lot about how the world works, what kinds of things tend to be hot in different situations, for instance. I mean, ideally it would learn things like, in 1996, in a speech to the United Nations, the United States President, Bla, said, now that would be a really good language model because it would actually have to know who was the United States president in that year. So like getting really good at training language models is a great way to learn a lot about, or teach a neural net, a lot about, what is our world? What's in our world? How do things work in our world? So it's a really fascinating topic and it's actually one that philosophers have been studying for hundreds of years now. There's actually a whole theory of philosophy which is about what can be learned from studying language alone. So it turns out, empirically, quite a lot. And so here's the interesting thing. You can start by training a language model on all of Wikipedia and then we can make that available to all of you. Just like a pre-trained image net model for vision, we've now made available a pre-trained wiki text model for NLP. Not because it's particularly useful of itself, predicting the next word of sentences is somewhat useful, but not normally what we want to do. But it tells us, it's a model that understands a lot about language and a lot about what language describes. So then we can take that and we can do transfer learning to create a new language model that's specifically good at predicting the next word of movie reviews. So if we can build a language model that's good at predicting the next word of movie reviews pre-trained with the wiki text model, right? Then that's gonna understand a lot about my favorite actor is Tom Hu, right? Or, you know, I thought the photography was fantastic but I wasn't really so happy about the director, whatever, right? So we can learn a lot about specifically how movie reviews are written. It'll even learn things like what are the names of some popular movies. So that would then mean we can still use a huge corpus of lots of movie reviews even if we don't know whether they're positive or negative, right? To learn a lot about how movie reviews are written. So for all of this pre-training and all of this language model fine-tuning, we don't need any labels at all. It's what the researcher, Jan Le Coon, calls self-supervised learning. In other words, it's a classic supervised model. We have labels, right? But the labels are not things that somebody else have created. They're kind of built into the data set itself. So this is really, really neat because at this point we've now got something that's good at understanding movie reviews and we can fine-tune that with transfer learning to do the thing we wanna do, which in this case is to classify movie reviews to be positive or negative. And so my hope was when I tried this last year that at that point 25,000 ones and zeros would be enough feedback to fine-tune that model. And it turned out, it absolutely was. All right, Rachel, let's go with a question. Does the language model approach work for text and forums that are informal English, misspelled words or slang or short form like S6 instead of Samsung S6? Yes, absolutely it does. Particularly if you start with your Wikitext model and then fine-tune it with your, we call it a target corpus. So your corpus is just a bunch of documents, right? Could be emails or tweets or medical reports or whatever. So you could fine-tune it so it can learn a bit about the specifics of the slang or abbreviations or whatever that didn't appear in the full corpus. And so interestingly, this is one of the big things that people were surprised about when we did this research last year. People thought that learning from something like Wikipedia wouldn't be that helpful because it's not that representative of how people tend to write. But it turns out it's extremely helpful because there's a much bigger difference between Wikipedia and random words than there is between Wikipedia and Reddit. So it kind of gets you 99% of the way there. So these language models themselves can be quite powerful. So for example, there was a blog post from, what are they called? SwiftKey? SwiftType? SwiftKey. The folks that do the mobile phone predictive text keyboard and they described how they kind of rewrote their underlying model to use neural nets. So, and now, this was a year or two ago, now most phone keyboards seem to do this. You'll be typing away on your mobile phone and in the predictions there'll be something telling you what word you might want next. So that's a language model in your phone. Another example was the researcher, Andre Capathie, who's now runs all this stuff at Tesla. Back when he was a PhD student, he created a language model of text in latex documents and created these automatic generation of latex documents that then became these kind of automatically generated papers, that's pretty cute. So we're not really that interested in the output of the language model ourselves, we're just interested in it because it's helpful with this process. So, we briefly looked at the process last week, so let's just have a reminder. The basic process is we're gonna start with the data in some format. So for example, we've prepared a little IMDB sample that you can use where it's in CSV file, so you can read it in with pandas and see there's negative or positive, the text of each movie review and boolean of is it in the validation set or the training set. So there's an example of a movie review. And so you can just go text data bunch from CSV to grab a language model specific data bunch and then you can create a learner from that in the usual way and fit it. You can save the data bunch, which means that the pre-processing that is done, you don't have to do it again, you can just load it. So what goes on behind the scenes? Well, what happens behind the scenes if we now load it as a classification data bunch that's gonna allow us to see the labels as well. Then as we described, it basically creates a separate unit, we call it a token, for each separate part of a word. So most of them are just four words, but sometimes if it's like an apostrophe S from its, it'll get its own token. Every bit of punctuation tends to get its own token like a comma or a full stop. And so forth. And then the next thing that we do is a numericalization, which is where we find, what are all of the unique tokens that appear here? And we create a big list of them. Here's the first 10 in order of frequency. And that big list of unique possible tokens is called the vocabulary. No, we just call it vocab. And so what we then do is we replace the tokens with the ID of where is that token in the vocab. Okay, and that's numericalization. Here's the thing though. As you'll learn, every word in our vocab is gonna require a separate row in a weight matrix in our neural net. And so to avoid that weight matrix getting too huge, we restrict the vocab to no more than by default 60,000 words. And if a word doesn't appear more than two times, we don't put it in the vocab either. So we kind of keep the vocab to a reasonable size in that way. And so when you see these xxunk, that's an unknown token. So when you see those unknown tokens, it just means this was something that was not a common enough word to appear in our vocab. Okay, so there is the numericalized version. We also have a couple of other special tokens like xxfield. This is a special thing where if you've got like title, summary, abstract, body, like separate parts of a document, each one will get a separate field. So they will get numbered. Also you'll find if there's something in all caps, it gets lower cased in a token called xxcap. We'll get added to it. Personally, I more often use the data block API because you get kind of, there's less to remember about exactly what data bunch to use and what parameters and so forth. And it can be a bit more flexible. So another approach to doing this is to just decide what kind of list you're creating. So what's your independent variable? So in this case, my independent variable is text. What is it coming from, a CSV? How do you want to split it into validation versus training? So in this case, column number two was the isValidation flag. How do you want to label it with positive or negative sentiment, for example? So column zero had that and then turn that into a data bunch. That's going to do the same thing. Okay, so now let's grab the whole dataset which has 25,000 reviews in training, 25,000 reviews in validation, and then 50,000 what they call unsupervised movie reviews. So 50,000 movie reviews that haven't been scored at all. So there it is, positive, negative, unsupervised. So we're going to start, as we described, with the language model. Now the good news is we don't have to train the WikiText 103 language model. Not that it's difficult, you can use exactly the same steps that you see here, just download the WikiText 103 corpus and run the same code. But it takes two or three days on a decent GPU, so not much point you're doing it. You may as well start with ours. Even if you've got a big corpus of like medical documents or legal documents, you should still start with WikiText 103. Like there's just no reason to start with random wets. It's always good to use transfer learning if you can. So we're going to start then at this point, which is fine-tuning our IMDB language model. So we can say, okay, it's a list of text files and the full IMDB actually is not in a CSV. Each document is a separate text file. So that's why we use a different constructor for our independent variable text files list, say where it is. And in this case, we have to make sure we just don't include the train and test folders. And we randomly split it by 0.1. Now this is interesting, 10%. Why are we randomly splitting it by 10% rather than using the predefined train and test they gave us? This is one of the cool things about transfer learning. Even though our test set or our validation set has to be held aside, it's actually only the labels that we have to keep aside. So we're not allowed to use the labels in the test set. So if you think about saying like a Kaggle competition, you certainly can't use the labels because they don't even give them to you. But you can certainly use the independent variables. So in this case, you could absolutely use the text that is in the test set to train your language model. So this is a good trick, right? Is actually when you do the language model, concatenate the training and test set together, and then just split out a smaller validation set. So you've got more data to train your language model. So that's a little trick. And so if you're doing NLP stuff on Kaggle, for example, or you've just got a smaller subset of labeled data, make sure that you use all of the text you have to train your language model because there's no reason not to. How are we gonna label it? Well, remember a language model kind of has its own labels. So the text itself is labeled. So label for language model does that for us and create a data bunch and save it. And that takes a few minutes to tokenize and numericalize. So since that takes a few minutes, we save it later on, you can just load it. No need to run that again. So here's what it looks like. And at this point, things are gonna look very familiar. We create a learner, but instead of creating a CNN learner, we're gonna create a language model learner. So behind the scenes, this is actually not gonna create a CNN, a convolutional neural network. It's gonna create an RNN, a recurrent neural network. So we're gonna be learning exactly how they're built over the coming lessons. But in short, they're the same basic structure. The input goes into a weight matrix, a matrix multiply, that then you replace the negatives with zeros and it goes into another matrix multiply and so forth a bunch of times. So it's the same basic structure. So as usual, when we create a learner, you have to pass in two things, the data. So here's our language model data. And in this case, what pre-trained model we want to use. And so here, the pre-trained model is the Wikitext 103 model. That will be downloaded for you from FastAI if you haven't used it before. Just like the same thing with things like ImageNet pre-trained models are downloaded for you. This here sets the amount of dropout. We haven't talked about that yet. We've talked briefly about this idea that there's something called regularization and you can reduce the regularization to avoid underfitting. So for now, just know that by using a number lower than one is because when I first tried to run this, I was underfitting. And so if you reduce that number, then it will avoid underfitting. Okay, so we've got a learner. We can LR find, looks pretty standard. And so then we can fit one cycle. And so what's happening here is we are just fine-tuning the last layers. So normally after we fine-tuned the last layers, the next thing we do is we go unfreeze and train the whole thing. And so here it is, unfreeze and train the whole thing. And as you can see, even on a pretty beefy GPU, that takes two or three hours. And in fact, I'm still underfitting. So probably tonight I might train it overnight and try and do it a little bit better. Because you can see, well, I guess I'm not underfitting. I'm guessing I could probably train this a bit longer because you can see the accuracy hasn't started going down again. So I wouldn't mind trying to train that a bit longer. But the accuracy, it's interesting. Point three means we're guessing the next word of the movie review correctly about a third of the time. So that sounds like a pretty high number, the idea that you can actually guess the next word that often. So that's a good sign that my language model is doing pretty well. For kind of more limited domain documents like medical transcripts and legal transcripts, you'll often find this accuracy gets a lot higher. So sometimes this can be even 50% or more. But point three or more is pretty good. So you can now run learn.predict. And pass in the start of a sentence and it will try and finish off that sentence for you. Now, I should mention this is not designed to be a good text generation system. This is really more designed to kind of check that it seems to be creating something that's vaguely sensible. There's a lot of tricks that you can use to generate much higher quality text, none of which we're using here. But you can kind of see that it's certainly not random words that it's generating. It sounds vaguely English, like even if that doesn't make any sense. So at this point, we have a movie review model. So now we're gonna save that in order to load it into our classifier to be our pre-trained model for the classifier. But I actually don't wanna save the whole thing. So a lot of this, kind of the second half, as we'll learn, the second half of the language model is all about predicting the next word rather than about understanding the sentence so far. So the bit which is specifically about understanding the sentence so far is called the encoder. So I just saved that. So and again, we're gonna learn the details of this in the coming weeks. We're just gonna save the encoder so the bit that understands the sentence rather than the bit that generates the word. So now we're ready to create our classifier. So step one, as per usual, is to create a data bunch and we're gonna do basically exactly the same thing. Bring it in, okay, and here's our path. But we wanna make sure that it uses exactly the same vocab that it used for the language model. If word number 10 was the in the language model, we need to make sure that word number 10 is the in the classifier. Because otherwise, the pre-trained model is gonna be totally meaningless. So that's why we pass in the vocab from the language model to make sure that this data bunch is gonna have exactly the same vocab. That's an important step. Split by folder and this time label. So remember the last time we had split randomly. Okay, but this time we need to make sure that the labels of the test set are not touched. So we split by folder. And then this time we label it not for a language model but we label these classes. And then finally create a data bunch. And remember sometimes you'll find that you run out of GPU memory. This will very often happen to you if you, so I was running this in an 11 gig machine. So you should make sure this number is a bit lower if you run out of memory. You may also want to make sure you restart the notebook and kind of start it just from here. So batch size 50 is as high as I could get on an 11 gig card. If you're using a P2 or P3 on Amazon or the K80 on Google, for example, I think you'll get 16 gig. So you might be able to make this a bit higher, get it up to 64. So you can find whatever batch size fits on your card. So here's our data bunch as we saw before and the labels. So this time rather than creating a language model learner we're creating a text classifier learner. But again, same thing, pass in the data that we want, figure out how much regularization we need. Again, if you're overfitting, then you can increase this number. If you're underfitting, you can decrease the number. And most importantly, load in our pre-trained model. And remember specifically it's this half of the model called the encoder, which is the bit that we want to load in. And freeze, LR find, find the learning rate and fit for a little bit. And we're already up nearly to 92% accuracy after less than three minutes of training. So this is a nice thing. In your particular domain, whether it be law or medicine or journalism or government or whatever, you probably only need to train your domain's language model once. And that might take overnight to train well. But once you've got it, you can now very quickly create all kinds of different classifiers and models with that. In this case, already a pretty good model after three minutes, right? So when you first start doing this, you might find it a bit, it's like annoying that your first models take four hours more or more to create that language model. But the key thing to remember is you only have to do that once for your entire kind of domain of stuff that you're interested in. And then you can build lots of different classifiers and other models on top of that in a few minutes. Okay? Right, so we can save that to make sure we don't have to run it again. And then here's something interesting. I'm gonna explain this more in just a few minutes. I'm not gonna say unfreeze. Instead, I'm gonna say freeze to. And what that says is unfreeze the last two layers. Don't unfreeze the whole thing. And so we've just found it really helps with these text classification, not to unfreeze the whole thing, but to unfreeze one layer at a time. So unfreeze the last two layers, train it a little bit more. Unfreeze the next layer again, train it a little bit more. Unfreeze the whole thing, train it a little bit more. You'll also see I'm passing in this thing, Momentums equals 0.8.7. We're gonna learn exactly what that means in the next week or two, probably next week. But for now, and we may even automate it. So maybe by the time you watch the video of this, this won't even be necessary anymore. Basically we found for training recurrent neural networks, RNNs, it really helps to decrease the momentum a little bit, so that's what that is. So that gets us a 94.4 accuracy after about half an hour or less of training, actually quite a lot less, of training the actual classifier. And we can actually get this quite a bit better with a few tricks. I don't know if we'll learn all the tricks. This part, it might be next part, but even this very simple kind of standard approach is pretty great. If we compare it to last year's State of the Art on IMDB, this is from the Cove paper from McCann et al at Salesforce Research. Their paper was 91.8% accurate. In the best paper they could find, they found a fairly domain-specific sentiment analysis paper from 2017. They've got 94.1, and here we've got 94.4. And the best models I've been able to build since have been about 95, 95.1. So if you're looking to do text classification, this really standardized transfer learning approach works super well. Any questions, Rachel? Okay, so that was NLP, and we'll be learning more about NLP later in this course. But now I wanted to switch over and look at Tabular. Now Tabular data is pretty interesting because it's the stuff that for a lot of you is actually what you use day to day at work in spreadsheets, in relational databases. Just come close, I guess. All right, so where does the magic number of 2.6 to the fourth in the learning rate come from? Yeah, good question. So the learning rate is various things divided by 2.6 to the fourth. The reason it's to the fourth, you will learn about the end of today. So let's focus on the 2.6. Why 2.6? Basically, as we're gonna see in more detail later today, this number, the difference between the bottom of the slice and the top of the slice is basically what's the difference between how quickly the lowest layer of the model learns versus the highest layer of the model learns. So this is called discriminative learning rates. And so really the question is like as you go from layer to layer, how much do I decrease the learning rate by? And we found out that for NLP RNNs that the answer is 2.6. How did we find out that it's 2.6? I ran lots and lots of different models like a year ago or so using lots of different sets of hyperparameters of various types, drop out learning rates and discriminative learning rate and so forth. And then I created something called a random forest which is a kind of model where I attempted to predict how accurate my NLP classifier would be based on the hyperparameters. And then I used random forest interpretation methods to basically figure out what the optimal parameter settings were. And I found out that the answer for this number was 2.6. So that's actually not something I've published or I don't think I've even talked about it before. So there's a new piece of information. You can actually, a few months after I did this, I think Stephen Merity and somebody else did publish a paper describing a similar approach. So the basic idea may be out there already. Some of that idea comes from a researcher named Frank Hutter and one of his collaborators. They did some interesting work showing how you can use random forests to actually find optimal hyperparameters. So it's kind of a neat trick. You know, a lot of people are very interested in this thing called auto ML which is this idea of like building models to figure out how to train your model. We're not big fans of it on the whole but we do find that building models to better understand how your hyperparameters work and then finding like those rules of thumb like, oh, basically it can always be 2.6, quite helpful. So that's just something we're kind of been playing with. Okay, so, yeah, so let's talk about tabular data. So tabular data such as you might see in a spreadsheet or a relational database, you know, or a financial report, it can contain all kinds of different things. It can contain all kinds of different things and I kind of tried to make a little list of some of the kinds of things that I've seen tabular data analysis used for. Using neural nets for analyzing tabular data is, or at least last year when I first presented this, was, maybe we started this two years ago. Anyway, when we first presented this, people were deeply skeptical and they thought it was a terrible idea to use neural nets to analyze tabular data because like everybody knows that you should use logistic regression or random forests or gradient boosting machines, all of which have their place for certain types of things. But since that time, you know, it's become clear that the commonly held wisdom is wrong. It's not true that neural nets are not useful for tabular data. In fact, they're extremely useful. And we've shown this in quite a few of our courses, but what's really kind of also helped is that some really effective organizations have started publishing papers and posts and stuff describing how they've been using neural nets for analyzing tabular data. One of the key things that comes up again and again is that although feature engineering doesn't go away, it certainly becomes simpler, right? So Pinterest, for example, replaced the gradient boosting machines that they were using to decide how to put stuff on their homepage with neural nets. And they presented at a conference this approach and they described how it really made engineering a lot easier because a lot of the hand-created features weren't necessary anymore. You still need some, but it was just simpler, right? So they ended up with something that was more accurate, but perhaps even more importantly, it required less maintenance, right? So I wouldn't say, you know, it's the only tool that you need in your toolbox for analyzing tabular data, but you know, where else I used to use random forests, 99% of the time when I was doing machine learning with tabular data, I now use neural nets, 90% of the time. It's kind of my standard first go-to approach now when it tends to be pretty reliable, pretty effective. One of the things that's made it difficult is that until now there hasn't been an easy way to kind of create and train tabular neural nets like nobody's really made it available on a library. So we've actually just created fastai.tabular, and I think this is pretty much the first time that it's become really easy to use neural nets with tabular data. So let me show you how easy it is. This is actually coming directly from the examples folder in the fastai repo. I haven't changed it at all. And as per usual, as well as importing fastai, you should import your application. So in this case, it's tabular. We assume that your data is in a pandas data frame. A pandas data frame is kind of the standard format of tabular data in Python. And it's lots of ways to get it in there, but probably the most common might be pd.readcsv. But whatever your data's in, you can probably get it into a pandas data frame easily enough. Okay, hit me with the question. What are the 10% of cases where you would not default to neural nets? Good question. I guess I still tend to kind of give them a try. But yeah, I don't know. It's kind of like as you do things for a while, you start to get a sense of the areas where things don't quite work as well. I have to think about that during the week. I don't think I have a rule of thumb, but I would say you may as well try both. Like I would say try a random forest and try a neural net. They're both pretty quick and easy to run and see how it looks. And if they're roughly similar, I might kind of dig into each and see if I can make them better and better. But if the random forest is doing way better, I'd probably just stick with that, use whatever works. So I currently have the wrong notebook in the lesson repo. So I'll update it after the class. So sorry about that. So we start with the data in a data frame. And so we've got a little thing, adult sample. It's a classic old data set. I'll have to dig up the citation for it because I've got to put it in this notebook. But it's a pretty small, simple old data set that's good for experimenting with, basically. And it's a CSV file. So you can read it into a data frame with pandas.readcsv, pd.readcsv. If your data is in a relational database, pandas can read from that. If it's in Spark or Hadoop, pandas can read from that. And pandas can read from most stuff that you can throw at it. So that's why we kind of use it as a default starting point. And as per usual, I think it's nice to use the data block API. And so in this case, the list that we're trying to create is a tabular list. And we're going to create it from a data frame. And so you can tell it what the data frame is and what the path that you're going to use to kind of save models and intermediate steps is. And then you need to tell it, what are your categorical variables and what are your continuous variables? So we're going to be learning a lot more about what that means to the neural net next week. But for now, the quick summary is this. Your independent variables are the things that you're using to make predictions with, right? So things like education and marital status and age and so forth. Some of those variables like age are basically numbers. They could be any number, you know, you could be 13.36 years old or 19.4 years old or whatever. Whereas things like marital status are options that can be selected from a discrete group, married, single, divorce, whatever. Sometimes those options might be quite a lot more like occupation, there's a lot of possible occupations. And sometimes they might be binary, could be just true or false. But anything which you can select the answer from a small group of possibilities is called a categorical variable. And so we're going to need to use a different approach to the neural net to modeling categorical variables to what we use for continuous variables. For categorical variables, we're going to be using something called embeddings, which we'll be learning about later today. For continuous variables, they could just be sent into the neural net just like pixels in a neural net can. Because like pixels in a neural net are already numbers, these continuous things are already numbers as well. So that's easy, okay? So that's why you have to tell the tabular list from data frame which ones are which. There are some other ways to do that by pre-processing them in pandas to make things categorical variables. But it's kind of nice to have one API for doing everything. You don't have to think too much about it. Then we've got something which is a lot like transforms in computer vision. Transforms in computer vision do things like flip a photo when it's accessed or turn it a bit or brighten it or normalize it. But for tabular data, instead of having transforms, we have things called processes. And they're nearly identical, but the key difference, which is quite important, is that a processor is something that happens ahead of time, right? So we basically pre-process the data frame rather than doing it as we go, right? So transformations are really for data augmentation. So you want to randomize it and do it differently each time. Whereas processes are things that you want to do once ahead of time. So we have a number of processes in the FastAI library. And the ones we're going to use this time are fill missing. So that's going to look for missing values and deal with them some way. We're going to find categorical variables and turn them into pandas categories. And we're going to do normalization ahead of time, which is to take continuous variables and subtract their mean and divide it by their standard deviation. So they're zero, one variables. The way we deal with missing data, we'll talk more about next week, but in short, we replace it with a median and add a new column, which is a binary column of saying whether that was missing or not. Normalization, there's an important thing here, which is, in fact, for all of these things, whatever you do to the training set, you need to do exactly the same thing to the validation set and the test set. So whatever you replaced your missing values with, you need to replace them with exactly the same thing in the validation set. So FastAI handles all these details for you. There are kinds of things that if you have to do it manually, at least if you're like me, you'll screw it up lots of times until you finally get it right. So that's what these processes are here. Then we're gonna split into training versus validation sets, and in this case, we do it by providing a list of indexes, so the index is from 800 to 1,000. It's very common, I don't quite remember the details of this data set, but it's very common for wanting to keep your validation sets to be contiguous groups of things, like if they're map tiles, they should be the map tiles that are next to each other. If they're time periods, they should be time periods, days that are next to each other. If they're video frames, they should be video frames next to each other, because otherwise you're kind of cheating. So it's often a good idea to use split by IDX and to grab a range that's next to each other if your data has some kind of structure like that or find some other way to structure it in that way. All right, so that's now given us a training and a validation set. We now need to add labels, and in this case, the labels can come straight from the data frame we grabbed earlier, so we just have to tell it which column it is. And so the dependent variable is, I think it's whether they're making over $50,000 salary. That's the thing we're trying to predict in this case. We'll talk about test sets later, but in this case, we can add a test set and finally get our data bunch. So at that point, we have something that looks like this, okay? So there is our data. And then to use it, it looks very familiar. You get a learner, in this case, it's a tabular learner, passing in the data, some information about your architecture and some metrics, and you then call fit. You had some questions? All right, let's hit the questions. How to combine NLP tokenized data with metadata, such as tabular data with fast AI? For instance, for IMBD classification, how to use information like who the actors are, year, May, genre, et cetera. Yeah, we're not quite up to that yet, so I need to learn a little bit more about how neural net architectures well work, but conceptually, it's kind of the same as the way we combine categorical variables and continuous variables. Basically, in the neural network, you can have two different sets of inputs merging together into some layer. Could go into an early layer or into a later layer. It kind of depends. If it's like text and an image and some metadata, you probably want the text going into an RNN, the image going into a CNN, the metadata going into some kind of tabular model like this, and then you'd have them basically all concatenated together and then go through some fully connected layers and train them end to end. We'll probably largely get into that in part two. In fact, we might entirely get into part two. I'm not sure if we'll have time to cover it in part one, but conceptually, it's a fairly simple extension of what we'll be learning in the next three weeks. Next question is, do you think things like scikit-learn and XGBoost will eventually become outdated? Will everyone use deep learning tools in the future, except for maybe small data sets? I have no idea. I'm not good at making predictions. I'm not a machine learning model.  There's quite a few really nice pieces of software for gradient boosting in particular. They have some really nice features or actually random forests in particular have some really nice features for interpretation which I'm sure we'll find similar versions for neural nets, but they don't necessarily exist yet. So I don't know, for now, they're both useful tools. Scikit-learn is a library that's often used for kind of pre-processing and running models. Yeah, I mean, again, it's hard to predict where things will end up. It's kind of in some ways, it's more focused on some older approaches to modeling. But I don't know, they keep on adding new things. So we'll see. I keep trying to incorporate more Scikit-learn stuff into FastAI and then I keep finding ways I think I can do it better and I throw it away again. So that's why there's still no Scikit-learn dependencies in FastAI. I keep finding other ways to do stuff. Okay, so we're gonna learn what layers equals means either towards the end of class today or the start of class next week, but this is where we're basically defining our architecture, just like when we chose ResNet 34 or whatever for ConvNets. We'll look at more about metrics in a moment, but just to remind you, metrics are just the things that get printed out. They don't change our model at all. So in this case, we're saying I want you to print out the accuracy to see how we're doing. Okay, so that's how to do Tabula. This is gonna work really well because we're gonna hit our break soon and the idea was that after three and a half lessons, we're gonna hit the end of all of the quick overview of applications and then we're gonna go down the other side. I think we're gonna be to the minute we're gonna hit it because the next one is collaborative filtering. Okay, so collaborative filtering is where you have information about who bought what or who liked what. It's basically something where you have something like a user or a reviewer or whatever and information about what they've bought or what they've written about or what they reviewed. So in the most basic version of collaborative filtering, you just have two columns, something like user ID and movie ID and that just says this user bought that movie, this user bought that movie, this user bought that movie. So for example, Amazon has a really big list of user IDs and product IDs of like, what did you buy? Then you can add additional information to that table such as, oh, they left a review. What review did they give it? So it's now like user ID, movie ID, number of stars. You could add a time code. So like this user bought this product at this time and gave it this review. But they're all basically the same kind of structure. So there's kind of like two ways you could draw that collaborative filtering structure. One is kind of a two column approach where you've got like user and I don't know, movie. Right? And you've got user ID, movie ID, each pair basically describes that user, what's that movie? Possibly also plus number of stars, you know, three, four, one, whatever. Well, the other way that you could write it would be you could have like all the users down here and all the movies along here. Right? And then, you know, you can look and find a particular cell in there to find out, you know, could be the rating of that user for that movie or there's just a one there if that user watched that movie or whatever. So there's like two different ways of representing the same information. Conceptually, it's often easier to think of it this way. Right? But most of the time you won't store it that way explicitly because most of the time you'll have what's called a very sparse matrix, which is to say most users haven't watched most movies or most customers haven't purchased most products. So if you store it as a matrix where every combination of customer and product is a separate cell in that matrix, it's gonna be enormous. So you tend to store it like this or you can store it as a matrix using some kind of special sparse matrix format. And if that sounds interesting, you should check out Rachel's computational linear algebra course on fast AI where we have lots and lots and lots of information about sparse matrix storage approaches. For now though, we're just gonna kind of keep it in this format on the left-hand side. So for collaborative filtering, there's a really nice dataset called movie lens created by the group lens group very hopefully and you can download various different sizes, 20 million ratings, 100,000 ratings. We've actually created an extra small version for playing around with, which is what we'll start with today and then probably next week we'll use the bigger version. But so you can grab the small version using urls.ml sample and it's a CSV. So you can read it with pandas and here it is, right? It's basically a list of user IDs. We don't actually know anything about who these users are. There's some movie IDs. There is some information about what the movies are, but we won't look at that until next week. And then there's the rating and then there's the timestamp. We're gonna ignore the timestamp for now. So that's a subset of our data that's the head. So the head in pandas is just the first few rows. So now that we've got a data frame, I mean the nice thing about collaborative filtering is it's incredibly simple. Like that's all the data that we need. So you can now go ahead and say get collaborative learner and you can actually just pass in the data frame directly. The architecture, you have to tell it how many factors you wanna use and we're gonna learn what that means after the break. And then something that can be helpful is to tell it what the range of scores are and we're gonna see how that helps after the break as well. So in this case, the minimum score is zero, the maximum score is five. So now that you've got a learner, you can go ahead and call fit one cycle. And transfer a few epochs and there it is. So at the end of it, you now have something where you can pick a user ID and a movie ID and guess whether or not that user will like that movie. So this is obviously a super useful application that a lot of you are probably gonna try over during the week in past classes. A lot of people have taken this collaborative filtering approach back to their workplaces and discovered that using it in practice is much more tricky than this because in practice you have something called the cold start problem. So the cold start problem is that the time you particularly wanna be good at recommending movies is when you have a new user and the time you particularly care about recommending a movie is when it's a new movie. But at that point you don't have any data in your collaborative filtering system and it's really hard. As I say this, we don't currently have anything built into fast AI to handle the cold start problem and that's really because the cold start problem, the only way I know of to solve it, in fact the only way I think that conceptually you can solve it, is to have a second model which is not a collaborative filtering model but a metadata driven model for new users or new movies. I don't know if Netflix still does this but certainly what they used to do when I signed up to Netflix was they started showing me lots of movies and saying have you seen this, did you like it, have you seen this, did you like it? And so they fixed the cold start problem through the UX. So there was no cold start problem. They found like 20 really common movies and asked me if I liked them. They used my replies to those 20 to show me 20 more that I might have seen and by the time I'd gone through 60, I wasn't, there was no cold start problem anymore. And for new movies it's not really a problem because like the first 100 users who haven't seen the movie go in and say whether they liked it and then the next 100,000, the next million it's not a cold start problem anymore. But the other thing you can do if you for whatever reason kind of can't go through that UX of like asking people did you like those things? So for example, if you're selling products and you don't really wanna show them like a big selection of your products and say did you like this because you just want them to buy, you can instead try and use a metadata based kind of tabular model, what geography did they come from? Maybe you know their age and sex. You can try and make some guesses about the initial recommendations. So collaborative filtering is specifically for once you have a bit of information about your users and movies or customers and products or whatever. Yeah, okay. How does the language model trained in this manner perform on code switch data such as Hindi written in English words or text with a lot of emojis? And then do you want the second question? Certainly. Yeah, that's a good question. So text with emojis, it'll be fine. There's not many emojis in Wikipedia and where they are in Wikipedia, it's more like a Wikipedia page about the emoji rather than the emoji being used in sensible place. But you can and should do this language model fine tuning where you take a corpus of text where people are using emojis in usual ways. And so you fine tune the Wikitext language model to your Reddit or Twitter or whatever language model. And there aren't that many emojis, right? If you think about it, there's like hundreds of thousands of possible words that people can be using but a small number of possible emojis. So it'll very quickly learn how those emojis are being used. So that's a piece of cake. So I'm not very familiar with Hindi, but I'll take an example I'm very familiar with, which is Mandarin. In Mandarin, you could have a model that's trained with Chinese characters. So there's kind of five or 6,000 Chinese characters in common use, but there's also a romanization of those characters called Pinyin. And it's a bit tricky because although there's a nearly direct mapping from the character to the Pinyin, I mean, there is a direct mapping, the pronunciation's not exactly direct. There isn't direct mapping from the Pinyin to the character because one Pinyin corresponds to multiple characters. So the first thing to note is that if you're going to use this approach for Chinese, you would need to start with a Chinese language model. So actually, Fast.ai has something called a model zoo where we're adding more and more language models for different languages and also increasingly for different domain areas like English medical texts or even language models for things other than NLP, like genome sequences, molecular data, musical MIDI notes and so forth. So you would obviously start there. To then convert that, that'll be in either simplified or traditional Chinese to then convert that into a, if you want to do Pinyin, you could either kind of map the vocab directly or as you'll learn, these multi-layer models, it's only the first layer that basically converts the tokens into a set of vectors. You can actually throw that away and fine-tune just the first layer of the model. So that second part is gonna require a bit more, a few more weeks of learning before you exactly understand how to do that and so forth. But if it's something you're interested in doing, we can talk about it on the forum because it's a kind of a nice test of understanding. So what about time series on tabular data? Is there an RNN model involved in tabular.models? So we're gonna look at time series tabular data next week, but the short answer is generally speaking, you don't use a RNN for time series tabular data, but instead you extract a bunch of columns for things like day of week, is it a weekend, is it a holiday, was the store open, stuff like that. And it turns out that adding those extra columns, which you can do somewhat automatically basically gives you state of the art results. There are some good uses of RNNs for time series, but not really for these kind of tabular style time series like retail store logistics databases and stuff like that. Right, and is there a source to learn more about the cold start problem? I'm gonna have to look that up. If you know a good resource, please mention it on the forums. Great. Okay, so that is both the break in the middle of lesson four. It's the halfway point of the course and it's the point at which we have now seen an example of all the key applications. And so the rest of this course is gonna be digging deeper into how they actually work behind the scenes, more of the theory, more of how the code, the source code is written and so forth. So it's a good time to have a nice break. Come back and furthermore, it's my birthday today. So it's really a special moment. So yeah, so let's have a break and come back at five past eight. So Microsoft Excel, this is one of my favorite ways to explore data and understand models. I'll make sure I put this in the repo. And actually this one we can probably largely do in Google Sheets. I've tried to move as much as I can over the last few weeks into Google Sheets but I just keep finding it's such a terrible product. So please try to find a copy of Microsoft Excel because there's nothing close, I've tried everything.  I mean, it takes thousands of hours to get really good at spreadsheets but a few dozen hours to get competent at them.  It's all laid out, it's really great. I'll give you one spreadsheet tip today which is if you hold down the control key or command key on your keyboard and press the arrow keys, here's control right. It takes you to the end of a block of a table that you're in and by far the best way to move around the place. So there you go. In this case, I wanna like skip around through this table so I can hit control down right, get to the bottom right, control left up to get to the top left, just gonna skip around and see what's going on. So here's, anyway, so here's some data and as we talked about one way to look at collaborative filtering data is like this. And so what we did was we grabbed from the movie lens data, the people that watched the most movies and the movies that were the most watched and just filtered the data set down to those 15. And as you can see, when you do it that way it's not sparse anymore. There's just a small number of, here we are, there's a small number of gaps, right? So this is something that we can now build a model with. And so how can we build a model? Like what we wanna do is we wanna create something which can predict for user 293, will they like movie 49, for example. So we gotta come up with some way of, some function that can represent that decision. And so here's a simple possible approach. And so we're gonna take this idea of doing some matrix multiplications. So I've created here a random matrix. So here's one matrix of random numbers and I've created here another matrix of random numbers. More specifically, for each movie I've created five random numbers and for each user I've created five random numbers. And so we could say then that user 14, movie 27, did they like it or not? Well, they're creating what we could do would be to multiply together this vector and that vector. We could do a dot product, right? And here's a dot product, right? And so then we can basically do that for every possible thing in here. We've got the dot product. And you know, thanks to spreadsheets we can just do that in one place and copy it over and it fills in the whole thing for us. Why would we do it this way? Well, this is the basic starting point of a neural net, isn't it? A basic starting point of a neural net is that you take the matrix multiplication of two matrices and that's what your first layer always is. And so we just have to come up with some way of saying like, well, what are two matrices that we can multiply? And so clearly, you need a matrix for a user or a vector for a user, a matrix for all the users and a vector for a movie or a matrix for all the movies and multiply them together and you get some numbers, right? Like, so they don't mean anything yet. They're just random, right? But we can now use gradient descent to try to make these numbers and these numbers give us results that are closer to what we wanted. So how do we do that? Well, we've set this up now as a linear model, right? So the next thing we need is a loss function. So we can calculate our loss function by saying, well, okay, movie three for user ID 14 should have been a rating of three with this random matrices. It's actually a rating of 0.91. So we can find the sum of squared errors would be three minus 0.91 squared and then we can add them up. So there's actually a sum squared, in Excel already, some x minus y squared. So we can use just some x minus y squared function passing in those two ranges and then divide by the count to get the mean. So here is a number that is the mean, well, it's actually the square root of the mean squared error. So like, sometimes you'll see people talk about MSE. So that's the mean squared error. Sometimes you'll see R MSE, that's the root mean squared error. So since I've got a square root at the front, this is the square root mean squared error. So we have a loss. So now all we need to do is use gradient descent to try to modify our weight matrices to make that loss smaller. So Excel will do that for me, but then installed. So it's probably worth knowing how to do that. So we have to install add-ins, oh, solver's there, okay. Let's see if we've gotten where it was. Oh yeah, okay. So the gradient descent solver in Excel is called solver and it just does normal gradient descent. So you just go data, solver. You'll need to make sure that in your settings that you've enabled the solver extension, it comes with Excel. And all you need to do is say, which cell represents my loss function? So there it is, v41, right? So where is your loss function stored? Which cells contain your variables, right? So you can see here I've got h19 to v23 which is up here and v25 to f39 which is over there. And then you can just say, okay, set your loss function to a minimum by changing those cells and solve. And you'll see the, it starts at 2.81 and you can see the numbers going down. And so all that's doing is using gradient descent exactly the same way that we did when we did it manually in the notebook the other day. Okay, but it's rather than solving the mean squared error for A at B in the A at X in the Python. Instead it is solving the loss function here which is the mean squared error with the dot product of each of those vectors by each of these vectors. And so there it goes. So we'll let that run for a little while and see what happens. But basically in micro here is a simple way of creating a neural network which is really in this case, it's like just a single linear layer with gradient descent to solve a collaborative filtering problem. So let's go back and see what we do over here. So over here we used get collab learner. Okay, so the function that was called in the notebook was get collab learner. And so as you dig deeper into deep learning one of the really good ways to dig deeper into deep learning is to dig into the fast AI source code and see what's going on. And so if you're gonna be able to do that you need to know how to use your editor well enough to dig through the source code. And basically there's two main things you need to know how to do. One is to jump to a particular symbol like a particular class or function by its name. And the other is that when you're looking at a particular symbol to be able to jump to its implementation. So for example in this case I want to find get collab learner. So in most editors including the one I used, Vim you can set it up so that you can kind of hit tab or something and it jumps through all the possible completions and you can hit enter and it jumps straight to the definition for you. So here is the definition of get collab learner. And as you can see it's pretty small as these things tend to be and in this case it kind of wraps a data frame and automatically creates a data bunch for you because it's so simple. But the key thing it does then is to create a model the particular kind which is an embedding.bias model passing in the various things you asked for. So you wanna find out in your editor how you jumped to the definition of that which in Vim you just hit control right square bracket and here is the definition of embedding.bias. And so now we have everything on screen at once and as you can see there's not much going on. So the models that are being created for you by FastAI are actually PyTorch models and a PyTorch model is called an nn.module. That's the name in PyTorch of their models. It's a little more nuanced than that but that's a good starting point for now. And when a PyTorch nn.module is run when you calculate the value, the result of that layer or neural net or whatever specifically it always calls a method for you called forward. So it's in here that you get to find out how this thing is actually calculated. When the model is built at the start it calls this thing called underscore underscore init underscore underscore. And as I think we've briefly mentioned before in Python people tend to call this dunder init double underscore init. So dunder init is how we create the model and forward is how we run the model. One thing if you're watching carefully you might notice is there's nothing here saying to how to calculate the gradients of the model and that's because PyTorch does it for us. So you only have to tell it how to calculate the output of your model and PyTorch will go ahead and calculate the gradients for you. And so in this case the model contains a set of weights for a user, a set of weights for an item, a set of biases for a user, a set of biases for an item and each one of those is coming from this thing called get embedding. So let's see get embedding. So here is the definition of get embedding and all it does basically is it calls this PyTorch thing called nn.embedding. So in PyTorch they have a lot of like standard neural network layers set up for you. So gates and embedding. And then this thing here is it just randomizes it. So this is something which creates normal random numbers for the embedding. So what's an embedding? An embedding, not surprisingly, is a matrix of weights. Specifically it's a matrix of weights. Specifically an embedding is a matrix of weights that looks something like this. It's a matrix of weights which you can basically look up into and grab one item out of it. So basically any kind of weight matrix and we're gonna be digging into this in a lot more detail in the coming lessons. But an embedding matrix is just a weight matrix that is designed to be something that you kind of index into it as an array and grab one vector out of it. That's what an embedding matrix is. And so in our case, we have an embedding matrix for a user and an embedding matrix for a movie. And here we have been taking the dot product of them. But if you think about it, that's not quite enough because we're missing this idea that maybe there are certain movies that everybody likes more. Maybe there are some users that just tend to like movies more. So I don't really just wanna multiply these two vectors together, but I really wanna add a single number of like how popular is this movie and add a single number of like how much does this user like movies in general? So those are called bias terms. Remember how I said like, there's this kind of idea of like bias and the way we dealt with that in our gradient descent notebook was we added a column of ones. Okay, but what we tend to do in practice is we actually explicitly say I want to add a bias term. So we don't just wanna have prediction equals dot product of these two things. We wanna say it's the dot product of those two things plus a bias term for a movie plus a bias term for a user ID. So that's basically what happens. When we set up the model, we set up the embedding matrix for the users and the embedding matrix for the items and then we also set up the bias vector for the users and the bias vector for the items. And then when we calculate the model, we literally just multiply the two together just like we did, right? We just take that product, call it dot, right? And then we add the bias and then putting aside the min and max score for a moment. That's what we return. So you can see that our model is literally doing what we did here with the tweak that we're also adding a bias, right? So it's an incredibly simple linear model. And for these kinds of collaborative filtering problems, this kind of simple linear model actually tends to work pretty well. And then there's one tweak that we do at the end, which is that in our case, we said that there's a min score of zero and a max score of five. And so here's something to point out. Here's something to point out. If you have a range, so you do that dot product and you add on the two biases and that could give you any possible number along the number line from very negative through to very positive numbers. But we know that we always want to end up with a number between zero and five. Let's say that's five and of course this is zero. So what if we mapped that number line like so, this function, okay? And so the shape of that function is called a sigmoid, right? And so it's gonna asymptote to five and it's gonna asymptote to zero. And so that way, whatever number comes out of our dot product and adding the biases, if we then stick it through this function, it's never gonna be higher than five and never gonna be smaller than zero. Now, strictly speaking, that's not necessary, right? Because our parameters could learn a set of weights that gives about the right number, right? So why would we do this extra thing if it's not necessary? Well, the reason is we wanna make this life as easy for our model as possible. So if we actually set it up, so it's impossible for it to ever predict too much or ever predict too little, then it can spend more of its weights predicting the thing we care about, which is deciding who's gonna like what movie. So this is an idea we're gonna keep coming back to when it comes to like making neural networks work better is it's about all these little decisions that we make to basically make it easier for the network to learn the right thing. So that's the last tweak here, which is we take the result of this dot product plus biases, we put it through a sigmoid. And so a sigmoid is just a function. It's basically one over one plus e to the x. The definition doesn't much matter, but it just has the shape that I just mentioned. And that goes between zero and one. And if you then multiply that by max minus min plus min, then that's gonna give you something that's between min score and max score. So that means that this tiny little neural network, I mean it's a push to call it a neural network, but it is, it's a neural network with one weight matrix and no non-linearities. So it's kind of the world's most boring neural network with a sigmoid at the end. That's actually, I guess it does have a non-linearity. The sigmoid at the end is the non-linearity. Just it only has one layer of weights. That actually turns out to give close to state of the art performance. Like I've looked up online to find out like what are the best results people have on this movie lens 100K database. And the results I get from this little thing are better than any of the results I can find from like the standard commercial products that you can download that are specialized for this. And the trick seems to be that adding this little sigmoid makes a big difference. And did you have a question? There was a question about how you set up your VIN and I've already linked to your .vmrc, but I wanted to know if you had more to say about that. What do they want to know about VIM? They really like your setup. You like my setup? There's almost nothing in my setup. It's pretty bare, honestly. Yeah, I mean, whatever you're doing with your editor, you probably want it to look like this, which is like when you've got a class that you're not currently working on, it should be, this is called Folded. This is called Folding, right? It should be closed up so you can't see it. And so you basically want something where it's easy to close and open fold. So VIM already does all this for you. And then, as I mentioned, you also want something where you can kind of jump to the definition of things, which in VIM it's called using tags. So if I want to jump to definition of learner. Basically, VIM already does all this for you. You just have to read the instructions. My VIM RC is minimal. I basically hardly use any extensions or anything. Another great editor to use is VS Code, Visual Studio Code. It's free and it's awesome. And it has all the same features that you're seeing that VIM does. Basically, VS Code does all of those things as well. I quite like using VIM because I can use it on the remote machine and play around. But you can, of course, just clone Git onto your, the Git repo onto your local computer and open it up in VS Code to play around with it. Just don't like, don't try and look through the code just on GitHub or something. Like that's gonna drive you crazy. You need to be able to open it and close it and jump and jump back.  Yeah, for me, I would say like, if you're gonna pick an editor, if you wanna use something on your local, I would go with VS Code today. I think it's the best. If you wanna use something on the terminal side, I would go with VIM or Emacs. To me, they're clear winners. So what I wanted to close with today is to kind of take this collaborative filtering example and describe how we're gonna build on top of it for the next three lessons to create the more complex neural networks we've been seeing. And so, roughly speaking, this is the bunch of concepts that we need to learn about. Let's think about what happens when you're using a CNN to, or whatever, a neural network to do image recognition. Basically, let's take a single pixel. You've got lots of pixels, but let's take a single pixel. So you've got a red, a green, and a blue pixel. So each one of those is some number between 0 and 255. Well, we kind of normalize them so they're a flooding point between, well, with the mean of zero and standard deviation of one. But let's just do the zero, let's say whatever they're like, do the 0 to 255 version. So there's like 10, 20, 30, whatever. So what do we do with these? Well, what we do is we basically treat that as a vector and we multiply it by a matrix. So this matrix, depending on how you think of the rows and the columns, let's treat the matrix as having three rows and then how many columns? Well, you get to pick. Just like with the collaborative filtering version, I decided to pick a vector of size five for each of my embedding vectors. So that would mean that that's an embedding, basically of size five. You can get to pick how big your weight matrix is. So let's make it size five. Okay, so this is three by five. So initially, this weight matrix contains random numbers. Remember when we looked up get embedding weight matrix just now and there were like two lines. The first line is like create the matrix and the second was fill it with random numbers. That's what we do, right? I mean, the law gets hidden behind the scenes by fast AI and PyTorch. That's all it's doing, just creating a matrix of random numbers when you set it up and the number of rows has to be three to match the input and the number of columns can be as big as you like. And so after you multiply the vector, the input vector by that weight matrix, you're gonna end up with a vector of size five. So people often ask like, how much linear algebra do I need to know to be able to do deep learning? This is the amount you need, right? So, and if you're not familiar with this, that's fine. You need to know about matrix products. Okay, you don't need to know a lot about them. You just need to know like computationally, what are they, what do they do? And you're gonna be very comfortable with like, if a matrix of size blah, times a matrix of size blah gives a matrix of size blah. Like, how do the dimensions match up? So if you have three, and then remember in NumPy and PyTorch, we use at times three by five gives a vector of size five, okay? And then what happens next? It goes through an activation function such as ReLU which is just max zero comma X and spits out a new vector which is of course gonna be exactly the same size because no activation function changes the size, right? It only changes the contents. So that's still a size five. What happens next? We multiply it by another matrix. And again, it can be any number of columns but the number of rows has to map nicely. So it's gonna be five by whatever. So maybe this one has, you know, five say by 10. And so that's gonna give some output. It should be size 10. And again, we put that through ReLU. And again, that gives us something of the same size. And then we can put that through another matrix. Actually, just to make this a bit clearer, you'll see why in a moment. I'm gonna use eight, not 10. So that these, let's say we're doing digit recognition, right? So there are 10 possible digits. So my last weight matrix has to be 10 in size because then that's gonna mean my final output is a vector of 10 in size. And remember, if we're doing that digit recognition, what happens? We take our actuals, right? Which is 10 in size. And like if the number that we're trying to predict was the number three, that's how I like, that's the thing we're trying to predict. Then that means that there is a three, zero, zero, zero in the third position, right? So what happens is our neural net runs along, right, starting with our input. I'm going weight matrix, ReLU, weight matrix, ReLU, weight matrix, final output. And then we compare these two together to see how close they are, how close they match using some loss function. We'll learn about all the loss functions that we use next week. For now, the only one we've learned is mean squared error. And yeah, we compare the actual, you can think of them as probabilities for each of the 10 to the actual, each of the 10 to get a loss. And then we find the gradients of every one of the weight matrices with respect to that and we update the weight matrices. So the main thing I wanted to show right now is the terminology we use because it's really important. These things contain numbers. Specifically, they initially, matrices containing random numbers. And we can refer to these yellow things as in PyTorch, they're called parameters. Sometimes we'll refer to them as weights, although weights is slightly less accurate because there can also be biases, right? But you know, we kind of use the terms a little bit interchangeably, but strictly speaking, we should call them parameters. And then after each of those matrix products, that calculates a vector of numbers. So here are some numbers that are calculated by, here are some numbers that are calculated by a weight matrix, multiply. And then there are some other sets of numbers that are calculated as a result of a value, as a result of the activation function, okay? Either one is called activations. So activations and parameters, both refer to numbers, right? They are numbers. But parameters are numbers that are stored, they're used to make a calculation. Activations are the result of a calculation, they're numbers that are calculated, right? So they're the two key things you need to remember. So use these terms and use them correctly and accurately, right? And if you read these terms, they mean these very specific things. So don't mix them up in your head. And remember, they're nothing weird and magical. They're very simple things. An activation is the result of either a matrix multiply or an activation function, okay? And a parameter are the numbers inside the weights, inside the matrices that we multiply by, okay? That's it. And then there are some special layers. So every one of these things that does a calculation, all of these things that does a calculation are all called layers. They're the layers of our neural net. So every layer results in a set of activations because there's a calculation that results in a set of results, okay? There's a special layer at the start, which is called the input layer. And then at the end, you just have a set of activations, okay? And we can refer to those special, I mean, they're not special mathematically, but they're semantically special. We can call those the outputs, right? So the important point to realize here is the outputs of a neural net are not actually like mathematically special. They're just the activations of a layer. And so what we did in our collaborative filtering example, we did something interesting. We actually added an additional activation function right at the very end. We added an extra activation function, which was sigmoid. Specifically, it was a scaled sigmoid between zero and five, right? And that's really common, right? It's very common to have an activation function as your last layer. And it's almost never gonna be a value because it's very unlikely that what you actually want to something that truncates at zero. It's very often gonna be a sigmoid or something similar because it's very likely that actually what you want is something that's between two values, okay? And kind of scaled in that way. So that's nearly it, right? So we've got inputs, weights, activations, activation functions, which we sometimes call non-linearities, output. And then the function that compares those two things together, right? Is called the loss function, which so far we've used MSE. Yeah, okay, and that's enough for today. So what we're gonna do next week is we're gonna kind of add in a few more extra bits, which is we're gonna learn the loss function that's used for classification, which is called cross entropy. We're gonna use the activation function that's used for single label classification, which is called softmax. And we're also gonna learn exactly what happens when we do fine tuning in terms of how these layers actually, what happens with unfreeze and what happens when we create transfer learning. So thanks everybody. Looking forward to seeing you next week.