人工智能(AI)全体系学习——系列三

人工智能(AI)全体系保姆级学习------系列三

文章目录

  • 人工智能(AI)全体系保姆级学习------系列三
  • [第10章 Attention机制](#第10章 Attention机制)
    • [10.1 注意力机制本质](#10.1 注意力机制本质)
      • [1. 什么是注意力机制](#1. 什么是注意力机制)
      • [2. 先用直观方式理解](#2. 先用直观方式理解)
      • [3. 数学本质是什么](#3. 数学本质是什么)
      • [4. 权重是怎么来的](#4. 权重是怎么来的)
      • [5. Query、Key、Value 到底是什么](#5. Query、Key、Value 到底是什么)
      • [6. 为什么注意力机制有效](#6. 为什么注意力机制有效)
      • [7. 一个具体例子](#7. 一个具体例子)
      • [8. 在哪些地方会用到注意力机制](#8. 在哪些地方会用到注意力机制)
      • [9. 一个最基础的注意力分类模型](#9. 一个最基础的注意力分类模型)
      • [10. 完整可运行代码](#10. 完整可运行代码)
      • [11. 核心思想总结](#11. 核心思想总结)
    • [10.2 Scaled Dot-Product](#10.2 Scaled Dot-Product)
      • [1. 这一节在解决什么问题](#1. 这一节在解决什么问题)
      • [2. 核心公式](#2. 核心公式)
      • [3. 每一项在干什么](#3. 每一项在干什么)
      • [4. 一句话理解](#4. 一句话理解)
      • [5. 一个直观例子](#5. 一个直观例子)
    • [6. 矩阵角度理解(很重要)](#6. 矩阵角度理解(很重要))
    • [7. PyTorch完整实现(从0实现)](#7. PyTorch完整实现(从0实现))
    • [8. 加入 Mask(真实模型必须)](#8. 加入 Mask(真实模型必须))
    • [9. 实际应用在哪里](#9. 实际应用在哪里)
    • [10. 核心总结](#10. 核心总结)
    • [10.3 Multi-Head Attention](#10.3 Multi-Head Attention)
  • [第11章 Transformer架构](#第11章 Transformer架构)
    • [11.1 Encoder-Decoder](#11.1 Encoder-Decoder)
  • [10.3 Multi-Head Attention](#10.3 Multi-Head Attention)
      • [1. 为什么需要 Multi-Head](#1. 为什么需要 Multi-Head)
      • [2. 核心思想](#2. 核心思想)
      • [3. 数学定义(核心公式)](#3. 数学定义(核心公式))
    • [4. 从计算流程理解](#4. 从计算流程理解)
    • [5. 为什么效果更好](#5. 为什么效果更好)
    • [6. 维度变化(必须理解)](#6. 维度变化(必须理解))
    • [7. 一个直观例子](#7. 一个直观例子)
    • [8. 完整代码(手写 Multi-Head)](#8. 完整代码(手写 Multi-Head))
    • [9. 实际意义](#9. 实际意义)
    • [10. 核心总结](#10. 核心总结)
    • [11.1 Encoder-Decoder 结构](#11.1 Encoder-Decoder 结构)
      • [1. Transformer在做什么](#1. Transformer在做什么)
      • [2. 一个非常直观的类比](#2. 一个非常直观的类比)
      • [3. Encoder做了什么(本质)](#3. Encoder做了什么(本质))
      • [4. Encoder内部结构(带理解)](#4. Encoder内部结构(带理解))
      • [6. Decoder做了什么(通俗理解)](#6. Decoder做了什么(通俗理解))
      • [7. 为什么不能"看到未来"(关键点)](#7. 为什么不能“看到未来”(关键点))
      • [8. Decoder最关键的一步](#8. Decoder最关键的一步)
      • [9. 一个完整流程(带理解)](#9. 一个完整流程(带理解))
      • [10. 一个最小Encoder实现](#10. 一个最小Encoder实现)
      • [11. 核心总结(这一节一定要记住)](#11. 核心总结(这一节一定要记住))
    • [11.2 Position Encoding(位置编码)](#11.2 Position Encoding(位置编码))
      • [1. 问题从哪里来](#1. 问题从哪里来)
      • [2. 核心解决思路](#2. 核心解决思路)
      • [3. 为什么用"加法"](#3. 为什么用“加法”)
      • [4. 数学定义(核心公式)](#4. 数学定义(核心公式))
      • [5. 为什么用正弦和余弦](#5. 为什么用正弦和余弦)
      • [6. 更直观理解](#6. 更直观理解)
      • [7. 一个小例子](#7. 一个小例子)
      • [8. PyTorch实现(位置编码)](#8. PyTorch实现(位置编码))
      • [9. 实际意义](#9. 实际意义)
      • [10. 核心总结](#10. 核心总结)
    • [11.3 Transformer整体流程](#11.3 Transformer整体流程)
  • [第12章 大语言模型(LLM)](#第12章 大语言模型(LLM))
    • [12.1 GPT系列(生成模型)](#12.1 GPT系列(生成模型))
      • [1. GPT在做什么](#1. GPT在做什么)
      • [2. 一种更直观的理解方式](#2. 一种更直观的理解方式)
      • [3. 数学本质](#3. 数学本质)
      • [4. GPT和Transformer的关系](#4. GPT和Transformer的关系)
      • [5. 为什么必须限制"看未来"](#5. 为什么必须限制“看未来”)
      • [6. GPT是如何学会语言的](#6. GPT是如何学会语言的)
      • [7. 为什么GPT可以写文章](#7. 为什么GPT可以写文章)
      • [8. 一个简单生成过程](#8. 一个简单生成过程)
      • [9. 一个最小GPT实现(简化版)](#9. 一个最小GPT实现(简化版))
      • [10. 本节核心总结](#10. 本节核心总结)
    • [12.2 BERT(理解)](#12.2 BERT(理解))
      • [1. BERT在做什么](#1. BERT在做什么)
      • [2. 和GPT最核心的区别](#2. 和GPT最核心的区别)
      • [3. 数学本质(核心目标)](#3. 数学本质(核心目标))
      • [4. Mask机制的不同](#4. Mask机制的不同)
      • [5. BERT是如何理解语言的](#5. BERT是如何理解语言的)
      • [6. 为什么BERT不能直接写文章](#6. 为什么BERT不能直接写文章)
      • [7. 一个简单理解例子](#7. 一个简单理解例子)
      • [8. 一个最小BERT实现(简化版)](#8. 一个最小BERT实现(简化版))
      • [9. GPT vs BERT(关键区别)](#9. GPT vs BERT(关键区别))
      • [10. 本节核心总结](#10. 本节核心总结)
    • [12.3 Prompt Engineering](#12.3 Prompt Engineering)
      • [1. Prompt在做什么](#1. Prompt在做什么)
      • [2. 为什么一句话能改变结果](#2. 为什么一句话能改变结果)
      • [3. Prompt的数学本质](#3. Prompt的数学本质)
      • [4. Prompt如何影响模型行为](#4. Prompt如何影响模型行为)
      • [5. Prompt为什么可以"变强"](#5. Prompt为什么可以“变强”)
      • [6. Chain-of-Thought(思维链)](#6. Chain-of-Thought(思维链))
      • [7. 一个实际应用变化](#7. 一个实际应用变化)
      • [8. Prompt在产品中的作用](#8. Prompt在产品中的作用)
      • [9. 一个简单代码示例](#9. 一个简单代码示例)
      • [10. 本节核心总结](#10. 本节核心总结)
    • [12.4 Fine-tuning(模型微调)](#12.4 Fine-tuning(模型微调))
      • [1. 为什么需要Fine-tuning](#1. 为什么需要Fine-tuning)
      • [2. Fine-tuning在做什么](#2. Fine-tuning在做什么)
      • [3. 数学本质](#3. 数学本质)
      • [4. 和Prompt的区别](#4. 和Prompt的区别)
      • [5. Fine-tuning带来的变化](#5. Fine-tuning带来的变化)
      • [6. 一个实际应用场景](#6. 一个实际应用场景)
      • [7. 一个简单微调示意代码](#7. 一个简单微调示意代码)
      • [8. Fine-tuning的局限](#8. Fine-tuning的局限)
      • [9. 什么时候该用Fine-tuning](#9. 什么时候该用Fine-tuning)
      • [10. 本节核心总结](#10. 本节核心总结)
  • [第13章 大模型训练技术](#第13章 大模型训练技术)
    • [13.1 RLHF(人类反馈强化学习)](#13.1 RLHF(人类反馈强化学习))
      • [1. RLHF在解决什么问题](#1. RLHF在解决什么问题)
      • [2. RLHF在做什么](#2. RLHF在做什么)
        • [3. 数学本质](#3. 数学本质)
      • [4. RLHF的三步流程](#4. RLHF的三步流程)
      • [5. 一个直观例子](#5. 一个直观例子)
      • [6. RLHF带来的变化](#6. RLHF带来的变化)
      • [7. 简单强化学习示意代码](#7. 简单强化学习示意代码)
      • [8. RLHF的意义](#8. RLHF的意义)
      • [9. 本节核心总结](#9. 本节核心总结)
    • [13.2 LoRA / PEFT](#13.2 LoRA / PEFT)
      • [1. 为什么需要高效微调](#1. 为什么需要高效微调)
      • [2. PEFT在做什么](#2. PEFT在做什么)
      • [3. LoRA的核心思想](#3. LoRA的核心思想)
      • [4. 为什么LoRA有效](#4. 为什么LoRA有效)
      • [5. 一个直观理解](#5. 一个直观理解)
      • [6. LoRA带来的优势](#6. LoRA带来的优势)
      • [7. 一个简单LoRA示意代码](#7. 一个简单LoRA示意代码)
      • [8. LoRA的应用场景](#8. LoRA的应用场景)
      • [9. 本节核心总结](#9. 本节核心总结)
    • [13.3 模型蒸馏](#13.3 模型蒸馏)
  • [第13章 大模型训练技术](#第13章 大模型训练技术)
    • [13.3 模型蒸馏(Model Distillation)](#13.3 模型蒸馏(Model Distillation))
      • [1. 为什么需要模型蒸馏](#1. 为什么需要模型蒸馏)
      • [2. 模型蒸馏在做什么](#2. 模型蒸馏在做什么)
      • [3. 数学本质](#3. 数学本质)
      • [4. 为什么蒸馏有效](#4. 为什么蒸馏有效)
      • [5. 一个直观理解](#5. 一个直观理解)
      • [6. 蒸馏带来的变化](#6. 蒸馏带来的变化)
      • [7. 一个简单蒸馏示意代码](#7. 一个简单蒸馏示意代码)
      • [8. 蒸馏的应用场景](#8. 蒸馏的应用场景)
      • [9. 本节核心总结](#9. 本节核心总结)
  • 系列三总结:Transformer与大模型(第10章---第13章)
    • [1. 从Attention到理解与生成](#1. 从Attention到理解与生成)
    • [2. Transformer:统一的建模框架](#2. Transformer:统一的建模框架)
    • [3. GPT与BERT:两条分化路径](#3. GPT与BERT:两条分化路径)
    • [4. Prompt:从"用模型"到"控制模型"](#4. Prompt:从“用模型”到“控制模型”)
    • [5. Fine-tuning与参数控制](#5. Fine-tuning与参数控制)
    • [6. RLHF:引入人类标准](#6. RLHF:引入人类标准)
    • [7. 模型蒸馏:走向实际落地](#7. 模型蒸馏:走向实际落地)
    • [8. 整体核心逻辑](#8. 整体核心逻辑)
    • [9. 一句话总总结](#9. 一句话总总结)
      • [7. 一个简单蒸馏示意代码](#7. 一个简单蒸馏示意代码)
      • [8. 蒸馏的应用场景](#8. 蒸馏的应用场景)
      • [9. 本节核心总结](#9. 本节核心总结)
  • 系列三总结:Transformer与大模型(第10章---第13章)
    • [1. 从Attention到理解与生成](#1. 从Attention到理解与生成)
    • [2. Transformer:统一的建模框架](#2. Transformer:统一的建模框架)
    • [3. GPT与BERT:两条分化路径](#3. GPT与BERT:两条分化路径)
    • [4. Prompt:从"用模型"到"控制模型"](#4. Prompt:从“用模型”到“控制模型”)
    • [5. Fine-tuning与参数控制](#5. Fine-tuning与参数控制)
    • [6. RLHF:引入人类标准](#6. RLHF:引入人类标准)
    • [7. 模型蒸馏:走向实际落地](#7. 模型蒸馏:走向实际落地)
    • [8. 整体核心逻辑](#8. 整体核心逻辑)
    • [9. 一句话总总结](#9. 一句话总总结)

第10章 Attention机制

10.1 注意力机制本质

1. 什么是注意力机制

注意力机制(Attention Mechanism)本质上是在解决一个很现实的问题:

当输入信息很多时,模型不应该平均对待所有内容,而应该把更多计算资源放到更重要的信息上。

例如一句话里,并不是每个词都同样重要。

在做情感分析时,"很好""失望""喜欢""差"这类词通常比"这个""东西""真的"更关键。

注意力机制做的事情,就是让模型自己学会:当前任务下,哪里更值得关注。

所以,注意力机制不是"记住全部",而是"有重点地看"。


2. 先用直观方式理解

可以把它理解成"阅读时划重点"。

人看一段文字时,不会每个字都花同样精力,而是会自然把注意力集中在关键词、转折词、结论句上。

神经网络中的注意力机制,其实就是把这个过程数学化了:

① 先比较"当前目标"和"各部分输入"的相关性

② 再给每个部分一个权重

③ 最后把重要部分加权汇总

也就是说,注意力机制最后输出的不是"原封不动的全部信息",而是经过筛选后的重点信息表示


3. 数学本质是什么

注意力机制最核心的形式,就是一个加权求和

设输入中有 (n) 个向量:
v 1 , v 2 , ... , v n v_1, v_2, \dots, v_n v1,v2,...,vn

模型会为每个向量分配一个权重:
α 1 , α 2 , ... , α n \alpha_1, \alpha_2, \dots, \alpha_n α1,α2,...,αn

最终输出为:
Attention ( V ) = ∑ i = 1 n α i v i \text{Attention}(V)=\sum_{i=1}^{n}\alpha_i v_i Attention(V)=i=1∑nαivi

这里的含义非常直接:

  • (v_i) 表示第 (i) 个位置携带的信息
  • (\alpha_i) 表示第 (i) 个位置的重要程度
  • 权重越大,说明该位置越值得关注

通常这些权重满足:
∑ i = 1 n α i = 1 , α i ≥ 0 \sum_{i=1}^{n}\alpha_i = 1,\quad \alpha_i \ge 0 i=1∑nαi=1,αi≥0

这表示它们像一个概率分布。

模型会把注意力"分配"到不同位置,只不过有的位置分得多,有的位置分得少。


4. 权重是怎么来的

注意力机制最关键的地方,不是加权求和,而是:这些权重怎么计算出来。

通常会先计算每个位置的"相关性分数":
e i = f ( q , k i ) e_i=f(q,k_i) ei=f(q,ki)

其中:

  • (q) 表示当前查询目标(Query)
  • (k_i) 表示第 (i) 个位置的特征(Key)
  • (f) 表示相似度函数

然后再通过 Softmax 把分数归一化,变成权重:
α i = exp ⁡ ( e i ) ∑ j = 1 n exp ⁡ ( e j ) \alpha_i=\frac{\exp(e_i)}{\sum_{j=1}^{n}\exp(e_j)} αi=∑j=1nexp(ej)exp(ei)

所以注意力机制完整过程是:
相似度计算 → 归一化 → 加权聚合 \text{相似度计算} \rightarrow \text{归一化} \rightarrow \text{加权聚合} 相似度计算→归一化→加权聚合

这一步非常重要,因为它说明注意力不是凭空来的,而是通过"比较当前目标和所有候选信息的关系"自动得到的。


5. Query、Key、Value 到底是什么

注意力机制里最经典的三个概念是:

Query(查询)、Key(键)、Value(值)

它们经常一起写成:
Attention ( Q , K , V ) \text{Attention}(Q,K,V) Attention(Q,K,V)

初看会有点抽象,但本质不难。

可以这样理解:

(1)Query :我现在到底想找什么

(2)Key :每条信息用来被匹配的"标签"

(3)Value:真正要取出来参与计算的内容

打个比方:

你在图书馆找"深度学习相关书籍"。

  • Query:你脑子里"深度学习"这个需求
  • Key:每本书的标签、标题、分类信息
  • Value:书本真正的内容

模型就是拿 Query 去和所有 Key 比较,看看谁更相关;

然后把相关的那些 Value 按权重聚合起来。

因此,注意力机制可以理解成:

用 Query 去检索 Key,再对对应的 Value 做加权汇总。


6. 为什么注意力机制有效

(1)它能抓住重点信息

传统方法常常会把所有输入压缩成一个固定表示,这样容易把关键信息冲淡。

注意力机制允许模型在每次处理时动态挑重点,因此表达能力更强。

(2)它能处理长距离依赖

一句很长的话里,前后很远的两个词可能有很强关系。

注意力机制可以直接计算任意两个位置之间的关联,而不需要一步一步传递。

这一点是 Transformer 能替代 RNN 的关键原因之一。

(3)它更适合并行计算

RNN 按顺序处理输入,而注意力机制可以通过矩阵运算一次性比较多个位置,天然适合 GPU 并行。

这也是它后来成为大模型核心组件的重要工程原因。


7. 一个具体例子

看这句话:

这个产品外观不错,但是续航很差。

如果任务是做情感分析,那么模型不能只看到"不错",因为后面"但是续航很差"对整体评价影响更大。

注意力机制会自动学到:在这句话里,"差""续航""但是"这些部分更值得关注。

也就是说,注意力机制并不是单纯找"积极词"或"消极词",而是在具体上下文中判断:哪部分对当前任务最关键。


8. 在哪些地方会用到注意力机制

注意力机制已经不是某个单独任务的小技巧,而是一种通用的信息建模方式。

在自然语言处理中,它可以用于:

机器翻译、文本分类、阅读理解、文本摘要、问答系统

在计算机视觉中,它可以用于:

图像分类、目标检测、图像生成、图像区域建模

在推荐系统中,它可以用于:

用户历史行为建模、商品兴趣加权、序列推荐

在大语言模型中,它几乎就是核心中的核心。

因为模型需要在很长的上下文中决定:当前生成下一个词时,到底该参考前文的哪些部分。


9. 一个最基础的注意力分类模型

下面给你一个最小但完整的例子:

用 PyTorch 实现一个带注意力机制的文本分类模型

这个模型做的事情是:

① 把每个字转成向量

② 给每个字计算一个注意力分数

③ 对所有字做加权求和

④ 用聚合后的句子向量做分类

数学形式如下。

先得到每个位置的向量表示:
h i = Embedding ( x i ) h_i=\text{Embedding}(x_i) hi=Embedding(xi)

然后计算每个位置的注意力得分:
e i = w T h i + b e_i=w^T h_i+b ei=wThi+b

用 Softmax 得到权重:
α i = exp ⁡ ( e i ) ∑ j = 1 n exp ⁡ ( e j ) \alpha_i=\frac{\exp(e_i)}{\sum_{j=1}^{n}\exp(e_j)} αi=∑j=1nexp(ej)exp(ei)

用权重对所有向量做加权求和:
s = ∑ i = 1 n α i h i s=\sum_{i=1}^{n}\alpha_i h_i s=i=1∑nαihi

最后分类输出:
y ^ = Softmax ( W s + b ) \hat{y}=\text{Softmax}(Ws+b) y^=Softmax(Ws+b)

这个结构虽然简单,但已经完整体现了注意力机制的本质。


10. 完整可运行代码

下面这份代码可以直接运行。

功能包括:

  • 构建简单训练数据
  • 建立词表
  • 训练带注意力的分类模型
  • 输出预测结果
  • 输出每个字对应的注意力权重
python 复制代码
import torch
import torch.nn as nn
import torch.optim as optim

# =========================
# 1. 准备训练数据
# =========================
texts = [
    "这个产品很好",
    "这个东西很差",
    "我非常喜欢",
    "我特别失望",
    "质量真的不错",
    "体验非常糟糕",
    "效果很好",
    "效果太差"
]

# 1 表示正向,0 表示负向
labels = [1, 0, 1, 0, 1, 0, 1, 0]

# =========================
# 2. 构建字符级词表
# =========================
vocab = {"<PAD>": 0}

for text in texts:
    for ch in text:
        if ch not in vocab:
            vocab[ch] = len(vocab)

# 句子最大长度
max_len = max(len(text) for text in texts)

def encode_text(text, vocab, max_len):
    """
    将文本转为索引序列,不足部分用 PAD 补齐
    """
    ids = [vocab[ch] for ch in text]
    if len(ids) < max_len:
        ids += [0] * (max_len - len(ids))
    return ids

X = torch.tensor([encode_text(text, vocab, max_len) for text in texts], dtype=torch.long)
y = torch.tensor(labels, dtype=torch.long)

# =========================
# 3. 定义带注意力机制的分类模型
# =========================
class AttentionClassifier(nn.Module):
    def __init__(self, vocab_size, embed_dim, num_classes):
        super().__init__()

        # 字符嵌入层:把每个字符映射成稠密向量
        self.embedding = nn.Embedding(vocab_size, embed_dim, padding_idx=0)

        # 注意力打分层:对每个位置输出一个分数
        self.attention_fc = nn.Linear(embed_dim, 1)

        # 分类层:用聚合后的句子向量做分类
        self.classifier = nn.Linear(embed_dim, num_classes)

    def forward(self, x):
        """
        x: [batch_size, seq_len]
        """
        # 1. 嵌入表示
        emb = self.embedding(x)  # [batch_size, seq_len, embed_dim]

        # 2. 计算注意力分数
        scores = self.attention_fc(emb).squeeze(-1)  # [batch_size, seq_len]

        # 3. 对 PAD 位置做掩码,避免其参与注意力计算
        mask = (x != 0)  # PAD位置为False
        scores = scores.masked_fill(~mask, -1e9)

        # 4. Softmax 归一化得到注意力权重
        attn_weights = torch.softmax(scores, dim=1)  # [batch_size, seq_len]

        # 5. 加权求和,得到句子表示
        sentence_vector = torch.sum(emb * attn_weights.unsqueeze(-1), dim=1)  # [batch_size, embed_dim]

        # 6. 分类输出
        logits = self.classifier(sentence_vector)  # [batch_size, num_classes]

        return logits, attn_weights

# =========================
# 4. 初始化模型、损失函数、优化器
# =========================
model = AttentionClassifier(
    vocab_size=len(vocab),
    embed_dim=32,
    num_classes=2
)

criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.01)

# =========================
# 5. 模型训练
# =========================
epochs = 300

for epoch in range(epochs):
    model.train()

    optimizer.zero_grad()

    logits, attn_weights = model(X)
    loss = criterion(logits, y)

    loss.backward()
    optimizer.step()

    if (epoch + 1) % 50 == 0:
        preds = torch.argmax(logits, dim=1)
        acc = (preds == y).float().mean().item()
        print(f"Epoch {epoch + 1:03d} | Loss = {loss.item():.4f} | Acc = {acc:.4f}")

# =========================
# 6. 定义预测函数
# =========================
def predict(text):
    """
    对单条文本进行预测,并打印注意力权重
    """
    model.eval()

    ids = encode_text(text, vocab, max_len)
    x = torch.tensor([ids], dtype=torch.long)

    with torch.no_grad():
        logits, attn_weights = model(x)
        probs = torch.softmax(logits, dim=1)[0]
        pred = torch.argmax(probs).item()

    print("=" * 50)
    print("输入文本:", text)
    print("预测类别:", "正向" if pred == 1 else "负向")
    print("类别概率:", probs.tolist())
    print("注意力权重:")

    # 只打印真实字符部分,不打印 PAD
    for ch, w in zip(text, attn_weights[0][:len(text)]):
        print(f"{ch} -> {w.item():.4f}")

# =========================
# 7. 测试模型
# =========================
predict("这个产品不错")
predict("这个体验很差")
predict("我很喜欢")
predict("我很失望")

11. 核心思想总结

注意力机制最重要的思想不是公式本身,而是它带来的处理方式变化:

过去的模型更像"平均处理全部输入",

而注意力机制更像"先判断谁重要,再重点处理谁"。

所以它的本质可以概括为一句话:
Attention = 相关性建模 + 权重分配 + 信息聚合 \text{Attention} = \text{相关性建模} + \text{权重分配} + \text{信息聚合} Attention=相关性建模+权重分配+信息聚合

再进一步压缩,就是:
Attention ( Q , K , V ) = Softmax ( f ( Q , K ) ) V \text{Attention}(Q,K,V)=\text{Softmax}(f(Q,K))V Attention(Q,K,V)=Softmax(f(Q,K))V

这也是后面 Transformer 和大模型的基础出发点。

10.2 Scaled Dot-Product

1. 这一节在解决什么问题

上一节已经知道:注意力机制核心是
Attention = Softmax ( Score ) ⋅ V \text{Attention} = \text{Softmax}(\text{Score}) \cdot V Attention=Softmax(Score)⋅V

关键在于:Score(相关性)怎么计算?

最简单的一种方式就是:

👉 用向量点积来衡量相似度

这就是 Scaled Dot-Product Attention。


2. 核心公式

给定:
Q ∈ R n × d , K ∈ R n × d , V ∈ R n × d Q \in \mathbb{R}^{n \times d},\quad K \in \mathbb{R}^{n \times d},\quad V \in \mathbb{R}^{n \times d} Q∈Rn×d,K∈Rn×d,V∈Rn×d

注意力计算为:
Attention ( Q , K , V ) = Softmax ( Q K T d ) V \text{Attention}(Q,K,V) = \text{Softmax}\left(\frac{QK^T}{\sqrt{d}}\right)V Attention(Q,K,V)=Softmax(d QKT)V


3. 每一项在干什么

(1)计算相似度

Q K T QK^T QKT

表示:

👉 每一个 Query 与所有 Key 的点积

结果是:
∈ R n × n \in \mathbb{R}^{n \times n} ∈Rn×n

含义:

  • 第 (i,j) 个元素表示:第 (i) 个位置对第 (j) 个位置的关注程度

(2)为什么要除以 (\sqrt{d})
latex 复制代码
\frac{QK^T}{\sqrt{d}}

作用是:防止数值过大导致 Softmax 失效

原因:

如果维度 (d) 很大,点积结果会变大:
Q ⋅ K ∼ O ( d ) Q \cdot K \sim O(d) Q⋅K∼O(d)

会导致:
Softmax → 极端分布(接近 o n e − h o t ) \text{Softmax} \rightarrow 极端分布(接近 one-hot) Softmax→极端分布(接近one−hot)

这样模型就学不动了(梯度消失)

所以需要缩放:
1 d \frac{1}{\sqrt{d}} d 1

👉 本质:控制方差,稳定训练


(3)Softmax 归一化

Softmax ( Q K T d ) \text{Softmax}\left(\frac{QK^T}{\sqrt{d}}\right) Softmax(d QKT)

作用:

👉 把"相似度矩阵"变成"注意力分布"

每一行满足:
∑ j α i j = 1 \sum_j \alpha_{ij} = 1 j∑αij=1


(4)加权 Value

Output = α V \text{Output} = \alpha V Output=αV

本质:
每一行 = ∑ j α i j v j \text{每一行} = \sum_j \alpha_{ij} v_j 每一行=j∑αijvj

👉 每个位置重新聚合全局信息


4. 一句话理解

Scaled Dot-Product Attention 可以理解为:

👉 用 Query 去"检索" Key,再用权重去聚合 Value

或者更数学一点:
每一行 = ∑ j α i j v j \text{每一行} = \sum_j \alpha_{ij} v_j 每一行=j∑αijvj


5. 一个直观例子

句子:

我 很 喜欢 这个 产品

当模型处理"喜欢"这个词时:

  • Query = "喜欢"的向量
  • Key = 所有词的向量
  • Value = 所有词的语义信息

模型会计算:
喜欢 ⋅ { 我, 很, 喜欢, 这个, 产品 } \text{喜欢} \cdot \{\text{我, 很, 喜欢, 这个, 产品}\} 喜欢⋅{我, 很, 喜欢, 这个, 产品}

结果可能是:

  • 喜欢 ↔ 喜欢(最高)
  • 喜欢 ↔ 产品(较高)
  • 喜欢 ↔ 我(较低)

然后:

👉 "喜欢"这个位置,会融合"产品""喜欢"等信息


6. 矩阵角度理解(很重要)

注意力可以完全用矩阵表示:
Q K T → 相似度矩阵Softmax ( Q K T ) → 权重矩阵Softmax ( Q K T ) V → 新表示 QK^T \rightarrow \text{相似度矩阵} \text{Softmax}(QK^T) \rightarrow \text{权重矩阵} \text{Softmax}(QK^T)V \rightarrow \text{新表示} QKT→相似度矩阵Softmax(QKT)→权重矩阵Softmax(QKT)V→新表示

所以本质是:

👉 一次矩阵乘法完成"全局信息交互"

这也是 Transformer 可以并行的核心原因。


7. PyTorch完整实现(从0实现)

下面代码手写 Scaled Dot-Product Attention(不调用现成API)

python 复制代码
import torch
import torch.nn as nn

# =========================
# 1. 构造输入
# =========================
batch_size = 2
seq_len = 5
d_model = 16

# 随机输入(模拟Embedding输出)
X = torch.randn(batch_size, seq_len, d_model)

# =========================
# 2. 定义Q K V映射
# =========================
W_Q = nn.Linear(d_model, d_model)
W_K = nn.Linear(d_model, d_model)
W_V = nn.Linear(d_model, d_model)

Q = W_Q(X)
K = W_K(X)
V = W_V(X)

# =========================
# 3. 计算Attention
# =========================

# Step1: 点积
scores = torch.matmul(Q, K.transpose(-2, -1))

# Step2: 缩放
d_k = Q.size(-1)
scores = scores / (d_k ** 0.5)

# Step3: Softmax
attn_weights = torch.softmax(scores, dim=-1)

# Step4: 加权求和
output = torch.matmul(attn_weights, V)

print("输出形状:", output.shape)
print("注意力矩阵:", attn_weights)

8. 加入 Mask(真实模型必须)

在实际中(比如语言模型),不能看到"未来信息"。

例如:

我 今天 去 吃饭

当预测"今天"时,不能看到"去 吃饭"

所以需要 Mask:
Masked Attention \text{Masked Attention} Masked Attention

代码实现:

python 复制代码
# 创建mask(上三角为True)
mask = torch.triu(torch.ones(seq_len, seq_len), diagonal=1).bool()

# 应用mask
scores = scores.masked_fill(mask, float('-inf'))

attn_weights = torch.softmax(scores, dim=-1)

9. 实际应用在哪里

Scaled Dot-Product Attention 是:

Transformer 的最底层核心算子

直接应用于:

  • GPT(生成模型)
  • BERT(理解模型)
  • ChatGPT(对话系统)
  • 代码生成模型
  • 多模态模型(文本+图像)

可以说:

所有大模型 = Attention 的堆叠


10. 核心总结

最重要的一行公式:
Attention ( Q , K , V ) = Softmax ( Q K T d ) V \text{Attention}(Q,K,V) = \text{Softmax}\left(\frac{QK^T}{\sqrt{d}}\right)V Attention(Q,K,V)=Softmax(d QKT)V

最终本质:

让每个位置都能"看见全局",并按重要性选择信息


10.3 Multi-Head Attention


第11章 Transformer架构

11.1 Encoder-Decoder

、好,这一版我帮你再精修到可直接发博客级别

  • 公式只集中在数学部分
  • 每个公式配简洁解释
  • 文字比刚才稍微更充实,但不过度
  • 不使用多余符号(👉最多不出现)
  • 结构清晰、专业但易理解

10.3 Multi-Head Attention

1. 为什么需要 Multi-Head

在上一节中,单个 Attention 已经可以实现:

让每个位置根据相关性,从整个序列中获取信息。

但它有一个本质限制:
只能在一个特征空间里建模所有关系。

而现实数据(尤其是语言)具有多种不同类型的依赖关系。例如一句话:

小明在北京工作

模型在理解时,往往需要同时处理:

(1)人物与动作的关系(小明 → 工作)

(2)动作与地点的关系(工作 → 北京)

(3)句子整体语义结构

如果只用一个 Attention,这些关系会被压在同一表示空间中,容易互相干扰,表达能力受限。

因此,引入 Multi-Head Attention,让模型可以同时从多个子空间建模不同关系


2. 核心思想

Multi-Head Attention 的核心思想可以概括为:

将一次注意力计算拆分为多个并行的子计算,每个子计算在不同的特征空间中进行,最后再进行融合。

从直观上看,可以理解为:

  • 单头 Attention:用一种方式理解信息
  • 多头 Attention:用多种方式同时理解信息,再进行综合

这样可以显著提升模型对复杂结构的表达能力。


3. 数学定义(核心公式)

首先,对输入进行线性变换,得到不同 head 的 Query、Key、Value:
Q i = Q W i Q , K i = K W i K , V i = V W i V Q_i = QW_i^Q,\quad K_i = KW_i^K,\quad V_i = VW_i^V Qi=QWiQ,Ki=KWiK,Vi=VWiV

这里的含义是:

每个 head 都有自己的一组参数 (W_i^Q, W_i^K, W_i^V),

它们会把原始表示映射到不同的子空间中。

接下来,每个 head 独立计算注意力:
head i = Softmax ( Q i K i T d k ) V i \text{head}_i = \text{Softmax}\left(\frac{Q_i K_i^T}{\sqrt{d_k}}\right)V_i headi=Softmax(dk QiKiT)Vi

这一公式可以拆开理解为三步:

  • (Q_i K_i^T):计算当前 head 中各位置之间的相似度
  • (\frac{1}{\sqrt{d_k}}):对相似度进行缩放,防止数值过大
  • Softmax:将相似度转为权重分布
  • 乘以 (V_i):根据权重对信息进行加权聚合

最后,将所有 head 的结果拼接并线性变换:
MultiHead ( Q , K , V ) = Concat ( head 1 , ... , head h ) W O \text{MultiHead}(Q,K,V) = \text{Concat}(\text{head}_1,\dots,\text{head}_h)W^O MultiHead(Q,K,V)=Concat(head1,...,headh)WO

这一步的作用是:

  • Concat:整合多个子空间的信息
  • (W^O):重新映射回统一表示空间

4. 从计算流程理解

整个 Multi-Head Attention 可以分为五个步骤:

第一步:输入经过线性映射,生成 Q、K、V

第二步:将 Q、K、V 按维度拆分成多个 head

第三步:每个 head 独立计算注意力

第四步:将所有 head 的输出拼接

第五步:通过线性层融合结果

这个过程的关键变化在于:

原本一次注意力计算,被扩展为多次并行计算,并在最后统一整合。


5. 为什么效果更好

(1)表达能力提升

单头 Attention 只能在一个空间中学习关系,而 Multi-Head 将表示拆分为多个子空间,每个子空间可以学习不同模式,使整体表达更加丰富。

(2)信息解耦

不同类型的关系被分配到不同 head 中建模,避免了在同一空间中的信息冲突,提高了建模质量。

(3)结构更稳定

多个 head 的结果在最后进行融合,相当于从多个角度进行综合判断,有助于模型训练更加稳定。


6. 维度变化(必须理解)

设模型维度为:

text 复制代码
d_model = 512

头数为:

text 复制代码
h = 8

则每个 head 的维度为:

text 复制代码
d_k = 64

这意味着:

  • 每个 head 在低维空间中进行注意力计算
  • 最终通过拼接恢复到原始维度

这种设计既保证了表达能力,又控制了计算复杂度。


7. 一个直观例子

句子:

我今天在图书馆学习

不同 head 可能关注不同内容:

一个 head 关注"我 → 学习"(行为关系)

一个 head 关注"学习 → 图书馆"(地点关系)

一个 head 关注"今天 → 学习"(时间关系)

最终输出是这些关系的综合结果,而不是单一关系。


8. 完整代码(手写 Multi-Head)

python 复制代码
import torch
import torch.nn as nn

class MultiHeadAttention(nn.Module):
    def __init__(self, d_model=32, num_heads=4):
        super().__init__()

        assert d_model % num_heads == 0

        self.d_model = d_model
        self.num_heads = num_heads
        self.d_k = d_model // num_heads

        # Q K V 映射
        self.W_Q = nn.Linear(d_model, d_model)
        self.W_K = nn.Linear(d_model, d_model)
        self.W_V = nn.Linear(d_model, d_model)

        # 输出映射
        self.W_O = nn.Linear(d_model, d_model)

    def forward(self, x):
        """
        x: [batch_size, seq_len, d_model]
        """

        batch_size, seq_len, _ = x.size()

        # 1. 线性映射得到 Q K V
        Q = self.W_Q(x)
        K = self.W_K(x)
        V = self.W_V(x)

        # 2. 切分为多头
        def split_heads(t):
            # [B, L, D] -> [B, H, L, d_k]
            return t.view(batch_size, seq_len, self.num_heads, self.d_k)\
                    .transpose(1, 2)

        Q = split_heads(Q)
        K = split_heads(K)
        V = split_heads(V)

        # 3. 注意力计算
        scores = torch.matmul(Q, K.transpose(-2, -1))  # 相似度
        scores = scores / (self.d_k ** 0.5)           # 缩放

        attn_weights = torch.softmax(scores, dim=-1)

        out = torch.matmul(attn_weights, V)           # 加权聚合

        # 4. 拼接多头
        out = out.transpose(1, 2).contiguous()
        out = out.view(batch_size, seq_len, self.d_model)

        # 5. 输出映射
        out = self.W_O(out)

        return out, attn_weights


# 测试
x = torch.randn(2, 5, 32)

model = MultiHeadAttention(d_model=32, num_heads=4)

out, attn = model(x)

print("输出形状:", out.shape)
print("注意力形状:", attn.shape)

9. 实际意义

Multi-Head Attention 是 Transformer 能够成功的关键结构之一。

它使模型具备:多角度理解能力,更强的上下文建模能力,更丰富的语义表达能力

在 GPT、BERT 等模型中,每一层都会使用 Multi-Head Attention,层层叠加后形成强大的建模能力。


10. 核心总结

Multi-Head Attention 的本质不是简单的"多次计算",而是:

在多个子空间中并行建模不同关系,并进行融合。

它解决了单一注意力表达能力不足的问题,使模型能够更全面地理解复杂数据结构。

好,这一版我帮你补强"通俗理解"部分,但不降低专业性,同时保持你现在的整体风格(结构清晰 + 公式少 + 有代码)。


11.1 Encoder-Decoder 结构

1. Transformer在做什么

前面学的 Attention,本质是在解决:

一句话内部,谁和谁有关。

但一个完整模型,不只是"理解一句话",还要:

  • 理解输入
  • 生成输出

Transformer 就是把这两件事拆开来做:

Encoder 负责理解,Decoder 负责生成

可以把它想成一个流程:

输入 → 理解 → 表示 → 再生成输出


2. 一个非常直观的类比

可以把 Transformer 理解成两个人协作:

Encoder:阅读者

负责把原文读懂,并整理成一份"笔记"

Decoder:写作者

根据这份笔记,一点一点写出新的内容

例如翻译:

原句:

I love AI

过程变成:

  • Encoder:理解这句话的意思(不是逐词,而是整体语义)
  • Decoder:根据理解,生成"我喜欢人工智能"

关键点在于:

👉 Decoder 并不是直接看原句,而是看 Encoder 给出的"理解结果"


3. Encoder做了什么(本质)

Encoder 的作用可以总结为一句话:

把"原始输入"变成"带上下文的语义表示"。

通俗一点说:

原始词向量:

  • "银行" → 只是一个词

经过 Encoder 后:

  • "银行" → 会结合上下文,变成"金融机构"或"河岸"

也就是说:

Encoder 让每个词"理解了周围环境"。


4. Encoder内部结构(带理解)

每一层 Encoder 做两件事:

(1)Self-Attention(信息交流)

作用:

让每个词看到整个句子

通俗理解:

一句话中,每个词都会问:

"我应该参考哪些词?"

然后根据相关性,把别的信息融合进来。


(2)前馈网络(信息加工)

作用:

对融合后的信息进行进一步处理

可以理解为:

Attention 是"收集信息"

FFN 是"加工信息"

类似:

收集资料 → 思考整理


5. 为什么要多层 Encoder

Transformer 通常会堆很多层(比如 12 层、24 层)

原因是:

第一层:学基础关系

第二层:学更复杂关系

第三层:学抽象语义

可以理解为:

逐层提炼信息

就像:

  • 第1层:看字
  • 第2层:看词
  • 第3层:看句子结构
  • 第N层:理解语义

6. Decoder做了什么(通俗理解)

Decoder 的作用是:

一步一步生成结果

例如生成句子:

我 今天 去 吃饭

Decoder 实际是这样工作的:

第一步:生成"我"

第二步:基于"我",生成"今天"

第三步:基于"我 今天",生成"去"

它是一个逐步预测的过程


7. 为什么不能"看到未来"(关键点)

在生成过程中,有一个非常重要的限制:

模型不能看到未来的词。

比如:

在预测"今天"时:

不能提前看到"去 吃饭"

否则模型会"作弊"。

所以引入:

Masked Self-Attention

作用:

👉 只允许看左边(历史信息)


8. Decoder最关键的一步

Decoder 和 Encoder 最大区别在这里:

Decoder会去"参考Encoder的输出"

这一步可以理解为:

  • Encoder:提供"理解结果"
  • Decoder:在生成时不断查阅这份理解

例如翻译:

生成"喜欢"时:

Decoder 会自动关注输入中的 "love"

所以这一步的本质是:

生成过程与输入语义对齐


9. 一个完整流程(带理解)

整个 Transformer 实际流程是:

① 输入文本 → 转为向量

② 进入 Encoder → 逐层理解

此时得到:

👉 "整句话的语义表示"

③ Decoder 开始生成

每一步都做:

  • 看已经生成的内容(历史)
  • 看 Encoder 的输出(理解结果)
  • 预测下一个词

不断循环,直到结束。


10. 一个最小Encoder实现

python 复制代码
import torch
import torch.nn as nn

class EncoderBlock(nn.Module):
    def __init__(self, d_model=32, num_heads=4, hidden_dim=64):
        super().__init__()

        # 多头注意力(信息交流)
        self.attn = nn.MultiheadAttention(d_model, num_heads, batch_first=True)

        # 前馈网络(信息加工)
        self.ffn = nn.Sequential(
            nn.Linear(d_model, hidden_dim),
            nn.ReLU(),
            nn.Linear(hidden_dim, d_model)
        )

        # 归一化
        self.norm1 = nn.LayerNorm(d_model)
        self.norm2 = nn.LayerNorm(d_model)

    def forward(self, x):
        # 1. 自注意力
        attn_out, _ = self.attn(x, x, x)

        # 残差连接 + 归一化
        x = self.norm1(x + attn_out)

        # 2. 前馈网络
        ffn_out = self.ffn(x)

        # 残差连接 + 归一化
        x = self.norm2(x + ffn_out)

        return x


# 测试
x = torch.randn(2, 5, 32)

model = EncoderBlock()

out = model(x)

print("输出形状:", out.shape)

11. 核心总结(这一节一定要记住)

Transformer 的核心结构可以记成一句话:

Encoder负责"理解",Decoder负责"生成"。

更具体一点:

  • Encoder:让每个词理解上下文
  • Decoder:基于理解,一步步生成结果

整个模型的关键在于:

用 Attention 让信息在序列中自由流动


11.2 Position Encoding(位置编码)

1. 问题从哪里来

在前面的结构中,Transformer 有一个非常"反直觉"的特点:

它本身并不具备顺序信息。

不像 RNN 按时间一步步处理,也不像 CNN 有局部滑动窗口,

Transformer 的 Attention 是这样工作的:

  • 所有位置同时输入
  • 每个位置可以直接"看到"所有位置

这带来一个问题:

如果输入是:

我 喜欢 你

你 喜欢 我

在没有位置信息的情况下,这两句话的"词集合"是一样的:

text 复制代码
我 喜欢 你

模型是无法区分顺序的。

也就是说:

Attention 只关心"谁和谁相关",但不知道"谁在前谁在后"。


2. 核心解决思路

为了解决这个问题,Transformer 引入:

Position Encoding(位置编码)

它的核心思想非常简单:

给每个位置一个"位置信号",让模型知道顺序。

具体做法是:

在词向量中加入位置信息:

text 复制代码
最终输入 = 词向量 + 位置编码

这样一来:

  • "我在第1个位置"
  • "你在第3个位置"

这些信息会被显式编码进去。


3. 为什么用"加法"

这里有一个设计选择:

为什么是"相加",而不是拼接?

原因是:

  • 保持维度不变(方便计算)
  • 让模型可以同时利用"语义信息"和"位置信息"

可以理解为:

词向量表示"是什么",位置编码表示"在哪里"。

相加之后:

👉 每个向量同时包含"内容 + 位置"


4. 数学定义(核心公式)

Transformer 使用的是一种固定的函数编码方式
P E ( p o s , 2 i ) = sin ⁡ ( p o s 10000 2 i d ) P E ( p o s , 2 i + 1 ) = cos ⁡ ( p o s 10000 2 i d ) PE(pos, 2i) = \sin\left(\frac{pos}{10000^{\frac{2i}{d}}}\right) PE(pos, 2i+1) = \cos\left(\frac{pos}{10000^{\frac{2i}{d}}}\right) PE(pos,2i)=sin(10000d2ipos)PE(pos,2i+1)=cos(10000d2ipos)

这里的含义是:

  • (pos):位置(第几个词)
  • (i):维度索引
  • (d):向量维度

解释一下这两个公式在干什么:

  • 偶数维用 sin
  • 奇数维用 cos
  • 不同维度使用不同频率

这样每个位置都会得到一个独特的编码向量


5. 为什么用正弦和余弦

这个设计看起来很"数学",但其实有两个很重要的工程意义:

(1)可以表示相对位置

由于 sin 和 cos 具有周期性:

不同位置之间的关系可以通过函数变化体现出来。

模型可以通过这些规律,学习:

  • 两个词之间距离远还是近
  • 顺序关系

(2)支持更长序列

这种编码是"函数生成"的,而不是查表:

  • 可以推广到任意长度
  • 不依赖训练数据

相比之下,如果用"可学习位置向量",长度受限。


6. 更直观理解

可以把位置编码理解为:

给每个位置贴一个"身份证"

例如:

第1个词 → 编码A

第2个词 → 编码B

第3个词 → 编码C

然后和词向量融合:

原本:

"我" → 含义向量

现在变成:

"我 + 第1位"

"喜欢 + 第2位"

"你 + 第3位"

这样模型在计算 Attention 时,就能区分:

谁在前

谁在后


7. 一个小例子

句子:

我 爱 你

加入位置编码后:

  • "我" → 向量 + 位置1
  • "爱" → 向量 + 位置2
  • "你" → 向量 + 位置3

如果换成:

你 爱 我

虽然词一样,但位置不同:

👉 输入向量完全不同

模型自然可以区分这两句话。


8. PyTorch实现(位置编码)

下面是一个标准实现(可直接运行):

python 复制代码
import torch
import torch.nn as nn
import math

class PositionalEncoding(nn.Module):
    def __init__(self, d_model, max_len=100):
        super().__init__()

        pe = torch.zeros(max_len, d_model)

        # 位置索引
        position = torch.arange(0, max_len).unsqueeze(1)

        # 频率项
        div_term = torch.exp(
            torch.arange(0, d_model, 2) * (-math.log(10000.0) / d_model)
        )

        # 偶数维:sin
        pe[:, 0::2] = torch.sin(position * div_term)

        # 奇数维:cos
        pe[:, 1::2] = torch.cos(position * div_term)

        pe = pe.unsqueeze(0)  # [1, max_len, d_model]

        self.register_buffer('pe', pe)

    def forward(self, x):
        """
        x: [batch_size, seq_len, d_model]
        """
        seq_len = x.size(1)
        return x + self.pe[:, :seq_len]


# 测试
x = torch.zeros(2, 5, 32)

pe = PositionalEncoding(d_model=32)

out = pe(x)

print("输出形状:", out.shape)

9. 实际意义

位置编码解决了 Transformer 的一个核心缺陷:

Attention 本身没有顺序感。

通过加入位置编码:

  • 模型可以感知顺序
  • 可以建模前后关系
  • 可以处理语言结构

这是 Transformer 能用于 NLP 的关键条件之一。


10. 核心总结

Position Encoding 的本质可以总结为:

给序列加入顺序信息,让无序模型具备"顺序感"。

它解决的问题是:

  • Attention 无法区分顺序

它带来的能力是:

  • 建模位置关系
  • 支持长序列
  • 提供结构信息

可以简单记为一句话:

Attention 负责"关系",Position Encoding 负责"顺序"。

11.3 Transformer整体流程

1. 这一节在解决什么问题

前面我们已经分别学了:

  • Attention:信息如何流动
  • Multi-Head:如何多角度建模
  • Encoder-Decoder:结构如何组织
  • Position Encoding:如何表示顺序

现在需要解决的是:

这些模块是如何组合起来,形成一个完整可工作的模型?

这一节的目标就是:

把 Transformer 从"模块理解"升级为"整体理解"。


2. 一句话理解Transformer

Transformer 的整体流程可以用一句话概括:

输入 → 加位置 → Encoder理解 → Decoder生成 → 输出结果

但这句话还太抽象,下面一步步展开。


3. 整体流程(从输入到输出)

(1)输入阶段

原始文本:

我 喜欢 AI

首先会变成:

  • 词向量(Embedding)
  • 加上位置编码(Position Encoding)

得到:

text 复制代码
带有语义 + 顺序信息的向量序列

这一阶段解决两个问题:

  • 每个词"是什么"
  • 每个词"在哪个位置"

(2)进入Encoder(理解阶段)

输入进入 Encoder(通常是多层叠加)

每一层都做:

① Self-Attention(信息交流)

② 前馈网络(信息加工)

经过多层后,每个词都会变成:

融合全局信息的表示

通俗理解:

  • 每个词已经"看懂整句话"
  • 表示中包含上下文

输出结果可以理解为:

text 复制代码
整句话的语义表示(上下文编码)

(3)进入Decoder(生成阶段)

Decoder 是一个"逐步生成"的过程。

它的输入有两部分:

(1)已经生成的内容

(2)Encoder的输出(理解结果)


(4)Decoder内部结构

每一层 Decoder 包含三步:

第一步:Masked Self-Attention

作用:

只看已经生成的内容

例如生成到第3个词时:

  • 可以看前2个词
  • 不能看后面的词

这是为了保证生成是"逐步"的。


第二步:Encoder-Decoder Attention

作用:

在生成时参考输入内容

可以理解为:

  • Encoder:提供"理解结果"
  • Decoder:不断查阅这个结果

例如翻译时:

生成"喜欢"时,会关注输入中的"love"。


第三步:前馈网络

作用:

对当前信息做非线性变换

类似 Encoder 中的 FFN,负责增强表达能力。


(5)输出阶段

Decoder 最后输出:

text 复制代码
每个词的概率分布

例如:

text 复制代码
P(我) = 0.7
P(你) = 0.2
P(他) = 0.1

然后选择概率最大的词,作为当前输出。

不断重复这个过程,直到生成结束。


4. 用一个完整例子串起来

以翻译为例:

输入:

I love AI

流程:

第一步:Embedding + 位置编码

第二步:Encoder理解 → 得到语义表示

第三步:Decoder开始生成:

  • 第1步:生成"我"
  • 第2步:基于"我",生成"喜欢"
  • 第3步:基于"我 喜欢",生成"人工智能"

整个过程:

👉 一边生成,一边参考输入


5. Transformer的核心特点

(1)完全基于Attention

Transformer 不依赖:

  • RNN(顺序处理)
  • CNN(局部卷积)

而是完全用 Attention:

直接建模全局关系


(2)并行计算能力强

Encoder 可以一次性处理整个序列:

text 复制代码
不需要一步一步循环

这使得训练速度大幅提升。


(3)长距离依赖能力强

任意两个位置之间:

都可以直接建立联系。

不像 RNN:

需要多步传递。


6. 一个极简Transformer实现

下面给你一个"最简版结构理解代码"(可运行):

python 复制代码
import torch
import torch.nn as nn

class SimpleTransformer(nn.Module):
    def __init__(self, d_model=32, num_heads=4):
        super().__init__()

        # 编码器
        self.encoder = nn.TransformerEncoder(
            nn.TransformerEncoderLayer(d_model=d_model, nhead=num_heads),
            num_layers=2
        )

        # 解码器
        self.decoder = nn.TransformerDecoder(
            nn.TransformerDecoderLayer(d_model=d_model, nhead=num_heads),
            num_layers=2
        )

        self.fc = nn.Linear(d_model, 10)

    def forward(self, src, tgt):
        """
        src: 输入序列
        tgt: 已生成序列
        """

        # Encoder
        memory = self.encoder(src)

        # Decoder
        output = self.decoder(tgt, memory)

        # 输出
        out = self.fc(output)

        return out


# 测试
src = torch.randn(5, 2, 32)  # [seq_len, batch, d_model]
tgt = torch.randn(5, 2, 32)

model = SimpleTransformer()

out = model(src, tgt)

print("输出形状:", out.shape)

7. 为什么这个结构这么重要

Transformer 的这个结构,带来了三个关键变化:

第一:统一建模方式

→ 所有任务都可以用同一套结构

第二:可扩展

→ 层数越多,能力越强

第三:成为大模型基础

→ GPT、BERT、本质都是它的变体


8. 核心总结

Transformer整体可以总结为:

Encoder负责理解,Decoder负责生成

完整流程:

  • 输入 → 编码 → 理解
  • 输出 → 逐步生成

其中最核心的机制是:

Attention驱动信息流动

整个模型的本质可以理解为:

用注意力构建一个"信息交互网络",再在这个网络上进行生成


接下来进入下一章:

第12章 大语言模型(LLM)

12.1 GPT系列(生成模型)

1. GPT在做什么

GPT 的核心任务其实非常简单:根据已有文本,预测下一个词。这个过程本身并不复杂,但当它不断重复时,就可以逐步生成完整的句子甚至文章。

例如输入一句话开头:

我今天很

模型不会去理解"情绪"这个概念,而是基于训练中学到的语言规律,去计算在这种语境下哪个词最可能出现。它可能认为"开心"出现的概率更高,于是生成:

我今天很开心

接着,它再基于"我今天很开心"继续预测下一个词。这个过程不断循环,最终形成一段完整文本。从本质上看,GPT 并不是在写作,而是在进行连续的概率预测。


2. 一种更直观的理解方式

可以把 GPT 理解为一个能力非常强的自动补全系统。当你输入一句话的开头时,它会根据过去见过的大量文本,去判断这个句子通常会如何继续。

例如输入:

我喜欢

模型并不会分析"喜欢"的情感含义,而是会去匹配类似表达在数据中的出现方式,从而推断"我喜欢"后面通常接什么。它可能生成:

我喜欢学习

随后再继续补全:

我喜欢学习人工智能

这个过程并不是整体规划出来的,而是一步一步延续出来的。模型每次只做一个局部决策,但由于这种决策足够准确,最终就能形成结构合理的文本。


3. 数学本质

GPT 的训练目标可以用下面这个公式表示:
P ( x 1 , x 2 , . . . , x n ) = ∏ t = 1 n P ( x t ∣ x 1 , . . . , x t − 1 ) P(x_1, x_2, ..., x_n) = \prod_{t=1}^{n} P(x_t \mid x_1, ..., x_{t-1}) P(x1,x2,...,xn)=t=1∏nP(xt∣x1,...,xt−1)

这个公式表达的含义是,一句话的生成过程可以拆解为多个连续步骤:先生成第一个词,然后基于第一个词生成第二个词,再基于前两个词生成第三个词,之后不断向后递推,直到整句话完成。

因此,模型在每一步只解决一个问题,就是在当前已有上下文的条件下,下一个词最可能是什么。整个语言生成能力,其实就是这种"局部预测"不断叠加的结果。


4. GPT和Transformer的关系

GPT 并不是一个全新的模型结构,它本质上是 Transformer 的一个特定使用方式。更准确地说,它只使用了 Transformer 中的 Decoder 部分。

这样设计的原因在于,生成任务本身就是从左到右逐步展开的过程,并不需要像 Encoder 那样进行双向理解。因此 GPT 的结构具有明显特点:只能看到前面的内容,并且一步步向后生成。

这种结构使得模型非常适合处理写作、对话、代码生成等任务,因为这些任务本身就是顺序展开的。


5. 为什么必须限制"看未来"

在训练 GPT 时,有一个非常关键的约束条件,就是模型不能看到未来的词。

例如在处理句子:

我今天很开心

如果模型在预测"开心"时已经提前看到了这个词,那么训练就变成了简单的"复制答案",模型无法真正学到语言规律。

因此在 Attention 中必须加入限制,使得每个位置只能访问它之前的内容。这种机制保证了模型在训练时的行为和实际生成时保持一致,也让每一步预测都具有真实意义。


6. GPT是如何学会语言的

GPT 并不会学习传统意义上的语法规则或逻辑推理,它的能力来自于对大量文本数据的统计学习。

在训练过程中,模型会逐渐掌握:

哪些词经常一起出现,哪些表达更符合语言习惯,以及不同上下文中常见的句子结构。随着数据规模和模型规模的不断扩大,这种统计能力会变得越来越强。

最终表现出来的效果是,模型生成的内容看起来像是经过理解和思考,但本质上仍然是基于概率的预测。


7. 为什么GPT可以写文章

当模型足够大时,它不仅学到了词之间的关系,还学到了更高层次的结构信息。例如句子如何衔接,段落如何展开,以及不同类型文本的表达方式。

因此它可以生成连贯的句子,组织合理的段落,甚至模仿特定风格进行写作。

需要注意的是,这种能力并不是来自"理解世界",而是来自对大量文本模式的学习。模型并没有真正的思考过程,它只是把预测能力发挥到了极致。


8. 一个简单生成过程

给定一句开头:

人工智能的发展

模型会先预测下一个词,例如"非常迅速",然后再基于这个结果继续预测后续内容,例如"对社会产生了深远影响"。这个过程会不断重复,直到生成完整文本。

整个过程中,模型不会回头修改已经生成的内容,也不会提前规划全文结构,而是始终基于当前上下文做出最优预测。


9. 一个最小GPT实现(简化版)

下面是一个简化版 GPT 结构代码,可以直接运行,用于理解其核心机制:

python 复制代码
import torch
import torch.nn as nn

class MiniGPT(nn.Module):
    def __init__(self, vocab_size=100, d_model=32, num_heads=4):
        super().__init__()

        self.embedding = nn.Embedding(vocab_size, d_model)

        self.decoder_layer = nn.TransformerDecoderLayer(
            d_model=d_model,
            nhead=num_heads
        )
        self.decoder = nn.TransformerDecoder(self.decoder_layer, num_layers=2)

        self.fc = nn.Linear(d_model, vocab_size)

    def forward(self, x):
        emb = self.embedding(x)

        seq_len = x.size(0)

        mask = torch.triu(torch.ones(seq_len, seq_len), diagonal=1).bool()

        out = self.decoder(emb, emb, tgt_mask=mask)

        logits = self.fc(out)

        return logits


x = torch.randint(0, 100, (5, 2))

model = MiniGPT()

out = model(x)

print("输出形状:", out.shape)

10. 本节核心总结

GPT 的核心思想可以概括为:通过不断预测下一个词,逐步构建完整文本。它基于 Transformer 的 Decoder 结构,采用自回归方式进行生成,并通过 Mask 机制保证预测过程的合理性。

可以用一句话总结:

GPT 是一个基于注意力机制的自回归语言生成模型。

12.2 BERT(理解)

1. BERT在做什么

如果说 GPT 的目标是"生成文本",那么 BERT 的目标就是:

理解文本。

它不会去预测"下一个词是什么",而是试图理解一句话中每个词的含义,以及它们之间的关系。

例如一句话:

我在银行工作

这里的"银行"可能表示金融机构,也可能表示河岸。

BERT 的作用就是根据上下文判断:这里的"银行"到底是什么意思。

因此,它更擅长的任务是:

  • 分类
  • 判断
  • 信息抽取
  • 语义理解

而不是生成内容。


2. 和GPT最核心的区别

GPT 是从左到右逐步生成的模型,而 BERT 的最大特点是:

它可以同时看到整个句子。

例如:

我喜欢这个电影,因为它很精彩

在理解"精彩"时,BERT 不仅可以看前面的"电影",还可以看后面的内容。

这意味着:

它的理解是"全局的",而不是"单向的"。

换句话说:

GPT 是一边读一边写,

BERT 是一次性把整句话读完再理解。


3. 数学本质(核心目标)

BERT 的核心训练任务之一是 Masked Language Model(掩码语言模型):
P ( x i ∣ x 1 , . . . , x i − 1 , x i + 1 , . . . , x n ) P(x_i \mid x_1, ..., x_{i-1}, x_{i+1}, ..., x_n) P(xi∣x1,...,xi−1,xi+1,...,xn)

这个公式表示:

模型在预测某个词时,可以利用它前后的所有上下文信息。

也就是说:

不是预测"下一个词",而是预测"被遮住的词"。


4. Mask机制的不同

GPT 的 Mask 是:

遮住未来

而 BERT 的 Mask 是:

随机遮住部分词

例如:

我喜欢[MASK]电影

模型需要预测:

精彩

这种训练方式的意义在于:

模型必须理解整个句子,而不是依赖局部信息。


5. BERT是如何理解语言的

BERT 的训练过程,本质是在不断学习:

一个词在不同上下文中的含义变化。

例如"苹果":

  • 在"我吃了一个苹果"中是水果
  • 在"苹果发布了新产品"中是公司

通过大量数据训练,模型逐渐学会:

根据上下文动态调整词的表示。

这也是它比传统词向量(如Word2Vec)更强的原因。


6. 为什么BERT不能直接写文章

BERT 虽然理解能力很强,但它不适合生成任务。

原因在于:

它的训练方式不是"从左到右生成",而是"填空"。

它并不知道:

下一步应该写什么,只知道"这个位置最合理的词是什么"。

因此:

  • GPT 擅长写作
  • BERT 擅长理解

这是由训练目标决定的,而不是模型大小。


7. 一个简单理解例子

句子:

这部电影非常[MASK]

BERT 会根据上下文判断:

最可能的词是"好看"或"精彩"。

这里它不是在"写句子",而是在做:

语义补全。

这种能力使它在很多任务中表现很好,例如:

情感分析、文本分类、问答系统等。


8. 一个最小BERT实现(简化版)

下面是一个简化版 BERT 编码结构,用来理解其核心机制:

python 复制代码
import torch
import torch.nn as nn

class MiniBERT(nn.Module):
    def __init__(self, vocab_size=100, d_model=32, num_heads=4):
        super().__init__()

        # 词向量
        self.embedding = nn.Embedding(vocab_size, d_model)

        # Encoder结构
        self.encoder_layer = nn.TransformerEncoderLayer(
            d_model=d_model,
            nhead=num_heads
        )
        self.encoder = nn.TransformerEncoder(self.encoder_layer, num_layers=2)

        # 输出层(预测词)
        self.fc = nn.Linear(d_model, vocab_size)

    def forward(self, x):
        """
        x: [seq_len, batch_size]
        """

        emb = self.embedding(x)

        # 编码(双向注意力)
        out = self.encoder(emb)

        logits = self.fc(out)

        return logits


# 测试
x = torch.randint(0, 100, (5, 2))

model = MiniBERT()

out = model(x)

print("输出形状:", out.shape)

9. GPT vs BERT(关键区别)

可以从本质上这样理解两者:

GPT 是顺序生成模型,它关注的是"接下来写什么";

BERT 是上下文理解模型,它关注的是"这句话是什么意思"。

两者的差异来自三个方面:

第一,信息流方向不同。GPT 是单向的,而 BERT 是双向的。

第二,训练目标不同。GPT 预测下一个词,BERT 预测被遮住的词。

第三,应用场景不同。GPT 更适合生成任务,BERT 更适合理解任务。


10. 本节核心总结

BERT 的核心可以总结为:

它通过双向上下文建模,实现对语言的深度理解。

相比 GPT,它不擅长生成,但在理解类任务中更有优势。

可以用一句话概括:

BERT 是一个基于双向注意力的语言理解模型。

12.3 Prompt Engineering

1. Prompt在做什么

在使用大模型时,我们表面上是在"提问",但本质上是在设计输入结构。这个输入就是 Prompt。

模型的输出并不是完全随机生成的,而是严格依赖于输入条件的结果。换句话说,模型并不会主动理解你的真实意图,它只能根据你提供的 Prompt 去推测你想要什么。

因此可以这样理解:

Prompt 并不是一句普通的话,而是模型行为的"控制信号"。

同一个模型,如果 Prompt 不同,输出结果可能完全不同。这种差异,往往比模型本身的差异还要大。


2. 为什么一句话能改变结果

来看一个非常直观的变化。

当输入是:

什么是注意力机制

模型通常会给出一个比较泛化的解释,内容可能正确,但结构松散。

如果换成:

请用通俗语言分三段解释注意力机制,并给出一个生活中的类比

模型输出会明显变得更清晰,结构更稳定,表达更符合阅读习惯。

这里并没有改变模型,只是改变了输入方式。

但结果却发生了明显变化。

这说明一个核心问题:

你不是在问问题,而是在定义输出的形态


3. Prompt的数学本质

从模型角度看,大语言模型始终在做一件事:
P ( 输出 ∣ 输入 ) P(\text{输出} \mid \text{输入}) P(输出∣输入)

这里的"输入",就是 Prompt。

也就是说,Prompt 决定了条件概率的范围。不同的输入,会让模型在不同的"可能答案空间"中进行选择。

因此可以理解为:

Prompt 并不是描述问题,而是在限定答案的生成路径


4. Prompt如何影响模型行为

Prompt 的作用,不只是提供信息,更是在约束模型。

首先,它决定模型如何理解任务。模型需要通过输入判断你是在做解释、分类,还是生成内容。如果表达不清,模型就会走偏。

其次,它会影响输出形式。是否需要结构化表达,是否需要代码,是否需要分段,这些都可以通过 Prompt 明确。

更关键的是,它会影响推理方式。不同的表达,会让模型走不同的推理路径,从而得到完全不同的结果。

换句话说:

Prompt 的本质,是在不断缩小模型的"自由度"。


5. Prompt为什么可以"变强"

随着模型规模的提升,一个重要现象开始出现:

模型本身已经具备大量潜在能力,但这些能力是否能被激发,取决于输入方式。

当 Prompt 设计得足够清晰时,模型更容易进入正确的输出轨道;当 Prompt 模糊时,模型会在多个可能方向中摇摆。

因此,一个好的 Prompt,其实是在做一件事情:

让模型"少走弯路"。


6. Chain-of-Thought(思维链)

在 Prompt 设计中,有一个非常重要的技巧,叫做 Chain-of-Thought。

它的核心思路不是让模型直接给出答案,而是引导模型一步一步展开推理。

例如一个简单问题:

23 × 17 等于多少

模型可能直接给出结果,但不一定稳定。

如果改成:

请一步一步计算 23 × 17,并给出中间过程

模型会先拆分问题,再逐步计算,最后得到结果。

这种方式的关键在于:

模型被引导进入"推理模式",而不是"猜答案模式"。

在复杂任务中,这种方法往往能显著提升准确率。


7. 一个实际应用变化

来看一个更贴近实际的例子。

任务是生成健康建议。

如果输入:

给我一些健康建议

模型通常会给出比较泛泛的回答,内容缺乏针对性。

如果改为:

请针对大学生作息,生成5条具体可执行的健康建议,每条不少于20字,并包含运动和饮食两个方面

输出会明显发生变化,建议更具体,结构更清晰,也更容易落地。

这个变化并不是模型变强了,而是输入更精确了。


8. Prompt在产品中的作用

在实际产品开发中,Prompt 并不是一个"辅助工具",而是核心能力的一部分。

它直接影响:

输出是否稳定,结果是否符合预期,以及用户体验是否一致。

在很多 AI 产品中,功能的好坏并不取决于模型大小,而取决于 Prompt 设计是否合理。

因此可以说:

Prompt 是连接"模型能力"和"用户需求"的关键桥梁。


9. 一个简单代码示例

下面是一个基础调用示例,可以直观看到 Prompt 的作用:

python 复制代码
from openai import OpenAI

client = OpenAI()

prompt = "请用通俗语言解释什么是Transformer,并用一个生活中的例子说明"

response = client.chat.completions.create(
    model="gpt-4.1-mini",
    messages=[
        {"role": "user", "content": prompt}
    ]
)

print(response.choices[0].message.content)

只需要修改 prompt 的内容,就可以明显改变模型输出的风格和结构。


10. 本节核心总结

Prompt Engineering 的本质,不是提问技巧,而是输入设计能力。

它通过改变输入,控制模型的输出范围、表达方式和推理路径,从而让模型更稳定地完成任务。

可以用一句话概括:

Prompt 是对模型行为的显式控制方式。


12.4 Fine-tuning(模型微调)

1. 为什么需要Fine-tuning

在很多场景下,仅仅通过 Prompt 已经可以完成大部分任务。但当需求变得更复杂时,会出现一个问题:

模型"能理解",但"不稳定"。

例如:

同样的输入,有时候回答很好,有时候偏离目标;

或者输出风格不统一,难以在产品中长期使用。

这时就会发现一个限制:

Prompt 只能"引导模型",但不能从根本上改变模型能力。

因此需要一种更深层的方法,让模型在特定任务上表现更稳定,这就是 Fine-tuning。


2. Fine-tuning在做什么

Fine-tuning 的本质,是在已有大模型基础上,继续用特定数据进行训练。

它不是从头训练模型,而是:

在已有能力之上,进行"定向强化"。

可以这样理解:

大模型已经学会了"语言",

而 Fine-tuning 是让它学会"特定领域的表达方式"。

例如:

  • 医疗问答
  • 法律文本分析
  • 产品客服回复

通过针对性数据训练后,模型会更倾向输出符合该领域风格的内容。


3. 数学本质

Fine-tuning 本质上仍然是在优化模型参数,使预测更符合目标数据分布:
θ ∗ = arg ⁡ max ⁡ θ ∑ ( x , y ) log ⁡ P θ ( y ∣ x ) \theta^* = \arg\max_\theta \sum_{(x,y)} \log P_\theta(y \mid x) θ∗=argθmax(x,y)∑logPθ(y∣x)

这个公式表示:

通过不断调整参数,使模型在输入 (x) 时,更容易输出目标结果 (y)。

换句话说:

模型原本的概率分布被"重新拉向"特定任务。


4. 和Prompt的区别

Prompt 和 Fine-tuning 解决的是两个不同层面的问题。

Prompt 是在输入层控制模型行为,它不改变模型本身,只是引导输出方向。

Fine-tuning 是在模型层改变参数,使模型在特定任务上形成"偏好"。

因此可以这样理解:

Prompt 是"短期控制",

Fine-tuning 是"长期改变"。

在实际应用中,两者往往结合使用。


5. Fine-tuning带来的变化

经过 Fine-tuning 后,模型会发生几个明显变化。

首先,输出更加稳定。同样输入,不会出现大幅波动。

其次,风格更加统一。模型会倾向于使用训练数据中的表达方式。

更重要的是,对特定任务的理解更强。例如客服场景中,模型会更准确识别用户意图。

这些变化,使模型更适合在真实产品中使用。


6. 一个实际应用场景

以智能客服为例。

如果只用 Prompt:

模型可能回答得不错,但风格不统一,有时偏离业务规范。

如果使用 Fine-tuning:

可以用历史客服对话数据进行训练,使模型输出更加符合企业要求。

例如:

  • 语气统一
  • 回答规范
  • 避免不合适表达

这样模型就从"通用助手",变成"专用客服"。


7. 一个简单微调示意代码

下面是一个简化的训练示例,用于理解 Fine-tuning 的基本流程:

python 复制代码
import torch
import torch.nn as nn
import torch.optim as optim

# 简化模型
model = nn.Linear(10, 2)

# 假数据(输入x,对应标签y)
x = torch.randn(100, 10)
y = torch.randint(0, 2, (100,))

# 损失函数和优化器
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)

# 训练过程
for epoch in range(10):
    outputs = model(x)
    loss = criterion(outputs, y)

    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

    print(f"Epoch {epoch}, Loss: {loss.item():.4f}")

这个过程本质上就是:

不断调整模型参数,让输出更接近目标结果。


8. Fine-tuning的局限

虽然 Fine-tuning 很强,但也存在一些问题。

首先,成本较高。需要数据、算力和时间。

其次,数据质量非常关键。如果数据不好,模型反而会变差。

另外,一旦微调完成,模型会更偏向某个任务,通用能力可能下降。

因此在实际使用中,需要权衡是否真的需要微调。


9. 什么时候该用Fine-tuning

当出现以下情况时,通常需要考虑使用 Fine-tuning:

模型输出不稳定,难以通过 Prompt 修复;

需要长期保持固定风格;

任务具有明显领域特征,例如医疗、金融等。

如果只是简单优化输出格式,一般使用 Prompt 就足够。


10. 本节核心总结

Fine-tuning 的核心,是通过调整模型参数,让模型在特定任务上表现更稳定、更符合需求。

它不是替代 Prompt,而是对 Prompt 的补充。

可以用一句话概括:

Fine-tuning 是对模型能力的定向强化。


第13章 大模型训练技术

13.1 RLHF(人类反馈强化学习)

1. RLHF在解决什么问题

当模型规模越来越大时,会出现一个明显问题:

模型"会说话",但不一定"说得对"。

例如:

回答可能逻辑通顺,但不符合人类习惯;

或者语气不合适,甚至出现偏差内容。

这说明一个问题:

模型优化的是"概率正确",而不是"人类满意"。

RLHF 的出现,就是为了弥补这一点。


2. RLHF在做什么

RLHF 的核心思想是:

让模型的输出,更符合人类偏好。

它不是单纯依赖数据训练,而是引入"人类评价"。

可以这样理解:

模型先生成多个答案,然后由人类判断哪个更好,

再用这些评价去反向优化模型。

本质上是:

把"人类标准"加入训练过程。


3. 数学本质

RLHF 可以看作是在最大化奖励函数:
max ⁡ θ E y ∼ P θ ( ⋅ ∣ x ) [ R ( x , y ) ] \max_\theta \mathbb{E}{y \sim P\theta(\cdot \mid x)} [R(x, y)] θmaxEy∼Pθ(⋅∣x)[R(x,y)]

这里的 (R(x, y)) 表示人类对结果的评分。

也就是说:

模型不再只追求概率最大,而是追求"评分最高"。


4. RLHF的三步流程

整个过程可以理解为三个阶段。

首先是监督微调,让模型具备基础能力;

然后训练奖励模型,用来模拟人类打分;

最后通过强化学习,让模型不断优化输出。

这三个步骤结合起来,使模型逐渐向"人类偏好"靠近。


5. 一个直观例子

假设模型回答问题:

如何提高学习效率

模型可能给出多个版本。

人类会选择:

更清晰、更具体、更有逻辑的那个。

经过大量这样的反馈,模型就会逐渐学会:

什么样的回答更"好"。


6. RLHF带来的变化

引入 RLHF 后,模型会发生明显变化。

回答更自然,更符合人类表达习惯;

逻辑更清晰,更有层次;

不合适内容减少。

这些变化,使模型从"会说话"变成"会交流"。


7. 简单强化学习示意代码

下面是一个简化示例,用来理解强化学习更新过程:

python 复制代码
import torch

# 假设模型输出概率
log_probs = torch.tensor([0.2, 0.5, 0.3], requires_grad=True)

# 假设奖励(人类反馈)
reward = torch.tensor([1.0, 2.0, 0.5])

# 强化学习目标(简单形式)
loss = - (log_probs * reward).mean()

loss.backward()

print("梯度:", log_probs.grad)

这个过程本质上是在:

让高奖励的输出更容易被模型选择。


8. RLHF的意义

RLHF 的最大价值在于:

它让模型从"数据驱动"转变为"人类驱动"。

模型不再只是模仿文本,而是逐渐学会:

什么是更符合人类期望的表达。


9. 本节核心总结

RLHF 的核心可以总结为:

通过引入人类反馈,让模型输出更加符合人类标准。

可以用一句话概括:

RLHF = 用人类偏好重新塑造模型行为。

13.2 LoRA / PEFT

1. 为什么需要高效微调

在实际应用中,Fine-tuning 虽然有效,但会遇到一个非常现实的问题:

成本太高。

大模型参数规模通常在亿级甚至百亿级,如果对整个模型进行微调,需要:

大量显存、较长训练时间,以及较高的工程复杂度。

更重要的是,每一个任务都单独微调一份完整模型,在实际系统中几乎不可维护。

因此就产生了一个核心需求:

能不能只改一小部分参数,就达到类似效果?

这就是 LoRA 和 PEFT 出现的背景。


2. PEFT在做什么

PEFT(Parameter Efficient Fine-Tuning)的核心思想是:

不改变大模型主体,只调整少量参数。

可以理解为:

模型的大部分能力已经足够强,不需要重新学习,只需要在关键位置进行轻量调整。

这种方式有两个直接好处:

一是训练成本大幅下降,二是可以快速适配多个任务。

因此在工业界中,PEFT 已经成为主流方案。


3. LoRA的核心思想

LoRA 是 PEFT 中最常用的一种方法,它的思路非常巧妙。

在原始模型中,一个线性层通常表示为:
W x W x Wx

LoRA 并不会直接修改 (W),而是引入一个"增量矩阵":
W ′ = W + A B W' = W + A B W′=W+AB

其中 (A) 和 (B) 是低秩矩阵,维度远小于原始参数。

这意味着:

模型的大部分参数保持不变,只额外学习一个小的"调整项"。

从效果上看,相当于对模型进行微调;

但从计算上看,成本却大幅降低。


4. 为什么LoRA有效

LoRA 能起作用的关键在于一个假设:

模型的更新不需要覆盖整个参数空间。

很多任务的差异,其实只需要在少量方向上进行调整,就可以完成适配。

低秩矩阵 (A B) 正好提供了这种"有限调整能力"。

可以这样理解:

原模型已经掌握了通用知识,而 LoRA 只是在某些方向上进行"微调校正"。


5. 一个直观理解

可以把大模型想象成一个已经写好的系统。

传统 Fine-tuning 是:

直接修改整个系统代码。

而 LoRA 更像是:

在系统外加一个"插件",通过少量修改改变整体行为。

这种方式不仅更轻量,而且更安全,不会破坏原始能力。


6. LoRA带来的优势

使用 LoRA 后,会带来几个明显优势。

训练成本显著降低,因为只需要训练小规模参数;

显存占用减少,可以在普通设备上运行;

模型复用性增强,可以针对不同任务加载不同 LoRA 权重。

这使得一个基础模型可以支持多个应用场景,而不需要重复训练。


7. 一个简单LoRA示意代码

下面是一个简化版本,用来理解 LoRA 的结构:

python 复制代码
import torch
import torch.nn as nn

class LoRALinear(nn.Module):
    def __init__(self, in_features, out_features, rank=2):
        super().__init__()

        # 原始权重(冻结)
        self.weight = nn.Linear(in_features, out_features)
        for param in self.weight.parameters():
            param.requires_grad = False

        # LoRA参数
        self.A = nn.Linear(in_features, rank, bias=False)
        self.B = nn.Linear(rank, out_features, bias=False)

    def forward(self, x):
        original = self.weight(x)
        lora_update = self.B(self.A(x))
        return original + lora_update


# 测试
x = torch.randn(4, 10)

model = LoRALinear(10, 5)

out = model(x)

print("输出形状:", out.shape)

这个结构体现了核心思想:

原始模型不动,只叠加一个可训练的低秩变化。


8. LoRA的应用场景

在实际项目中,LoRA 非常适合以下场景。

当需要快速适配多个业务任务时,可以为每个任务训练独立 LoRA;

当算力资源有限时,可以在较低成本下完成微调;

当需要保持基础模型能力时,可以避免过度修改模型参数。

因此,它在 AI 产品开发中非常常见。


9. 本节核心总结

LoRA 和 PEFT 的核心思想,是用最小的参数调整,实现最大的效果变化。

它不追求"重新训练模型",而是:

在已有能力基础上进行轻量优化。

可以用一句话概括:

LoRA = 用低成本实现高效微调。

13.3 模型蒸馏

继续保持完全一致风格👇


第13章 大模型训练技术

13.3 模型蒸馏(Model Distillation)

1. 为什么需要模型蒸馏

大模型的能力很强,但在实际使用中会遇到一个现实问题:

太大、太慢、成本太高。

例如,在服务器上运行还可以接受,但如果要部署到移动端、网页端,或者需要高并发服务时,大模型的计算开销会变得不可承受。

这就带来一个核心问题:

能不能保留大模型的能力,同时让模型变小、变快?

模型蒸馏正是为了解决这个问题。


2. 模型蒸馏在做什么

模型蒸馏的核心思想是:

用一个大模型去"教"一个小模型。

大模型被称为 Teacher(教师模型),

小模型被称为 Student(学生模型)。

训练时,小模型不仅学习真实数据,还会学习大模型的输出结果。

可以理解为:

不是直接学答案,而是学"老师是怎么判断的"。


3. 数学本质

蒸馏的核心,是让学生模型去拟合教师模型的输出分布:

latex 复制代码
L = \alpha L_{\text{真实标签}} + (1 - \alpha) L_{\text{蒸馏}}

其中蒸馏损失通常表示为:

latex 复制代码
L_{\text{蒸馏}} = KL(p_{\text{teacher}} \parallel p_{\text{student}})

这表示:

学生模型不仅要接近真实答案,还要接近教师模型的"概率分布"。

这种分布中包含了更多信息,例如哪些选项更接近正确答案。


4. 为什么蒸馏有效

传统训练中,模型只知道"正确答案是什么"。

但在蒸馏中,模型还能学到:

不同类别之间的"相似程度"。

例如一个分类任务中:

正确答案是"猫",但教师模型可能给出:

  • 猫:0.8
  • 狗:0.15
  • 车:0.05

学生模型通过学习这个分布,可以理解:

"狗"比"车"更接近"猫"。

这种信息,被称为"软标签",它比单一标签更有价值。


5. 一个直观理解

可以把蒸馏理解为学习方式的变化。

传统训练更像是:

老师只告诉你答案对不对。

而蒸馏更像是:

老师告诉你为什么这个答案更合理,以及其他选项差在哪里。

因此学生模型不仅学结果,还学判断过程。


6. 蒸馏带来的变化

经过蒸馏后,小模型通常会表现出明显提升。

相比直接训练的小模型,它的效果更接近大模型;

推理速度更快,资源消耗更低;

在实际部署中更加灵活。

这种方式,使得"强能力 + 低成本"成为可能。


7. 一个简单蒸馏示意代码

下面是一个简化版本,用来理解蒸馏过程:

python 复制代码
import torch
import torch.nn.functional as F

# teacher输出(已经训练好)
teacher_logits = torch.tensor([[2.0, 1.0, 0.1]])

# student输出
student_logits = torch.tensor([[1.5, 0.8, 0.3]], requires_grad=True)

# 转为概率分布
teacher_probs = F.softmax(teacher_logits, dim=1)
student_log_probs = F.log_softmax(student_logits, dim=1)

# KL散度(蒸馏损失)
loss = F.kl_div(student_log_probs, teacher_probs, reduction='batchmean')

loss.backward()

print("梯度:", student_logits.grad)

这个过程的核心在于:

学生模型通过模仿教师模型的输出分布,不断逼近其能力。


8. 蒸馏的应用场景

在实际项目中,模型蒸馏非常常见。

当需要部署到移动端或边缘设备时,可以用蒸馏得到轻量模型;

在高并发服务中,可以用小模型替代大模型以降低成本;

在多模型系统中,可以用蒸馏统一模型表现。

因此,它是从"研究模型"走向"工程落地"的关键技术之一。


9. 本节核心总结

模型蒸馏的核心思想,是通过教师模型指导学生模型训练,使小模型获得接近大模型的能力。

它实现了一个重要目标:

在降低计算成本的同时,尽量保持性能。

可以用一句话概括:

模型蒸馏 = 用大模型指导小模型学习。


至此,这一部分完成了核心闭环:

  • RLHF 解决"符合人类"
  • LoRA 解决"高效微调"
  • 蒸馏解决"模型变小"

好,这一部分我给你做一个真正"能写进博客/申报书"的总结

  • 不罗列碎点
  • 有结构但不死板
  • 有概念、有逻辑、有理解

直接可用👇


系列三总结:Transformer与大模型(第10章---第13章)

1. 从Attention到理解与生成

从第10章开始,整个体系的核心建立在一个关键思想上:

模型不再"逐个处理信息",而是"动态关注重要信息"。

Attention 机制本质上是在做一件事:

在当前任务中,判断"哪些信息更重要"。

Scaled Dot-Product Attention 通过相似度计算,让模型自动选择关注对象;

Multi-Head Attention 则进一步扩展,让模型可以从多个角度同时理解信息,例如语义关系、位置关系和上下文关联。

这一阶段的关键变化在于:

模型从"固定计算流程",转变为"动态信息选择"。


2. Transformer:统一的建模框架

第11章将 Attention 上升为完整结构,形成 Transformer。

Transformer 的核心突破,不在于某一个公式,而在于整体设计:

它完全抛弃了传统的 RNN 顺序结构,转而使用 Attention 实现全局建模。

Position Encoding 的引入,使模型在没有顺序结构的情况下,仍然可以理解"先后关系";

Encoder-Decoder 结构,则分别承担"理解"和"生成"的角色。

这一阶段的本质是:

把"信息选择机制"升级为"统一建模框架"。

Transformer 不再是一个技巧,而成为后续所有大模型的基础架构。


3. GPT与BERT:两条分化路径

进入第12章后,模型开始沿着两个方向发展:

一个是生成,一个是理解。

GPT 采用单向结构,通过自回归方式逐步生成文本,本质是连续的概率预测过程;

BERT 则采用双向结构,通过 Mask 训练,实现对上下文的整体理解。

两者的差异,并不是能力强弱,而是目标不同:

GPT 关注"接下来写什么",

BERT 关注"这句话是什么意思"。

这一阶段的关键认知是:

模型能力由训练目标决定,而不是结构本身。


4. Prompt:从"用模型"到"控制模型"

随着大模型能力增强,一个重要变化出现:

模型本身已经很强,但如何使用它,变得更加关键。

Prompt Engineering 的出现,使人可以通过输入设计,直接影响模型输出。

模型不再只是工具,而变成一种"可被引导的系统"。

不同的 Prompt,可以改变任务理解、输出格式,甚至推理路径。

这一阶段的核心转变是:

人与模型的关系,从"调用工具"变为"控制行为"。


5. Fine-tuning与参数控制

当 Prompt 无法满足需求时,就需要进一步深入模型层。

Fine-tuning 通过调整模型参数,使其在特定任务上更加稳定;

LoRA 和 PEFT 则进一步优化,使这种调整变得高效、低成本。

这一阶段解决的是:

如何在不破坏原有能力的情况下,让模型适应具体应用。

可以理解为:

从"临时控制"走向"长期能力塑造"。


6. RLHF:引入人类标准

在模型能力不断增强后,一个新的问题出现:

模型的输出是否符合人类预期。

RLHF 的核心,是把"人类评价"引入训练过程,使模型优化目标从"数据概率"转向"人类偏好"。

这一阶段的关键变化在于:

模型不再只是模仿数据,而开始对齐人类标准。


7. 模型蒸馏:走向实际落地

当模型能力、控制方式都具备之后,最后一个问题是:

如何真正落地使用。

模型蒸馏通过"教师---学生"机制,使小模型获得接近大模型的能力,从而降低计算成本,提高部署效率。

这一阶段解决的是:

从"能用"走向"可规模化使用"。


8. 整体核心逻辑

从第10章到第13章,其实形成了一条非常清晰的技术演进路径:

从 Attention 的信息选择机制出发,构建 Transformer 框架;

在此基础上分化出 GPT(生成)与 BERT(理解);

再通过 Prompt 实现对模型行为的直接控制;

进一步通过 Fine-tuning 和 LoRA 调整模型能力;

引入 RLHF 使模型符合人类偏好;

最后通过蒸馏实现工程落地。

这条路径可以总结为一个闭环:

建模能力 → 行为控制 → 能力优化 → 人类对齐 → 工程落地


9. 一句话总总结

整个系列可以用一句话概括:

Transformer提供结构,GPT/BERT定义能力,Prompt负责控制,Fine-tuning与RLHF优化行为,蒸馏实现落地。

模型通常会表现出明显提升。

相比直接训练的小模型,它的效果更接近大模型;

推理速度更快,资源消耗更低;

在实际部署中更加灵活。

这种方式,使得"强能力 + 低成本"成为可能。


7. 一个简单蒸馏示意代码

下面是一个简化版本,用来理解蒸馏过程:

python 复制代码
import torch
import torch.nn.functional as F

# teacher输出(已经训练好)
teacher_logits = torch.tensor([[2.0, 1.0, 0.1]])

# student输出
student_logits = torch.tensor([[1.5, 0.8, 0.3]], requires_grad=True)

# 转为概率分布
teacher_probs = F.softmax(teacher_logits, dim=1)
student_log_probs = F.log_softmax(student_logits, dim=1)

# KL散度(蒸馏损失)
loss = F.kl_div(student_log_probs, teacher_probs, reduction='batchmean')

loss.backward()

print("梯度:", student_logits.grad)

这个过程的核心在于:

学生模型通过模仿教师模型的输出分布,不断逼近其能力。


8. 蒸馏的应用场景

在实际项目中,模型蒸馏非常常见。

当需要部署到移动端或边缘设备时,可以用蒸馏得到轻量模型;

在高并发服务中,可以用小模型替代大模型以降低成本;

在多模型系统中,可以用蒸馏统一模型表现。

因此,它是从"研究模型"走向"工程落地"的关键技术之一。


9. 本节核心总结

模型蒸馏的核心思想,是通过教师模型指导学生模型训练,使小模型获得接近大模型的能力。

它实现了一个重要目标:

在降低计算成本的同时,尽量保持性能。

可以用一句话概括:

模型蒸馏 = 用大模型指导小模型学习。


至此,这一部分完成了核心闭环:

  • RLHF 解决"符合人类"
  • LoRA 解决"高效微调"
  • 蒸馏解决"模型变小"

好,这一部分我给你做一个真正"能写进博客/申报书"的总结

  • 不罗列碎点
  • 有结构但不死板
  • 有概念、有逻辑、有理解

直接可用👇


系列三总结:Transformer与大模型(第10章---第13章)

1. 从Attention到理解与生成

从第10章开始,整个体系的核心建立在一个关键思想上:

模型不再"逐个处理信息",而是"动态关注重要信息"。

Attention 机制本质上是在做一件事:

在当前任务中,判断"哪些信息更重要"。

Scaled Dot-Product Attention 通过相似度计算,让模型自动选择关注对象;

Multi-Head Attention 则进一步扩展,让模型可以从多个角度同时理解信息,例如语义关系、位置关系和上下文关联。

这一阶段的关键变化在于:

模型从"固定计算流程",转变为"动态信息选择"。


2. Transformer:统一的建模框架

第11章将 Attention 上升为完整结构,形成 Transformer。

Transformer 的核心突破,不在于某一个公式,而在于整体设计:

它完全抛弃了传统的 RNN 顺序结构,转而使用 Attention 实现全局建模。

Position Encoding 的引入,使模型在没有顺序结构的情况下,仍然可以理解"先后关系";

Encoder-Decoder 结构,则分别承担"理解"和"生成"的角色。

这一阶段的本质是:

把"信息选择机制"升级为"统一建模框架"。

Transformer 不再是一个技巧,而成为后续所有大模型的基础架构。


3. GPT与BERT:两条分化路径

进入第12章后,模型开始沿着两个方向发展:

一个是生成,一个是理解。

GPT 采用单向结构,通过自回归方式逐步生成文本,本质是连续的概率预测过程;

BERT 则采用双向结构,通过 Mask 训练,实现对上下文的整体理解。

两者的差异,并不是能力强弱,而是目标不同:

GPT 关注"接下来写什么",

BERT 关注"这句话是什么意思"。

这一阶段的关键认知是:

模型能力由训练目标决定,而不是结构本身。


4. Prompt:从"用模型"到"控制模型"

随着大模型能力增强,一个重要变化出现:

模型本身已经很强,但如何使用它,变得更加关键。

Prompt Engineering 的出现,使人可以通过输入设计,直接影响模型输出。

模型不再只是工具,而变成一种"可被引导的系统"。

不同的 Prompt,可以改变任务理解、输出格式,甚至推理路径。

这一阶段的核心转变是:

人与模型的关系,从"调用工具"变为"控制行为"。


5. Fine-tuning与参数控制

当 Prompt 无法满足需求时,就需要进一步深入模型层。

Fine-tuning 通过调整模型参数,使其在特定任务上更加稳定;

LoRA 和 PEFT 则进一步优化,使这种调整变得高效、低成本。

这一阶段解决的是:

如何在不破坏原有能力的情况下,让模型适应具体应用。

可以理解为:

从"临时控制"走向"长期能力塑造"。


6. RLHF:引入人类标准

在模型能力不断增强后,一个新的问题出现:

模型的输出是否符合人类预期。

RLHF 的核心,是把"人类评价"引入训练过程,使模型优化目标从"数据概率"转向"人类偏好"。

这一阶段的关键变化在于:

模型不再只是模仿数据,而开始对齐人类标准。


7. 模型蒸馏:走向实际落地

当模型能力、控制方式都具备之后,最后一个问题是:

如何真正落地使用。

模型蒸馏通过"教师---学生"机制,使小模型获得接近大模型的能力,从而降低计算成本,提高部署效率。

这一阶段解决的是:

从"能用"走向"可规模化使用"。


8. 整体核心逻辑

从第10章到第13章,其实形成了一条非常清晰的技术演进路径:

从 Attention 的信息选择机制出发,构建 Transformer 框架;

在此基础上分化出 GPT(生成)与 BERT(理解);

再通过 Prompt 实现对模型行为的直接控制;

进一步通过 Fine-tuning 和 LoRA 调整模型能力;

引入 RLHF 使模型符合人类偏好;

最后通过蒸馏实现工程落地。

这条路径可以总结为一个闭环:

建模能力 → 行为控制 → 能力优化 → 人类对齐 → 工程落地


9. 一句话总总结

整个系列可以用一句话概括:

Transformer提供结构,GPT/BERT定义能力,Prompt负责控制,Fine-tuning与RLHF优化行为,蒸馏实现落地。

相关推荐
新缸中之脑2 小时前
NOMAD:战时离线智能体
人工智能
章鱼丸-2 小时前
DAY38 Dataset 类和DataLoader 类
人工智能
老师好,我是刘同学2 小时前
Python执行系统命令的最佳实践
python
鄭郑2 小时前
Figma学习笔记---03
笔记·学习·figma
深藏功yu名2 小时前
Day25(高阶篇):RAG检索与重排序算法精研|从原理到参数调优,彻底攻克检索瓶颈
人工智能·算法·ai·自然语言处理·排序算法·agent
司南-70492 小时前
claude初探- 国内镜像安装linux版claude
linux·运维·服务器·人工智能·后端
cd_949217212 小时前
《观澜社张庆与中信证券联手,共探金融发展新路径》
人工智能·金融
郝学胜-神的一滴2 小时前
深入解析:生成器在UserList中的应用与Python可迭代对象实现原理
开发语言·python·程序人生·算法
一晌小贪欢2 小时前
【计算机科普知识】:什么是AI智能体(AI Agent)
人工智能·ai·chatgpt·ai agent·智能体·ai智能体