Few-shot学习:小样本学习技术
--- title: "Few-shot学习:小样本学习技术" description: "理解大语言模型中的少样本学习原理和实践技巧" tags: ["Few-shot", "少样本学习", "In-Context Learning", "LLM"] category: "llm" icon: "🧠"
Few-shot学习:小样本学习技术
什么是Few-shot学习
Few-shot学习是指模型仅通过少量标注示例就能学习并完成新任务的能力。在大语言模型中,这通常通过 In-Context Learning(上下文学习)实现。
Few-shot vs Zero-shot vs One-shot
# Zero-shot:无示例
zero_shot = """将以下文本分类为正面或负面情感:
"这家餐厅的服务很棒"
分类:"""
# One-shot:1个示例
one_shot = """将文本分类为正面或负面情感。
示例:
输入:"产品质量太差了"
分类:负面
现在请分类:
输入:"这家餐厅的服务很棒"
分类:"""
# Few-shot:多个示例
few_shot = """将文本分类为正面或负面情感。
示例1:
输入:"产品质量太差了"
分类:负面
示例2:
输入:"非常满意这次购物"
分类:正面
示例3:
输入:"价格偏高但质量不错"
分类:正面
现在请分类:
输入:"这家餐厅的服务很棒"
分类:"""
实现Few-shot分类器
from openai import OpenAI
client = OpenAI()
class FewShotClassifier:
def __init__(self, model="gpt-3.5-turbo"):
self.model = model
self.examples = []
def add_example(self, text, label):
self.examples.append({"text": text, "label": label})
def classify(self, text):
# 构建提示
examples_text = "\n".join([
f"示例{i+1}:\n输入:\"{ex['text']}\"\n分类:{ex['label']}"
for i, ex in enumerate(self.examples)
])
prompt = f"""将文本分类为指定类别。
{examples_text}
现在请分类:
输入:\"{text}\"
分类:"""
response = client.chat.completions.create(
model=self.model,
messages=[{"role": "user", "content": prompt}],
temperature=0
)
return response.choices[0].message.content.strip()
# 使用示例
classifier = FewShotClassifier()
# 添加示例
classifier.add_example("产品很好用,推荐购买", "正面")
classifier.add_example("质量太差了,不推荐", "负面")
classifier.add_example("一般般,没什么特别的", "中性")
# 分类新文本
result = classifier.classify("性价比很高,值得入手")
print(f"分类结果: {result}")
示例选择策略
1. 基于相似度选择
from sentence_transformers import SentenceTransformer
import numpy as np
class DynamicFewShot:
def __init__(self):
self.model = SentenceTransformer('paraphrase-multilingual-MiniLM-L12-v2')
self.examples = []
def add_example(self, text, label):
embedding = self.model.encode([text])[0]
self.examples.append({
"text": text,
"label": label,
"embedding": embedding
})
def select_examples(self, query, k=3):
query_embedding = self.model.encode([query])[0]
# 计算相似度
similarities = [
np.dot(query_embedding, ex['embedding'])
for ex in self.examples
]
# 选择最相似的k个示例
top_k_indices = np.argsort(similarities)[-k:][::-1]
return [self.examples[i] for i in top_k_indices]
# 使用示例
selector = DynamicFewShot()
selector.add_example("这部电影非常精彩", "正面")
selector.add_example("剧情拖沓,演技一般", "负面")
selector.add_example("画面很美但故事一般", "中性")
selector.add_example("绝对值得二刷", "正面")
selector.add_example("浪费了两个小时", "负面")
# 为新查询选择最相关的示例
selected = selector.select_examples("特效很棒,但剧情有点弱", k=2)
for ex in selected:
print(f"示例: {ex['text'][:20]}... -> {ex['label']}")
2. 多样性采样
from sklearn.cluster import KMeans
def diverse_sampling(examples, k):
"""选择多样化的示例,避免重复"""
embeddings = np.array([ex['embedding'] for ex in examples])
# K-means聚类
kmeans = KMeans(n_clusters=k, random_state=42)
clusters = kmeans.fit_predict(embeddings)
# 从每个簇中选择一个示例
selected = []
for cluster_id in range(k):
cluster_indices = np.where(clusters == cluster_id)[0]
# 选择最接近簇中心的
selected.append(examples[cluster_indices[0]])
return selected
Few-shot学习的最佳实践
1. 示例顺序的影响
# 不同的示例顺序可能导致不同的结果
prompt_v1 = """分类规则:正面/负面
示例1: "好" -> 正面
示例2: "差" -> 负面
示例3: "一般" -> 中性
分类:"还可以" -> """
prompt_v2 = """分类规则:正面/负面
示例1: "差" -> 负面
示例2: "好" -> 正面
示例3: "一般" -> 中性
分类:"还可以" -> """
# 建议:将最相关的示例放在前面
# 或者多次采样取多数结果
2. 示例数量的选择
def find_optimal_k(classifier, validation_data, k_range=range(1, 11)):
"""找到最佳的示例数量"""
results = {}
for k in k_range:
correct = 0
for text, expected in validation_data:
# 选择k个示例
# classifier.set_k(k)
prediction = classifier.classify(text)
if prediction == expected:
correct += 1
accuracy = correct / len(validation_data)
results[k] = accuracy
print(f"k={k}: 准确率={accuracy:.2%}")
best_k = max(results, key=results.get)
return best_k, results
3. 标签平衡
def balance_examples(examples):
"""确保各类别示例数量均衡"""
from collections import Counter
label_counts = Counter(ex['label'] for ex in examples)
min_count = min(label_counts.values())
balanced = []
for label in label_counts:
label_examples = [ex for ex in examples if ex['label'] == label]
balanced.extend(label_examples[:min_count])
return balanced
高级Few-shot技术
1. 自我反思(Self-Reflection)
def self_reflect_classify(text, examples, classifier):
"""先分类,然后反思并可能修正"""
# 第一次分类
initial_result = classifier.classify(text, examples)
# 反思提示
reflect_prompt = f"""请分析以下分类是否合理:
文本:"{text}"
初步分类:{initial_result}
考虑因素:
1. 文本中的情感词汇
2. 语境和语气
3. 是否存在讽刺或反转
如果认为分类有误,请给出修正后的分类。
如果认为正确,请重复原分类。"""
response = client.chat.completions.create(
model="gpt-3.5-turbo",
messages=[{"role": "user", "content": reflect_prompt}]
)
return response.choices[0].message.content.strip()
2. 标签描述增强
label_description_prompt = """将文本分类到以下类别:
类别描述:
- 正面:表达满意、推荐、赞扬的文本
- 负面:表达不满、批评、失望的文本
- 中性:客观陈述或混合情感的文本
示例:
输入:"服务态度很好,但等位时间太长"
分析:包含正面(服务好)和负面(等位长)情感,整体偏向中性客观陈述
分类:中性
现在请分类:
输入:"{text}"
分析:"""
实际应用场景
# 邮件自动分类
email_classifier = FewShotClassifier()
email_classifier.add_example("会议通知:明天下午3点开会", "工作通知")
email_classifier.add_example("恭喜您中奖!请点击链接领取", "垃圾邮件")
email_classifier.add_example("项目进度报告已完成", "工作通知")
email_classifier.add_example("限时优惠,立即购买!", "营销推广")
# 代码审查标记
code_reviewer = FewShotClassifier()
code_reviewer.add_example("这里可能有内存泄漏", "Bug风险")
code_reviewer.add_example("建议使用更高效的算法", "性能优化")
code_reviewer.add_example("变量命名不够清晰", "代码规范")
总结
Few-shot学习是大语言模型的强大能力之一,通过精心设计的示例和提示,模型可以在极少的标注数据下完成各种任务。掌握示例选择、顺序安排和数量平衡等技巧,可以显著提升Few-shot学习的效果。