Skip to content

Commit 5a0ce3c

Browse files
committed
new post: gpt2 training
1 parent c34578d commit 5a0ce3c

1 file changed

Lines changed: 248 additions & 0 deletions

File tree

Lines changed: 248 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,248 @@
1+
---
2+
categories: [machine learning]
3+
tags: [ai]
4+
mathjax: true
5+
---
6+
7+
# 基于GPT2的古诗生成器:LLM训练入门
8+
9+
本项目在了解Transformer基本原理的基础上,从零构建一个会写诗的大语言模型,走通从预训练到监督微调的全流程,见证模型从牙牙学语到像模像样创作诗词的进化过程。核心目标不是训练一个"最强古诗生成器",而是**通过实操理解LLM训练的每一个环节**
10+
11+
本项目着眼于工程应用,因此不准备从零构建Transformer模型,而是基于HuggingFace生态,直接复用其已经封装好的模型和训练逻辑,从而更多专注于数据集构建、模型配置和训练参数。
12+
13+
本项目所有代码在[国家超算互联网](https://www.scnet.cn/)免费提供试用的 64GB 显存异构加速卡上运行,特此感谢。
14+
15+
https://github.com/dothinking/llm_learning
16+
17+
## 项目全景:一条完整的LLM训练流水线
18+
19+
大模型训练的典型流程包括三个阶段:预训练、监督微调(全量SFT、LoRA)和对齐/偏好微调(例如DPO)。预训练让模型“会说人话”(掌握诗词的语言规律),监督微调让模型“听懂人话”(理解对话指令),偏好微调则进一步让模型“说得好听”(对齐人类偏好)。
20+
21+
```
22+
┌────────┐
23+
│ SFT ┼──────────────┐
24+
│ SFT │ │
25+
└────▲───┘ │
26+
│ │
27+
┌──────────┐ ┌───────────┐ ┌───────┴──────┐ ┌──────▼────┐
28+
│ poetry │ │ tokenizer │ │ pre-training │ │ alignment │
29+
│ dataset ┼───► BPE ┼───► GPT2 ┼────► DPO │
30+
└──────────┘ └───────────┘ └───────┬──────┘ └──────▲────┘
31+
│ │
32+
│ │
33+
┌────▼───┐ │
34+
│ SFT │ │
35+
│ LoRA ┼──────────────┘
36+
└────────┘
37+
```
38+
39+
40+
| 阶段 | 目标 | 输入 → 输出 | 核心能力 |
41+
|------|------|------------|---------|
42+
| **预训练** | 学习语言的统计规律 | 诗句前半段 → 续写后半段 | 格律、韵律、常见意象搭配 |
43+
| **SFT** | 学会遵循指令 | "写一首思乡诗" → 完整的诗 | 指令理解、按需创作 |
44+
| **LoRA** | 高效复现SFT效果 | 同上 | 仅训练2.13%参数达到同等效果 |
45+
| **DPO** | 提升生成质量 | 好诗 vs 差诗 → 偏好对齐 | 风格优化、质量提升 |
46+
47+
48+
本项目目录结构:
49+
50+
```
51+
llm-learning/
52+
├── dataset/ # 数据集
53+
│ ├── dataset/poetry.csv # 预训练数据集
54+
│ └── dataset/sft.csv # SFT数据集
55+
├── pre_training/ # 预训练:分词器 + GPT2训练
56+
│ ├── train_tokenizer.py # 训练BPE分词器
57+
│ ├── train.py # 预训练主脚本
58+
│ ├── chat.py # 推理对话
59+
│ └── final_model/ # 预训练产出
60+
├── sft/ # 监督微调
61+
│ ├── train.py # SFT训练脚本
62+
│ ├── chat.py # 推理对话
63+
│ └── final_model/ # SFT产出
64+
├── lora/ # LoRA微调
65+
│ ├── train.py # LoRA训练脚本
66+
│ ├── chat.py # 推理对话
67+
│ └── final_model/ # LoRA适配器权重
68+
├── dpo/ # 偏好对齐(TODO)
69+
└── chat.py # 统一Web界面(FastAPI)
70+
```
71+
72+
73+
## 技术选型
74+
75+
本项目基于 PyTorch 和 HuggingFace 生态构建,这是目前LLM开发的事实标准。
76+
77+
| 角色 | 具体工具/库 | 用途 |
78+
|------|------------|------|
79+
| 底层框架 | PyTorch | 张量计算与自动微分 |
80+
| 模型调用 | Transformers | 模型加载、训练和推理 |
81+
| 数据处理 | Datasets | 高效加载CSV/JSON数据集 |
82+
| 分词技术 | Tokenizers | 训练自定义BPE分词器 |
83+
| 参数高效微调 | PEFT (LoRA) | 低秩适配器微调 |
84+
| 偏好优化 | TRL (DPO) | 直接偏好优化训练 |
85+
86+
动手实践之前,需要先准备好环境:
87+
88+
```bash
89+
pip install torch>=2.1.0
90+
pip install transformers>=4.40.0
91+
pip install datasets>=2.18.0
92+
pip install tokenizers>=0.19.0
93+
pip install peft>=0.10.0
94+
pip install trl>=0.8.0
95+
pip install accelerate>=0.28.0
96+
```
97+
98+
## 数据集构建
99+
100+
中国历史上留下了海量古诗词,开源社区已经整理好了85万+首的结构化数据,省去了数据清洗的繁琐工作。再加上个人对诗词的一点兴趣,因此选择古诗生成这个场景作为学习的起点。古诗有明确的格律约束(押韵、对仗、字数),但又允许一定的创作自由度。一个72M参数的小模型就能生成"像模像样"的作品,学习的正反馈来得很快。
101+
102+
本项目使用了 GitHub 上的三个开源数据集:
103+
104+
|| 数据集 | 规模/首 | 用途 |
105+
|--------|------|------|------|
106+
|1| [Werneror/Poetry](https://github.com/Werneror/Poetry) | 85万+ | 预训练(学习诗词语言规律) |
107+
|2| [xiu-ze/Poetry](https://github.com/xiu-ze/Poetry) | 101万+ | SFT数据集构造(含体裁、作者标签) |
108+
|3| [yuting-wei/CCPD](https://github.com/yuting-wei/CCPD) | 1.7万+ | SFT数据集构造(含主题、情感标签) |
109+
110+
### 预训练数据
111+
112+
从数据集1的CSV文件中提取纯诗文本,数据格式如下(训练时只使用了`content`列的诗词正文)。
113+
114+
```csv
115+
title,dynasty,author,content
116+
赠歌者杜氏入道三首 其三,元,潘纯,云髻高梳鬓不分,扫除虚室事元君...
117+
七岁游法兴寺,元,胡天游,山色摇光入袖凉,松阴十丈印回廊...
118+
```
119+
120+
### SFT数据集
121+
122+
基于数据集2和数据集3的原始数据,构造了三类指令-回答对。数据格式统一为:
123+
124+
```csv
125+
instruction,answer
126+
创作一首思乡诗,客里春光又可怜,客怀乡思总凄然。风尘未扫燕南地,雨雪偏深蓟北天。...
127+
仿写李白的诗,头陀悬万仞,远眺望华峰。聊借金沙水,洗开九芙蓉。...
128+
```
129+
130+
| 指令类型 | 示例 | 来源 |
131+
|---------|------|------|
132+
| 体裁创作 | "以白日依山尽为出句,续写绝句/律诗" | 数据集2子集的5.4万+唐诗中随机选取绝句和律诗共计2万条 |
133+
| 主题创作 | "以思乡为主题,写一首诗/绝句/律诗" | 数据集3主题、多标签排列组合得到的3.9万+条记录中随机选取2万条 |
134+
| 诗人仿写 | "仿写李白的诗" | 数据集2子集的5.4万+唐诗中选取13位著名诗人作品共计9256条 |
135+
136+
137+
138+
## 模型配置
139+
140+
以上诗词数据集的量级并不是很大,因此参考 GPT2-small 的规模选择了下表所示的模型参数。这个配置比标准GPT2-small(124M)更轻量,但保留了完整的Transformer架构,即便消费级GPU也可轻松完成训练。
141+
142+
| 参数 || 说明 |
143+
|------|-----|------|
144+
| 总参数量 | 72.26M | 标准GPT2-small为124M |
145+
| 隐藏层维度 | 768 | 与标准GPT2-small一致 |
146+
| Transformer层数 | 8 | 标准GPT2-small为12层 |
147+
| 注意力头数 | 12 | 与标准GPT2-small一致 |
148+
| 最大序列长度 | 256 | 一首诗+指令足够,标准GPT2-small为1024 |
149+
| 词表大小 | 20,001 | 自定义BPE分词器 |
150+
151+
152+
## 模型效果
153+
154+
最后,在深入技术细节之前,先直观感受一下各阶段模型的输出效果。
155+
156+
### 预训练模型:诗句接龙
157+
158+
预训练模型只会"续写"——给它一个开头,它顺着往下编。虽然有些句子略显生硬,但整体上确实学到了古诗的统计规律,或多或少能够感受到**押韵、对仗、意象**这些诗词元素。
159+
160+
> **输入**
161+
> 落霞与孤鹜齐飞
162+
>
163+
> **输出**
164+
>
165+
> 落霞与孤鹜齐飞,近渚连洲锦绮围。若待他年垂钓处,秋风还到钓鱼矶。
166+
>
167+
> 水静天青万象开,中流击楫独登台。不知黄鹤楼边月,能照当年霸楚才。
168+
>
169+
> 漠漠蒹葭水拍天,烟波浩荡水连天。不知身在潇湘后,多少人家在枕边。
170+
>
171+
> 秋风袅袅白蘋洲,杜若香中一钓舟。一片青山无别恨,数声何处起边愁。
172+
>
173+
> 万里秋风下洞庭,五湖波浪正冥冥。月明吹笛...
174+
175+
176+
即便给预训练模型一条指令,它也无法理解指令的含义,只能机械地进行“接龙”。
177+
178+
> **输入**
179+
>
180+
> 写一首塞外风光律诗
181+
>
182+
> **输出**
183+
>
184+
> 写一首塞外风光律诗,一肩行李去如飞。
185+
>
186+
> 江山满目非吾土,岁月催人两鬓丝。
187+
>
188+
> 客里光阴如转毂,镜中华发已盈丝。
189+
>
190+
> 他年准拟从公醉,莫待秋霜白接䍦。
191+
>
192+
> 身行万里无长策,志在三边岂异人。
193+
>
194+
> 千里家山归梦遥,百年天地白头新。
195+
>
196+
> 春风杨柳堪行乐,夜雨芭蕉可寄人。
197+
>
198+
> 他日相思问消息,为言留滞又经春。
199+
>
200+
> 十年前此复同庚,老去那堪百感生。
201+
>
202+
> 壮志未能忘魏阙,壮心犹未...
203+
204+
### SFT模型:按指令创作
205+
206+
经过监督微调后,模型学会了"听指令"。
207+
208+
> **输入**
209+
>
210+
> 写一首塞外风光律诗
211+
>
212+
> **输出**
213+
>
214+
> 将军曾射石壕前,今日胡天识汉年。
215+
>
216+
> 万里关山随汉节,十年烽火照甘泉。
217+
>
218+
> 风悲瀚海吹边月,雪暗天山落塞烟。
219+
>
220+
> 此去单于应未灭,汉家恩泽又经年。
221+
222+
223+
模型理解了"塞外风光"的主题要求,生成了"关山"、"烽火"、"瀚海"、"天山"、"单于"等典型边塞意象;同时也理解了“律诗”的体裁要求,押韵、颔联颈联的对仗、平仄(虽然还不完美)都有体现。
224+
225+
### LoRA模型:同等效果,仅训练2.13%参数
226+
227+
> **输入**
228+
>
229+
> 写一首塞外风光律诗
230+
>
231+
> **输出**
232+
>
233+
> 北塞连秦望,南临瀚海清。
234+
>
235+
> 天围平野阔,云接大荒平。
236+
>
237+
> 铁骑寒嘶月,雕戈夜啸城。
238+
>
239+
> 谁怜羁旅客,辛苦恋浮名!
240+
241+
LoRA模型仅训练了约 **154万** 参数(占总参数的2.13%),就达到了与全量SFT相当的效果。
242+
243+
244+
## 总结
245+
246+
本文概述了基于GPT2的古诗生成器项目全貌。项目基于HuggingFace生态,使用85万+首古诗词完成预训练,构造4.9万条指令-回答对进行监督微调,完整走通了LLM训练的核心流程。72M参数的迷你GPT2即便在消费级GPU上也能轻松完成全部训练:预训练模型学会了诗句接龙,SFT模型具备了按主题、体裁、诗人风格创作的能力,LoRA模型仅训练2.13%参数便达到同等效果。
247+
248+
接下来三篇文章将逐一深入每个阶段的技术细节。例如,下一篇将开启 **预训练** :喂85万首诗词,让BPE分词器"认识"汉字,让GPT2模型从"牙牙学语"进化到具备"诗句接龙"的能力。

0 commit comments

Comments
 (0)