OpenAssistant 数据增强r/changemyview 原始语料清洗与 Parquet 训练集构建实战【免费下载链接】Open-AssistantOpenAssistant is a chat-based assistant that understands tasks, can interact with third-party systems, and retrieve information dynamically to do so.项目地址: https://gitcode.com/gh_mirrors/op/Open-Assistant导读本篇文章以 OpenAssistant 仓库中notebooks/data-augmentation/changemyview-builder/目录的官方说明文档为主体结合其配套的 data_processor.ipynb 完整源码讲解如何把 Reddit 子版块 r/changemyviewCMV上发表观点 他人反驳的讨论内容转换成可供大模型微调使用的「指令—回复」型数据并落盘为 Apache Parquet 格式。读完本文你将掌握该数据构建管线的数据格式约定、Reddit API 接入方式、评论清洗与毒性过滤策略以及如何运行与验证这套流程。一、项目定位从争论帖到指令数据集r/changemyview 是 Reddit 上一个以发表一个观点让其他人来说服你改变看法为玩法的子版块。帖主OP在标题与正文中陈述一个立场评论区则是大量试图反驳该立场的论证。这种天然成对的「观点INSTRUCTION— 反驳论证RESPONSE」结构非常适合改造成大语言模型的指令微调样本。但原始数据远不能直接进入模型训练帖子正文混杂了引用符号gt;、版规模板、编辑记录、DeltaBot 机器人消息、被删除的账号与评论、重复回复以及有毒内容。因此该目录下的程序先把从子版块抓取的数据清洗成规范格式供后续进一步处理。从仓库结构看它位于notebooks/data-augmentation/数据增强目录下目录说明与其他数据增强 notebookessay-instructions、wikidata-qa 等并列属于 OpenAssistant 数据收集与清洗流水线的一环。二、目标数据格式四列 Parquet 文件官方 README 明确规定了清洗后数据的存储格式——一个 Apache Parquet 文件包含以下四列列名说明数据类型INSTRUCTION帖子标题 正文文本StringRESPONSE试图改变楼主OP观点的评论正文ListStringSOURCEReddit 帖子的 Permalink永久链接StringMETADATA与 RESPONSE 相关的元数据DictVariant这套结构与主流指令微调数据集的字段约定高度一致INSTRUCTION充当用户输入promptRESPONSE充当期望的助手输出SOURCE保留溯源信息METADATA为后续质量过滤留出扩展空间。关于 METADATA目前元数据只规划了一个类别detoxify_labels由 UnitaryAI 的 Detoxify 毒性检测模型对某个帖子下每条评论输出的分值字典关于 Detoxify 模型家族见下文毒性过滤小节。需要说明的是README 描述的RESPONSE为 ListString、METADATA为 Dict 的 schema 是文档约定的目标格式而当前版本 notebook 最后实际写盘的 DataFrame 仅包含INSTRUCTION、RESPONSE、SOURCE三列并以 post id 作为索引。阅读源码时应注意这一差异清洗阶段已用 Detoxify 完成毒性过滤但尚未把每条评论的毒性分值沉淀进METADATA列。三、运行环境与依赖安装官方文档给出的使用步骤针对仓库内目录clone 步骤略去进入目录cd notebooks/data-augmentation/changemyview-builder打开 Jupyter Notebookjupyter notebook data_processor.ipynb按顺序执行各单元格notebook 的第一段代码单元格用!pip install安装全部依赖实测环境版本来自 notebook 输出如下依赖包作用示例版本pandasDataFrame 数据处理1.4.4prawReddit API 客户端7.6.1python-dotenv读取 .env 环境变量0.21.0pyarrowParquet 读写10.0.1detoxify毒性文本检测0.5.1tqdm进度条显示4.64.1其中 detoxify 会连带安装 transformersnotebook 中为 4.22.1、torch、sentencepiece、huggingface-hub、tokenizers 等深度学习组件这也是整个依赖链中最重的部分。笔记本内核为 Python 3ipykernelnotebook 元数据中标注的版本为 3.9.13。四、前置配置Reddit API 凭据与 .env程序使用 PRAW 访问 Reddit API 获取最新评论数据因此必须先注册 Reddit 应用并配置凭据。notebook 顶部有醒目提示REMEMBER: setup the .env before running this code!运行前务必先配置 .env。代码通过 python-dotenv 在脚本同目录加载.env文件main.load_dotenv(join(dirname(os.path.realpath(__file__)), .env)) reddit praw.Reddit( client_idos.environ.get(CLIENT_ID), client_secretos.environ.get(CLIENT_SECRET), user_agentCMV_Scraper, )即.env文件中至少需要以下键值CLIENT_ID你的Reddit客户端ID CLIENT_SECRET你的Reddit客户端密钥PRAW 客户端使用固定的user_agentCMV_Scraper以脚本应用script app方式认证——即只提供 client_id 与 client_secret无需用户名密码即可读取公开数据。五、数据源下载与原始数据格式5.1 下载 CMV 历史数据集程序不直接全量抓取 Reddit而是先下载一个已打包的历史数据集cmv.tar.bz2其来源是https://chenhaot.com/data/cmv/。notebook 会先检查本地是否已有该文件不存在才下载fname cmv.tar.bz2 url https://chenhaot.com/data/cmv/ fname if not os.path.isfile(fname): f BytesIO() with request.urlopen(url) as resp, open(fname, wb) as f_disk: data resp.read() f_disk.write(data) # save to disk too f.write(data) f.seek(0) else: f open(fname, rb)从 tar 包中提取两个文件训练集与留出集train_fname op_task/train_op_data.jsonlist.bz2 test_fname op_task/heldout_op_data.jsonlist.bz25.2 原始记录的 JSON 结构训练文件是 bzip2 压缩的 JSON Lines每行一个 JSON 对象notebook 用BZ2File逐行反序列化。从示例输出可以看到每条记录的结构{ title: CMV: I shouldnt get a job in this economic climate because itll be automated anyway..., delta_label: false, name: t3_2rpsl8, selftext: I think the world is automating fast enough that a utopia will arise... }各字段含义title帖子标题delta_label是否被授予 ΔDelta表示帖主被说服的布尔标签nameReddit 全量 ID含t3_前缀对应 submission 类型selftext帖子正文Markdown 文本。原始数据会被装载进 pandas DataFrame 以便后续按行处理。六、源码级流程解析从帖子到训练样本主循环对df.head(ENTRIES_COUNT)中的每个帖子执行抓取评论 → 清洗 → 汇总流水线核心函数是get_top_comment_and_clean_data(post_id)。下面按步骤拆解其实现逻辑。6.1 关键常量# Set the head number to the amount of entries you want to load in minus one ENTRIES_COUNT 10 # Set the threshold for toxic comments to be removed TOXIC_THRESHOLD 0.95ENTRIES_COUNT本次要处理的帖子数量注释说明实际是想加载的条数减一的 head 切片默认 10TOXIC_THRESHOLD毒性评分阈值超过该值的评论会被剔除默认 0.95。6.2 评论抓取与排序submission reddit.submission(idpost_id.lstrip(t3_)) submission.submission_type best submission.comments.replace_more(limit0) replies list(submission.comments)[0].replies.list()逻辑要点用 PRAW 按帖子 ID去掉t3_前缀获取 submission设置submission_type best以最佳排序获取评论replace_more(limit0)不展开更多评论占位符避免请求过多取顶层评论中的第一条即最佳回复再取其下所有子回复组成replies列表——即聚焦于最佳反驳链。6.3 作者切换与正反论证推断代码采用一个朴素但巧妙的启发式每当评论作者切换就认为论证方向翻转由此把评论交替归类为支持标题论点pro与反对标题论点conlast_author is_pro_argument False ... if author ! last_author: is_pro_argument !is_pro_argument同时处理两类无效作者若作者对象为空账号被删除或无效作者记为[deleted]评论被跳过作者为DeltaBotReddit 上 CMV 版块用于确认 Δ 的机器人的评论同样被跳过。代码注释还解释了变量命名Pros arguments for the Title of this postCons arguments against the title of this post。6.4 评论正文清洗对每条评论执行多层清洗comment.body .join([line for line in comment.body.splitlines() if not re.search(r(?i)(Change\smy\sview|CMV), line) and line not in pros])删除含有 Change my view / CMV 字样的元讨论行跳过与已收集内容重复的评论源码注释指出该行去重逻辑存在未解决的问题Why doesnt this line work在追加前再次用if comment.body in pros: continue做一层兜底去重。6.5 毒性过滤Detoxify对通过以上清洗的每条评论调用 Detoxify 的multilingual模型计算毒性分数超过阈值则清空正文if Detoxify(multilingual).predict(comment.body)[toxicity] TOXIC_THRESHOLD: comment.body Detoxify 是 UnitaryAI 开源的毒性检测模型族仓库中的 detoxify-evaluation 说明 记录了其三个模型变体模型名Transformer 类型训练数据originalbert-base-uncasedToxic Comment Classification Challengeunbiasedroberta-baseUnintended Bias in Toxicity Classificationmultilingualxlm-roberta-baseMultilingual Toxic Comment Classification该评估文档的经验结论是unbiased 与 multilingual 在识别隐性毒性上表现较好但都难以识别以正式语言包装的毒性内容multilingual适合多语言场景本 notebook 即选用它。对每个帖子下的所有评论打分后可聚合为 README 中描述的detoxify_labels元数据当前版本实现仅用于过滤、未落盘为独立列。6.6 帖子标题与正文处理主循环中还对标题与正文做了两处加工modified_title post.title.replace(CMV, Change my mind) ... post.selftext cleanup_body_text(post.selftext) all_titles.append(modified_title post.selftext)标题中的 CMV 统一替换为自然语言 Change my mind使指令更接近人类表达示例输出中可见 Change my mind: I shouldnt get a job...正文经cleanup_body_text清理逐行剔除以gt;引用转义开头、以____开头、以 So go forth and CMV, noble redditors!版规模板结尾开头以及前两个词包含 edit编辑说明的行。6.7 样本拼装与输出每条帖子最终拼装为all_titles.append(modified_title post.selftext) # INSTRUCTION all_pros.append(pros) # RESPONSE all_sources.append(fhttps://reddit.com/r/changemyview/comments/{post.post_id}) # SOURCE其中pros是全部被采纳评论经set去重后以空格拼接的字符串pros .join([*set(pros)]) pros pros.replace([deleted], )最后写入 Parquetclean_df pd.DataFrame({ INSTRUCTION: all_titles, RESPONSE: all_pros, SOURCE: all_sources }, indexall_names) table pa.Table.from_pandas(clean_df) pq.write_table(table, output.parquet)并使用pq.read_table(output.parquet).to_pandas()读回验证写入成功。notebook 中的 10 条示例输出显示INSTRUCTION形如 Change my mind: Iran has the right to develop ...RESPONSE为该帖最佳反驳链的长文本SOURCE为对应帖子的 permalink。七、运行注意点与已知限制基于 notebook 实际输出与源码注释以下几点值得实操者注意耗时较长notebook 中 10 条帖子的完整抓取过滤流程耗时约 8 分 45 秒CPU 7min49s sys 2min29s主因是逐条调用 Reddit API 与 Detoxify 推理。处理全量数据前建议先用小ENTRIES_COUNT验证。资源泄漏警告运行中出现ResourceWarning: unclosed file提示 bz2/tar 文件句柄未显式关闭可自行用with上下文改进。源码注释标明的待改进点去重逻辑line not in pros被作者标注为未生效is_pro_argument的翻转仅基于作者是否变化这一启发式实际回复链中论证方向未必严格交替。README 与实现的 schema 差异README 声明的RESPONSEListString与METADATA含detoxify_labels是目标格式当前 notebook 输出的RESPONSE为拼接后的 String、暂无METADATA列二次处理时可按需补齐。Reddit API 限流批量抓取依赖 Reddit API 配额大规模运行时需考虑频率控制与容错重试。八、进一步探索changemyview-builder 官方说明数据格式与使用步骤的权威文档data_processor.ipynb本文全部流程的完整可运行实现数据增强目录说明该 notebook 在 OpenAssistant 数据增强体系中的位置detoxify-evaluation 说明 与 评估 notebookDetoxify 三模型变体的内存、速度与过滤质量评测项目其余数据管线参考data 目录数据集说明、OASST 数据读写工具。本项目整体遵循 Apache-2.0 许可证详见仓库根目录的 LICENSE 文件如需二次开发本清洗管线建议 Fork 仓库后提交 Pull Request。【免费下载链接】Open-AssistantOpenAssistant is a chat-based assistant that understands tasks, can interact with third-party systems, and retrieve information dynamically to do so.项目地址: https://gitcode.com/gh_mirrors/op/Open-Assistant创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考