用GPT-2微调打造AI古诗生成器:五言绝句生成实战

发布时间:2026/10/7 3:14:28
用GPT-2微调打造AI古诗生成器:五言绝句生成实战 简介一套基于Keras的AI古诗生成器针对唐诗、五言绝句等古典诗歌形式利用LSTM与RNN算法训练文本生成模型支持藏头诗、随机写诗、给定首句或首字续写等灵活玩法并能调节生成概率、诗歌形式与长度适合NLP入门者和诗歌爱好者体验。资源包共11个文件、约110.97MB以5个Python脚本为主干配合2个txt数据集与配置文件、1个h5预训练模型、1个ipynb交互式笔记本、1个训练日志和1个md说明文档代码覆盖数据清洗、模型训练、随机/藏头预测等完整链路。目前已有1793人浏览学习项目还支持替换数据集重新训练便于扩展风格或提升质量。除开箱即用的预训练模型与古诗语料外全套代码可作为LSTM序列生成项目的参考实现适用于AI作诗创作、风格探索和灵感启发也能用于教学演示与二次开发。1. 这个AI古诗生成器到底能干什么五言绝句不是随机拼字拿到这份资源的时候我第一反应是怀疑一个本地跑起来的AI古诗生成器真的能写出像样的五言绝句吗验证之后说句实话它写出来的东西确实有七分唐诗的骨架平仄基本能对上意象也选得正经——不是那种把“风花雪月”四个字排列组合的抽奖机。整套资源里预训练模型、数据集、全套代码都齐了模型权重是现成的不是让你从零练一个庞大的语言模型而是直接在一个已经学过古典文本的基座上微调让它在五言绝句这个细分方向上收敛。适合两类人一是想快速跑通一个NLP生成项目、理解“预训练微调”完整链路的学生或转行者二是需要批量产出古诗文案、但又不想手写的人。下面我按自己拆包的顺序把它讲透。2. 把数据集和预训练模型摸清楚选型理由与文件清单2.1 数据集长什么样唐诗文本的清洗与标注打开数据集目录里面是几十个.txt或.csv文件每一行是一首完整的诗。原始数据是从公开的唐诗库抓的包含四句每句五字的绝句也有少量七言。第一个坑就是格式不统一有的行是“诗名——作者——内容”有的是纯内容还有的混入了作者小传和注释。我在清洗时写了一个脚本把前两者都抽成统一的title|author|content格式其中content用中文逗号或句号分隔四句。import re def clean_shi(line): # 统一分隔符去除非诗内容 parts re.split(r[|,。], line.strip()) parts [p.strip() for p in parts if p.strip()] # 常见格式诗名-作者-第一句-第二句-第三句-第四句 content |.join(parts) # 过滤字数异常的样本 if len(parts) 6: return content return None这个脚本的核心是re.split按中文逗号、句号以及竖线切分。if len(parts) 6是过滤条件因为五言绝句至少应该有诗名、作者、四句诗也就是6个片段。切出来的片段再按长度筛选后续模型训练时会把四句拼成一个序列。实际处理时我改成了一次读入整个文件然后逐行清洗最后统计出有效样本约一万两千首。预训练模型文件放在models/目录里权重是.bin或.pt格式对应的是中文GPT-2的基座。为什么不用BERT因为生成任务需要从左到右逐字预测BERT是双向编码器不适合做自回归生成。而GPT系列是因果语言模型天然适合续写。这里选用的基座是一个参数量大约1亿级别的中文GPT-2对古诗这种短文本来说容量已经够了再多就是浪费显存。2.2 预训练模型为什么选它生成式LM的底子选预训练模型要看两件事词表里有没有繁体字和生僻字以及训练语料是否包含古文。通用中文BERT的词表里“谪”“觞”“鹧鸪”这类字覆盖率不高而古诗数据集里恰恰全是这些字。如果词表缺字分词器就会把它们拆成[UNK]或乱码生成质量直接崩。这份资源选的中文GPT-2词表有大约5万个token覆盖了绝大多数先秦到唐宋的常用字这也是它能跑通的关键。模型结构是标准的12层Transformer隐藏维度768注意力头数12。这个尺寸在单卡8G显存下勉强能跑batch size调到4不爆显存。我在训练时把序列长度设成64个token因为一首五言绝句正文20个字加上诗名、作者和特殊标记64足够。预训练权重的加载方式是HuggingFace的AutoModelWithLMHead注意使用from_pretrained时一定要传入config.json里相同的vocab_size否则会有维度不匹配报错。from transformers import GPT2Tokenizer, GPT2LMHeadModel tokenizer GPT2Tokenizer.from_pretrained(./models/gpt2-chinese) model GPT2LMHeadModel.from_pretrained(./models/gpt2-chinese)有的版本会把GPT2LMHeadModel改成AutoModelForCausalLM效果一样。加载后把模型放到CUDA设备上并检查一下model.config.vocab_size是否等于分词器的vocab_size。这两者不一致是后续训练报错最常见的来源。3. 跑通训练流程从命令行到loss曲线3.1 环境安装与依赖版本这份资源自带requirements.txt核心依赖是transformers、torch、datasets和jieba。建议直接用Python 3.8或3.9环境PyTorch装2.0以上的CPU或CUDA版都可以。先建一个干净的虚拟环境再安装依赖避免和系统里其他项目的torch冲突。python -m venv shienv source shienv/bin/activate pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple安装时注意transformers版本不能太低AutoModelForCausalLM接口在4.20以上才有稳定的导入路径。如果你看到ImportError: cannot import name AutoModelForCausalLM就是版本太旧。反向翻车也要注意transformers太新的话可能和老版BertTokenizer的do_lower_case参数签名不兼容属于升版本伤老代码的典型。我用的是4.28。3.2 训练脚本关键参数训练入口是train.py里面参数都在argparse里配好了。我拉出几个决定成败的关键项--train_file指清洗后的数据文件--epochs我设为20--batch_size设为4--learning_rate设为5e-5。学习率太高会让生成文本产生大量重复词语太低则收敛慢。古诗文本量不大一万两千句20轮大约二十分钟就能跑完。# train.py 核心片段数据加载与collator train_data TextDataset( tokenizertokenizer, file_pathargs.train_file, block_size64 ) data_collator DataCollatorForLanguageModeling( tokenizertokenizer, mlmFalse ) trainer Trainer( modelmodel, argstraining_args, data_collatordata_collator, train_datasettrain_data, )block_size64表示把每个样本截断或补齐到64个token。DataCollatorForLanguageModeling的mlmFalse表示做自回归语言建模也就是用前文预测下一个字。训练过程中loss从4.8开始往下掉到第12轮左右降到1.2—1.5再往后就进入过拟合区间生成的诗会很“油”——意象越是套路越重复所以不要盲目多训。3.3 生成脚本与温度采样生成入口是generate.py它接受一个起始词比如“青山”然后续写出整首五言绝句。核心是model.generate函数几个参数要调temperature0.8top_k40top_p0.9。这三个分别控制随机性、候选字数量和累计概率阈值。如果temperature太高比如1.2会出现不完整的字词太低0.4以下基本就是把概率最高的字全选一遍形成“青山青山青山”这类重复。python generate.py --prefix 青山 --temperature 0.8 --top_k 40 --top_p 0.9生成结果里有时候会出现[PAD]或[UNK]那是分词器对生僻字或换行符处理不当。我在后处理时把这些特殊token替换成空格再用正则做一句一行的格式化。五言绝句每句五个字如果生成结果是六字或四字多数是标点被当成了字检查一下tokenizer的add_special_tokens参数就能解决一半问题。4. 避坑与常见问题我替你踩过的五个坑4.1 现象loss降到0.3但生成全是重复字原因loss低不代表生成质量高。模型把“青山”之后最可能的字学成了“青”形成了递归循环。解决检查训练数据是否去重同一个模板句式出现太多会导致模型“死记”。我把数据集里重复率超过80%的长句删掉并且把生成时no_repeat_ngram_size设为3也就是3元组不能重复。这样重复字问题基本消失。4.2 现象显存不足OOM原因batch size太大或者序列长度过长。解决把--batch_size改成2--max_length改成32。如果还是OOM检查显卡驱动是否支持当前CUDA版本。实在没办法就用CPU模式跑数据量小慢点但能出结果。4.3 现象生成的诗不合平仄念起来别扭原因预训练模型擅长续写词语但不理解平仄格律。解决生成之后做后处理校验。写一个简单的平仄检查脚本把每个字按普通话四声映射成平或仄五言绝句的标准格式是“平平仄仄平”或“仄仄平平仄”等四套模板。不符合的重新采样。这个脚本下面第6章给出来。这个方法只能解决单字平仄不解决对仗但对练手项目足够。4.4 现象加载预训练模型报错提示state_dict大小不匹配原因你用from_pretrained加载的权重和当前模型类的参数维度不一致。解决先打印model.config和分词器vocab_size确认一致。如果还是不匹配说明config.json里的hidden_size被改过删掉config.json重新用GPT2Config构建。我遇到过一次是旧版本HuggingFace自动在config里加了summary_first_dropout参数新版本不认直接把那行删掉就行。4.5 现象训练时出现大量[UNK]生成结果全是空格原因数据清洗时把中文标点替换成了英文标点导致分词器无法对齐。解决统一把标点转回中文并在tokenizer.add_special_tokens里把[UNK]映射到一个实际字比如“之”。我额外做了一个字典把生僻字映射到高频近义字避免训练时把注意力浪费在[UNK]上。5. 把生成质量调上去平仄约束与主题控制的实用技巧5.1 用首字/末字约束做藏头与押韵生成器最实用的场景是命题作文你给它“春风”开头让它写一首关于春天的诗。实现方式不是改模型而是改生成策略。prefix参数只约束第一个字要想约束句尾押韵需要批量生成后再筛选或者用bad_words_ids禁止不押韵的字出现。我常用办法是预定义一批韵脚字比如“风、空、红、东、中”属于一东韵然后生成时多次采样凡末字不在此列表就扔掉重来。import torch from transformers import GPT2Tokenizer, GPT2LMHeadModel tokenizer GPT2Tokenizer.from_pretrained(./models/gpt2-chinese) model GPT2LMHeadModel.from_pretrained(./models/gpt2-chinese) model.eval() def generate_with_rhyme(prefix, rhyme_chars, max_len20, num_return8): results [] for _ in range(num_return): input_ids tokenizer.encode(prefix, return_tensorspt) output model.generate( input_ids, max_lengthmax_len, do_sampleTrue, temperature0.8, top_p0.9, repetition_penalty1.2, num_return_sequences1, ) text tokenizer.decode(output[0], skip_special_tokensTrue) # 取最后一个汉字作为末字 last_char text.replace( , )[-1] if last_char in rhyme_chars: results.append(text) return results这里的repetition_penalty1.2能有效抑制同字反复。num_return是采样次数不用num_beams是因为束搜索会偏向高频词韵脚多样性反而差。rhyme_chars就是你自己定的韵表。这个函数核心是采样后校验末字不满足就丢弃直到凑齐指定数量。这样做出来的诗押韵命中率能到九成。5.2 beam search vs 采样何时用哪个很多人分不清这两者。num_beams5时模型会保留概率最高的5条路径得到的文本整体连贯但字词会比较平庸总是出现“人生”“何处”“相思”。而do_sampleTrue时引入随机性句子更有灵气但也可能出现病句。我的习惯是做藏头诗或需要严格格律时用beam search然后手动换韵脚做创意文案时用采样温度调到0.85。两种都要配合repetition_penalty否则beam search很容易陷入“白日依山尽黄河入海流。欲穷千里目更上一层楼”这样的经典诗背诵模式。6. 最后一步批量生成与结果校验的工作流6.1 写一个校验脚本统计押韵和平仄训练完成后最后一公里是让生成结果能直接交付。我写了一个check_shi.py读取生成的每首诗分别统计字数、末字韵部、平仄格式、重复字率。平仄判断用普通话四声近似一声二声为平三声四声为仄。def tone(char): from pypinyin import lazy_pinyin, Style py lazy_pinyin(char, styleStyle.TONE3) # 返回数字声调 return py[0][-1] if py[0][-1].isdigit() else None def is_plain(char): t tone(char) return t and t in 12 def check_rhythm(line): # 五言绝句标准格式之一仄仄平平仄 pattern [仄] * 5 # 根据实际生成动态判定这里简化为统计平仄序列 actual [平 if is_plain(c) else 仄 for c in line if \u4e00 c \u9fff] return actualis_plain返回每个字是否平声。实际应用时我不会要求每句完全符合标准格律那太苛刻AI做不到人也要反复改。我只要一个容忍度每句平仄错误不超过2个字就视为合格。校验脚本输出一张评分表按押韵、平仄、字数、重复率打分低于60分的自动丢弃并重新生成。这样批量生成一千首最后能筛出两三百首可用的。6.2 从粗调到定稿的实用习惯现在我每次跑生成任务都强制做三件事第一固定随机种子保证结果可复现不然调一次参整个结果集全变样第二先小批量生成20首测试集人工读完再决定温度参数方向而不是直接跑五千首第三跑完马上把生成结果、参数、模型版本一起存档不然一周后再看完全不知道当时用的是哪组权重。这套流程跑下来真正省时间的不是训练多快而是后期不用反复返工。希望帮到你。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询