合成数据
→ 返回数据工程
使用算法、模型或仿真生成的数据,而非从真实世界采集。当真实数据稀缺、标注昂贵、或涉及隐私时,合成数据是绕过数据瓶颈的关键手段。
合成数据的价值
| 场景 | 真实数据问题 | 合成数据方案 |
|---|---|---|
| 医疗影像 | 隐私合规限制共享 | GAN 生成患者影像 |
| 罕见场景 | 真实事件极少发生 | 仿真生成极端情况 |
| 指令微调 | 人工标注成本高 | LLM 批量生成指令对 |
| 代码数据 | 特定语言/框架样本少 | 模板+规则生成 |
| 对话数据 | 真实对话难收集 | 模型自我对话 |
主要生成方式
基于 LLM 的文本合成
用大模型生成训练数据,是目前最主流的方式:
import anthropic
client = anthropic.Anthropic()
def generate_instruction_pairs(topic: str, n: int = 100) -> list[dict]:
"""生成指令微调数据对"""
response = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=4096,
messages=[{
"role": "user",
"content": f"""生成 {n} 条关于"{topic}"的指令-回答对,用于微调语言模型。
要求:
1. 指令多样,覆盖解释、比较、计算、分析等不同类型
2. 回答准确、完整、有教育价值
3. 输出 JSON 数组格式:[{{"instruction": "...", "output": "..."}}]
只输出 JSON,不要其他文字。"""
}]
)
import json
return json.loads(response.content[0].text)Self-Instruct / Alpaca 方法
用种子指令 + LLM 自动扩展,生成大规模指令数据:
1. 人工准备 175 条种子指令(覆盖多种任务类型)
2. 随机从种子中采样 3-5 条作为示例
3. 让 GPT/Claude 生成新的指令
4. 过滤低质量(重复、太短、无意义)
5. 重复直到达到目标数量
代表数据集:Alpaca(52K)、Dolly(15K)、OpenHermes
基于模板和规则
适合结构化数据:
import random
def generate_sql_training_data(schema: dict, n: int = 1000) -> list[dict]:
"""根据数据库 schema 生成 NL → SQL 训练对"""
templates = [
("查询{table}中所有{field}大于{value}的记录",
"SELECT * FROM {table} WHERE {field} > {value}"),
("统计{table}中每个{group_by}的数量",
"SELECT {group_by}, COUNT(*) FROM {table} GROUP BY {group_by}"),
]
pairs = []
for _ in range(n):
template_nl, template_sql = random.choice(templates)
# 填充真实的表名、字段名
...
pairs.append({"question": nl, "sql": sql})
return pairsGAN / 扩散模型合成图像
# 使用 diffusers 生成图像数据
from diffusers import StableDiffusionPipeline
pipe = StableDiffusionPipeline.from_pretrained("stabilityai/stable-diffusion-2-1")
pipe = pipe.to("cuda")
prompts = [
"a photo of a cat sitting on a sofa, realistic, high quality",
"a dog running in the park, daylight, photorealistic",
]
for i, prompt in enumerate(prompts * 50):
image = pipe(prompt).images[0]
image.save(f"synthetic_dataset/image_{i}.jpg")质量控制
过滤策略
def filter_synthetic_data(samples: list[dict]) -> list[dict]:
filtered = []
seen = set()
for s in samples:
text = s["instruction"] + s["output"]
# 1. 去重(相似度过高)
if text[:50] in seen:
continue
seen.add(text[:50])
# 2. 长度过滤
if len(s["output"]) < 50 or len(s["output"]) > 2000:
continue
# 3. 质量评分(用小模型打分)
score = quality_score(s)
if score < 0.7:
continue
filtered.append(s)
return filtered数据多样性检查
from sentence_transformers import SentenceTransformer
import numpy as np
def diversity_score(texts: list[str]) -> float:
"""评估合成数据的语义多样性"""
model = SentenceTransformer("all-MiniLM-L6-v2")
embeddings = model.encode(texts)
# 计算平均成对距离(越大越多样)
n = len(embeddings)
distances = []
for i in range(min(n, 500)):
for j in range(i + 1, min(n, 500)):
dist = 1 - np.dot(embeddings[i], embeddings[j])
distances.append(dist)
return np.mean(distances)注意事项
| 风险 | 说明 | 对策 |
|---|---|---|
| 模型坍缩 | 用合成数据训练的模型再生成合成数据,质量递减 | 始终混入真实数据锚点 |
| 偏见放大 | 生成模型的偏见被固化到训练数据 | 多样化提示词,人工审查样本 |
| 幻觉传播 | LLM 生成的错误事实混入训练集 | 对事实性内容做验证或限制使用场景 |
| 版权问题 | 合成数据可能复现训练数据中的受版权内容 | 过滤已知文本,法律评估 |