| |
| """ |
| NeuroFlow 蒸馏数据生成 — 调用 DeepSeek API 获取教师数据 |
| |
| 用法: |
| python3 scripts/gen_distill_data.py --prompts prompts.txt --output teacher_data.jsonl --max-samples 10000 |
| |
| 输出 JSONL 格式: {"prompt": "...", "completion": "...", "teacher_text": "..."} |
| """ |
|
|
| import argparse, json, os, sys, time, random |
| import requests |
|
|
| |
| API_URL = os.environ.get('DEEPSEEK_API_URL', |
| 'https://api.deepseek.com/anthropic/v1/messages') |
| API_KEY = os.environ.get('DEEPSEEK_API_KEY', |
| os.environ.get('ANTHROPIC_AUTH_TOKEN', '')) |
| HEADERS = { |
| "Authorization": f"Bearer {API_KEY}", |
| "Content-Type": "application/json", |
| } |
|
|
|
|
| def call_deepseek(prompt: str, max_tokens: int = 128, temperature: float = 0.7) -> str: |
| """Call DeepSeek API to generate text completion""" |
| payload = { |
| "model": "deepseek-chat", |
| "messages": [{"role": "user", "content": prompt}], |
| "max_tokens": max_tokens, |
| "temperature": temperature, |
| "stream": False, |
| } |
| try: |
| resp = requests.post(API_URL, headers=HEADERS, json=payload, timeout=60) |
| if resp.status_code == 200: |
| data = resp.json() |
| |
| for choice in data.get("content", []): |
| if choice.get("type") == "text": |
| return choice.get("text", "") |
| |
| if "choices" in data: |
| return data["choices"][0]["message"]["content"] |
| else: |
| print(f" API error {resp.status_code}: {resp.text[:200]}") |
| return "" |
| except Exception as e: |
| print(f" API exception: {e}") |
| return "" |
|
|
|
|
| def load_prompts(path: str) -> list: |
| """Load prompts from file (one per line) or generate default Chinese prompts""" |
| if path and os.path.exists(path): |
| with open(path, 'r', encoding='utf-8') as f: |
| return [line.strip() for line in f if line.strip() and not line.startswith('#')] |
|
|
| |
| defaults = [ |
| |
| "请解释量子力学的基本原理", |
| "什么是相对论?用简单的话解释", |
| "人工智能的发展历史是什么", |
| "DNA双螺旋结构的发现过程", |
| |
| "如何求解一元二次方程", |
| "微积分的基本思想是什么", |
| "请解释概率论中的贝叶斯定理", |
| |
| "请写一首关于春天的诗", |
| "唐诗和宋词的区别是什么", |
| "中国四大名著有哪些", |
| |
| "秦始皇统一六国的过程", |
| "工业革命对世界的影响", |
| |
| "如何保持健康的饮食习惯", |
| "怎样提高学习效率", |
| "推荐几种有效的记忆方法", |
| |
| "什么是存在主义", |
| "孔子的仁政思想是什么", |
| |
| "Python编程语言的特点", |
| "什么是深度学习", |
| "区块链技术的基本原理", |
| ] |
| return defaults |
|
|
|
|
| def main(): |
| parser = argparse.ArgumentParser(description='NeuroFlow 蒸馏数据生成') |
| parser.add_argument('--prompts', default='', help='Prompt文件 (一行一个)') |
| parser.add_argument('--output', default='teacher_data.jsonl', help='输出文件') |
| parser.add_argument('--max-samples', type=int, default=1000, help='最大样本数') |
| parser.add_argument('--max-tokens', type=int, default=128, help='教师生成长度') |
| parser.add_argument('--temperature', type=float, default=0.7, help='教师温度') |
| parser.add_argument('--repeat', type=int, default=1, help='每个prompt重复次数(不同温度)') |
| args = parser.parse_args() |
|
|
| prompts = load_prompts(args.prompts) |
| print(f"📝 加载 {len(prompts)} 个 prompts") |
|
|
| |
| all_tasks = [] |
| for p in prompts: |
| for r in range(args.repeat): |
| temp = 0.3 + r * 0.4 / max(1, args.repeat - 1) if args.repeat > 1 else args.temperature |
| all_tasks.append((p, temp)) |
|
|
| random.shuffle(all_tasks) |
| all_tasks = all_tasks[:args.max_samples] |
|
|
| print(f"🎯 目标: {len(all_tasks)} 个样本") |
| print(f"🔑 API: {API_URL}") |
| print() |
|
|
| success = 0 |
| total_chars = 0 |
| t0 = time.time() |
|
|
| with open(args.output, 'w', encoding='utf-8') as out: |
| for i, (prompt, temp) in enumerate(all_tasks): |
| text = call_deepseek(prompt, args.max_tokens, temp) |
|
|
| if text and len(text) >= 10: |
| record = { |
| "prompt": prompt, |
| "completion": text, |
| "temperature": temp, |
| } |
| out.write(json.dumps(record, ensure_ascii=False) + '\n') |
| out.flush() |
| success += 1 |
| total_chars += len(text) |
|
|
| if (i + 1) % 10 == 0: |
| elapsed = time.time() - t0 |
| rate = (i + 1) / elapsed * 60 if elapsed > 0 else 0 |
| print(f" [{i+1}/{len(all_tasks)}] success={success} " |
| f"rate={rate:.0f}/min elapsed={elapsed:.0f}s") |
| else: |
| print(f" [{i+1}] ❌ empty response for: {prompt[:50]}") |
|
|
| |
| if (i + 1) % 50 == 0: |
| time.sleep(1) |
|
|
| elapsed = time.time() - t0 |
| size_mb = os.path.getsize(args.output) / 1e6 if os.path.exists(args.output) else 0 |
|
|
| print(f"\n✅ 完成!") |
| print(f" 样本: {success}/{len(all_tasks)}") |
| print(f" 字符: {total_chars:,}") |
| print(f" 文件: {args.output} ({size_mb:.1f} MB)") |
| print(f" 耗时: {elapsed:.0f}s ({elapsed/60:.1f}min)") |
| print(f" 费用预估: ~${success * 128 / 1e6 * 0.14:.2f} (DeepSeek 输入$0.14/M tokens)") |
|
|
| |
| stats = { |
| "total_samples": success, |
| "total_chars": total_chars, |
| "elapsed_seconds": elapsed, |
| "model": "deepseek-chat", |
| } |
| stats_path = args.output.replace('.jsonl', '_stats.json') |
| with open(stats_path, 'w') as f: |
| json.dump(stats, f, indent=2, ensure_ascii=False) |
| print(f" 统计: {stats_path}") |
|
|
|
|
| if __name__ == '__main__': |
| main() |
|
|