Andrej Karpathy is een naam die veel mensen in de AI-wereld zullen herkennen. hij was enige tijd professor aan Stanford, later werd hij hoofd van de AI-afdeling van Tesla, werkte bij OpenAI en, naar mijn mening, produceert hij ook enkele van de beste AI-educatieve video's die vandaag beschikbaar zijn. Zijn nieuwste project, , however, is something I can only describe as a work of art. microGPT microGPT is een complete GPT-implementatie geschreven in En dit is geen slim gecomprimeerde of verduisterde code. Integendeel, de code is schoon, goed gestructureerd en grondig gecommenteerd. Het vermijdt zelfs het gebruik van externe diepleren bibliotheken. Met andere woorden, het bevat niet alleen het neurale netwerk zelf, maar ook het minimale kader dat nodig is om het te trainen en te runnen. only about 200 lines of Python code In feite heeft het hele project niet eens een volledig repository - het wordt eenvoudig gepubliceerd als een . single GitHub Gist https://gist.github.com/karpathy/8627fe009c40f57531cb18360106ce95?embedable=true In dit artikel zal ik proberen uit te leggen hoe dit prachtige stuk code werkt op een manier die . anyone with basic Python knowledge can understand Laten we beginnen met de naam . GPT GPT staat voor . This architecture forms the foundation of most modern large language models. ChatGPT itself contains this abbreviation in its name, and most major alternatives are currently built on the same underlying idea. Generative Pretrained Transformer Een GPT-model voorspelt op basis van de voorgaande woorden in een tekst. the next word (or token) Dit is in wezen wat alle taalmodellen doen. ze genereren antwoorden door één woord per keer te voorspellen. eerst voorspellen ze het volgende woord, dan voegen ze dat woord toe aan de tekst en voorspellen ze het volgende weer, enzovoort. At first glance, this may sound simple. But if we think about it more carefully, predicting the next word correctly requires a certain level of . understanding of the text and its meaning In neurale netwerken wordt dit “denken” proces als een . very large mathematical function De invoerwoorden worden omgezet in getallen en gevoed in deze functie, die vervolgens het volgende woord berekent.In principe kan elk regelsysteem wiskundig worden weergegeven met behulp van dergelijke functies. Deze functie is wat wij de . model Het probleem is dat deze functie Moderne taalmodellen bevatten miljarden parameters, wat betekent dat de wiskundige formule die ze beschrijft miljarden componenten kan hebben. extremely complex Gelukkig is er een slimme workaround. Instead of writing the exact formula ourselves, we define a voor de formule, een structuur met veel aanpasbare parameters. Deze parameters kunnen dan automatisch worden afgestemd totdat het model goed werkt. “template” We hebben verschillende dergelijke sjablonen, afhankelijk van het type probleem dat we willen oplossen: Convolutionele netwerken worden meestal gebruikt voor beeldverwerking MLPs (multi-layer perceptrons) worden gebruikt voor algemene functionele benadering Transformers worden gebruikt voor taalmodellen zoals ChatGPT enzovoort Deze sjablonen vertegenwoordigen enorme wiskundige structuren die complexe regels kunnen benaderen zodra hun parameters goed zijn aangepast. De resterende vraag is: Of, met andere woorden: How do we adjust these parameters? How do we “program” a neural network? Het handmatig aanpassen van de parameters van een neurale netwerk zou duidelijk onmogelijk zijn, vooral als we te maken hebben met modellen die miljoenen of zelfs miljarden parameters bevatten. Gelukkig is er een manier om dit automatisch te doen, met behulp van gegevens. , en de methode die het mogelijk maakt wordt genoemd . training gradient descent Als we een grote dataset en een grote wiskundige formule (onze model) hebben, kunnen we de fout van het model voor elk voorbeeld in de dataset berekenen. In het geval van transformatoren werkt het proces ongeveer zo. Woorden worden weergegeven als punten in een hogedimensionale vectorruimte, waar woorden met vergelijkbare betekenissen dichter bij elkaar verschijnen. Het model ontvangt een volgorde van woorden als input en probeert het volgende woord te voorspellen.Aangezien woorden als vectoren worden weergegeven, kunnen we berekenen hoe ver het voorspelde woord is van het juiste. En nu komt de magie. Met behulp van gradient afdaling, kunnen we berekenen hoe de parameters van de formule moeten veranderen om deze fout te verminderen. Als we voldoende gegevens hebben, een voldoende groot netwerk, en we trainen het lang genoeg, past de formule geleidelijk aan aan de patronen in de dataset en produceert steeds nauwkeuriger voorspellingen. Maar hoe werkt deze “magie” precies?Hoe vindt gradiëntdaling eigenlijk betere parameters? We kunnen de fout visualiseren als een functie in een hoogdimensionale ruimte, waar elke dimensie overeenkomt met één parameter van het model. Denken in vele dimensies is voor de mens praktisch onmogelijk, dus in plaats daarvan kunnen we ons een eenvoudiger analogie voorstellen: een landschap van heuvels en valleien. In deze analogie: Elk punt op het landschap vertegenwoordigt een specifieke combinatie van modelparameters. De hoogte van het landschap op dat punt vertegenwoordigt de fout van het model. Aan het begin van de training worden de parameters willekeurig geïnitieerd.Dit is alsof je ergens willekeurig op de heuvel wordt geplaatst. Ons doel is om de fout te minimaliseren, wat betekent het vinden van het laagste punt in het landschap. The difficulty is that we do not know what the landscape looks like. It’s as if we are trying to walk down a mountain blindfolded or in thick fog. So what can we do? This is where gradient descent comes in. In de wiskunde is er een concept dat de , die de helling van een functie op een bepaald punt beschrijft. derivative This is incredibly useful here. The derivative tells us . which direction the landscape slopes downward Dus het algoritme doet gewoon het volgende: Measure the slope of the landscape. Maak een kleine stap in de richting waar de fout afneemt. Herhaal het Stap voor stap gaat het model geleidelijk naar beneden totdat het een laag punt bereikt in het foutlandschap. Dit is in wezen wat de gradiëntdaling doet. De resterende vraag is: hoe berekenen we de helling van zo'n complexe functie? Ik ga hier niet in de volledige wiskundige details gaan, omdat Karpathy al een uit te leggen. Uitstekende video Voor onze doeleinden is het voldoende om het volgende te weten. Elke wiskundige operatie heeft een overeenkomstige regel die ons in staat stelt om de lokale gradiënt te berekenen.Bovendien is er een regel genaamd de kettingregel, die ons in staat stelt om deze lokale gradiënten te combineren om de gradiënt van een hele samengestelde functie te berekenen. Het belangrijkste idee is dat we achteruit bewegen door de keten van operaties, het verzamelen van gradiënten langs de weg. Alle grote deep learning frameworks implementeren dit mechanisme. Bijvoorbeeld : TensorFlow maakt gebruik van een systeem genaamd GradientTape, dat operaties registreert zoals een tape-recorder, zodat gradiënten later kunnen worden berekend. PyTorch hecht gradiënt informatie rechtstreeks aan tensors. Elke tensor herinnert zich hoe het werd gemaakt, waardoor gradiënten automatisch kunnen worden berekend. De implementatie van Karpathy volgt hetzelfde basisidee. # Let there be Autograd to recursively apply the chain rule through a computation graph class Value: __slots__ = ('data', 'grad', '_children', '_local_grads') # Python optimization for memory usage def __init__(self, data, children=(), local_grads=()): self.data = data # scalar value of this node calculated during forward pass self.grad = 0 # derivative of the loss w.r.t. this node, calculated in backward pass self._children = children # children of this node in the computation graph self._local_grads = local_grads # local derivative of this node w.r.t. its children def __add__(self, other): other = other if isinstance(other, Value) else Value(other) return Value(self.data + other.data, (self, other), (1, 1)) def __mul__(self, other): other = other if isinstance(other, Value) else Value(other) return Value(self.data * other.data, (self, other), (other.data, self.data)) def __pow__(self, other): return Value(self.data**other, (self,), (other * self.data**(other-1),)) def log(self): return Value(math.log(self.data), (self,), (1/self.data,)) def exp(self): return Value(math.exp(self.data), (self,), (math.exp(self.data),)) def relu(self): return Value(max(0, self.data), (self,), (float(self.data > 0),)) def __neg__(self): return self * -1 def __radd__(self, other): return self + other def __sub__(self, other): return self + (-other) def __rsub__(self, other): return other + (-self) def __rmul__(self, other): return self * other def __truediv__(self, other): return self * other**-1 def __rtruediv__(self, other): return other * self**-1 def backward(self): topo = [] visited = set() def build_topo(v): if v not in visited: visited.add(v) for child in v._children: build_topo(child) topo.append(v) build_topo(self) self.grad = 1 for v in reversed(topo): for child, local_grad in zip(v._children, v._local_grads): child.grad += local_grad * v.grad In de code van Karpathy wordt de gehele gradiëntcomputinglogica geïmplementeerd in de De klas, die alleen maar . Value 40 lines long Deze klasse is in wezen een wrapper rond numerieke waarden. Naast het opslaan van de gegevens zelf, slaat het ook op: Welke waarden zijn er van berekend (zijn kinderen), en de lokale gradiënten die nodig zijn voor backpropagatie. Als we naar de code kijken, kunnen we zien dat de standaardoperatoren opnieuw zijn gedefinieerd: - toevoegen De muur en anderen. Dit betekent dat wanneer we een wiskundige operatie uitvoeren op Het programma berekent niet alleen het resultaat, maar registreert ook welke waarden het hebben geproduceerd en hoe de gradiënt moet worden verspreid. Value Ten slotte, de De methode voert het backpropagatieproces uit.Het gaat terug door de keten van operaties en berekent de totale gradiënt met betrekking tot de fout. backward() En dat is in wezen het hele idee. Het andere belangrijke onderdeel van de training is de gradiëntdaling zelf, die de berekende gradiënten gebruikt om de parameters van het model bij te werken. Met andere woorden, dit is het deel van de code dat daadwerkelijk de heuvel afloopt met behulp van de hellingsinformatie. # Adam optimizer update: update the model parameters based on the corresponding gradients lr_t = learning_rate * (1 - step / num_steps) # linear learning rate decay for i, p in enumerate(params): m[i] = beta1 * m[i] + (1 - beta1) * p.grad v[i] = beta2 * v[i] + (1 - beta2) * p.grad ** 2 m_hat = m[i] / (1 - beta1 ** (step + 1)) v_hat = v[i] / (1 - beta2 ** (step + 1)) p.data -= lr_t * m_hat / (v_hat ** 0.5 + eps_adam) p.grad = 0 In de implementatie van Karpathy wordt dit gedaan met de , dat is een van de meest gebruikte optimalisatie algoritmen in diep leren. Adam optimizer Adam is iets geavanceerder dan de basisgradiëntdaling. In plaats van vaste stappen te nemen, past hij de stapgrootte dynamisch aan op basis van de geschiedenis van eerdere gradiënten. . faster and more stable The gradient computation described earlier and the optimization step together form what we could call the deep learning framework part of the code. Elk neurale netwerk - of het nu een taalmodel, een beeldgenerator, een robotcontroller of een zelfrijdende auto aandrijft - wordt getraind met in wezen hetzelfde principe. Deze paar regels van code vangen het kernidee achter moderne AI vast. Large frameworks like: De TensorFlow Pythagoras Jax provide highly optimized implementations that can run on GPUs, TPUs, and distributed clusters, and include many additional tricks and optimizations. Maar als we alles tot het essentiële snijden, is het onderliggende principe precies hetzelfde als wat we zien in deze kleine Python-implementatie. Now that we have seen the deep learning framework part of the code, we can move on to the actual neural network, in other words, the GPT model itself. Zoals eerder vermeld, is het doel van GPT om de volgende token te voorspellen op basis van de tokens die daarvoor kwamen. Deze definitie is enigszins vereenvoudigd, omdat de input eigenlijk niet bestaat uit woorden, maar van tokens. Tokens zijn zeer vergelijkbaar met woorden, maar ze zijn niet hetzelfde.In plaats van te vertrouwen op een vooraf gedefinieerd woordenboek, leert het systeem een woordenschat statistisch van de trainingsgegevens. So training does not begin with a fixed list of words where each word already has a number assigned to it. Instead, this “dictionary” emerges from the data itself during preprocessing. Deze benadering is vooral nuttig voor agglutinatieve talen, zoals Hongaars, waar een enkel woord vele verschillende vormen kan hebben vanwege volgen en grammaticale uiteinden. With enough training data, a language model can learn any language, whether natural or artificial. In feite hoeven tokens zelfs geen tekst te vertegenwoordigen. delen van beelden Fragmenten van audio Sensoren lezen Bijna elk type gegevens Om deze reden zijn transformatormodellen niet beperkt tot taalverwerking. ze kunnen ook worden gebruikt voor beeldgeneratie, spraakverwerking, robotica en vele andere taken. Karpathy’s model is opzettelijk erg klein, dus in dit geval zijn de tokens geen woorden, maar tekens. Het doel van het model is dus niet om volledige zinnen of antwoorden te genereren, maar gewoon om realistische namen te produceren. De trainingsdataset bestaat uit een grote lijst met namen, en na de training verwachten we dat het model nieuwe namen genereert die statistisch op de voorbeelden lijken. Dit is duidelijk verre van een full-scale taalmodel zoals ChatGPT, maar in werkelijkheid is het verschil meestal een schaal. Als we dit model miljoenen keren zouden vergroten, tokens zouden gebruiken in plaats van tekens, en het zouden trainen op enorme datasets die zijn verzameld van het internet, zouden we uiteindelijk iets hebben dat erg lijkt op een modern groot taalmodel. Deze grote modellen worden meestal in twee fasen getraind: Pre-training – training op enorme internetdatasets om algemene taalpatronen te leren. Fine-tuning – verdere training met behulp van gecurateerde door de mens gegenereerde gesprekken om reacties te verbeteren. Het proces vereist enorme computationele middelen en enorme hoeveelheden gegevens van hoge kwaliteit, vaak kost miljoenen dollars in computing. Aangezien de meesten van ons geen toegang hebben tot dergelijke middelen, zullen we ons moeten regelen voor het genereren van namen. # Let there be a Dataset `docs`: list[str] of documents (e.g. a list of names) if not os.path.exists('input.txt'): import urllib.request names_url = 'https://raw.githubusercontent.com/karpathy/makemore/988aa59/names.txt' urllib.request.urlretrieve(names_url, 'input.txt') docs = [line.strip() for line in open('input.txt') if line.strip()] random.shuffle(docs) print(f"num docs: {len(docs)}") # Let there be a Tokenizer to translate strings to sequences of integers ("tokens") and back uchars = sorted(set(''.join(docs))) # unique characters in the dataset become token ids 0..n-1 BOS = len(uchars) # token id for a special Beginning of Sequence (BOS) token vocab_size = len(uchars) + 1 # total number of unique tokens, +1 is for BOS print(f"vocab size: {vocab_size}") Aan het begin van de code vinden we de sectie die verantwoordelijk is voor het laden van de dataset van namen en het opbouwen van het woordenschat. In dit geval bestaat het woordenschat eenvoudigweg uit de lijst met tekens die in de dataset verschijnen. Elk personage krijgt een numerieke identificator toegewezen, waardoor de tekst kan worden omgezet in getallen die het neurale netwerk kan verwerken. Hieronder volgt een van de belangrijkste concepten in diepgaand leren: . embeddings Het idee is eenvoudig maar krachtig. In plaats van met raw token-ID's te werken, mappen we elke token in een Deze vectoren zijn wat het neurale netwerk eigenlijk verwerkt. point in a high-dimensional vector space In feite kan elk neurale netwerk worden beschouwd als een functie die . maps vectors from one high-dimensional space into another Bijvoorbeeld : Als we een neurale netwerk trainen om afbeeldingen te classificeren als honden of katten, mappt het netwerk de afbeeldingsrepresentatie in een tweedimensionale ruimte, waar een dimensie overeenkomt met "dogness" en de andere met "catness". Als we ons een beeldgenerator voorstellen zoals Midjourney, mapt het willekeurig lawaai in een hoogdimensionale ruimte waar elk punt een beeld vertegenwoordigt dat is geconditioneerd op de prompt. Regardless of the task, the network is always performing a . vector-to-vector transformation using a large mathematical function Hetzelfde geldt voor GPT. De dimensionaliteit van de vectorruimte wordt in de code gedefinieerd door de constante die in deze uitvoering is vastgesteld om . n_embd 16 Dit betekent dat elke token (in dit geval, elk karakter) wordt weergegeven als een . 16-dimensional vector Wiskundig gezien is deze kaart gewoon een . matrix multiplication In de code wordt de matrix die verantwoordelijk is voor deze transformatie genoemd , die staat voor . wte word/token embedding Weten welke personages in een woord verschijnen, is echter niet genoeg. Ook van belang. position De betekenis van een sequentie verandert bijvoorbeeld als we de tekens opnieuw regelen. Om positionele informatie te integreren, gebruikt het model , geïmplementeerd met een andere matrix genaamd . positional embeddings wpe De code mapt zowel de token als de positie ervan in 16-dimensionale vectoren, en vervolgens gewoon . adds the two vectors together Het resultaat is een enkele vector die beide coderen: the identity of the token its position within the sequence Eerder hebben we vermeld dat deze vectorrepresentaties zinvol moeten zijn, omdat later het model fouten zal berekenen op basis van afstanden tussen vectoren. Ideaal voor: should be close to the correct vector Almost correct predictions should be far away from it Very wrong predictions Dit roept een interessante vraag op: How do we design a good embedding space? The answer is surprisingly simple: We don’t. In plaats daarvan initialiseren we de embedded matrices ( en ) met willekeurige getallen en toestaan gradiënt afdaling om de juiste vertegenwoordiging te leren tijdens de training. wte wpe If we have enough data, the optimization process will gradually adjust the matrices until they represent useful relationships. Dit kan leiden tot verrassend krachtige opkomende eigenschappen. For example, in the famous Vectorarithmetica kan semantische relaties vastleggen.Een klassiek voorbeeld is: word2vec king − man + woman ≈ queen Here we can already see that the embedding space begins to represent a kind of , where relationships between concepts appear as geometric relationships between vectors. simplified model of the world Now that we have seen how vectors are created, we can finally look at the neural network itself, the component that transforms these vectors into new vectors representing the next token. Met andere woorden, het netwerk kaart vectoren van de token die de ruimte terug in dezelfde ruimte, maar verplaatst door een token. Voor elke token, voorspelt het welke token moet volgen volgende. Door herhaaldelijk dit proces toe te passen, kan het model een hele tekstreeks genereren - of in dit geval, een naam. The architecture used for this is called the . Transformer De Transformer werd in 2017 geïntroduceerd door onderzoekers van Google in het beroemde artikel: “Attention Is All You Need.” De oorspronkelijke architectuur is ontworpen voor . It consisted of two main parts: machine translation Een encoder a decoder De encoder verwerkte de invoerwoordwoordwoordwoordwoordwoordwoordwoordwoordwoordwoordwoordwoordwoordwoordwoordwoordwoordwoordwoordwoordwoordwoordwoordwoordwoordwoordwoordwoordwoordwoordwoordwoordwoordwoordwoordwoordwoordwoord For generative models like GPT, however, we only need : de . half of the original architecture decoder stack This is why GPT models are often described as . decoder-only transformers De decoder ontvangt de input tokens en verwerkt ze herhaaldelijk via een stapel identieke lagen. Zelfoplettend Een feed-forward neurale netwerk (MLP) Deze lagen worden vele malen herhaald in grote modellen.In diagrammen zie je dit vaak vertegenwoordigd als Dit betekent dat het blok meerdere keren is gestapeld. ×N One of the key innovations of the Transformer architecture is that it processes the . entire sequence at once Older language models, especially recurrent neural networks (RNNs), processed text one word at a time, sequentially passing information along the sequence. Transformers werken anders. ze kunnen alle tokens tegelijkertijd bekijken, waardoor het model relaties kan leren tussen alle delen van de tekst. This mechanism is called , which is why the original paper was titled . attention Aandacht is alles wat je nodig hebt The attention mechanism calculates how In de sequentie. relevant each token is to every other token Voor elke tokenvector berekent het model een set gewichten waarin wordt beschreven hoeveel aandacht het moet besteden aan de andere tokens. De resulterende vector vertegenwoordigt dus niet alleen het token zelf, maar ook . its meaning in the context of the entire sequence This may sound complicated, but the intuition is straightforward. Suppose we ask a language model: “What is the capital of France?” If we only looked at the word , we could not determine the answer. But attention allows the model to connect the word met . “capital” “capital” “France” De resulterende weergave vangt de betekenis van de zin , making it possible for the model to produce the correct answer: . “capital of France” Paris Een manier om te denken over transformatoren is om ze voor te stellen als een soort van . soft database Instead of storing explicit facts, the model stores knowledge in a vector space representation. Because neural networks approximate functions rather than memorize exact rules, they can often answer questions they have never seen before. Returning to our earlier embedding example: If the training data contains information about kings and women, the model may still be able to answer questions about queens, because the relationships between these concepts are captured in the vector space. If we follow this database analogy, we might say: acts like an , helping the model locate relevant information. Attention index De MLP-lagen bevatten de kennis zelf. Dit mentale model is nuttig voor intuïtie, maar het is niet letterlijk correct. In a real transformer like the one used in ChatGPT, these attention + MLP blocks are repeated many times. Kennis wordt niet opgeslagen op één locatie, maar wordt verspreid over verschillende lagen. Additionally, each layer includes a residual connection, which mixes the original input vectors with the newly computed vectors. This allows information to flow through the network more effectively and stabilizes training. As the vectors pass through the layers, new abstractions and meanings can emerge. By the time the final layer produces its output, the model has combined information from many different levels of representation. The full process is far too complex to follow step by step with human intuition. Yet despite this complexity, the system works remarkably well in practice. Nu we een ruwe intuïtie hebben over de transformatorarchitectuur, laten we een van de belangrijkste componenten in meer detail bekijken: . attention # 1) Multi-head Attention block x_residual = x x = rmsnorm(x) q = linear(x, state_dict[f'layer{li}.attn_wq']) k = linear(x, state_dict[f'layer{li}.attn_wk']) v = linear(x, state_dict[f'layer{li}.attn_wv']) keys[li].append(k) values[li].append(v) x_attn = [] for h in range(n_head): hs = h * head_dim q_h = q[hs:hs+head_dim] k_h = [ki[hs:hs+head_dim] for ki in keys[li]] v_h = [vi[hs:hs+head_dim] for vi in values[li]] attn_logits = [sum(q_h[j] * k_h[t][j] for j in range(head_dim)) / head_dim**0.5 for t in range(len(k_h))] attn_weights = softmax(attn_logits) head_out = [sum(attn_weights[t] * v_h[t][j] for t in range(len(v_h))) for j in range(head_dim)] x_attn.extend(head_out) x = linear(x_attn, state_dict[f'layer{li}.attn_wo']) x = [a + b for a, b in zip(x, x_residual)] In de implementatie van Karpathy wordt aandacht berekend met behulp van drie matrices genaamd: Q (Query) K (de sleutel) V (de waarde) Deze matrices voeren vectorprojecties uit, met andere woorden, elke token-vector wordt in drie verschillende vectorruimten gemarkeerd. Voor elk token dat we berekenen: a query vector Een belangrijke vector Een waarde vector Zodra we deze vectoren hebben, vergelijken we de query vector van een token met de sleutel vectoren van alle tokens in de sequentie. Het puntproduct geeft een score die weergeeft hoe sterk twee vectoren gerelateerd zijn. Hierdoor ontstaat een reeks getallen die . how relevant each token is to the current token Deze ruwe scores zijn echter nog geen waarschijnlijkheden. Om ze om te zetten in een waarschijnlijkheidsverdeling, gebruiken we de , which transforms the scores into values between 0 and 1 that sum to 1. softmax function These values represent how much attention each token should receive. Finally, the model combines the value vectors using these attention weights, producing a new vector that contains information gathered from the entire context. De formule voor scaled dot-product attention ziet er als volgt uit: Attention(Q, K, V) = softmax(QKᵀ / √dₖ) V Here: QKT berekent de gelijkenis tussen queries en sleutels is a scaling factor that stabilizes training √dₖ converts the scores into attention probabilities softmax provides the information that is combined according to those probabilities V The result is a new representation for each token that reflects . its meaning in the context of the entire sequence Op dit punt is het de moeite waard om een belangrijk concept te noemen: . context length Zoals we eerder hebben besproken, verwerken transformatoren de hele sequentie tegelijk. . every token with every other token Dat betekent dat de computationele kosten stijgen with the number of tokens. quadratically If we double the context length, the amount of computation increases roughly four times. Dit is een van de belangrijkste beperkingen van transformatormodellen. Unlike some other architectures, transformers do not have a separate memory system. They can only “see” the tokens that fit within their context window. Everything outside that window is effectively invisible to the model. Daarom is contextlengte zo'n belangrijke eigenschap van moderne taalmodellen. In veel moderne AI-systemen wordt deze beperking aangepakt door een extern geheugenmechanisme toe te voegen. A common approach is to use a . vector database In plaats van kennis rechtstreeks in het model op te slaan, kan informatie extern worden opgeslagen als vectorembeddings. Wanneer het model een vraag ontvangt, kan het systeem: Convert the question into a vector. Zoek de vectordatabase voor gerelateerde informatie. Insert the retrieved information into the model’s context. Dit betekent dat het model beide ziet: De vraag and the relevant knowledge retrieved from the database Omdat beide verschijnen in het contextvenster, kan het model een antwoord genereren op basis van die informatie. Deze techniek staat bekend als en wordt op grote schaal gebruikt in moderne AI-systemen en agentframeworks. Retrieval-Augmented Generation (RAG) In this setup, the language model’s main role is not to store knowledge, but to generate coherent answers based on the information available in its context. But as we can see, this requires space in the context window, which is why context length remains so important. Terug naar de implementatie van Karpathy gebruikt het model , wat een verbeterde vorm is van het basismechanisme van de aandacht. multi-head attention Instead of computing attention using a single set of Q, K, and V matrices, the model uses multiple attention heads. In deze uitvoering zijn er vier hoofden. Elk hoofd leert zich te concentreren op verschillende soorten relaties tussen tokens.Bijvoorbeeld, kan een hoofd zich richten op grammaticale relaties, terwijl een ander afhankelijkheden van een langere reikwijdte kan vastleggen. Using multiple heads improves the quality of the representation. To keep the computational cost roughly the same, the dimensionality of each head is reduced. Earlier, we mapped vectors from a . 16-dimensional space to another 16-dimensional space Met vier aandachtspieren werkt elk hoofd in plaats daarvan in een . The results from the heads are then combined back into a single vector. 4-dimensional space Although each head works with lower-dimensional vectors, the combined result is typically more expressive and more accurate than using a single attention head. Nu we het mechanisme van de aandacht hebben behandeld, gaan we over naar de tweede belangrijke component van het transformatorblok: de , of . MLP feed-forward neural network In de code ziet het MLP-blok er zo uit: # 2) MLP block x_residual = x x = rmsnorm(x) x = linear(x, state_dict[f'layer{li}.mlp_fc1']) x = [xi.relu() for xi in x] x = linear(x, state_dict[f'layer{li}.mlp_fc2']) x = [a + b for a, b in zip(x, x_residual)] An MLP is a . If we look at the structure of the weight matrices, we can interpret the rows of the matrix as . classic neural network architecture neurons Een neuron is een eenvoudige computationele eenheid die: vermenigvuldigt elke input met een gewicht, Summeren van de resultaten, Then it applies a nonlinear activation function to produce the output. This model was originally inspired by biological neurons in the human brain. In that sense, neural networks were historically motivated by attempts to mimic how the brain might process information. However, modern AI systems have moved quite far from this original analogy. In the MLP component, we can still loosely recognize something that resembles neurons. But when we look at mechanisms like , it becomes much harder to maintain the brain-inspired interpretation. attention Om deze reden is het vaak beter om moderne AI-systemen simpelweg als , rather than literal models of the brain. trainable mathematical functions Het MLP-blok in de code bestaat uit drie hoofdstappen: een lineaire transformatie (matrix multiplication) Een niet-lineaire activeringsfunctie (ReLU) Een andere lineaire transformatie. This may look simple, but structures like this have an extremely powerful mathematical property. They are known as . Universele Approximatie Universele Approximatie Dit betekent dat onder bepaalde omstandigheden een voldoende grote MLP to an arbitrary degree of accuracy. any mathematical function In principe kan een enkele enorme MLP bijna alles leren. However, that would not be very efficient in practice. That is why transformer architectures combine multiple mechanisms, including attention and stacked layers, to distribute the computation more effectively. The output of the network is not a single token, but a . probability distribution over all possible tokens In other words, for each token in the vocabulary, the model outputs the probability that it should appear next in the sequence. Gedurende de generatie, het algoritme dan steekproeven uit deze waarschijnlijkheid distributie. Dit betekent dat tokens met een hogere waarschijnlijkheid vaker worden gekozen, maar er is nog steeds een element van willekeurigheid. This randomness is controlled by a parameter called . temperature The parameter determines how deterministic or creative the model’s output will be. temperature Lage temperatuur - het model bevoordeelt sterk de meest waarschijnlijke tokens, waardoor meer voorspelbare en nauwkeurige antwoorden. Hoge temperatuur - de waarschijnlijkheidsverdeling wordt platter, waardoor minder waarschijnlijke tokens vaker worden geselecteerd, wat resulteert in meer diverse of creatieve outputs. Bijvoorbeeld : Als we willen dat het model een document analyseert en feitelijke vragen beantwoordt, is een lage temperatuur meestal de voorkeur. Als we willen dat het model creatieve tekst genereert of nieuwe ideeën verkent, kan een hogere temperatuur interessantere resultaten opleveren. This is roughly what I wanted to explain about this beautiful piece of code, and about GPT models in general. Op veel plaatsen bleef de uitleg noodzakelijkerwijs wat oppervlakkig.Mijn doel was om een evenwicht te vinden tussen twee dingen: zoveel mogelijk nuttige inzichten opnemen, terwijl de discussie nog steeds binnen het bereik van een enkel artikel werd gehouden. For readers who found parts of the explanation a bit unclear, or who want to explore the details more deeply, I highly recommend Zijn en Daar vindt u uitstekend materiaal dat alles uitlegt wat nodig is om de hier besproken concepten volledig te begrijpen. Persoonlijke website van Andrej Karpathy YouTube kanaal his blog Ik hoop dat dit artikel nuttig was voor veel lezers.Als niets anders, misschien dient het als een uitnodiging om de fascinerende wereld van AI te verkennen.