AI大模型-LLM原理剖析到训练微调实战(第二部分:大模型核心原理与Transformer架构)

第二部分:大模型核心原理与Transformer架构

摘要:本部分将带你从零开始构建大模型的理论大厦。我们将从 NLP 的基石(词向量)出发,深入剖析 Transformer 架构的每一个细节------从 Tokenizer 分词原理到 BPE 算法实现,再到手写 Self-Attention、MQA/GQA 以及旋转位置编码(RoPE)。这是从"调包侠"进阶为"算法工程师"的关键一步。


第3章 DeepSeek的起源

3.1 机器如何理解语言:词向量 (Word Embedding)

在计算机眼中,文本只是字符串。为了让机器理解语义(比如知道"国王"和"王后"的关系类似于"男人"和"女人"),我们需要将词转化为向量。

  • One-Hot 编码:维度爆炸,无法表示词之间的相似度。
  • Word2Vec :将词映射到低维稠密空间(如 512 维)。
    • 核心思想:由上下文决定词的含义(King - Man + Woman ≈ Queen)。

【实战】使用 Gensim 训练词向量

python 复制代码
from gensim.models import Word2Vec

# 1. 准备语料(简单的分词后的句子列表)
sentences = [
    ["深度", "求索", "发布", "了", "DeepSeek", "模型"],
    ["大", "模型", "改变", "了", "人工智能", "行业"],
    ["学习", "Transformer", "架构", "非常", "重要"]
]

# 2. 训练 Word2Vec 模型
# vector_size=100: 每个词表示为100维向量
# window=5: 上下文窗口大小
# min_count=1: 忽略出现次数少于1次的词
model = Word2Vec(sentences, vector_size=100, window=5, min_count=1, workers=4)

# 3. 获取词向量
vector = model.wv['DeepSeek']
print(f"DeepSeek 的向量前10位: {vector[:10]}")

# 4. 计算相似度
print("DeepSeek 与 模型 的相似度:", model.wv.similarity('DeepSeek', '模型'))

3.2 预训练模型演进:从 BERT 到 GPT

  • BERT (Encoder-only) :擅长理解(完形填空),如文本分类、情感分析。它看得到上下文(双向)。
  • GPT (Decoder-only) :擅长生成(文字接龙)。它只能看上文,预测下一个字。
  • DeepSeek 的选择:现代大语言模型(LLM)大多采用 Decoder-only 架构,因为"生成"任务可以兼容"理解"任务,且训练效率更高。

第4章 解析大模型的输入输出

4.1 什么是 Token?

大模型读的不是"字",而是 Token(词元)。Token 可以是一个字、一个词,甚至是一个字节片段。

4.2 深入理解 BPE (Byte Pair Encoding) 算法

几乎所有主流大模型(GPT-4, DeepSeek, Llama)都使用 BPE 算法进行分词。

原理

  1. 将单词拆分为字符。
  2. 统计最常出现的相邻字符对。
  3. 将最频繁的字符对合并为一个新符号。
  4. 重复步骤 2-3,直到达到预设的词表大小。

【实战】手撸简化版 BPE 训练代码

python 复制代码
import collections

def get_stats(vocab):
    pairs = collections.defaultdict(int)
    for word, freq in vocab.items():
        symbols = word.split()
        for i in range(len(symbols)-1):
            pairs[symbols[i], symbols[i+1]] += freq
    return pairs

def merge_vocab(pair, v_in):
    v_out = {}
    bigram = ' '.join(pair)
    replacement = ''.join(pair)
    for word in v_in:
        w_out = word.replace(bigram, replacement)
        v_out[w_out] = v_in[word]
    return v_out

# 初始语料 (假设已经做了一些预处理)
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}
num_merges = 10

print("--- BPE Merge 过程 ---")
for i in range(num_merges):
    pairs = get_stats(vocab)
    if not pairs:
        break
    best = max(pairs, key=pairs.get)
    vocab = merge_vocab(best, vocab)
    print(f"第 {i+1} 次合并: {best}")

4.3 大模型解码策略

模型输出的是下一个 Token 的概率分布。如何选择?

  • Greedy Search:每次只选概率最大的。容易陷入循环,不够丰富。
  • Temperature (温度)
    • 低温度 (<0.5):概率分布更尖锐,回答更确定、保守(适合代码、数学)。
    • 高温度 (>0.8):概率分布更平缓,回答更有创造力(适合写诗、头脑风暴)。
  • Top-P (Nucleus Sampling):截断累积概率达到 P 的部分,DeepSeek 推荐 Top-P 采样。

第5章 Transformer的注意力机制

这是核心中的核心。Transformer 通过"注意力机制"计算词与词之间的关联强度。

5.1 手撸 Self-Attention (自注意力机制)

公式: <math xmlns="http://www.w3.org/1998/Math/MathML"> A t t e n t i o n ( Q , K , V ) = softmax ( Q K T d k ) V Attention(Q, K, V) = \text{softmax}(\frac{QK^T}{\sqrt{d_k}})V </math>Attention(Q,K,V)=softmax(dk QKT)V

  • Q (Query):查询向量(我要找什么?)
  • K (Key):键向量(我是什么?)
  • V (Value):值向量(我的内容是什么?)

PyTorch 实现代码

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

class SelfAttention(nn.Module):
    def __init__(self, d_model, head_size):
        super().__init__()
        self.key = nn.Linear(d_model, head_size, bias=False)
        self.query = nn.Linear(d_model, head_size, bias=False)
        self.value = nn.Linear(d_model, head_size, bias=False)
        self.d_k = head_size

    def forward(self, x):
        # x shape: (Batch, Seq_Len, d_model)
        k = self.key(x)   # (B, T, H)
        q = self.query(x) # (B, T, H)
        v = self.value(x) # (B, T, H)

        # 1. 计算注意力分数 (Scaled Dot-Product)
        # (B, T, H) @ (B, H, T) -> (B, T, T)
        wei = q @ k.transpose(-2, -1) * (1.0 / math.sqrt(self.d_k))

        # 2. Mask (对于 Decoder,不能看未来的词)
        tril = torch.tril(torch.ones(x.shape[1], x.shape[1])).to(x.device)
        wei = wei.masked_fill(tril == 0, float('-inf'))

        # 3. Softmax
        wei = torch.nn.functional.softmax(wei, dim=-1)

        # 4. 加权聚合
        out = wei @ v # (B, T, T) @ (B, T, H) -> (B, T, H)
        return out

# 测试
d_model = 64
head_size = 16
x = torch.randn(1, 10, d_model) # Batch=1, 长度10个词
sa = SelfAttention(d_model, head_size)
output = sa(x)
print(f"Self-Attention 输出尺寸: {output.shape}") # 应为 [1, 10, 16]

5.2 注意力机制的进化:MQA 与 GQA

为了减少显存占用(KV Cache),DeepSeek 和 Llama 采用了优化的注意力机制。

  • MHA (Multi-Head Attention):标准多头。每个头都有自己的 Q, K, V。显存占用大。
  • MQA (Multi-Query Attention):所有头共享同一组 K, V,只有 Q 不同。推理极快,但性能略降。
  • GQA (Grouped-Query Attention):DeepSeek-V2/V3 采用。折中方案,将头分组,每组共享 K, V。平衡了性能与速度。

第6章 Transformer中的位置编码

Transformer 本身是并行计算的,没有时间顺序的概念。如果打乱句子中词的顺序,Attention 的结果是一样的。因此必须加入位置编码

6.1 旋转位置编码 (RoPE)

这是目前最先进的位置编码方式(DeepSeek, Llama, Qwen 均使用)。

  • 核心思想:通过绝对位置编码的数学形式,实现相对位置的性质。它不是将位置向量"加"在词向量上,而是将词向量在向量空间中进行"旋转"。
  • 优势:极好的外推性(训练时长度 4k,推理时可扩展到 32k 甚至更长)。

【实战】手撸 RoPE 核心逻辑

python 复制代码
def precompute_freqs_cis(dim: int, end: int, theta: float = 10000.0):
    # 计算旋转角度
    freqs = 1.0 / (theta ** (torch.arange(0, dim, 2)[: (dim // 2)].float() / dim))
    t = torch.arange(end, device=freqs.device)  # type: ignore
    freqs = torch.outer(t, freqs).float()  # type: ignore
    # 转换为极坐标形式 (cos + isin)
    freqs_cis = torch.polar(torch.ones_like(freqs), freqs)  # complex64
    return freqs_cis

def apply_rotary_emb(xq: torch.Tensor, xk: torch.Tensor, freqs_cis: torch.Tensor):
    # 将输入视为复数
    xq_ = torch.view_as_complex(xq.float().reshape(*xq.shape[:-1], -1, 2))
    xk_ = torch.view_as_complex(xk.float().reshape(*xk.shape[:-1], -1, 2))
    
    # 调整 freqs_cis 形状以广播
    freqs_cis = freqs_cis.view(1, xq_.shape[1], 1, xq_.shape[-1])
    
    # 复数乘法实现旋转
    xq_out = torch.view_as_real(xq_ * freqs_cis).flatten(3)
    xk_out = torch.view_as_real(xk_ * freqs_cis).flatten(3)
    return xq_out.type_as(xq), xk_out.type_as(xk)

第二部分总结: 在这一部分,我们深入到了大模型的"心脏"。通过手写 BPE、Self-Attention 和 RoPE,你不再只是把模型当做一个黑盒,而是理解了它是如何把文本切碎、如何计算词与词的关联、以及如何记住位置信息的。

下期预告 : 理论基础已备,接下来我们将进入 第三部分:大模型训练流程(预训练)。我们将探讨如何收集和清洗海量数据,如何配置分布式训练集群(NCCL, DeepSpeed),以及如何训练一个万亿参数的模型。这部分将涉及真正的"算力"与"系统"工程。

相关推荐
老妪力虽衰2 小时前
零基础的小白也能通过AI搭建自己的网页应用
前端
褪色的笔记簿2 小时前
在 Vue 项目里管理弹窗组件:用 ref 还是用 props?
前端·vue.js
Danny_FD2 小时前
使用Taro实现微信小程序仪表盘:使用canvas实现仪表盘(有仪表盘背景,也可以用于Web等)
前端·taro·canvas
掘金安东尼2 小时前
VSCode V1.107 发布(2025 年 11 月)
前端·visual studio code
一只小阿乐2 小时前
前端vue3 web端中实现拖拽功能实现列表排序
前端·vue.js·elementui·vue3·前端拖拽
AAA阿giao2 小时前
从“操纵绳子“到“指挥木偶“:Vue3 Composition API 如何彻底改变前端开发范式
开发语言·前端·javascript·vue.js·前端框架·vue3·compositionapi
TextIn智能文档云平台2 小时前
图片转文字后怎么输入大模型处理
前端·人工智能·python
专注前端30年2 小时前
在日常开发项目中Vue与React应该如何选择?
前端·vue.js·react.js
文刀竹肃2 小时前
DVWA -XSS(DOM)-通关教程-完结
前端·安全·网络安全·xss