大语言模型基础
一句话
大语言模型(LLM)是现代智能体的核心组件,其基础架构从N-gram、RNN发展到Transformer,通过自注意力机制实现并行计算和长距离依赖捕捉,并通过提示工程和文本分词等技术实现与人类的交互。
什么时候翻这页
- 需要理解大语言模型的基本架构和工作原理时
- 学习如何设计有效的提示词(提示工程)时
- 需要了解文本分词的基本原理和实现时
- 选择适合特定任务的模型时
- 解决模型幻觉等局限性问题时
核心概念
语言模型(Language Model, LM)
- 根本任务是计算一个词序列出现的概率
- 从统计语言模型(N-gram)到神经网络语言模型(RNN/LSTM)再到Transformer架构的演进
N-gram模型
- 基于马尔可夫假设:一个词的出现概率只与前面有限的n-1个词有关
- 分为Bigram(N=2)和Trigram(N=3)等
- 存在数据稀疏性和泛化能力差的问题
神经网络语言模型
- 引入词嵌入(Word Embedding)表示词的语义
- 通过余弦相似度(Cosine Similarity)计算词向量间的相似性
- 解决了N-gram模型的泛化能力问题
循环神经网络(RNN)
- 引入隐藏状态(hidden state)作为网络的短期记忆
- 存在长期依赖问题(Long-term Dependency Problem)
- 梯度消失(Vanishing Gradients)和梯度爆炸(Gradient Explosion)
长短时记忆网络(LSTM)
- 引入细胞状态(cell state)和门控机制(gating mechanism)
- 包含遗忘门(forget gate)、输入门(input gate)和输出门(output gate)
Transformer架构
- 完全抛弃循环结构,依赖注意力(Attention)机制实现并行计算
- 编码器-解码器(Encoder-Decoder)结构
- 核心组件包括自注意力(Self-Attention)、多头注意力(Multi-Head Attention)、前馈网络(Feed-Forward Network)
自注意力机制
- 为每个词元引入查询(Query)、键(Key)、值(Value)三个角色
- 公式:Attention(Q,K,V)=softmax(QK^T/√d_k)V
多头注意力(Multi-Head Attention)
- 将Q,K,V向量在维度上切分成h份,独立进行单头注意力计算
- 增强模型表达能力,同时关注不同位置、不同表示子空间的信息
位置编码(Positional Encoding)
- 解决Transformer本身不包含词元顺序信息的问题
- 使用正弦和余弦函数直接计算位置向量
Decoder-Only架构
- 只保留Transformer的解码器部分
- 采用自回归(Autoregressive)工作模式
- 使用掩码自注意力(Masked Self-Attention)确保预测公平性
提示工程(Prompt Engineering)
- 通过设计精准提示引导模型产生期望输出
- 模型采样参数:Temperature、Top-k、Top-p
- 提示类型:零样本(Zero-shot)、单样本(One-shot)、少样本(Few-shot)
- 指令调优(Instruction Tuning):使用"指令-回答"格式数据对模型进行微调
- 基础提示技巧:角色扮演(Role-playing)、上下文示例(In-context Example)
- 思维链(Chain-of-Thought, CoT):引导模型"一步一步地思考"
文本分词(Tokenization)
- 将文本序列转换为数字序列的过程
- 分词器(Tokenizer)定义规则将文本切分成词元(Token)
- 子词分词(Subword Tokenization):平衡词表大小和语义表达
- 字节对编码(Byte Pair Encoding, BPE):迭代合并最高频的相邻词元对
- WordPiece:最大化提升语料库的语言模型概率
- SentencePiece:将空格视为普通字符,分词完全可逆
缩放法则(Scaling Laws)
- 模型性能与参数量、数据量和计算量之间存在可预测的幂律关系
- Chinchilla定律:模型参数量和训练数据量存在最优配比
- 能力涌现:模型规模达到阈值后突然展现全新能力
模型幻觉(Hallucination)
- 模型生成内容与客观事实、用户输入或上下文信息相矛盾
- 类型:事实性幻觉(Factual Hallucinations)、忠实性幻觉(Faithfulness Hallucinations)、内在幻觉(Intrinsic Hallucinations)
- 缓解方法:检索增强生成(RAG)、多步推理与验证、引入外部工具
怎么做
计算N-gram模型概率
import collections
# 示例语料库
corpus = "datawhale agent learns datawhale agent works"
tokens = corpus.split()
total_tokens = len(tokens)
# 计算P(datawhale)
count_datawhale = tokens.count('datawhale')
p_datawhale = count_datawhale / total_tokens
# 计算P(agent|datawhale)
bigrams = zip(tokens, tokens[1:])
bigram_counts = collections.Counter(bigrams)
count_datawhale_agent = bigram_counts[('datawhale', 'agent')]
p_agent_given_datawhale = count_datawhale_agent / count_datawhale
# 计算P(learns|agent)
count_agent_learns = bigram_counts[('agent', 'learns')]
count_agent = tokens.count('agent')
p_learns_given_agent = count_agent_learns / count_agent
# 计算句子概率
p_sentence = p_datawhale * p_agent_given_datawhale * p_learns_given_agent
实现多头注意力机制
import torch
import torch.nn as nn
import math
class MultiHeadAttention(nn.Module):
def __init__(self, d_model, num_heads):
super(MultiHeadAttention, self).__init__()
assert d_model % num_heads == 0, "d_model 必须能被 num_heads 整除"
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 scaled_dot_product_attention(self, Q, K, V, mask=None):
# 计算注意力得分
attn_scores = torch.matmul(Q, K.transpose(-2, -1)) / math.sqrt(self.d_k)
# 应用掩码
if mask is not None:
attn_scores = attn_scores.masked_fill(mask == 0, -1e9)
# 计算注意力权重
attn_probs = torch.softmax(attn_scores, dim=-1)
# 加权求和
output = torch.matmul(attn_probs, V)
return output
def split_heads(self, x):
batch_size, seq_length, d_model = x.size()
return x.view(batch_size, seq_length, self.num_heads, self.d_k).transpose(1, 2)
def combine_heads(self, x):
batch_size, num_heads, seq_length, d_k = x.size()
return x.transpose(1, 2).contiguous().view(batch_size, seq_length, self.d_model)
def forward(self, Q, K, V, mask=None):
# 对 Q, K, V 进行线性变换
Q = self.split_heads(self.W_q(Q))
K = self.split_heads(self.W_k(K))
V = self.split_heads(self.W_v(V))
# 计算缩放点积注意力
attn_output = self.scaled_dot_product_attention(Q, K, V, mask)
# 合并多头输出并进行最终的线性变换
output = self.W_o(self.combine_heads(attn_output))
return output
实现位置编码
import torch
import torch.nn as nn
import math
class PositionalEncoding(nn.Module):
def __init__(self, d_model: int, dropout: float = 0.1, max_len: int = 5000):
super().__init__()
self.dropout = nn.Dropout(p=dropout)
# 创建位置编码矩阵
position = torch.arange(max_len).unsqueeze(1)
div_term = torch.exp(torch.arange(0, d_model, 2) * (-math.log(10000.0) / d_model))
pe = torch.zeros(max_len, d_model)
pe[:, 0::2] = torch.sin(position * div_term)
pe[:, 1::2] = torch.cos(position * div_term)
self.register_buffer('pe', pe.unsqueeze(0))
def forward(self, x: torch.Tensor) -> torch.Tensor:
x = x + self.pe[:, :x.size(1)]
return self.dropout(x)
本地部署开源大语言模型
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
# 指定模型ID
model_id = "Qwen/Qwen1.5-0.5B-Chat"
# 设置设备
device = "cuda" if torch.cuda.is_available() else "cpu"
# 加载分词器和模型
tokenizer = AutoTokenizer.from_pretrained(model_id)
model = AutoModelForCausalLM.from_pretrained(model_id).to(device)
# 准备对话输入
messages = [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "你好,请介绍你自己。"}
]
# 使用分词器的模板格式化输入
text = tokenizer.apply_chat_template(
messages,
tokenize=False,
add_generation_prompt=True
)
# 编码输入文本
model_inputs = tokenizer([text], return_tensors="pt").to(device)
# 生成回答
generated_ids = model.generate(
model_inputs.input_ids,
max_new_tokens=512
)
# 截取生成部分并解码
generated_ids = [
output_ids[len(input_ids):] for input_ids, output_ids in zip(model_inputs.input_ids, generated_ids)
]
response = tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
print(response)
BPE算法实现
import re, 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 = re.escape(' '.join(pair))
p = re.compile(r'(?<!\S)' + bigram + r'(?!\S)')
for word in v_in:
w_out = p.sub(''.join(pair), word)
v_out[w_out] = v_in[word]
return v_out
# 准备语料库
vocab = {'h u g </w>': 1, 'p u g </w>': 1, 'p u n </w>': 1, 'b u n </w>': 1}
num_merges = 4
# 执行BPE算法
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} -> {''.join(best)}")
print(f"新词表(部分): {list(vocab.keys())}")
命令 / 代码速查
模型采样参数
- Temperature: 控制输出随机性,值越小输出越确定
- Top-k: 保留概率最高的k个token组成候选集
- Top-p: 动态选择累积概率≥p的最小token集合
提示类型
- 零样本提示(Zero-shot): 不提供示例,直接下达指令
- 单样本提示(One-shot): 提供一个完整示例
- 少样本提示(Few-shot): 提供多个示例
分词算法
- BPE: 迭代合并最高频的相邻词元对
- WordPiece: 最大化提升语料库的语言模型概率
- SentencePiece: 将空格视为普通字符,分词完全可逆
模型选择考量因素
- 性能与能力
- 成本
- 速度(延迟)
- 上下文窗口
- 部署方式
- 生态与工具链
- 可微调性与定制化
- 安全性与伦理
与 Python / Claude Code 手册的联系
- 使用Python的
transformers库加载和运行大语言模型 - 使用PyTorch实现Transformer架构的核心组件
- 使用正则表达式处理文本分词
- 使用数学库(如numpy)计算词向量和相似度
初学者易错点
- 混淆词元(Token)、单词(Word)和字符(Character)的概念
- 忽视上下文窗口限制是以Token数量计算的,而非字符数
- 错误理解Temperature参数的作用,认为高温度总是产生更好的结果
- 忽视模型幻觉问题,将模型输出视为绝对事实
- 在选择模型时只关注参数量,忽视数据质量和计算效率的重要性