 Okay, yeah, you've got a question. Yeah. Okay, so I've got my paper space open. And I can see, I haven't started the machine in a while. Yeah, my machine is not actually starting, which is not great. So if I can see a list of the direct which like goes clean image tools. I've got a 102 blah blah blah. How do we get over to the 20, you know, the course to the current course cost 2022. So you would get cloned it. So you would open so you would open up Jupyter lab. Right. Just go into a terminal and you would CD to slash docs, sorry CD to slash notebooks, get cloned and copy and post the, the get URL from GitHub. Okay, let's see what happens. Okay. Thank you. No worries. Any other questions anybody having any trouble getting things working smoothly. I read in. Oops. Yeah. Please go on. Just a question. I tried to look at my history, my bash history. I tried the same link. I can see it there. Yeah. In my home. But I don't seem to be out of history from my previous session. Yeah. So the bash underscore history file dot bashing history file is only created when you close the terminal. So you can't sim link it to it till it exists. And so to make it exist, there's two things you could do. The first is you could open a terminal, run a command like LS and then close the terminal and open a terminal again. And now the bash history file will be there because you've done something and you can sim link to it. Or you can just create it and to create an empty file in Unix, you just type touch space and then the file name. So dot. Okay. And somebody else had a question or comment. Yes. So my question is about with Kaggle part from last lesson. So what I understand from, from the lesson, you need to either do everything in the Kaggle website, the training and the inference, let's say, or it's possible to train your model in local machine or gradient, let's say. Then somehow transfer it to the Kaggle somehow. Right. So what is the problem? Yeah. Great. What is the proper way? That was my question. Yeah, yeah, yeah. Great. Perfect. I love it when people ask the question that I want to solve today because that's a sign that it's a question worth asking. Answering, I should say. Okay. Well, neither of my gradient machines are starting. Setting up instance. That's not good. All right. I guess we're going to use the terminal. Bad news is that I'm on my Mac, where I don't think I've got anything set up. You can use your fancy set of things script. Yeah, I mean, I mean, yeah, it's, it's sort of slightly set up. I don't have the Kaggle stuff downloaded. So, all right. Well, it's always good to revise anyways. Yeah. So. Share screen portion. Share. Right. Okay, you guys can see that hopefully. I wonder if we should maybe make this a little bigger as well. You guys can't see that. Okay. Is that reasonably visible? Yes, it is. Great. Yes. All right. So this is T-Max, obviously running in a terminal. And because I'm sharing my screen, I'm using a slightly lower resolution kind of area than usual. So a particularly good idea to zoom into one of these panes. So I just hit control BZ to zoom into the pain. And let's see if on this machine I already, okay, so this machine does not currently have a Kaggle directory. So pip install Kaggle. And if I try to run that, it's not going to work. Do I have SSH config set up? Oh yeah, that's right. I think Max got some really old version of SCP that doesn't know how to do much. So I might have to, normally with a current version of open SSH, SCP, you could tap complete even to get remote files, which is quite great. But I think I noticed that Mac tends to ship really old versions of a lot of the Unix software, which is a shame. So we have to do it the slow way. So we're going to copy.Kaggle slash Kaggle.JSON to here. Why am I putting in SSH? Move Kaggle.JSON into Kaggle. And that should now work. Great. So let's download the data. All right. And we're going to go competitions. Patty and data and copy paste. Okay. All right. And then we're going to see if you've got Jupiter running. We do. All right. Well, it's going to be crazy over there. So let's open up Jupiter. And if anybody keeps an eye on paper space, let me know if paper space seems to start working. All right. Here's Patty. And all. Okay. From fastai.vision.all import star. It's like this is finished. So we can now unzip minus Q. Not that. Unzip minus Q. Patty disease classification. There we go. Oh, you know what we could do? We could run this on my GPU server. Because of course running this on the max, a bit of a dumb idea anyway. So I don't think we've talked about how to do that before. So this might be slightly obscure. But that's okay. We'll learn something in the process. So all right. I'm switching over now. Actually let's jump out of T-Mux. Because running T-Mux in T-Mux is always a little bit weird. So this is my GPU server. Okay. And it is running Jupiter. And it says, oh, you can go to localhost 8888 to use this. But I can't because that's not localhost refers to the machine I'm currently on. And I'm not on this machine. I'm SSH-ing into a remote machine. But what I've done, and as I say, this is like something that not everybody needs to know about for sure. But for those who are interested, what I've done is when I SSH to this particular machine called local, it forwards anything that I use on my local machines port 8888 to the remote machines 8888. Which means that I can use localhost 8888. And it will actually forward those packets to the remote machine and forward remote machine packets back to here. So this is called SSH forwarding, you know, FYI. So if I go here, and the other thing we should probably do is make sure that Jupiter is not running on the local machine. I'll cancel that. And so to exit out of this, I could create another window or another tab or whatever, but I can just hit CTRL BD to detach from Tmux. So that stuff's all running still in the background. And then I can SSH to my machine. And let's see if that's all working. There we go. Okay. So that's great. And so here we actually have that going so we can create a new notebook. And it's easy enough, by the way, if you do like buy a machine with a GPU, which it's not a terrible idea, especially if eventually GPU prices start to come back down to reasonable levels at some point, you know, it doesn't need to be a notebook or anything. You can chuck it anywhere in the house, just like I've done. And as you can see, log into it from your computer. Now, I can only log in to mine, right, you know, by default, I'd only be able to log in from home. If you want to be able to log in when you're not at home, log into your router's settings and say forward port 22, which is the SSH port, to your GPU server. And you'd also have to know the IP address that your house's Wi-Fi is on, and that tends to change. So you can use something called Dynamic DNS. There's lots of different providers of Dynamic DNS. So I use something called din.com just because they've been around forever. And so, yeah, so I can log in to my machine from anywhere, which is very nice. Okay, so let's try this again from fastai.vision.all imports. All right. And so path equals, so we can do LS in bash like so. Here we go. Great. So you can just use the current path is where our data is. And so our training path. Oh, and we're also, that's fine. And then our training path is path slash train images. So I'm not sure we've really talked much about path lib before. So this path object comes from a Python class called pathlib, and it's imported by default with pretty much any fast core or fastai thing you use. So to learn about it, obviously, you can just Google for pathlib. But basically, yeah, it lets you create a path. This is a path in your current working directory, or you can do something here to go to a relative directory, or you can go to a absolute directory. And then you can, you know, it's kind of got this somewhat neat use of the slash operator to mean, you know, go to a sub directory. .ls doesn't come with it by default. Fast core adds that to list things, as you see. Yeah, so that's pretty cool. And so the other thing we did yesterday was we looked at the files. Get image files inside. Let's have a look at the ones inside the training path. And so we can create an image. We can look at it in size, which is a property. Okay, so there's a few things we can do. That kind of gets us back to where we were yesterday. So a question I saw in the forum was, how would I get, like, the sizes of all of the files? Well, it actually showed how to do it kind of a slightly slow way, which is, let's do it the slightly slow way and time how long it takes. Sizes equals. Let's just copy that. Paste that here. .size40 in files. Yes. Is there a question coming? So to do this in parallel, which would obviously be faster, one would expect, I mean, it would depend. If most of the time is spent reading this from the disk, then doing this in parallel won't be any faster. If most of the time is being spent decoding the JPEG, then doing this in parallel will be faster. And which of those is true? It will depend on whether we're using an SSD or not. So anyway, I'll show you how to do it. So if you import a Fastcore.parallel, which is a module, that module contains a function or parallel, which applies this function to these items. So the function we want to apply is... Let's look at the doc for it. Show in docs. So here's an example of parallel. Now that should be ordered. So here's something that takes two things, X and A, and adds something to each one. And so here's how we use parallel. The docs for FastAA libraries are a bit different to some in that the tests and the docs are all one thing. So to read this, this is saying if you call parallel, passing it this function, which is just X plus A, where A defaults to one, and you do it on this input, which is range 50, then you would expect to get this output, which is the range from 1 to 51. So this kind of is showing you lots of examples of using the function and telling you what you would expect to get for each one. So if we want a function which is going to take some file and it's going to return this, I think so. And so if we want to run that in parallel, then we can say parallel, and the function we want to run is this function, and the files we want to run on is files, and there's lots of other things we could pass in. So let's say we want to do it on four parallel workers, see if that ends up any faster. So as you can see, running stuff in parallel when you use Fastcore is actually pretty fast and easy. But as I say, it doesn't necessarily result in a speed up if the main thing that's taking time is getting stuff off the disk, then it won't be faster. Okay, so in this case, it was a bit faster. I think they use really slow disks on... Actually, this is my disk, this is a good disk that ought to be fast. So we could see if increasing it further is faster still. I guess it's probably... We'll see. So Jeremy, quick question about this. Does this use CPU cores, or is it using the GPU for running it in parallel? CPU. So the GPU is only used for models, basically. Pretty much everything else is going to be done on CPU. Okay, thank you. Okay, so that's definitely worth the speed up. Now, I don't normally create a function to do one thing like this. What I would normally do instead is to use a lambda expression. And so to use a lambda expression, it's just basically it's a function you define in line. You just type lambda and you say the argument and you don't have to say return. And so then we can get rid of the definition and run. Okay, so that's interesting. So we can't use a lambda with parallel. Oh, I guess I didn't know that now I think about it. All right, that's fine. We won't use it then. Parallel processing on Python is notoriously crappy. So, yeah, it has a lot of limitations, including now I think about it not being able to use lambdas. Okay, so then we created our data loaders, image data loaders from path and folder. And we passed in the training path, and I think we want some resized transform as well, right? Cool. And so then we created a model. So last time we used ResNet 34, but what I'd be inclined to do is to head over to Kaggle and look at which image models are best and see if there's something we might want to use. It's better than ResNet 34. So this is showing speed in a log scale, and this is showing accuracy on ImageNet. And the different colors of various different kind of families. So ResNet is this family here. And things like ResNet 34 are not particularly great, as you can see. So let's try using ConvNext base in 22 blah, blah, blah instead. Okay, so Vision Learner, we first passed in the data loaders. And so these image models here from a library called Tim, which to use it, you need it installed, which I probably have installed, but just to check. Yep, that's already installed. And you can check out things on Tim such as, so if you import it, then you can say Tim.listModels and you can pass in basically a glob. So I want to look at ConvNextModels. See what options there are. Mainly because I just want to copy and post and so, okay, so there's base, there's small as well, small. Now why small? Next, if you double click, you'll get this. There's base, large, extra large. That's weird. For some reason, the small one's not appearing. And there's also a tiny. Hi Jeremy. Yeah. I think they added the small and the tiny one in the last version of Tim that is not in the peeping style version. Right. Okay. So, oh yeah. We need to install the dev version of it. Correct. Yes. Thank you. So Ross who creates Tim created a pre-release version. 0.62. And so to install that we would need to call minus you upgrade. Oh, just one moment please. My daughter's having computer problems. All right. Tim. Greater than 0.6. Equal to 0.6. I think something like this. I'm not quite sure. Oh, it says I've already got 0.6. 2 dev installed. Oh, I see. So I've got it on my machine, but it wasn't on the Kaggle machine because I didn't install the, that version on Kaggle. Okay. Cool. Well, we might as well fix it on Kaggle just so you see how these things work as well. Because there's actually something quite nifty here. So we'll click edit on Kaggle and we'll somehow it's okay. Oh, all right. It's, he doesn't have it in his data, I guess. All right. So not much we can do about that. All right. Well, I think we should just go ahead and try one of the smaller ones. So come, let's try small. That has to be a string when he used Tim. Okay. It happens. So when you use a pre-trained model, it needs the weights. And so the first time you use it, it downloads the weights. Depending on how much space, if you're using paper space, depending on how much space you have and how long this takes on paper space, you may want to consider sim linking your home directories.cash slash torch into slash storage. And that way you won't have to download these. Not that it seems to take too long. I don't know if you care or not. You know, one thing we might want to do. Well, let's just start trying to fine tune it, shall we? It's good. Seems to be working. Let me know if anybody's got any questions or thoughts along the way. So when it fine tunes. Oh, okay. So the other thing we want to do is tell it that we want to keep track of the error rate. It's going to help. So yeah, so when we fine tune, just create another copy. So we can look at the source code to see exactly what it's doing when we call fine tune. So what it's actually doing is it's calling freeze. What that does is it says all of the weights except for the very last layer. The optimizer is not allowed to change. So if you think back to that Silo and Fergus paper we saw with the different layers and the different, like, you know, the later layers were more and specific. So initially we just want to fit the last layer. So it calls fit on the last layer only. And then it decreases the learning rate and then unfreezes. So then it says, okay, you know, you can train the whole thing. And then it trains the whole model for however many epochs we asked for. So we can see. So generally speaking fast AI methods or I mean pretty much any methods I write tend to be very small. So they're designed to be reasonably easy to read the source code and see what's going on, at least if you're reasonably comfortable with Python. Oh, and I just sort of something else we should do. Which is if you are using a GPU released in the last, I don't know, four years or so, it's very likely that it'll be much faster using what's called half precision floating point, which is basically like less, less precise numbers. It'll be way, way, way faster. Most of the time on Colab and Kaggle, you're not going to get one of those more up to date GPUs. But having said that, there's really never any harm in using half precision floating point. And even if you use an older GPU, it's still going to save memory. So actually to ask fast AI to do that for you, you can add two floating point 16 as in 16 bit at the end of your learner command. So, yeah, so when this finishes, we might try rerunning it with this instead. Excuse me, Jeremy, I'm just following along on paper space. And if I want to bother with importing tin just to keep up what instead of using ConvNext, what would be a good default to use? I mean, why not use ConvNext? I guess because I would need to import tin, I think I missed that bit. So pip install tin, yeah. Or if you want to get the more recent models such as the one we're using, then pip install, let me copy this for you. So that's the command there. And I'll put it in the Zoom chat for you. Great text. And Jeremy, just while we're talking about fine tuning and as that's going on, I don't know if anyone else would find it helpful. But I mean, obviously like conceptually understand what's happening with fine tuning. But I don't know if anyone else kind of feels like trying to understand better what's actually going under the hood with fine tuning. Like what's actually being altered within the model more than just at a kind of at a high level. I'm just trying to get a bit of a better grip on what exactly we're fine tuning and how it's going about fine tuning it, I guess, just under that first surface level. Just want to make sure I understand it better. Yeah, so we just looked at the source code for it. So what, yeah, what did you want to go? Which bit of this did you want to look deeper at or like what did you? Yeah, tell me more. What do you want to know? Yeah, I guess. Stepping through it. So you've got it frozen at a particular point, right? And then this fit one cycle. So just going through the definition of fit one cycle again. Oh, so we haven't done that yet in the course. I don't think. Yeah. So yeah, so we can certainly talk about that. I don't want to hijack things. If other people want to kind of move on, that's fine. I can follow it up later. But I just kind of wanted to get a bit of an overview of what's actually going on there. Let's take a look. Fit one cycle. So we'll look at the docs. Here it is. So what does fit one cycle do? So actually there's a paper you can read if you want to know exactly what it does. But there's a picture here, which tells you what it does. And what this picture is, is so fit one cycle uses something called a scheduler. And a scheduler is something which actually changes the learning rate during the training. So remember the learning rate is the thing we multiply the gradients by before we subtract from the parameters. When you have a randomly initialized model, or even a pre-trained model, we actually randomly initialize the last layer of weights. So at first, even a pre-trained model that we're fine tuning can't do anything. It's still giving random answers. And so that means we want to use a really small learning rate because it's very difficult to get to a point where it's starting to learn something slightly useful. And so when we start training the first-year batches use a tiny learning rate. And then as it gets better and better at like doing something useful, you can increase the learning rate because it's got to a point where it's like, yeah, it's kind of knows vaguely what it's doing. And so as it trains, the learning rate goes up and up and up and up and up. And then as you start to get close to the answer, you need to decrease the learning rate again. And the reason for that is that you're really fine going to small little steps. You're really, really close now. So when you... So you're saying as you get closer to the answer, like are we saying that that's in comparison to the validation set so that we're moving away from overfit where those might... Yeah, I guess where the... Nothing to do with validation or training or anything. So this is just a plot of the curve of batch number against learning rate. So this is the exact shape that is used. There's nothing clever going on. It just follows this exact curve. Oh, okay. So that's not interacting with anything else to derive those numbers. It's just doing that. Okay. All right. Understood. So in fact, if we look at the source code for it, what it does is it calls something called combined cause. You can look at the definition of. Which is something that uses two cosine schedules. And so a cosine schedule is one that... So it's also known as an annealer. It's called learning rate annealing. It's something that literally uses cosine. Got it. That's it. Yeah. Okay. That's helpful. So I get now kind of where that's mapping to that idea. Yeah. And for people who are interested in going deeper and understanding like what is fast day I do and why and what actually makes... What's important in deep learning and stuff. This is how exploring the documentation and source code of fast day I, when you're at a point where you feel this is what you're ready to do, can be super useful because the documentation can tell you what paper is being implemented and why and shows you pictures of what it's doing. And the source code is something that you can copy and paste into your notebook and try it yourself and so forth. Yes. Did you have any other questions about this? No, that's fine for the moment. I don't know if anyone else does. All right. I just wanted to comment that Sylvan had a very good blog post explaining the fit one cycle policy. Yes, he does. Perfect. And so there's other policies you can use like the triangular version. So this is actually what we originally did I think for one cycle as you can see it ends up being pretty similar. And what would be I guess the criteria for where you would change that policy? Like what would I guess what's the basis for the decision you make about changing that policy? I mean, you don't basically it works fine and you just do it. Yeah. Okay. All right. So it's pretty arbitrary. Yeah. I mean, it's no, it's not arbitrary. It's something that lots of experimentation has found that this works well. Okay, right. Like everything pretty much in fast AI we try to find the things that work well. And the things that need changing we generally tell people all about them, but this is generally something that doesn't need changing too much. Okay. So is this related to learning trade finder? Okay, so let's talk about learning. I'm finding it quite confusing, which actually which number is correct with learning trade finder. Sure. So just before we do that, I'll just point out. The next precision version on my RTX card, which is a consumer GPU, the speed's gone from a minute 41 to 28 seconds. So you can see it really does make a huge difference to use FP16. So this question about something called the learning rate finder. So the learning rate finder does something very similar to one cycle, the one cycle scheduler or one cycle annealing, which is it gradually increases the learning rate while it trains. But it actually only does up to 100 batches. So generally speaking far less than even an epoch. And it doesn't increase the learning rate and then decrease it again. It just keeps increasing the learning rate until the whole thing falls apart. And so this is a graph of the learning rate. And remember, it increases it logarithmically increasing every batch. So this is also kind of a graph of time of batch number. And then it shows you what loss it got. So the first few batches it got a loss of about four. And until it got up to a learning rate of about 10 to the negative four, nothing really improved. So clearly learning rates of less than 10 to the negative four aren't very useful. And then as it increased the learning rate, you can see the slope started to get steeper and steeper. And so this area here is where it's learning the most quickly. And then it gets to a point up here where it's too high. And when it gets too high, initially it just doesn't really improve at all. And then it gets really too high. It jumps past the answer and starts getting much worse. So the, yeah, so I generally just pick somewhere visually around the middle, or you can, you know, see it says something around 0.01. So is the magnitude of that thing or why we wouldn't choose the minimum here? I mean, okay. Sorry, that's what I thought like. This would be a really bad spot, right? Because at this point it's not learning. So what you want to look at is the gradient. You want to look at the slope of this line because the slope is how quickly is it improving. So at this point here that this learning rate, it doesn't improve at all. So if we use this learning rate. So wouldn't that make sense to use gradient actually for this? Yes. To see what's the minimum? I mean, rather than doing that visually. Well, not necessarily because you see here, there's a really steep gradient, but that's definitely a bad spot. True. Okay. Sorry. So I mean, don't be sorry. It's a great question. Like it's surprisingly difficult to come up algorithmically with the thing that our eyes do when we say like, oh, we're about somewhere around here. Wouldn't that be local minimum? No. Sorry. Because the minimum is down here, which is definitely not what we want. And the minimum gradient would be here, which is definitely not what we want. I'm not saying it's possible. But the learning rate finder. So Zach Mueller actually spent a lot of time trying different things and wrote a whole blog post for his company and came up with four different approaches, all of which actually don't work too bad. And you can actually look at all of them by saying, what suggestion functions do you want to use? So there's, we probably should have a link to Zach's blog post in the docs because that would be quite helpful for people for a second about that. Okay. So yeah, so you can see minimum. It's actually one of the suggestion functions, but I don't actually know why it's even there because you'd never use it. So minimum will, the plot will be in the minimum, but the suggestion value is still like, it's like 10, like divided by 10. Oh, is that what happens? Yeah. Oh, I see. So it finds the minimum divided by 10. Got it. So we should probably plot that then on the minimum rather than plotting what's effectively 10 times that. Okay. Thanks for explaining. Yeah. So you can see all these numbers are all in the same order of magnitude. And default is 0.002. So is this something that fast AI uses underneath the hood? Or I mean, like, what's the benefit of changing this learning rate manually or trying to find it? So most of the time, our default works perfectly fine, which is why I don't talk about this as much as I used to, actually. But you know, sometimes some data, well, particularly like for a tabular data set, the learning rate can be almost anything. It really does depend on the model. I find most pretty much all computer vision models seem to have pretty similar learning rates that are useful. So the defaults generally work pretty well. But yeah, if you try something and it doesn't seem to be training particularly well, just try running the, you know, the first thing I try would be try running LR find just in case the default learning rates nowhere near the recommended values. And then you could try, yeah, you could just try some different number. But yeah, these are all very close to our default anyway. So I wouldn't bother in this particular case. Thank you. Yeah, no worries. These are good questions. Okay, we've got a model. I'm actually going to have to train it again because I just created a new learner for the purpose of that. And so the next thing we're going to have to do is to apply it to our training set. Sorry, to our test set in order to submit to Kaggle. So the test set, it's always good to have two windows, two tabs going on because that way we can start working on the next thing while this is training, right? And you can see it's still training because the little hourglass icon is there in the fab icon. So there's something called test underscore DL, which for some reason is not appearing. It must be from some different part of the library. I test DL. Data core. Fastai.data.all import star. Something silly. Oh, it's a method. Okay. My bad. DLs.testdl. Okay. Help. No doc. All right. So this creates a test data loader. So a test data loader is a data loader used for inference of a bunch of things at once, basically. So there should be an example down here. Okay. So a test DL is something that we pass some items to. So I don't know, like Radek, Tanishk, anybody else? You know, I'm thinking I'm just going to call get image files on the test set and pass it to test DL. Is that what you guys would do? Or do you have a better way to do this? Yeah. I think that should work. I don't know. Like what people, you know, I don't do nearly as much inference stuff as most people. So I never quite know what the fastai community's preferred idiomatic approaches. Okay. So we've got 3,469 files to apply this to. So we could create a test data loader. And that's going to be DLs.testDL with those files, I guess. And we should be able to go testDL.showBatch. So I do always like to see what I'm doing, you know? So that looks helpful. And so a test data loader, the key difference is that it doesn't have labels. So there's no dependent variable. All right. So then I guess we would go, is it dot getPreds or dot predict? I never quite remember. That's an item. So I guess it's getPreds. We need better names for these. Okay. And then DL data loader equals the test data loader. Oh, and I should have assigned that to something, obviously. That was a bit silly of me. And also we should look at the documentation for it. Do you're not used to that keyboard shortcuts doc. Get the predictions with some particular data loader. It can optionally return the input. It can optionally return the loss. We don't need any of that. Okay. So what I think we should do is we should look at Kaggle at this point. And actually, we don't even need to look at Kaggle. What Kaggle normally does is they provide us with a sample submission. Here's one here. Right. So let's look at the submission. Sample submission equals pd.readcsv. And notice in Jupiter, if you start quotes and you press tab, it will tab complete file names, which is nice. Okay. Not a very useful sample submission. Unless there's something wrong with Python. This is not a great submission, but they just want the name of the class. I see. What a terrible sample submission, particularly for a training one. You would think they would be more helpful. So they just want the text of the name of the class. Do they? Yes. I mean, obviously we could actually look it up and find out rather than guessing when you don't have Radick on the line to tell you the answer. Or maybe you can just call Radick and ask him. So data evaluation. Yes. See, they've actually got a sample here. Yeah. All right. Let's try that. The Prads equals and so by default, it's got to return the probability of every class, which we can certainly turn into what we want. But I think if we call with decoded, that will do it for us. Does that sound right? You can see I'm so out of practice with this. Okay. It's pretty close, right? So we're going to look at the indexes of each one. So this is actually going to be a really good exercise. So in terms of like what's in there, there's three things. There's the probabilities. There's something we don't care about. And there's the indexes. So these are the indexes. So what are these indexes of? They're indexes into the vocab. So if you remember, the vocab is the tells you what's what. Right. So we need to convert these predictions into these pieces of these strings. So the first had probably be inclined to just to maybe turn that into a panda series. And so I guess we should give it a name as well. There is. Okay. So let's call these indexes. Oopsie-daisy. Oh, and it's called. Oopsie-daisy. It's called. Okay. So there's a panda series. And I always find pandas. The pandas API difficult to remember. I don't find it particularly consistent or intuitive, but there is a dot map function, which I think we can look up into dls.vocab. Category enough is not callable, fair enough. So dls.vocab is, although it looked like a list, I guess it's not one, but we might be able to turn it into a list. Normally you can turn things into lists like so. Yes, we can. Let's see if that works. Oh, okay. That's annoying. So I'm pretty sure that you can pass a dictionary. Yes, you can. And I thought a list would count as a dictionary, but apparently it doesn't, which is, I mean, a bit mapping. So a mapping just basically refers to something that behaves like a dictionary. So we actually have to create a dictionary which maps from the index to the name, which is a bit of a pointless thing to do in a sense, but that's okay. So for k comma v in, so if we enumerate through that. Okay. So that's a map, that's what a mapping looks like. So I could say mapping equals. And here we'll say mapping. There we go. So that's what we want. So this is basically our results, right? So I was thinking like an alternative way, like mapping also, map function also takes functions, correct? Correct. I was avoiding that because that, I mean, I know it doesn't matter here, but it's really slow. So we could also pass in a function. I was just thinking like you could just have a function that indexes into the, into the list or something like that. Correct. Correct. Like a lambda function or something like that. Exactly. Let's go ahead and do that to see what it looks like. But almost nobody knows that you can use a dictionary or a mapping. So almost everybody on KACL uses a function and often it can take a very, very, very long time to run at, you know, on big data sets. So yeah, you could also have a lambda and so that's going to pass in each index and you would just want to return the dls.vocab at i. So that does the same thing. Now obviously this is tiny, so it doesn't actually matter, but I've tried to show the neat trick which almost nobody knows about, which is the mapping. Okay. So we basically want to use that as our labels. So I think we can go SS label equals, there we go. Okay. So, you know, normally at this point I would like visually check some results. And the easiest way to visually check some results is to go learn.showResults. And this is showing me the actual and the predicted and the accuracy is very high, so you see all correct. The problem is I don't know which of these are right and which are wrong, so I have no idea what to look for. So I don't have that ability to do my normal checking. Okay. So we can say this is a CSV submission. There we go. Okay. So there's a few things we could do here. I guess probably the easiest one would be to use the Kaggle CLI. I was going to note something for the submission or for the two CSV. I think you might have to do index equals false because Right. I was going to say normally what I always do after that this time, which I forgot, is to do exclamation mark head to show me the first few lines. And yeah, so now we would see, as Tanishk says, we've got this extra column out the front, which is because the default is that it shows kind of the row number. Thanks, Tanishk. And so that will fix it. And if we compare that to their sample, yeah, it looks nice and similar. So that's good. So these are all kind of steps in the same thing. So I'll pop these all together. Bit of an item. And BD to get Patty. And there's that submission file. Oh, and there's no Kaggle installed on this machine. That's surprising. Okay. So generally minus help or minus minus, sorry, minus H or minus minus help normally gives you a quick version of help. And so you're going to want to do something with competitions. Competitions. Okay. There we go. And so we're going to want to do a submission. All right. We need a file for upload. And we're going to need the competition. And so I could go Kaggle competitions, list, type, grep, Patty. And that way I don't even have to. Oh, that's not what I expected to happen. Oh, I bet it pages it. Okay. So rather than grep, we should use minus S. And it's going to use a regular expression or something. Look at a few examples. Okay. So there's definitely something called space ship. Space ship. All right. I will go over here after all. This is what it's called. So I don't know. Is it not active? Probably. It's active. Yeah. And I don't think it ought to matter. Is it because it's like not really actually organized by Kaggle, maybe the only list. Or we need a capital letter. Category all. It's fine. But maybe it's group. Maybe this is considered in class. Don't know. Yeah. Anyhoo. So we were going to do a submission. And so we need to provide the file name minus F. Oh, full path. That's a bit weird. A message minus M. Initial con next to epoch by machine. Okay. And then the competition. Took a while for a 70 K file, but so be it. Okay. So. Let's see if it's there. It is. How did we do. I see. Oh, I jumped to your leaderboard position. 157. Out of. 167. So I'm guessing that there's a problem. Without submission because it's. I think maybe what happened was the. Test files were not like. They got shuffled somehow. Like maybe when you did get. Image files, it got shuffled or something like that. I think sometimes that might happen. Yeah, that's a good question. Yeah. Yeah. Yeah. That looks like that seems very likely. So we didn't do a great job of checking as we went. Yes. So they were expecting that 2001 would be first and we have 2000. So that is not. Ideal. Yeah, this has happened to me sometimes too. It would be nice to get image files by default. Return things in a more sensible order. Anyway, it's good to see these problems. You know, we could just sort it right. But it looks like it works. It probably does work as long as they've got exactly the same number as long as they're all 1, 2, 3, 4, 5, 6 digits. If some of them are different numbers of digits, we can't sort it because this is sorting in string order. But yeah, maybe that's OK. Test. Tail doesn't have a tail. Yes. 203469. 203469. Yeah, OK. Maybe we're fine then. So sorted. Oopsie daisy sorted. Returns the sorted version or sort sorts in place. OK. So those. Those. OK. And so it's very nice to have things set up. You know that you're doing things from the command line and notebooks and stuff so that when you screw up, which, you know, if you're anything like me, you will always screw up. You can pretty quickly repeat the process. So I just hit up arrow. That's sorted to our message. Literally and figuratively, hopefully. Welcome to the leaderboard. Not a very successful welcome. Oh, it's a bit better, isn't it? Point nine one. There we go. Good start. About in the middle. All right. So does anybody have questions about. Yeah, this process of. I see Mike had a question in the chat and I had the same problem. When people installing Tim. We, this is in paper space. I assume Mike was the same. We can see the list of models. But it doesn't actually create the learner. It says. Tim is not defined. So you need to. So, yeah. So, actually, I was able to do that. Matt, I just restarted my kernel. So just to explain when you see in Python, something is not defined. It means what it says. It means that that symbol. Python doesn't know what it is. And so there are. Two ways basically to define a symbol to create a symbol. One is to say something like a equals one that defines a symbol called a. Right. Or another is to do something like to death. And that defines a symbol called F. Right. Or the other way to define symbols is to import them. So in this case, Tim is not defined means you have not imported Tim. And that will solve your problem. Does that make sense? Yes, it does, but I. Yeah. It's sort of, I was importing Tim and running that command. I don't think it was working. It will definitely work. If you say import Tim, this will definitely work. So I'd say you might have reset your kernel or something and hadn't run that cell. Yeah. If you say if you restart the kernel, it works. Yeah. If you say import module. Yeah. Oh, yeah. I mean, the other possibility is that you might have got a different message, which is something like this module not found. And module not found means either you haven't pip installed it, or if you have pip installed it, you might need to restart your kernel by clicking kernel restart. So it can like recheck what modules you have since you just installed it. That's what I had. Got it. Great. Thank you. All right. Well, that was pretty successful. Even if paper space wasn't. Thanks guys. And see you. Yeah. See you tomorrow. Thanks for joining. Thanks, Jeremy. Thank you. Thank you.