十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

GPT-2 二次开发实战:3 种格式一次搞定文本生成结果导出

GPT-2 二次开发实战:3 种格式一次搞定文本生成结果导出 GPT-2 二次开发实战3 种格式一次搞定文本生成结果导出【免费下载链接】gpt-2Code for the paper Language Models are Unsupervised Multitask Learners项目地址: https://gitcode.com/GitHub_Trending/gp/gpt-2GPT-2 是 OpenAI 开源的文本生成模型能根据 prompt 续写出一段段像模像样的自然语言。但它的官方仓库有个老毛病生成结果只会print到控制台想拿去写博客、进数据库、喂给下游程序都得人肉复制粘贴。本文就带你在读懂源码的基础上做一次实打实的开源项目二次开发——给 GPT-2 加上 JSON、Markdown、纯文本三种格式的导出能力让生成结果从控制台走进文件。先把仓库拉到本地并安装依赖git clone https://gitcode.com/GitHub_Trending/gp/gpt-2 cd gpt-2 pip install -r requirements.txt python download_model.py 124M # 下载最小的124M模型约500MB一、从一次翻车说起打印出来的文本根本没法用上个月我想攒一篇 AI 主题的公众号文章让 124M 模型续写人工智能的未来。模型跑了两分钟出来一段话我很满意然后……我盯着终端愣了五秒接下来呢复制粘贴进编辑器重新排版更要命的是同事第二天找我要这批生成文本做数据清洗人家点名要 JSON 格式带sample_id、timestamp、temperature这些元数据。我总不能对着终端一条条手抄吧。打开源码一看问题一目了然。交互式生成的入口在src/interactive_conditional_samples.py它的输出逻辑只有三行# 文件src/interactive_conditional_samples.py原始实现 text enc.decode(out[i]) # 生成文本 print( * 40 SAMPLE str(generated) * 40) print(text) # 直接打到控制台没有任何导出批量生成脚本src/generate_unconditional_samples.py里几乎是同一套代码。整条生成链路prompt → token → 文本到print就戛然而止。这就是文本生成结果导出能力缺失的根源生成和消费之间缺一个格式化落盘的出口。小结一下GPT-2 的输出层只做了打印没做交付。若你运行时报No module named tensorflow通常是环境里没装 TensorFlow 1.x该仓库用的是tf.Session老接口装好对应版本即可。二、先让输出能落盘20 行临时脚本的成就感既然缺出口第一反应不是去改仓库而是先写个二十行的临时脚本把生成→写文件跑通获得即时成就感。这个脚本完全复用仓库自己的encoder、sample、model模块只需十几行核心逻辑# dump_samples.py —— 临时脚本先解决能落盘 import os, json, tensorflow as tf import model, sample, encoder # 复用仓库自己的模块 MODEL_NAME 124M enc encoder.get_encoder(MODEL_NAME, models) hparams model.default_hparams() # 读取模型默认超参 with open(os.path.join(models, MODEL_NAME, hparams.json)) as f: hparams.override_from_dict(json.load(f)) with tf.Session(graphtf.Graph()) as sess: context tf.placeholder(tf.int32, [1, None]) output sample.sample_sequence( # 生成token序列 hparamshparams, length100, contextcontext, batch_size1, temperature0.8) saver tf.train.Saver() saver.restore(sess, tf.train.latest_checkpoint( os.path.join(models, MODEL_NAME))) # 载入预训练权重 ctx enc.encode(人工智能的未来) # prompt → token out sess.run(output, feed_dict{context: [ctx]})[:, len(ctx):] text enc.decode(out[0]) # token → 文本 with open(result.txt, w, encodingutf-8) as f: f.write(text) # 总算能落盘了运行python dump_samples.py一个result.txt就出现在当前目录。虽然丑但它证明了一件事生成结果是可以离开控制台的。但临时脚本的问题也很明显格式写死、元数据没有、两条样本只能覆盖写、换个格式就得改代码。它适合跑一次拿结果撑不起持续产出。所以下一步我们把眼光放回仓库本身的架构上。若你运行时报AssertionError多半是某处参数没对齐——这是接下来要重点处理的。三、看清最后一公里token 是怎么变成文本的动手前先搞明白数据在仓库里怎么流转。整条链路其实非常短我用一张图把它画出来逐层解释一下enc.encode(raw_text)把 prompt 变成 token词元模型处理文本的最小单位序列sample.sample_sequence(...)在src/sample.py里用tf.while_loop逐 token 采样返回完整的 token 张量enc.decode(out[i])把 token 序列解码回可读文本print(...)这里就是被我们忽略的最后一公里。关键洞察在于decode之后、print之前的这一小段恰恰是插入格式化 导出的最佳位置。此时我们手里握着完整的信息——生成的文本、模型名、temperature、top_k、当前时间甚至 prompt 原文这些正是 JSON 格式里最有价值的元数据描述数据的数据。小结改动点已经锁定就是两处生成循环里的print附近。若你发现decode出来的文本开头总是多一个空格那是 GPT-2 的 BPE字节对编码一种子词切分算法机制导致的后面避坑清单里会专门讲。四、接口化改造把格式化从生成循环里拆出去临时脚本告诉我们把格式化逻辑硬塞进生成循环代码会越来越乱。正确做法是引入策略模式——把每一种格式封装成一个独立的类它们都实现同一个format方法再加一个工厂类负责按名字返回对应实例。这样生成循环只依赖一个统一接口加新格式时循环代码一行都不用动。新建src/formatter.py# src/formatter.py —— 把格式化从生成循环里拆出来 import json, re from datetime import datetime class OutputFormatter: # 统一接口策略模式 def format(self, text, metadataNone): raise NotImplementedError class PlainTextFormatter(OutputFormatter): def format(self, text, metadataNone): return text.strip() # 纯文本去掉多余空白 class JsonFormatter(OutputFormatter): def format(self, text, metadataNone): result {text: text.strip(), length: len(text.strip())} result.update(metadata or {}) # 元数据并进JSON return json.dumps(result, ensure_asciiFalse, indent2) class MarkdownFormatter(OutputFormatter): def format(self, text, metadataNone): title (metadata or {}).get(title, GPT-2 Generated Text) md [f# {title}, ] for para in re.split(r\n\s*\n, text.strip()): # 按空行切段 md.append( .join(para.split())) if metadata: md [, ## 生成信息] md [f- **{k}**: {v} for k, v in metadata.items()] return \n\n.join(md) class FormatterFactory: # 工厂注册新格式的唯一入口 FORMATTERS {text: PlainTextFormatter, json: JsonFormatter, markdown: MarkdownFormatter} classmethod def get(cls, fmt): try: return cls.FORMATTERS[fmt]() except KeyError: raise ValueError(f不支持的格式: {fmt})这个设计的核心好处是隔离变化JsonFormatter想调整字段结构只动这一个类要支持 CSV只需往FORMATTERS里注册一个新类三步搞定写类、实现 format、注册生成循环完全无感。小结接口抽象 工厂注册是开源项目二次开发里性价比最高的改造方式。若调用FormatterFactory.get(yaml)报了ValueError别慌那说明你忘了在FORMATTERS里注册它。五、给两个生成脚本装上导出开关现在把工厂接进两个生成脚本。先看交互式脚本src/interactive_conditional_samples.py它靠fire.Fire(interact_model)把函数签名直接映射成命令行参数——这意味着只要在函数签名里加两个形参CLI 就自动多出两个开关。修改前生成循环长这样for i in range(batch_size): generated 1 text enc.decode(out[i]) print( * 40 SAMPLE str(generated) * 40) print(text)修改后def interact_model(..., top_p1, models_dirmodels, output_formattext, output_fileNone): # 新增两个开关 ... results [] # 本次会话的全部样本 ... for i in range(batch_size): generated 1 text enc.decode(out[i]) metadata { # 组装元数据 sample_id: generated, prompt: raw_text, timestamp: datetime.now().isoformat(), model_name: model_name, temperature: temperature, top_k: top_k, } formatted FormatterFactory.get(output_format).format(text, metadata) print( * 40 f SAMPLE {generated} * 40) print(formatted) # 控制台看到的已是格式化结果 results.append({text: text, **metadata}) if output_file: # 指定了文件就增量落盘 _flush(output_format, results, output_file)文件写入单独抽成一个_flush函数。这里有个隐藏的坑JSON 是结构化格式如果用追加写的方式文件随时处于半截状态一打开就是非法 JSON。所以我对 JSON 采用整表重写策略——样本量不大时简单可靠def _flush(output_format, results, output_file): if output_format json: # JSON要保证整个文件始终合法 with open(output_file, w, encodingutf-8) as f: json.dump(results, f, ensure_asciiFalse, indent2) else: # 其他格式直接覆盖写 with open(output_file, w, encodingutf-8) as f: f.write(\n\n.join( f SAMPLE {r[sample_id]} \n{r[text]} for r in results))src/generate_unconditional_samples.py的sample_model做同样处理区别只是批量场景在循环结束后一次性_flush即可不用每步都写。小结靠fire的签名映射两个脚本零命令行解析代码就获得了--output_format、--output_file参数。若提示参数不识别多半是函数形参名和命令行参数名不一致——fire 只认形参名。六、实战演练一次生成三种格式同时落盘现在到了验收环节。交互式模式导出 JSONpython src/interactive_conditional_samples.py --model_name124M \ --output_formatjson --output_filegenerated.json输入 prompt 后generated.json长这样结构完整可直接进数据库或下游程序[ { text: 人工智能的未来既令人兴奋又充满未知。, length: 23, sample_id: 1, prompt: 人工智能的未来, timestamp: 2026-08-13T17:15:22.438217, model_name: 124M, temperature: 1, top_k: 0 } ]批量生成脚本导出 Markdown正好用来当博客草稿python src/generate_unconditional_samples.py --model_name124M \ --nsamples3 --length200 --output_formatmarkdown --output_fileblog.md打开blog.md看到的是一篇带标题、分段、元信息表的结构化文档# GPT-2 Generated Text 人工智能的未来既令人兴奋又充满未知。它正在改变我们写代码、写文章、做设计的方式。 ## 生成信息 - **sample_id**: 3 - **timestamp**: 2026-08-13T17:16:01.220384 - **model_name**: 124M - **temperature**: 1 - **top_k**: 0控制台里打印的也是同样经过格式化的内容——也就是说无论你看屏幕还是看文件拿到的都是同一份可直接交付的结果。至此GPT-2 的文本生成结果导出能力已经完整落地交互式、批量式两条路径全部打通三种格式随意切换。七、避坑清单与可扩展方向最后把这趟折腾攒下的经验留给你。避坑经验按踩坑概率排序生成文本开头常有前导空格GPT-2 的 BPE 词表用词前空格编码单词decode后第一个 token 会带出空格。Formatter里统一strip()处理别到下游再后悔。JSON 别用追加写半截的 JSON 不是 JSON。要么整表重写样本少时够用要么用先写[收尾时再闭合的流式方案并保证程序异常退出时文件也能闭合。参数三连查nsamples必须是batch_size的整数倍源码里assert直接报错、length不能超过模型窗口n_ctx、CLI 参数名必须等于函数形参名。可扩展方向新格式三步注册按OutputFormatter写个CsvFormatter处理逗号、引号、换行转义后注册进FORMATTERS就能导出 CSV 表格。配置驱动把格式、标题模板、要带哪些元数据字段写进一个 yaml/json 配置文件运行时读取做到改配置不改代码。模板引擎与管线集成接入 Jinja2 支持自定义 HTML/LaTeX 模板或把导出层封装成异步任务直接对接数据清洗和内容发布管线。这次改造总共只动了两个文件、新增一个模块却让 GPT-2 从只会打印变成了能交付。开源项目二次开发的乐趣就在于此读透源码里那条最短的数据链路在最合适的位置插上自己的扩展点——剩下的都是水到渠成。【免费下载链接】gpt-2Code for the paper Language Models are Unsupervised Multitask Learners项目地址: https://gitcode.com/GitHub_Trending/gp/gpt-2创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表