Andrej Karpathy é um nome que muitas pessoas no mundo da IA reconhecerão.Ele foi professor em Stanford por um tempo, mais tarde se tornou o chefe da divisão de IA da Tesla, trabalhou na OpenAI, e, na minha opinião, ele também produz alguns dos melhores vídeos educacionais de IA disponíveis hoje. O seu mais recente projeto, No entanto, é algo que só posso descrever como uma obra de arte. microGPT microGPT é uma implementação GPT completa escrita em E isso não é algum código inteligentemente compactado ou obstruído. Pelo contrário, o código é limpo, bem estruturado e comentado minuciosamente. Ele mesmo evita o uso de bibliotecas de aprendizagem profunda externas. Em outras palavras, ele não contém apenas a própria rede neural, mas também o quadro mínimo necessário para treiná-lo e executá-lo. only about 200 lines of Python code Na verdade, o projeto inteiro nem sequer tem um repositório completo – é simplesmente publicado como um . single GitHub Gist https://gist.github.com/karpathy/8627fe009c40f57531cb18360106ce95?embedable=true Neste artigo, tentarei explicar como essa bela peça de código funciona de uma forma que . anyone with basic Python knowledge can understand Vamos começar pelo nome . GPT O PT está a favor . 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 O modelo GPT prevê com base nas palavras anteriores em um texto. the next word (or token) Isso é essencialmente o que todos os modelos de linguagem fazem. Eles geram respostas por prever uma palavra de cada vez. Primeiro, eles preveem a próxima palavra, então eles adicionam essa palavra ao texto e preveem a próxima novamente, e assim por diante. 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 neural networks, this “thinking” process is implemented as a . very large mathematical function As palavras de entrada são convertidas em números e alimentadas nesta função, que então calcula a próxima palavra.Em princípio, qualquer sistema de regras pode ser representado matematicamente usando tais funções. Esta função é o que chamamos de . model O problema é que essa função pode ser Modelos de linguagem modernos contêm bilhões de parâmetros, o que significa que a fórmula matemática que os descreve pode ter bilhões de componentes. extremely complex Felizmente, há uma solução inteligente. Em vez de escrever a fórmula exata nós mesmos, definimos uma para a fórmula, uma estrutura com muitos parâmetros ajustáveis. Esses parâmetros podem então ser ajustados automaticamente até que o modelo funcione bem. “template” Temos vários modelos, dependendo do tipo de problema que queremos resolver: As redes convolucionais são comumente usadas para processamento de imagens. MLPs (multi-layer perceptrons) são usados para aproximação de funções gerais Os transformadores são usados para modelos de linguagem como o ChatGPT etc . Estes modelos representam enormes estruturas matemáticas que podem aproximar regras complexas uma vez que seus parâmetros são devidamente ajustados. A pergunta restante é: Ou, em outras palavras: How do we adjust these parameters? How do we “program” a neural network? Ajustar manualmente os parâmetros de uma rede neural seria obviamente impossível, especialmente quando estamos lidando com modelos que contêm milhões ou mesmo bilhões de parâmetros. Felizmente, há uma maneira de fazer isso automaticamente, usando dados. O método que o torna possível é chamado de . training gradient descent Se tivermos um grande conjunto de dados e uma grande fórmula matemática (nosso modelo), podemos calcular o erro do modelo para cada exemplo no conjunto de dados. No caso dos transformadores, o processo funciona aproximadamente assim. Words are represented as points in a high-dimensional vector space, where words with similar meanings appear closer to each other. Each word corresponds to a point in this space. O modelo recebe uma sequência de palavras como entrada e tenta prever a próxima palavra.Como as palavras são representadas como vetores, podemos calcular quão longe a palavra predita está da correta.Esta distância nos dá uma medida numérica do erro. E agora vem a magia. Usando a descida de gradiente, podemos calcular como os parâmetros da fórmula devem mudar para reduzir esse erro. Se tivermos dados suficientes, uma rede suficientemente grande, e treiná-la por tempo suficiente, a fórmula gradualmente se adapta aos padrões no conjunto de dados e produz previsões cada vez mais precisas. Mas como exatamente essa “mágica” funciona?Como a descida de gradiente realmente encontra melhores parâmetros? Podemos visualizar o erro como uma função em um espaço de alta dimensão, onde cada dimensão corresponde a um parâmetro do modelo. Thinking in many dimensions is practically impossible for humans, so instead we can imagine a simpler analogy: a landscape of hills and valleys. Nessa analogia: Cada ponto da paisagem representa uma combinação específica de parâmetros do modelo. A altura da paisagem nesse ponto representa o erro do modelo. No início do treinamento, os parâmetros são inicializados aleatoriamente.Isso é como ser colocado aleatoriamente em algum lugar na colina. Nosso objetivo é minimizar o erro, o que significa encontrar o ponto mais baixo da paisagem. A dificuldade é que não sabemos como a paisagem parece.É como se estivéssemos tentando descer uma montanha cegada ou em espessa névoa. É aí que entra a descida gradual. Em matemática, existe um conceito chamado , que descreve a inclinação de uma função em um determinado ponto. derivative Isso é incrivelmente útil aqui.O derivativo nos diz . which direction the landscape slopes downward O algoritmo simplesmente faz o seguinte: Medir a inclinação da paisagem. Faça um pequeno passo na direção em que o erro diminui. e repetição. Passo a passo, o modelo caminha gradualmente para baixo até atingir um ponto baixo na paisagem de erro. Isso é essencialmente o que a descida de gradiente faz. A pergunta restante é: como calcular a inclinação de uma função tão complexa? I won’t go into the full mathematical details here, because Karpathy already has an e explicando isso. excellent video Para os nossos propósitos, basta saber o seguinte. Every mathematical operation has a corresponding rule that allows us to compute its local gradient. In addition, there is a rule called the chain rule, which allows us to combine these local gradients to compute the gradient of an entire composite function. A ideia-chave é que nos movemos para trás através da cadeia de operações, coletando gradientes ao longo do caminho. Todos os principais quadros de aprendizagem profunda implementam esse mecanismo. Por exemplo: O TensorFlow usa um sistema chamado GradientTape, que grava operações como um gravador de fita para que os gradientes possam ser calculados posteriormente. O PyTorch liga informações de gradiente diretamente aos tensores. Cada tensor lembra como foi criado, o que permite que os gradientes sejam calculados automaticamente. A implementação de Karpathy segue a mesma idéia básica. # 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 No código de Karpathy, toda a lógica de computação de gradiente é implementada na A escola, que é apenas sobre . Value 40 lines long Esta classe é essencialmente um envoltório em torno de valores numéricos. Além de armazenar os dados em si, também armazena: O que é que ele (seus filhos) tem feito? e os gradientes locais necessários para a retropropaganda. Se olharmos para o código, podemos ver que os operadores padrão são redefinidos: Adição O MUL and others. Isso significa que, sempre que uma operação matemática é O programa não só calcula o resultado, mas também registra quais valores o produziram e como o gradiente deve ser propagado. Value Finally, the O método executa o processo de retropropagacao, caminha para trás através da cadeia de operações e calcula o gradiente total em relação ao erro. backward() E essa é basicamente toda a ideia. O outro componente importante do treinamento é a própria descida de gradientes, que usa os gradientes calculados para atualizar os parâmetros do modelo. Em outras palavras, esta é a parte do código que realmente desce a colina usando as informações de inclinação. # 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 Na implementação de Karpathy, isso é feito com o , que é um dos algoritmos de otimização mais amplamente utilizados na aprendizagem profunda. Adam optimizer Adam é um pouco mais sofisticado do que a descida de gradiente básica. Em vez de tomar passos de tamanho fixo, ele adapta o tamanho do passo dinamicamente com base na história dos gradientes anteriores. . faster and more stable O cálculo de gradiente descrito anteriormente e o passo de otimização juntos formam o que poderíamos chamar de framework de aprendizagem profunda parte do código. Todas as redes neurais – sejam elas um modelo de linguagem, um gerador de imagens, um controlador robótico ou um carro autônomo – são treinadas usando essencialmente o mesmo princípio. These few lines of code capture the core idea behind modern AI. Grandes frameworks como: TensorFlow Pythagoras Jax fornecer implementações altamente otimizadas que podem ser executadas em GPUs, TPUs e aglomerados distribuídos, e incluir muitos truques e otimizações adicionais. But if we strip everything down to the essentials, the underlying principle is exactly the same as what we see in this tiny Python implementation. Agora que vimos a parte do framework de aprendizagem profunda do código, podemos passar para a rede neural real, em outras palavras, o próprio modelo GPT. Como mencionado anteriormente, o objetivo do GPT é prever o próximo token com base nos tokens que vieram antes dele. This definition is slightly simplified, because the input does not actually consist of words, but of tokens. Tokens are very similar to words, but they are not the same. Instead of relying on a predefined dictionary, the system learns a vocabulary statistically from the training data. Tokens are, therefore, character sequences that appear frequently in the dataset. Assim, o treinamento não começa com uma lista fixa de palavras onde cada palavra já tem um número atribuído a ela. Esta abordagem é especialmente útil para línguas aglutinativas, como o húngaro, onde uma única palavra pode ter muitas formas diferentes devido a sufixos e terminações gramaticais. Com dados de treinamento suficientes, um modelo de idioma pode aprender qualquer idioma, seja natural ou artificial. Na verdade, os tokens nem precisam representar texto. Partes de Imagens fragments of audio Sensores de leitura or practically any type of data Devido a isso, os modelos de transformadores não se limitam ao processamento de linguagem, mas também podem ser usados para geração de imagens, processamento de fala, robótica e muitas outras tarefas. O modelo de Karpathy é intencionalmente muito pequeno, por isso, neste caso, os tokens não são palavras, mas caracteres. O objetivo do modelo não é, portanto, gerar sentenças ou respostas completas, mas simplesmente produzir nomes realistas. O conjunto de dados de treinamento consiste em uma grande lista de nomes, e após o treinamento, esperamos que o modelo gera novos nomes que se assemelham estatisticamente aos exemplos. Isso é obviamente longe de um modelo de linguagem em escala completa como o ChatGPT. Mas na realidade, a diferença é principalmente de escala. Se ampliássemos este modelo milhões de vezes, usássemos tokens em vez de caracteres, e treinássemos com enormes conjuntos de dados coletados da internet, acabaríamos com algo muito semelhante a um modelo de grande linguagem moderno. These large models are typically trained in two stages: Pre-treinamento – Treinamento em grandes conjuntos de dados da Internet para aprender padrões gerais de linguagem. Fine-tuning – treinamento adicional usando conversas geradas por humanos curadas para melhorar as respostas. O processo requer enormes recursos computacionais e enormes quantidades de dados de alta qualidade, muitas vezes custando milhões de dólares em computação. Since most of us do not have access to such resources, we will have to settle for generating names. # 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}") No início do código, encontramos a seção responsável por carregar o conjunto de dados de nomes e construir o vocabulário. Neste caso, o vocabulário consiste simplesmente na lista de caracteres que aparecem no conjunto de dados. Cada caracter é atribuído um identificador numérico, permitindo que o texto seja convertido em números que a rede neural pode processar. A seguir, um dos conceitos mais importantes na aprendizagem profunda: . embeddings The idea is simple but powerful. Em vez de trabalhar com IDs de token bruto, mapeamos cada token em um . These vectors are what the neural network actually processes. point in a high-dimensional vector space Na verdade, qualquer rede neural pode ser vista como uma função que . maps vectors from one high-dimensional space into another Por exemplo: Se treinarmos uma rede neural para classificar imagens como cães ou gatos, a rede mapeará a representação da imagem em um espaço bidimensional, onde uma dimensão corresponde a “dogness” e a outra a “catness”. Se imaginarmos um gerador de imagem como o Midjourney, ele mapeia o ruído aleatório em um espaço de alta dimensão, onde cada ponto representa uma imagem condicionada no prompt. Seja qual for a tarefa, a rede está sempre executando uma . vector-to-vector transformation using a large mathematical function O mesmo vale para o GPT. The dimensionality of the vector space is defined in the code by the constant O que, nesta implementação, é . n_embd 16 Isto significa que cada token (neste caso, cada caracter) é representado como um . 16-dimensional vector Em termos matemáticos, este mapa é simplesmente um . matrix multiplication No código, a matriz responsável por essa transformação é chamada O que representa para . wte word/token embedding No entanto, saber quais personagens aparecem em uma palavra não é suficiente. também as coisas. position Por exemplo, o significado de uma sequência muda se reordenarmos os caracteres. To incorporate positional information, the model uses , implementado usando outra matriz chamada . positional embeddings wpe O código mapeia tanto o token quanto sua posição em vetores de 16 dimensões e, em seguida, simplesmente . adds the two vectors together O resultado é um único vetor que codifica ambos: the identity of the token its position within the sequence Anteriormente, mencionamos que essas representações vetoriais devem ser significativas, porque mais tarde o modelo calculará erros com base nas distâncias entre vetores. O ideal é: should be close to the correct vector Almost correct predictions should be far away from it Very wrong predictions Isso levanta uma pergunta interessante: How do we design a good embedding space? The answer is surprisingly simple: We don’t. Em vez disso, inicializamos as matrizes de incorporação ( and ) com números aleatórios e permitir descida de gradiente para aprender a representação correta durante o treinamento. wte wpe Se tivermos dados suficientes, o processo de otimização irá ajustar gradualmente as matrizes até que elas representem relações úteis. This can lead to surprisingly powerful emergent properties. For example, in the famous A aritmética vetorial pode capturar relações semânticas.Um exemplo clássico é: word2vec king − man + woman ≈ queen Here we can already see that the embedding space begins to represent a kind of , onde as relações entre conceitos aparecem como relações geométricas entre vetores. 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. Em outras palavras, a rede mapeia vetores do token incorporando espaço de volta para o mesmo espaço, mas deslocado por um token. Para cada token, ele prevê que token deve seguir em seguida. The architecture used for this is called the . Transformer The Transformer was introduced in 2017 by researchers at Google in the famous paper: “Attention Is All You Need.” The original architecture was designed for Consistia de duas partes principais: machine translation an encoder a decoder O codificador processou a frase de entrada, enquanto o decodificador gerou a frase de saída traduzida. Para modelos gerativos como o GPT, no entanto, só precisamos : the . half of the original architecture decoder stack This is why GPT models are often described as . decoder-only transformers O decodificador recebe os tokens de entrada e os processa repetidamente através de uma pilha de camadas idênticas. Self-attention A feed-forward neural network (MLP) These layers are repeated many times in large models. In diagrams, you often see this represented as , meaning the block is stacked multiple times. ×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 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 The attention mechanism calculates how e na sequência. 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 Pode parecer complicado, mas a intuição é simples. 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 com . “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. 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. Se seguirmos esta analogia de banco de dados, poderíamos dizer: acts like an , helping the model locate relevant information. Attention index As camadas MLP contêm o próprio conhecimento. This mental model is useful for intuition, but it is not literally correct. In a real transformer like the one used in ChatGPT, these attention + MLP blocks are repeated many times. O conhecimento não é armazenado em um único local, mas é distribuído em várias camadas. 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. À medida que os vetores passam pelas camadas, novas abstrações e significados podem surgir.No momento em que a camada final produz sua saída, o modelo combinou informações de muitos níveis diferentes de representação. The full process is far too complex to follow step by step with human intuition. No entanto, apesar desta complexidade, o sistema funciona incrivelmente bem na prática. Now that we have a rough intuition about the transformer architecture, let’s look at one of its most important components in more detail: . 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)] Na implementação de Karpathy, a atenção é calculada usando três matrizes chamadas: Q (Query) K – A chave V (Value) Estas matrizes executam projeções vetoriais.Em outras palavras, cada vetor token é mapeado em três espaços vetoriais diferentes. For every token we compute: a query vector a key vector a value vector Uma vez que tenhamos esses vetores, comparamos o vetor de consulta de um token com os vetores-chave de todos os tokens na sequência. Matematicamente, isso é feito usando um produto de ponto. O produto de ponto dá uma pontuação que representa o quão fortemente dois vetores estão relacionados. This produces a set of numbers that represent . how relevant each token is to the current token However, these raw scores are not yet probabilities. To convert them into a probability distribution, we apply the , which transforms the scores into values between 0 and 1 that sum to 1. softmax function Estes valores representam a quantidade de atenção que cada token deve receber. Finally, the model combines the value vectors using these attention weights, producing a new vector that contains information gathered from the entire context. The formula for scaled dot-product attention looks like this: Attention(Q, K, V) = softmax(QKᵀ / √dₖ) V Here: QKT calcula a semelhança entre consultas e chaves is a scaling factor that stabilizes training √dₖ softmax converte as pontuações em probabilidades de atenção 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 As we discussed earlier, transformers process the entire sequence at once. This is necessary because attention requires comparing . every token with every other token That means the computational cost grows 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. 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. This is why context length is such an important property of modern language models. Em muitos sistemas modernos de IA, essa limitação é abordada adicionando um mecanismo de memória externa. Uma abordagem comum é a utilização de . vector database Em vez de armazenar conhecimento diretamente no modelo, a informação pode ser armazenada externamente como inserções vetoriais. When the model receives a question, the system can: Convert the question into a vector. Procure na base de dados de vetores para obter informações relacionadas. Insert the retrieved information into the model’s context. This means the model sees both: the question and the relevant knowledge retrieved from the database Because both appear in the context window, the model can generate an answer based on that information. This technique is known as e é amplamente utilizado em sistemas modernos de IA e frameworks de agentes. 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. Mas, como podemos ver, isso requer espaço na janela de contexto, razão pela qual o comprimento do contexto permanece tão importante. Voltando à implementação de Karpathy, o modelo usa , which is an improved form of the basic attention mechanism. multi-head attention Em vez de calcular a atenção usando um único conjunto de matrizes Q, K e V, o modelo usa múltiplas cabeças de atenção. Nesta implementação, existem quatro cabeças. Cada cabeça aprende a se concentrar em diferentes tipos de relações entre tokens.Por exemplo, uma cabeça pode se concentrar em relações gramaticais, enquanto outra pode capturar dependências de maior alcance. O uso de várias cabeças melhora a qualidade da representação. To keep the computational cost roughly the same, the dimensionality of each head is reduced. Anteriormente, nós mapeamos vetores de uma . 16-dimensional space to another 16-dimensional space With four attention heads, each head instead works in a Os resultados das cabeças são então combinados de volta em um único vetor. 4-dimensional space Embora cada cabeça funcione com vetores de dimensão inferior, o resultado combinado é tipicamente mais expressivo e mais preciso do que usando uma única cabeça de atenção. Agora que cobrimos o mecanismo da atenção, passemos ao segundo componente principal do bloco de transformador: o , or . MLP feed-forward neural network In the code, the MLP block looks something like this: # 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)] Um MLP é um . If we look at the structure of the weight matrices, we can interpret the rows of the matrix as . classic neural network architecture neurons Um neurônio é uma unidade computacional que: multiplies each input by a weight, Resumindo os resultados, Em seguida, aplica uma função de ativação não linear para produzir a saída. 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. No componente MLP, ainda podemos reconhecer livremente algo que se assemelha a neurônios. , torna-se muito mais difícil manter a interpretação inspirada no cérebro. attention Por causa disso, muitas vezes é melhor pensar em sistemas modernos de IA simplesmente como em vez de modelos literários do cérebro. trainable mathematical functions O bloco MLP no código consiste em três etapas principais: a (matrix multiplication), linear transformation a (ReLU), nonlinear activation function Uma transformação linear. This may look simple, but structures like this have an extremely powerful mathematical property. Eles são conhecidos como . universal approximators Aproximadores Universais Isso significa que, sob certas condições, um MLP suficientemente grande pode aproximar de um grau arbitrário de precisão. any mathematical function Em princípio, um único MLP enorme poderia aprender quase tudo. É por isso que as arquiteturas de transformadores combinam vários mecanismos, incluindo atenção e camadas empilhadas, para distribuir a computação de forma mais eficaz. A saída da rede não é um único token, mas um . probability distribution over all possible tokens Em outras palavras, para cada token no vocabulário, o modelo produz a probabilidade de que ele deve aparecer próximo na sequência. During generation, the algorithm then samples from this probability distribution. Isso significa que tokens com maior probabilidade são mais propensos a ser escolhidos, mas ainda há um elemento de aleatoriedade. This randomness is controlled by a parameter called . temperature O O parâmetro determina o quão determinista ou criativa será a saída do modelo. temperature Baixa temperatura - o modelo favorece fortemente os tokens mais prováveis, produzindo respostas mais previsíveis e precisas. Alta temperatura - a distribuição de probabilidade torna-se mais lisa, permitindo que tokens menos prováveis sejam selecionados com mais frequência, resultando em saídas mais diversificadas ou criativas. Por exemplo: Se queremos que o modelo analise um documento e responda a perguntas factuais, uma temperatura baixa é geralmente preferível. If we want the model to generate creative text or explore new ideas, a can produce more interesting results. higher temperature Isso é aproximadamente o que eu queria explicar sobre este belo pedaço de código, e sobre os modelos GPT em geral. Em muitos lugares, a explicação permaneceu necessariamente um pouco superficial.Meu objetivo era encontrar um equilíbrio entre duas coisas: incluir o máximo de informações úteis possíveis, mantendo a discussão no âmbito de um único artigo. For readers who found parts of the explanation a bit unclear, or who want to explore the details more deeply, I highly recommend O seu e Lá, você encontrará excelente material explicando tudo o que é necessário para entender completamente os conceitos discutidos aqui. Site pessoal de Andrej Karpathy YouTube channel O seu blog Espero que este artigo tenha sido útil para muitos leitores.Se nada mais, talvez sirva como um convite para explorar o fascinante mundo da IA.