基座模型

大语言模型如何理解和生成文本:词元切分、概率预测与自回归采样全解析

深度剖析现代大语言模型从离散文本 Tokenization、高维向量空间嵌入、因果注意力机制到自回归解码与概率采样的完整技术全景与工程实现。

发布于 8 分钟阅读

引言:概率生成机器的内部运转

在公众眼中,以 GPT-4、Claude、LLaMA 和 DeepSeek 为代表的大语言模型(Large Language Models, LLMs)仿佛具备了深不可测的通用思维能力。它们能够解答复杂的微积分定理、撰写高质量的工程架构设计文档、进行幽默风趣的文学创作,甚至像资深工程师一样调试复杂的分布式并发代码。

然而,在底层的数学与物理实现层面上,现代大语言模型本质上是一台极度精密、基于超大规模人工神经网络参数化的自回归概率序列生成机器。给定一个已有的提示词序列(Prompt Context),模型执行的核心任务极其纯粹且单一:基于已观测到的前驱符号序列,精确估计高维离散词表中下一个最可能出现的符号的条件概率分布,并通过特定的采样策略输出该符号,进而将其追加至历史上下文中循环迭代。

从无序的自然语言字符串,到计算机底层的高维浮点数矩阵运算,再到连贯逻辑文本的动态喷涌,这一过程究竟是如何实现的?本文将逐层拆解大语言模型从离散化预处理、几何向量变换、因果多头注意力计算,到最终概率采样与显存优化的完整计算流水线。


一、离散世界与符号切分:词元化(Tokenization)的工程艺术

计算机无法直接识别带有语法、隐喻与情感色彩的人类自然语言文本,它只能处理形式化的离散整数或连续浮点数。因此,大模型文本处理的第一步是将原始的非结构化字符串切分为离散的符号单位——词元(Token)。

1. 分词粒度的工程权衡

在自然语言处理早期,学者们主要面临两种极端的分词粒度选择:

  • 字符级分词(Character-level):将文本拆分为单一英文字母或中文字符。其优势在于词表规模极小(几百个字符即可覆盖所有 ASCII 与基础 Unicode),永远不会发生未登录词(Out-Of-Vocabulary, OOV)错误;然而其缺陷极其致命,序列展开长度过长,极度消耗注意力的二次方计算资源,且单一字符本身缺乏独立的语义表征。
  • 词级分词(Word-level):以空格或形态学边界划分单词(如英文中的空格切分,中文的分词工具结巴等)。其优势在于语义单元完整;但缺陷是词表规模不可控,动辄包含数百万词汇,不仅导致词嵌入矩阵显存爆炸,面对新造词、缩写、拼写错误时还会频繁触发 <unk> 标记。

现代大语言模型无一例外地采用了介于二者之间的平衡方案——子词级切分(Subword Tokenization)。其中,以字节对编码(Byte-Pair Encoding, BPE)和 SentencePiece 最为普遍。

2. BPE 算法工作机制

BPE 是一种自底向上的数据驱动统计压缩算法:

  1. 初始阶段将所有文本拆解为基础字符(甚至单字节 Byte 级别,保证覆盖所有 UTF-8 编码,消除 OOV);
  2. 统计整个预训练训练语料库中所有相邻符号对(Pairs)的共现频次;
  3. 将出现频次最高的符号对合并为一个全新的单一符号,并将其添加到词表中;
  4. 反复迭代上述合并步骤,直至词表规模达到预设大小(例如 LLaMA 采用 32,000 到 128,000 规模,GPT-4o 采用约 200,000 词表规模)。
# 简化版 Byte-Pair Encoding (BPE) 训练合并过程演示
from collections import defaultdict

def get_stats(vocab: dict[tuple[str, ...], int]) -> dict[tuple[str, str], int]:
    pairs = defaultdict(int)
    for word, freq in vocab.items():
        for i in range(len(word) - 1):
            pairs[(word[i], word[i+1])] += freq
    return pairs

def merge_vocab(pair: tuple[str, str], vocab: dict[tuple[str, ...], int]) -> dict[tuple[str, ...], int]:
    new_vocab = {}
    bigram = pair
    replacement = "".join(pair)
    for word, freq in vocab.items():
        new_word = []
        i = 0
        while i < len(word):
            if i < len(word) - 1 and (word[i], word[i+1]) == bigram:
                new_word.append(replacement)
                i += 2
            else:
                new_word.append(word[i])
                i += 1
        new_vocab[tuple(new_word)] = freq
    return new_vocab

# 初始微型语料词频统计
toy_vocab = {
    ('l', 'o', 'w', '</w>'): 5,
    ('l', 'o', 'w', 'e', 'r', '</w>'): 2,
    ('n', 'e', 'w', 'e', 's', 't', '</w>'): 6,
    ('w', 'i', 'd', 'e', 's', 't', '</w>'): 3
}

# 模拟 3 轮合并
current_vocab = toy_vocab
for iteration in range(3):
    pairs = get_stats(current_vocab)
    best_pair = max(pairs, key=pairs.get)
    current_vocab = merge_vocab(best_pair, current_vocab)
    print(f"Iteration {iteration + 1}: Merged {best_pair} with frequency {pairs[best_pair]}")

经过 Tokenizer 切分后,一段自然语言输入如 "Attention is all you need" 将被精准转换为一维离散整数数组,例如 [2049, 318, 477, 345, 761]。


二、几何空间变换:嵌入层与旋转位置编码(RoPE)

离散整数本身不具备几何代数运算性质。在模型输入端,系统必须通过查找表(Look-Up Table)将每一个 Token ID 映射为一个连续高维欧氏空间中的稠密向量(例如 dmodel=4096d_{\text{model}} = 4096 或 81928192),即词嵌入向量(Word Embeddings)。

1. 词嵌入的语义拓扑

在理想的嵌入空间中,相似含义的 Token 具有较高的余弦相似度,且语义关系呈现几何向量位移性质(如经典的 v⃗King−v⃗Man+v⃗Woman≈v⃗Queen\vec{v}_{\text{King}} - \vec{v}_{\text{Man}} + \vec{v}_{\text{Woman}} \approx \vec{v}_{\text{Queen}})。然而,自注意力机制本身是置换不变的(Permutation Invariant)——若不引入序列顺序信息,"张三打了李四" 与 "李四打了张三" 在初始状态下生成的特征集合将完全等同。

2. 旋转位置编码(Rotary Position Embedding, RoPE)

现代主流大模型(如 LLaMA、Mistral、Qwen、DeepSeek)普遍舍弃了早期 Transformer 的绝对正弦位置编码,全量采用了旋转位置编码(RoPE)。

RoPE 巧妙地将位置信息注入到了自注意力中的 Query (QQ) 与 Key (KK) 向量中。在二维平面的复数表示下,向量乘以一个旋转矩阵:

RΘ,md=(cos⁡(mθ)−sin⁡(mθ)sin⁡(mθ)cos⁡(mθ))R_{\Theta, m}^d = \begin{pmatrix} \cos(m\theta) & -\sin(m\theta) \\ \sin(m\theta) & \cos(m\theta) \end{pmatrix}

其核心性质在于:两个不同绝对位置 mm 与 nn 上的词元,其旋转变换后的内积只取决于它们的相对距离 m−nm - n:

⟨RΘ,mq,RΘ,nk⟩=g(q,k,m−n)\langle R_{\Theta, m} \mathbf{q}, R_{\Theta, n} \mathbf{k}\rangle = g(\mathbf{q}, \mathbf{k}, m - n)

这一数学优美性使得 RoPE 不仅能自然保持平移不变性,更赋予了模型极其优秀的长上下文外推能力(Length Extrapolation),为百万 Token 超长上下文架构(如 RoPE 动态缩放、YaRN 插值技术)奠定了坚实的理论基石。


三、因果自注意力与前向计算流:下一词概率的诞生

1. 统一通信总线:残差流(Residual Stream)

在多层 Transformer 解码器中,信息沿着主干通道——残差流(Residual Stream)持续向前传递。每一层的自注意力模块(Self-Attention Block)与前馈神经网络模块(SwiGLU MLP Block)在逻辑上可以被视作挂载在残差流两旁的“读写处理单元”:

  1. 读取:从当前残差流向量中通过归一化(RMSNorm)读取信息;
  2. 计算:多头自注意力层在不同空间子平面建立全序列关联,MLP 层进行高阶知识记忆的非线性抽取;
  3. 写入:将计算结果通过加法叠加回主残差流:xl=xl−1+f(xl−1)\mathbf{x}_{l} = \mathbf{x}_{l-1} + f(\mathbf{x}_{l-1})。

2. 因果下三角掩码(Causal Mask)

在文本生成场景中,自注意力机制必须遵循因果律(Causality):位于第 tt 步的词元,只能对第 1…t1 \dots t 步的前驱 Token 施加注意力,严禁“窥探未来”。在计算注意力分数矩阵时,通过引入一个严格的因果下三角掩码矩阵 MM,将右上角未来位置的分数强行置为 −∞-\infty:

Attention(Q,K,V)=Softmax(QKTdk+M)V,Mij={0i≥j−∞i<j\text{Attention}(Q, K, V) = \text{Softmax}\left(\frac{QK^T}{\sqrt{d_k}} + M \right)V, \quad M_{ij} = \begin{cases} 0 & i \ge j \\ -\infty & i < j \end{cases}

经 Softmax 激活后,未来位置的注意力权重精确收敛为 0,彻底切断了信息逆时间流动的可能。

3. LM Head 与输出对数几率(Logits)

当残差流穿透最后一层 Transformer 并完成终结归一化后,最后一个位置的上下文隐向量 hT∈Rdmodel\mathbf{h}_T \in \mathbb{R}^{d_{\text{model}}} 被送入线性投影头(Language Model Head)。LM Head 的权重矩阵大小为 RV×dmodel\mathbb{R}^{V \times d_{\text{model}}}(其中 VV 为词表总容量):

z=WheadhT+bhead∈RV\mathbf{z} = W_{\text{head}} \mathbf{h}_T + \mathbf{b}_{\text{head}} \in \mathbb{R}^V

输出向量 z\mathbf{z} 即为对应整个词表上每个离散 Token 的未归一化对数概率(Logits)。


四、自回归采样与解码:决定模型表达的艺术

获得 Logits 向量后,最直观的做法是通过 argmax⁡\operatorname{argmax} 每次选取概率绝对最大的词元——这被称为贪婪搜索(Greedy Search)。然而大量学术研究证明,贪婪搜索极易导致生成内容陷入重复循环、语言单调枯燥或局部次优陷阱。为了使生成文本兼具丰富性、创造力与语法严谨性,工业界采用了多重采样控制算法。

# 现代大语言模型综合概率采样算法实现
import torch
import torch.nn.functional as F

def sample_next_token(
    logits: torch.Tensor,
    temperature: float = 0.7,
    top_k: int = 50,
    top_p: float = 0.9,
    min_p: float = 0.05,
    repetition_penalty: float = 1.1,
    generated_tokens: list[int] | None = None
) -> int:
    logits = logits.clone()

    # 1. 施加重复惩罚 (Repetition Penalty)
    if generated_tokens and repetition_penalty != 1.0:
        for token_id in set(generated_tokens):
            if logits[token_id] > 0:
                logits[token_id] /= repetition_penalty
            else:
                logits[token_id] *= repetition_penalty

    # 2. 温度平滑 (Temperature Scaling)
    temperature = max(temperature, 1e-5)
    logits = logits / temperature

    # 3. Top-k 截断
    if top_k > 0:
        top_k = min(top_k, logits.size(-1))
        indices_to_remove = logits < torch.topk(logits, top_k)[0][..., -1, None]
        logits[indices_to_remove] = -float('inf')

    # 4. 计算初始概率分布
    probs = F.softmax(logits, dim=-1)

    # 5. Min-p 截断 (过滤相对最高概率低于特定阈值的尾部噪音)
    if min_p > 0.0:
        max_prob = torch.max(probs)
        scaled_min_p = max_prob * min_p
        min_p_mask = probs < scaled_min_p
        logits[min_p_mask] = -float('inf')
        probs = F.softmax(logits, dim=-1)

    # 6. 核采样 (Top-p / Nucleus Filtering)
    if 0.0 < top_p < 1.0:
        sorted_probs, sorted_indices = torch.sort(probs, descending=True)
        cumulative_probs = torch.cumsum(sorted_probs, dim=-1)

        # 移除累积概率超过 top_p 的词元
        sorted_indices_to_remove = cumulative_probs > top_p
        sorted_indices_to_remove[..., 1:] = sorted_indices_to_remove[..., :-1].clone()
        sorted_indices_to_remove[..., 0] = False

        indices_to_remove = sorted_indices[sorted_indices_to_remove]
        logits[indices_to_remove] = -float('inf')
        probs = F.softmax(logits, dim=-1)

    # 7. 多项式随机采样
    next_token = torch.multinomial(probs, num_samples=1).item()
    return next_token

各核心参数在前端与推理系统中的作用可归纳如下:

参数名称

核心物理含义

典型推荐取值

低值表现

高值表现

Temperature

玻尔兹曼分布温度,缩放 Logits 方差

0.2 ~ 0.8

确定性极高,严谨保真,易复读

联想丰富发散,极易语无伦次

Top-k

候选词池截断绝对数量

20 ~ 50

仅在极少数最优选词中抉择

保留更多长尾稀缺词汇候选

Top-p (Nucleus)

累积动态置信度阈值截断

0.8 ~ 0.95

概率集中时候选极小,自适应剪枝

候选词范围更广,语篇多变

Min-p

相对峰值概率的比率截断

0.02 ~ 0.08

动态清除极低可信度的词元尾部

更加激进的动态词池过滤

Repetition Penalty

对已生成词元施加惩罚项

1.05 ~ 1.2

原汁原味自然语言习惯

强制避免任何词汇或句式重复


五、显存瓶颈与系统工程:KV Cache 机制解析

在单步自回归解码过程中,每当模型输出一个新的 Token,该 Token 就必须被拼接到上下文末尾,作为下一步推理的输入。如果每次都从头对整个序列执行全量前向计算,时间复杂度将呈现极其恐怖的 O(L3)O(L^3) 爆发,造成极其严重的计算资源浪费。

1. 为什么需要 KV Cache

自注意力计算依赖矩阵 QQ、KK、VV。当生成第 t+1t+1 个词时:

  • 只有第 t+1t+1 步需要生成新的查询向量 qt+1\mathbf{q}_{t+1};
  • 历史前驱位置 1…t1 \dots t 的键向量(Keys)和值向量(Values)在后续各层计算中是静态且不变的。

因此,现代推理引擎(如 vLLM、TGI、Ollama)在第一阶段 Prefill(预填充)完成后,便将所有历史层级的 KK 与 VV 矩阵常驻在 GPU 高速显存(HBM)中,称之为 KV Cache。在后续每一个生成步(Decode Phase),模型仅计算当前单个 Token 的投影,并将新产生的 kt+1\mathbf{k}_{t+1} 与 vt+1\mathbf{v}_{t+1} 追加到缓存中。

2. KV Cache 显存占用开销

KV Cache 极大地降低了计算延迟,但代价是消耗了惊人的 GPU 显存。对于单精度 FP16 浮点数,KV Cache 显存占用量公式为:

MemoryKVCache=2×2×nlayers×nheads×dhead×b×L(Bytes)\text{Memory}_{\text{KVCache}} = 2 \times 2 \times n_{\text{layers}} \times n_{\text{heads}} \times d_{\text{head}} \times b \times L \quad (\text{Bytes})

其中 bb 为 Batch Size,LL 为上下文总长度。以一个 70B 参数的大模型(80 层、8 头 GQA、隐藏维度 8192)为例,处理并发 Batch=8、上下文长度 128k 时,KV Cache 显存需求即可突破上百吉字节(GB),这也是现代大模型推理系统往往是内存带宽受限(Memory-Bound)而非算力受限(Compute-Bound)的核心根本原因。


六、总结

大语言模型看似无所不知的智能表象背后,是层层嵌套的高维线性代数投影、多维因果空间几何旋转、精巧的概率分布截断与高并发显存工程调度。

理解了从离散 Token 到连续空间,再从因果自注意力到自回归采样的全链条机制,我们便能更加清晰地把握现代生成式 AI 的能力边界——它不是神秘的不可知玄学,而是一套严格建立在经验概率论、矩阵论与大规模并行计算体系之上的现代计算机科学巅峰成就。