基于GPT2的古诗生成器:LLM训练入门¶
发布于:2026-05-01 | 分类:machine learning
本项目在了解Transformer基本原理的基础上,从零构建一个会写诗的大语言模型,走通从预训练到监督微调的全流程,见证模型从牙牙学语到像模像样创作诗词的进化过程。核心目标不是训练一个"最强古诗生成器",而是**通过实操理解LLM训练的每一个环节**。
本项目着眼于工程应用,因此不准备从零构建Transformer模型,而是基于HuggingFace生态,直接复用其已经封装好的模型和训练逻辑,从而更多专注于数据集构建、模型配置和训练参数。
本项目所有代码在国家超算互联网免费提供试用的 64GB 显存异构加速卡上运行,特此感谢。
https://github.com/dothinking/llm_learning
项目全景:一条完整的LLM训练流水线¶
大模型训练的典型流程包括三个阶段:预训练、监督微调(全量SFT、LoRA)和对齐/偏好微调(例如DPO)。预训练让模型“会说人话”(掌握诗词的语言规律),监督微调让模型“听懂人话”(理解对话指令),偏好微调则进一步让模型“说得好听”(对齐人类偏好)。
┌────────┐
│ SFT ┼──────────────┐
│ SFT │ │
└────▲───┘ │
│ │
┌──────────┐ ┌───────────┐ ┌───────┴──────┐ ┌──────▼────┐
│ poetry │ │ tokenizer │ │ pre-training │ │ alignment │
│ dataset ┼───► BPE ┼───► GPT2 ┼────► DPO │
└──────────┘ └───────────┘ └───────┬──────┘ └──────▲────┘
│ │
│ │
┌────▼───┐ │
│ SFT │ │
│ LoRA ┼──────────────┘
└────────┘
| 阶段 | 目标 | 输入 → 输出 | 核心能力 |
|---|---|---|---|
| 预训练 | 学习语言的统计规律 | 诗句前半段 → 续写后半段 | 格律、韵律、常见意象搭配 |
| SFT | 学会遵循指令 | "写一首思乡诗" → 完整的诗 | 指令理解、按需创作 |
| LoRA | 高效复现SFT效果 | 同上 | 仅训练2.13%参数达到同等效果 |
| DPO | 提升生成质量 | 好诗 vs 差诗 → 偏好对齐 | 风格优化、质量提升 |
本项目目录结构:
llm-learning/
├── dataset/ # 数据集
│ ├── dataset/poetry.csv # 预训练数据集
│ └── dataset/sft.csv # SFT数据集
├── pre_training/ # 预训练:分词器 + GPT2训练
│ ├── train_tokenizer.py # 训练BPE分词器
│ ├── train.py # 预训练主脚本
│ ├── chat.py # 推理对话
│ └── final_model/ # 预训练产出
├── sft/ # 监督微调
│ ├── train.py # SFT训练脚本
│ ├── chat.py # 推理对话
│ └── final_model/ # SFT产出
├── lora/ # LoRA微调
│ ├── train.py # LoRA训练脚本
│ ├── chat.py # 推理对话
│ └── final_model/ # LoRA适配器权重
├── dpo/ # 偏好对齐(TODO)
└── chat.py # 统一Web界面(FastAPI)
技术选型¶
本项目基于 PyTorch 和 HuggingFace 生态构建,这是目前LLM开发的事实标准。
| 角色 | 具体工具/库 | 用途 |
|---|---|---|
| 底层框架 | PyTorch | 张量计算与自动微分 |
| 模型调用 | Transformers | 模型加载、训练和推理 |
| 数据处理 | Datasets | 高效加载CSV/JSON数据集 |
| 分词技术 | Tokenizers | 训练自定义BPE分词器 |
| 参数高效微调 | PEFT (LoRA) | 低秩适配器微调 |
| 偏好优化 | TRL (DPO) | 直接偏好优化训练 |
动手实践之前,需要先准备好环境:
pip install torch>=2.1.0
pip install transformers>=4.40.0
pip install datasets>=2.18.0
pip install tokenizers>=0.19.0
pip install peft>=0.10.0
pip install trl>=0.8.0
pip install accelerate>=0.28.0
数据集构建¶
中国历史上留下了海量古诗词,开源社区已经整理好了85万+首的结构化数据,省去了数据清洗的繁琐工作。再加上个人对诗词的一点兴趣,因此选择古诗生成这个场景作为学习的起点。古诗有明确的格律约束(押韵、对仗、字数),但又允许一定的创作自由度。一个72M参数的小模型就能生成"像模像样"的作品,学习的正反馈来得很快。
本项目使用了 GitHub 上的三个开源数据集:
| 数据集 | 规模/首 | 用途 | |
|---|---|---|---|
| 1 | Werneror/Poetry | 85万+ | 预训练(学习诗词语言规律) |
| 2 | xiu-ze/Poetry | 101万+ | SFT数据集构造(含体裁、作者标签) |
| 3 | yuting-wei/CCPD | 1.7万+ | SFT数据集构造(含主题、情感标签) |
预训练数据¶
从数据集1的CSV文件中提取纯诗文本,数据格式如下(训练时只使用了content列的诗词正文)。
title,dynasty,author,content
赠歌者杜氏入道三首 其三,元,潘纯,云髻高梳鬓不分,扫除虚室事元君...
七岁游法兴寺,元,胡天游,山色摇光入袖凉,松阴十丈印回廊...
SFT数据集¶
基于数据集2和数据集3的原始数据,构造了三类指令-回答对。数据格式统一为:
instruction,answer
创作一首思乡诗,客里春光又可怜,客怀乡思总凄然。风尘未扫燕南地,雨雪偏深蓟北天。...
仿写李白的诗,头陀悬万仞,远眺望华峰。聊借金沙水,洗开九芙蓉。...
| 指令类型 | 示例 | 来源 |
|---|---|---|
| 体裁创作 | "以白日依山尽为出句,续写绝句/律诗" | 数据集2子集的5.4万+唐诗中随机选取绝句和律诗共计2万条 |
| 主题创作 | "以思乡为主题,写一首诗/绝句/律诗" | 数据集3主题、多标签排列组合得到的3.9万+条记录中随机选取2万条 |
| 诗人仿写 | "仿写李白的诗" | 数据集2子集的5.4万+唐诗中选取13位著名诗人作品共计9256条 |
模型配置¶
以上诗词数据集的量级并不是很大,因此参考 GPT2-small 的规模选择了下表所示的模型参数。这个配置比标准GPT2-small(124M)更轻量,但保留了完整的Transformer架构,即便消费级GPU也可轻松完成训练。
| 参数 | 值 | 说明 |
|---|---|---|
| 总参数量 | 72.26M | 标准GPT2-small为124M |
| 隐藏层维度 | 768 | 与标准GPT2-small一致 |
| Transformer层数 | 8 | 标准GPT2-small为12层 |
| 注意力头数 | 12 | 与标准GPT2-small一致 |
| 最大序列长度 | 256 | 一首诗+指令足够,标准GPT2-small为1024 |
| 词表大小 | 20,001 | 自定义BPE分词器 |
模型效果¶
最后,在深入技术细节之前,先直观感受一下各阶段模型的输出效果。
预训练模型:诗句接龙¶
预训练模型只会"续写"——给它一个开头,它顺着往下编。虽然有些句子略显生硬,但整体上确实学到了古诗的统计规律,或多或少能够感受到**押韵、对仗、意象**这些诗词元素。
输入: 落霞与孤鹜齐飞
输出:
落霞与孤鹜齐飞,近渚连洲锦绮围。若待他年垂钓处,秋风还到钓鱼矶。
水静天青万象开,中流击楫独登台。不知黄鹤楼边月,能照当年霸楚才。
漠漠蒹葭水拍天,烟波浩荡水连天。不知身在潇湘后,多少人家在枕边。
秋风袅袅白蘋洲,杜若香中一钓舟。一片青山无别恨,数声何处起边愁。
万里秋风下洞庭,五湖波浪正冥冥。月明吹笛...
即便给预训练模型一条指令,它也无法理解指令的含义,只能机械地进行“接龙”。
输入:
写一首塞外风光律诗
输出:
写一首塞外风光律诗,一肩行李去如飞。
江山满目非吾土,岁月催人两鬓丝。
客里光阴如转毂,镜中华发已盈丝。
他年准拟从公醉,莫待秋霜白接䍦。
身行万里无长策,志在三边岂异人。
千里家山归梦遥,百年天地白头新。
春风杨柳堪行乐,夜雨芭蕉可寄人。
他日相思问消息,为言留滞又经春。
十年前此复同庚,老去那堪百感生。
壮志未能忘魏阙,壮心犹未...
SFT模型:按指令创作¶
经过监督微调后,模型学会了"听指令"。
输入:
写一首塞外风光律诗
输出:
将军曾射石壕前,今日胡天识汉年。
万里关山随汉节,十年烽火照甘泉。
风悲瀚海吹边月,雪暗天山落塞烟。
此去单于应未灭,汉家恩泽又经年。
模型理解了"塞外风光"的主题要求,生成了"关山"、"烽火"、"瀚海"、"天山"、"单于"等典型边塞意象;同时也理解了“律诗”的体裁要求,押韵、颔联颈联的对仗、平仄(虽然还不完美)都有体现。
LoRA模型:同等效果,仅训练2.13%参数¶
输入:
写一首塞外风光律诗
输出:
北塞连秦望,南临瀚海清。
天围平野阔,云接大荒平。
铁骑寒嘶月,雕戈夜啸城。
谁怜羁旅客,辛苦恋浮名!
LoRA模型仅训练了约 154万 参数(占总参数的2.13%),就达到了与全量SFT相当的效果。
总结¶
本文概述了基于GPT2的古诗生成器项目全貌。项目基于HuggingFace生态,使用85万+首古诗词完成预训练,构造4.9万条指令-回答对进行监督微调,完整走通了LLM训练的核心流程。72M参数的迷你GPT2即便在消费级GPU上也能轻松完成全部训练:预训练模型学会了诗句接龙,SFT模型具备了按主题、体裁、诗人风格创作的能力,LoRA模型仅训练2.13%参数便达到同等效果。
接下来三篇文章将逐一深入每个阶段的技术细节。例如,下一篇将开启 预训练 :喂85万首诗词,让BPE分词器"认识"汉字,让GPT2模型从"牙牙学语"进化到具备"诗句接龙"的能力。