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

资讯详情

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

基于LoRA微调internlm2的煤矿安全智能问答实践

基于LoRA微调internlm2的煤矿安全智能问答实践 简介面向AI大模型应用与自然语言处理开发者这套资源围绕微调InternLM2模型构建煤矿事故与安全知识智能问答系统提供从语料准备、模型微调到知识库检索问答的完整实现思路。包体共123个文件以Python脚本、ipynb交互式笔记本和txt语料文档为主辅以md说明笔记、png/jpg部署效果图以及docx/doc/pdf安全技术资料压缩包约20.78MB层次清晰便于按模块查阅。内容预览中包含煤矿安全技术措施汇编等原始语料也提供faiss向量索引与基于InternLM2-Chat-1.8B、GLM-4的集成问答Notebook覆盖语料整理、向量检索、模型调用与部署展示等核心环节。目前已有137人学习下载适合具备Python基础、希望快速上手垂直领域大模型微调与RAG问答落地的开发者。对需要将通用大模型落地到工矿安全生产场景的团队来说这份资源也提供了从领域语料到检索问答的完整参考范式。1. 微调internlm2做煤矿安全问答先解决“知识进参数”这一步瓦斯浓度达到 1.5% 时该怎么处置通用大模型通常会说“加强通风、撤出人员、查明原因”但是懂行的人知道这个回答在采煤工作面和掘进工作面、在回风隅角和上隅角处置优先级完全不同。这类细粒度行业知识不在通用模型语料里靠写提示词把规则硬灌进去既脆弱也维持不了几轮对话。用 internlm2 做微调把煤矿事故案例、安全规程条文、应急处置流程批量转成训练样本让模型在 LoRA 微调后把答案“背”进参数里这才是“针对煤矿事故和煤矿安全知识的智能问答”的正规落地方式。整个过程不需要从零训练单卡 24G 显存就能跑通适合矿山信息化工程师、安全培训平台开发者和大模型应用团队直接参考。下面按数据加工、LoRA 微调、合并部署和场景边界控制的顺序展开。2. 煤矿事故语料到 internlm2 微调数据集的加工方法格式、正负样本与转换脚本2.1 为什么数据格式决定了微调的上限internlm2 的对话模板使用 ChatML 风格的结构消息按 role 和 content 区分。直接拿原始文本训练会破坏对话结构因此第一步是把语料统一成框架能识别的格式。常见做法是使用 LLaMA-Factory 这类微调平台它在数据集注册表 dataset_info.json 里声明文件路径和格式类型训练时自动做模板映射。单轮煤矿知识问答用 alpaca 格式即可每一条样本包含 instruction、input、output 三个字段如果后续要做“先问场景、再追问处置细节”的多轮对话换成 sharegpt 格式更合适它的 conversations 数组能精确表达每一轮的角色和内容。对比项alpacasharegpt原生 ChatML字段结构instruction / input / outputconversations 数组messages 数组多轮对话支持弱需手动拼接强强LLaMA-Factory 适配开箱即用开箱即用需自定义注册单轮知识问答够用稍显冗余繁琐数据格式本身不难真正的难点在于怎么从事故报告和安全规程里挖出“可复核的问答对”。我一般按四个来源组织语料事故案例库覆盖瓦斯爆炸、煤与瓦斯突出、顶板事故、水害、火灾、机电运输六类安全规程条文重点抽取通风瓦斯、防灭火、防治水条款现场操作规程和“手指口述”内容以及常见违章行为辨识问答。每个答案都必须带出处依据。2.2 构造一个高质量煤矿安全问答样本以瓦斯超限场景为例alpaca 格式的一条完整样本长这样{ instruction: 某采煤工作面回风隅角甲烷传感器显示瓦斯浓度达到1.5%作为当班瓦斯检查工你的第一处置动作是什么, input: , output: 立即组织回风隅角附近作业人员撤离切断工作面和回风巷内非本质安全型电气设备电源随后向调度室汇报。依据是《煤矿安全规程》对采掘工作面瓦斯浓度超过1.0%停止作业、超过1.5%撤人断电的规定。 }instruction 字段描述具体事故场景要带入地点、岗位和数值避免“瓦斯超限怎么办”这类泛化提问output 字段按处置步骤写先撤人、再断电、后汇报顺序不能颠倒。这类样本的价值在于把“知识点”固定成“场景处置动作”模型在推理时能模仿这种结构化输出。训练集里还应有硬负样本场景类似但事故类型不同处置方式完全不同比如火灾事故要先断电还是先撤人与瓦斯事故的操作优先级就有差异。把这类样本放在相邻训练批次里能有效压制模型把“瓦斯超限”和“火灾”方案混淆。2.3 用 Python 脚本把 Word/Excel 语料批量转成训练集拿到的是打包好的 zip 交付物里面通常只是一批已经切分好的问答对文本。真正要把这些数据转成训练集我一般写一个轻量脚本把原始文本按 Q/A 标记切分后输出 alpaca JSONimport json import re def parse_qas_from_text(text: str): 从事故案例文本中提取(question, answer)对。 约定原始文本中 Q1: 开头为问题A1: 开头为答案。 qas [] current_q None current_a [] for line in text.splitlines(): if re.match(r^Q\d[:], line): if current_q and current_a: qas.append({ instruction: current_q, input: , output: \n.join(current_a) }) current_q re.sub(r^Q\d[:], , line).strip() current_a [] elif re.match(r^A\d*[:], line): current_a.append(re.sub(r^A\d*[:], , line).strip()) elif current_q and line.strip(): current_a.append(line.strip()) if current_q and current_a: qas.append({ instruction: current_q, input: , output: \n.join(current_a) }) return qas with open(mine_safety_raw.txt, encodingutf-8) as f: raw_text f.read() samples parse_qas_from_text(raw_text) with open(mine_safety_alpaca.json, w, encodingutf-8) as f: json.dump(samples, f, ensure_asciiFalse, indent2)这个脚本用正则识别 Q 和 A 标记将所有答案行合并为一个 output 字段。核心逻辑是“当前问题存在且收集到答案行时才追加一条样本”避免空样本或半截问答进入训练集。转换完成后还要按 9:1 比例随机切分训练集和验证集切分时确保同一事故案例的问答对落在同一集合里防止数据泄漏。3. 用 LLaMA-Factory 对 internlm2 做 LoRA 微调最小配置、训练参数与显存控制3.1 LoRA 微调如何把煤矿知识注入 internlm2全参数微调 7B 模型需要几十 GB 显存对普通项目团队并不划算。LoRA 微调的做法是冻结原始权重在注意力层的 Q、K、V、O 投影旁插入低秩矩阵只训练这些增量部分。对 internlm2-chat-7b 来说LoRA 可训练参数量约占全模型的 0.5% 到 1%效果却能在垂直领域问答上逼近全参数微调这也是大模型微调实践里最常见的选型。需要说清楚LoRA 不是在原模型知识上“替换”而是通过大量煤矿语料的引导让模型在安全场景里更倾向输出行业规范要求的处置步骤。训完后原模型对通用问题的能力基本保留但对煤矿问题的回答分布会明显向训练数据靠拢。正因如此训练数据里每一条 output 的规范性都要人工把关脚本里混入一句“大概是这样”的模糊表述最后都会在生成阶段被放大。3.2 最小可用的 LLaMA-Factory 配置文件LLaMA-Factory 是当前开源社区应用最广的微调平台之一它对 internlm2 的模型结构和对话模板适配较成熟不用改模型源码就能跑 LoRA。准备好数据文件 mine_safety_alpaca.json 并放到 data 目录后还需要在 data/dataset_info.json 中注册数据集名{ mine_safety_alpaca: { file_name: mine_safety_alpaca.json, formatting: alpaca, columns: { prompt: instruction, query: input, response: output } } }然后写一个 LoRA 微调用的 yaml 配置model_name_or_path: /models/internlm2-chat-7b dataset: mine_safety_alpaca dataset_dir: data template: intern2 cutoff_len: 2048 lora_rank: 64 lora_alpha: 128 lora_dropout: 0.05 learning_rate: 1.0e-4 num_train_epochs: 3.0 max_samples: 5000 per_device_train_batch_size: 1 gradient_accumulation_steps: 8 lr_scheduler_type: cosine warmup_ratio: 0.03 logging_steps: 1 save_steps: 500 output_dir: output/mine_safety_lora参数里最需要理解的是 lora_rank 和 lora_alpha。lora_rank64 表示低秩矩阵的秩为 64秩越大可学习的表达能力越强但显存占用和过拟合风险同步上升lora_alpha 是缩放系数通常设为 rank 的 2 倍即 128此时实际生效的缩放比例是 alpha / rank。学习率用 1e-4比全参数微调常用的 2e-5 高因为低秩矩阵需要相对更大的更新步长。per_device_train_batch_size 设为 1配合 gradient_accumulation_steps8等效 batch size 为 8在保持训练稳定的同时把显存峰值压下来。3.3 启动训练、观察 loss 与显存不够时的调整手段配置写好后直接用命令行启动训练llamafactory-cli train config/mine_safety_lora.yaml首次运行前建议先手动把 internlm2-chat-7b 权重下载到本地并指定绝对路径避免训练中途因网络问题断掉。训练过程中重点看 loss 曲线前几百步 loss 从 2 左右快速下降是正常现象如果 loss 降到 0.3 以下且验证集指标没有同步提升说明模型开始死记硬背训练样本此时应增大 lora_dropout 到 0.1或减少训练轮次。显存不够时优先启用 gradient_checkpointing 和 bf16显存小于 12G 再考虑 4bit 量化位。训练配置显存占用训练速度适用场景7B LoRA bf16约 18G快单卡 24G 起7B LoRA 4bit 量化约 10G中消费级显卡7B LoRA fp16约 20G快显存充足且卡不支持 bf16提示loss 在训练初期就接近 0多半是训练集和验证集存在重复样本先回数据集查重而不是调参数。4. LoRA 合并、量化部署与基于事故类型的评测4.1 合并 LoRA 权重并用 vLLM 部署智能问答服务LoRA 训练产物是低秩适配器权重不能直接用于常规推理框架。常见做法是先调用 LLaMA-Factory 的导出命令把适配器合并回基础模型生成完整的模型权重目录llamafactory-cli export \ --model_name_or_path /models/internlm2-chat-7b \ --adapter_name_or_path output/mine_safety_lora \ --template intern2 \ --export_dir output/mine_safety_merged \ --export_size 4 \ --export_legacy_format false导出完成后output/mine_safety_merged 就是一个可以直接被 vLLM 加载的完整模型。用 vLLM 部署的优势是吞吐高并内置了 OpenAI 兼容接口方便后续集成到培训系统或矿山安全知识库前端from vllm import LLM, SamplingParams llm LLM( modeloutput/mine_safety_merged, tensor_parallel_size1, gpu_memory_utilization0.85 ) params SamplingParams( temperature0.1, top_p0.9, max_tokens512 ) out llm.chat( messages[{ role: user, content: 掘进工作面发生煤与瓦斯突出预兆时现场作业人员首先应该怎么做 }], sampling_paramsparams ) print(out[0].outputs[0].text)推理参数里 temperature 必须调低安全知识问答是确定性任务temperature 过高会让模型在“断电”“撤人”“汇报”三个动作之间随机排列这在应急场景里是致命的。gpu_memory_utilization 设为 0.85 是给 CUDA context 和后续并发请求留出余量。4.2 评测集不按随机划分按事故类型分层训练完不能只看 loss更重要的卡点是设计评测集。按随机比例切分出的验证集会让模型在同一事故案例的不同问法上“见过答案”评估出来虚高。我一般按事故类型分层抽样从瓦斯爆炸、煤与瓦斯突出、顶板、水害、火灾、机电运输六类案例中各抽出 10% 的问答对单独组成评测集确保每一类事故都有未参与训练的样本。评估时对每个答案做关键词命中率计算def keyword_hit_rate(pred: str, gold_keywords: list) - float: 计算答案对关键动作词的覆盖比例。 gold_keywords 示例: [撤人, 断电, 汇报调度室] if not gold_keywords: return 0.0 hit [kw for kw in gold_keywords if kw in pred] return len(hit) / len(gold_keywords)同时统计四个核心指标指标计算方式合格参考关键步骤准确率关键词命中率超过 0.8 的样本占比90% 以上拒答率模型回答“无法确定”或“超出范围”的占比5% 以下幻觉率答案中出现编造的规程条款或错误数据的占比2% 以下泛化率在未训练事故案例上的准确率与训练集内相差小于 10%4.3 用“事故场景长尾”找模型的翻车点在正式发布前可以准备一组边界测试问题专门压模型不愿回答的里面比较隐蔽的场景比如“井下发生火灾时是否可以开动井下运输车辆”“电气设备起火能不能直接用水灭火”。这些问题常见于培训考试但容易触发模型自由发挥如果微调数据里没有覆盖模型往往会给出一个看起来合理但违反规程的答案。此时回到数据侧补充同类样本比反复调 prompt 更有效。5. 让微调后的 internlm2 准确触达“事故场景”边界System 提示词与规则门控的小技巧5.1 在 System 提示词里写入职权边界和规章版本微调模型在训练分布内表现很好但用户实际提问往往超出训练覆盖。一个低成本的做法是在部署层加上 System 提示词明确告知模型哪些问题可以答、哪些必须拒答同时限定回答依据的规章版本范围system_prompt ( 你是煤矿安全技术问答助手。你只能回答与煤矿事故、煤矿安全规程、 应急处置、违章辨识相关的问题。回答必须基于《煤矿安全规程》及相关行业标准 涉及处置步骤时按先撤人、再断电、后汇报的优先级输出。 如果问题不属于煤矿安全领域或者你无法确定答案直接回答该问题超出我的可回答范围。 ) out llm.chat( messages[ {role: system, content: system_prompt}, {role: user, content: 矿井停电后应该先恢复什么设备} ], sampling_paramsparams )这段 System 提示词的作用相当于在模型输出前加了一道“软护栏”。由于模型经过了煤矿语料的 LoRA 微调它在内部表示上更倾向于响应煤矿相关内容System 层再约束它不要跨界作答两者配合能明显降低幻觉率。实际使用时还可以把矿名、适用的规程版本号直接拼进去方便做多矿部署。5.2 用两段式规则门控拦截“越界提问”System 提示词能拦得住大多数通用问题但用户用“它”“那个东西怎么处理”这种代词指代前文煤矿对象时模型可能误解为跨领域。更稳的做法是在模型调用前加一层轻量规则门控通过安全术语命中判断是否走微调模型SAFETY_TOPICS [ 瓦斯, 突出, 顶板, 水害, 火灾, 粉尘, 机电, 运输, 提升, 通风, 采掘, 爆破 ] def should_route_to_mine_model(query: str) - bool: 命中煤矿安全术语则调用微调模型否则走通用兜底。 可配合对话历史中的上一句场景描述使用。 return any(topic in query for topic in SAFETY_TOPICS)门控逻辑并不复杂但能防止微调模型在完全无关的问题上硬套煤矿话术。对多轮对话场景将当前问题和最近一轮用户消息拼接后一起做术语匹配能覆盖“它怎么处置”这类省略主语的问法。这个技巧的实际价值是把“模型语义边界”和“业务权限边界”分开治理前者靠微调后者靠规则互不干扰。5.3 生成后用规则二次校验核心动作顺序即使 temperature 设到 0.1模型偶尔还是会出现“先汇报、后撤人”这种顺序颠倒。最可靠的兜底是在生成结果上加一个极简校验器检查关键动作的先后关系不满足则重新生成一次def verify_action_order(answer: str) - bool: 校验应急处置步骤优先级。 正确顺序: 撤人 - 断电 - 汇报。 idx_evac answer.find(撤人) idx_power answer.find(断电) idx_report answer.find(汇报) if idx_evac -1: return False if idx_power ! -1 and idx_power idx_evac: return False if idx_report ! -1 and idx_report idx_evac: return False return True校验失败时把 temperature 降到 0.05 并重新生成一次通常就能得到合规结果。这种“生成加校验”的双保险比单纯增大训练数据量更能解决偶发错误也是我把模型交到一线安全培训人员手上之前的最后一道防线。本文还有配套的精品资源点击获取
返回列表