GPT-2 文本导出完整指南三步把生成结果转成 JSON、Markdown 与纯文本【免费下载链接】gpt-2Code for the paper Language Models are Unsupervised Multitask Learners项目地址: https://gitcode.com/GitHub_Trending/gp/gpt-2模型好不容易跑通了生成的文本却只能躺在终端里滚屏。把结果一份份复制、粘贴、整理成可交付的文档往往比调参还折磨人。这篇文章讲的就是一件事如何给 GPT-2 的输出加一条后处理流水线让生成结果一键变成 JSON、Markdown、纯文本想入库就入库想发博客就发博客。先讲个真实场景模型是通的交付是堵的你周末部署了 GPT-2用src/interactive_conditional_samples.py敲了 20 条 prompt每条都生成了 3 段短文。终端里塞满了 SAMPLE 1 这样的分隔线和一大段一大段的文字看起来非常壮观。周一你把结果发给同事对方问能给我 JSON 吗我这边要入库。你沉默了——因为所有结果都只是print()出去的字符串没有任何结构化信息没有 prompt 对应关系没有生成时间没有温度参数。你只能重新跑一遍对着屏幕一条条抄。这个场景几乎人人都遇到过。问题从来不是生成不出来而是生成完没法用。一个类比先理解格式化到底在解决什么把 GPT-2 想象成一个不眠不休的车间。模型本身是生产环节负责把 token 序列吐出来而你缺的是分拣打包环节。车间里的产品如果不打包就出厂客户拿到的是堆在一起的散货分不清批次、看不清规格。格式化输出做的事就是给每件产品贴上标签、装进对应的包装——JSON 是标准工业箱机器好拆Markdown 是带说明书的礼盒人看舒服纯文本是裸包装最轻量。所以整个改造的核心思路很简单在生成和交付之间插入一个可插拔的转换层让同一条生成结果想输出成什么样就输出成什么样。先拆原始链路文本到底是从哪条路出来的动手之前得先看清现在的输出路径。以交互式脚本src/interactive_conditional_samples.py为例核心就三步# 1. prompt 文本 → token 序列 context_tokens enc.encode(prompt) # 2. token 序列 → 模型采样出新 tokensrc/sample.py 的 sample_sequence tokens sample.sample_sequence( hparamshparams, lengthlength, contextcontext_tokens, batch_sizebatch_size, temperaturetemperature, top_ktop_k, top_ptop_p, ) # 3. 新 token → 文本直接 print 出去 text enc.decode(tokens[0]) print(text)src/encoder.py负责文本和 token 的双向转换src/sample.py负责采样。一切都很干净唯一的短板在最后一步print(text)把好不容易算出来的东西当成一次性消费品扔掉了。我们要做的就是把最后这一行 print 替换成一个分发出口文本生成后先包成一条带元信息的记录再按指定格式渲染最后决定是打屏、写文件还是两者都要。三种交付格式先选型再动手别急着写代码。先明确你的下游是谁格式自然就定了交付格式结构化程度人读体验机器解析成本最配的场景JSON高一般极低数据入库、API 响应、脚本消费JSONL高一般极低流式落盘、攒训练语料Markdown中好低写博客、进知识库、沉淀文档纯文本无最好无快速浏览、人工二次整理多提一句 JSONL如果生成量很大别费劲去维护一个巨大的 JSON 数组每行一条 JSON 记录JSONL写起来零成本、追加零风险后续想转成数组一个脚本就搞定。这是实战里最省心的方案。落地第一步写一个独立的导出模块新建src/exporter.py里面只放渲染逻辑不碰模型保持单一职责。函数命名刻意和原脚本区分开方便你按自己的口味改# src/exporter.py import json import re from datetime import datetime def pack_payload(text, promptNone, **extra): 把一段生成文本包装成可序列化的记录附上元信息 content text.strip() return { content: content, char_count: len(content), word_count: len(content.split()), prompt: prompt, created_at: datetime.now().isoformat(timespecseconds), **extra, } def as_json(record): JSON完整保留结构机器可读 return json.dumps(record, ensure_asciiFalse, indent2) def as_jsonl(record): JSONL一行一条记录适合追加写入 return json.dumps(record, ensure_asciiFalse) def as_markdown(record, heading生成结果): Markdown段落归一化 元信息小节 body \n\n.join( .join(para.split()) for para in re.split(r\n\s*\n, record[content]) if para.strip() ) meta \n.join( f- **{key}**: {value} for key, value in record.items() if key ! content ) return f## {heading}\n\n{body}\n\n### 记录信息\n{meta}\n def as_text(record): 纯文本只保留正文最轻量 return record[content] \n几个设计要点供你参考所有格式共享同一个record先有数据再谈展示。将来加 CSV、HTML只是多一个渲染函数的事。ensure_asciiFalse别省否则中文全变成\uXXXX可读性直接归零。Markdown 里做了段落归一化把连续换行拆成段落、把段内多余空格压平避免模型吐出的断行把文档搞得稀碎。created_at自动补齐这是最容易漏、事后又最想找回来的信息。落地第二步加一个统一的分发出口光有渲染函数还不够还需要一个统一调度的函数把格式选择 控制台输出 文件写入包在一起RENDERS { json: as_json, jsonl: as_jsonl, markdown: as_markdown, text: as_text, } def emit(record, fmttext, sinkNone, previewTrue): fmt 指定格式sink 为文件路径preview 控制是否打印全文 rendered RENDERSfmt if preview: # 生成量大时控制台只打印摘要避免刷屏 head record[content][:80].replace(\n, ) print(f[{record[created_at]}] {head}...) if sink: with open(sink, a, encodingutf-8) as fh: if fmt json: # JSON 整份落盘走覆盖写追加用 jsonl 更稳 with open(sink, w, encodingutf-8) as wf: wf.write(rendered \n) else: fh.write(rendered \n) return rendered这里有个实战上的取舍值得讲透追加写入天然适合 JSONL、Markdown、纯文本唯独不适合 JSON 数组。想在多个样本之间不断往数组里插记录就得把文件读回来、改、再写回去样本一多性能就很难看。所以我的建议是单条 JSON → 覆盖写一个文件内容就是完整对象批量场景 → 用 JSONL 一路追加收尾时统一聚合。落地第三步接入两个入口脚本导出模块就绪后改动量其实很小。以交互式脚本为例只需要在生成循环里把print(text)换成emit(...)# 原代码 # text enc.decode(out[i]) # print( * 40 SAMPLE str(generated) * 40) # print(text) record pack_payload( enc.decode(out[i]), promptraw_text, sample_idgenerated, model_namemodel_name, temperaturetemperature, top_ktop_k, ) emit(record, fmtoutput_format, sinkoutput_file)批量脚本src/generate_unconditional_samples.py的改法完全同构——把sample_id换成累计的generated把prompt字段去掉即可。两个脚本共用同一套exporter逻辑零重复。命令行的调用方式也随之简化# 交互式生成结果同时追加到 Markdown 文件 python src/interactive_conditional_samples.py \ --model_name124M --output_formatmarkdown --output_filesamples.md # 批量攒 20 条 JSONL 训练语料 python src/generate_unconditional_samples.py \ --model_name355M --nsamples20 --length300 \ --output_formatjsonl --output_filecorpus.jsonl踩坑清单这些坑我都替你趟过了坑一JSON 数组越拼越碎。在文件尾部用seek挪位置删掉]再补,的做法看着聪明遇到进程中断、磁盘写满就是整个文件损坏。改用 JSONL或者一次性收集完再整体落盘。坑二中文变成乱码或\u转义。打开文件一律encodingutf-8json.dumps一律ensure_asciiFalse两条都做到基本就稳了。坑三模型吐出的换行把 Markdown 结构搅乱。生成文本里经常夹着莫名奇妙的换行。段落归一化按空行分段、段内压平能救回大部分可读性代码里已经实现别手贱删掉。坑四空 prompt 或空输出没兜底。交互式脚本里已有空 prompt 检查但批量模式下仍可能解码出空白内容建议在emit里过滤content为空字符串的记录。坑五控制台被刷爆。大批量生成时全文打印会拖慢速度、淹没日志。用摘要预览模式只在终端显示前 80 个字符完整内容走文件。坑六把格式化逻辑塞进模型脚本。我见过有人直接把json.dumps写进src/sample.py从此每次调参都得看一堆序列化代码。独立模块隔离改动面小回滚也容易。下一步从能导出到更好用到这里你已经拥有了一条生成 → 打包 → 渲染 → 落盘的完整链路。再往前可以做的事还很多加格式CSV、HTML、LaTeX每个只是一个新渲染函数 注册进RENDERS五分钟搞定加模板把 Markdown 的标题、页眉做成可配置让不同项目输出不同风格的文档加校验落盘前用json.loads验证一遍坏数据尽早发现加汇总批量生成结束后额外生成一份 index列出每条样本的 prompt、长度、文件位置查找样本不用再从头翻。如果还没把项目拉到本地可以执行git clone https://gitcode.com/GitHub_Trending/gp/gpt-2然后照着src/sample.py和src/encoder.py把生成链路读一遍再动手加你的exporter.py。最后说句实在话格式化输出不是什么高深技术但它决定了你的模型产出是能看还是能用。花一个下午把这条流水线搭好之后每一次生成交付的都不再是零散的文本而是随时可入库、可发布、可追溯的成果。【免费下载链接】gpt-2Code for the paper Language Models are Unsupervised Multitask Learners项目地址: https://gitcode.com/GitHub_Trending/gp/gpt-2创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考