ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

AI古诗生成器实战:五言绝句数据集清洗、GPT-2续训与平仄约束

AI古诗生成器实战:五言绝句数据集清洗、GPT-2续训与平仄约束 简介一套基于Keras的AI古诗生成器完整实现面向AI爱好者、NLP学习者及创意写作人群利用LSTM与RNN算法学习古诗词规律能自动生成唐诗、五言绝句等作品并支持藏头诗、随机创作、按首句续写等灵活模式用户还可自由调节诗体形式、长度与生成概率适应从功能演示到写诗灵感激发、风格探索等多场景使用需求。资源包共11个文件压缩后约110.97MB其中5个Python脚本覆盖训练、预测与数据预处理流程1个h5预训练模型加载即用另附古诗数据集、ipynb示例笔记本、使用说明文档和训练日志配置链条完整可直接上手复现。目前已有1793人学习下载。除开箱即用外代码还支持数据集替换与语料扩充便于持续迭代优化生成效果读者在掌握循环神经网络文本生成原理的同时也能打造出更具个人风格的专属作诗模型整体兼具学习价值与趣味性。1. AI古诗生成器五言绝句这事难在让模型先学会闭嘴把“AI古诗生成器”这几个字扔进搜索引擎你会发现大部分人做的其实是“套壳调用大模型”而真正带着预训练模型、数据集、全套代码跑通唐诗五言绝句自动生成的项目少得可怜。原因不在模型在于通用大模型写现代诗还行一写格律诗就露馅平仄对不上、押韵靠缘分、二十个字里能塞进三十个字的废话。这个标题指向的是一个完整的垂直落地链——数据清洗、模型选型、续训策略、生成约束、结果验证。适合谁适合那些手里有GPU、想认真做一个能展示、能复用的古诗词生成工具的开发者。这篇笔记就按这条链讲透。2. 唐诗绝句数据集的构建清洗、切分与格式设计的四个决定2.1 数据源怎么选全唐诗库的取舍做古诗生成第一道坎不是模型而是数据。网上能拿到的全唐诗库常见有三种形态一种是带注释和作者简介的纯文本一种是结构化 JSON另一种是爬虫抓下来的网页碎片。我的建议是优先找结构化 JSON 版本字段至少得有标题和正文。纯文本版看着全其实清洗成本极高——里面有大量“同前”“又作”“卷八百零一”这类校勘残留正则写少了清不干净。数据源选好后先别急着训练做一轮粗暴过滤。五言绝句的硬条件只有一个严格四句、每句五字。用这个标准去套全唐诗能筛掉一大半。你会发现号称绝句的样本里混着六言诗、杂言诗、甚至只有两句的残句。这一步宁可错杀不可放过因为模型对句子长度的模仿能力极强——你给它看多少杂言它就敢生成长短不一的半吊子。2.2 五言绝句的切分口径与格式设计格式设计直接决定模型能不能学到结构。我一般把每首诗做成一行 JSON格式如下{title: 登鹳雀楼, poem: 白日依山尽黄河入海流。欲穷千里目更上一层楼。}这里有两个细节容易翻车。第一诗题到底保留还是丢弃我做对比实验发现保留诗题对生成效果几乎没有帮助反而会引入“这首诗写的是哪个景点”这类现代检索逻辑让模型把注意力分散到题目上。第二句间标点必须统一。全唐诗库原始的标点混乱有句号有逗号甚至有分号我统一成“逗号分句、句号结尾”的格式每个字的 tokens 数量稳定模型更容易学会五言节奏。切分训练集和验证集也有讲究。不要随机切按诗题做哈希后分桶这样同一首诗的多个版本不会跨集合出现。古诗数据集本来就小渗漏会导致验证集虚高看起来 BLEU 不错实际生成一测就塌。2.3 清洗规则去掉哪些“并不像诗”的样本全唐诗库里有些样本是编修者的批注混进了正文比如“一作明月光”这种。清洗规则我按优先级排了四层逐层压下去import re def clean_poem(text): # 第一层去掉注文和校勘内容 text re.sub(r[(](.*?)[)], , text) # 第二层只保留中文、逗号、句号 text re.sub(r[^\u4e00-\u9fa5。], , text) # 第三层按句读分割校验必须为四句 lines [l for l in text.split(。) if l.strip() and in l] if len(lines) ! 4: return None # 第四层每句严格五字 for l in lines: chars l.replace(, ) if len(chars) ! 5: return None return text第一层正则吃掉括号内的注文避免模型学到“一作”“又作”这些校勘黑话。第二层把所有非中文元素抹掉这一步能清掉数字序号和半角标点。第三层和第四层是对绝句物理结构的硬校验——字数超过或少于五直接丢弃。清洗完建议肉眼抽检 200 条重点看不认识的异体字有没有被正则误杀。生僻字不需要全部保留模型词表装不下时会被映射成 UNK训练数据里 UNK 占比超过 2% 就要考虑扩充词表或替换字。2.4 最小可用数据集多少首能训练我常被问到“只有一千首能不能训”。能出形似但上限很矮。一千首左右模型能学会“四句、每句五字、句末用句号”这个骨架但意象词汇会严重贫瘠翻来覆去就是明月、春风、青山这几个高频词。想生成有变化的句子建议目标到三千首以上。五千首量级时模型基本能自己组合出“不重复且读得下去”的绝句。如果数据量实在不够有两个补法。一是数据增强把绝句里个别字替换成近义词比如“孤舟”换“扁舟”“远山”换“青山”但替换比例控制在 20% 以内否则句子会失真。二是从原数据里做截断重组把不同诗的诗句拼成新绝句——但新诗要满足平仄无脑拼接会产生大量废料我试过性价比不高不如直接砍掉两千首也要保住干净的 2800 首。3. 预训练模型选型从 GPT-2 到专用小模型的参数对比3.1 通用中文预训练模型写古诗为什么“像话但不像诗”中文预训练模型比如 Roberta、BERT 系、通用 GPT 系在古诗文语料上表现不佳根因是领域分布漂移它们预训练时看的大部分是白话文古汉语只在极小比例语料里出现过。你把“床前明月光”喂进去模型按现代汉语的概率分布续写写出来的东西通顺、有“诗意”但一到平仄就彻底放飞。这不是玄学是分布没压住。解决思路有两种一是在古汉语语料上继续训练通用模型续训二是从零训练一个小规模古诗句模型。续训性价比高因为古诗数据集小从头练几百轮也喂不出足够的语法先验。我在实际项目里默认走续训唯一例外是小显存环境。3.2 三套可跑的模型方案与参数量做个对比表方便你按自己的显存和需求选方案参数量显存需求生成特点适合场景中文 GPT-2 继续训练约 124M8G 上下语句通顺意象丰富首选有 1080Ti 就能跑LSTM 从零训练约 20M2G 上下结构稳、押韵可控但句子呆滞显卡受限、快速出原型国产大模型 LoRA 微调7B 以上20G语义好平仄仍难控追求词汇丰富度硬件充足我一般首选 124M 的 GPT-2。这个量级在古诗这种高约束低多样性任务上足够而且生成速度可以做到毫秒级部署成本低。LSTM 是给没显卡的读者留的后路——它不会爆炸但你得接受它的句子像“复读机”这个现实。LoRA 调 7B 大模型我也试过语义确实好但平仄问题依旧存在需要靠后处理强制约束等于把生成器的责任甩给了过滤器。3.3 基于 GPT-2 继续训练的最小命令用 transformers 加载中文 GPT-2 继续训练代码比想象中短。核心就是加载模型、加载数据、跑 Trainerfrom transformers import AutoTokenizer, AutoModelForCausalLM, Trainer, TrainingArguments tokenizer AutoTokenizer.from_pretrained(uer/gpt2-chinese-cluecorpus-small) model AutoModelForCausalLM.from_pretrained(uer/gpt2-chinese-cluecorpus-small) training_args TrainingArguments( output_dir./poem-gpt2, per_device_train_batch_size8, gradient_accumulation_steps4, num_train_epochs30, learning_rate2e-5, logging_steps20, save_steps500, warmup_steps100, fp16True, ) trainer Trainer( modelmodel, argstraining_args, train_datasettrain_dataset, ) trainer.train()这里几个参数是古诗续训的关键learning_rate不能开大2e-5 已经是上限古诗数据量小lr 大了会把预训练学到的词法知识冲掉num_train_epochs我设 30 是因为数据少但每 5 轮就手动存一次档方便回退到中间的过拟合状态gradient_accumulation_steps4是为了用小 batch 凑出稳定的梯度显存不够时这个数往上加。训练时长方面单张 1080Ti 跑 3000 首诗30 个 epoch 大约两到三个小时完全在可接受范围内。训练完不要只看 loss下一步生成端才是真正检验模型的地方。4. 训练与生成损失函数、Beam Search、平仄韵脚怎么落地4.1 训练目标不只是交叉熵续训时默认的损失是语言模型交叉熵但古诗有一种特殊现象模型学得很快loss 掉得漂亮生成出来却是一堆“看似五言、实则空转”的组合比如“春风吹绿水绿水照春风”。问题出在交叉熵只负责逐字概率不管句间的押韵和平仄结构。我常用的做法是保留交叉熵为主损失同时用一个轻量的辅助损失预测每句末字的韵母类别。具体来说把绝句每句的最后一个字单独挖出来映射到韵母编号比如“光”“霜”“乡”都归到 ang 韵作为辅助分类目标。代码实现不复杂在模型的语言模型头之外再接一个小分类头两个 loss 按 0.9 和 0.1 加权求和。这个辅助头能强制模型在隐层里保留“句末押韵”这个结构信息实测对押韵率的提升非常直接。4.2 Beam Search 的宽度设置推理阶段我默认用 Beam Search 而不是贪心解码。贪心解码出来的诗太平滑Beam 可以保留多个候选再挑。宽度太高也不用——古诗只有二十个字搜索空间被结构约束压得很窄宽度 6 到 8 基本够用from transformers import AutoTokenizer, AutoModelForCausalLM tokenizer AutoTokenizer.from_pretrained(./poem-gpt2) model AutoModelForCausalLM.from_pretrained(./poem-gpt2).cuda() prompt 窗前明月光 input_ids tokenizer.encode(prompt, return_tensorspt).cuda() gen_ids model.generate( input_ids, max_new_tokens24, num_beams8, no_repeat_ngram_size2, repetition_penalty1.2, do_sampleFalse, ) print(tokenizer.decode(gen_ids[0]))max_new_tokens24是把后半句 15 个字、两个标点和可能的结束符都算进去的余量no_repeat_ngram_size2禁止任意两个连续字重复出现这是防“床前床前明月光”这种复读的保险丝repetition_penalty1.2进一步压低重复字概率。注意do_sample保持 False古诗生成要的是确定性和结构稳定性采样会让平仄检查形同虚设。4.3 韵律约束怎么加先验过滤Beam Search 解决的是“通顺”平仄和押韵得靠生成后的过滤。标准五言绝句的平仄格式有四种最常见的“仄起不入韵”式是仄仄平平仄平平仄仄平。 平平平仄仄仄仄仄平平。我的落地做法是让模型拿 20 组 prompt 各生成一批候选然后用平仄检测脚本筛掉不匹配的剩下的按押韵质量排序。这里的关键是别指望模型自己学会平仄——它偶尔能蒙对几首但正确率不稳定过滤器才是保底。from pypinyin import lazy_pinyin, Style def get_tone(char): return lazy_pinyin(char, styleStyle.TONE3, errorsdefault)[0][-1] def check_flat_oblique(line, pattern): tones [get_tone(c) for c in line if c not in 。] if len(tones) ! len(pattern): return False return all(t in 12 for t, p in zip(tones, pattern) if p 平) and \ all(t in 34 for t, p in zip(tones, pattern) if p 仄)Style.TONE3返回带声调数字的拼音比如“平”返回“ping3”取末位字符就是声调数字。判断逻辑很简单普通话阴平阳平算平声上声去声算仄声。但有个边界要留意入声字在《平水韵》里归仄普通话里可能读平声检测会误判。我一般接受这个误差至少保证现代读音下的平仄结构想更严格就得维护一张入声字表。4.4 预训练模型 全量微调 vs LoRA用 124M 的模型做全量微调显存和速度都没压力这是首选。我不会在古诗这种垂直且数据量很小的任务上无脑套大模型 LoRA理由很简单数据太少7B 模型的大部分参数在古诗任务上是“无关容量”微调后容易产生语义澎湃但格律崩坏的句子。如果你就是想在 7B 模型上做 LoRA注意两点rank 不要超过 16数据量决定了扛不住太高秩学习率控制在 1e-4 量级避免把底座模型的现代文本能力完全覆盖掉。我实测下来7B LoRA 出来的诗在“想象力”上确实比 124M 强但平仄达标率反而低一截所以我会把 7B 的输出全部丢给过滤器二次筛选生成量翻倍才能得到同样数量的合格品成本并不低。5. 古诗生成器常见问题排查五个真实踩坑记录5.1 现象loss 降到 0.4生成却全是“空山不见人、空山不见人”式复读这是一开始最容易遇到的坑。损失降得漂亮说明模型已经把训练语料里的热门诗句背下来了但它没有学到“组织新句子”的能力。原因很简单古诗数据集太小而“床前明月光”“白日依山尽”这些名句在语料里比重极高模型背下来就能把交叉熵刷得很低。解决办法分三层。第一层是数据端对语料做高频句降权重复出现超过三次的句子从训练集里按概率剔除。第二层是推理端no_repeat_ngram_size设到 2repetition_penalty提到 1.3。第三层是结构端做 n-gram 覆盖度检查解码时如果某个 2-gram 已经出现两次直接抑制对应分支的概率。三层都做了复读现象能压到 5% 以下。5.2 现象五言诗生成了七言甚至四言六言混搭模型偶尔会输出“春风吹绿江南岸明月照我还”这种句长失控的结果。原因大概率是训练数据的清洗没过硬数据里混入了七言绝句或者词牌模型学到的是“字数不定”的错误先验。另一个隐蔽原因是标点处理不一致——有的句子逗号后没有正常断句模型把两句话拼在了一起。解决第一把清洗脚本的第四层校验做成硬规则不满足五字直接丢不网开一面。第二推理端把max_new_tokens卡死在 24配合在生成结果里按“”“。”分割任何一句超过五字就丢弃重来。第三看看验证集生成结果里句长的分布如果方差仍然很大回数据池里看一眼有没有漏网的杂言诗。5.3 现象训练集上平仄达标率 95%生成集一测只有 50%这个翻车最伤士气。排查之后发现原因有三一是多音字处理错误“教”“骑”这类字在不同词境下声调不同按固定读音挂到平仄上必然出错二是模型在生成时偶发吐字错误把一个合理的字替换成了不合理的同形字三是训练集评估用了原文做输入模型相当于开卷考试。解决把平仄检测对多音字只取最常见读音宁紧勿松生成端做两轮过滤第一轮用检测脚本第二轮用生成内容重新分词后再测一遍最关键的是在验证阶段只信任“从零 prompt 生成出来”的样本绝不用训练语料里的诗做评测。血的教训是拿训练集测韵律没有任何参考价值。5.4 现象数据集里混入“不是诗”的样本训练出来的句子有些像对联我遇到过清洗脚本不够严时属对工整但不像绝句的文本混进训练集比如“天对地雨对风”这种《笠翁对韵》残片。模型学到的是“两句对称就行”完全丢掉了绝句“起承转合”的叙事结构。解决清洗规则里加一条结构校验——后两句必须和前三句形成语义承接关系这用规则写不完但至少可以做一个启发式判定后一句不能和第一句读起来像对子。另外把数据集里标题含“对韵”“蒙学”的样本全部删掉。这一坑的根治方法只有一个抽 500 条训练样本肉眼查一遍发现有结构异类立刻止损。5.5 现象训练中途 loss 突然变 NaN或直接显存溢出最神秘的灵异事件是 loss 变 NaN。排查第 1 步就是看数据里有没有 NaN 字符或者超长字符串我碰到的原因是有一行 poem 字段是空数组加载后 label 全为空梯度炸了。第 2 步是降低学习率到 1e-5 试跑 100 步看是否稳定。显存溢出则是 batch size 和序列长度没算好古诗文本短单条序列不会超过 64 token所以问题通常出在per_device_train_batch_size调太高、优雅地撞上显存上限。解决数据加载时做空值过滤dataset dataset.filter(lambda x: len(x[poem]) 20)训练参数里加gradient_clippingtraining_args TrainingArguments(..., max_grad_norm1.0)降 batch、开梯度累积、锁max_grad_norm这三招基本能把 NaN 和 OOM 同时压住。别忘了训练日志前 50 步盯紧 loss 曲线连续不降或猛涨直接 CtrlC 改参数不要觉得是自己玄学。6. 末章交出一首能用的绝句得过四道关真正敢拿出去展示的模型不是“loss 最低的那个”而是“通过四道关比例最高的那个”。我每一版训练完都会跑同一个批量测试给定 50 个不同的起句各生成 20 首然后过四个筛子。第一道字数关严格四句每句五字第二道平仄关按标准格式套一遍第三道押韵关至少二、四句尾字落在同一韵母第四道语义关人工读一遍看有没有明显语病。前两道用脚本自动跑第三道可以半自动第四道只能靠人。def autocheck(text): lines text.split(。) lines [l for l in lines if l.strip()] # 字数关 if len(lines) ! 4: return 0 if any(len(l.replace(, )) ! 5 for l in lines): return 0 # 平仄关简化版只测每句第二、四、五字 key_patterns [仄平平, 平仄仄, 平仄平, 仄仄平] for i, l in enumerate(lines): if get_tone(l[1] if len(l) 1 else 平) not in 12 and key_patterns[i % 4][0] 平: return 0 return 1这里只是示意实际脚本会把押韵、平仄、字数全部展开做成 HTML 表格人工审阅直接在表里打分。我自己的习惯是每个候选打出四个维度分然后算加权总分字数占 20%、平仄占 30%、押韵占 30%、语义占 20%。模型迭代时只看总分不单看某一个指标提升。最后一句话是我这几年做古诗生成器最想强调的教训不要迷信 loss不要迷信预训练模型自带的“才气”古诗生成这事九成功夫在数据清洗和生成后的格律过滤上。模型选型只是金字塔塔尖塔基是你能把多少首干净的五言绝句喂进去你敢不敢在生成端写出第四道关。先把前三道关用脚本焊死再谈让模型自由发挥。希望帮到你。本文还有配套的精品资源点击获取
返回列表