ARTICLE DETAIL

资讯详情

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

Python古诗生成器源码拆解:BERT模型训练与Flask Web部署实战

Python古诗生成器源码拆解:BERT模型训练与Flask Web部署实战 简介本资源是一套基于Python的古诗生成器完整源码面向文学爱好者、编程学习者与AI技术入门开发者帮助读者在体验古诗创作的同时理解自然语言处理与前后端协作的基本流程。压缩包共43个文件、约10.85MB以7个Python脚本为核心涵盖数据加载、模型定义、训练与诗词评估等模块另有5个XML配置、5个CSS样式、5个JavaScript脚本及HTML页面构成前端界面与交互逻辑并配有字体、图片、文本说明与项目配置文件目录结构清晰。目前已有324人学习下载。读者可获得一套可直接运行、便于二次开发的前后端一体项目既能观察古诗生成算法的组织方式也能参考界面设计与模块划分思路适合作为课程实践或兴趣练手素材。1. 拆开这份 43 文件的古诗生成器它到底能跑出什么前阵子有个做语文教具的朋友问我有没有那种「输入几个字就能续出一首五言绝句」的小系统最好还能挂在网页上给学生玩。我翻了一圈最后盯上这份基于 Python 的古诗生成器源码。它不是那种只丢一个generate.py的玩具而是把后端推理和前端页面一起打包了43 个文件里7 个 Python 脚本负责数据、模型、训练、评估5 个 JavaScript 和 5 个 CSS 撑起网页交互还带了一份chinese_L-12_H-768_A-12的 BERT 配置目录。换句话说它是一套「能训练、能推理、能展示」的完整链路而不是一段孤立的算法。适合谁想入门 NLP 但被 Transformer 吓退的 Python 学习者可以拿它当第一个能看见输出的项目做传统文化类小工具的前端同学可以直接复用它的页面骨架至于只想体验「AI 写诗」的文学爱好者跑通app.py就能在浏览器里点着玩。下面我按「先搞懂结构、再动手跑、最后避坑」的顺序把这份源码拆给你看。2. 文件结构与技术栈7 个 Python 脚本各自扛什么活2.1 从目录树反推数据流拿到一个压缩包我习惯先不急着装依赖而是把目录扫一遍判断它的运行链路。这份源码的顶层大致是这样分布的ancient-poetry-generator/ ├── app.py # Web 应用入口Flask 起服务 ├── train.py # 模型训练脚本 ├── eval.py # 生成效果评估 ├── model.py # 模型结构定义 ├── dataset.py # 数据集加载与预处理 ├── utils.py # 通用工具函数 ├── settings.py # 全局配置 ├── requirements.txt # 依赖清单 ├── poetry.txt # 古诗语料 ├── chinese_L-12_H-768_A-12/ │ ├── bert_config.json │ └── vocab.txt ├── templates/ │ └── index.html # 前端页面模板 └── static/ ├── js/ # fishc.js / layer.js / jquery.min.js / run.js └── css/ # fishc.css / layui 相关样式这条链路很清楚dataset.py读poetry.txt做分词和序列化model.py定义网络train.py调用前两者完成训练并把权重落盘eval.py单独验证生成质量最后app.py加载权重、渲染index.html前端用run.js发请求把结果贴回页面。utils.py和settings.py是横切模块前者放文本清洗、padding 之类的函数后者集中管理路径、超参。理解了这个顺序后面调哪个文件心里就有数了。2.2 依赖与运行环境怎么定requirements.txt是判断项目年代的第一个线索。这类基于 BERT 的古诗项目常见依赖是tensorflow1.x 或 2.x 的 compat 模式、flask、numpy、jieba之类。我一般不会直接pip install -r而是先看版本约束再决定用虚拟环境还是 conda。# 建一个隔离环境避免污染系统 Python python -m venv venv source venv/bin/activate # Windows 用 venv\Scripts\activate # 先看依赖清单里锁了哪些版本 cat requirements.txt # 确认无误后再安装 pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple这里的关键参数是-i换成国内镜像能明显减少超时。逻辑说明先建虚拟环境是为了让 TensorFlow 这种体积大、版本敏感的库不跟系统里其他项目打架先cat再装是为了避免清单里写死了某个老版本、而你机器上已经有新版本导致冲突。如果requirements.txt里没有锁版本我通常会手动补一个tensorflow2.x的约束因为 BERT 的bert_config.json对 TF 版本比较挑。2.3 前端集成的实现方式很多人以为「前端集成」是前后端分离调 API但这份源码走的是更轻的路子Flask 的render_template直接吐index.html页面里的run.js用 Ajax 把用户输入 POST 给后端后端生成完再返回 JSON。static/js下的jquery.min.js和layer.js负责交互和弹层layui提供 UI 组件fishc.js大概率是项目自己的业务脚本。// run.js 里典型的请求逻辑示意 function generatePoetry() { const seed $(#seedInput).val(); // 取用户输入的开头 $.ajax({ url: /generate, // 对应 app.py 里的路由 type: POST, contentType: application/json, data: JSON.stringify({ text: seed, max_len: 50 }), success: function (res) { $(#result).text(res.poetry); // 把生成结果写回页面 }, error: function () { layer.msg(生成失败检查后端是否启动); } }); }逻辑说明seed是用户给的开头几个字max_len控制生成长度后端拿到后走模型推理。参数上max_len设太小会只续一两个字设太大又容易跑偏成重复句我一般从 30 到 50 之间试。这段代码的价值在于它把「模型」和「页面」解耦了——你换掉后端模型前端几乎不用动。3. 从零跑通数据准备、训练与 Web 启动3.1 语料格式与 dataset.py 的预处理poetry.txt是整个项目的燃料。这类古诗语料通常是「一行一首」的纯文本dataset.py要做的是读入、按字切分、建立字表、转成 id 序列。我见过不少人直接拿带标点、带标题的原始文本往里塞结果模型学出一堆逗号句号。# dataset.py 里预处理的核心思路示意 def load_poetry(path): lines [] with open(path, r, encodingutf-8) as f: for line in f: line line.strip() if not line: continue # 只保留汉字过滤标点和空白 line .join(ch for ch in line if \u4e00 ch \u9fff) if len(line) 10: # 太短的句子丢掉 lines.append(line) return lines def build_vocab(lines): chars sorted(set(.join(lines))) char2id {ch: i 1 for i, ch in enumerate(chars)} # 0 留给 padding return char2id逻辑说明\u4e00 ch \u9fff是汉字 Unicode 区间用它过滤掉标点和英文len(line) 10是经验阈值太短的残句对训练没帮助。char2id从 1 开始编号把 0 留给 padding这是序列任务里的常规做法。参数上如果你的语料里混了繁体或生僻字这个区间要相应放宽否则会被误删。3.2 train.py 的关键超参怎么设训练脚本是这份源码里最需要耐心的地方。BERT 类模型在普通机器上跑全量微调很吃力所以常见做法是冻结底层、只训练顶层或者干脆用一个小型 LSTM 做生成头。# 启动训练示意具体参数以 train.py 的 argparse 为准 python train.py \ --data_path poetry.txt \ --bert_config chinese_L-12_H-768_A-12/bert_config.json \ --vocab chinese_L-12_H-768_A-12/vocab.txt \ --batch_size 32 \ --epochs 20 \ --learning_rate 2e-5 \ --max_seq_len 64逻辑说明batch_size受显存限制32 是 8G 显存左右的保守值learning_rate用2e-5是 BERT 微调的经典量级设成1e-3会直接训崩max_seq_len决定单句最大长度古诗一般 64 够用。如果训练时 loss 一直不降先查学习率是不是太大再查语料是不是没洗干净。epochs不用贪多古诗语料重复度高20 轮左右就能看出效果再多容易过拟合。3.3 app.py 起服务与前端联调训练完权重落盘后app.py负责把它加载起来并提供 Web 接口。启动方式和普通 Flask 项目一样# 确保权重文件路径和 settings.py 里一致 python app.py # 默认一般跑在 http://127.0.0.1:5000逻辑说明app.py里通常有一个/路由渲染index.html一个/generate路由处理生成请求。启动前要确认settings.py里的模型路径指向你训练出来的权重否则会报找不到文件。前端联调时如果页面能打开但点生成没反应先按 F12 看 Network 里/generate的返回码——500 多半是后端加载模型失败404 则是路由没对上。提示第一次跑建议先用小批量语料比如从poetry.txt里截 500 行验证链路确认能出结果再上全量能省下大量等待时间。4. 避坑与排查跑不起来时先看这几处4.1 现象导入 tensorflow 报一堆警告甚至报错原因requirements.txt里的 TF 版本和你 Python 版本不匹配比如 TF 1.x 不支持 Python 3.9 以上。解决先python --version确认版本再对照 TF 官方支持矩阵选版本实在不行用 conda 建一个指定 Python 版本的环境比硬扛 pip 冲突省事。4.2 现象训练 loss 是 nan 或者一直不降原因学习率过大、语料里有空行或异常字符、或者 padding 处理没对齐。解决把learning_rate降到1e-5再试在dataset.py里加打印看清洗后的样本数量和最长句长检查char2id里有没有把 0 号位误用成真实字符。4.3 现象网页能开但生成结果是一串乱码或重复字原因vocab.txt和训练时用的字表不一致或者解码时没做 id 到字符的反查。解决确认chinese_L-12_H-768_A-12/vocab.txt就是训练时用的那份检查eval.py里的解码逻辑确保id2char映射和char2id是严格互逆的。4.4 现象前端样式全丢页面变成裸 HTML原因Flask 的静态文件路径没配对static/目录下的 css、js 没被正确引用。解决确认index.html里用的是{{ url_for(static, filename...) }}而不是写死的相对路径检查static/css和static/js的层级是否和模板里的引用一致。4.5 现象生成速度极慢点一次等十几秒原因每次请求都重新加载模型或者生成时没限制长度。解决把模型加载提到app.py的全局初始化里只加载一次给max_len设一个上限避免用户传个超大值把推理拖死。5. 进阶玩法把生成器改成可调风格的接口跑通之后我一般不会停在「能出诗」这一步而是想办法让它可控。这份源码的eval.py其实留了口子——它本来就是做效果评估的稍微改一改就能变成「风格开关」。具体做法是在生成时引入温度参数temperature和重复惩罚让输出在「工整」和「放飞」之间切换。# 在生成逻辑里加入温度和重复惩罚示意 def sample_with_temperature(logits, temperature1.0): logits logits / temperature # 温度越低越保守 probs softmax(logits) return np.random.choice(len(probs), pprobs) def generate(model, seed, max_len50, temperature0.8, rep_penalty1.2): result seed for _ in range(max_len): logits model.predict(result) # 对已出现的字降权减少重复 for ch in set(result): logits[char2id[ch]] / rep_penalty next_id sample_with_temperature(logits, temperature) result id2char[next_id] return result逻辑说明temperature控制随机性0.5左右偏工整、适合五言1.0以上容易出奇句但也容易跑偏rep_penalty对已经出现过的字做除法降权能明显缓解「一句里同一个字反复出现」的毛病。参数上我一般把temperature默认设0.8、rep_penalty设1.2再在前端加两个滑块让用户自己调体验会好很多。参数保守值放飞值效果temperature0.51.2越低越像格律诗越高越发散rep_penalty1.51.1越高越不重复但可能丢韵脚max_len2060控制单次生成长度验证改动是否有效不用靠感觉。我会固定同一个开头比如「明月」分别用两组参数各生成 20 首人工看重复字比例和通顺度再决定默认值。这套流程跑下来基本能把一个「随机出诗」的玩具调成一个「可调风格」的小工具。从那以后我每次拿到这类生成式项目都强制先固定种子、跑一组对照再谈效果——不然改了半天参数连是不是变好了都说不清。希望这份拆解能帮你少走点弯路。本文还有配套的精品资源点击获取
返回列表