Andrej Karpathy yra vardas, kurį pripažins daugelis žmonių AI pasaulyje.Jis kurį laiką buvo Stanfordo profesorius, vėliau tapo "Tesla" AI padalinio vadovu, dirbo "OpenAI" ir, mano nuomone, jis taip pat gamina keletą geriausių šiandien prieinamų AI švietimo vaizdo įrašų. Jūsų naujausias projektas, Tačiau tai yra kažkas, ką aš galiu apibūdinti tik kaip meno kūrinį. microGPT microGPT yra pilnas GPT įgyvendinimas, parašytas Ir tai nėra kažkoks sumaniai suspaustas ar neaiškus kodas. Priešingai, kodas yra švarus, gerai struktūrizuotas ir kruopščiai komentuojamas. Jis netgi vengia naudoti išorines gilių mokymosi bibliotekas. Kitaip tariant, jame yra ne tik pats neuroninis tinklas, bet ir minimali sistema, reikalinga mokymui ir jo veikimui. only about 200 lines of Python code Tiesą sakant, visas projektas net neturi pilno saugyklos – jis paprasčiausiai skelbiamas kaip . single GitHub Gist https://gist.github.com/karpathy/8627fe009c40f57531cb18360106ce95?embedable=true Šiame straipsnyje bandysiu paaiškinti, kaip šis gražus kodo gabalas veikia taip, kad . anyone with basic Python knowledge can understand Pradėkime nuo pavadinimo . GPT VSD stovi už Ši architektūra sudaro pagrindą daugeliui šiuolaikinių didelių kalbų modelių. „ChatGPT“ pats savo pavadinime yra šis santrumpa, o dauguma pagrindinių alternatyvų šiuo metu yra pastatytos ant tos pačios pagrindinės idėjos. Generative Pretrained Transformer GPT modelis prognozuoja Pagal ankstesnius žodžius tekste. the next word (or token) Tai iš esmės yra tai, ką daro visi kalbos modeliai.Jie generuoja atsakymus, prognozuodami vieną žodį vienu metu.Pirmiausia jie prognozuoja kitą žodį, tada jie prideda tą žodį prie teksto ir prognozuoja kitą ir pan. Iš pirmo žvilgsnio tai gali atrodyti paprasta. bet jei mes galvojame apie tai atidžiau, teisingai prognozuoti kitą žodį reikalauja tam tikro lygio . understanding of the text and its meaning neuroniniuose tinkluose šis „mąstymo“ procesas įgyvendinamas kaip . very large mathematical function Įvesties žodžiai konvertuojami į skaičius ir tiekiami į šią funkciją, kuri tada apskaičiuoja kitą žodį. Ši funkcija vadinama . model Problema ta, kad ši funkcija gali būti Šiuolaikiniai kalbos modeliai turi milijardus parametrų, o tai reiškia, kad matematinė formulė, apibūdinanti juos, gali turėti milijardus komponentų. extremely complex Laimei, yra protingas darbas. Vietoj to, kad parašytume tikslią formulę, mes apibrėžiame formule, struktūra su daugybe reguliuojamų parametrų. Šie parametrai gali būti automatiškai reguliuojami, kol modelis gerai veikia. “template” Mes turime keletą tokių šablonų, priklausomai nuo to, kokią problemą norime išspręsti: Konvoluciniai tinklai paprastai naudojami vaizdo apdorojimui MLP (daugiapakopiai perceptronai) naudojami bendrai funkcijai apibūdinti Transformatoriai naudojami kalbų modeliams, pvz., ChatGPT etc. Šie šablonai yra didžiulės matematinės struktūros, kurios gali apibūdinti sudėtingas taisykles, kai jų parametrai yra tinkamai sureguliuoti. Likęs klausimas yra: Arba kitaip tariant: How do we adjust these parameters? How do we “program” a neural network? Akivaizdu, kad būtų neįmanoma rankiniu būdu koreguoti neuroninio tinklo parametrų, ypač kai kalbame apie modelius, kuriuose yra milijonai ar net milijardai parametrų. Laimei, yra būdas tai padaryti automatiškai, naudojant duomenis. , and the method that makes it possible is called . training gradient descent If we have a large dataset and a large mathematical formula (our model), we can compute the error of the model for each example in the dataset. Transformatorių atveju procesas veikia maždaug taip. Žodžiai pateikiami kaip taškai aukštos dimensijos vektorinėje erdvėje, kur žodžiai su panašiomis reikšmėmis pasirodo arčiau vienas kito. Modelis gauna žodžių seką kaip įvestį ir bando nuspėti kitą žodį.Kadangi žodžiai yra atstovaujami kaip vektoriai, galime apskaičiuoti, kaip toli prognozuotas žodis yra nuo teisingo. O dabar ateina magija. Naudojant gradiento nuosmukį, galime apskaičiuoti, kaip turėtų pasikeisti formulės parametrai, kad sumažintume šią klaidą. Jei turime pakankamai duomenų, pakankamai didelį tinklą ir jį mokome pakankamai ilgai, formulė palaipsniui prisitaiko prie duomenų rinkinio modelių ir gamina vis tikslesnes prognozes. Bet kaip tiksliai veikia šis „stebuklas“?Kaip gradiento nuosmukis iš tikrųjų suranda geresnius parametrus? Mes galime vizualizuoti klaidą kaip funkciją aukštos dimensijos erdvėje, kur kiekvienas matmuo atitinka vieną modelio parametrą. Daugeliu matmenų mąstyti žmonėms praktiškai neįmanoma, todėl vietoj to galime įsivaizduoti paprastesnę analogiją: kalvų ir slėnių kraštovaizdį. Pagal šią analogiją: Kiekvienas taškas ant kraštovaizdžio atstovauja konkrečiam modelio parametrų deriniui. Šio taško kraštovaizdžio aukštis atspindi modelio klaidą. Mokymo pradžioje parametrai yra inicijuojami atsitiktinai.Tai tarsi būti įdėti kažkur atsitiktinai ant kalvos. Mūsų tikslas yra sumažinti klaidą, o tai reiškia rasti žemiausią tašką kraštovaizdyje. Sunkumas yra tas, kad mes nežinome, kaip atrodo kraštovaizdis.Tai tarsi mes stengiamės vaikščioti po kalną apakinti ar storu rūku.Taigi ką mes galime padaryti? Štai kur atsiranda gradiento nuosmukis. Matematikoje egzistuoja sąvoka, vadinama , kuris apibūdina funkcijos nuolydį tam tikru tašku. derivative Tai yra neįtikėtinai naudinga čia. išvestinė mums sako . which direction the landscape slopes downward So the algorithm simply does the following: Išmatuokite kraštovaizdžio nuolydį. Padarykite nedidelį žingsnį ta kryptimi, kur klaida mažėja. Repeat. Žingsnis po žingsnio modelis palaipsniui eina žemyn, kol pasiekia žemą tašką klaidų kraštovaizdyje. Tai iš esmės yra tai, ką daro gradiento nuosmukis. Kitas klausimas: kaip apskaičiuoti tokios sudėtingos funkcijos nuolydį? Aš čia neįeisiu į visas matematines detales, nes Karpatai jau turi Tai paaiškinti Puikus video Mūsų tikslams pakanka žinoti, kas toliau. Be to, yra taisyklė, vadinama grandinės taisyklė, kuri leidžia mums sujungti šiuos vietinius gradientus apskaičiuoti visos sudėtinės funkcijos gradientą. Pagrindinė idėja yra ta, kad mes judame atgal per operacijų grandinę, rinkdami gradientus kelyje. Visi pagrindiniai giliojo mokymosi sistemos įgyvendina šį mechanizmą. Pavyzdžiui: TensorFlow naudoja sistemą, vadinamą GradientTape, kuri registruoja operacijas kaip juostelės įrašymo įrenginį, kad po to būtų galima apskaičiuoti gradientus. PyTorch prijungia gradiento informaciją tiesiai prie tensorių. Kiekvienas tensorius prisimena, kaip jis buvo sukurtas, o tai leidžia gradientus apskaičiuoti automatiškai. Karpatijos įgyvendinimas seka tą pačią pagrindinę idėją. pažiūrėkime, kaip. # 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 Karpathy’s code, the entire gradient computation logic is implemented in the Klasė, kuri yra tik apie . Value 40 lines long Ši klasė iš esmės yra apvyniojimas aplink skaitines reikšmes. Be to, kad saugo duomenis, ji taip pat saugo: Kokias vertybes jis apskaičiavo iš (savo vaikų), ir vietinius gradientus, reikalingus atgaliniam plitimui. Jei pažvelgsime į kodą, pamatysime, kad standartiniai operatoriai yra iš naujo apibrėžti: • Pridėti Ąžuolė ir kitus. Tai reiškia, kad kiekvieną kartą, kai mes atliekame matematinę operaciją objektų, programa ne tik apskaičiuoja rezultatą, bet ir registruoja, kurios vertės jį sukūrė ir kaip gradientas turėtų būti propaguojamas. Value Finally, the Jis eina atgal per operacijų grandinę ir apskaičiuoja bendrą gradientą atsižvelgiant į klaidą. backward() Ir tai iš esmės yra visa idėja. Kitas svarbus mokymo komponentas yra pats gradiento nuosmukis, kuris naudoja apskaičiuotus gradientus, kad atnaujintų modelio parametrus. Kitaip tariant, tai yra kodo dalis, kuri iš tikrųjų eina žemyn kalną, naudodama nuolydžio informaciją. # 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 Karpato įgyvendinimo metu tai daroma su , kuris yra vienas iš plačiausiai naudojamų optimizavimo algoritmų giliojo mokymosi srityje. Adam optimizer Adomas yra šiek tiek sudėtingesnis nei pagrindinis gradiento nusileidimas. Vietoj to, kad imtųsi fiksuoto dydžio žingsnių, jis dinamiškai pritaiko žingsnio dydį, remdamasis ankstesnių gradientų istorija. . faster and more stable Anksčiau aprašytas gradiento skaičiavimas ir optimizavimo žingsnis kartu sudaro tai, ką galėtume vadinti gilios mokymosi sistema, kodo dalimi. Kiekvienas neuroninis tinklas – ar tai būtų kalbos modelis, vaizdo generatorius, robotų valdiklis, ar savarankiškas automobilis – yra apmokomas naudojant iš esmės tą patį principą. Šios kelios kodo eilutės užfiksuoja pagrindinę šiuolaikinio AI idėją. Large frameworks like: „TensorFlow“ Piteris Džeksas teikia labai optimizuotas įgyvendinimus, kurie gali veikti GPU, TPU ir paskirstytose grupėse, ir apima daug papildomų gudrybių ir optimizavimo. Bet jei viską sumažinsime iki esminių dalykų, pagrindinis principas yra tiksliai tas pats, ką matome šioje mažoje Python įgyvendinime. Dabar, kai mes matėme giliai mokymosi sistemos dalį kodo, mes galime pereiti prie faktinio neuroninio tinklo, kitaip tariant, pats GPT modelis. Kaip minėta anksčiau, GPT tikslas yra prognozuoti kitą žetoną, pagrįstą ženklais, kurie atėjo prieš jį. Šis apibrėžimas yra šiek tiek supaprastintas, nes įvestis iš tikrųjų susideda ne iš žodžių, o iš žetonų. Tokenai yra labai panašūs į žodžius, tačiau jie nėra tokie patys. Vietoj to, kad pasitikėtų iš anksto apibrėžtu žodynu, sistema išmoksta žodyną statistiškai iš mokymo duomenų. Taigi mokymas neprasideda fiksuotu žodžių sąrašu, kuriame kiekvienas žodis jau turi jam priskirtą numerį. Šis metodas yra ypač naudingas aglutinacinėms kalboms, pvz., Vengrijos, kur vienas žodis gali turėti daug skirtingų formų dėl priedų ir gramatinių galų. Turint pakankamai mokymo duomenų, kalbos modelis gali išmokti bet kokią kalbą, tiek natūralią, tiek dirbtinę. Tiesą sakant, žetonai net nereikia atstovauti tekstui. Nuotraukų dalys Audio fragmentai Sensoriai skaitytojai Praktiškai bet kokio tipo duomenys Dėl šios priežasties transformatorių modeliai neapsiriboja kalbos apdorojimu, jie taip pat gali būti naudojami vaizdo gamybai, kalbos apdorojimui, robotikai ir daugeliui kitų užduočių. Karpathy modelis yra tyčia labai mažas, todėl šiuo atveju žetonai nėra žodžiai, bet simboliai. Todėl modelio tikslas yra ne generuoti pilnus sakinius ar atsakymus, bet tiesiog gaminti realistiškus pavadinimus. Mokymo duomenų rinkinį sudaro didelis pavadinimų sąrašas, o po mokymo mes tikimės, kad modelis sukurs naujus pavadinimus, kurie statistiškai panašūs į pavyzdžius. This is obviously far from a full-scale language model like ChatGPT. But in reality, the difference is mostly one of scale. Jei mes išplėsime šį modelį milijonus kartų, naudosime žetonus vietoj simbolių ir mokysime jį didžiuliuose duomenų rinkiniuose, surinktuose iš interneto, galų gale turėtume kažką labai panašaus į šiuolaikinį didelį kalbos modelį. Šie dideli modeliai paprastai mokomi dviem etapais: Išankstinis mokymas - mokymas apie didžiulius interneto duomenų rinkinius, siekiant išmokti bendrų kalbų modelius. Fine-tuning – tolesnis mokymas naudojant kuruojamus žmogaus sukurtus pokalbius, siekiant pagerinti atsakymus. Procesas reikalauja didžiulių skaičiavimo išteklių ir didžiulių kiekių aukštos kokybės duomenų, dažnai kainuojančių milijonus dolerių. Kadangi dauguma iš mūsų neturi prieigos prie tokių išteklių, turėsime susitaikyti su pavadinimų generavimu. # 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}") Kodo pradžioje randame skyrių, atsakingą už vardų duomenų rinkinio įkėlimą ir žodyną. Šiuo atveju žodynas paprasčiausiai susideda iš simbolių, kurie pasirodo duomenų rinkinyje, sąrašo. Kiekvienam simboliui priskiriamas skaitinis identifikatorius, leidžiantis tekstą konvertuoti į skaičius, kuriuos gali apdoroti neuroninis tinklas. Next comes one of the most important concepts in deep learning: . embeddings Idėja paprasta, bet galinga. Vietoj to, kad dirbtume su žaliaviniais žetonų ID, mes kiekvieną žetoną nukreipiame į Šie vektoriai yra tai, ką iš tikrųjų apdoroja neuroninis tinklas. point in a high-dimensional vector space Iš tikrųjų bet koks neuroninis tinklas gali būti vertinamas kaip funkcija, kuri . maps vectors from one high-dimensional space into another Pavyzdžiui: If we train a neural network to classify images as , the network maps the image representation into a , where one dimension corresponds to “dogness” and the other to “catness”. dogs or cats two-dimensional space Jei įsivaizduosime vaizdo generatorių, pvz., „Midjourney“, jis atsitiktinį triukšmą nukreipia į aukštos dimensijos erdvę, kurioje kiekvienas taškas atstovauja vaizdui, kuris yra sąlyginis. Nepriklausomai nuo užduoties, tinklas visada atlieka . vector-to-vector transformation using a large mathematical function Tas pats pasakytina ir apie GPT. Vektorinės erdvės matmenis kodas apibrėžia konstanta. Įgyvendinant šią nuostatą numatyta . n_embd 16 This means that each token (in this case, each character) is represented as a . 16-dimensional vector Mathematically, this mapping is simply a . matrix multiplication Kodas, kuris yra atsakingas už šią transformaciją, vadinamas Kas yra už . wte word/token embedding Tačiau žinant, kokie simboliai pasirodo žodžiuose, nepakanka. Taip ir svarbu. position Pavyzdžiui, sekos reikšmė pasikeičia, jei perskirstome simbolius. Norėdami įtraukti pozicijos informaciją, modelis naudoja , implemented using another matrix called . positional embeddings wpe Kodas supažindina tiek žetoną, tiek jo padėtį su 16 dimensijų vektoriais, o tada paprasčiausiai . adds the two vectors together Rezultatas yra vienas vektorius, kuris koduoja abu: the identity of the token its position within the sequence Anksčiau minėjome, kad šie vektorių atstovavimai turi būti prasmingi, nes vėliau modelis apskaičiuos klaidas, pagrįstas atstumais tarp vektorių. Idealiu atveju: should be close to the correct vector Almost correct predictions should be far away from it Very wrong predictions Tai kelia įdomų klausimą: How do we design a good embedding space? Atsakymas stebėtinai paprastas: We don’t. Instead, we initialize the embedding matrices ( ir ) su atsitiktiniais skaičiais ir leisti gradiento nuosmukiui išmokti teisingą atstovavimą mokymo metu. wte wpe Jei turime pakankamai duomenų, optimizavimo procesas palaipsniui koreguos matricas, kol jos atspindės naudingus santykius. Tai gali sukelti stebėtinai galingas naujas savybes. For example, in the famous embedding model, vector arithmetic can capture semantic relationships. A classic example is: word2vec king − man + woman ≈ queen Čia jau matome, kad įterptinė erdvė pradeda atstovauti tam tikram , kur santykiai tarp sąvokų pasirodo kaip geometriniai santykiai tarp vektorių. simplified model of the world Dabar, kai mes matėme, kaip sukuriami vektoriai, galime pagaliau pažvelgti į patį neuronų tinklą, komponentą, kuris transformuoja šiuos vektorius į naujus vektorius, atstovaujančius kitam žetonui. Kitaip tariant, tinklas nukreipia vektorus iš žetonų, įterpiančių erdvę atgal į tą pačią erdvę, bet perkelia vieną žetoną.Kiekvienam žetonui jis prognozuoja, kuris žetonas turėtų sekti toliau. Šiam tikslui naudojama architektūra vadinama . Transformer „Transformer“ buvo pristatytas 2017 m. „Google“ mokslininkų garsiame straipsnyje: “Attention Is All You Need.” Originali architektūra buvo sukurta siekiant Jį sudarė dvi pagrindinės dalys: machine translation Kodavimas Iš decoder The encoder processed the input sentence, while the decoder generated the translated output sentence. For generative models like GPT, however, we only need • The . half of the original architecture decoder stack Štai kodėl GPT modeliai dažnai apibūdinami kaip . decoder-only transformers Dekoderis gauna įvesties žetonus ir pakartotinai juos apdoroja per identiškų sluoksnių krūvą. Savęs dėmesys A feed-forward neural network (MLP) These layers are repeated many times in large models. In diagrams, you often see this represented as Tai reiškia, kad blokas yra kaupiamas kelis kartus. ×N Viena iš pagrindinių „Transformer“ architektūros naujovių yra ta, kad ji apdoroja . entire sequence at once Senesni kalbos modeliai, ypač pasikartojantys neuroniniai tinklai (RNN), vienu metu apdorojo tekstą vienu žodžiu, nuosekliai perduodant informaciją palei seką. Transformers work differently. They can look at all tokens simultaneously, allowing the model to learn relationships between any parts of the text. This mechanism is called , which is why the original paper was titled . attention Attention Is All You Need Dėmesio mechanizmas apskaičiuoja, kaip in the sequence. relevant each token is to every other token For each token vector, the model computes a set of weights describing how much attention it should pay to the other tokens. It then combines the information from those tokens accordingly. The resulting vector therefore represents not only the token itself, but also . its meaning in the context of the entire sequence This may sound complicated, but the intuition is straightforward. Tarkime, kad mes paprašysime kalbos modelio: “What is the capital of France?” Jei žiūrėtume į žodį , we could not determine the answer. But attention allows the model to connect the word with . “capital” “capital” “France” The resulting representation captures the meaning of the phrase , making it possible for the model to produce the correct answer: . “capital of France” Paris One way to think about transformers is to imagine them as a kind of . 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. Grįžtant prie ankstesnio įterpimo pavyzdžio: jei mokymo duomenyse yra informacijos apie karalius ir moteris, modelis vis tiek gali atsakyti į klausimus apie karalienes, nes šių sąvokų santykiai užfiksuojami vektorinėje erdvėje. Jei laikysimės šios duomenų bazės analogijos, galėtume pasakyti: acts like an , helping the model locate relevant information. Attention index MLP sluoksniai apima pačias žinias. Šis protinis modelis yra naudingas intuicijai, bet jis nėra tiesiogine prasme teisingas. Tikrame transformatoriuje, kaip naudojamas ChatGPT, šie dėmesio + MLP blokai kartojami daug kartų. Knowledge is not stored in a single location but is distributed across layers. Be to, kiekvienas sluoksnis apima likutinį ryšį, kuris sumaišo pradinius įvesties vektorius su naujai apskaičiuotais vektoriais. 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. Dabar, kai turime didelę intuiciją apie transformatorių architektūrą, pažiūrėkime į vieną iš svarbiausių jos komponentų išsamiau: . 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)] Karpatijos įgyvendinime dėmesys apskaičiuojamas naudojant tris matricas, vadinamas: Q (Query) K (Key) V – vertė Kitaip tariant, kiekvienas žymeklio vektorius yra suskirstytas į tris skirtingas vektorines erdves. Už kiekvieną žetoną skaičiuojame: a query vector a key vector a value vector Once we have these vectors, we compare the query vector of one token with the key vectors of all tokens in the sequence. Mathematically, this is done using a dot product. The dot product gives a score that represents how strongly two vectors are related. This produces a set of numbers that represent . how relevant each token is to the current token Tačiau šie žaliaviniai balai dar nėra tikimybės. Norėdami konvertuoti juos į tikimybės pasiskirstymą, mes taikome , 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. Skaliuojamo taško produkto dėmesio formulė atrodo taip: Attention(Q, K, V) = softmax(QKᵀ / √dₖ) V Štai čia: computes the similarity between queries and keys QKᵀ 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 At this point, it is worth mentioning an important concept: . context length Kaip aptarėme anksčiau, transformatoriai vienu metu apdoroja visą seką. . every token with every other token Tai reiškia, kad skaičiavimo išlaidos didėja with the number of tokens. quadratically If we double the context length, the amount of computation increases roughly four times. This is one of the main limitations of transformer models. Skirtingai nuo kai kurių kitų architektūrų, transformatoriai neturi atskiros atminties sistemos. Everything outside that window is effectively invisible to the model. This is why context length is such an important property of modern language models. Daugelyje šiuolaikinių AI sistemų šis apribojimas sprendžiamas pridedant išorinės atminties mechanizmą. A common approach is to use a . vector database Vietoj tiesioginio žinių saugojimo modelyje, informacija gali būti saugoma išorėje kaip vektoriniai įterpimai. When the model receives a question, the system can: Convert the question into a vector. Search the vector database for related information. Įdėkite surinktą informaciją į modelio kontekstą. Tai reiškia, kad modelis mato abu: Klausimas ir atitinkamos žinios, paimtos iš duomenų bazės Because both appear in the context window, the model can generate an answer based on that information. Ši technika yra žinoma kaip and is widely used in modern AI systems and agent frameworks. 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. Returning to Karpathy’s implementation, the model uses , which is an improved form of the basic attention mechanism. multi-head attention Užuot skaičiuojant dėmesį naudojant vieną Q, K ir V matricos rinkinį, modelis naudoja kelis dėmesio galvučius. Šiame įgyvendinime yra keturios galvos. Pavyzdžiui, viena galva gali sutelkti dėmesį į gramatinius santykius, o kita gali užfiksuoti ilgesnes priklausomybes. Using multiple heads improves the quality of the representation. To keep the computational cost roughly the same, the dimensionality of each head is reduced. Anksčiau kartografavome vektorus iš a . 16-dimensional space to another 16-dimensional space With four attention heads, each head instead works in a . 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. Now that we have covered the attention mechanism, let’s move on to the second major component of the transformer block: the arba . MLP feed-forward neural network Kodas, MLP blokas atrodo kažkas panašaus: # 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 Jei pažvelgsime į masės matricos struktūrą, matricos eilutes galime interpretuoti kaip . classic neural network architecture neurons Neuronas yra paprastas skaičiavimo vienetas, kuris: Kiekvieną indėlį padauginkite iš svorio. Apibendrinant rezultatus, Tada jis taiko neliniarinę aktyvacijos funkciją, kad gautų išvestį. Šis modelis iš pradžių buvo įkvėptas biologinių neuronų žmogaus smegenyse.Tokiu būdu, neuroniniai tinklai istoriniu požiūriu buvo motyvuoti bandymais imituoti, kaip smegenys gali apdoroti informaciją. Tačiau šiuolaikinės AI sistemos nuėjo gana toli nuo šios originalios analogijos. In the MLP component, we can still loosely recognize something that resembles neurons. But when we look at mechanisms like , tampa daug sunkiau išlaikyti smegenų įkvėptą interpretaciją. attention Because of this, it is often better to think of modern AI systems simply as , rather than literal models of the brain. trainable mathematical functions MLP bloką kodas susideda iš trijų pagrindinių žingsnių: linijinė transformacija (matricos dauginimasis) Ne linijinės aktyvacijos funkcija (ReLU) Dar viena linijinė transformacija. Tai gali atrodyti paprasta, tačiau tokios struktūros turi labai galingą matematinę savybę. They are known as . universal approximators Visuotinis priartėjimas Tai reiškia, kad tam tikromis sąlygomis pakankamai didelis MLP gali būti to an arbitrary degree of accuracy. any mathematical function Iš esmės vienas milžiniškas MLP galėtų išmokti beveik viską. Štai kodėl transformatorių architektūros sujungia keletą mechanizmų, įskaitant dėmesį ir sluoksnius, kad efektyviau paskirstytų skaičiavimą. Tinklo išvestis nėra vienas žetonas, bet . 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. Generavimo metu algoritmas imasi pavyzdžių iš šio tikimybės pasiskirstymo. This means that tokens with higher probability are more likely to be chosen, but there is still an element of randomness. Šis atsitiktinumas kontroliuojamas pagal parametrą, vadinamą . temperature The parameter determines how deterministic or creative the model’s output will be. temperature Žema temperatūra - modelis labai palankiai vertina labiausiai tikėtinus žetonus, gaminant labiau nuspėjamus ir tikslius atsakymus. - the probability distribution becomes flatter, allowing less likely tokens to be selected more often, resulting in more diverse or creative outputs. High temperature Pavyzdžiui: Jei norime, kad modelis analizuotų dokumentą ir atsakytų į faktinius klausimus, paprastai pageidautina žema temperatūra. Jei norime, kad modelis sukurtų kūrybinį tekstą arba ištirtų naujas idėjas, aukštesnė temperatūra gali duoti įdomesnių rezultatų. Tai maždaug tai, ką norėjau paaiškinti apie šį gražų kodą ir apie GPT modelius apskritai. Daugelyje vietų paaiškinimas būtinai liko šiek tiek paviršutiniškas.Mano tikslas buvo pasiekti pusiausvyrą tarp dviejų dalykų: įtraukti kuo daugiau naudingų įžvalgų, tuo pačiu išlaikant diskusiją viename straipsnyje. Skaitytojams, kurie mano, kad paaiškinimo dalys yra šiek tiek neaiškios, arba kurie nori giliau ištirti detales, aš labai rekomenduoju Jo ir . There, you will find excellent material explaining everything needed to fully understand the concepts discussed here. Andrej Karpathy asmeninė svetainė Youtube kanalas Jūsų tinklaraštis Tikiuosi, kad šis straipsnis buvo naudingas daugeliui skaitytojų.