大语言模型的预训练,就像让模型玩一个“填空”游戏,模型需要预测句子中下一个会出现的词,并通过不断学习来提高预测的准确率。
picoGPT:GPT 的“迷你版”,麻雀虽小五脏俱全,一个用纯 Python 实现的极简 GPT 模型 虽然没有演示这个预训练,但是演示了推理过程,即如何基于GPT2的模型参数,完成续写下一个词的。
https://jaykmody.com/blog/gpt-from-scratch/
整个过程如下图:
从宏观的角度来看,GPT2推理架构由三个部分组成:
- 文本 + 位置嵌入(positional embeddings)
- 基于transformer的解码器层(decoder stack)
- 投影为词汇表(projection to vocab)的步骤
代码层面的话,就像这样:
def gpt2(inputs, wte, wpe, blocks, ln_f, n_head): # [n_seq] -> [n_seq, n_vocab]
# token + positional embeddings
x = wte[inputs] + wpe[range(len(inputs))] # [n_seq] -> [n_seq, n_embd]
# forward pass through n_layer transformer blocks
for block in blocks:
x = transformer_block(x, **block, n_head=n_head) # [n_seq, n_embd] -> [n_seq, n_embd]
# projection to vocab
x = layer_norm(x, **ln_f) # [n_seq, n_embd] -> [n_seq, n_embd]
return x @ wte.T # [n_seq, n_embd] -> [n_seq, n_vocab]
下面我们将这三个部分做更细致的拆解。
一、文本 + 位置嵌入 (Text + Position Embedding)
这一步是模型接收输入的起点。
文本被转化为词向量(word embeddings),而位置嵌入则赋予模型处理序列数据的能力,因为它能区分相同词语在不同位置的含义。
x = wte[inputs] + wpe[range(len(inputs))]
“文本嵌入”是将每个词转换成一个高维向量,这个向量捕捉了词的语义信息,也就是说,意思相近的词,它们的向量在空间中也会比较接近。
而“位置嵌入”则是为了让模型理解词语的顺序。 由于Transformer架构本身不具备处理顺序信息的能力,所以需要额外添加位置信息。
二、基于Transformer的解码器层 (Transformer Decoder Stack)
这是整个流程图中最核心的部分,也是GPT模型能力的关键所在。 你可以把它想象成一个“翻译专家”,他会仔细阅读被打上“特殊标记”的文字,理解每个词的意思,以及它们之间的关系,最终理解整句话的含义。
想象一下,你给一位精通多种语言的翻译专家看一段话。 他不仅知道每个词的意思,还能理解这些词组合在一起表达的深层含义。 解码器层就像这位“翻译专家”,它会关注每个词的“标签”,并分析它们之间的联系,从而理解这段文字的上下文信息。 图中的蓝色方框代表一个这样的“翻译专家”,而 “Nx” 表示有很多个这样的专家重复审阅,让理解更加精准。
每个解码器层主要由两个子层组成:多头因果自注意力 (Multi-Head Casual Self Attention) 和 前馈网络 (Feed Forward)。
def transformer_block(x, mlp, attn, ln_1, ln_2, n_head): # [n_seq, n_embd] -> [n_seq, n_embd]
# multi-head causal self attention
x = x + mha(layer_norm(x, **ln_1), **attn, n_head=n_head) # [n_seq, n_embd] -> [n_seq, n_embd]
# position-wise feed forward network
x = x + ffn(layer_norm(x, **ln_2), **mlp) # [n_seq, n_embd] -> [n_seq, n_embd]
return x
1、多头因果自注意力:
这是Transformer的核心机制。
- “自注意力”意味着模型会关注输入序列中的不同位置,并计算它们之间的关系,简单来说就是看看哪些词和当前要预测的词更相关。
- “因果”表示在预测当前词的时候,只能看到之前的词,不能“偷看”后面的词,这保证了生成文本的连贯性。
- “多头” 就像让多个“注意力”机制并行工作,从不同的角度理解上下文信息。
2、前馈网络:
在自注意力层之后,还有一个前馈网络,它对每个位置的表示进行独立的处理,进一步提取特征。
可以这样理解: 多头因果自注意力让句子中的词语“互相了解”,建立了联系;而前馈神经网络则像是为每个词语提供了一个独立的“加工车间”,让它们在吸收了上下文信息后,进行“独立思考”,提取更深层次的特征。
3、层归一化 (Layer Norm) 和残差连接 (Residual Connections):
图中的圆圈加号表示残差连接,它将上一层的输入直接加到当前层的输出上,有助于信息更好地流动,避免梯度消失。
Layer Norm 则用于稳定训练过程。
4、重复的层 (Nx)
GPT模型通常会堆叠多个这样的解码器层,每一层都在前一层的输出基础上进行更深层次的理解和特征提取。 你可以理解为“多次审阅”和“深入思考”。
5、Output Embeddings
经过解码器层的层层处理,模型对输入文本的理解更加深入,形成了一系列新的向量表示,这就是“输出嵌入”。
这一步的输出嵌入 (Output Embeddings) 可以理解为提炼后的“理解成果”,它包含了模型对整个输入序列的上下文信息的编码。
6、Transformer的解码器层小结
解码器层的作用不仅仅是“理解”,更准确地说是:
- 提取输入序列的上下文信息。
- 学习词语之间的依赖关系。
- 生成一个融合了上下文信息的高维表示。
三、投影为词汇表 (Projection to Vocab)
现在,模型已经对之前的文本有了充分的理解。 接下来,就要开始预测下一个词了。
1、线性层 (Linear)
线性层作用是将“输出嵌入”投影到词汇表的大小。 假设我们的词汇表有10000个词,那么线性层就会输出一个包含10000个数字的向量,每个数字代表对应词语的可能性大小,这个过程也叫做计算 “logits”。
2、Softmax —— 概率化
Softmax 函数会将线性层的输出(logits)转换为概率分布。 对于词汇表中的每个词,都会得到一个介于0和1之间的概率值,所有词的概率之和为1。 概率最高的词就是模型预测的下一个词。
3、下一个词的概率 (Next Token Probabilities)
模型会选择概率最高的词作为最终的预测结果。 在实际应用中,为了增加生成的多样性,可能会采用一些其他的采样策略,比如Top-K采样或者温度采样。
4、投影为词汇表小结
总结来说,投影步骤的作用是:
- 将模型的内部表示转化为一个可以直接解释的输出,即词汇表中每个词作为下一个词的概率。
- 选择概率最高的词作为预测结果。
GPT2推理过程总结
GPT2推理的步骤如下:
- 文本 + 位置嵌入: 将文本转化为模型可处理的数值表示,并编码位置信息。
- 基于Transformer的解码器层: 通过多层 Casual 自注意力机制和前馈网络,从输入序列中提取上下文信息,学习词语之间的依赖关系,并生成高维的上下文表示,可以简单认为是理解前一步的输入。
- 投影为词汇表: 通过线性层将上下文表示投影到词汇表空间,然后使用 Softmax 函数计算每个词作为下一个词的概率分布,最终选择概率最高的词作为预测结果。
了解解码器层内部的自注意力机制对于深入理解GPT的工作原理至关重要。希望通过这篇文章,你能对GPT的架构有一个更直观的理解。
下次再看到GPT生成的内容时,不妨想想这张流程图,也许你会对AI的“思考”方式有更深刻的认识。