Building the Software 2 0 Stack (Andrej Karpathy)

Andrej Karpathy argues that the future of software is not hand-coded but learned from data. Instead of engineers writing rules, you define a neural network and let gradient-based optimization write the code by learning from massive labeled datasets, as Tesla does with Autopilot. The real work becomes data labeling and tooling to manage it.
Chapters
Andrej Karpathy. Ah, great. Thank you. So I'm excited to be here. I'd like to tell you a little bit about what I see as a transformation in how we write software. So, as referring to Software 2.0. Actually, to tell the story correctly, I actually have to go back quite a bit of time, about 1 million years back. This is us throwing rocks at each other 1 million years ago, but we're actually a pretty clever species, We discovered how to control fire and then developed our agriculture, and then we started building machines. We use those machines for computation, and we transitioned the computation from mechanical to electrical. And then here we are, 2018, and we're writing software, and we've built up pretty complex software tools. And the way we've come about all of this progress is that we actually apply a single kind of approach to, to to advancing all of these applications. So first we identified some kind of a problem, and then we break it down to subproblems, and then we create algorithms for every one of those subproblems, and then we stack them together up into a system, and then those systems can actually get pretty elaborate and pretty complex. And so this has— this really kind of approach by decomposition has worked for us very well. And we've been able to create kind of amazing progress. Now, unfortunately, in the last few years, we've actually come across a few problems that actually make it really difficult to apply this methodology that has been so successful for us historically. So in particular, one problem that I'm quite familiar with is computer vision, and it's actually really difficult to take a million numbers that describe that image and turn that into a concept like a cat or not. And so this approach by decomposition and by engineering the solution is actually not working extremely well. So it's not for lack of trying. People have kind of tried to decompose computer vision. So we've come up with a theory of how we're going to break down the problem. If you'd like to recognize a human, maybe you'd like to recognize the parts of a human first, and we're going to go through several stages of processing, and we're going to try to engineer it. Unfortunately, this doesn't work very well because there's so much variation in what this looks like. So instead, in the 1990s, we started to discover that machine learning is actually a good way to go about some of these problems. So instead we're trying to think of accumulating a few datasets, but we are still trying, we're still in this mindset of developing engineering tools to adjust the problem. So we're still engineering the features because that's just how we are trained, that's how we make progress. And then we have a bit of machine learning on the top, like training a support vector machine. And then we figured out in 2012 that actually we want to step back and not design those features. We actually just want to lay out a skeleton of the architecture, of the convolutional network architecture, We want to leave much more to the optimization. In particular, we're optimizing over the weights of that network and we're training those features. And so we're stepping back, we're designing less, and things work better. Now, we're still designing the architectures, but some of the most state-of-the-art techniques for ImageNet actually step back even more and we're actually optimizing over the architectures now. So we do even less design. We don't even trust ourselves to lay out the architectures, and this is working well. As well. So really we're seeing this trend in using specific example of computer vision that the better you want the thing to work, if you have an evaluation criterion like the loss on your test set or the accuracy on your test set, then the best thing to do actually is to step back, design less, and leave more to the optimization. So really the way to look at it, I think a good kind of framework to have in mind is that if you'd like to design the code yourself, this is software 1.0, you sit down and you write some Python or C++, then you're going to identify some piece of the program space, you write an algorithm, and the algorithm can't be too complex, so it's somewhere around the origin because we're finite people. And so that's one solution, and then you can evaluate it, and then you can iterate on your algorithm. When you're approaching this from kind of the software 2.0 perspective, you're instead specifying a subset of programs that you're going to search over. So a convolutional neural network architecture, you're basically identifying a piece of the program space that you are willing to search for the solution in, And then the optimization actually finds a part of that program space that works really well on your data or on your problem. So the optimization really writes the code. We only identify a region where we should search. And so this is kind of— I had a tweet a while ago and the tweet said, gradient descent can write code better than you. I'm sorry. And people are kind of confused about what that meant. But this is kind of like what I meant is we don't write the code ourselves. We just lay out the skeleton. We don't trust to write the code, don't trust ourselves to write that code. And so this is working well not just in computer vision, but we're seeing this across other disciplines, machine translation, speech recognition, and so on. And it's not even constrained to datasets necessarily. Anytime you have an evaluation criterion that you can evaluate, such as playing even a good game of Go or chess and winning, you can actually apply this methodology. So you can either go on and write C++ and Python and complex repositories of code which is kind of the Stockfish approach, or you can step back and you can say, okay, I don't know how to write a Go plane program, so I'm just going to search the program space, and you can actually discover through optimization by paying in compute the much better algorithms in that space. And this is not even necessarily restricted to neural networks. You can also search over, say, assembly programs, like anything that works. If you have an evaluation criteria that you can repeatedly evaluate, then you're better off not designing. You're better off just stepping away and paying in compute to find programs that work really well. So, I'm the director of AI at Tesla, and we're applying this methodology to kind of get self-driving cars to work really well. So, we have, at Tesla, the largest deployment of robots in the world. We have about a quarter million robots, and our job is to try to make them autonomous and drive well. Now, when I arrived at Tesla maybe about a year ago, we basically have this software stack. The software stack is actually quite simple in terms of the code. There's a number of sensors that stream into the stack over time, and we're only trying to predict two scalars. We're trying to predict the steering and the acceleration of this vehicle, and we're trying to keep it in line and so on. And when I arrived, you have this, like, meld of code. Um, most of it was a huge C++ repository, but then of course there's a convolutional neural network doing some of the base visual recognition. And, uh, over the last year, we've basically been, uh, porting some of that code to the 2.0 stack. And, uh, we see that there are improvements when you actually adopt this approach and when you get it to work really well. And so, uh, this is— the red is the code that we've written and the blue is the code we've discovered through, uh, lots of compute. Um, so just to give you a concrete example of this transition and what that looks like, suppose you want to detect if a vehicle is parked or not. This is something we want to know because of the control algorithms. So one approach you might think of if you again are in this mindset of designing solutions, is you might say, okay, well, the neural network is giving me some kind of bounding boxes, and now a car is parked if— okay, so now I'm designing, right? So a car is on the edge of the road, and maybe it hasn't moved for a while, and maybe there's a pattern to the cars. And so this is not the right way to approach it, I think. It's— you're designing, and you shouldn't trust yourself to write that code. Instead, a car is parked if a neural network says so based on a lot of labeled data. That's a much better approach. And we see that it's a much better approach because we've tried. And we tried pretty hard. And so that's just an example of kind of this transition. And now in terms of, like, programming with the 2.0 stack, what does that look like? What are you actually doing? Where is the work? So what you might be familiar with, and this is what I'm familiar with as well, is when you're writing code, you're actually designing algorithms, you're measuring running times, you're engineering these, and you write out pseudocode like this, and you feel very clever when you get something really cool. This is not too much of what it looks like. In the 2.0 stack, the workforce splits in two. There's one large piece of the workforce, all they do is label data. So you have pretty complicated UI interfaces and these people are putting bounding boxes and lines and so on on these images, and in the process they are literally programming the Autopilot because this data will end up being compiled by the optimization into Software 2.0 code. And so they label and and we just help them out. This is what we do, the Software 1.0 programmers. We help out the Software 2.0 programmers. They're doing all the work. They're programming the autopilot. We try to help them out with surrounding infrastructure. So we create the UI tools, we create the analytics around it, and we kind of insert a layer of intelligence around some of these workflows that they have to go through, and I'll go into that in a bit more detail. So really, my background as a PhD student, and I spent a lot of time worrying about the models and the algorithms and how you actually train these networks, But when I kind of arrived to Tesla, there's been a little bit of a transformation in terms of, like, trying to actually apply this methodology and what that looks like in practice. My PhD is spent worrying about the architectures, but at Tesla, I spend most of my time just massaging the datasets. And this takes a huge amount of work, huge amount of effort, and you want to do it extremely well. So, just to give you hints at what this kind of— why this is so complex to maintain this infrastructure. So number one, even the data labeling is highly non-trivial as I found out pretty early. You might think this is pretty straightforward because we have some kind of an image and we want to of course stay in the lane. So, okay, so there's a lane line there, a lane line there, and we should stay in that lane. So this is the annotation instructions even to the labelers, and then you go out to the real world and you find all kinds of craziness. So this is somewhere in Europe, there's zigzag, and now you're suddenly really not sure, like, do I annotate the zigzag, do I go through? It's really not obvious. Or, you know, you find something like this, and then the labelers are confused and everyone's confused, and now I have to, like, change the labeling instructions. It's kind of a craziness. Like, what the hell is that? Why does it go on the side? Do I annotate with it and then someone later worries about it, or do I annotate through it and I try to put that in 2-point stack? Like, it's not obvious where you put this code that has to worry about that little kink. Or you're trying to label cars and you might think it's pretty straightforward to put bounding boxes around cars. This is very much not the case because there's lots of crazy stuff in the world. It's not obvious if this is one car or it's four cars or it's two cars because of the joint. Traffic lights, you might think it's just red, orange, green, and you put bounding boxes around them, but that gets really complicated really fast. So, yeah, and you end up basically accumulating these labeling documentations that are hundreds of pages to do some of these tasks right, and the— this 2.0 workforce actually has to be pretty highly skilled to even understand what you're trying to get them to label, and if they don't label it very well, then your network won't work very well. Speed limits are a complete disaster. I thought it was just a number, maybe I'll run some OCR or something, but speed limits are pretty complex. It's like 60 miles an hour if you're a truck after 6 PM during Sunday, I don't know, it's just— gets AI-complete extremely quickly, like how do I handle this in my neural network, what do I output, it's not obvious. So even the labeling, I was stuck there for a while. The next kind of huge challenge is if you're applying the stack, you need your data imbalances to be in check. So for example, if we're trying to recognize whether a car has a blinker on, you know, you might, as you might imagine, the blinkers are almost always off. So if you're naive and you just sample your data at random, then you will get very few examples of blinkers actually being on or off. And so suddenly you have to worry about your data imbalance and, and chasing it and developing the tools to actually find all those rare examples that are very important. Uh, for example, orange traffic lights are another, are another example. We have a huge amount of annotations for red and green, not as many for orange. And so the network struggles in those cases. It's not just about the labels, it's also about the data. So most of our data looks something like this highway driving going forward. And then of course, if you take a neural network that is trained on something like this and you bring it to an environment that looks different, that's not going to work very well. So either in this kind of environment or even in San Francisco where the roads do weird things, that might look foreign, and so now you need quite a bit of data to actually have a coverage and have a broad distribution. The other thing I didn't appreciate is just how iterative the labeling process is. In academia, I was just given ImageNet, that's done, but you can't annotate a dataset and be done with it. That's not something that happens. As an example, we have this auto wiper feature Normally you'd use a sensor, but Elon looked at some of these windshield images and he's like, well, vision can see, we can see raindrops, so we can just use that. And now it's my problem. So the problem now is we have a windshield and we're looking out with a camera and we're trying to just detect if there are raindrops there. And you might think this is pretty straightforward. We just collect some data, we train the model, we try to deploy it, and this completely breaks. It breaks in all the kind of rare situations. And that's the problem is, you know, if there's ice on the windshield, there's dust, The auto wiper, the initial result of it when we trained the first time, was extremely excited about tunnels. The wipers would just go like mad inside tunnels and when sun is in the view. So now what you have to do is you have to now massage your training set. So suddenly I need a lot more tunnels and I need to make sure that the network knows that you should not be turning on inside tunnels. And now I need to add that. I need to have enough of it in the dataset and worry about it. But if you do your job well, this actually works somewhat. We've shipped it. It works to a decent amount. We're still improving it. It definitely wipes when there's a lot of water on the windshield. In fact, it wipes even if you put cornflakes on there, according to this video called "Will It Wipe?" Cornflakes wipe. Ketchup does not wipe. So that's cool. So I think my kind of takeaway from being at Tesla for a year and trying to really apply this technology is is this is a whole new way of designing software, and we need tooling for it. We've been writing the 1.0 software for a long time, and we've written out IDE— for example, we have IDEs that help us write code. So, you know, we have pretty fancy programs that do, you know, highlight syntax highlighting, go to definition, debuggers, profilers, infrastructure for helping you write code. But now, instead of writing the code explicitly, we're accumulating and massaging the datasets and those are effectively the code because they are compiled by the optimization into code. So your dataset is really the code, and what is— where are the IDEs for datasets? And so we have some of our own answers to this, and we're still trying to develop it, and I'm not going to flash the exact interfaces, but just to give you an idea on a high level, some of the things we find very useful is around visualizing datasets, of course, making sure that you have a very broad distribution, that You want to look at the label distribution. You want to look at potentially some of the labels for each image or some of the predictions that the network makes for any image. So a lot of infrastructure just for getting a sense of what's in the dataset because that's really your code. Annotation is, of course, huge. So we have pretty complex tools. We're kind of designing what feels like a Photoshop really for data annotation because these Software 2.0 workers, this is their full-time job is to label data and you really want to make them power users and you want to get them to work really efficiently. And it's not just about the annotation itself, it's usually you have a workforce, and so now you need to make sure that when a labeler is confused, they don't just do something random. They need to be able to escalate a feature, escalate some kind of an image when they're confused, and you need to resolve that later. Or you need to flag disagreements between them. You need to make sure that they're performing well, and you of course want to potentially have a layer of AI kind of helping them out. Like, they're programming, you have to do your best to help them out. As one example of something we also found pretty useful, just to give you ideas of the workflows, for cleaning the datasets, the layer of AI that can help you with that is that your networks can actually tell when a label for an image looks suspicious. So for example, if you're annotating lane lines, that one on the very left will have a small loss because the network is like, oh yeah, that's right. But if you annotate a lane line in the sky by accident by one of the workers, the network can actually bubble it up and say, well, that looks weird. I would mispredict a lot on that. So we can create these clean datasets and we can help out the labelers to find to find the mistakes in the data. This is not only due to mistakes, by the way, but if we change the annotation instructions, which we do quite often, then when you change your labeling documentation, then suddenly lots of your data is suddenly mislabeled effectively, and you need to come back and you need to fix it. The other thing we worry about— a lot about is normally in your setting where you have a lot of labeled data, but then you have even more unlabeled data. In our case, we have the fleet. We have actually infinite data. The problem is not how do I train on my infinite data. The problem is how do I pick and choose intelligently what I should label? Because I have to pay for that labeling. What are the examples worth labeling? And of course, it's things like where your network is uncertain or mispredicts, and how do you bubble those up, and how do you show them to the labelers and show them that actually the network does mispredict here? And so you end up with what I refer to as kind of like a data engine where to fix these problems, you actually end up combining a number of microservices around this data infrastructure and around massaging of these datasets. So when you notice a problem like the tunnel gets our auto wiper way too excited. We need to have a way of boosting the amount of tunnels and we have a lot of infrastructure for bubbling those similar images up and then we label them and then we want to train, retrain and redeploy and we spin this data engine for all the tasks, for all the cameras and the nice benefit of this is that the programmers are not addressing all the edge cases themselves. You've made all the problems look the same way because now you just turn the data crank on all of it, and it's much easier to accumulate these datasets and have all of the infrastructure for all the problems, and then actually writing the explicit code in all the things that fail. And so we made all the problems kind of look the same with this approach, and then we just train the networks and we ship them and we just massage those datasets. And if we can do our job very well, then we'll be able to get this beautiful robot to drive nicely, and then more people will buy Tesla vehicles, and then the future will will be a good place on Earth and beyond. And so if you'd like to— if you're really excited about the Software 2.0 stack and want to push it to its limit, then please reach out. We need a lot more help building out the entire stack and the whole infrastructure. OK, thank you.
More from Andrej

Skill Issue: Andrej Karpathy on Code Agents, AutoResearch, and the Loopy Era of AI

Andrej Karpathy: Tesla AI, Self-Driving, Optimus, Aliens, and AGI | Lex Fridman Podcast #333








