第3章 大语言模型基础:Transformer架构原理、自注意力机制、预训练与微调、Prompt Engineering入门

说实话,刚开始接触大语言模型那会儿,我也挺懵的。

什么Transformer、自注意力、预训练……一堆术语砸过来。但后来我慢慢发现,这些东西其实没那么玄乎。今天我就用我自己的理解,给你拆开揉碎了讲讲。

3.1 Transformer架构:它到底解决了什么问题?

在Transformer出现之前,主流的序列模型是RNN和LSTM。它们有个硬伤——必须按顺序处理数据。你想想看,一句话要一个字一个字地读,读完前面才能读后面,这效率能高吗?

而且还有个更麻烦的问题:长距离依赖。比如句子开头的一个词,可能要到结尾才能找到它的关联对象。RNN处理这种场景,效果往往很差。

Transformer的出现,彻底改变了这个局面。它用了一个核心思想:并行计算 + 全局注意力

核心要点:Transformer不再按顺序读句子,而是把整个句子一次性扔进去,让每个词都能“看到”所有其他词。这就好比你看一篇文章,不用一个字一个字地读,扫一眼就能抓住重点。

Transformer的结构分两大部分:编码器(Encoder)解码器(Decoder)

  • 编码器:负责把输入文本转换成一组向量表示。说白了,就是把文字变成机器能懂的数学语言。
  • 解码器:负责根据编码器的输出,一步步生成目标文本。比如你问它一个问题,它就开始一个字一个字地往外蹦答案。

每个编码器和解码器内部,又由多个相同的层堆叠而成。每一层里,最重要的就是自注意力机制前馈神经网络

3.2 自注意力机制:模型是怎么“看懂”上下文的?

自注意力机制,说白了就是让模型学会“关注该关注的地方”。

举个例子,句子是:“那只猫坐在垫子上,它很可爱。”这里的“它”指的是谁?人类一眼就能看出来是“猫”。但机器怎么知道?

自注意力机制就是干这个的。它会计算句子中每个词和其他所有词之间的关联强度。对于“它”这个词,模型会发现它和“猫”的关联分数最高,于是就知道“它”指的就是“猫”。

我的经验:我在做代码生成模型时,遇到过一个问题——模型总是把变量名和函数名搞混。后来发现,就是因为自注意力机制没有很好地捕捉到变量定义和引用之间的长距离关系。调整了注意力头数和位置编码后,效果明显好了很多。

自注意力的计算过程,可以简单理解为三步:

  1. 生成Q、K、V:每个词都会生成三个向量——查询(Query)、键(Key)、值(Value)。你可以把Q想象成“我要找什么”,K想象成“我有什么”,V想象成“我实际的内容”。
  2. 计算注意力分数:用Q和所有K做点积,得到一个分数。分数越高,说明这两个词越相关。
  3. 加权求和:用这些分数对V进行加权求和,得到最终的输出。
# 伪代码示意:自注意力计算
def self_attention(Q, K, V):
    # 计算注意力分数
    scores = Q @ K.T / sqrt(d_k)  # d_k是向量维度
    # 归一化
    weights = softmax(scores)
    # 加权求和
    output = weights @ V
    return output

嗯,这里要注意:除以sqrt(d_k)这一步很关键。如果不做这个缩放,当向量维度很大时,点积的结果会非常大,softmax之后梯度会变得极小,模型就学不动了。

3.3 预训练与微调:为什么我们不用从头训练?

你想想看,训练一个像GPT这样的大模型,动辄需要几千张GPU跑几个月,电费都够买套房了。普通人根本玩不起。

所以就有了预训练 + 微调这套组合拳。

阶段 做什么 成本
预训练 在海量通用数据上训练,让模型学会语言的基本规律 极高(百万级)
微调 在特定任务的小数据集上继续训练,让模型适配你的场景 较低(千元级)

预训练的目标很简单:让模型学会“填词”。比如给你一句话“今天天气真____”,模型要能预测出“好”或者“不错”。这个过程重复几万亿次,模型就掌握了语法、常识、甚至一些推理能力。

微调就更有意思了。我记得有一次,我需要让模型专门理解Python代码的bug报告。我收集了5000条真实的bug报告和对应的修复代码,在预训练好的模型上继续训练了几天。结果模型从“只会写通用文本”变成了“能看懂代码报错并给出修复建议”的专家。

避坑指南:我曾经犯过一个错误——微调时用了太大的学习率。结果模型把预训练学到的知识全忘了,变成了一个只会说“你好”的傻子。微调的学习率一般要比预训练小10到100倍,这个经验值你可以直接拿去用。

3.4 Prompt Engineering入门:怎么让模型听懂人话?

Prompt Engineering,说白了就是学会跟AI聊天

你可能会觉得:“聊天谁不会啊?”但实际用起来,你会发现同样的问题,不同的问法,模型给出的答案质量天差地别。

我总结了几条核心原则:

  • 明确具体:不要问“帮我写个代码”,要问“用Python写一个读取CSV文件并计算每列平均值的函数”。越具体,模型越不容易跑偏。
  • 给出示例:如果你想让模型按某种格式输出,先给它一个例子。这叫Few-shot Prompting
  • 分步骤引导:复杂任务拆成几步。比如“第一步,分析需求;第二步,设计数据结构;第三步,编写代码”。
# 不好的Prompt
“帮我优化这段代码”

# 好的Prompt
“请帮我优化以下Python代码。要求:
1. 提高运行速度
2. 保持功能不变
3. 添加注释说明优化点

代码:
def calc(data):
    result = []
    for i in range(len(data)):
        for j in range(len(data)):
            if i != j:
                result.append(data[i] * data[j])
    return result”

你看,好的Prompt就像给一个实习生布置任务——你说得越清楚,他干得越好。

一个小技巧:我习惯在Prompt最后加一句“请一步一步思考”。对于复杂推理任务,这句话能让模型的准确率提升不少。原因嘛,其实就是让模型在生成答案前,先内部“想”一遍推理过程。

最后说一句:Prompt Engineering不是玄学,它是有规律可循的。多试几次,找到适合你任务的模板,效果会越来越好。