Transcript of Let's build GPT: from scratch, in code, spelled out.
Andrej Karpathy
0:00hi everyone so by now you have probably0:02heard of chat GPT it has taken the world0:04and AI Community by storm and it is a0:07system that allows you to interact with0:09an AI and give it text based tasks so0:12for example we can ask chat GPT to write0:15us a small Hau about how important it is0:16that people understand Ai and then they0:18can use it to improve the world and make0:20it more prosperous so when we run this0:23AI knowledge brings prosperity for all0:25to see Embrace its0:27power okay not bad and so you could see0:29that chpt went from left to right and0:32generated all these words SE sort of0:35sequentially now I asked it already the0:37exact same prompt a little bit earlier0:39and it generated a slightly different0:41outcome ai's power to grow ignorance0:44holds us back learn Prosperity weights0:47so uh pretty good in both cases and0:49slightly different so you can see that0:50chat GPT is a probabilistic system and0:52for any one prompt it can give us0:54multiple answers sort of uh replying to0:57it now this is just one example of a0:59problem people have come up with many1:01many examples and there are entire1:03websites that index interactions with1:06chpt and so many of them are quite1:08humorous explain HTML to me like I'm a1:10dog uh write release notes for chess 21:14write a note about Elon Musk buying a1:16Twitter and so on so as an example uh1:20please write a breaking news article1:21about a leaf falling from a1:23tree uh and a shocking turn of events a1:26leaf has fallen from a tree in the local1:28park Witnesses report that the leaf1:30which was previously attached to a1:31branch of a tree attached itself and1:33fell to the ground very dramatic so you1:36can see that this is a pretty remarkable1:37system and it is what we call a language1:40model uh because it um it models the1:43sequence of words or characters or1:46tokens more generally and it knows how1:49sort of words follow each other in1:50English language and so from its1:52perspective what it is doing is it is1:55completing the sequence so I give it the1:57start of a sequence and it completes the2:00sequence with the outcome and so it's a2:02language model in that sense now I would2:05like to focus on the under the hood of2:07um under the hood components of what2:09makes CH GPT work so what is the neural2:12network under the hood that models the2:14sequence of these words and that comes2:17from this paper called attention is all2:19you need in 2017 a landmark paper a2:23landmark paper in AI that produced and2:25proposed the Transformer2:27architecture so GPT is uh short for2:31generally generatively pre-trained2:33Transformer so Transformer is the neuron2:35nut that actually does all the heavy2:36lifting under the hood it comes from2:39this paper in 2017 now if you read this2:41paper this uh reads like a pretty random2:44machine translation paper and that's2:46because I think the authors didn't fully2:47anticipate the impact that the2:49Transformer would have on the field and2:51this architecture that they produced in2:52the context of machine translation in2:54their case actually ended up taking over2:57uh the rest of AI in the next 5 years3:00after and so this architecture with3:02minor changes was copy pasted into a3:05huge amount of applications in AI in3:07more recent years and that includes at3:10the core of chat GPT now we are not3:13going to what I'd like to do now is I'd3:15like to build out something like chat3:17GPT but uh we're not going to be able to3:19of course reproduce chat GPT this is a3:21very serious production grade system it3:23is trained on uh a good chunk of3:26internet and then there's a lot of uh3:29pre-training and fine-tuning stages to3:31it and so it's very complicated what I'd3:33like to focus on is just to train a3:36Transformer based language model and in3:38our case it's going to be a character3:40level language model I still think that3:43is uh very educational with respect to3:45how these systems work so I don't want3:47to train on the chunk of Internet we3:48need a smaller data set in this case I3:51propose that we work with uh my favorite3:53toy data set it's called tiny3:55Shakespeare and um what it is is3:57basically it's a concatenation of all of3:59the works of sh Shakespeare in my4:00understanding and so this is all of4:02Shakespeare in a single file uh this4:05file is about 1 megab and it's just all4:07of4:08Shakespeare and what we are going to do4:10now is we're going to basically model4:12how these characters uh follow each4:14other so for example given a chunk of4:16these characters like this uh given some4:19context of characters in the past the4:22Transformer neural network will look at4:24the characters that I've highlighted and4:26is going to predict that g is likely to4:28come next in the sequence and it's going4:30to do that because we're going to train4:31that Transformer on Shakespeare and it's4:34just going to try to produce uh4:36character sequences that look like this4:39and in that process is going to model4:40all the patterns inside this data so4:43once we've trained the system i' just4:45like to give you a preview we can4:47generate infinite Shakespeare and of4:49course it's a fake thing that looks kind4:51of like4:53Shakespeare4:55um apologies for there's some Jank that4:59I'm not able to resolve in in here but5:02um you can see how this is going5:05character by character and it's kind of5:07like predicting Shakespeare like5:09language so verily my Lord the sites5:12have left the again the king coming with5:15my curses with precious pale and then5:19tranos say something else Etc and this5:21is just coming out of the Transformer in5:23a very similar manner as it would come5:25out in chat GPT in our case character by5:27character in chat GPT uh it's coming out5:31on the token by token level and tokens5:33are these sort of like little subword5:35pieces so they're not Word level they're5:36kind of like word chunk5:38level um and now I've already written5:43this entire code uh to train these5:45Transformers um and it is in a GitHub5:48repository that you can find and it's5:50called nanog5:51GPT so nanog GPT is a repository that5:54you can find in my GitHub and it's a5:56repository for training Transformers um5:59on any given text and what I think is6:02interesting about it because there's6:03many ways to train Transformers but this6:05is a very simple implementation so it's6:06just two files of 300 lines of code each6:10one file defines the GPT model the6:12Transformer and one file trains it on6:14some given Text data set and here I'm6:17showing that if you train it on a open6:18web Text data set which is a fairly6:20large data set of web pages then I6:22reproduce the the performance of6:25gpt2 so gpt2 is an early version of open6:29AI GPT uh from 2017 if I recall6:32correctly and I've only so far6:34reproduced the the smallest 124 million6:36parameter model uh but basically this is6:38just proving that the codebase is6:39correctly arranged and I'm able to load6:42the uh neural network weights that openi6:45has released later so you can take a6:48look at the finished code here in N GPT6:50but what I would like to do in this6:51lecture is I would like to basically uh6:55write this repository from scratch so6:57we're going to begin with an empty file6:59and we're we're going to define a7:00Transformer piece by piece we're going7:03to train it on the tiny Shakespeare data7:05set and we'll see how we can then uh7:08generate infinite Shakespeare and of7:10course this can copy paste to any7:12arbitrary Text data set uh that you like7:14uh but my goal really here is to just7:16make you understand and appreciate uh7:18how under the hood chat GPT works and um7:22really all that's required is a7:24Proficiency in Python and uh some basic7:27understanding of um calculus and7:29statistics7:30and it would help if you also see my7:32previous videos on the same YouTube7:34channel in particular my make more7:35series where I um Define smaller and7:40simpler neural network language models7:42uh so multi perceptrons and so on it7:45really introduces the language modeling7:46framework and then uh here in this video7:49we're going to focus on the Transformer7:50neural network itself okay so I created7:53a new Google collab uh jup notebook here7:57and this will allow me to later easily7:58share this code that we're going to8:00develop together uh with you so you can8:01follow along so this will be in a video8:03description uh later now here I've just8:07done some preliminaries I downloaded the8:09data set the tiny Shakespeare data set8:10at this URL and you can see that it's8:12about a 1 Megabyte file then here I open8:15the input.txt file and just read in all8:17the text of the string and we see that8:20we are working with 1 million characters8:22roughly and the first 1,000 characters8:24if we just print them out are basically8:26what you would expect this is the first8:281,000 characters of the tiny Shakespeare8:30data set roughly up to here so so far so8:34good next we're going to take this text8:37and the text is a sequence of characters8:39in Python so when I call the set8:41Constructor on it I'm just going to get8:44the set of all the characters that occur8:46in this text and then I call list on8:49that to create a list of those8:51characters instead of just a set so that8:53I have an ordering an arbitrary ordering8:56and then I sort that so basically we get8:59just all the characters that occur in9:00the entire data set and they're sorted9:02now the number of them is going to be9:04our vocabulary size these are the9:06possible elements of our sequences and9:09we see that when I print here the9:11characters there's 65 of them in total9:14there's a space character and then all9:16kinds of special characters and then U9:19capitals and lowercase letters so that's9:21our vocabulary and that's the sort of9:23like possible uh characters that the9:25model can see or emit okay so next we9:29will would like to develop some strategy9:31to tokenize the input text now when9:35people say tokenize they mean convert9:36the raw text as a string to some9:39sequence of integers According to some9:41uh notebook According to some vocabulary9:43of possible elements so as an example9:46here we are going to be building a9:48character level language model so we're9:49simply going to be translating9:50individual characters into integers so9:53let me show you uh a chunk of code that9:55sort of does that for us so we're9:57building both the encoder and the9:58decoder10:00and let me just talk through what's10:01happening10:02here when we encode an arbitrary text10:05like hi there we're going to receive a10:08list of integers that represents that10:10string so for example 46 47 Etc and then10:14we also have the reverse mapping so we10:17can take this list and decode it to get10:20back the exact same string so it's10:22really just like a translation to10:24integers and back for arbitrary string10:26and for us it is done on a character10:28level10:30now the way this was achieved is we just10:31iterate over all the characters here and10:34create a lookup table from the character10:35to the integer and vice versa and then10:38to encode some string we simply10:40translate all the characters10:41individually and to decode it back we10:44use the reverse mapping and concatenate10:46all of it now this is only one of many10:49possible encodings or many possible sort10:51of tokenizers and it's a very simple one10:54but there's many other schemas that10:55people have come up with in practice so10:57for example Google uses a sentence10:59piece uh so sentence piece will also11:02encode text into um integers but in a11:05different schema and using a different11:08vocabulary and sentence piece is a11:10subword uh sort of tokenizer and what11:13that means is that um you're not11:15encoding entire words but you're not11:17also encoding individual characters it's11:19it's a subword unit level and that's11:22usually what's adopted in practice for11:24example also openai has this Library11:26called tick token that uses a bite pair11:28encode11:29tokenizer um and that's what GPT uses11:33and you can also just encode words into11:35like hell world into a list of integers11:38so as an example I'm using the Tik token11:40Library here I'm getting the encoding11:43for gpt2 or that was used for gpt211:46instead of just having 65 possible11:48characters or tokens they have 50,00011:51tokens and so when they encode the exact11:54same string High there we only get a11:57list of three integers but those11:59integers are not between 0 and 64 they12:01are between Z and 5,12:055,256 so basically you can trade off the12:09code book size and the sequence lengths12:12so you can have very long sequences of12:13integers with very small vocabularies or12:16we can have short um sequences of12:20integers with very large vocabularies12:23and so typically people use in practice12:25these subword encodings but I'd like to12:28keep our token ier very simple so we're12:30using character level tokenizer and that12:33means that we have very small code books12:35we have very simple encode and decode12:37functions uh but we do get very long12:40sequences as a result but that's the12:42level at which we're going to stick with12:43this lecture because it's the simplest12:45thing okay so now that we have an12:46encoder and a decoder effectively a12:49tokenizer we can tokenize the entire12:51training set of Shakespeare so here's a12:53chunk of code that does that and I'm12:55going to start to use the pytorch12:56library and specifically the torch.12:58tensor from the pytorch library so we're13:01going to take all of the text in tiny13:03Shakespeare encode it and then wrap it13:05into a torch. tensor to get the data13:08tensor so here's what the data tensor13:10looks like when I look at just the first13:121,000 characters or the 1,000 elements13:14of it so we see that we have a massive13:16sequence of integers and this sequence13:18of integers here is basically an13:20identical translation of the first13:2210,000 characters13:24here so I believe for example that zero13:27is a new line character and maybe one13:29one is a space not 100% sure but from13:32now on the entire data set of text is13:34re-represented as just it's just13:35stretched out as a single very large uh13:38sequence of13:39integers let me do one more thing before13:41we move on here I'd like to separate out13:43our data set into a train and a13:45validation split so in particular we're13:48going to take the first 90% of the data13:51set and consider that to be the training13:52data for the Transformer and we're going13:54to withhold the last 10% at the end of13:56it to be the validation data and this13:59will help us understand to what extent14:01our model is overfitting so we're going14:03to basically hide and keep the14:04validation data on the side because we14:06don't want just a perfect memorization14:08of this exact Shakespeare we want a14:11neural network that sort of creates14:12Shakespeare like uh text and so it14:15should be fairly likely for it to14:17produce the actual like stowed away uh14:21true Shakespeare text um and so we're14:24going to use this to uh get a sense of14:26the overfitting okay so now we would14:28like to start plugging these text14:30sequences or integer sequences into the14:32Transformer so that it can train and14:34learn those patterns now the important14:36thing to realize is we're never going to14:38actually feed entire text into a14:40Transformer all at once that would be14:42computationally very expensive and14:44prohibitive so when we actually train a14:46Transformer on a lot of these data sets14:48we only work with chunks of the data set14:50and when we train the Transformer we14:52basically sample random little chunks14:53out of the training set and train on14:55just chunks at a time and these chunks14:58have basically some kind of a length and15:01some maximum length now the maximum15:04length typically at least in the code I15:06usually write is called block size you15:08can you can uh find it under different15:10names like context length or something15:12like that let's start with the block15:14size of just eight and let me look at15:16the first train data characters the15:18first block size plus one characters15:20I'll explain why plus one in a15:22second so this is the first nine15:24characters in the sequence in the15:27training set now what I'd like to point15:30out is that when you sample a chunk of15:31data like this so say the these nine15:34characters out of the training set this15:36actually has multiple examples packed15:38into it and uh that's because all of15:41these characters follow each other and15:43so what this thing is going to say when15:47we plug it into a Transformer is we're15:49going to actually simultaneously train15:50it to make prediction at every one of15:52these15:53positions now in the in a chunk of nine15:56characters there's actually eight indiv15:58ual examples packed in there so there's16:01the example that when 18 when in the16:04context of 18 47 likely comes next in a16:08context of 18 and 47 56 comes next in a16:12context of 18 47 56 57 can come next and16:16so on so that's the eight individual16:18examples let me actually spell it out16:20with16:21code so here's a chunk of code to16:24illustrate X are the inputs to the16:26Transformer it will just be the first16:28block size characters y will be the uh16:32next block size characters so it's16:34offset by one and that's because y are16:37the targets for each position in the16:40input and then here I'm iterating over16:42all the block size of eight and the16:45context is always all the characters in16:47x uh up to T and including T and the16:51target is always the teth character but16:53in the targets array y so let me just16:56run16:57this and basically it spells out what I16:59said in words uh these are the eight17:02examples hidden in a chunk of nine17:04characters that we uh sampled from the17:08training set I want to mention one more17:11thing we train on all the eight examples17:14here with context between one all the17:16way up to context of block size and we17:19train on that not just for computational17:20reasons because we happen to have the17:22sequence already or something like that17:23it's not just done for efficiency it's17:26also done um to make the Transformer17:28Network be used to seeing contexts all17:32the way from as little as one all the17:33way to block size and we'd like the17:36transform to be used to seeing17:38everything in between and that's going17:39to be useful later during inference17:41because while we're sampling we can17:43start the sampling generation with as17:45little as one character of context and17:47the Transformer knows how to predict the17:49next character with all the way up to17:51just context of one and so then it can17:53predict everything up to block size and17:55after block size we have to start17:56truncating because the Transformer will17:58will never um receive more than block18:01size inputs when it's predicting the18:03next18:03character Okay so we've looked at the18:06time dimension of the tensors that are18:07going to be feeding into the Transformer18:09there's one more Dimension to care about18:11and that is the batch Dimension and so18:13as we're sampling these chunks of text18:15we're going to be actually every time18:17we're going to feed them into a18:18Transformer we're going to have many18:20batches of multiple chunks of text that18:22are all like stacked up in a single18:23tensor and that's just done for18:25efficiency just so that we can keep the18:27gpus busy uh because they are very good18:29at parallel processing of um of data and18:33so we just want to process multiple18:35chunks all at the same time but those18:37chunks are processed completely18:38independently they don't talk to each18:39other and so on so let me basically just18:42generalize this and introduce a batch18:44Dimension here's a chunk of18:46code let me just run it and then I'm18:48going to explain what it18:50does so here because we're going to18:52start sampling random locations in the18:54data set to pull chunks from I am18:57setting the seed so that um in the19:00random number generator so that the19:01numbers I see here are going to be the19:02same numbers you see later if you try to19:04reproduce this now the batch size here19:07is how many independent sequences we are19:09processing every forward backward pass19:11of the19:12Transformer the block size as I19:14explained is the maximum context length19:16to make those predictions so let's say B19:19size four block size eight and then19:21here's how we get batch for any19:23arbitrary split if the split is a19:25training split then we're going to look19:26at train data otherwise at valid data19:30that gives us the data array and then19:33when I Generate random positions to grab19:35a chunk out of I actually grab I19:38actually generate batch size number of19:41Random offsets so because this is four19:44we are ex is going to be a uh four19:47numbers that are randomly generated19:49between zero and Len of data minus block19:51size so it's just random offsets into19:53the training19:54set and then X's as I explained are the19:58first first block size characters20:00starting at I the Y's are the offset by20:05one of that so just add plus one and20:08then we're going to get those chunks for20:10every one of integers I INX and use a20:14torch. stack to take all those uh uh20:17one-dimensional tensors as we saw here20:20and we're going to um stack them up at20:24rows and so they all become a row in a20:274x8 tensor20:29so here's where I'm printing then when I20:32sample a batch XB and YB the inputs to20:35the Transformer now are the input X is20:39the 4x8 tensor four uh rows of eight20:44columns and each one of these is a chunk20:47of the training20:48set and then the targets here are in the20:52associated array Y and they will come in20:54to the Transformer all the way at the20:55end uh to um create the loss function20:59uh so they will give us the correct21:01answer for every single position inside21:03X and then these are the four21:06independent21:07rows so spelled out as we did21:11before uh this 4x8 array contains a21:14total of 32 examples and they're21:17completely independent as far as the21:19Transformer is21:20concerned uh so when the input is 24 the21:25target is 43 or rather 43 here in the Y21:28array21:29when the input is 2443 the target is21:3158 uh when the input is 24 43 58 the21:34target is 5 Etc or like when it is a 5221:38581 the target is21:4058 right so you can sort of see this21:43spelled out these are the 32 independent21:45examples packed in to a single batch of21:48the input X and then the desired targets21:51are in y and so now this integer tensor21:57of um X is going to feed into the22:00Transformer and that Transformer is22:02going to simultaneously process all22:04these examples and then look up the22:06correct um integers to predict in every22:08one of these positions in the tensor y22:11okay so now that we have our batch of22:13input that we'd like to feed into a22:15Transformer let's start basically22:16feeding this into neural networks now22:19we're going to start off with the22:20simplest possible neural network which22:22in the case of language modeling in my22:23opinion is the Byram language model and22:25we've covered the Byram language model22:26in my make more series in a lot of depth22:29and so here I'm going to sort of go22:31faster and let's just Implement pytorch22:33module directly that implements the byr22:36language22:36model so I'm importing the pytorch um NN22:41module uh for22:43reproducibility and then here I'm22:44constructing a Byram language model22:46which is a subass of NN22:48module and then I'm calling it and I'm22:51passing it the inputs and the targets22:53and I'm just printing now when the22:55inputs on targets come here you see that22:57I'm just taking the index uh the inputs23:00X here which I rename to idx and I'm23:03just passing them into this token23:04embedding table so it's going on here is23:07that here in the Constructor we are23:09creating a token embedding table and it23:12is of size vocap size by vocap23:15size and we're using an. embedding which23:18is a very thin wrapper around basically23:20a tensor of shape voap size by vocab23:23size and what's happening here is that23:25when we pass idx here every single23:28integer in our input is going to refer23:30to this embedding table and it's going23:32to pluck out a row of that embedding23:34table corresponding to its index so 2423:37here will go into the embedding table23:39and we'll pluck out the 24th row and23:42then 43 will go here and pluck out the23:4443d row Etc and then pytorch is going to23:47arrange all of this into a batch by Time23:50by channel uh tensor in this case batch23:53is four time is eight and C which is the23:57channels is vocab size or 65 and so24:01we're just going to pluck out all those24:02rows arrange them in a b by T by C and24:05now we're going to interpret this as the24:07logits which are basically the scores24:10for the next character in the sequence24:12and so what's happening here is we are24:14predicting what comes next based on just24:17the individual identity of a single24:19token and you can do that because um I24:22mean currently the tokens are not24:23talking to each other and they're not24:25seeing any context except for they're24:26just seeing themselves so I'm a f I'm a24:29token number five and then I can24:32actually make pretty decent predictions24:33about what comes next just by knowing24:35that I'm token five because some24:37characters uh know um C follow other24:39characters in in typical scenarios so we24:42saw a lot of this in a lot more depth in24:44the make more series and here if I just24:46run this then we currently get the24:49predictions the scores the lits for24:53every one of the 4x8 positions now that24:55we've made predictions about what comes24:57next we'd like to evaluate the loss24:58function and so in make more series we25:00saw that a good way to measure a loss or25:03like a quality of the predictions is to25:05use the negative log likelihood loss25:07which is also implemented in pytorch25:09under the name cross entropy so what we'25:12like to do here is loss is the cross25:15entropy on the predictions and the25:17targets and so this measures the quality25:20of the logits with respect to the25:21Targets in other words we have the25:24identity of the next character so how25:26well are we predicting the next25:28character based on the lits and25:30intuitively the correct um the correct25:33dimension of low jits uh depending on25:36whatever the target is should have a25:38very high number and all the other25:39dimensions should be very low number25:41right now the issue is that this won't25:44actually this is what we want we want to25:46basically output the logits and the25:50loss this is what we want but25:52unfortunately uh this won't actually run25:55we get an error message but intuitively25:57we want to uh measure this now when we26:01go to the pytorch um cross entropy26:04documentation here um we're trying to26:08call the cross entropy in its functional26:10form uh so that means we don't have to26:11create like a module for it but here26:14when we go to the documentation you have26:16to look into the details of how pitor26:18expects these inputs and basically the26:20issue here is ptor expects if you have26:24multi-dimensional input which we do26:25because we have a b BYT by C tensor then26:28it actually really wants the channels to26:31be the second uh Dimension here so if26:35you um so basically it wants a b by C26:38BYT instead of a b by T by C and so it's26:42just the details of how P torch treats26:45um these kinds of inputs and so we don't26:49actually want to deal with that so what26:51we're going to do instead is we need to26:52basically reshape our logits so here's26:54what I like to do I like to take26:56basically give names to the dimensions26:58so lit. shape is B BYT by C and unpack27:01those numbers and then let's uh say that27:04logits equals lit. View and we want it27:07to be a b * c b * T by C so just a two-27:11dimensional27:12array right so we're going to take all27:15the we're going to take all of these um27:18positions here and we're going to uh27:20stretch them out in a onedimensional27:22sequence and uh preserve the channel27:25Dimension as the second27:26dimension so we're just kind of like27:28stretching out the array so it's two-27:29dimensional and in that case it's going27:31to better conform to what pytorch uh27:33sort of expects in its Dimensions now we27:36have to do the same to targets because27:38currently targets are um of shape B by T27:44and we want it to be just B * T so27:47onedimensional now alternatively you27:49could always still just do minus one27:51because pytor will guess what this27:53should be if you want to lay it out uh27:55but let me just be explicit and say p *27:57t once we've reshaped this it will match28:00the cross entropy case and then we28:03should be able to evaluate our28:06loss okay so that R now and we can do28:10loss and So currently we see that the28:12loss is28:134.87 now because our uh we have 6528:17possible vocabulary elements we can28:19actually guess at what the loss should28:20be and in28:22particular we covered negative log28:24likelihood in a lot of detail we are28:26expecting log or lawn of um 1 over 6528:32and negative of that so we're expecting28:34the loss to be about 4.1 17 but we're28:37getting 4.87 and so that's telling us28:40that the initial predictions are not uh28:42super diffuse they've got a little bit28:43of entropy and so we're guessing wrong28:47uh so uh yes but actually we're I a we28:50are able to evaluate the loss okay so28:53now that we can evaluate the quality of28:54the model on some data we'd like to also28:57be able to generate from the model so28:59let's do the generation now I'm going to29:01go again a little bit faster here29:03because I covered all this already in29:04previous29:05videos29:07so here's a generate function for the29:11model so we take some uh we take the the29:15same kind of input idx here and29:18basically this is the current uh context29:22of some characters in a batch in some29:24batch so it's also B BYT and the job of29:28generate is to basically take this B BYT29:30and extend it to be B BYT + 1 plus 229:32plus 3 and so it's just basically it29:34continues the generation in all the29:36batch dimensions in the time Dimension29:39So that's its job and it will do that29:41for Max new tokens so you can see here29:43on the bottom there's going to be some29:45stuff here but on the bottom whatever is29:47predicted is concatenated on top of the29:50previous idx along the First Dimension29:53which is the time Dimension to create a29:54b BYT + one so that becomes a new idx so29:58the job of generate is to take a b BYT30:00and make it a b BYT plus 1 plus 2 plus30:02three as many as we want Max new tokens30:05so this is the generation from the model30:08now inside the generation what what are30:10we doing we're taking the current30:11indices we're getting the predictions so30:15we get uh those are in the low jits and30:18then the loss here is going to be30:19ignored because um we're not we're not30:21using that and we have no targets that30:23are sort of ground truth targets that30:25we're going to be comparing with30:28then once we get the logits we are only30:30focusing on the last step so instead of30:33a b by T by C we're going to pluck out30:36the negative-1 the last element in the30:38time Dimension because those are the30:40predictions for what comes next so that30:42gives us the logits which we then30:44convert to probabilities via softmax and30:47then we use tor. multinomial to sample30:49from those probabilities and we ask30:51pytorch to give us one sample and so idx30:54next will become a b by one because in30:57each uh one of the batch Dimensions31:00we're going to have a single prediction31:01for what comes next so this num samples31:03equals one will make this be a31:06one and then we're going to take those31:08integers that come from the sampling31:10process according to the probability31:11distribution given here and those31:13integers got just concatenated on top of31:15the current sort of like running stream31:17of integers and this gives us a b BYT +31:20one and then we can return that now one31:24thing here is you see how I'm calling31:26self of idx which will end up going to31:29the forward function I'm not providing31:31any Targets So currently this would give31:33an error because targets is uh is uh31:36sort of like not given so targets has to31:39be optional so targets is none by31:41default and then if targets is none then31:44there's no loss to create so it's just31:47loss is none but else all of this31:50happens and we can create a loss so this31:53will make it so um if we have the31:56targets we provide them and get a loss31:57if we have no targets it will'll just31:59get the32:00loits so this here will generate from32:02the model um and let's take that for a32:06ride32:08now oops so I have another code chunk32:11here which will generate for the model32:13from the model and okay this is kind of32:15crazy so maybe let me let me break this32:18down so these are the idx32:23right I'm creating a batch will be just32:26one time will be just one so I'm32:30creating a little one by one tensor and32:32it's holding a zero and the D type the32:35data type is uh integer so zero is going32:38to be how we kick off the generation and32:40remember that zero is uh is the element32:44standing for a new line character so32:45it's kind of like a reasonable thing to32:47to feed in as the very first character32:49in a sequence to be the new32:51line um so it's going to be idx which32:54we're going to feed in here then we're32:56going to ask for 100 tokens32:58and then. generate will continue that33:01now because uh generate works on the33:05level of batches we we then have to33:07index into the zero throw to basically33:09unplug the um the single batch Dimension33:13that exists and then that gives us a um33:18time steps just a onedimensional array33:20of all the indices which we will convert33:23to simple python list from pytorch33:26tensor so that that can feed into our33:28decode function and uh convert those33:32integers into text so let me bring this33:34back and we're generating 100 tokens33:37let's33:37run and uh here's the generation that we33:40achieved so obviously it's garbage and33:43the reason it's garbage is because this33:44is a totally random model so next up33:47we're going to want to train this model33:49now one more thing I wanted to point out33:50here is this function is written to be33:53General but it's kind of like ridiculous33:55right now because33:58we're feeding in all this we're building33:59out this context and we're concatenating34:02it all and we're always feeding it all34:05into the model but that's kind of34:07ridiculous because this is just a simple34:09Byram model so to make for example this34:11prediction about K we only needed this W34:14but actually what we fed into the model34:15is we fed the entire sequence and then34:18we only looked at the very last piece34:20and predicted K so the only reason I'm34:23writing it in this way is because right34:25now this is a byr model but I'd like to34:27keep keep this function fixed and I'd34:29like it to work um later when our34:32characters actually um basically look34:35further in the history and so right now34:37the history is not used so this looks34:39silly uh but eventually the history will34:42be used and so that's why we want to uh34:44do it this way so just a quick comment34:46on that so now we see that this is um34:49random so let's train the model so it34:51becomes a bit less random okay let's Now34:53train the model so first what I'm going34:55to do is I'm going to create a pyour34:57optimization object so here we are using35:00the optimizer ATM W um now in a make35:05more series we've only ever use tastic35:06gradi in descent the simplest possible35:08Optimizer which you can get using the35:10SGD instead but I want to use Adam which35:12is a much more advanced and popular35:14Optimizer and it works extremely well35:16for uh typical good setting for the35:19learning rate is roughly 3 E4 uh but for35:22very very small networks like is the35:23case here you can get away with much35:25much higher learning rates R3 or even35:28higher probably but let me create the35:30optimizer object which will basically35:33take the gradients and uh update the35:35parameters using the35:36gradients and then here our batch size35:40up above was only four so let me35:41actually use something bigger let's say35:4332 and then for some number of steps um35:46we are sampling a new batch of data35:48we're evaluating the loss uh we're35:51zeroing out all the gradients from the35:52previous step getting the gradients for35:54all the parameters and then using those35:56gradients to up update our parameters so35:58typical training loop as we saw in the36:00make more series so let me now uh run36:04this for say 100 iterations and let's36:07see what kind of losses we're going to36:09get so we started around36:124.7 and now we're getting to down to36:14like 4.6 4.5 Etc so the optimization is36:18definitely happening but um let's uh36:22sort of try to increase number of36:23iterations and only print at the36:25end because we probably want train for36:29longer okay so we're down to 3.636:34roughly roughly down to36:40three this is the most janky36:46optimization okay it's working let's36:48just do36:5010,000 and then from here we want to36:53copy this and hopefully that we're going36:56to get something reason and of course36:58it's not going to be Shakespeare from a37:00byr model but at least we see that the37:01loss is improving and uh hopefully we're37:05expecting something a bit more37:06reasonable okay so we're down at about37:082.5 is let's see what we get okay37:12dramatic improvements certainly on what37:14we had here so let me just increase the37:17number of tokens okay so we see that37:19we're starting to get something at least37:21like reasonable is37:25um certainly not shakes spear but uh the37:29model is making progress so that is the37:31simplest possible37:33model so now what I'd like to do37:36is obviously this is a very simple model37:39because the tokens are not talking to37:41each other so given the previous context37:43of whatever was generated we're only37:45looking at the very last character to37:46make the predictions about what comes37:48next so now these uh now these tokens37:50have to start talking to each other and37:53figuring out what is in the context so37:55that they can make better predictions37:56for what comes next and this is how37:57we're going to kick off the uh37:59Transformer okay so next I took the code38:02that we developed in this juper notebook38:03and I converted it to be a script and38:05I'm doing this because I just want to38:08simplify our intermediate work into just38:10the final product that we have at this38:12point so in the top here I put all the38:15hyp parameters that we to find I38:16introduced a few and I'm going to speak38:18to that in a little bit otherwise a lot38:20of this should be recognizable uh38:23reproducibility read data get the38:25encoder and the decoder create the train38:27into splits uh use the uh kind of like38:30data loader um that gets a batch of the38:34inputs and Targets this is new and I'll38:36talk about it in a second now this is38:39the Byram language model that we38:40developed and it can forward and give us38:43a logits and loss and it can38:45generate and then here we are creating38:48the optimizer and this is the training38:51Loop so everything here should look38:53pretty familiar now some of the small38:55things that I added number one I added38:57the ability to run on a GPU if you have39:00it so if you have a GPU then you can39:02this will use Cuda instead of just CPU39:04and everything will be a lot more faster39:07now when device becomes Cuda then we39:09need to make sure that when we load the39:11data we move it to39:13device when we create the model we want39:15to move uh the model parameters to39:18device so as an example here we have the39:21N an embedding table and it's got a39:23weight inside it which stores the uh39:26sort of lookup table so so that would be39:27moved to the GPU so that all the39:29calculations here happen on the GPU and39:32they can be a lot faster and then39:34finally here when I'm creating the39:35context that feeds in to generate I have39:37to make sure that I create it on the39:39device number two what I introduced is39:43uh the fact that here in the training39:46Loop here I was just printing the um l.39:50item inside the training Loop but this39:53is a very noisy measurement of the39:54current loss because every batch will be39:56more or less lucky and so what I want to39:59do usually um is uh I have an estimate40:02loss function and the estimate loss40:05basically then um goes up here and it40:10averages up the loss over multiple40:12batches so in particular we're going to40:15iterate eval iter times and we're going40:17to basically get our loss and then we're40:19going to get the average loss for both40:21splits and so this will be a lot less40:24noisy so here when we call the estimate40:26loss we're we're going to report the uh40:28pretty accurate train and validation40:31loss now when we come back up you'll40:33notice a few things here I'm setting the40:35model to evaluation phase and down here40:38I'm resetting it back to training phase40:40now right now for our model as is this40:42doesn't actually do anything because the40:44only thing inside this model is this uh40:46nn. embedding and um this this um40:51Network would behave both would behave40:53the same in both evaluation mode and40:55training mode we have no drop off layers40:57we have no batm layers Etc but it is a41:00good practice to Think Through what mode41:02your neural network is in because some41:04layers will have different Behavior Uh41:07at inference time or training time and41:11there's also this context manager torch41:12up nograd and this is just telling41:14pytorch that everything that happens41:16inside this function we will not call do41:18backward on and so pytorch can be a lot41:21more efficient with its memory use41:23because it doesn't have to store all the41:25intermediate variables uh because we're41:27never going to call backward and so it41:29can it can be a lot more memory41:30efficient in that way so also a good41:32practice to tpy torch when we don't41:35intend to do back41:36propagation so right now this script is41:39about 120 lines of code of and that's41:43kind of our starter code I'm calling it41:45b.p and I'm going to release it later41:48now running this41:50script gives us output in the terminal41:52and it looks something like this it41:54basically as I ran this code uh it was41:57giving me the train loss and Val loss41:59and we see that we convert to somewhere42:01around42:012.5 with the pyr model and then here's42:04the sample that we produced at the42:07end and so we have everything packaged42:09up in the script and we're in a good42:11position now to iterate on this okay so42:13we are almost ready to start writing our42:15very first self attention block for42:18processing these uh tokens now before we42:22actually get there I want to get you42:24used to a mathematical trick that is42:26used in the self attention inside a42:28Transformer and is really just like at42:30the heart of an an efficient42:32implementation of self attention and so42:34I want to work with this toy example to42:36just get you used to this operation and42:38then it's going to make it much more42:39clear once we actually get to um to it42:43uh in the script42:44again so let's create a b BYT by C where42:47BT and C are just 48 and two in the toy42:50example and these are basically channels42:53and we have uh batches and we have the42:55time component and we have information42:58at each point in the sequence so43:01see now what we would like to do is we43:03would like these um tokens so we have up43:06to eight tokens here in a batch and43:08these eight tokens are currently not43:10talking to each other and we would like43:11them to talk to each other we'd like to43:13couple them and in particular we don't43:17we we want to couple them in a very43:18specific way so the token for example at43:21the fifth location it should not43:23communicate with tokens in the sixth43:25seventh and eighth location43:27because uh those are future tokens in43:29the sequence the token on the fifth43:31location should only talk to the one in43:33the fourth third second and first so43:36it's only so information only flows from43:38previous context to the current time43:40step and we cannot get any information43:42from the future because we are about to43:44try to predict the43:45future so what is the easiest way for43:49tokens to communicate okay the easiest43:52way I would say is okay if we're up to43:54if we're a fifth token and I'd like to43:56communicate with my past the simplest43:58way we can do that is to just do a44:00weight is to just do an average of all44:03the um of all the preceding elements so44:06for example if I'm the fif token I would44:08like to take the channels uh that make44:10up that are information at my step but44:13then also the channels from the fourth44:15step third step second step and the44:17first step I'd like to average those up44:19and then that would become sort of like44:21a feature Vector that summarizes me in44:23the context of my history now of course44:26just doing a sum or like an average is44:28an extremely weak form of interaction44:30like this communication is uh extremely44:32lossy we've lost a ton of information44:34about the spatial Arrangements of all44:35those tokens uh but that's okay for now44:38we'll see how we can bring that44:39information back later for now what we44:41would like to do is for every single44:43batch element independently for every44:46teeth token in that sequence we'd like44:49to now calculate the average of all the44:53vectors in all the previous tokens and44:55also at this token so let's write that44:58out um I have a small snippet here and45:01instead of just fumbling around let me45:03just copy paste it and talk to45:05it so in other words we're going to45:08create X and B is short for bag of words45:12because bag of words is um is kind of45:15like um a term that people use when you45:17are just averaging up things so this is45:19just a bag of words basically there's a45:21word stored on every one of these eight45:23locations and we're doing a bag of words45:25we're just averaging45:27so in the beginning we're going to say45:28that it's just initialized at Zero and45:30then I'm doing a for Loop here so we're45:32not being efficient yet that's coming45:34but for now we're just iterating over45:36all the batch Dimensions independently45:38iterating over time and then the45:40previous uh tokens are at this uh batch45:45Dimension and then everything up to and45:47including the teeth token okay so when45:51we slice out X in this way X prev45:54Becomes of shape um how many T elements45:58there were in the past and then of46:00course C so all the two-dimensional46:02information from these little tokens so46:05that's the previous uh sort of chunk of46:08um tokens from my current sequence and46:12then I'm just doing the average or the46:13mean over the zero Dimension so I'm46:15averaging out the time here and I'm just46:19going to get a little c one dimensional46:21Vector which I'm going to store in X bag46:23of words so I can run this and and uh46:27this is not going to be very informative46:30because let's see so this is X of Zer so46:32this is the zeroth batch element and46:35then expo at zero now you see how the at46:40the first location here you see that the46:42two are equal and that's because it's46:45we're just doing an average of this one46:46token but here this one is now an46:49average of these two and now this one is46:53an average of these46:54three and so on46:57so uh and this last one is the average47:01of all of these elements so vertical47:03average just averaging up all the tokens47:05now gives this outcome47:07here so this is all well and good uh but47:10this is very inefficient now the trick47:12is that we can be very very efficient47:14about doing this using matrix47:16multiplication so that's the47:18mathematical trick and let me show you47:19what I mean let's work with the toy47:21example here let me run it and I'll47:24explain I have a simple Matrix here that47:27is a 3X3 of all ones a matrix B of just47:31random numbers and it's a 3x2 and a47:33matrix C which will be 3x3 multip 3x247:36which will give out a 3x2 so here we're47:39just using um matrix multiplication so a47:43multiply B gives us47:46C okay so how are these numbers in C um47:51achieved right so this number in the top47:54left is the first row of a dot product47:57with the First Column of B and since all48:00the the row of a right now is all just48:02ones then the do product here with with48:05this column of B is just going to do a48:07sum of these of this column so 2 + 6 + 648:11is48:1214 the element here in the output of C48:15is also the first column here the first48:17row of a multiplied now with the second48:20column of B so 7 + 4 + 5 is 16 now you48:25see that there's repeating elements here48:26so this 14 again is because this row is48:28again all ones and it's multiplying the48:30First Column of B so we get 14 and this48:33one is and so on so this last number48:35here is the last row do product last48:39column now the trick here is uh the48:42following this is just a boring number48:44of um it's just a boring array of all48:48ones but torch has this function called48:50Trail which is short for a48:54triangular uh something like that and48:56you can wrap it in torch up once and it48:58will just return the lower triangular49:00portion of this49:03okay so now it will basically zero out49:06uh these guys here so we just get the49:08lower triangular part well what happens49:10if we do49:14that so now we'll have a like this and B49:17like this and now what are we getting49:18here in C well what is this number well49:22this is the first row times the First49:24Column and because this is zeros49:28uh these elements here are now ignored49:30so we just get a two and then this49:32number here is the first row times the49:35second column and because these are49:37zeros they get ignored and it's just49:39seven this seven multiplies this one but49:42look what happened here because this is49:43one and then zeros we what ended up49:46happening is we're just plucking out the49:48row of this row of B and that's what we49:51got now here we have one 1 Z so here 11049:57do product with these two columns will49:59now give us 2 + 6 which is 8 and 7 + 450:02which is 11 and because this is 111 we50:05ended up with the addition of all of50:07them and so basically depending on how50:10many ones and zeros we have here we are50:12basically doing a sum currently of a50:16variable number of these rows and that50:18gets deposited into50:20C So currently we're doing sums because50:23these are ones but we can also do50:25average right and you can start to see50:27how we could do average uh of the rows50:29of B uh sort of in an incremental50:32fashion because we don't have to we can50:35basically normalize these rows so that50:37they sum to one and then we're going to50:39get an average so if we took a and then50:41we did aals50:43aide torch. sum in the um of a in the um50:51oneth Dimension and then let's keep them50:55as true so so therefore the broadcasting50:57will work out so if I rerun this you see51:00now that these rows now sum to one so51:04this row is one this row is 0. 5.5 Z and51:07here we get 1/3 and now when we do a51:09multiply B what are we getting here we51:12are just getting the first row first row51:15here now we are getting the average of51:18the first two51:20rows okay so 2 and six average is four51:23and four and seven average is51:255.5 and on the bottom here we are now51:27getting the average of these three rows51:31so the average of all of elements of B51:33are now deposited here and so you can51:36see that by manipulating these uh51:40elements of this multiplying Matrix and51:42then multiplying it with any given51:44Matrix we can do these averages in this51:47incremental fashion because we just get51:50um and we can manipulate that based on51:53the elements of a okay so that's very51:55convenient so let's let's swing back up51:57here and see how we can vectorize this51:59and make it much more efficient using52:00what we've learned so in52:03particular we are going to produce an52:05array a but here I'm going to call it we52:08short for weights but this is our52:11a and this is how much of every row we52:14want to average up and it's going to be52:17an average because you can see that52:18these rows sum to52:20one so this is our a and then our B in52:23this example of course is X52:27so what's going to happen here now is52:29that we are going to have an expo52:312 and this Expo 2 is going to be way52:36multiplying52:38RX so let's think this true way is T BYT52:42and this is Matrix multiplying in52:44pytorch a b by T by52:47C and it's giving us uh different what52:50shape so pytorch will come here and it52:52will see that these shapes are not the52:54same so it will create a batch Dimension52:57here and this is a batched matrix53:00multiply and so it will apply this53:02matrix multiplication in all the batch53:04elements um in parallel and individually53:08and then for each batch element there53:09will be a t BYT multiplying T by C53:12exactly as we had53:15below so this will now create B by T by53:20C and Expo 2 will now become identical53:24to Expo53:28so we can see that torch. all close of53:32xbo and xbo 2 should be true53:36now so this kind of like convinces us53:38that uh these are in fact um the same so53:43xbo and xbo 2 if I just print53:47them uh okay we're not going to be able53:49to okay we're not going to be able to53:51just stare it down but53:54um well let me try Expo basically just53:56at the zeroth element and Expo two at53:58the zeroth element so just the first53:59batch and we should see that this and54:02that should be identical which they54:04are right so what happened here the54:07trick is we were able to use batched54:09Matrix multiply to do this uh54:12aggregation really and it's a weighted54:15aggregation and the weights are54:17specified in this um T BYT array and54:21we're basically doing weighted sums and54:24uh these weighted sums are are U54:26according to uh the weights inside here54:28they take on sort of this triangular54:31form and so that means that a token at54:33the teth dimension will only get uh sort54:36of um information from the um tokens54:39perceiving it so that's exactly what we54:41want and finally I would like to rewrite54:43it in one more way and we're going to54:46see why that's useful so this is the54:48third version and it's also identical to54:50the first and second but let me talk54:53through it it uses54:54softmax so Trill here is this Matrix55:00lower triangular55:01ones way begins as all55:05zero okay so if I just print way in the55:07beginning it's all zero then I55:11used masked fill so what this is doing55:15is we. masked fill it's all zeros and55:18I'm saying for all the elements where55:20Trill is equal equal Z make them be55:23negative Infinity so all the elements55:26where Trill is zero will become negative55:28Infinity now so this is what we get and55:32then the final line here is55:36softmax so if I take a softmax along55:38every single so dim is negative one so55:40along every single row if I do softmax55:44what is that going to55:46do well softmax is um is also like a55:51normalization operation right and so55:54spoiler alert you get the exact same55:58Matrix let me bring back to56:00softmax and recall that in softmax we're56:02going to exponentiate every single one56:04of these and then we're going to divide56:06by the sum and so if we exponentiate56:10every single element here we're going to56:11get a one and here we're going to get uh56:14basically zero 0 z0 Z everywhere else56:17and then when we normalize we just get56:19one here we're going to get one one and56:21then zeros and then softmax will again56:24divide and this will give us 5.5 and so56:27on and so this is also the uh the same56:30way to produce uh this mask now the56:33reason that this is a bit more56:34interesting and the reason we're going56:36to end up using it in self56:37attention is that these weights here56:41begin uh with zero and you can think of56:44this as like an interaction strength or56:46like an affinity so basically it's56:49telling us how much of each uh token56:52from the past do we want to Aggregate56:54and average up56:57and then this line is saying tokens from56:59the past cannot communicate by setting57:02them to negative Infinity we're saying57:04that we will not aggregate anything from57:06those57:07tokens and so basically this then goes57:09through softmax and through the weighted57:11and this is the aggregation through57:12matrix57:14multiplication and so what this is now57:16is you can think of these as um these57:19zeros are currently just set by us to be57:21zero but a quick preview is that these57:25affinities between the tokens are not57:27going to be just constant at zero57:29they're going to be data dependent these57:31tokens are going to start looking at57:32each other and some tokens will find57:34other tokens more or less interesting57:37and depending on what their values are57:39they're going to find each other57:41interesting to different amounts and I'm57:42going to call those affinities I think57:45and then here we are saying the future57:47cannot communicate with the past we're57:49we're going to clamp them and then when57:51we normalize and sum we're going to57:53aggregate uh sort of their values57:56depending on how interesting they find57:57each other and so that's the preview for57:59self attention and basically long story58:03short from this entire section is that58:05you can do weighted aggregations of your58:07past58:08Elements by having by using matrix58:12multiplication of a lower triangular58:14fashion and then the elements here in58:17the lower triangular part are telling58:18you how much of each element uh fuses58:21into this position so we're going to use58:24this trick now to develop the self58:25attention block block so first let's get58:27some quick preliminaries out of the way58:30first the thing I'm kind of bothered by58:31is that you see how we're passing in58:33vocap size into the Constructor there's58:35no need to do that because vocap size is58:36already defined uh up top as a global58:38variable so there's no need to pass this58:40stuff58:41around next what I want to do is I don't58:44want to actually create I want to create58:46like a level of indirection here where58:47we don't directly go to the embedding58:49for the um logits but instead we go58:52through this intermediate phase because58:54we're going to start making that bigger58:57so let me introduce a new variable n58:59embed it shorted for number of embedding59:02Dimensions so59:04nbed here will be say 32 that was a59:09suggestion from GitHub co-pilot by the59:11way um it also suest 32 which is a good59:14number so this is an embedding table and59:16only 32 dimensional59:18embeddings so then here this is not59:21going to give us logits directly instead59:23this is going to give us token59:24embeddings that's I'm going to call it59:27and then to go from the token Tings to59:29the logits we're going to need a linear59:30layer so self. LM head let's call it59:34short for language modeling head is n59:36and linear from n ined up to vocap size59:39and then when we swing over here we're59:41actually going to get the loits by59:43exactly what the co-pilot says now we59:46have to be careful here because this C59:48and this C are not equal um this is nmed59:52C and this is vocap size so let's just59:55say that n ined is equal to59:57C and then this just creates one spous1:00:01layer of interaction through a linear1:00:02layer but uh this should basically1:00:11run so we see that this runs and uh this1:00:15currently looks kind of spous but uh1:00:17we're going to build on top of this now1:00:19next up so far we've taken these indices1:00:22and we've encoded them based on the1:00:23identity of the uh tokens in inside idx1:00:28the next thing that people very often do1:00:30is that we're not just encoding the1:00:31identity of these tokens but also their1:00:33position so we're going to have a second1:00:35position uh embedding table here so1:00:38self. position embedding table is an an1:00:41embedding of block size by an embed and1:00:44so each position from zero to block size1:00:46minus one will also get its own1:00:47embedding vector and then here first let1:00:50me decode B BYT from idx do1:00:54shape and then here we're also going to1:00:56have a pause embedding which is the1:00:58positional embedding and these are this1:01:00is to arrange so this will be basically1:01:03just integers from Z to T minus one and1:01:06all of those integers from 0 to T minus1:01:08one get embedded through the table to1:01:09create a t by1:01:11C and then here this gets renamed to1:01:14just say x and x will be the addition of1:01:18the token embeddings with the positional1:01:20embeddings and here the broadcasting1:01:22note will work out so B by T by C plus T1:01:25by C1:01:26this gets right aligned a new dimension1:01:28of one gets added and it gets1:01:30broadcasted across1:01:31batch so at this point x holds not just1:01:34the token identities but the positions1:01:37at which these tokens occur and this is1:01:39currently not that useful because of1:01:41course we just have a simple byr model1:01:43so it doesn't matter if you're in the1:01:44fifth position the second position or1:01:46wherever it's all translation invariant1:01:48at this stage uh so this information1:01:50currently wouldn't help uh but as we1:01:52work on the self attention block we'll1:01:54see that this starts to matter1:01:59okay so now we get the Crux of self1:02:01attention so this is probably the most1:02:03important part of this video to1:02:05understand we're going to implement a1:02:07small self attention for a single1:02:08individual head as they're called so we1:02:11start off with where we were so all of1:02:13this code is familiar so right now I'm1:02:16working with an example where I Chang1:02:17the number of channels from 2 to 32 so1:02:20we have a 4x8 arrangement of tokens and1:02:24each to and the information each token1:02:26is currently 32 dimensional but we just1:02:28are working with random1:02:30numbers now we saw here that the code as1:02:34we had it before does a uh simple weight1:02:37simple average of all the past tokens1:02:41and the current token so it's just the1:02:43previous information and current1:02:44information is just being mixed together1:02:45in an average and that's what this code1:02:48currently achieves and it Doo by1:02:50creating this lower triangular structure1:02:52which allows us to mask out this uh we1:02:55uh Matrix that we create so we mask it1:02:59out and then we normalize it and1:03:01currently when we initialize the1:03:03affinities between all the different1:03:05sort of tokens or nodes I'm going to use1:03:08those terms1:03:09interchangeably so when we initialize1:03:11the affinities between all the different1:03:13tokens to be zero then we see that way1:03:16gives us this um structure where every1:03:18single row has these um uniform numbers1:03:22and so that's what that's what then uh1:03:25in this Matrix multiply makes it so that1:03:27we're doing a simple1:03:28average now we don't actually want this1:03:32to be all uniform because different uh1:03:36tokens will find different other tokens1:03:38more or less interesting and we want1:03:40that to be data dependent so for example1:03:42if I'm a vowel then maybe I'm looking1:03:44for consonants in my past and maybe I1:03:46want to know what those consonants are1:03:48and I want that information to flow to1:03:50me and so I want to now gather1:03:52information from the past but I want to1:03:54do it in the data dependent way and this1:03:56is the problem that self attention1:03:58solves now the way self attention solves1:04:00this is the following every single node1:04:03or every single token at each position1:04:06will emit two vectors it will emit a1:04:09query and it will emit a1:04:12key now the query Vector roughly1:04:15speaking is what am I looking for and1:04:18the key Vector roughly speaking is what1:04:20do I1:04:21contain and then the way we get1:04:24affinities between these uh tokens now1:04:27in a sequence is we basically just do a1:04:29do product between the keys and the1:04:31queries so my query dot products with1:04:35all the keys of all the other tokens and1:04:37that dot product now becomes1:04:41wayy and so um if the key and the query1:04:45are sort of aligned they will interact1:04:47to a very high amount and then I will1:04:50get to learn more about that specific1:04:52token as opposed to any other token in1:04:55the sequence1:04:56so let's implement this1:05:00now we're going to implement a1:05:03single what's called head of self1:05:07attention so this is just one head1:05:09there's a hyper parameter involved with1:05:10these heads which is the head size and1:05:13then here I'm initializing linear1:05:15modules and I'm using bias equals false1:05:18so these are just going to apply a1:05:19matrix multiply with some fixed1:05:21weights and now let me produce a key and1:05:26q k and Q by forwarding these modules on1:05:29X so the size of this will now1:05:32become B by T by 16 because that is the1:05:36head size and the same here B by T by1:05:4416 so this being the head size so you1:05:47see here that when I forward this linear1:05:49on top of my X all the tokens in all the1:05:52positions in the B BYT Arrangement all1:05:55of them them in parallel and1:05:57independently produce a key and a query1:05:59so no communication has happened1:06:01yet but the communication comes now all1:06:04the queries will do product with all the1:06:07keys so basically what we want is we1:06:09want way now or the affinities between1:06:12these to be query multiplying key but we1:06:16have to be careful with uh we can't1:06:18Matrix multiply this we actually need to1:06:20transpose uh K but we have to be also1:06:23careful because these are when you have1:06:25The Bash Dimension so in particular we1:06:27want to transpose uh the last two1:06:30dimensions dimension1 and dimension -21:06:33so1:06:36-21 and so this Matrix multiply now will1:06:40basically do the following B by T by1:06:4416 Matrix multiplies B by 16 by T to1:06:49give us B by T by1:06:53T right1:06:56so for every row of B we're now going to1:06:58have a t Square Matrix giving us the1:07:01affinities and these are now the way so1:07:04they're not zeros they are now coming1:07:06from this dot product between the keys1:07:08and the queries so this can now run I1:07:11can I can run this and the weighted1:07:13aggregation now is a function in a data1:07:16Bandon manner between the keys and1:07:18queries of these nodes so just1:07:20inspecting what happened1:07:22here the way takes on this form1:07:26and you see that before way was uh just1:07:29a constant so it was applied in the same1:07:31way to all the batch elements but now1:07:33every single batch elements will have1:07:34different sort of we because uh every1:07:37single batch element contains different1:07:39uh tokens at different positions and so1:07:41this is not data dependent so when we1:07:44look at just the zeroth uh Row for1:07:47example in the input these are the1:07:49weights that came out and so you can see1:07:51now that they're not just exactly1:07:53uniform um and in particular as an1:07:55example here for the last row this was1:07:58the eighth token and the eighth token1:08:00knows what content it has and it knows1:08:02at what position it's in and now the E1:08:04token based on that uh creates a query1:08:08hey I'm looking for this kind of stuff1:08:10um I'm a vowel I'm on the E position I'm1:08:12looking for any consonant at positions1:08:14up to four and then all the nodes get to1:08:18emit keys and maybe one of the channels1:08:20could be I am a I am a consonant and I1:08:23am in a position up to four and that1:08:25that key would have a high number in1:08:27that specific Channel and that's how the1:08:29query and the key when they do product1:08:31they can find each other and create a1:08:33high affinity and when they have a high1:08:35Affinity like say uh this token was1:08:38pretty interesting to uh to this eighth1:08:41token when they have a high Affinity1:08:43then through the softmax I will end up1:08:45aggregating a lot of its information1:08:47into my position and so I'll get to1:08:49learn a lot about1:08:51it now just this we're looking at way1:08:55after this has already happened um let1:08:59me erase this operation as well so let1:09:01me erase the masking and the softmax1:09:03just to show you the under the hood1:09:04internals and how that works so without1:09:07the masking in the softmax Whey comes1:09:09out like this right this is the outputs1:09:11of the do products um and these are the1:09:14raw outputs and they take on values from1:09:15negative you know two to positive two1:09:18Etc so that's the raw interactions and1:09:21raw affinities between all the nodes but1:09:24now if I'm going if I'm a fifth node I1:09:26will not want to aggregate anything from1:09:28the sixth node seventh node and the1:09:30eighth node so actually we use the upper1:09:32triangular masking so those are not1:09:35allowed to1:09:37communicate and now we actually want to1:09:40have a nice uh distribution uh so we1:09:42don't want to aggregate negative .11 of1:09:45this node that's crazy so instead we1:09:47exponentiate and normalize and now we1:09:49get a nice distribution that sums to one1:09:51and this is telling us now in the data1:09:52dependent manner how much of information1:09:54to aggregate from any of these tokens in1:09:56the1:09:58past so that's way and it's not zeros1:10:01anymore but but it's calculated in this1:10:04way now there's one more uh part to a1:10:08single self attention head and that is1:10:10that when we do the aggregation we don't1:10:12actually aggregate the tokens exactly we1:10:15aggregate we produce one more value here1:10:17and we call that the1:10:20value so in the same way that we1:10:22produced p and query we're also going to1:10:23create a value1:10:26and1:10:26then here we don't1:10:30aggregate X we calculate a v which is1:10:34just achieved by uh propagating this1:10:37linear on top of X again and then we1:10:40output way multiplied by V so V is the1:10:44elements that we aggregate or the the1:10:46vectors that we aggregate instead of the1:10:47raw1:10:48X and now of course uh this will make it1:10:51so that the output here of this single1:10:53head will be 16 dimensional because that1:10:55is the head1:10:57size so you can think of X as kind of1:10:59like private information to this token1:11:01if you if you think about it that way so1:11:03X is kind of private to this token so1:11:06I'm a fifth token at some and I have1:11:08some identity and uh my information is1:11:11kept in Vector X and now for the1:11:14purposes of the single head here's what1:11:16I'm interested in here's what I have and1:11:20if you find me interesting here's what I1:11:21will communicate to you and that's1:11:23stored in v and so V is the thing that1:11:26gets aggregated for the purposes of this1:11:28single head between the different1:11:30notes and that's uh basically the self1:11:34attention mechanism this is this is what1:11:36it does there are a few notes that I1:11:39would make like to make about attention1:11:41number one attention is a communication1:11:44mechanism you can really think about it1:11:46as a communication mechanism where you1:11:48have a number of nodes in a directed1:11:50graph where basically you have edges1:11:52pointed between noes like1:11:53this and what happens is every node has1:11:56some Vector of information and it gets1:11:58to aggregate information via a weighted1:12:01sum from all of the nodes that point to1:12:03it and this is done in a data dependent1:12:06manner so depending on whatever data is1:12:08actually stored that you should not at1:12:09any point in time now our graph doesn't1:12:13look like this our graph has a different1:12:15structure we have eight nodes because1:12:17the block size is eight and there's1:12:18always eight to1:12:20tokens and uh the first node is only1:12:23pointed to by itself the second node is1:12:25pointed to by the first node and itself1:12:27all the way up to the eighth node which1:12:29is pointed to by all the previous nodes1:12:32and itself and so that's the structure1:12:34that our directed graph has or happens1:12:37happens to have in Auto regressive sort1:12:38of scenario like language modeling but1:12:41in principle attention can be applied to1:12:42any arbitrary directed graph and it's1:12:44just a communication mechanism between1:12:46the nodes the second note is that notice1:12:48that there is no notion of space so1:12:51attention simply acts over like a set of1:12:53vectors in this graph and so by default1:12:56these nodes have no idea where they are1:12:58positioned in the space and that's why1:12:59we need to encode them positionally and1:13:02sort of give them some information that1:13:03is anchored to a specific position so1:13:05that they sort of know where they are1:13:08and this is different than for example1:13:09from convolution because if you're run1:13:11for example a convolution operation over1:13:13some input there's a very specific sort1:13:15of layout of the information in space1:13:18and the convolutional filters sort of1:13:20act in space and so it's it's not like1:13:23an attention in ATT ention is just a set1:13:26of vectors out there in space they1:13:27communicate and if you want them to have1:13:29a notion of space you need to1:13:31specifically add it which is what we've1:13:33done when we calculated the um relative1:13:36the positional encode encodings and1:13:38added that information to the vectors1:13:40the next thing that I hope is very clear1:13:41is that the elements across the batch1:13:43Dimension which are independent examples1:13:45never talk to each other they're always1:13:47processed independently and this is a1:13:49batched matrix multiply that applies1:13:51basically a matrix multiplication uh1:13:53kind of in parallel across the batch1:13:54dimension so maybe it would be more1:13:56accurate to say that in this analogy of1:13:58a directed graph we really have because1:14:00the back size is four we really have1:14:03four separate pools of eight nodes and1:14:05those eight nodes only talk to each1:14:07other but in total there's like 32 nodes1:14:08that are being processed uh but there's1:14:11um sort of four separate pools of eight1:14:13you can look at it that way the next1:14:15note is that here in the case of1:14:18language modeling uh we have this1:14:20specific uh structure of directed graph1:14:22where the future tokens will not1:14:24communicate to the Past tokens but this1:14:27doesn't necessarily have to be the1:14:28constraint in the general case and in1:14:30fact in many cases you may want to have1:14:32all of the uh noes talk to each other uh1:14:35fully so as an example if you're doing1:14:37sentiment analysis or something like1:14:38that with a Transformer you might have a1:14:40number of tokens and you may want to1:14:42have them all talk to each other fully1:14:45because later you are predicting for1:14:46example the sentiment of the sentence1:14:49and so it's okay for these NOS to talk1:14:50to each other and so in those cases you1:14:53will use an encoder block of self1:14:55attention and uh all it means that it's1:14:58an encoder block is that you will delete1:15:00this line of code allowing all the noes1:15:02to completely talk to each other what1:15:04we're implementing here is sometimes1:15:06called a decoder block and it's called a1:15:09decoder because it is sort of like a1:15:12decoding language and it's got this1:15:15autor regressive format where you have1:15:17to mask with the Triangular Matrix so1:15:19that uh nodes from the future never talk1:15:22to the Past because they would give away1:15:24the answer1:15:25and so basically in encoder blocks you1:15:27would delete this allow all the noes to1:15:29talk in decoder blocks this will always1:15:31be present so that you have this1:15:33triangular structure uh but both are1:15:35allowed and attention doesn't care1:15:36attention supports arbitrary1:15:38connectivity between nodes the next1:15:40thing I wanted to comment on is you keep1:15:41me you keep hearing me say attention1:15:43self attention Etc there's actually also1:15:45something called cross attention what is1:15:47the1:15:47difference1:15:49so basically the reason this attention1:15:52is self attention is because because the1:15:55keys queries and the values are all1:15:57coming from the same Source from X so1:16:01the same Source X produces Keys queries1:16:03and values so these nodes are self1:16:05attending but in principle attention is1:16:08much more General than that so for1:16:10example an encoder decoder Transformers1:16:12uh you can have a case where the queries1:16:15are produced from X but the keys and the1:16:17values come from a whole separate1:16:18external source and sometimes from uh1:16:21encoder blocks that encode some context1:16:23that we'd like to condition on1:16:25and so the keys and the values will1:16:26actually come from a whole separate1:16:28Source those are nodes on the side and1:16:31here we're just producing queries and1:16:32we're reading off information from the1:16:34side so cross attention is used when1:16:37there's a separate source of nodes we'd1:16:40like to pull information from into our1:16:42nodes and it's self attention if we just1:16:45have nodes that would like to look at1:16:46each other and talk to each other so1:16:48this attention here happens to be self1:16:51attention but in principle um attention1:16:55is a lot more General okay and the last1:16:57note at this stage is if we come to the1:16:59attention is all need paper here we've1:17:01already implemented attention so given1:17:03query key and value we've U multiplied1:17:06the query and a key we've soft maxed it1:17:09and then we are aggregating the values1:17:11there's one more thing that we're1:17:12missing here which is the dividing by1:17:13one / square root of the head size the1:17:16DK here is the head size why are they1:17:18doing this finds this important so they1:17:21call it the scaled attention and it's1:17:24kind of like an important normalization1:17:25to basically1:17:26have the problem is if you have unit gsh1:17:29and inputs so zero mean unit variance K1:17:32and Q are unit gashin then if you just1:17:34do we naively then you see that your we1:17:37actually will be uh the variance will be1:17:38on the order of head size which in our1:17:40case is 16 but if you multiply by one1:17:43over head size square root so this is1:17:45square root and this is one1:17:47over then the variance of we will be one1:17:50so it will be1:17:52preserved now why is this important1:17:54you'll not notice that way1:17:56here will feed into1:17:58softmax and so it's really important1:18:00especially at initialization that we be1:18:03fairly diffuse so in our case here we1:18:06sort of locked out here and we had a1:18:10fairly diffuse numbers here so um like1:18:13this now the problem is that because of1:18:15softmax if weight takes on very positive1:18:18and very negative numbers inside it1:18:20softmax will actually converge towards1:18:22one hot vectors and so I can illustrate1:18:25that here um say we are applying softmax1:18:29to a tensor of values that are very1:18:31close to zero then we're going to get a1:18:33diffuse thing out of1:18:34softmax but the moment I take the exact1:18:36same thing and I start sharpening it1:18:38making it bigger by multiplying these1:18:40numbers by eight for example you'll see1:18:42that the softmax will start to sharpen1:18:44and in fact it will sharpen towards the1:18:46max so it will sharpen towards whatever1:18:48number here is the highest and so um1:18:51basically we don't want these values to1:18:52be too extreme especially at1:18:53initialization otherwise softmax will be1:18:55way too peaky and um you're basically1:18:58aggregating um information from like a1:19:01single node every node just agregates1:19:03information from a single other node1:19:04that's not what we want especially at1:19:06initialization and so the scaling is1:19:08used just to control the variance at1:19:11initialization okay so having said all1:19:13that let's now take our self attention1:19:15knowledge and let's uh take it for a1:19:17spin so here in the code I created this1:19:19head module and it implements a single1:19:22head of self attention so you give it a1:19:24head size and then here it creates the1:19:26key query and the value linear layers1:19:29typically people don't use biases in1:19:31these uh so those are the linear1:19:33projections that we're going to apply to1:19:34all of our nodes now here I'm creating1:19:37this Trill variable Trill is not a1:19:40parameter of the module so in sort of1:19:41pytorch naming conventions uh this is1:19:43called a buffer it's not a parameter and1:19:46you have to call it you have to assign1:19:47it to the module using a register buffer1:19:49so that creates the trill uh the triang1:19:52lower triangular Matrix and we're given1:19:55the input X this should look very1:19:56familiar now we calculate the keys the1:19:58queries we C calculate the attention1:20:00scores inside way uh we normalize it so1:20:03we're using scaled attention here then1:20:06we make sure that uh future doesn't1:20:08communicate with the past so this makes1:20:10it a decoder block and then softmax and1:20:13then aggregate the value and1:20:15output then here in the language model1:20:17I'm creating a head in the Constructor1:20:20and I'm calling it self attention head1:20:22and the head size I'm going to keep as1:20:24the same and embed just for1:20:27now and then here once we've encoded the1:20:31information with the token embeddings1:20:32and the position embeddings we're simply1:20:34going to feed it into the self attention1:20:36head and then the output of that is1:20:38going to go into uh the decoder language1:20:42modeling head and create the logits so1:20:44this the sort of the simplest way to1:20:46plug in a self attention component uh1:20:49into our Network right now I had to make1:20:51one more change which is that here in1:20:55the generate uh we have to make sure1:20:57that our idx that we feed into the model1:21:01because now we're using positional1:21:02embeddings we can never have more than1:21:04block size coming in because if idx is1:21:07more than block size then our position1:21:09embedding table is going to run out of1:21:11scope because it only has embeddings for1:21:12up to block size and so therefore I1:21:15added some uh code here to crop the1:21:17context that we're going to feed into1:21:20self um so that uh we never pass in more1:21:23than block siiz elements1:21:25so those are the changes and let's Now1:21:27train the network okay so I also came up1:21:29to the script here and I decreased the1:21:30learning rate because uh the self1:21:32attention can't tolerate very very high1:21:34learning rates and then I also increased1:21:36number of iterations because the1:21:37learning rate is lower and then I1:21:39trained it and previously we were only1:21:41able to get to up to 2.5 and now we are1:21:43down to 2.4 so we definitely see a1:21:46little bit of an improvement from 2.5 to1:21:482.4 roughly uh but the text is still not1:21:51amazing so clearly the self attention1:21:53head is doing some useful communication1:21:56but um we still have a long way to go1:21:59okay so now we've implemented the scale.1:22:01product attention now next up and the1:22:02attention is all you need paper there's1:22:05something called multi-head attention1:22:07and what is multi-head attention it's1:22:09just applying multiple attentions in1:22:11parallel and concatenating their results1:22:13so they have a little bit of diagram1:22:15here I don't know if this is super clear1:22:18it's really just multiple attentions in1:22:20parallel so let's Implement that fairly1:22:23straightforward1:22:25if we want a multi-head attention then1:22:27we want multiple heads of self attention1:22:28running in parallel so in pytorch we can1:22:32do this by simply creating multiple1:22:35heads so however heads how however many1:22:38heads you want and then what is the head1:22:39size of each and then we run all of them1:22:43in parallel into a list and simply1:22:46concatenate all of the outputs and we're1:22:48concatenating over the channel1:22:50Dimension so the way this looks now is1:22:53we don't have just a single ATT1:22:56that uh has a hit size of 32 because1:22:59remember n Ed is1:23:0032 instead of having one Communication1:23:03channel we now have four communication1:23:06channels in parallel and each one of1:23:08these communication channels typically1:23:10will be uh smaller uh correspondingly so1:23:14because we have four communication1:23:15channels we want eight dimensional self1:23:18attention and so from each Communication1:23:20channel we're going to together eight1:23:22dimensional vectors and then we have1:23:23four of them and that concatenates to1:23:25give us 32 which is the original and1:23:28embed and so this is kind of similar to1:23:30um if you're familiar with convolutions1:23:32this is kind of like a group convolution1:23:34uh because basically instead of having1:23:36one large convolution we do convolution1:23:38in groups and uh that's multi-headed1:23:40self1:23:41attention and so then here we just use1:23:44essay heads self attention heads instead1:23:47now I actually ran it and uh scrolling1:23:51down I ran the same thing and then we1:23:53now get this down to 2.28 roughly and1:23:57the output is still the generation is1:23:58still not amazing but clearly the1:24:00validation loss is improving because we1:24:02were at 2.4 just now and so it helps to1:24:05have multiple communication channels1:24:07because obviously these tokens have a1:24:09lot to talk about they want to find the1:24:11consonants the vowels they want to find1:24:13the vowels just from certain positions1:24:15uh they want to find any kinds of1:24:17different things and so it helps to1:24:19create multiple independent channels of1:24:20communication gather lots of different1:24:22types of data and then uh decode the1:24:25output now going back to the paper for a1:24:27second of course I didn't explain this1:24:28figure in full detail but we are1:24:30starting to see some components of what1:24:32we've already implemented we have the1:24:33positional encodings the token encodings1:24:35that add we have the masked multi-headed1:24:37attention implemented now here's another1:24:41multi-headed attention which is a cross1:24:42attention to an encoder which we haven't1:24:45we're not going to implement in this1:24:46case I'm going to come back to that1:24:48later but I want you to notice that1:24:50there's a feed forward part here and1:24:52then this is grouped into a block that1:24:53gets repeat it again and again now the1:24:56feedforward part here is just a simple1:24:57uh multi-layer perceptron1:25:00um so the multi-headed so here position1:25:04wise feed forward networks is just a1:25:06simple little MLP so I want to start1:25:08basically in a similar fashion also1:25:10adding computation into the network and1:25:13this computation is on a per node level1:25:16so I've already implemented it and you1:25:18can see the diff highlighted on the left1:25:20here when I've added or changed things1:25:22now before we had the self multi-headed1:25:25self attention that did the1:25:26communication but we went way too fast1:25:28to calculate the logits so the tokens1:25:31looked at each other but didn't really1:25:32have a lot of time to think on what they1:25:35found from the other tokens and so what1:25:38I've implemented here is a little feet1:25:40forward single layer and this little1:25:42layer is just a linear followed by a Rel1:25:45nonlinearity and that's that's it so1:25:48it's just a little layer and then I call1:25:50it feed1:25:52forward um and embed1:25:54and then this feed forward is just1:25:56called sequentially right after the self1:25:58attention so we self attend then we feed1:26:01forward and you'll notice that the feet1:26:02forward here when it's applying linear1:26:04this is on a per token level all the1:26:06tokens do this independently so the self1:26:09attention is the communication and then1:26:11once they've gathered all the data now1:26:13they need to think on that data1:26:15individually and so that's what feed1:26:16forward is doing and that's why I've1:26:18added it here now when I train this the1:26:21validation LW actually continues to go1:26:23down now to 2. 24 which is down from1:26:262.28 uh the output still look kind of1:26:28terrible but at least we've improved the1:26:31situation and so as a preview we're1:26:34going to now start to intersperse the1:26:37communication with the computation and1:26:39that's also what the Transformer does1:26:42when it has blocks that communicate and1:26:44then compute and it groups them and1:26:46replicates them okay so let me show you1:26:49what we'd like to do we'd like to do1:26:51something like this we have a block and1:26:53this block is is basically this part1:26:55here except for the cross1:26:57attention now the block basically1:26:59intersperses communication and then1:27:01computation the computation the1:27:03communication is done using multi-headed1:27:05selfelf attention and then the1:27:07computation is done using a feed forward1:27:08Network on all the tokens1:27:11independently now what I've added here1:27:14also is you'll1:27:16notice this takes the number of1:27:18embeddings in the embedding Dimension1:27:19and number of heads that we would like1:27:21which is kind of like group size in1:27:22group convolution and and I'm saying1:27:24that number of heads we'd like is four1:27:26and so because this is 32 we calculate1:27:29that because this is 32 the number of1:27:31heads should be four um the head size1:27:34should be eight so that everything sort1:27:36of works out Channel wise um so this is1:27:39how the Transformer structures uh sort1:27:41of the uh the sizes typically so the1:27:44head size will become eight and then1:27:45this is how we want to intersperse them1:27:47and then here I'm trying to create1:27:49blocks which is just a sequential1:27:51application of block block block so that1:27:53we're interspersing communication feed1:27:55forward many many times and then finally1:27:57we decode now I actually tried to run1:28:01this and the problem is this doesn't1:28:02actually give a very good uh answer and1:28:05very good result and the reason for that1:28:07is we're start starting to actually get1:28:09like a pretty deep neural net and deep1:28:11neural Nets uh suffer from optimization1:28:13issues and I think that's what we're1:28:14kind of like slightly starting to run1:28:16into so we need one more idea that we1:28:18can borrow from the um Transformer paper1:28:21to resolve those difficulties now there1:28:23are two optimizations that dramatically1:28:25help with the depth of these networks1:28:27and make sure that the networks remain1:28:29optimizable let's talk about the first1:28:31one the first one in this diagram is you1:28:33see this Arrow here and then this arrow1:28:36and this Arrow those are skip1:28:38connections or sometimes called residual1:28:40connections they come from this paper uh1:28:43the presidual learning for image1:28:44recognition from about1:28:462015 uh that introduced the concept now1:28:51these are basically what it means is you1:28:53transform data but then you have a skip1:28:55connection with addition from the1:28:57previous features now the way I like to1:29:00visualize it uh that I prefer is the1:29:03following here the computation happens1:29:05from the top to bottom and basically you1:29:08have this uh residual pathway and you1:29:11are free to Fork off from the residual1:29:13pathway perform some computation and1:29:15then project back to the residual1:29:16pathway via addition and so you go from1:29:19the the uh inputs to the targets only1:29:22via plus and plus plus and the reason1:29:25this is useful is because during back1:29:27propagation remember from our microG1:29:29grad video earlier addition distributes1:29:32gradients equally to both of its1:29:34branches that that fed as the input and1:29:37so the supervision or the gradients from1:29:40the loss basically hop through every1:29:43addition node all the way to the input1:29:46and then also Fork off into the residual1:29:50blocks but basically you have this1:29:52gradient Super Highway that goes1:29:53directly from the supervision all the1:29:55way to the input unimpeded and then1:29:58these viral blocks are usually1:29:59initialized in the beginning so they1:30:01contribute very very little if anything1:30:03to the residual pathway they they are1:30:05initialized that way so in the beginning1:30:07they are sort of almost kind of like not1:30:09there but then during the optimization1:30:11they come online over time and they uh1:30:14start to contribute but at least at the1:30:17initialization you can go from directly1:30:19supervision to the input gradient is1:30:21unimpeded and just flows and then the1:30:23blocks over time1:30:24kick in and so that dramatically helps1:30:27with the optimization so let's implement1:30:29this so coming back to our block here1:30:31basically what we want to do is we want1:30:33to do xal1:30:35X+ self attention and xal X+ self. feed1:30:39forward so this is X and then we Fork1:30:43off and do some communication and come1:30:45back and we Fork off and we do some1:30:46computation and come back so those are1:30:49residual connections and then swinging1:30:51back up here we also have to introd use1:30:54this projection so nn.1:30:57linear and uh this is going to be1:31:00from after we concatenate this this is1:31:03the prze and embed so this is the output1:31:05of the self tension itself but then we1:31:08actually want the uh to apply the1:31:11projection and that's the1:31:13result so the projection is just a1:31:15linear transformation of the outcome of1:31:16this1:31:17layer so that's the projection back into1:31:20the virual pathway and then here in a1:31:22feet forward it's going to be the same1:31:23same thing I could have a a self doot1:31:26projection here as well but let me just1:31:28simplify it and let me uh couple it1:31:32inside the same sequential container and1:31:34so this is the projection layer going1:31:36back into the residual1:31:38pathway and1:31:40so that's uh well that's it so now we1:31:43can train this so I implemented one more1:31:44small change when you look into the1:31:47paper again you see that the1:31:49dimensionality of input and output is1:31:51512 for them and they're saying that the1:31:53inner layer here in the feet forward has1:31:55dimensionality of 248 so there's a1:31:57multiplier of four and so the inner1:32:00layer of the feet forward Network should1:32:02be multiplied by four in terms of1:32:04Channel sizes so I came here and I1:32:06multiplied four times embed here for the1:32:08feed forward and then from four times1:32:10nmed coming back down to nmed when we go1:32:13back to the pro uh to the projection so1:32:15adding a bit of computation here and1:32:17growing that layer that is in the1:32:19residual block on the side of the1:32:21residual1:32:22pathway and then I train this and we1:32:24actually get down all the way to uh 2.081:32:27validation loss and we also see that1:32:29network is starting to get big enough1:32:30that our train loss is getting ahead of1:32:32validation loss so we're starting to see1:32:33like a little bit of1:32:35overfitting and um our our1:32:38um uh Generations here are still not1:32:41amazing but at least you see that we can1:32:42see like is here this now grief syn like1:32:46this starts to almost look like English1:32:48so um yeah we're starting to really get1:32:50there okay and the second Innovation1:32:52that is very helpful for optimizing very1:32:54deep neural networks is right here so we1:32:57have this addition now that's the1:32:58residual part but this Norm is referring1:33:00to something called layer Norm so layer1:33:03Norm is implemented in pytorch it's a1:33:04paper that came out a while back here1:33:09um and layer Norm is very very similar1:33:11to bash Norm so remember back to our1:33:14make more series part three we1:33:16implemented bash1:33:17normalization and uh bash normalization1:33:19basically just made sure that um Across1:33:22The Bash dimension any individual neuron1:33:25had unit uh Gan um distribution so it1:33:30was zero mean and unit standard1:33:32deviation one standard deviation output1:33:35so what I did here is I'm copy pasting1:33:37the bashor 1D that we developed in our1:33:39make more series and see here we can1:33:42initialize for example this module and1:33:44we can have a batch of 32 1001:33:47dimensional vectors feeding through the1:33:48bachor layer so what this does is it1:33:52guarantees that when we look at just the1:33:54zeroth column it's a zero mean one1:33:58standard deviation so it's normalizing1:34:00every single column of this uh input now1:34:04the rows are not uh going to be1:34:06normalized by default because we're just1:34:08normalizing columns so let's now1:34:10Implement layer Norm uh it's very1:34:12complicated look we come here we change1:34:15this from zero to one so we don't1:34:18normalize The Columns we normalize the1:34:20rows and now we've implemented layer1:34:23Norm1:34:25so now the columns are not going to be1:34:28normalized um but the rows are going to1:34:31be normalized for every individual1:34:33example it's 100 dimensional Vector is1:34:35normalized uh in this way and because1:34:38our computation Now does not span across1:34:40examples we can delete all of this1:34:43buffers stuff uh because uh we can1:34:45always apply this operation and don't1:34:48need to maintain any running buffers so1:34:50we don't need the1:34:52buffers uh we1:34:54don't There's no distinction between1:34:56training and test1:34:58time uh and we don't need these running1:35:00buffers we do keep gamma and beta we1:35:03don't need the momentum we don't care if1:35:05it's training or not and this is now a1:35:08layer1:35:09norm and it normalizes the rows instead1:35:12of the columns and this here is1:35:15identical to basically this here so1:35:19let's now Implement layer Norm in our1:35:21Transformer before I incorporate the1:35:23layer Norm I just wanted to note that as1:35:25I said very few details about the1:35:27Transformer have changed in the last 51:35:28years but this is actually something1:35:30that slightly departs from the original1:35:31paper you see that the ADD and Norm is1:35:34applied after the1:35:36transformation but um in now it is a bit1:35:40more uh basically common to apply the1:35:42layer Norm before the transformation so1:35:44there's a reshuffling of the layer Norms1:35:46uh so this is called the prorm1:35:48formulation and that's the one that1:35:49we're going to implement as well so1:35:50select deviation from the original paper1:35:53basically we need two layer Norms layer1:35:55Norm one is uh NN do layer norm and we1:35:59tell it how many um what is the1:36:01embedding Dimension and we need the1:36:03second layer norm and then here the1:36:06layer Norms are applied immediately on X1:36:09so self. layer Norm one applied on X and1:36:13self. layer Norm two applied on X before1:36:15it goes into self attention and feed1:36:18forward and uh the size of the layer1:36:20Norm here is an ed so 32 so when the1:36:23layer Norm is normalizing our features1:36:26it is uh the normalization here uh1:36:30happens the mean and the variance are1:36:32taken over 32 numbers so the batch and1:36:34the time act as batch Dimensions both of1:36:37them so this is kind of like a per token1:36:40um transformation that just normalizes1:36:42the features and makes them a unit mean1:36:46uh unit Gan at1:36:48initialization but of course because1:36:50these layer Norms inside it have these1:36:52gamma and beta training1:36:54parameters uh the layer Norm will U1:36:57eventually create outputs that might not1:36:59be unit gion but the optimization will1:37:01determine that so for now this is the uh1:37:05this is incorporating the layer norms1:37:06and let's train them on okay so I let it1:37:09run and we see that we get down to 2.061:37:12which is better than the previous 2.081:37:14so a slight Improvement by adding the1:37:15layer norms and I'd expect that they1:37:17help uh even more if we had bigger and1:37:19deeper Network one more thing I forgot1:37:21to add is that there should be a layer1:37:23Norm here also typically as at the end1:37:26of the Transformer and right before the1:37:28final uh linear layer that decodes into1:37:31vocabulary so I added that as well so at1:37:35this stage we actually have a pretty1:37:36complete uh Transformer according to the1:37:38original paper and it's a decoder only1:37:40Transformer I'll I'll talk about that in1:37:42a second uh but at this stage uh the1:37:44major pieces are in place so we can try1:37:46to scale this up and see how well we can1:37:47push this number now in order to scale1:37:50out the model I had to perform some1:37:51cosmetic changes here to make it nicer1:37:54so I introduced this variable called n1:37:56layer which just specifies how many1:37:57layers of the blocks we're going to have1:38:01I created a bunch of blocks and we have1:38:02a new variable number of heads as well I1:38:05pulled out the layer Norm here and uh so1:38:07this is identical now one thing that I1:38:10did briefly change is I added a Dropout1:38:13so Dropout is something that you can add1:38:15right before the residual connection1:38:17back right before the connection back1:38:19into the residual pathway so we can drop1:38:22out that as l layer here we can drop out1:38:26uh here at the end of the multi-headed1:38:27exension as well and we can also drop1:38:30out here uh when we calculate the um1:38:34basically affinities and after the1:38:36softmax we can drop out some of those so1:38:38we can randomly prevent some of the1:38:40nodes from1:38:41communicating and so Dropout uh comes1:38:43from this paper from 2014 or so and1:38:49basically it takes your neural1:38:50nut and it randomly every forward1:38:53backward pass shuts off some subset of1:38:56uh neurons so randomly drops them to1:38:59zero and trains without them and what1:39:02this does effectively is because the1:39:04mask of what's being dropped out is1:39:06changed every single forward backward1:39:07pass it ends up kind of uh training an1:39:11ensemble of sub networks and then at1:39:13test time everything is fully enabled1:39:15and kind of all of those sub networks1:39:16are merged into a single Ensemble if you1:39:18can if you want to think about it that1:39:20way so I would read the paper to get the1:39:22full detail for now we're just going to1:39:24stay on the level of this is a1:39:25regularization technique and I added it1:39:28because I'm about to scale up the model1:39:30quite a bit and I was concerned about1:39:32overfitting so now when we scroll up to1:39:34the top uh we'll see that I changed a1:39:36number of hyper parameters here about1:39:38our neural nut so I made the batch size1:39:40be much larger now it's 64 I changed the1:39:43block size to be 256 so previously it1:39:46was just eight eight characters of1:39:47context now it is 256 characters of1:39:50context to predict the 257th1:39:54uh I brought down the learning rate a1:39:55little bit because the neural net is now1:39:57much bigger so I brought down the1:39:58learning rate the embedding Dimension is1:40:01now 384 and there are six heads so 3841:40:05divide 6 means that every head is 641:40:08dimensional as it as a standard and then1:40:11there's going to be six layers of that1:40:13and the Dropout will be at 02 so every1:40:15forward backward pass 20% of all of1:40:18these um intermediate calculations are1:40:21disabled and dropped to zero1:40:24and then I already trained this and I1:40:25ran it so uh drum roll how well does it1:40:28perform so let me just scroll up1:40:31here we get a validation loss of1:40:341.48 which is actually quite a bit of an1:40:37improvement on what we had before which1:40:38I think was 2.07 so it went from 2.071:40:41all the way down to 1.48 just by scaling1:40:43up this neural nut with the code that we1:40:45have and this of course ran for a lot1:40:47longer this maybe trained for I want to1:40:49say about 15 minutes on my a100 GPU so1:40:52that's a pretty a GPU and if you don't1:40:54have a GPU you're not going to be able1:40:56to reproduce this uh on a CPU this would1:40:59be um I would not run this on a CPU or1:41:01MacBook or something like that you'll1:41:03have to Brak down the number of uh1:41:04layers and the embedding Dimension and1:41:06so on uh but in about 15 minutes we can1:41:09get this kind of a result and um I'm1:41:12printing some of the Shakespeare here1:41:15but what I did also is I printed 10,0001:41:17characters so a lot more and I wrote1:41:18them to a file and so here we see some1:41:21of the outputs1:41:24so it's a lot more recognizable as the1:41:26input text file so the input text file1:41:29just for reference looked like this so1:41:31there's always like someone speaking in1:41:33this manner and uh our predictions now1:41:37take on that form except of course1:41:40they're they're nonsensical when you1:41:41actually read them1:41:43so it is every crimp tap be a house oh1:41:47those1:41:48prepation we give1:41:51heed um you know1:41:56Oho sent me you mighty1:41:59Lord anyway so you can read through this1:42:02um it's nonsensical of course but this1:42:04is just a Transformer trained on a1:42:06character level for 1 million characters1:42:09that come from Shakespeare so there's1:42:10sort of like blabbers on in Shakespeare1:42:12like manner but it doesn't of course1:42:14make sense at this scale uh but I think1:42:18I think still a pretty good1:42:19demonstration of what's1:42:20possible so now1:42:24I think uh that kind of like concludes1:42:26the programming section of this video we1:42:28basically kind of uh did a pretty good1:42:30job and um of implementing this1:42:32Transformer uh but the picture doesn't1:42:35exactly match up to what we've done so1:42:37what's going on with all these digital1:42:38Parts here so let me finish explaining1:42:41this architecture and why it looks so1:42:43funky basically what's happening here is1:42:45what we implemented here is a decoder1:42:47only Transformer so there's no component1:42:50here this part is called the encoder and1:42:52there's no cross attention block here1:42:55our block only has a self attention and1:42:58the feet forward so it is missing this1:43:00third in between piece here this piece1:43:03does cross attention so we don't have it1:43:05and we don't have the encoder we just1:43:07have the decoder and the reason we have1:43:08a decoder only uh is because we are just1:43:12uh generating text and it's1:43:13unconditioned on anything we're just1:43:15we're just blabbering on according to a1:43:16given data set what makes it a decoder1:43:19is that we are using the Triangular mask1:43:21in our uh trans former so it has this1:43:24Auto regressive property where we can1:43:26just uh go and sample from it so the1:43:28fact that it's using the Triangular1:43:30triangular mask to mask out the1:43:32attention makes it a decoder and it can1:43:34be used for language modeling now the1:43:37reason that the original paper had an1:43:39incoder decoder architecture is because1:43:41it is a machine translation paper so it1:43:43is concerned with a different setting in1:43:45particular it expects some uh tokens1:43:49that encode say for example French and1:43:52then it is expecting to decode the1:43:54translation in English so so you1:43:56typically these here are special tokens1:43:59so you are expected to read in this and1:44:02condition on it and then you start off1:44:04the generation with a special token1:44:05called start so this is a special new1:44:08token um that you introduce and always1:44:10place in the beginning and then the1:44:12network is expected to Output neural1:44:15networks are awesome and then a special1:44:17end token to finish the1:44:20generation so this part here will be1:44:23decoded exactly as we we've done it1:44:25neural networks are awesome will be1:44:27identical to what we did but unlike what1:44:29we did they wanton to condition the1:44:32generation on some additional1:44:34information and in that case this1:44:36additional information is the French1:44:38sentence that they should be1:44:39translating so what they do now is they1:44:42bring in the encoder now the encoder1:44:45reads this part here so we're only going1:44:48to take the part of French and we're1:44:50going to uh create tokens from it1:44:52exactly as we've seen in our video and1:44:54we're going to put a Transformer on it1:44:57but there's going to be no triangular1:44:58mask and so all the tokens are allowed1:45:00to talk to each other as much as they1:45:02want and they're just encoding1:45:04whatever's the content of this French uh1:45:07sentence once they've encoded it they1:45:10they basically come out in the top here1:45:13and then what happens here is in our1:45:14decoder which does the uh language1:45:17modeling there's an additional1:45:20connection here to the outputs of the1:45:22encoder1:45:23and that is brought in through a cross1:45:26attention so the queries are still1:45:28generated from X but now the keys and1:45:30the values are coming from the side the1:45:32keys and the values are coming from the1:45:34top generated by the nodes that came1:45:36outside of the de the encoder and those1:45:40tops the keys and the values there the1:45:42top of it feed in on a side into every1:45:45single block of the decoder and so1:45:47that's why there's an additional cross1:45:49attention and really what it's doing is1:45:51it's conditioning the decoding1:45:53not just on the past of this current1:45:55decoding but also on having seen the1:45:59full fully encoded French um prompt sort1:46:04of and so it's an encoder decoder model1:46:06which is why we have those two1:46:07Transformers an additional block and so1:46:09on so we did not do this because we have1:46:12no we have nothing to encode there's no1:46:13conditioning we just have a text file1:46:15and we just want to imitate it and1:46:16that's why we are using a decoder only1:46:19Transformer exactly as done in1:46:21GPT okay okay so now I wanted to do a1:46:24very brief walkthrough of nanog GPT1:46:26which you can find in my GitHub and uh1:46:28nanog GPT is basically two files of1:46:30Interest there's train.py and model.py1:46:33train.py is all the boilerplate code for1:46:35training the network it is basically all1:46:38the stuff that we had here it's the1:46:40training loop it's just that it's a lot1:46:42more complicated because we're saving1:46:44and loading checkpoints and pre-trained1:46:46weights and we are uh decaying the1:46:48learning rate and compiling the model1:46:50and using distributed training across1:46:51multiple nodes or GP use so the training1:46:54Pi gets a little bit more hairy1:46:56complicated uh there's more options Etc1:46:59but the model.py should look very very1:47:01um similar to what we've done here in1:47:04fact the model is is almost identical so1:47:08first here we have the causal self1:47:09attention block and all of this should1:47:11look very very recognizable to you we're1:47:13producing queries Keys values we're1:47:16doing Dot products we're masking1:47:18applying soft Maxs optionally dropping1:47:20out and here we are pulling the wi the1:47:23values what is different here is that in1:47:25our code I have separated out the1:47:30multi-headed detention into just a1:47:31single individual head and then here I1:47:34have multiple heads and I explicitly1:47:36concatenate them whereas here uh all of1:47:39it is implemented in a batched manner1:47:41inside a single causal self attention1:47:43and so we don't just have a b and a T1:47:45and A C Dimension we also end up with a1:47:47fourth dimension which is the heads and1:47:50so it just gets a lot more sort of hairy1:47:52because we have four dimensional array1:47:54um tensors now but it is um equivalent1:47:57mathematically so the exact same thing1:47:59is happening as what we have it's just1:48:01it's a bit more efficient because all1:48:02the heads are now treated as a batch1:48:04Dimension as1:48:05well then we have the multier perceptron1:48:08it's using the Galu nonlinearity which1:48:10is defined here except instead of Ru and1:48:13this is done just because opening I used1:48:14it and I want to be able to load their1:48:17checkpoints uh the blocks of the1:48:19Transformer are identical to communicate1:48:21in the compute phase as we saw and then1:48:23the GPT will be identical we have the1:48:25position encodings token encodings the1:48:27blocks the layer Norm at the end uh the1:48:30final linear layer and this should look1:48:33all very recognizable and there's a bit1:48:35more here because I'm loading1:48:36checkpoints and stuff like that I'm1:48:38separating out the parameters into those1:48:40that should be weight decayed and those1:48:42that1:48:42shouldn't um but the generate function1:48:44should also be very very similar so a1:48:47few details are different but you should1:48:48definitely be able to look at this uh1:48:51file and be able to understand little1:48:52the pieces now so let's now bring things1:48:55back to chat GPT what would it look like1:48:57if we wanted to train chat GPT ourselves1:48:59and how does it relate to what we1:49:00learned today well to train in chat GPT1:49:03there are roughly two stages first is1:49:05the pre-training stage and then the1:49:07fine-tuning stage in the pre-training1:49:09stage uh we are training on a large1:49:12chunk of internet and just trying to get1:49:14a first decoder only Transformer to1:49:17babble text so it's very very similar to1:49:20what we've done ourselves except we've1:49:23done like a tiny little baby1:49:24pre-training step um and so in our case1:49:28uh this is how you print a number of1:49:30parameters I printed it and it's about1:49:3210 million so this Transformer that I1:49:35created here to create little1:49:37Shakespeare um Transformer was about 101:49:40million parameters our data set is1:49:42roughly 1 million uh characters so1:49:45roughly 1 million tokens but you have to1:49:47remember that opening I is different1:49:48vocabulary they're not on the Character1:49:50level they use these um subword chunks1:49:53of words and so they have a vocabulary1:49:55of 50,000 roughly elements and so their1:49:58sequences are a bit more condensed so1:50:01our data set the Shakespeare data set1:50:03would be probably around 300,000 uh1:50:05tokens in the open AI vocabulary roughly1:50:09so we trained about 10 million parameter1:50:11model on roughly 300,000 tokens now when1:50:14you go to the gpt31:50:16paper and you look at the Transformers1:50:20that they trained they trained a number1:50:22of trans Transformers of different sizes1:50:24but the biggest Transformer here has 1751:50:27billion parameters uh so ours is again1:50:2910 million they used this number of1:50:31layers in the Transformer this is the1:50:34nmed this is the number of heads and1:50:36this is the head size and then this is1:50:39the batch size uh so ours was1:50:4365 and the learning rate is similar now1:50:46when they train this Transformer they1:50:47trained on 300 billion tokens so again1:50:51remember ours is about 300,0001:50:53so this is uh about a millionfold1:50:56increase and this number would not be1:50:57even that large by today's standards1:50:59you'd be going up uh 1 trillion and1:51:01above so they are training a1:51:04significantly larger1:51:06model on uh a good chunk of the internet1:51:10and that is the pre-training stage but1:51:12otherwise these hyper parameters should1:51:13be fairly recognizable to you and the1:51:15architecture is actually like nearly1:51:17identical to what we implemented1:51:18ourselves but of course it's a massive1:51:20infrastructure challenge to train this1:51:22you're talking about typically thousands1:51:24of gpus having to you know talk to each1:51:27other to train models of this size so1:51:29that's just a pre-training stage now1:51:32after you complete the pre-training1:51:33stage uh you don't get something that1:51:35responds to your questions with answers1:51:38and is not helpful and Etc you get a1:51:40document1:51:41completer right so it babbles but it1:51:44doesn't Babble Shakespeare it babbles1:51:46internet it will create arbitrary news1:51:48articles and documents and it will try1:51:50to complete documents because that's1:51:51what it's trained for it's trying to1:51:52complete the sequence so when you give1:51:54it a question it would just uh1:51:56potentially just give you more questions1:51:58it would follow with more questions it1:52:00will do whatever it looks like the some1:52:02close document would do in the training1:52:05data on the internet and so who knows1:52:07you're getting kind of like undefined1:52:08Behavior it might basically answer with1:52:11to questions with other questions it1:52:13might ignore your question it might just1:52:15try to complete some news article it's1:52:17totally unineed as we say so the second1:52:20fine-tuning stage is to actually align1:52:22it to be an assistant and uh this is the1:52:25second stage and so this chat GPT block1:52:28post from openi talks a little bit about1:52:30how the stage is achieved we basically1:52:34um there's roughly three steps to to1:52:36this stage uh so what they do here is1:52:39they start to collect training data that1:52:41looks specifically like what an1:52:42assistant would do so these are1:52:44documents that have to format where the1:52:46question is on top and then an answer is1:52:47below and they have a large number of1:52:50these but probably not on the order of1:52:51the internet uh this is probably on the1:52:53of maybe thousands of examples and so1:52:58they they then fine-tune the model to1:53:00basically only focus on documents that1:53:03look like that and so you're starting to1:53:05slowly align it so it's going to expect1:53:07a question at the top and it's going to1:53:08expect to complete the answer and uh1:53:11these very very large models are very1:53:13sample efficient during their1:53:14fine-tuning so this actually somehow1:53:16works but that's just step one that's1:53:19just fine tuning so then they actually1:53:20have more steps where okay the second1:53:23step is you let the model respond and1:53:25then different Raiders look at the1:53:27different responses and rank them for1:53:29their preference as to which one is1:53:30better than the other they use that to1:53:32train a reward model so they can predict1:53:35uh basically using a different network1:53:37how much of any candidate1:53:39response would be desirable and then1:53:43once they have a reward model they run1:53:45po which is a form of polic policy1:53:47gradient um reinforcement learning1:53:49Optimizer to uh fine-tune this sampling1:53:53policy uh so that the answers that the1:53:55GP chat GPT now generates are expected1:53:59to score a high reward according to the1:54:02reward model and so basically there's a1:54:04whole aligning stage here or fine-tuning1:54:07stage it's got multiple steps in between1:54:09there as well and it takes the model1:54:11from being a document completer to a1:54:14question answerer and that's like a1:54:16whole separate stage a lot of this data1:54:19is not available publicly it is internal1:54:21to open AI and uh it's much harder to1:54:24replicate this stage um and so that's1:54:27roughly what would give you a chat GPT1:54:29and nanog GPT focuses on the1:54:31pre-training stage okay and that's1:54:32everything that I wanted to cover today1:54:35so we trained to summarize a decoder1:54:38only Transformer following this famous1:54:41paper attention is all you need from1:54:432017 and so that's basically a GPT we1:54:47trained it on Tiny Shakespeare and got1:54:50sensible results1:54:52all of the training code is1:54:54roughly 200 lines of code I will be1:54:57releasing this um code base so also it1:55:01comes with all the git log commits along1:55:04the way as we built it1:55:05up in addition to this code I'm going to1:55:08release the um notebook of course the1:55:10Google collab and I hope that gave you a1:55:13sense for how you can train um these1:55:16models like say gpt3 that will be um1:55:19architecturally basically identical to1:55:20what we have but they are somewhere1:55:22between 10,000 and 1 million times1:55:24bigger depending on how you count and so1:55:27uh that's all I have for now uh we did1:55:30not talk about any of the fine-tuning1:55:32stages that would typically go on top of1:55:33this so if you're interested in1:55:35something that's not just language1:55:36modeling but you actually want to you1:55:38know say perform tasks um or you want1:55:40them to be aligned in a specific way or1:55:43you want um to detect sentiment or1:55:45anything like that basically anytime you1:55:47don't want something that's just a1:55:48document completer you have to complete1:55:50further stages of fine tuning which did1:55:52not cover uh and that could be simple1:55:55supervised fine tuning or it can be1:55:57something more fancy like we see in chat1:55:58jpt where we actually train a reward1:56:00model and then do rounds of Po to uh1:56:03align it with respect to the reward1:56:04model so there's a lot more that can be1:56:06done on top of it I think for now we're1:56:08starting to get to about two hours Mark1:56:10uh so I'm going to um kind of finish1:56:13here uh I hope you enjoyed the lecture1:56:15uh and uh yeah go forth and transform1:56:18see you later
21,030 words · 2955 lines



![바벨로우의 올바른 운동법 [헬스바이블] Barbell Row Workout](https://i.ytimg.com/vi/IBG8XWAyeGQ/hqdefault.jpg)
![스쿼트의 올바른운동법 1편-로우바스쿼트[헬스바이블]How to Lowbar Squat Workout](https://i.ytimg.com/vi/S-RabrFWCXU/hqdefault.jpg)
![스쿼트의 올바른운동법 2편-하이바스쿼트[헬스바이블]How to High bar Squat Workout](https://i.ytimg.com/vi/MbGk9dzNg2I/hqdefault.jpg)

