资讯动态

MixPoet复现全记录:Windows 11下GPT-2可控诗歌生成实战

发布时间:2026/9/28 14:15:17 来源:尧图企业网站定制
简介面向AI写诗与中文自然语言处理方向的研究者、开发者和爱好者提供基于清华大学MixPoet项目在Windows11环境下的完整训练代码与可用模型。压缩包中既包含训练好的模型权重pkl/pickle、Python源码py/pyc与JSON/XML配置也带有sample样例文本、png可视化结果及Git仓库元数据从模型加载、诗歌生成到结果展示均有现成文件便于快速验证SOTA级写诗效果。全套资源共102个文件压缩包约260MB目录保留完整项目工程结构和版本提交信息方便对比不同训练配置与代码迭代其中pkl/pickle是训练好的模型产物可直接调用完成文本生成txt/json涵盖语料与配置sample目录则给出模型输出样例帮助理解生成质量。目前已有322人学习下载适合具备一定Python基础、希望复现或微调中文诗歌生成模型的研究者和开发者。无论是快速体验生成效果还是基于已有权重深入二次开发都能从中获得完整参考。1. 从论文到能跑通的 MixPoet我在 Windows 11 上的一次完整复现MixPoet 是清华大学开源的 AI 写诗项目SOAT 效果这个词被提得很多但大多数人第一次下载仓库后卡在环境配置而不是模型原理上。这个项目基于 GPT-2 架构用可控诗歌生成框架Controllable Poetry Generation Framework实现五言、七言律诗和绝句的生成核心是两个层次的训练目标先让 LLM1-CFG 学会句内词语搭配再让 LLM2-CFG 学会句间语义连贯。我拿到项目后在 Windows 11 上用 RTX 3060 复现了完整流程从数据预处理到训练再到调用推理接口写诗耗时约两天。这篇文章把每一步的可执行命令、参数含义和踩过的坑写清楚适合想真正把模型跑起来而不是停留在读论文阶段的 NLP 从业者。2. 认识仓库结构与文本预处理LLM1-CFG 和 LLM2-CFG 到底分工做什么2.1 仓库里的核心文件与训练管线MixPoet 的仓库从表面看非常精简甚至有点简陋——没有庞大的 docs 目录核心就是几个 Python 文件和数据文件夹。我第一次 clone 下来后用 Tree 命令扫了一遍结构发现真正决定训练行为的只有config配置文件、data数据目录和两个模型训练脚本。训练管线分两阶段LLM1-CFG 处理的是「词级别」的诗歌生成它学会的是在一个句子内部哪些词可以出现在哪些位置LLM2-CFG 处理的是「句级别」的生成它的输入是整个前一句输出是下一句。这种分层方式在诗歌生成里非常关键因为五言律诗每句五个字词的搭配是否自然决定了诗的第一观感。tree /F /A . | findstr /V .gitMixPoet ├── config │ ├── config_LLM1_CFG.json │ └── config_LLM2_CFG.json ├── data │ ├── all_data │ ├── couplet_train.jsonl │ └── poetry_train.jsonl ├── generate.py ├── main.py ├── model.py └── preprocess.py这段命令在 Windows 11 的 cmd 或 PowerShell 里都能运行/F参数让 tree 列出所有文件路径/A用文本符号代替图形线条避免在某些终端里出现乱码。findstr /V .git是 Windows 下的过滤命令等价于 Linux 的grep -v用来把.git目录排除掉。我建议读者拿到仓库后先执行这一步确认数据文件是否齐全。2.2 数据预处理的逻辑从 jsonl 到 masked 序列MixPoet 的训练数据核心格式是 jsonl每一行是一条完整的 JSON包含诗句的原始文本和对应的韵律标注。数据处理脚本会把一首诗拆成 token 序列然后按照 LLM1-CFG 和 LLM2-CFG 的需求分别构造训练样本。LLM1-CFG 的样本是「词 位置掩码」模型需要学会的是在已知前几个字的情况下预测下一个位置的字LLM2-CFG 的样本是「前句 后句」模型需要学会的是根据上一句的语义生成下一句。python preprocess.py --data_path data/poetry_train.jsonl --output_dir data/all_data --task LLM1预处理脚本的参数需要特别注意--task参数决定了切分方式LLM1 模式会按句内词序构造训练对LLM2 模式会按句间顺序构造训练对。两个任务必须分别执行因为生成的训练样本格式完全不同。我在 Windows 11 上执行时遇到过一个问题数据文件路径如果包含中文Python 的 open 函数在默认编码下可能报UnicodeDecodeError解决方式是在调用脚本前先设置环境变量set PYTHONUTF81 python preprocess.py --data_path data/poetry_train.jsonl --output_dir data/all_data --task LLM1PYTHONUTF81会让 Python 解释器在 Windows 上强制使用 UTF-8 编码读写文件。这是 Windows 平台特有的坑Linux 和 macOS 上很少遇到。预处理完成后data/all_data目录下会出现经过 token 化的训练样本文件后续训练脚本会从这些文件里读取数据。2.3 参数配置读懂 config 文件里的每一个字段config_LLM1_CFG.json 这个文件决定了小模型的训练方式。第一次打开时我对着字段逐个查发现它和标准 GPT-2 的配置非常接近只是多了一个特殊的cft控制字段。这个字段的值是一个整数取值范围一般是 0 到 3它告诉模型当前生成任务属于哪种诗歌类型——是五言绝句、五言律诗、七言绝句还是七言律诗。这个控制代码在训练时会被拼接在输入序列的最前面让模型在生成时能区分不同格式的要求。{ n_ctx: 512, n_embd: 768, n_head: 12, n_layer: 6, cft: 1, cft_vocab_size: 4, batch_size: 4, learning_rate: 5e-5 }n_ctx是上下文窗口长度512 意味着模型最多能看到 512 个 tokenn_embd是词向量的维度n_layer是 Transformer 的层数——这个值在 LLM1 配置里只有 6 层比 GPT-2 small 的 12 层少一半因为句内词序任务相对简单用更浅的网络可以显著减少训练时间。cft_vocab_size必须和数据预处理时生成的类型数量一致否则训练脚本会在词表映射阶段报下标越界错误。我刚开始没注意这个字段把 cft 值设成了 8训练直接崩了报错信息是index out of range in self排查了很久才发现是这里的问题。3. 从零训练 LLM1-CFG 小模型Windows 11 下的显存管理与训练曲线解读3.1 环境依赖安装顺序的细节Windows 11 安装深度学习环境比 Linux 更容易翻车因为 CUDA 版本和 PyTorch 版本的兼容矩阵非常严格。MixPoet 项目使用的是 PyTorch 1.8 左右的版本这个版本官方支持的最高 CUDA 是 11.1。我一开始直接装了最新版的 PyTorch 2.x结果运行main.py时报了算子不存在或者不匹配的错误。后来重新安装了 CUDA 11.1 和对应版本的 PyTorch 才恢复正常。conda create -n mixpoet python3.8 conda activate mixpoet pip install torch1.8.1cu111 torchvision0.9.1cu111 --extra-index-url https://download.pytorch.org/whl/cu111python3.8是 MixPoet 项目能用 Python 3.9 跑但 3.8 最稳。--extra-index-url参数指定了 PyTorch 的 CUDA 11.1 预编译 wheel 包所在源地址。这里有一个 Windows 特有的问题如果显存小于 6GB建议把 batch_size 调成 2并且在训练脚本里加上torch.cuda.empty_cache()的调用否则连续迭代几十步后显存碎片会让 OOM 错误越来越频繁。3.2 训练启动命令与日志关键指标解读LLM1-CFG 模型的训练入口是main.py通过--config参数指定配置文件。训练开始后控制台会每秒输出一次损失值和困惑度perplexity。我自己的经验是前 500 步内损失值如果从 10 以上下降到 5 以下说明数据预处理没有问题模型在学习有效的词序规律如果损失值在某个数值附近抖动超过 2000 步不下降优先检查学习率是否过大——5e-5 是安全的起点但如果显存较小导致 batch size 减半学习率最好同步降到 3e-5。python main.py --config config/config_LLM1_CFG.json --mode train --output_dir output/llm1--mode train指定当前运行训练流程--output_dir是模型检查点保存目录。训练过程中每个 epoch 结束时会保存一个 checkpoint 文件命名格式类似model_epoch_3_step_1200.pt。我建议不要覆盖保存因为 LLM2-CFG 的训练需要加载 LLM1-CFG 的完整权重如果中途发现 LLM1 训练得不够好回退到之前的 checkpoint 重新训练比从头再来省时间。3.3 训练中断恢复Windows 下的 CtrlC 与 checkpoint 续训训练中途断掉是常事特别是用电高峰期Windows 的显卡驱动可能因为供电不稳直接重置 CUDA 上下文报错信息通常是CUDA error: unspecified launch failure。这时不用慌main.py支持从 checkpoint 恢复训练命令如下python main.py --config config/config_LLM1_CFG.json --mode train --resume output/llm1/model_epoch_3_step_1200.pt --output_dir output/llm1--resume参数接受一个 checkpoint 文件路径加载后会从该 step 继续训练而不是从头开始。这里有个细节值得注意恢复训练时学习率调度器也会恢复但如果你在中断前手动调低过学习率checkpoint 里记录的是调整前的学习率这会导致恢复后损失值突然上升。我一般在中断恢复后观察 100 步如果损失值反弹超过 1.5 倍就在命令行里手动覆盖学习率。4. LLM2-CFG 训练与可控生成让模型学会「上一句决定下一句」4.1 LLM2-CFG 的输入构造与训练目标差异LLM1-CFG 跑通后LLM2-CFG 才是 MixPoet 真正的重头戏。它要解决的是句间连贯性问题——前一句说「春风又绿江南岸」下一句不能接「铁马冰河入梦来」虽然单句都很优美但放在一起语义断裂。LLM2-CFG 的训练样本由连续的上下句构成输入序列是「前句 分隔符 后句」模型需要预测后句的所有 token同时控制代码 cft 仍然保留在最前面。python preprocess.py --data_path data/poetry_train.jsonl --output_dir data/all_data --task LLM2 python main.py --config config/config_LLM2_CFG.json --mode train --output_dir output/llm2--task LLM2生成的是句间配对样本样本数量比 LLM1 少一半因为一首诗里句对的数量远小于句内词对的数量。这也意味着 LLM2-CFG 训练更容易过拟合尤其是当数据量不足时loss 会降到很低但生成的诗句千篇一律。我一般会在配置里把batch_size调小同时把n_layer调大——LLM2 的配置里层数通常是 8 层因为句间语义建模比句内词序复杂得多。4.2 负样本的策略CFG 训练中「补集」含义MixPoet 使用 CFGControllable Poetry Generation而非普通的语言模型训练关键区别在于它需要同时学习「好诗的分布」和「坏诗的分布」。LLM2-CFG 的训练数据里除了正样本语义连贯的前后句对还有负样本——随机拼接的上下句、韵律不合的句对。模型要学会区分这两者生成时才不会被带偏。# 负样本构造逻辑常见做法 if random.random() 0.15: next_line random.choice(all_lines) else: next_line paired_line这段伪代码展示的是常见的数据增强方式每 100 个训练样本里大约 15 个样本的下一句会被替换成随机句子。这个比例不是固定的我调过 0.1 到 0.3 之间的几个值发现 0.15 在 BLEU 和人工评审两个维度上表现最均衡。替换比例过高模型会变得过于保守生成的诗句就像四字成语接龙缺少新意比例过低模型又学不会拒绝不连贯的接续。如果你想快速验证负样本比例的影响可以先训练 500 步然后分别用 0.1 和 0.3 的配置各训练 500 步对比生成结果的语义跳跃程度。4.3 两阶段训练的顺序依赖与伪代码实现严格来说LLM1-CFG 和 LLM2-CFG 是两个独立训练的模型但 LLM2 在训练时会加载 LLM1 的编码器参数作为初始化。这个设计不是必须的但能加快 LLM2 的收敛速度因为句间语义判断需要的字面理解能力已经被 LLM1 学会了。实际执行的顺序是先完整训练 LLM1保存最好的 checkpoint然后在 LLM2 的main.py启动命令里通过--model_path指定 LLM1 的权重。python main.py --config config/config_LLM2_CFG.json --mode train --model_path output/llm1/model_best.pt --output_dir output/llm2--model_path参数指定的是预训练权重路径脚本会自动把该权重中与 LLM2 结构匹配的层加载进来。这里有一个易错点LLM1 的层数是 6LLM2 的层数是 8如果两者配置差异过大权重加载会跳过不匹配的层只加载 embedding 层的参数。我实际测试下来加载 embedding 层对收敛速度的提升已经足够明显不匹配的层从头训练也完全可以接受。这个阶段训练时间明显更长RTX 3060 12G 显存的情况下每 1000 步耗时约 18 分钟完整训练到平稳需要 6 到 8 小时。5. 避坑指南Windows 11 上复现 MixPoet 的 5 个高频翻车现场5.1 中文路径导致编码崩溃现象数据集放在D:\我的数据\poetry_train.jsonl执行preprocess.py时报错UnicodeDecodeError: gbk codec cant decode byte。原因Windows 11 的 Python 默认使用系统区域设置编码中文系统是 GBK而 JSONL 文件是 UTF-8 编码open 函数没有显式指定 encoding 参数时就会用 GBK 读取。解决在代码文件开头加上import sys; sys.stdout.reconfigure(encodingutf-8)数据读取时显式声明open(path, encodingutf-8)。最稳妥的方式是把数据路径改成纯英文比如D:\mixpoet_data\poetry_train.jsonl。5.2 CUDA out of memory 在训练中段突然出现现象训练前 1000 步一切正常第 1200 步突然报CUDA out of memory显存占用监控显示还在持续增长。原因PyTorch 的显存分配器在 Windows 上不会主动向系统归还不再使用的显存块多个 epoch 之间如果有 batch 大小波动显存碎片化会让实际可用显存越来越少。解决在训练循环的每个 epoch 结束时调用torch.cuda.empty_cache()并检查是否有变量在循环外被意外持有引用。另外把 batch_size 从 4 降到 2给显存留出 20% 的余量基本能避免这个问题。5.3 Windows 的换行符 \r 引发数据错位现象预处理完成后生成的训练样本里出现大量空行模型 loss 不下降。原因Linux 下编辑的数据文件是 LF 换行Windows 的某些编辑器如记事本打开并保存后会变成 CRLF导致每行末尾多出一个\r字符切分 token 时产生空项。解决预处理脚本里读取数据后执行line line.replace(\r, ).strip()或者用 PowerShell 批量转换文件格式Get-ChildItem .\data\*.jsonl | ForEach-Object { (Get-Content $_.FullName -Raw).Replace(rn, n) | Set-Content $_.FullName -NoNewline -Encoding UTF8 }5.4 预训练模型加载报错 shape mismatch现象LLM2 训练加载 LLM1 权重时报size mismatch for word_embeddings.weight: copying a param with shape torch.Size([vocab_size, 768]) from checkpoint, the shape in current model is torch.Size([vocab_size4, 768])。原因LLM2 的控制代码数量可能和 LLM1 不一致或者预处理任务不同导致词表末尾追加了特殊 token检查点形状与当前模型不匹配。解决确认两个配置文件里的cft_vocab_size字段一致都是 4。不一致时统一后重新预处理数据不要手动修改权重张量。5.5 显存充足但训练速度极慢现象GPU 利用率只有 30% 左右CPU 占用 100%loss 下降非常慢。原因DataLoader 的num_workers在 Windows 上默认是 0数据加载完全在主进程执行GPU 大部分时间在等数据。解决在main.py里找到 DataLoader 初始化处把num_workers设为 2 或 4并加上if __name__ __main__保护。Windows 的多进程数据加载不支持在交互式环境里运行脚本方式启动不受影响。dataloader DataLoader( dataset, batch_sizeconfig[batch_size], shuffleTrue, num_workers2, pin_memoryTrue )pin_memoryTrue让数据加载到固定内存页减少 CPU 到 GPU 的拷贝时间。这两个参数改完后训练速度在我机器上提升了约 1.8 倍。6. 把现有模型变成写诗服务推理接口与韵律控制参数的调优习惯模型训练完成后generate.py是直接面对用户的推理脚本。它支持两种写诗模式给定首句续写整诗以及给定关键词直接生成。推理时的核心参数有三个temperature 控制随机性top_k 控制候选词范围cft 控制诗歌体裁。我实际测试过temperature0.8, top_k40是平衡质量和新意的最佳区间低于 0.5 时生成的诗句过于保守经常出现重复词语高于 1.2 时句子开始出现不通顺的搭配。python generate.py --model_path output/llm2/model_best.pt --cft 1 --first_line 春风又绿江南岸 --temperature 0.8 --top_k 40--cft 1表示七言绝句格式--first_line是用户给定的人机交互首句。生成的结果是一个完整的文本块包含题目、正文和韵律标注信息。我自己最常用的验证方法是把生成的诗句逐句标注平仄检查是否符合近体诗的格律规则——如果三连平或者三连仄超过两次说明模型的韵律控制还不够精确需要调整负样本比例或者增加训练epoch。从使用习惯来说我现在每次生成完都会保留一份「体裁 温度 top_k 生成结果」的对照记录。刚开始嫌麻烦后来发现同一组参数生成的诗歌在这一版模型和下一版模型上的表现差很多没有对照记录就很难判断是参数问题还是模型退化了。这个习惯帮我定位过三次明显的训练事故其中两次是数据预处理跑飞导致一次是学习率设置过大。从那以后我每次重训模型前都强制走一遍「先备份旧的配置文件和数据预处理脚本」的流程改任何参数前也先记下基线输出。希望这些在 Windows 11 上复现 MixPoet 的路径和参数经验能帮你少走弯路直接把精力放在诗歌生成的效果调优上。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑