neuroflow-cpp / scripts /gen_distill_data.py
cwenzi's picture
Upload folder using huggingface_hub
26d5b81 verified
Raw
History Blame Contribute Delete
6.36 kB
#!/usr/bin/env python3
"""
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
# DeepSeek API (Anthropic-compatible endpoint)
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()
# Extract text from response
for choice in data.get("content", []):
if choice.get("type") == "text":
return choice.get("text", "")
# Fallback: try standard format
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('#')]
# Default: diverse Chinese prompts from different domains
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")
# Expand: each prompt × repeat times with different temperatures
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]}")
# Rate limit: ~60 requests/min to be safe
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)")
# Save stats
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()