ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

从自我造题到自我迭代:35B模型如何用数据飞轮逼近万亿参数

从自我造题到自我迭代:35B模型如何用数据飞轮逼近万亿参数 最近“35B 干赢万亿参数大模型”这个话题在 AI 社区里讨论度很高核心点倒不只是“小模型打败大模型”这个结果而是背后的训练思路变了模型开始给自己造题再靠着自我迭代一步步变强。很多同学看到这类新闻第一反应是“这又是营销号标题党吧”但深入研究后会发现这其实是数据驱动范式下很扎实的一条技术路线。这篇文章我想从一个工程开发者的视角把这个话题拆开来看先讲清楚“自我造题 自我迭代”到底是怎么工作的再给出一套简化的可运行代码闭环最后聊一聊 35B 规模模型在部署和推理阶段可能遇到的工程问题包括很多人关心的 TTFTTime To First Token首 token 延迟偏高问题。无论你是准备入门大模型训练还是已经在做模型微调和本地部署这篇文章都可以给你一个比较完整的参考。1. 从“拼参数”到“拼数据”一个 35B 模型的新故事1.1 为什么 35B 模型能叫板万亿参数过去两年大模型的军备竞赛几乎等于参数竞赛从百亿到千亿再到万亿模型越大似乎能力就越强。这种“大力出奇迹”的思路在早期非常有效因为它直接提升了模型的容量、记忆能力和泛化表现。但随着模型规模增长边际收益开始下降。一个万亿参数模型的训练成本极高推理成本也不低不是所有团队都有能力玩得起。更重要的是参数规模只是能力的一个维度数据质量和训练范式往往对最终效果影响更大。最近上海交通大学相关研究团队探索的方向就是在这个背景下出现的。通过让 35B 规模的模型自己生成题目、自己作答、自我筛选高质量数据并在训练过程中不断迭代模型在部分任务上的表现可以逼近甚至超过规模大得多的模型。乍一听很玄但背后的逻辑并不复杂模型的能力上限除了取决于参数容量还取决于它见过多少高质量、高覆盖度的数据。如果能让模型不断发现自己的盲区并针对性地补齐那么在一个相对较小的模型上也能激发出相当强的能力。1.2 这套路线的关键词自我造题、自我迭代、闭环评估要理解这种训练方式先要抓住几个关键词。自我造题Self-Question Generation不是由人类标注员去写训练题而是让模型根据已有知识、已有数据和任务目标自己生成新的问题或任务。这个过程可以不断扩展数据覆盖范围尤其是那些原始语料中没有充分覆盖的“长尾场景”。自我迭代Self-Training / Iterative Training模型生成新数据后经过筛选、修正再拿这些数据继续训练出一个新版本。新版本再次生成数据、再次训练循环往复。每一轮迭代模型都在用自己的能力“向上爬”。闭环评估Closed-loop Evaluation如果模型自己出题又自己回答很容易“自说自话”——出的题越来越简单给出的答案看似流畅但其实是错误的这就是典型的模型退化。所以必须引入一个评估机制例如规则校验、验证器模型或者由更强的模型打分来确保每一轮留下的数据是真正高质量、有价值的。从工程角度看这其实就是一个“数据飞轮”生成 → 评估 → 筛选 → 训练 → 再生成。关键在于每一环都要可控、可度量。2. 核心原理拆解模型如何“给自己造题”2.1 自我造题的本质是数据增强我们可以把自我造题看成一种更高级的数据增强。传统的 NLP 数据增强做的是同义词替换、回译、随机删除等操作本质上是把已有数据做轻微扰动。而自我造题是让模型基于“任务意图”和“已知答案”反向生成问题生成的内容在语义上更丰富。比如我们希望模型掌握“Python 异常处理”这个知识点传统方式需要人工找几千道笔试题目。而自我造题的做法是给模型一段关于异常处理的资料或者一个相关的简单问答对。让模型根据资料生成多个角度的问题。再让模型回答自己生成的问题。用验证器判断答案是否正确、逻辑是否通顺。这个过程可以批量执行而且生成问题的角度往往比人工设计更发散能覆盖更多边界场景。2.2 质量过滤是整个流程的灵魂自我造题最大的风险不是生成不了题目而是生成的题目质量太差。如果模型生成的题目本身就是错误诱导型的或者答案存在事实幻觉那么把这些数据拿去训练模型只能越训越差。所以一个严格的训练闭环必须包含质量过滤层。常见的做法有过滤手段说明优点缺点规则过滤检查长度、关键词、格式速度快、成本低只能过滤明显问题验证器模型训练一个小模型判断答案好坏可扩展性好需要额外训练数据强模型打分用更强的大模型给回答打分效果较好成本较高人工抽检小批量人工审核质量最可靠无法规模化在真实项目中这些方法通常是组合使用的。先用规则过滤掉低质量样本再抽样交给强模型或人工评估形成一套“机器初筛 人为抽检”的机制。2.3 迭代训练一轮、两轮、三轮……直到收敛迭代训练的过程可以这样理解第 0 轮用已有的种子数据训练一个基础模型。第 1 轮用基础模型生成一批新题经过筛选后加入训练集训练出 v1 版本。第 2 轮用 v1 版本生成新题重点去覆盖上一轮模型答错的题目训练出 v2 版本。第 N 轮直到模型在验证集上的提升不再明显或者达到预先设定的数据量上限。每一轮迭代中需要重点记录模型在哪些问题上得分低、在哪些问题上得分高。下一轮造题时应该让模型多生成那些让它“翻车”的题目类型形成一种针对性的补强训练。这和人类备考很像刷第一遍题时发现薄弱点然后重点做错题再做第二遍题分数自然就上去了。3. 为什么要用 35B 而不是 7B 或万亿参数3.1 参数规模和能力的“甜点区间”7B 模型成本低、速度快但复杂推理能力往往不足。当模型能力不够时它“自己给自己造题”就容易产生一种虚假繁荣题目简单、答案套路化、评估得分虚高但放到真实场景下很快就露馅。万亿参数模型能力最强但训练和推理成本太高普通团队很难持续做多轮迭代。而且模型太大时单次推理耗时明显增加生成一批数据的成本也会被放大很多倍。35B 处于一个比较合适的“甜点区间”参数量足够支撑复杂的推理和生成任务又不会像千亿、万亿模型那样让训练和部署成本失控。多轮迭代所产生的算力消耗是很多高校实验室和中小团队可以承受的。3.2 算力成本与部署成本从部署角度看35B 模型经过 4bit 量化后显存需求大概在 20GB 左右普通消费级显卡勉强能跑。如果是 FP16 精度大概需要 70GB 显存需要专业显卡或多卡环境。相比万亿参数模型动辄需要数十张甚至上百张高端 GPU 才能部署35B 模型显然更适合做实验迭代和私有化部署。这种成本优势让“多轮自我迭代”成为可能。3.3 与知识蒸馏、强化学习的联系与区别很多人会把这种“自我造题 自我迭代”和知识蒸馏、强化学习混淆这里简单区分一下知识蒸馏通常用一个强大的教师模型生成数据训练一个小学生模型。核心是“学生从教师那里学知识”教师本身不参与迭代。强化学习RLHF/RLVR模型生成结果后通过奖励模型或规则函数计算奖励再用策略梯度等方法更新模型。自我迭代可以看作一种简化的策略优化只不过它的“奖励信号”更多体现在数据筛选上而不一定是端到端的梯度更新。自我迭代训练教师和学生可以是同一个模型上一轮的模型生成数据训练出下一轮的模型然后再由新模型去生成数据。整个过程更像“自己当自己的老师”而不是依赖一个固定的大模型。这种范式的优势是模型的最终能力不完全依赖于某个外部教师模型的强弱只要数据筛选机制足够可靠模型就能持续进步。4. 实战搭建一个轻量级“自我造题 自我迭代”训练闭环理论讲再多不如动手跑一遍。下面我用一套示例代码演示如何用很简单的流程实现一个迷你版的“自我造题 自我迭代”闭环。需要注意的是真实的大模型训练远比这个复杂下面的代码是为了展示核心流程帮助你理解框架不能直接用于生产级训练。4.1 环境准备建议使用 Python 3.10 或更高版本并创建一个独立的虚拟环境。python -m venv venv source venv/bin/activate # Windows 下使用 venv\Scripts\activate安装需要的依赖pip install torch transformers datasets accelerate版本说明torch建议安装当前官方稳定版transformers和datasets也建议使用较新版本。如果你的机器有 GPU请安装对应 CUDA 版本的 PyTorch具体命令参考 PyTorch 官网。4.2 项目结构self_train_demo/ ├── config.yaml ├── scripts/ │ ├── generate_questions.py │ ├── generate_answers.py │ ├── filter_samples.py │ └── train_loop.py └── data/ ├── seed.jsonl ├── round1/ └── round2/config.yaml用来保存迭代轮数、模型路径、最大生成长度等参数避免把超参数硬编码在代码里。# config.yaml model_name: Qwen/Qwen2.5-7B-Instruct # 示例模型可按实际环境调整 max_new_tokens: 512 temperature: 0.7 filter_min_length: 50 iterations: 3说明示例中使用的是 7B 模型主要是为了演示流程。实际复现“35B 自我迭代”思路时可以把model_name换成一个 35B 规模的开源模型。4.3 第一轮生成训练题目我们先准备一小批种子数据作为模型生成题目的起点。{topic: Python 异常处理, context: try/except/finally 的基本用法} {topic: SQL 索引失效, context: 索引列上使用函数导致索引失效} {topic: 大模型推理优化, context: KV Cache 与首 token 延迟的关系}生成题目的脚本如下# scripts/generate_questions.py import json import random seed_file data/seed.jsonl output_file data/round1/questions.jsonl question_templates [ 请结合具体示例解释{topic}的核心原理。, 在{topic}中最常见的坑是什么如何排查和解决, 如果要给初学者讲清楚{topic}你会怎么组织讲解思路, 针对{topic}你能设计一个进阶练习题吗, ] def load_seed(file_path): with open(file_path, r, encodingutf-8) as f: return [json.loads(line) for line in f if line.strip()] def generate_question(item, template): return template.format(topicitem[topic]) def main(): seed_data load_seed(seed_file) with open(output_file, w, encodingutf-8) as f: for item in seed_data: for template in question_templates: question generate_question(item, template) record { topic: item[topic], context: item.get(context, ), question: question, } f.write(json.dumps(record, ensure_asciiFalse) \n) print(f生成题目完成共 {len(seed_data) * len(question_templates)} 条输出到 {output_file}) if __name__ __main__: main()这段代码的作用是读取种子数据中的主题结合预定义的模板生成多个角度的问题。这里使用模板是为了演示路径实际项目中可以让模型基于context自由生成问题生成方式会灵活得多。4.4 第二轮模型回答题目有了题目之后下一步是让模型自己作答。我们用 Transformers 的pipeline或底层 API 加载模型。# scripts/generate_answers.py import json import torch from transformers import AutoModelForCausalLM, AutoTokenizer question_file data/round1/questions.jsonl answer_file data/round1/answers.jsonl model_name Qwen/Qwen2.5-7B-Instruct def load_questions(file_path): with open(file_path, r, encodingutf-8) as f: return [json.loads(line) for line in f if line.strip()] def main(): tokenizer AutoTokenizer.from_pretrained(model_name) model AutoModelForCausalLM.from_pretrained( model_name, torch_dtypetorch.float16, device_mapauto, ) questions load_questions(question_file) with open(answer_file, w, encodingutf-8) as f: for idx, item in enumerate(questions): messages [ {role: system, content: 你是一个严谨的技术助手请用清晰、准确的语言回答问题。}, {role: user, content: item[question]}, ] text tokenizer.apply_chat_template( messages, tokenizeFalse, add_generation_promptTrue, ) inputs tokenizer(text, return_tensorspt).to(model.device) outputs model.generate( **inputs, max_new_tokens512, do_sampleTrue, temperature0.7, ) answer tokenizer.decode(outputs[0][inputs[input_ids].shape[1]:], skip_special_tokensTrue) record { id: idx, topic: item[topic], question: item[question], answer: answer.strip(), } f.write(json.dumps(record, ensure_asciiFalse) \n) print(f[{idx 1}/{len(questions)}] 生成完成) print(f答案生成完毕输出到 {answer_file}) if __name__ __main__: main()这段代码里需要注意几个地方apply_chat_template会按照模型自身的对话格式拼接消息不同模型的模板不同用这个方法最稳妥。max_new_tokens控制生成的最大 token 数避免模型无限输出。do_sample和temperature控制生成的随机性。自我造题阶段需要一定的随机性才能让题目更多样。4.5 第三轮质量过滤生成答案之后不能直接拿去训练必须过滤。下面是一个简化版过滤脚本。# scripts/filter_samples.py import json answer_file data/round1/answers.jsonl filtered_file data/round1/filtered.jsonl MIN_LENGTH 50 def is_high_quality(record): answer record[answer] # 1. 长度过滤太短说明回答不完整 if len(answer) MIN_LENGTH: return False # 2. 关键词过滤判断回答是否覆盖了主题相关内容 topic_keywords { Python 异常处理: [try, except, finally, 异常], SQL 索引失效: [索引, 查询, 优化], 大模型推理优化: [KV, 缓存, 推理, 延迟], } topic record[topic] keywords topic_keywords.get(topic, []) if keywords: if not any(keyword.lower() in answer.lower() for keyword in keywords): return False # 3. 简单去重过滤重复内容 if 不知道 in answer or 我不确定 in answer: return False return True def main(): passed 0 with open(answer_file, r, encodingutf-8) as fin, \ open(filtered_file, w, encodingutf-8) as fout: for line in fin: if not line.strip(): continue record json.loads(line) if is_high_quality(record): fout.write(json.dumps(record, ensure_asciiFalse) \n) passed 1 print(f过滤完成保留 {passed} 条高质量样本输出到 {filtered_file}) if __name__ __main__: main()真实项目里这种规则过滤只能作为第一道防线。更好的做法是训练一个小型验证器模型或者调用一个强模型对回答进行打分。打分提示词可以参考下面这种写法请对以下回答进行评分评分标准包括 1. 正确性是否有事实错误 2. 完整性是否覆盖问题核心 3. 清晰度是否容易理解 请输出 1-5 分并给出简短理由。用这种提示词调用强模型可以得到一个相对可靠的“数据质量分”再根据分数阈值决定是否保留样本。4.6 第四轮微调与下一轮迭代过滤后的数据需要转成训练集然后对模型做一次有监督微调。# scripts/train_loop.py import json from datasets import Dataset from transformers import ( AutoModelForCausalLM, AutoTokenizer, Trainer, TrainingArguments, ) filtered_file data/round1/filtered.jsonl output_dir models/round1 def load_filtered_data(file_path): samples [] with open(file_path, r, encodingutf-8) as f: for line in f: if not line.strip(): continue record json.loads(line) samples.append({ question: record[question], answer: record[answer], }) return samples def build_dataset(samples, tokenizer): texts [] for sample in samples: messages [ {role: user, content: sample[question]}, {role: assistant, content: sample[answer]}, ] text tokenizer.apply_chat_template(messages, tokenizeFalse) texts.append(text) encodings tokenizer( texts, truncationTrue, paddingTrue, max_length1024, return_tensorspt, ) encodings[labels] encodings[input_ids].clone() return Dataset.from_dict(encodings) def main(): tokenizer AutoTokenizer.from_pretrained(Qwen/Qwen2.5-7B-Instruct) model AutoModelForCausalLM.from_pretrained( Qwen/Qwen2.5-7B-Instruct, torch_dtypeauto, device_mapauto, ) samples load_filtered_data(filtered_file) dataset build_dataset(samples, tokenizer) training_args TrainingArguments( output_diroutput_dir, num_train_epochs3, per_device_train_batch_size1, gradient_accumulation_steps4, save_strategyepoch, logging_steps10, fp16True, report_tonone, ) trainer Trainer( modelmodel, argstraining_args, train_datasetdataset, ) trainer.train() trainer.save_model(output_dir) tokenizer.save_pretrained(output_dir) print(f第一轮微调完成模型保存到 {output_dir}) if __name__ __main__: main()训练完成后把output_dir作为下一轮的model_name重新执行“生成题目 → 生成答案 → 过滤 → 微调”的流程就实现了自我迭代。4.7 运行与验证运行顺序如下cd self_train_demo python scripts/generate_questions.py python scripts/generate_answers.py python scripts/filter_samples.py python scripts/train_loop.py每轮迭代结束后建议在固定验证集上评测模型效果观察指标是否仍在提升。如果连续两轮指标没有明显变化说明训练已经趋于收敛继续迭代的意义不大应该考虑调整数据生成策略或模型容量。5. 从训练回到部署35B 规模模型的本地落地经验训练只是一个环节对一个 35B 规模模型来说部署和推理同样值得关注。模型做自我迭代时每轮都要生成大量数据如果推理速度太慢整个实验周期会被大幅拉长。5.1 显存与内存估算思路35B 模型以 FP16 精度加载时光权重就需要大约 70GB 显存。如果做 4bit 量化权重可压缩到 20GB 左右配合少量 KV Cache单张 24GB 显存的消费级显卡有机会跑起来。估算公式可以简化成模型权重显存 ≈ 参数量 × 每个参数的字节数 FP1635B × 2 字节 ≈ 70GB INT835B × 1 字节 ≈ 35GB INT435B × 0.5 字节 ≈ 17.5GB这个估算只是权重大小实际推理还需要额外的 KV Cache、激活值、CUDA context 等内存所以最终显存需求通常会更高。部署前建议预留 20%-30% 的余量。5.2 Ollama 部署示例如果你只想快速把模型跑起来体验效果用 Ollama 是一条捷径。Ollama 支持从模型仓库拉取量化后的模型一条命令就能启动本地服务。ollama pull qwen2.5:35b ollama run qwen2.5:35b启动后可以调用本地 APIcurl http://localhost:11434/api/generate -d { model: qwen2.5:35b, prompt: 请用通俗易懂的话解释一下什么是 KV Cache。, stream: false }提示不同版本的 Ollama 对模型命名、API 参数略有差异具体以你安装的版本为准。5.3 为什么 MoE 架构的 35B 模型 TTFT 可能偏高很多人在讨论“为什么 Qwen 3.6 35B A3B 的 TTFT 比较高”这类问题。这里先说结论TTFT 高不一定代表模型变笨了而是推理流程中存在额外的计算开销。TTFT 指的是从用户发起请求到模型生成第一个 token 之间的耗时。影响 TTFT 的主要因素有因素说明Prefill 阶段计算量输入 prompt 越长prefill 计算越大TTFT 越高KV Cache 初始化需要根据输入长度分配并计算 KV Cache模型架构复杂度MoE 模型要计算路由决定每个 token 激活哪些专家硬件性能GPU 算力、显存带宽、内存带宽都影响耗时并发负载同一时刻请求越多排队等待越久MoEMixture of Experts混合专家模型虽然总参数量很大但每个 token 只激活一部分专家推理时真正参与计算的参数并不多。比如 35B A3B意思是总参数 35B激活参数只有 3B理论上推理速度应该比同规模稠密模型快。但实际情况是MoE 模型在 prefill 阶段需要把所有专家加载进显存路由网络要计算每个 token 与每个专家的匹配概率。如果推理框架没有针对 MoE 做优化或者硬件无法同时容纳所有专家那么 TTFT 反而不低。5.4 推理优化方向想让 35B 模型在实际项目中跑得更顺畅可以考虑以下优化方向使用 vLLM、TensorRT-LLM 等推理框架它们对 KV Cache 和 MoE 路由做了深度优化。启用前缀缓存prefix caching当多个请求共享相同系统提示词时可以复用 prefill 结果。减少输入长度控制 context 大小LLM 处理 long context 时 TTFT 会线性增长。做量化部署INT8/INT4 可以降低显存带宽压力但会带来一定精度损失。使用多卡并行或异步调度提升整体吞吐。6. 常见问题与排查思路在实际实践过程中最容易踩到的坑主要集中在数据生成、训练稳定性、部署推理三个环节。问题现象常见原因解决思路模型生成的题目越来越简单模型为了快速完成任务倾向于生成低难度问题在生成提示词中加入“需要覆盖边界情况”约束用验证器对题目难度打分模型回答内容重复采样参数设置不合理温度过低导致多样性不足提高 temperature 到 0.8-1.0增加 top_p 采样过滤后数据量太少无法支撑微调种子数据主题太集中或过滤条件过于严格扩充种子主题放宽关键词匹配规则增加强模型打分环节训练 loss 下降但验证集效果没提升数据分布和验证集分布不一致检查数据集分布确保训练数据覆盖验证集任务类型TTFT 一直很高输入文本过长或推理框架未优化精简 prompt使用前缀缓存尝试 vLLM 等推理框架多轮迭代后模型能力退化生成数据质量下降模型学到错误模式引入人类抽检机制增加验证器降低每一轮新生成数据的比例这里想重点提醒一个容易被忽略的坑多轮迭代后模型能力退化这是一个真实存在的风险。由于每一轮训练数据都是由上一轮模型生成的如果某一步过滤不严错误信息就会在后续迭代中不断放大最终导致模型产生“自我崩溃”self-collapse现象。预防措施是保留一部分原始种子数据每一轮混合一定比例的人类高质量数据同时每轮迭代都在固定 benchmark 上做回归测试。7. 最佳实践与工程建议7.1 数据版权与合法授权自我造题虽然能自动生成大量数据但生成过程中模型可能会隐式引用训练语料中的内容。在实际项目中要特别注意不要使用未经授权爬取的书籍、论文、商业文档。对于种子数据要确保来源有合法授权。生成的数据如果要对外发布或商用建议做一轮敏感信息识别和版权审查。7.2 验证器与奖励模型不要完全相信模型自己生成的答案。一个严谨的训练闭环应该包含多层验证第一层规则校验如格式、长度、关键词。第二层模型互评使用另一个模型对生成结果打分。第三层人工抽检随机抽取 5%-10% 的样本进行人工审核。人工抽检虽然成本高但它能发现验证器模型的盲区也能帮助我们持续改进自动过滤规则。7.3 训练日志与版本管理多轮迭代训练会产生多个版本的模型和数据集如果不做版本管理很容易出现“不知道某个数据是哪一轮生成的”“这个模型是用哪个数据集训练的”这种混乱情况。建议为每一轮迭代建立独立目录并记录迭代轮次编号。种子数据来源。生成数据的提示词和采样参数。过滤规则和保留数量。训练超参数。验证集评测结果。这些信息可以写在一个 CSV 或 Markdown 文件里也可以直接作为模型目录下的 README 保存。7.4 安全边界与权限控制如果模型最终要接入业务系统不能忽略安全边界用户输入要经过内容安全过滤防止恶意 prompt 注入。模型输出也要做合规检查不能把未经审核的内容直接展示给用户。训练和标注过程中涉及用户数据的部分要脱敏处理。部署到公网前确认服务具备认证、限流、审计能力。8. 从学术亮点到工程能力“35B 干赢万亿参数”听起来很惊艳但真正的价值不在于参数数量的对比而在于它验证了一条新的能力提升路径高质量数据的自主生产能力 闭环迭代机制。以前我们想提高模型能力第一反应是加参数、加数据、加算力。现在我们看到在模型参数不变甚至更小的情况下通过让模型自己出题、自己纠错、自己迭代也能走出一条持续进化的路。如果你是做应用开发的可以从数据生成与质量过滤入手把这套思路用在垂直领域的数据增强上。如果你是做算法研究的可以进一步探索验证器设计、迭代收敛条件、以及如何防止自我崩溃。如果你只是对大模型感兴趣先把文章里的简化实战跑一遍你就对“自我迭代”不再感到神秘了。模型的成长本质上也是一次次与自己的薄弱点较量的过程。对 35B 如此对开发者亦然。
返回列表