由于 Transformer 本质上是位置无关的,因此通过正确设置 positional embedding 和 attention mask,我们可以把多个“序列”合并到一个序列里进行推理。当这些序列具有很长的公共前缀时,这种方法会比 batched inference 更高效。这种方法的具体用途不是本文的重点,此处不做展开。

图片出自 SpecInfer: Accelerating Generative Large Language Model Serving with Tree-based Speculative Inference and Verification

但是,Transformers 库的自带 API 并不支持传递 attention mask 矩阵,而只支持选择是否 mask 掉整个 token(这种 mask 是用来处理 padding 的)。一种常见的解决方法是直接修改模型的代码,比如 REST 的实现。显然,这种方法在需要测试多种模型时会很麻烦。

有没有更通用一点的方法呢?有的!通过阅读源码可以发现,当模型把 2d 的 attention mask(这个参数是从 forward 一路传过来的)转化为 4d 时,如果输入已经是 4d 的话,这个函数会直接返回输入。因此通过这个文档里没有的 API,就可以传递 attention mask 矩阵了。

代码大概是这样的:(注意传入的 mask 值应为 -inf/0 而非 0/1)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer

# Load model
model_name = "Qwen/Qwen2.5-0.5B-Instruct"
model = AutoModelForCausalLM.from_pretrained(model_name, device_map="auto")
tokenizer = AutoTokenizer.from_pretrained(model_name)

# Create test input
message = "You are a are not a"
message_tokenized = tokenizer.encode(message, return_tensors="pt").to(model.device)
assert message_tokenized.shape[-1] == 6

# Create position_ids and attention_mask according to the tree structure
position_ids = torch.Tensor([[0, 1, 2, 1, 2, 2]]).long().to(model.device)
attn_mask_bool = torch.Tensor([[[
[1, 0, 0, 0, 0, 0],
[1, 1, 0, 0, 0, 0],
[1, 1, 1, 0, 0, 0],
[1, 0, 0, 1, 0, 0],
[1, 0, 0, 1, 1, 0],
[1, 0, 0, 1, 0, 1],
]]]).bool()
attn_mask_float = torch.where(attn_mask_bool, 0.0, -torch.inf).to(model.device)
print("position_ids:", position_ids.shape)
print("attn_mask_float:", attn_mask_float.shape)

r'''
树的结构:
- are ----- a
/
You --- - not
\ /
- are ---
\
- a

如果实现正确,两个 "are" 和 "a" 的 logits 应该相同
'''

# Run model
with torch.no_grad():
outputs = model(
message_tokenized,
position_ids=position_ids,
attention_mask=attn_mask_float
)
logits = outputs.logits
print("logits:", logits.shape)
print(f"{torch.allclose(logits[0, 1, :], logits[0, 3, :])=}")
print(f"{torch.allclose(logits[0, 2, :], logits[0, 5, :])=}")

输出为:

1
2
3
4
5
position_ids: torch.Size([1, 6])
attn_mask_float: torch.Size([1, 1, 6, 6])
logits: torch.Size([1, 6, 151936])
torch.allclose(logits[0, 1, :], logits[0, 3, :])=True
torch.allclose(logits[0, 2, :], logits[0, 5, :])=True

这种方法的优点:

  • 对大部分 Transformer 模型即插即用
  • 不需要深入模型的实现细节

这种方法的缺点:

  • 不是官方支持的 API,随时可能失效
  • 不支持 Flash Attention 2

收录了一些博主喜欢的实用工具。本页面不定期更新。

计算

Qalculate!

功能非常全面且设计合理的 PC 端计算器。(高级计算器和编程语言之间并没有明确的区隔;由于它很重视 fuzzy parsing,所以我还是将其算作计算器)

支持的特性非常多,比如大量非初等函数、简单的符号计算、不确定度传播、单位转换等等。详见官方示例

出自 qalculate.github.io

IPython

博主在科学计算方面基本只会 Python 生态,会用 MATLAB 或 Mathematica 的人可以忽略此节。

Python 自带 REPL 的上位。支持保存历史记录、语法高亮以及用·exit 而非 exit() 退出等。其中一部分功能也添加到了 Python 3.13 的新 REPL 中。

IPython 还支持一些拓展语法。博主比较常用的有:

  • 按 Ctrl+R 可以搜索历史记录
  • 函数/类名后加 ? 可以查看其帮助文档
  • Tab 补全可以补全目录/文件名
  • 全局变量 _ 可以访问上一个返回值,Out[i] 可以返回第 i 个语句(块)的返回值

Plotly

比 Matplotlib 更现代的 Python 绘图库。这个库视 DataFrame 为一等公民,而且默认就能生成美观的交互式图表,适合 prototyping。

美中不足的是深度定制样式还是不如 Matplotlib 方便,毕竟后者资料太多了。而且现在有大模型。

网页小工具

Pastebin

无需注册,支持不超过 50MB 的二进制文件,可以直接 POST/GET 的 pastebin。

最朴素的就是最好用的。

Windows 工具

PowerToys

由微软官方开发的一组 Windows 上的奇怪小工具。本人用它把 CapsLock 键改成了 Backspace(因为我打字准度太差了

AutoHotkey

用于操作自动化的脚本语言,可以写一些快捷键什么的。其实拿来写游戏的挂机脚本都可以,就是满屏 ImageSearchClick 啊可维护性太差了。

WizTree

可以非常快速地统计出磁盘占用的树形结构,清理磁盘空间时很有用。

看抽象代数的时候突然想到,群的 Cayley 表和数独一样,都要求每行(列)中的元素互异。那么能不能按照群的规则(即结合律)出一道变种数独题呢?于是简单试了一下。

规则:

  • 题面是一个 \(10 \times 10\) 数表(行和列从 \(0\) 开始计数),元素为 \(0 \sim 9\) 的整数;第 \(0\) 行和第 \(0\) 列的值已经给出
  • 与普通数独相同,每行、每列的元素不能重复;注意没有九宫格的条件
  • \(i\)\(j\) 列的值为 \(x\)\(j\)\(k\) 列的值为 \(y\),则 \(i\)\(y\) 列和 \(x\)\(k\) 列的值相同

TLDR:补全一个以 \(0\) 为单位元的 \(10\) 阶群的乘法表。(提示:\(10\) 阶群只有 \(\mathrm{Z}_{10}\)\(\mathrm{D}_{10}\) 两种)

题 1:(表中横、竖线仅作美化排版用途,无实际含义)

\[ \begin{array} {r|rrr|rrr|rrr} 0 & 1 & 2 & 3 & 4 & 5 & 6 & 7 & 8 & 9 \\ \hline 1 & 0 & & & & & & & & \\ 2 & & & 1 & & & & & & \\ 3 & & 4 & & & & & & & \\ \hline 4 & & & & & & & & & \\ 5 & & & & 2 & & & & & \\ 6 & & & & & & & & & \\ \hline 7 & & & & & & 3 & & & \\ 8 & & & & & 9 & & & & \\ 9 & & & & & & & & & \\ \end{array} \]

解析

表中 \(2 \times 3 \ne 3 \times 2\),说明这个群一定是 \(\mathrm{D}_{10}\). 这里先明确一下记号:\(\mathrm{D}_{10} = \langle r, s \mid r^5 = s^2 = e,\ sr = r^{-1}s \rangle\).

解决题目的关键在于理解 \(\mathrm{D}_{10}\) 的自同构。具体而言,对于任意的 \(n \in \{1, 2, 3, 4\},\ m \in \{0, 1, 2, 3, 4\}\),存在一个自同构,把 \(r^n\) 映射到 \(r\),把 \(r^m s\) 映射到 \(s\).

\(0\) 是单位元,而 \(1 \times 1 = 0\),说明 \(1\) 是“s 型”元素。根据这个群的自同构,我们可以确定,假如本题有解,那么一定存在一个 \(1\) 对应群中元素 \(s\)(下文简写为 \(1 \sim s\))的解。那么我们不妨设 \(1 \sim s\).

\(2 \times 3 = 1\),说明 \(2\)\(3\) 一个是“r 型”,一个是“s 型”。注意到 \(5 \times (3 \times 2) = 2\),因此 \(5\)\(3\) 互为逆元。“s 型”元素的逆元都是它本身,因此 \(3\) 是“r 型”,\(2\) 是“s 型”。

不妨设 \(3 \sim r\),则 \(2 \sim rs\)\(5 \sim r^4\). \(3 \times 2 = 4\),说明 \(4 \sim r^2 s\).

这是目前已确定的元素:

\(0\)\(1\)\(2\)\(3\)\(4\)\(5\)\(6\)\(7\)\(8\)\(9\)
\(e\)\(s\)\(rs\)\(r\)\(r^2 s\)\(r^4\)

还剩下 \(r^2,\, r^3,\, r^3 s,\, r^4s\) 尚未确定。

\(7 \times 6 = 3\),说明 \(6\)\(7\) 要么都是“r 型”,要么都是“s 型”。而 \(r^2 \times r^3 = r^3 \times r^2 = e\),说明 \(6\)\(7\) 只能都是“s 型”,因此 \(6 \sim r^3 s\)\(7 \sim r^4 s\).

\(8 \times 5 = 9\),而 \(8\)\(9\) 只能在 \(r^2,\, r^3\) 中取值,因此 \(8 \sim r^3\)\(9 \sim r^2\).

完整的对应关系如下:

\(0\)\(1\)\(2\)\(3\)\(4\)\(5\)\(6\)\(7\)\(8\)\(9\)
\(e\)\(s\)\(rs\)\(r\)\(r^2 s\)\(r^4\)\(r^3 s\)\(r^4 s\)\(r^3\)\(r^2\)

据此把乘法表补全即可。

答案:

\[ \begin{array} {r|rrr|rrr|rrr} 0 & 1 & 2 & 3 & 4 & 5 & 6 & 7 & 8 & 9 \\ \hline 1 & 0 & 5 & 7 & 8 & 2 & 9 & 3 & 4 & 6 \\ 2 & 3 & 0 & 1 & 5 & 4 & 8 & 9 & 6 & 7 \\ 3 & 2 & 4 & 9 & 6 & 0 & 7 & 1 & 5 & 8 \\ \hline 4 & 9 & 3 & 2 & 0 & 6 & 5 & 8 & 7 & 1 \\ 5 & 7 & 1 & 0 & 2 & 8 & 4 & 6 & 9 & 3 \\ 6 & 8 & 9 & 4 & 3 & 7 & 0 & 5 & 1 & 2 \\ \hline 7 & 5 & 8 & 6 & 9 & 1 & 3 & 0 & 2 & 4 \\ 8 & 6 & 7 & 5 & 1 & 9 & 2 & 4 & 3 & 0 \\ 9 & 4 & 6 & 8 & 7 & 3 & 1 & 2 & 0 & 5 \\ \end{array} \]

题 2:

\[ \begin{array} {r|rrr|rrr|rrr} 0 & 1 & 2 & 3 & 4 & 5 & 6 & 7 & 8 & 9 \\ \hline 1 & & & & & & & & & \\ 2 & & & & & & & & & \\ 3 & & & 0 & & & & & & 4 \\ \hline 4 & & & & & & & & 0 & \\ 5 & & 7 & & & & & & & \\ 6 & & & & & & & & & \\ \hline 7 & & & & & & & & & \\ 8 & & & & & 2 & & & & \\ 9 & & & & 1 & & & & & \\ \end{array} \]

解析

用和题 1 类似的方法,可以发现 \(\mathrm{D}_{10}\) 是不行的。因此,这个群只能是 \(\mathrm{Z}_{10}\). 记 \(\mathrm{Z}_{10} = \langle g \mid g^{10} = e \rangle\).

\(3 \times 3 = 0\),说明 \(3\) 的阶为 \(2\),因此 \(3 \sim g^5\).

考虑从 \(4\) 出发往后推。但我们还不确定 \(4\) 的阶是 \(5\) 还是 \(10\). 先假设 \(4\) 的阶是 \(5\),那么不妨设 \(4 \sim g^2\).

\(3 \times 9 = 4\),说明 \(9 \sim g^7\). \(4 \times 8 = 0\),说明 \(8 \sim g^8\). \(9 \times 4 = 1\),说明 \(1 \sim g^9\).

这是目前已确定的元素:

\(0\)\(1\)\(2\)\(3\)\(4\)\(5\)\(6\)\(7\)\(8\)\(9\)
\(e\)\(g^9\)\(g^5\)\(g^2\)\(g^8\)\(g^7\)

还剩下 \(g,\, g^3,\, g^4,\, g^6\) 尚未确定。

还有两个条件没有用到:\(5 \times 2 = 7\)\(8 \times 5 = 2\). 对 \(8 \times 5 \times 2\) 使用结合律,得到 \(2 \times 2 = 8 \times 7\).

这说明 \(7\)\(g^4\) 或者 \(g^6\). 若 \(7 \sim g^4\),则 \(2 \sim g\)\(2 \sim g^6\);若 \(7 \sim g^6\),则 \(2 \sim g^2\)\(2 \sim g^7\),矛盾。因此,\(7 \sim g^4\).

\(5 \times 2 = 7\),若 \(2 \sim g\),则 \(5 \sim g^3\);若 \(2 \sim g^6\),则 \(5 \sim g^8\),矛盾。因此,\(2 \sim g\)\(5 \sim g^3\)\(6 \sim g^6\).

完整的对应关系如下:

\(0\)\(1\)\(2\)\(3\)\(4\)\(5\)\(6\)\(7\)\(8\)\(9\)
\(e\)\(g^9\)\(g\)\(g^5\)\(g^2\)\(g^3\)\(g^6\)\(g^4\)\(g^8\)\(g^7\)

据此把乘法表补全即可。

答案:

\[ \begin{array} {r|rrr|rrr|rrr} 0 & 1 & 2 & 3 & 4 & 5 & 6 & 7 & 8 & 9 \\ \hline 1 & 8 & 0 & 7 & 2 & 4 & 3 & 5 & 9 & 6 \\ 2 & 0 & 4 & 6 & 5 & 7 & 9 & 3 & 1 & 8 \\ 3 & 7 & 6 & 0 & 9 & 8 & 2 & 1 & 5 & 4 \\ \hline 4 & 2 & 5 & 9 & 7 & 3 & 8 & 6 & 0 & 1 \\ 5 & 4 & 7 & 8 & 3 & 6 & 1 & 9 & 2 & 0 \\ 6 & 3 & 9 & 2 & 8 & 1 & 4 & 0 & 7 & 5 \\ \hline 7 & 5 & 3 & 1 & 6 & 9 & 0 & 8 & 4 & 2 \\ 8 & 9 & 1 & 5 & 0 & 2 & 7 & 4 & 6 & 3 \\ 9 & 6 & 8 & 4 & 1 & 0 & 5 & 2 & 3 & 7 \\ \end{array} \]


以下是作者的一些疑问:

  1. 存不存在只有 5 个已知数且有唯一解的题面?
  2. 有没有比较有效的方法构造这类题目的 \(8 \times 8\) 版本?

本章以 Llama 3 为讨论对象。

2.1 模型设计

Llama 3 的模型架构较为常规,但值得一提的是其模型尺寸的选择。Llama 3 的旗舰版本是 405B 而非常见的 70B,这一选择是经过了充分分析和论证的。

给定总计算量(这直接由预算决定),Llama 团队希望训练出一个尽可能强的模型。盲目增加参数量并不是最优解:增加参数意味着减少训练数据量,而一个欠拟合的大模型未必比一个充分拟合的较小模型更优。DeepMind 团队在 2022 年研究了该问题。这篇文章在固定总计算量的条件下训练了大量不同尺寸的 LLM,并观察到(最小化 loss 意义下的)最优模型尺寸与总计算量之间存在与数据相当吻合的经验关系。Llama 3 沿用了这一方法,但重做了其中的实验。实验得出的数据与原文有差异,但结论是一致的。405B 的选择正是根据这项数据外推得来。

图片出自 Training Compute-Optimal Large Language Models

作者曾经读到过一句话:“工程师是能用最低限度的创新达成目的的人。”Llama 3 正是这样:其成功的最主要原因并非其方法论所含的原创性,而是大量人力、算力资源的投入以及对现有 best practice 的有效整合。这样的工作是否预示着在不久的将来,深度学习领域“单打独斗”的时代将会迎来结束?这是一个引人遐想的问题。

2.2 Pre-training

Llama 3 的预训练分为三个步骤:初始训练、上下文增长和 annealing(冷却?)。

2.2.1 初始训练

训练由一个较短的预热阶段(学习率线性增长)和一个较长的主阶段(学习率余弦衰减)组成。模型初始阶段很不稳定,因此使用更低的学习率和更小的 batch size 以保证梯度在合理范围内,使模型的学习更加可控。

值得一提的是,训练数据不仅在内容上进行了多方面的把控,不同类型数据的配比也是刻意调整优化过的。得益于 scaling law,小模型上的实验结果可以较为可靠地迁移到大模型上,使得对训练数据配比的调优成为可能。展现了深度学习中炼金术的一面

2.2.2 上下文增长

由于 transformer 模型的算力消耗随输入长度是超线性增长的,以超长上下文训练会拖慢训练效率。因此,模型在初始训练阶段以 8K 上下文长度进行训练,训练好之后逐步增长到 128K。

用于监控训练进程的指标是原长度下的表现和新长度下 needle in a haystack 测试的成功率。当模型 100% 完成 needle in a haystack 任务,且在原长度下的表现恢复到训练前水平时,即认为模型适应了新的上下文长度,接下来再进行下一轮上下文增长,直到达到最终的 128K。

2.2.3 冷却

在以上两个阶段后,还会再进行一个较短的冷却阶段(学习率线性衰减)。这一阶段使用精选的高质量数据进行训练。这或许是 LLM 版的“考前冲刺”?

2.3 Post-training

经过 pre-training 后,模型具有了理解语言的能力,但它只学习了文本续写这一项任务。想要让模型顺利地和人类对话,还需要作出一定微调。

2.3.1 Instruction Tuning

首先,需要规定一种用于对话的格式,以便 LLM 知道上文的每一部分都来自于谁(系统/用户/LLM/工具...)。以 Llama 3.1 为例,一个简单的 prompt 如下:(形如 <|begin_of_text|> 的为特殊 token)

1
2
3
4
5
6
7
8
<|begin_of_text|><|start_header_id|>system<|end_header_id|>

Cutting Knowledge Date: December 2023
Today Date: 23 July 2024

You are a helpful assistant<|eot_id|><|start_header_id|>user<|end_header_id|>

What is the capital of France?<|eot_id|><|start_header_id|>assistant<|end_header_id|>

定义了对话格式后,需要在对话数据上微调 LLM。对话数据可能来自于人,也可能由已经 post-training 过的 LLM 生成。

2.3.2 偏好学习

仅仅在格式上让 LLM 适配对话是不够的。互联网上存在大量的低质量内容,也包含很多我们不希望 LLM 去模仿的行为(如恶意言论)。因此,需要让 LLM 学习在人类看来更加“正确”的行为,而非无意识地模仿互联网上的内容。

构建高质量的对话数据集是较为困难的。但是还有一种相对容易的获取人类偏好的方式:让人类比较对同一问题的两个回答孰优孰劣。模型通过某种方式的学习,提高生成较优答案的概率,降低生成较劣答案的概率,从而实现适配人类偏好的效果。

受限于作者的数学水平,本节只概括性地描述偏好学习的理念,不涉及具体细节。

一个典型的 RLHF (Reinforcement Learning from Human Feedback) 流程如下:

  1. 收集偏好数据。一条偏好数据是形如 \(\mathrm{(input,\,output\_win,\,output\_lose)}\) 的三元组。
  2. 根据偏好数据训练一个模型(通常是 LLM 附加一个分类层),用于给 \(\mathrm{(input,\,output)}\) 对打分。训练时最大化打分和偏好数据的吻合程度(给 \(\mathrm{output\_win}\) 高分,给 \(\mathrm{output\_lose}\) 低分)。这个模型被称为 reward model。
  3. 以 reward model 为指导微调模型。这一步最大化模型输出在 reward model 上的得分,同时通过一个惩罚项避免模型偏离太远。由于 reward model 并不可微,这一步无法使用梯度下降法。通常使用强化学习领域的 PPO 算法进行优化。

PPO 过程较为繁琐,需要训练辅助模型和使用相对复杂的优化算法。DPO 通过一些数学上的调整,在保留原本算法的优秀性质的同时不再需要 reward model 和强化学习,而是直接更新模型参数。DPO 的复杂性显著低于 PPO,同时性能接近或更优。

Transformer 模型通常采用三种主要架构:encoder-decoder、encoder-only 和 decoder-only。

1.1 Encoder-decoder

图片出自 Attention Is All You Need

Transformer 原始论文中设计的模型架构就是 encoder-decoder 的。Encoder 通过双向自注意力处理输入,decoder 通过单向自注意力逐个生成输出,encoder 通过互注意力向 decoder 传递信息。

Encoder-decoder 架构起源于机器翻译等输入和输出之间具有一定异质性的任务。对于这种任务,使用一个模型理解输入,另一个模型生成输出是合理的做法。然而,在 LLM 的主要任务(QA、续写、聊天等)中,输入和输出是高度同质的(它们大概率是同一种语言,且在逻辑上相承接),这时使用两个模型分别处理两部分信息不仅没有必要,还会在模型设计中引入额外的复杂性。因此,LLM 架构中 decoder-only 的占比远远高于 encoder-decoder。

1.2 Encoder-only

这类模型的典型代表为 BERT。这一模型是文本理解领域的经典 backbone。

BERT 的预训练是自监督的,包括两个任务。

较为重要的一个是预测被 mask 的 token,一种类似于 denoising autoencoder 的经典预训练方法。具体而言,输入中随机 15% 的 token 会被 mask 掉(80% 概率变为 [MASK],10% 概率变为随机 token,10% 概率不变),而模型的任务就是还原这些 token。通过这个任务,模型可以学到 token 与 token 之间的双向关系,这是 next token prediction 做不到的。

另一个任务是 next sentence prediction,即输入两个语段,预测它们是否出自同一篇文章的相邻片段。这个任务可以加强模型对语段之间关系的理解。

BERT 可以生成用于下游文本理解任务的 deep representation,但不适合用于文本生成。虽然确实存在这样的方法,但其生成过程明显比 decoder-only 模型更复杂。究其原因,BERT 被训练为利用双向信息理解语言,但生成文本的过程本质上是单向的(生成文本时,模型只知道已经生成的 token,但不知道未来的 token)。这导致朴素的生成方式用于 BERT 时效果很差。

1.3 Decoder-only

目前的绝大多数 LLM 都是 decoder-only 语言模型。这类语言模型主要由四部分组成:

  1. Tokenizer:tokenizer 负责在输入文本和 token 序列之间相互转换。token 是语言模型处理信息的最小单位。对于英语输入,token 通常是一个完整单词或较不常用单词的一部分(在 ChatGPT 的 tokenizer 中,一个 token 大概相当于 3/4 个英文单词)。可能的 token 总数大致为 \(10^5\) 量级。
  2. Embedding:embedding 层是一个可学习的表,将每个 token 映射到一个高维向量。经过 tokenizer 和 embedding 层之后,文本输入被转化为一个 \(\mathrm{num\_tokens} \times \mathrm{embed\_dim}\) 的矩阵。
  3. Transformer 网络: 这一部分包含了模型的绝大部分计算量。每个 transformer 块包含一个掩蔽多头自注意力层和一个 feed-forward network(通常是两层神经网络),配有归一化和残差连接。在 LLM 中,整个网络通常由连续数十个规模相同的 transformer 块组成。
  4. LM head:这是模型的输出层,将 transformer 网络的输出转化为下一个 token 的概率分布。推理时,LM head 的输出通过一些采样方法生成出 token 序列,再通过 tokenizer 转换为文本。

以下是 Meta-Llama-3.1-8B-InstructQwen2.5-7B-Instruct 的大致架构,可以发现两者大同小异:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
LlamaForCausalLM(
(model): LlamaModel(
(embed_tokens): Embedding(128256, 4096, padding_idx=128004)
(layers): ModuleList(
(0-31): 32 x LlamaDecoderLayer(
(self_attn): LlamaSdpaAttention(
(q_proj): Linear(in_features=4096, out_features=4096, bias=False)
(k_proj): Linear(in_features=4096, out_features=1024, bias=False)
(v_proj): Linear(in_features=4096, out_features=1024, bias=False)
(o_proj): Linear(in_features=4096, out_features=4096, bias=False)
(rotary_emb): LlamaRotaryEmbedding()
)
(mlp): LlamaMLP(
(gate_proj): Linear(in_features=4096, out_features=14336, bias=False)
(up_proj): Linear(in_features=4096, out_features=14336, bias=False)
(down_proj): Linear(in_features=14336, out_features=4096, bias=False)
(act_fn): SiLU()
)
(input_layernorm): LlamaRMSNorm((4096,), eps=1e-05)
(post_attention_layernorm): LlamaRMSNorm((4096,), eps=1e-05)
)
)
(norm): LlamaRMSNorm((4096,), eps=1e-05)
(rotary_emb): LlamaRotaryEmbedding()
)
(lm_head): Linear(in_features=4096, out_features=128256, bias=False)
)

Qwen2ForCausalLM(
(model): Qwen2Model(
(embed_tokens): Embedding(152064, 3584)
(layers): ModuleList(
(0-27): 28 x Qwen2DecoderLayer(
(self_attn): Qwen2SdpaAttention(
(q_proj): Linear(in_features=3584, out_features=3584, bias=True)
(k_proj): Linear(in_features=3584, out_features=512, bias=True)
(v_proj): Linear(in_features=3584, out_features=512, bias=True)
(o_proj): Linear(in_features=3584, out_features=3584, bias=False)
(rotary_emb): Qwen2RotaryEmbedding()
)
(mlp): Qwen2MLP(
(gate_proj): Linear(in_features=3584, out_features=18944, bias=False)
(up_proj): Linear(in_features=3584, out_features=18944, bias=False)
(down_proj): Linear(in_features=18944, out_features=3584, bias=False)
(act_fn): SiLU()
)
(input_layernorm): Qwen2RMSNorm((3584,), eps=1e-06)
(post_attention_layernorm): Qwen2RMSNorm((3584,), eps=1e-06)
)
)
(norm): Qwen2RMSNorm((3584,), eps=1e-06)
)
(lm_head): Linear(in_features=3584, out_features=152064, bias=False)
)

Decoder-only 语言模型的预训练任务为 next token prediction。具体而言,模型对每个位置预测其 token 种类的概率分布(由于 transformer decoder 使用的是掩蔽自注意力,模型预测某个位置时只能看到它之前的 token),训练目标为最大化正确文本的 log likelihood。推理与其他模型类似,逐个采样即可。

在 decoder-only 语言模型的发展过程中,积累的量变产生了质变。这一点由 GPT 系列的发展可见一斑:

  • GPT-1:模型尺寸约 0.1B,训练语料来自书籍。在完成下游任务时仍然需要微调。
  • GPT-2:模型尺寸约 1.5B,训练语料来自互联网。可以 few-shot 完成下游任务,但通常需要精心设计的 prompt。
  • GPT-3:模型尺寸最大 175B,训练语料来自经过调配的多个数据集。可以 zero-shot 完成一些任务,也能理解一般的自然语言 prompt。

TOC

h3

h4

h5

another h4

LaTeX

\[\int_{0}^{1}\!x^{-x} \mathrm{d}x = \sum_{n=1}^{\infty}n^{-n}\]

\(\int_{0}^{+\infty}\!\sin(x^2) \mathrm{d}x = \sqrt{\frac{\pi}{8}}\)

\[\mathit{mathit} \quad \mathrm{mathrm} \quad \mathcal{mathcal} \quad \mathscr{mathscr} \quad \mathbb{mathbb} \quad \mathfrak{mathfrak}\]

\[\mathit{MATHIT} \quad \mathrm{MATHRM} \quad \mathcal{MATHCAL} \quad \mathscr{MATHSCR} \quad \mathbb{MATHBB} \quad \mathfrak{MATHFRAK}\]

\[\mathit{01234} \quad \mathrm{56789} \quad \mathcal{01234} \quad \mathscr{56789} \quad \mathbb{01234} \quad \mathfrak{56789}\]

\[2.71828\,18284\,59045\,23536\,02874\,71352\,66249\,77572\,47093\,69995\,95749\,66967\,62772\,40766\,30353\,54759\,45713\,82178\,52516\,64274\]

代码块

1
2
3
4
5
6
7
8
9
10
11
12
13
(* take first n elements from list xs *)
let take n xs =
let rec take_impl acc n xs = match (n, xs) with
| (0, _) -> acc
| (_, []) -> acc
| (n, x::xs) -> take_impl (x::acc) (n-1) xs
in List.rev (take_impl [] n xs)

(* drop first n elements from list xs *)
let rec drop n xs = match (n, xs) with
| (_, []) -> []
| (0, xs) -> xs
| (n, _::xs) -> drop (n-1) xs
Copied from lipsum.com
1
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

Mermaid 图

sequenceDiagram
    Alice->>John: Hello John, how are you?
    John-->>Alice: Great!
    Alice-)John: See you later!

折叠

不要点开

Hidden text

0%