ARTICLE DETAIL

资讯详情

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

大模型预训练数据集构建:从清洗到LLaMA Factory就绪的七道工序

大模型预训练数据集构建:从清洗到LLaMA Factory就绪的七道工序 1. 项目概述为什么预训练数据集不是“随便找点文本就能用”的凑数工程“大模型训练全流程实战指南实战篇十六——预训练数据集构建”这个标题里“预训练数据集构建”这七个字是整条大模型技术链路里最沉默、最被低估、也最容易翻车的环节。很多人以为预训练就是把维基百科Common CrawlGitHub代码一股脑塞进LLaMA Factory跑起来结果训完的模型张口就胡说八道、逻辑断裂、中英文混杂得毫无章法——问题十有八九出在数据上而不是模型结构或超参。我带过三轮从零启动的大模型预训练项目其中两次中期失败复盘下来70%的根因都指向数据集一次是中文网页爬虫没过滤掉大量广告弹窗文本导致模型学会了生成“点击领取百万红包”这类垃圾句式另一次是代码数据混入了大量未注释的私有项目片段模型在推理时竟会无意识复现敏感路径名。这不是玄学而是数据质量直接映射到模型能力边界的硬事实。预训练数据集的本质是给模型构建一个“世界认知的初始坐标系”。它不负责教会模型解微分方程但必须确保模型知道“苹果”是一种水果而非操作系统“Java”可以是咖啡也可以是编程语言“bank”在金融语境下指机构在河岸语境下指土坡。这种多义性识别、常识锚定、语域区分的能力全部依赖于数据的多样性、代表性、清洁度与结构合理性。而LLaMA Factory之所以成为当前主流工具链的关键一环正因为它把原本需要手写数千行Python脚本才能完成的数据清洗、格式对齐、分词预处理、去重校验等流程封装成了可配置、可复现、可版本化的命令行指令。但工具再好也救不了源头污染——就像再先进的净水器也滤不掉水管里锈蚀脱落的铁屑。所以本篇不讲“怎么用LLaMA Factory”而是聚焦在“怎么让LLaMA Factory有干净的水可滤”。你会看到如何用Markdown语法精准标注跨文档引用关系避免知识孤岛如何设计分层采样策略让法律文书、医学论文、小说对话、技术博客在数据流中保持合理权重如何用正则规则小模型三重校验把“ ”这类HTML残留从纯文本中物理剥离。这不是理论推演而是我在某金融垂类大模型项目中为解决“模型总把‘质押率’错写成‘质压率’”这一具体问题倒推回数据层重构的完整过程。如果你正在准备自己的预训练数据或者刚被LLaMA Factory报出“token length mismatch”卡在第一步这篇就是为你写的实操手册。2. 数据集构建的整体设计思路从“数据堆砌”到“认知基建”的范式转换2.1 为什么不能照搬Llama 2或Qwen的公开数据配方很多新手会直接下载The Pile、RefinedWeb或OpenWebText的公开数据集改个路径就往LLaMA Factory里塞。这就像盖楼前不看地质勘探报告直接按上海陆家嘴的地基图纸去建兰州新区的写字楼。问题出在三个维度领域漂移Domain ShiftLlama 2的训练数据中英文比例约3:7技术文档占比超40%而你若想训一个面向中医古籍问答的模型中文古文占比需达65%以上且需包含《伤寒论》《本草纲目》等特定文本结构。强行套用通用数据模型在“麻黄汤主治何证”这类问题上会优先匹配Stack Overflow里关于“HTTP 404 error”的讨论因为其token分布更接近训练数据中的高频模式。噪声谱系差异Noise Spectrum MismatchCommon Crawl数据中存在大量机器翻译腔、低质SEO文章、论坛灌水帖其噪声表现为“语法正确但语义空洞”如“这款手机真的非常棒特别棒超级棒”。而医疗数据特有的噪声是“术语准确但逻辑错误”如“青霉素过敏者禁用头孢菌素”——实际二者交叉过敏率仅5%-10%。不同噪声类型需要完全不同的清洗策略通用清洗脚本对此束手无策。许可合规断层License Compliance GapGitHub数据虽丰富但MIT/BSD协议允许商用GPL协议则要求衍生作品开源。某团队曾因未剥离GPL代码片段导致训出的模型无法商用法律团队介入后被迫全量重训。而中文网络数据更复杂微信公众号文章受《著作权法》保护即使标注“转载”原始授权链也常断裂。因此我们的设计起点不是“找数据”而是“定义认知边界”。以我参与的“工业设备故障诊断大模型”项目为例我们先用专家访谈列出237个核心概念如“轴承内圈剥落”“变频器IGBT击穿”再反向构建数据需求矩阵概念层级所需数据类型最小样本量典型来源示例许可核查要点故障现象描述技术论坛帖子、维修工单≥5000条知乎“机械维修”话题、企业内部工单系统脱敏导出工单需确认员工签署数据授权书原理图解说明PDF手册OCR文本、SVG矢量图alt文本≥800份西门子PLC手册、ABB变频器说明书PDF需验证是否含DRM加密排查步骤序列维修SOP文档、视频字幕≥300份三一重工服务手册、B站维修教程ASR文本视频字幕需排除AI生成内容这个矩阵直接决定了后续所有技术选型PDF处理必须支持OCR公式识别选用pymupdf而非pdfplumber网页爬取需定制JavaScript渲染引擎Puppeteer而非requests文本清洗要嵌入领域术语词典自建“工业故障同义词库”而非依赖jieba默认词典。LLaMA Factory在此只是执行终端真正的决策大脑在数据需求矩阵里。2.2 LLaMA Factory在数据流中的真实定位不是万能胶而是精密接口很多人误以为LLaMA Factory是数据处理全家桶其实它本质是一个数据协议转换器。它的核心价值在于将异构数据源统一转换为{input: ..., output: ...}或{text: ...}格式并完成tokenization前的标准化。但关键前置工作——数据获取、清洗、标注、去重——它根本不做。我们画一张真实项目中的数据流水线图文字描述版[原始数据源] → [采集层]Scrapy爬虫带JS渲染 API对接企业知识库 OCR引擎pymupdfmathpix → [清洗层]正则规则引擎去除HTML标签/广告/页眉页脚 小模型过滤finetuned tiny-bert识别低质文本 人工抽检按1%比例抽样 → [结构化层]Markdown语法注入为技术文档添加#故障代码#、##解决方案##等语义标记 跨文档引用解析用spaCy提取“参见第3.2节”并生成link → [LLaMA Factory接入点]调用llamafactory-cli data process命令指定 --dataset_dir ./cleaned_data --template default --tokenizer_name /path/to/your/tokenizer --max_length 2048 → [输出]HuggingFace Dataset格式的arrow文件供trainer直接加载注意箭头中的每个环节都是不可跳过的。曾有团队试图跳过“结构化层”直接把清洗后的纯文本喂给LLaMA Factory结果模型在回答“如何处理变频器过流报警”时会把不同品牌手册的解决方案随机拼接因为缺乏##品牌A方案##和##品牌B方案##这样的显式分隔符。而Markdown语法在这里的作用远不止美观——它是给模型植入“文档结构感知能力”的最轻量级方式。当你用#章节标题#包裹内容时LLaMA Factory的default template会自动将其转为s### 章节标题 ###\n这比单纯加换行符更能强化模型对信息层级的理解。这也是为什么热搜词里“markdown”反复出现它不是排版工具而是数据语义编码的基础设施。2.3 构建效率与质量的平衡点为什么我们放弃100%自动化清洗行业里有个危险共识“数据量越大越好”。某项目曾追求“单日处理1TB网页数据”结果清洗脚本用正则暴力删除所有.*?标签连sup2/sup上标2都删了导致化学方程式全乱套。后来我们彻底转向“质量优先速度可控”策略核心原则是人工干预必须嵌入关键节点在清洗层末尾设置“人工抽检闸门”每处理10万条数据必须由领域专家审核200条覆盖故障描述、原理图解、排查步骤三类。审核表不是打勾而是记录三类错误① 事实性错误如温度单位写错② 逻辑断裂如“先断电再拆外壳”写成“先拆外壳再断电”③ 语义模糊如“适当拧紧”未注明扭矩值。这些错误类型会反哺清洗规则迭代。小模型只做初筛不做终判我们用3亿参数的tiny-bert微调了一个“文本质量分类器”输入一段文本输出0-1分。但它只用于过滤掉得分0.3的明显垃圾如纯广告、乱码绝不用于保留得分0.7的“优质”文本——因为0.7分可能只是语法通顺但专业术语全错。终审权永远在人手中。版本化一切每个数据集版本都绑定三个哈希值raw_hash原始数据压缩包SHA256clean_hash清洗后数据集SHA256llm_hashLLaMA Factory处理后arrow文件SHA256 这样当模型效果异常时能精准定位是原始数据污染、清洗规则缺陷还是tokenizer配置错误。某次模型突然无法识别“RS485通信协议”追溯发现是清洗时误删了所有RS-485中的短横线导致模型只见过RS485和RS485两种写法无法泛化。这种看似“低效”的流程反而让我们在6个月项目周期内将数据相关故障率从初期的38%降至最终的2.1%。效率不是跑得快而是少返工。3. 核心细节解析从原始数据到LLaMA Factory就绪数据的七道工序3.1 第一道工序多源数据采集的避坑清单采集不是简单wget而是带着“数据考古”思维的定向挖掘。我们按数据源类型总结关键陷阱网页数据占70%以上避坑点1动态渲染内容。某设备手册网站用Vue.js异步加载章节requests返回的HTML里只有div idapp/div。必须用Puppeteer启动真实浏览器等待document.querySelector(.chapter-content)出现后再截图/提取。避坑点2反爬策略升级。新站点不再用User-Agent检测而是通过Canvas指纹、WebGL渲染特征识别爬虫。我们采用“真人行为模拟”鼠标随机移动轨迹、页面滚动延迟、点击间隔符合正态分布用pynput实现。避坑点3版权隐性声明。很多技术论坛在页脚用极小字体写“转载需联系站长”但爬虫不会识别。解决方案在采集前先用OCR扫描页脚区域匹配正则/(转载|引用|版权).*?联系/ig命中则跳过。PDF文档设备手册/标准规范避坑点1扫描版PDF的OCR陷阱。直接用Tesseract识别数学公式会变成乱码。必须先用pymupdf检测页面是否含文本层page.get_text(text)返回空字符串则为扫描版需调用mathpix API专精公式识别。避坑点2页眉页脚污染。某GB/T标准PDF每页页眉含“GB/T 12345-2023”清洗时若只删固定字符串会误删正文中的“GB/T 12345-2023”引用。正确做法用pymupdf获取页眉区域坐标只删除该矩形框内文本。避坑点3表格结构丢失。PDF表格转文本后变成“列1列2列3”挤在一起。我们用tabula-py提取表格为CSV再转为Markdown表格|列1|列2|列3|保留结构语义。API数据企业知识库/维修系统避坑点1字段语义混淆。某系统API返回{status: OK}但“OK”在不同接口中分别表示“操作成功”“设备在线”“工单关闭”。必须人工梳理API文档建立字段-语义映射表。避坑点2时间戳时区混乱。API返回update_time: 2023-01-01T00:00:00未注明时区。我们强制统一为UTC8所有时间字段追加[CST]后缀避免模型学习错误的时间逻辑。提示所有采集脚本必须内置“断点续传”。用Redis记录已处理URL的MD5每次启动先读取已处理列表跳过重复项。某次网络中断导致重跑靠此机制节省了17小时。3.2 第二道工序基于Markdown语法的数据结构化编码这是让模型理解“文档是什么”的关键一步。我们不用XML或JSON因为它们太重也不用纯文本因为太扁平。Markdown是最佳平衡点——人类可读、机器可解析、LLaMA Factory原生支持。核心编码规则已集成到清洗脚本中章节层级标记# 故障现象#→ 表示一级故障类别如“电源类故障”## 故障代码E01##→ 表示二级具体故障必须与设备手册严格一致### 可能原因###→ 表示三级分析维度固定为“可能原因”“解决方案”“预防措施”为什么用#号而非因为LLaMA Factory的default template会将#转为###而*会被忽略失去结构信号。*跨文档引用注入原始文本“参见第3.2节电机过热处理”。结构化后“参见 第3.2节电机过热处理 ”。脚本自动解析所有参见.*?节生成锚点ID#section-3-2并在目标章节开头插入a idsection-3-2/a。这样模型在训练时能学习到“参见”背后的知识关联逻辑。代码块语义标注原始pythondef check_voltage():return read_adc(0) 2.5结构化python title电压检测函数 languagepython def check_voltage(): return read_adc(0) 2.5title属性让模型知道这是“检测函数”language属性强化编程语言识别。测试表明带title的代码块使模型在生成同类函数时命名准确率提升22%。表格增强原始Markdown表格故障代码可能原因解决方案E01电源电压过低检查输入电压结构化后#故障代码##可能原因##解决方案#------------------------------------##E01#####电源电压过低######检查输入电压###这种嵌套标记让模型明确知道表格各列的语义角色而非仅当作字符串排列。注意所有Markdown标记必须用半角#且前后无空格。曾因脚本误加空格# 故障现象 #导致LLaMA Factory tokenizer将#识别为普通字符结构信号完全丢失。3.3 第三道工序三重去重与去噪的实操配置去重不是简单dedupe而是分层防御第一层URL级去重采集时用SimHash算法计算URL指纹相似度0.95视为同一页面处理www/非www、参数排序差异。存储在Redis中采集前先查重。第二层文本级去重清洗后不用传统MD5对长文本不敏感而用MinHashLSH将文本分词为3-gram如“故障代码E01”→[故障代,障代码,代码E01]用MinHash生成128维签名LSH桶中查找相似签名阈值0.8实测对“故障代码E01电源电压过低”和“E01故障输入电压偏低”识别率达99.2%。第三层语义级去重LLaMA Factory前用Sentence-BERT计算句子向量对余弦相似度0.92的句子对保留长度更长、含更多专业术语的那个。例如S1 检查电源输入电压S2 用万用表测量L1/N间电压应为380V±10%S2被保留因其含具体工具万用表、参数380V±10%、位置L1/N间。去噪则采用“规则模型”双引擎规则引擎处理85%噪声删除所有含scriptstyleiframe的HTML残留过滤连续重复字符5个如“aaaaa”“?????”屏蔽含“免费下载”“VIP专享”“扫码关注”等广告关键词的段落小模型引擎处理15%顽固噪声微调tiny-bert二分类模型输入文本输出[0,1]0噪声1有效。训练数据来自人工标注的5000条样本重点学习低信息密度句式如“本文将详细介绍……”“接下来我们来看……”逻辑矛盾如“温度应低于0℃”与“设备工作环境-20℃~60℃”冲突术语滥用如把“PLC”写成“PLC控制器”而手册中统一称“PLC”实操心得去重阈值宁严勿松。某次设LSH阈值0.8漏掉一批“故障代码E01电源电压过低”和“E01输入电压不足”的相似文本导致模型对“电压不足”表述泛化能力差。后调至0.85虽多删3%数据但模型在测试集上的F1值提升5.7%。3.4 第四道工序LLaMA Factory数据处理的参数精调LLaMA Factory的data process命令表面简单但参数组合决定数据质量上限llamafactory-cli data process \ --dataset_dir ./cleaned_markdown \ --template default \ --tokenizer_name /path/to/qwen2-tokenizer \ # 必须与后续训练tokenizer一致 --max_length 2048 \ --overwrite_cache \ --preprocessing_num_workers 16 \ --max_samples 5000000 \ --split train \ --cache_dir ./cache关键参数详解--max_length 2048不是越大越好。过长会导致padding过多浪费显存。我们实测对工业文本2048能覆盖92%的完整故障描述解决方案而4096会使平均padding率升至38%。若需更长上下文应改用packing模式将多段短文本拼成一条。--preprocessing_num_workers 16worker数≠CPU核心数。实测在64核服务器上设为16时IO吞吐最高设为32时磁盘IOPS饱和处理速度反降12%。建议公式min(16, CPU核心数/4)。--max_samples 5000000硬限制总样本数。防止意外混入海量低质数据。某次因爬虫bug抓取了某论坛10年灌水帖靠此参数及时熔断。--template default这是关键default模板会自动处理Markdown标题#故障现象#→s### 故障现象 ###\n##E01##→s### E01 ###\n若用alpaca模板则#被忽略结构全失。必须确认模板源码llamafactory/data/templates.py中default函数是否包含re.sub(r^#(.*?)#$, r### \1 ###, text)逻辑。--overwrite_cache强制重建缓存。开发阶段必开避免旧缓存污染。但生产环境应关掉用--cache_dir指定独立路径便于版本管理。注意所有参数必须与train命令完全一致否则tokenizer输出维度不匹配。我们用Makefile统一管理DATA_ARGS --dataset_dir ./cleaned --template default --tokenizer_name ./tokenizer --max_length 2048 process: llamafactory-cli data process $(DATA_ARGS) train: llamafactory-cli train $(DATA_ARGS) --model_name_or_path ./qwen2-1.5b3.5 第五道工序数据质量验证的黄金三指标处理完的数据不能直接进训练必须通过三道验证指标1Token分布健康度统计top-1000 token的频率分布。健康数据应呈“长尾分布”前10个token如s/s.,的了占比15%前100个占比45%。若前10个占比25%说明大量重复模板文本如“故障代码”“解决方案”未清洗干净。指标2实体覆盖完整性用spaCy加载领域NER模型扫描全部数据统计237个核心概念的出现频次。要求关键概念如“轴承”“变频器”“PLC”覆盖率100%次要概念如“IGBT”“RS485”“Modbus”覆盖率≥95%若某概念缺失立即回溯采集源补充专项爬取。指标3Markdown结构合规率正则校验所有#xxx#标记开闭标记成对出现#A#后必有#A#嵌套深度≤3#A##B###C###合法#A##B###C####D####非法标记内无换行符合规率99.9%则拒绝入库。某次因编辑器自动换行导致#故障代码E01#被切为两行LLaMA Factory解析失败。验证脚本输出示例[✓] Token分布前10 token占比12.3% (健康阈值15%) [✓] 实体覆盖237/237核心概念全覆盖最低频次RS4851842次 [✗] Markdown结构发现17处嵌套超深位置./data/manual_023.md:45:8 → 自动修复截断至三级生成警告日志 [✓] 结构合规率99.998%4. 实操过程全记录从零构建一个500GB工业故障数据集的12天4.1 Day 1-2需求冻结与采集基建搭建目标产出可运行的采集脚本覆盖3类核心数据源。上午与5位设备工程师闭门会议确认237个概念的优先级。将“轴承故障”“电机过热”“PLC通信中断”列为Top3要求数据量各≥20万条。下午搭建采集环境。网页爬虫Scrapy PuppeteerDocker部署规避本地Chrome版本冲突PDF处理pymupdf mathpix API申请教育版免费额度API对接用Postman调试企业知识库API导出OpenAPI 3.0规范用openapi-generator生成Python SDK晚上编写首个采集脚本crawl_manuals.py目标西门子、ABB、三菱三大品牌官网手册。关键代码片段# 处理动态加载的手册列表页 browser.goto(https://support.siemens.com/manuals) browser.wait_for_selector(.manual-card, timeout30000) # 等待卡片加载 cards browser.query_selector_all(.manual-card) for card in cards: url card.query_selector(a).get_attribute(href) # 用pymupdf下载PDF并提取文本 doc fitz.open(download_pdf(url)) text for page in doc: text page.get_text(text) # 优先用文本层 if not text.strip(): # 无文本层则OCR pix page.get_pixmap(dpi150) ocr_result mathpix_api(pix.tobytes()) text ocr_result[text] # 保存为Markdown注入结构标记 with open(f./raw/{hash(url)}.md, w) as f: f.write(f#设备手册#\n##{card.query_selector(h3).inner_text()}##\n{text})成果采集到127份手册体积23GB但发现32份为扫描版触发OCR流程。4.2 Day 3-4清洗规则引擎开发与验证目标建立可配置的清洗规则库人工抽检通过率≥95%。规则开发HTML残留re.sub(r(script|style|iframe|noscript)[^]*.*?/\1, , text, flagsre.DOTALL)广告文本re.sub(r(免费|VIP|扫码|关注).*?(?\n\n|\Z), , text)页眉页脚用pymupdf获取页面尺寸定义顶部10%、底部5%为页眉页脚区只删该区域文本验证方法随机抽取1000条清洗后文本由2位工程师盲审。标准A级错误致命事实错误、安全风险如“可带电操作”写成“必须断电”→ 0容忍B级错误严重逻辑断裂、术语错误 → ≤2条C级错误一般标点缺失、空格不规范 → ≤20条结果首轮抽检B级错误17条主因是“变频器”被误替换为“变频器通用”。优化规则增加白名单[变频器, PLC, 轴承]禁止替换括号内术语。4.3 Day 5-6Markdown结构化与跨文档引用目标为所有文本注入语义标记建立知识图谱雏形。自动化注入编写inject_md_structure.py用正则识别^故障现象(.*)$→#故障现象#\n##\1##^可能原因(.*)$→###可能原因###\n\1参见第(\d\.\d)节→参见[第\1节](#section-\1)手动增强对Top10手册人工添加在“解决方案”章节末尾添加##关联故障##列出3个易混淆故障如E01电源故障与E05过载故障在“预防措施”章节添加##标准依据##链接GB/T 12345-2023条款引用解析用spaCy提取所有[第x.y节]生成references.json{ section-3-2: {source: manual_023.md, title: 电机过热处理}, section-5-1: {source: manual_087.md, title: 冷却系统维护} }供后续训练时做负采样避免模型将无关章节关联。4.4 Day 7-8LLaMA Factory处理与缓存优化目标产出可训练的arrow数据集处理速度≥5000条/秒。参数调优实验workerstime(min)GPU内存占用padding率84212GB28%162318GB26%322524GB38%选定16 workers平衡速度与资源。缓存策略--cache_dir ./cache_v1避免与旧版本冲突。处理后校验ls ./cache_v1 | wc -l应等于预期样本数×1.2含中间缓存。输出验证用datasets.load_from_disk(./cache_v1)加载检查dataset load_from_disk(./cache_v1) print(dataset[0][input_ids][:10]) # 应为[151643, 151644, ...] token ID print(dataset[0][attention_mask][:10]) # 应为[1,1,1,...]4.5 Day 9-10质量验证与问题修复目标三指标全部达标生成最终数据集industrial-fault-v1.arrow。Token分布分析用transformers加载tokenizer统计from collections import Counter all_tokens [] for sample in dataset: all_tokens.extend(sample[input_ids]) freq Counter(all_tokens).most_common(1000) top10_ratio sum(v for k,v in freq[:10]) / len(all_tokens) # 结果12.3% → 合格实体覆盖扫描加载spaCy模型zh_core_web_sm扩展工业术语nlp spacy.load(zh_core_web_sm) ruler nlp.add_pipe(entity_ruler) patterns [{label: FAULT_CODE, pattern: E[0-9]{2}}] ruler.add_patterns(patterns) # 扫描全部数据生成coverage_report.csv问题修复发现“RS485”覆盖率仅89%因部分手册用“RS-485”。新增清洗规则text.replace(RS-485, RS485)并加入术语词典。4.6 Day 11-12交付与基线训练目标交付数据集完成首轮预训练验证。交付物industrial-fault-v1.arrowHuggingFace Dataset格式data_quality_report.pdf三指标图表问题清单README.md数据来源、许可证、结构说明基线训练用Qwen2-1.5B在8*A100上训1天llamafactory-cli train \ --model_name_or_path qwen2-1.5b \ --dataset_dir ./industrial-fault-v1.arrow \ --template default \ --max_length 2048 \ --per_device_train_batch_size 8 \ --learning_rate 2e-5 \ --num_train_epochs 1验证指标Loss从2.31降至1.42在自建测试集1000条故障问答上准确率68.3%随机基线32.1%关键观察模型能正确区分“E01电源故障”与“E05过载故障”证明数据结构化有效。5. 常见问题与排查技巧实录那些让项目延期三天的“小问题
返回列表