Hermes-agent
This commit is contained in:
+350
@@ -0,0 +1,350 @@
|
||||
---
|
||||
title: "Huggingface Accelerate — 最简分布式训练 API"
|
||||
sidebar_label: "Huggingface Accelerate"
|
||||
description: "最简分布式训练 API"
|
||||
---
|
||||
|
||||
{/* This page is auto-generated from the skill's SKILL.md by website/scripts/generate-skill-docs.py. Edit the source SKILL.md, not this page. */}
|
||||
|
||||
# Huggingface Accelerate
|
||||
|
||||
最简分布式训练 API。仅需 4 行代码即可为任意 PyTorch 脚本添加分布式支持。统一的 DeepSpeed/FSDP/Megatron/DDP API。自动设备放置、混合精度(FP16/BF16/FP8)。交互式配置,单条启动命令。HuggingFace 生态系统标准。
|
||||
|
||||
## Skill 元数据
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| 来源 | 可选 — 通过 `hermes skills install official/mlops/accelerate` 安装 |
|
||||
| 路径 | `optional-skills/mlops/accelerate` |
|
||||
| 版本 | `1.0.0` |
|
||||
| 作者 | Orchestra Research |
|
||||
| 许可证 | MIT |
|
||||
| 依赖项 | `accelerate`, `torch`, `transformers` |
|
||||
| 平台 | linux, macos, windows |
|
||||
| 标签 | `Distributed Training`, `HuggingFace`, `Accelerate`, `DeepSpeed`, `FSDP`, `Mixed Precision`, `PyTorch`, `DDP`, `Unified API`, `Simple` |
|
||||
|
||||
## 参考:完整 SKILL.md
|
||||
|
||||
:::info
|
||||
以下是 Hermes 在触发该 skill 时加载的完整 skill 定义。这是 skill 激活时 agent 所看到的指令内容。
|
||||
:::
|
||||
|
||||
# HuggingFace Accelerate - 统一分布式训练
|
||||
|
||||
## 快速开始
|
||||
|
||||
Accelerate 将分布式训练简化为 4 行代码。
|
||||
|
||||
**安装**:
|
||||
```bash
|
||||
pip install accelerate
|
||||
```
|
||||
|
||||
**转换 PyTorch 脚本**(4 行):
|
||||
```python
|
||||
import torch
|
||||
+ from accelerate import Accelerator
|
||||
|
||||
+ accelerator = Accelerator()
|
||||
|
||||
model = torch.nn.Transformer()
|
||||
optimizer = torch.optim.Adam(model.parameters())
|
||||
dataloader = torch.utils.data.DataLoader(dataset)
|
||||
|
||||
+ model, optimizer, dataloader = accelerator.prepare(model, optimizer, dataloader)
|
||||
|
||||
for batch in dataloader:
|
||||
optimizer.zero_grad()
|
||||
loss = model(batch)
|
||||
- loss.backward()
|
||||
+ accelerator.backward(loss)
|
||||
optimizer.step()
|
||||
```
|
||||
|
||||
**运行**(单条命令):
|
||||
```bash
|
||||
accelerate launch train.py
|
||||
```
|
||||
|
||||
## 常见工作流
|
||||
|
||||
### 工作流 1:从单 GPU 到多 GPU
|
||||
|
||||
**原始脚本**:
|
||||
```python
|
||||
# train.py
|
||||
import torch
|
||||
|
||||
model = torch.nn.Linear(10, 2).to('cuda')
|
||||
optimizer = torch.optim.Adam(model.parameters())
|
||||
dataloader = torch.utils.data.DataLoader(dataset, batch_size=32)
|
||||
|
||||
for epoch in range(10):
|
||||
for batch in dataloader:
|
||||
batch = batch.to('cuda')
|
||||
optimizer.zero_grad()
|
||||
loss = model(batch).mean()
|
||||
loss.backward()
|
||||
optimizer.step()
|
||||
```
|
||||
|
||||
**使用 Accelerate**(新增 4 行):
|
||||
```python
|
||||
# train.py
|
||||
import torch
|
||||
from accelerate import Accelerator # +1
|
||||
|
||||
accelerator = Accelerator() # +2
|
||||
|
||||
model = torch.nn.Linear(10, 2)
|
||||
optimizer = torch.optim.Adam(model.parameters())
|
||||
dataloader = torch.utils.data.DataLoader(dataset, batch_size=32)
|
||||
|
||||
model, optimizer, dataloader = accelerator.prepare(model, optimizer, dataloader) # +3
|
||||
|
||||
for epoch in range(10):
|
||||
for batch in dataloader:
|
||||
# 无需 .to('cuda') — 自动处理!
|
||||
optimizer.zero_grad()
|
||||
loss = model(batch).mean()
|
||||
accelerator.backward(loss) # +4
|
||||
optimizer.step()
|
||||
```
|
||||
|
||||
**配置**(交互式):
|
||||
```bash
|
||||
accelerate config
|
||||
```
|
||||
|
||||
**问题**:
|
||||
- 使用哪种机器?(单/多 GPU/TPU/CPU)
|
||||
- 机器数量?(1)
|
||||
- 混合精度?(no/fp16/bf16/fp8)
|
||||
- DeepSpeed?(no/yes)
|
||||
|
||||
**启动**(适用于任意配置):
|
||||
```bash
|
||||
# 单 GPU
|
||||
accelerate launch train.py
|
||||
|
||||
# 多 GPU(8 个 GPU)
|
||||
accelerate launch --multi_gpu --num_processes 8 train.py
|
||||
|
||||
# 多节点
|
||||
accelerate launch --multi_gpu --num_processes 16 \
|
||||
--num_machines 2 --machine_rank 0 \
|
||||
--main_process_ip $MASTER_ADDR \
|
||||
train.py
|
||||
```
|
||||
|
||||
### 工作流 2:混合精度训练
|
||||
|
||||
**启用 FP16/BF16**:
|
||||
```python
|
||||
from accelerate import Accelerator
|
||||
|
||||
# FP16(带梯度缩放)
|
||||
accelerator = Accelerator(mixed_precision='fp16')
|
||||
|
||||
# BF16(无缩放,更稳定)
|
||||
accelerator = Accelerator(mixed_precision='bf16')
|
||||
|
||||
# FP8(H100+)
|
||||
accelerator = Accelerator(mixed_precision='fp8')
|
||||
|
||||
model, optimizer, dataloader = accelerator.prepare(model, optimizer, dataloader)
|
||||
|
||||
# 其余均自动处理!
|
||||
for batch in dataloader:
|
||||
with accelerator.autocast(): # 可选,已自动完成
|
||||
loss = model(batch)
|
||||
accelerator.backward(loss)
|
||||
```
|
||||
|
||||
### 工作流 3:DeepSpeed ZeRO 集成
|
||||
|
||||
**启用 DeepSpeed ZeRO-2**:
|
||||
```python
|
||||
from accelerate import Accelerator
|
||||
|
||||
accelerator = Accelerator(
|
||||
mixed_precision='bf16',
|
||||
deepspeed_plugin={
|
||||
"zero_stage": 2, # ZeRO-2
|
||||
"offload_optimizer": False,
|
||||
"gradient_accumulation_steps": 4
|
||||
}
|
||||
)
|
||||
|
||||
# 代码与之前完全相同!
|
||||
model, optimizer, dataloader = accelerator.prepare(model, optimizer, dataloader)
|
||||
```
|
||||
|
||||
**或通过配置**:
|
||||
```bash
|
||||
accelerate config
|
||||
# 选择:DeepSpeed → ZeRO-2
|
||||
```
|
||||
|
||||
**deepspeed_config.json**:
|
||||
```json
|
||||
{
|
||||
"fp16": {"enabled": false},
|
||||
"bf16": {"enabled": true},
|
||||
"zero_optimization": {
|
||||
"stage": 2,
|
||||
"offload_optimizer": {"device": "cpu"},
|
||||
"allgather_bucket_size": 5e8,
|
||||
"reduce_bucket_size": 5e8
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**启动**:
|
||||
```bash
|
||||
accelerate launch --config_file deepspeed_config.json train.py
|
||||
```
|
||||
|
||||
### 工作流 4:FSDP(全分片数据并行)
|
||||
|
||||
**启用 FSDP**:
|
||||
```python
|
||||
from accelerate import Accelerator, FullyShardedDataParallelPlugin
|
||||
|
||||
fsdp_plugin = FullyShardedDataParallelPlugin(
|
||||
sharding_strategy="FULL_SHARD", # 等价于 ZeRO-3
|
||||
auto_wrap_policy="TRANSFORMER_AUTO_WRAP",
|
||||
cpu_offload=False
|
||||
)
|
||||
|
||||
accelerator = Accelerator(
|
||||
mixed_precision='bf16',
|
||||
fsdp_plugin=fsdp_plugin
|
||||
)
|
||||
|
||||
model, optimizer, dataloader = accelerator.prepare(model, optimizer, dataloader)
|
||||
```
|
||||
|
||||
**或通过配置**:
|
||||
```bash
|
||||
accelerate config
|
||||
# 选择:FSDP → Full Shard → No CPU Offload
|
||||
```
|
||||
|
||||
### 工作流 5:梯度累积
|
||||
|
||||
**累积梯度**:
|
||||
```python
|
||||
from accelerate import Accelerator
|
||||
|
||||
accelerator = Accelerator(gradient_accumulation_steps=4)
|
||||
|
||||
model, optimizer, dataloader = accelerator.prepare(model, optimizer, dataloader)
|
||||
|
||||
for batch in dataloader:
|
||||
with accelerator.accumulate(model): # 自动处理累积
|
||||
optimizer.zero_grad()
|
||||
loss = model(batch)
|
||||
accelerator.backward(loss)
|
||||
optimizer.step()
|
||||
```
|
||||
|
||||
**有效批大小**:`batch_size * num_gpus * gradient_accumulation_steps`
|
||||
|
||||
## 与替代方案的对比
|
||||
|
||||
**适合使用 Accelerate 的场景**:
|
||||
- 需要最简单的分布式训练方式
|
||||
- 需要单脚本适配任意硬件
|
||||
- 使用 HuggingFace 生态系统
|
||||
- 需要灵活性(DDP/DeepSpeed/FSDP/Megatron)
|
||||
- 需要快速原型开发
|
||||
|
||||
**核心优势**:
|
||||
- **4 行代码**:代码改动极少
|
||||
- **统一 API**:同一套代码适用于 DDP、DeepSpeed、FSDP、Megatron
|
||||
- **自动化**:设备放置、混合精度、分片均自动处理
|
||||
- **交互式配置**:无需手动配置启动器
|
||||
- **单条启动命令**:适用于所有环境
|
||||
|
||||
**适合使用替代方案的场景**:
|
||||
- **PyTorch Lightning**:需要回调机制、高层抽象
|
||||
- **Ray Train**:多节点编排、超参数调优
|
||||
- **DeepSpeed**:直接 API 控制、高级特性
|
||||
- **原生 DDP**:最大控制权、最少抽象层
|
||||
|
||||
## 常见问题
|
||||
|
||||
**问题:设备放置错误**
|
||||
|
||||
不要手动移动到设备:
|
||||
```python
|
||||
# 错误
|
||||
batch = batch.to('cuda')
|
||||
|
||||
# 正确
|
||||
# Accelerate 在 prepare() 之后自动处理
|
||||
```
|
||||
|
||||
**问题:梯度累积不生效**
|
||||
|
||||
使用上下文管理器:
|
||||
```python
|
||||
# 正确
|
||||
with accelerator.accumulate(model):
|
||||
optimizer.zero_grad()
|
||||
accelerator.backward(loss)
|
||||
optimizer.step()
|
||||
```
|
||||
|
||||
**问题:分布式环境下的检查点保存**
|
||||
|
||||
使用 accelerator 方法:
|
||||
```python
|
||||
# 仅在主进程保存
|
||||
if accelerator.is_main_process:
|
||||
accelerator.save_state('checkpoint/')
|
||||
|
||||
# 在所有进程上加载
|
||||
accelerator.load_state('checkpoint/')
|
||||
```
|
||||
|
||||
**问题:FSDP 结果不一致**
|
||||
|
||||
确保使用相同的随机种子:
|
||||
```python
|
||||
from accelerate.utils import set_seed
|
||||
set_seed(42)
|
||||
```
|
||||
|
||||
## 高级主题
|
||||
|
||||
**Megatron 集成**:张量并行、流水线并行和序列并行的配置,请参阅 [references/megatron-integration.md](https://github.com/NousResearch/hermes-agent/blob/main/optional-skills/mlops/accelerate/references/megatron-integration.md)。
|
||||
|
||||
**自定义插件**:创建自定义分布式插件及高级配置,请参阅 [references/custom-plugins.md](https://github.com/NousResearch/hermes-agent/blob/main/optional-skills/mlops/accelerate/references/custom-plugins.md)。
|
||||
|
||||
**性能调优**:性能分析、内存优化及最佳实践,请参阅 [references/performance.md](https://github.com/NousResearch/hermes-agent/blob/main/optional-skills/mlops/accelerate/references/performance.md)。
|
||||
|
||||
## 硬件要求
|
||||
|
||||
- **CPU**:支持(速度较慢)
|
||||
- **单 GPU**:支持
|
||||
- **多 GPU**:DDP(默认)、DeepSpeed 或 FSDP
|
||||
- **多节点**:DDP、DeepSpeed、FSDP、Megatron
|
||||
- **TPU**:支持
|
||||
- **Apple MPS**:支持
|
||||
|
||||
**启动器要求**:
|
||||
- **DDP**:`torch.distributed.run`(内置)
|
||||
- **DeepSpeed**:`deepspeed`(pip install deepspeed)
|
||||
- **FSDP**:PyTorch 1.12+(内置)
|
||||
- **Megatron**:需自定义配置
|
||||
|
||||
## 资源
|
||||
|
||||
- 文档:https://huggingface.co/docs/accelerate
|
||||
- GitHub:https://github.com/huggingface/accelerate
|
||||
- 版本:1.11.0+
|
||||
- 教程:"Accelerate your scripts"
|
||||
- 示例:https://github.com/huggingface/accelerate/tree/main/examples
|
||||
- 使用方:HuggingFace Transformers、TRL、PEFT 及所有 HF 库
|
||||
+425
@@ -0,0 +1,425 @@
|
||||
---
|
||||
title: "Chroma — 面向 AI 应用的开源 embedding 数据库"
|
||||
sidebar_label: "Chroma"
|
||||
description: "面向 AI 应用的开源 embedding 数据库"
|
||||
---
|
||||
|
||||
{/* This page is auto-generated from the skill's SKILL.md by website/scripts/generate-skill-docs.py. Edit the source SKILL.md, not this page. */}
|
||||
|
||||
# Chroma
|
||||
|
||||
面向 AI 应用的开源 embedding(向量嵌入)数据库。存储 embedding 与元数据,执行向量搜索和全文搜索,按元数据过滤。简洁的 4 函数 API,从 notebook 到生产集群均可扩展。适用于语义搜索、RAG 应用或文档检索。最适合本地开发和开源项目。
|
||||
|
||||
## Skill 元数据
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| 来源 | 可选 — 通过 `hermes skills install official/mlops/chroma` 安装 |
|
||||
| 路径 | `optional-skills/mlops/chroma` |
|
||||
| 版本 | `1.0.0` |
|
||||
| 作者 | Orchestra Research |
|
||||
| 许可证 | MIT |
|
||||
| 依赖 | `chromadb`, `sentence-transformers` |
|
||||
| 平台 | linux, macos, windows |
|
||||
| 标签 | `RAG`, `Chroma`, `Vector Database`, `Embeddings`, `Semantic Search`, `Open Source`, `Self-Hosted`, `Document Retrieval`, `Metadata Filtering` |
|
||||
|
||||
## 参考:完整 SKILL.md
|
||||
|
||||
:::info
|
||||
以下是 Hermes 在触发此 skill 时加载的完整 skill 定义。这是 agent 在 skill 激活时所看到的指令内容。
|
||||
:::
|
||||
|
||||
# Chroma - 开源 Embedding 数据库
|
||||
|
||||
专为构建具备记忆能力的 LLM 应用而设计的 AI 原生数据库。
|
||||
|
||||
## 何时使用 Chroma
|
||||
|
||||
**适用场景:**
|
||||
- 构建 RAG(检索增强生成)应用
|
||||
- 需要本地/自托管向量数据库
|
||||
- 希望使用开源方案(Apache 2.0)
|
||||
- 在 notebook 中快速原型验证
|
||||
- 对文档进行语义搜索
|
||||
- 存储带元数据的 embedding
|
||||
|
||||
**指标**:
|
||||
- **24,300+ GitHub stars**
|
||||
- **1,900+ forks**
|
||||
- **v1.3.3**(稳定版,每周发布)
|
||||
- **Apache 2.0 许可证**
|
||||
|
||||
**以下场景请使用替代方案**:
|
||||
- **Pinecone**:托管云服务,自动扩缩容
|
||||
- **FAISS**:纯相似度搜索,不支持元数据
|
||||
- **Weaviate**:面向生产的 ML 原生数据库
|
||||
- **Qdrant**:高性能,基于 Rust
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 安装
|
||||
|
||||
```bash
|
||||
# Python
|
||||
pip install chromadb
|
||||
|
||||
# JavaScript/TypeScript
|
||||
npm install chromadb @chroma-core/default-embed
|
||||
```
|
||||
|
||||
### 基本用法(Python)
|
||||
|
||||
```python
|
||||
import chromadb
|
||||
|
||||
# Create client
|
||||
client = chromadb.Client()
|
||||
|
||||
# Create collection
|
||||
collection = client.create_collection(name="my_collection")
|
||||
|
||||
# Add documents
|
||||
collection.add(
|
||||
documents=["This is document 1", "This is document 2"],
|
||||
metadatas=[{"source": "doc1"}, {"source": "doc2"}],
|
||||
ids=["id1", "id2"]
|
||||
)
|
||||
|
||||
# Query
|
||||
results = collection.query(
|
||||
query_texts=["document about topic"],
|
||||
n_results=2
|
||||
)
|
||||
|
||||
print(results)
|
||||
```
|
||||
|
||||
## 核心操作
|
||||
|
||||
### 1. 创建集合
|
||||
|
||||
```python
|
||||
# Simple collection
|
||||
collection = client.create_collection("my_docs")
|
||||
|
||||
# With custom embedding function
|
||||
from chromadb.utils import embedding_functions
|
||||
|
||||
openai_ef = embedding_functions.OpenAIEmbeddingFunction(
|
||||
api_key="your-key",
|
||||
model_name="text-embedding-3-small"
|
||||
)
|
||||
|
||||
collection = client.create_collection(
|
||||
name="my_docs",
|
||||
embedding_function=openai_ef
|
||||
)
|
||||
|
||||
# Get existing collection
|
||||
collection = client.get_collection("my_docs")
|
||||
|
||||
# Delete collection
|
||||
client.delete_collection("my_docs")
|
||||
```
|
||||
|
||||
### 2. 添加文档
|
||||
|
||||
```python
|
||||
# Add with auto-generated IDs
|
||||
collection.add(
|
||||
documents=["Doc 1", "Doc 2", "Doc 3"],
|
||||
metadatas=[
|
||||
{"source": "web", "category": "tutorial"},
|
||||
{"source": "pdf", "page": 5},
|
||||
{"source": "api", "timestamp": "2025-01-01"}
|
||||
],
|
||||
ids=["id1", "id2", "id3"]
|
||||
)
|
||||
|
||||
# Add with custom embeddings
|
||||
collection.add(
|
||||
embeddings=[[0.1, 0.2, ...], [0.3, 0.4, ...]],
|
||||
documents=["Doc 1", "Doc 2"],
|
||||
ids=["id1", "id2"]
|
||||
)
|
||||
```
|
||||
|
||||
### 3. 查询(相似度搜索)
|
||||
|
||||
```python
|
||||
# Basic query
|
||||
results = collection.query(
|
||||
query_texts=["machine learning tutorial"],
|
||||
n_results=5
|
||||
)
|
||||
|
||||
# Query with filters
|
||||
results = collection.query(
|
||||
query_texts=["Python programming"],
|
||||
n_results=3,
|
||||
where={"source": "web"}
|
||||
)
|
||||
|
||||
# Query with metadata filters
|
||||
results = collection.query(
|
||||
query_texts=["advanced topics"],
|
||||
where={
|
||||
"$and": [
|
||||
{"category": "tutorial"},
|
||||
{"difficulty": {"$gte": 3}}
|
||||
]
|
||||
}
|
||||
)
|
||||
|
||||
# Access results
|
||||
print(results["documents"]) # List of matching documents
|
||||
print(results["metadatas"]) # Metadata for each doc
|
||||
print(results["distances"]) # Similarity scores
|
||||
print(results["ids"]) # Document IDs
|
||||
```
|
||||
|
||||
### 4. 获取文档
|
||||
|
||||
```python
|
||||
# Get by IDs
|
||||
docs = collection.get(
|
||||
ids=["id1", "id2"]
|
||||
)
|
||||
|
||||
# Get with filters
|
||||
docs = collection.get(
|
||||
where={"category": "tutorial"},
|
||||
limit=10
|
||||
)
|
||||
|
||||
# Get all documents
|
||||
docs = collection.get()
|
||||
```
|
||||
|
||||
### 5. 更新文档
|
||||
|
||||
```python
|
||||
# Update document content
|
||||
collection.update(
|
||||
ids=["id1"],
|
||||
documents=["Updated content"],
|
||||
metadatas=[{"source": "updated"}]
|
||||
)
|
||||
```
|
||||
|
||||
### 6. 删除文档
|
||||
|
||||
```python
|
||||
# Delete by IDs
|
||||
collection.delete(ids=["id1", "id2"])
|
||||
|
||||
# Delete with filter
|
||||
collection.delete(
|
||||
where={"source": "outdated"}
|
||||
)
|
||||
```
|
||||
|
||||
## 持久化存储
|
||||
|
||||
```python
|
||||
# Persist to disk
|
||||
client = chromadb.PersistentClient(path="./chroma_db")
|
||||
|
||||
collection = client.create_collection("my_docs")
|
||||
collection.add(documents=["Doc 1"], ids=["id1"])
|
||||
|
||||
# Data persisted automatically
|
||||
# Reload later with same path
|
||||
client = chromadb.PersistentClient(path="./chroma_db")
|
||||
collection = client.get_collection("my_docs")
|
||||
```
|
||||
|
||||
## Embedding 函数
|
||||
|
||||
### 默认(Sentence Transformers)
|
||||
|
||||
```python
|
||||
# Uses sentence-transformers by default
|
||||
collection = client.create_collection("my_docs")
|
||||
# Default model: all-MiniLM-L6-v2
|
||||
```
|
||||
|
||||
### OpenAI
|
||||
|
||||
```python
|
||||
from chromadb.utils import embedding_functions
|
||||
|
||||
openai_ef = embedding_functions.OpenAIEmbeddingFunction(
|
||||
api_key="your-key",
|
||||
model_name="text-embedding-3-small"
|
||||
)
|
||||
|
||||
collection = client.create_collection(
|
||||
name="openai_docs",
|
||||
embedding_function=openai_ef
|
||||
)
|
||||
```
|
||||
|
||||
### HuggingFace
|
||||
|
||||
```python
|
||||
huggingface_ef = embedding_functions.HuggingFaceEmbeddingFunction(
|
||||
api_key="your-key",
|
||||
model_name="sentence-transformers/all-mpnet-base-v2"
|
||||
)
|
||||
|
||||
collection = client.create_collection(
|
||||
name="hf_docs",
|
||||
embedding_function=huggingface_ef
|
||||
)
|
||||
```
|
||||
|
||||
### 自定义 embedding 函数
|
||||
|
||||
```python
|
||||
from chromadb import Documents, EmbeddingFunction, Embeddings
|
||||
|
||||
class MyEmbeddingFunction(EmbeddingFunction):
|
||||
def __call__(self, input: Documents) -> Embeddings:
|
||||
# Your embedding logic
|
||||
return embeddings
|
||||
|
||||
my_ef = MyEmbeddingFunction()
|
||||
collection = client.create_collection(
|
||||
name="custom_docs",
|
||||
embedding_function=my_ef
|
||||
)
|
||||
```
|
||||
|
||||
## 元数据过滤
|
||||
|
||||
```python
|
||||
# Exact match
|
||||
results = collection.query(
|
||||
query_texts=["query"],
|
||||
where={"category": "tutorial"}
|
||||
)
|
||||
|
||||
# Comparison operators
|
||||
results = collection.query(
|
||||
query_texts=["query"],
|
||||
where={"page": {"$gt": 10}} # $gt, $gte, $lt, $lte, $ne
|
||||
)
|
||||
|
||||
# Logical operators
|
||||
results = collection.query(
|
||||
query_texts=["query"],
|
||||
where={
|
||||
"$and": [
|
||||
{"category": "tutorial"},
|
||||
{"difficulty": {"$lte": 3}}
|
||||
]
|
||||
} # Also: $or
|
||||
)
|
||||
|
||||
# Contains
|
||||
results = collection.query(
|
||||
query_texts=["query"],
|
||||
where={"tags": {"$in": ["python", "ml"]}}
|
||||
)
|
||||
```
|
||||
|
||||
## LangChain 集成
|
||||
|
||||
```python
|
||||
from langchain_chroma import Chroma
|
||||
from langchain_openai import OpenAIEmbeddings
|
||||
from langchain.text_splitter import RecursiveCharacterTextSplitter
|
||||
|
||||
# Split documents
|
||||
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000)
|
||||
docs = text_splitter.split_documents(documents)
|
||||
|
||||
# Create Chroma vector store
|
||||
vectorstore = Chroma.from_documents(
|
||||
documents=docs,
|
||||
embedding=OpenAIEmbeddings(),
|
||||
persist_directory="./chroma_db"
|
||||
)
|
||||
|
||||
# Query
|
||||
results = vectorstore.similarity_search("machine learning", k=3)
|
||||
|
||||
# As retriever
|
||||
retriever = vectorstore.as_retriever(search_kwargs={"k": 5})
|
||||
```
|
||||
|
||||
## LlamaIndex 集成
|
||||
|
||||
```python
|
||||
from llama_index.vector_stores.chroma import ChromaVectorStore
|
||||
from llama_index.core import VectorStoreIndex, StorageContext
|
||||
import chromadb
|
||||
|
||||
# Initialize Chroma
|
||||
db = chromadb.PersistentClient(path="./chroma_db")
|
||||
collection = db.get_or_create_collection("my_collection")
|
||||
|
||||
# Create vector store
|
||||
vector_store = ChromaVectorStore(chroma_collection=collection)
|
||||
storage_context = StorageContext.from_defaults(vector_store=vector_store)
|
||||
|
||||
# Create index
|
||||
index = VectorStoreIndex.from_documents(
|
||||
documents,
|
||||
storage_context=storage_context
|
||||
)
|
||||
|
||||
# Query
|
||||
query_engine = index.as_query_engine()
|
||||
response = query_engine.query("What is machine learning?")
|
||||
```
|
||||
|
||||
## 服务器模式
|
||||
|
||||
```python
|
||||
# Run Chroma server
|
||||
# Terminal: chroma run --path ./chroma_db --port 8000
|
||||
|
||||
# Connect to server
|
||||
import chromadb
|
||||
from chromadb.config import Settings
|
||||
|
||||
client = chromadb.HttpClient(
|
||||
host="localhost",
|
||||
port=8000,
|
||||
settings=Settings(anonymized_telemetry=False)
|
||||
)
|
||||
|
||||
# Use as normal
|
||||
collection = client.get_or_create_collection("my_docs")
|
||||
```
|
||||
|
||||
## 最佳实践
|
||||
|
||||
1. **使用持久化客户端** — 避免重启后数据丢失
|
||||
2. **添加元数据** — 支持过滤与追踪
|
||||
3. **批量操作** — 一次性添加多个文档
|
||||
4. **选择合适的 embedding 模型** — 平衡速度与质量
|
||||
5. **使用过滤器** — 缩小搜索范围
|
||||
6. **唯一 ID** — 避免冲突
|
||||
7. **定期备份** — 复制 `chroma_db` 目录
|
||||
8. **监控集合大小** — 按需扩容
|
||||
9. **测试 embedding 函数** — 确保质量
|
||||
10. **生产环境使用服务器模式** — 更适合多用户场景
|
||||
|
||||
## 性能
|
||||
|
||||
| 操作 | 延迟 | 备注 |
|
||||
|-----------|---------|-------|
|
||||
| 添加 100 个文档 | ~1-3s | 含 embedding 生成 |
|
||||
| 查询(top 10) | ~50-200ms | 取决于集合大小 |
|
||||
| 元数据过滤 | ~10-50ms | 正确索引下速度较快 |
|
||||
|
||||
## 资源
|
||||
|
||||
- **GitHub**: https://github.com/chroma-core/chroma ⭐ 24,300+
|
||||
- **文档**: https://docs.trychroma.com
|
||||
- **Discord**: https://discord.gg/MMeYNTmh3x
|
||||
- **版本**: 1.3.3+
|
||||
- **许可证**: Apache 2.0
|
||||
+272
@@ -0,0 +1,272 @@
|
||||
---
|
||||
title: "Clip — OpenAI 连接视觉与语言的模型"
|
||||
sidebar_label: "Clip"
|
||||
description: "OpenAI 连接视觉与语言的模型"
|
||||
---
|
||||
|
||||
{/* This page is auto-generated from the skill's SKILL.md by website/scripts/generate-skill-docs.py. Edit the source SKILL.md, not this page. */}
|
||||
|
||||
# Clip
|
||||
|
||||
OpenAI 连接视觉与语言的模型。支持零样本图像分类、图文匹配和跨模态检索。在 4 亿图文对上训练而成。可用于图像搜索、内容审核或视觉语言任务,无需微调。最适合通用图像理解场景。
|
||||
|
||||
## Skill 元数据
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| 来源 | 可选 — 通过 `hermes skills install official/mlops/clip` 安装 |
|
||||
| 路径 | `optional-skills/mlops/clip` |
|
||||
| 版本 | `1.0.0` |
|
||||
| 作者 | Orchestra Research |
|
||||
| 许可证 | MIT |
|
||||
| 依赖项 | `transformers`, `torch`, `pillow` |
|
||||
| 平台 | linux, macos, windows |
|
||||
| 标签 | `Multimodal`, `CLIP`, `Vision-Language`, `Zero-Shot`, `Image Classification`, `OpenAI`, `Image Search`, `Cross-Modal Retrieval`, `Content Moderation` |
|
||||
|
||||
## 参考:完整 SKILL.md
|
||||
|
||||
:::info
|
||||
以下是 Hermes 在触发此 skill 时加载的完整 skill 定义。这是 skill 激活时 agent 所看到的指令内容。
|
||||
:::
|
||||
|
||||
# CLIP - 对比语言图像预训练(Contrastive Language-Image Pre-Training)
|
||||
|
||||
OpenAI 推出的能够通过自然语言理解图像的模型。
|
||||
|
||||
## 何时使用 CLIP
|
||||
|
||||
**适用场景:**
|
||||
- 零样本图像分类(无需训练数据)
|
||||
- 图文相似度/匹配
|
||||
- 语义图像搜索
|
||||
- 内容审核(检测 NSFW、暴力内容)
|
||||
- 视觉问答
|
||||
- 跨模态检索(图像→文本、文本→图像)
|
||||
|
||||
**指标**:
|
||||
- **GitHub 25,300+ 星**
|
||||
- 在 4 亿图文对上训练
|
||||
- 零样本下在 ImageNet 上与 ResNet-50 持平
|
||||
- MIT 许可证
|
||||
|
||||
**以下情况请使用替代方案**:
|
||||
- **BLIP-2**:更好的图像描述生成
|
||||
- **LLaVA**:视觉语言对话
|
||||
- **Segment Anything**:图像分割
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 安装
|
||||
|
||||
```bash
|
||||
pip install git+https://github.com/openai/CLIP.git
|
||||
pip install torch torchvision ftfy regex tqdm
|
||||
```
|
||||
|
||||
### 零样本分类
|
||||
|
||||
```python
|
||||
import torch
|
||||
import clip
|
||||
from PIL import Image
|
||||
|
||||
# Load model
|
||||
device = "cuda" if torch.cuda.is_available() else "cpu"
|
||||
model, preprocess = clip.load("ViT-B/32", device=device)
|
||||
|
||||
# Load image
|
||||
image = preprocess(Image.open("photo.jpg")).unsqueeze(0).to(device)
|
||||
|
||||
# Define possible labels
|
||||
text = clip.tokenize(["a dog", "a cat", "a bird", "a car"]).to(device)
|
||||
|
||||
# Compute similarity
|
||||
with torch.no_grad():
|
||||
image_features = model.encode_image(image)
|
||||
text_features = model.encode_text(text)
|
||||
|
||||
# Cosine similarity
|
||||
logits_per_image, logits_per_text = model(image, text)
|
||||
probs = logits_per_image.softmax(dim=-1).cpu().numpy()
|
||||
|
||||
# Print results
|
||||
labels = ["a dog", "a cat", "a bird", "a car"]
|
||||
for label, prob in zip(labels, probs[0]):
|
||||
print(f"{label}: {prob:.2%}")
|
||||
```
|
||||
|
||||
## 可用模型
|
||||
|
||||
```python
|
||||
# Models (sorted by size)
|
||||
models = [
|
||||
"RN50", # ResNet-50
|
||||
"RN101", # ResNet-101
|
||||
"ViT-B/32", # Vision Transformer (recommended)
|
||||
"ViT-B/16", # Better quality, slower
|
||||
"ViT-L/14", # Best quality, slowest
|
||||
]
|
||||
|
||||
model, preprocess = clip.load("ViT-B/32")
|
||||
```
|
||||
|
||||
| 模型 | 参数量 | 速度 | 质量 |
|
||||
|-------|------------|-------|---------|
|
||||
| RN50 | 102M | 快 | 良好 |
|
||||
| ViT-B/32 | 151M | 中等 | 更好 |
|
||||
| ViT-L/14 | 428M | 慢 | 最佳 |
|
||||
|
||||
## 图文相似度
|
||||
|
||||
```python
|
||||
# Compute embeddings
|
||||
image_features = model.encode_image(image)
|
||||
text_features = model.encode_text(text)
|
||||
|
||||
# Normalize
|
||||
image_features /= image_features.norm(dim=-1, keepdim=True)
|
||||
text_features /= text_features.norm(dim=-1, keepdim=True)
|
||||
|
||||
# Cosine similarity
|
||||
similarity = (image_features @ text_features.T).item()
|
||||
print(f"Similarity: {similarity:.4f}")
|
||||
```
|
||||
|
||||
## 语义图像搜索
|
||||
|
||||
```python
|
||||
# Index images
|
||||
image_paths = ["img1.jpg", "img2.jpg", "img3.jpg"]
|
||||
image_embeddings = []
|
||||
|
||||
for img_path in image_paths:
|
||||
image = preprocess(Image.open(img_path)).unsqueeze(0).to(device)
|
||||
with torch.no_grad():
|
||||
embedding = model.encode_image(image)
|
||||
embedding /= embedding.norm(dim=-1, keepdim=True)
|
||||
image_embeddings.append(embedding)
|
||||
|
||||
image_embeddings = torch.cat(image_embeddings)
|
||||
|
||||
# Search with text query
|
||||
query = "a sunset over the ocean"
|
||||
text_input = clip.tokenize([query]).to(device)
|
||||
with torch.no_grad():
|
||||
text_embedding = model.encode_text(text_input)
|
||||
text_embedding /= text_embedding.norm(dim=-1, keepdim=True)
|
||||
|
||||
# Find most similar images
|
||||
similarities = (text_embedding @ image_embeddings.T).squeeze(0)
|
||||
top_k = similarities.topk(3)
|
||||
|
||||
for idx, score in zip(top_k.indices, top_k.values):
|
||||
print(f"{image_paths[idx]}: {score:.3f}")
|
||||
```
|
||||
|
||||
## 内容审核
|
||||
|
||||
```python
|
||||
# Define categories
|
||||
categories = [
|
||||
"safe for work",
|
||||
"not safe for work",
|
||||
"violent content",
|
||||
"graphic content"
|
||||
]
|
||||
|
||||
text = clip.tokenize(categories).to(device)
|
||||
|
||||
# Check image
|
||||
with torch.no_grad():
|
||||
logits_per_image, _ = model(image, text)
|
||||
probs = logits_per_image.softmax(dim=-1)
|
||||
|
||||
# Get classification
|
||||
max_idx = probs.argmax().item()
|
||||
max_prob = probs[0, max_idx].item()
|
||||
|
||||
print(f"Category: {categories[max_idx]} ({max_prob:.2%})")
|
||||
```
|
||||
|
||||
## 批量处理
|
||||
|
||||
```python
|
||||
# Process multiple images
|
||||
images = [preprocess(Image.open(f"img{i}.jpg")) for i in range(10)]
|
||||
images = torch.stack(images).to(device)
|
||||
|
||||
with torch.no_grad():
|
||||
image_features = model.encode_image(images)
|
||||
image_features /= image_features.norm(dim=-1, keepdim=True)
|
||||
|
||||
# Batch text
|
||||
texts = ["a dog", "a cat", "a bird"]
|
||||
text_tokens = clip.tokenize(texts).to(device)
|
||||
|
||||
with torch.no_grad():
|
||||
text_features = model.encode_text(text_tokens)
|
||||
text_features /= text_features.norm(dim=-1, keepdim=True)
|
||||
|
||||
# Similarity matrix (10 images × 3 texts)
|
||||
similarities = image_features @ text_features.T
|
||||
print(similarities.shape) # (10, 3)
|
||||
```
|
||||
|
||||
## 与向量数据库集成
|
||||
|
||||
```python
|
||||
# Store CLIP embeddings in Chroma/FAISS
|
||||
import chromadb
|
||||
|
||||
client = chromadb.Client()
|
||||
collection = client.create_collection("image_embeddings")
|
||||
|
||||
# Add image embeddings
|
||||
for img_path, embedding in zip(image_paths, image_embeddings):
|
||||
collection.add(
|
||||
embeddings=[embedding.cpu().numpy().tolist()],
|
||||
metadatas=[{"path": img_path}],
|
||||
ids=[img_path]
|
||||
)
|
||||
|
||||
# Query with text
|
||||
query = "a sunset"
|
||||
text_embedding = model.encode_text(clip.tokenize([query]))
|
||||
results = collection.query(
|
||||
query_embeddings=[text_embedding.cpu().numpy().tolist()],
|
||||
n_results=5
|
||||
)
|
||||
```
|
||||
|
||||
## 最佳实践
|
||||
|
||||
1. **大多数场景使用 ViT-B/32** — 性能与速度均衡
|
||||
2. **归一化 embedding(嵌入向量)** — 余弦相似度计算必须归一化
|
||||
3. **批量处理** — 效率更高
|
||||
4. **缓存 embedding** — 重新计算代价较高
|
||||
5. **使用描述性标签** — 零样本性能更好
|
||||
6. **推荐使用 GPU** — 速度提升 10–50 倍
|
||||
7. **预处理图像** — 使用提供的 preprocess 函数
|
||||
|
||||
## 性能
|
||||
|
||||
| 操作 | CPU | GPU (V100) |
|
||||
|-----------|-----|------------|
|
||||
| 图像编码 | ~200ms | ~20ms |
|
||||
| 文本编码 | ~50ms | ~5ms |
|
||||
| 相似度计算 | <1ms | <1ms |
|
||||
|
||||
## 局限性
|
||||
|
||||
1. **不适合细粒度任务** — 最适合宽泛类别
|
||||
2. **需要描述性文本** — 模糊标签效果差
|
||||
3. **网络数据偏差** — 可能存在数据集偏差
|
||||
4. **无边界框** — 仅处理整张图像
|
||||
5. **空间理解有限** — 位置/计数能力较弱
|
||||
|
||||
## 资源
|
||||
|
||||
- **GitHub**: https://github.com/openai/CLIP ⭐ 25,300+
|
||||
- **论文**: https://arxiv.org/abs/2103.00020
|
||||
- **Colab**: https://colab.research.google.com/github/openai/clip/
|
||||
- **许可证**: MIT
|
||||
+240
@@ -0,0 +1,240 @@
|
||||
---
|
||||
title: "Faiss — Facebook 用于高效相似性搜索和密集向量聚类的库"
|
||||
sidebar_label: "Faiss"
|
||||
description: "Facebook 用于高效相似性搜索和密集向量聚类的库"
|
||||
---
|
||||
|
||||
{/* This page is auto-generated from the skill's SKILL.md by website/scripts/generate-skill-docs.py. Edit the source SKILL.md, not this page. */}
|
||||
|
||||
# Faiss
|
||||
|
||||
Facebook 用于高效相似性搜索和密集向量聚类的库。支持数十亿向量、GPU 加速以及多种索引类型(Flat、IVF、HNSW)。适用于快速 k-NN 搜索、大规模向量检索,或仅需纯相似性搜索而无需元数据的场景。最适合高性能应用。
|
||||
|
||||
## Skill 元数据
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| 来源 | 可选 — 通过 `hermes skills install official/mlops/faiss` 安装 |
|
||||
| 路径 | `optional-skills/mlops/faiss` |
|
||||
| 版本 | `1.0.0` |
|
||||
| 作者 | Orchestra Research |
|
||||
| 许可证 | MIT |
|
||||
| 依赖项 | `faiss-cpu`, `faiss-gpu`, `numpy` |
|
||||
| 平台 | linux, macos |
|
||||
| 标签 | `RAG`, `FAISS`, `Similarity Search`, `Vector Search`, `Facebook AI`, `GPU Acceleration`, `Billion-Scale`, `K-NN`, `HNSW`, `High Performance`, `Large Scale` |
|
||||
|
||||
## 参考:完整 SKILL.md
|
||||
|
||||
:::info
|
||||
以下是 Hermes 在触发此 skill 时加载的完整 skill 定义。这是 skill 激活时 agent 所看到的指令内容。
|
||||
:::
|
||||
|
||||
# FAISS - 高效相似性搜索
|
||||
|
||||
Facebook AI 用于十亿级向量相似性搜索的库。
|
||||
|
||||
## 何时使用 FAISS
|
||||
|
||||
**在以下情况下使用 FAISS:**
|
||||
- 需要对大型向量数据集(百万/十亿级)进行快速相似性搜索
|
||||
- 需要 GPU 加速
|
||||
- 纯向量相似性搜索(无需元数据过滤)
|
||||
- 对高吞吐量、低延迟有严格要求
|
||||
- 对 embedding(嵌入向量)进行离线/批量处理
|
||||
|
||||
**指标**:
|
||||
- **GitHub 31,700+ 星**
|
||||
- Meta/Facebook AI Research 出品
|
||||
- **支持数十亿向量**
|
||||
- **C++** 并提供 Python 绑定
|
||||
|
||||
**以下情况请使用替代方案**:
|
||||
- **Chroma/Pinecone**:需要元数据过滤
|
||||
- **Weaviate**:需要完整数据库功能
|
||||
- **Annoy**:更简单,功能较少
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 安装
|
||||
|
||||
```bash
|
||||
# 仅 CPU
|
||||
pip install faiss-cpu
|
||||
|
||||
# GPU 支持
|
||||
pip install faiss-gpu
|
||||
```
|
||||
|
||||
### 基本用法
|
||||
|
||||
```python
|
||||
import faiss
|
||||
import numpy as np
|
||||
|
||||
# 创建示例数据(1000 个向量,128 维)
|
||||
d = 128
|
||||
nb = 1000
|
||||
vectors = np.random.random((nb, d)).astype('float32')
|
||||
|
||||
# 创建索引
|
||||
index = faiss.IndexFlatL2(d) # L2 距离
|
||||
index.add(vectors) # 添加向量
|
||||
|
||||
# 搜索
|
||||
k = 5 # 查找 5 个最近邻
|
||||
query = np.random.random((1, d)).astype('float32')
|
||||
distances, indices = index.search(query, k)
|
||||
|
||||
print(f"Nearest neighbors: {indices}")
|
||||
print(f"Distances: {distances}")
|
||||
```
|
||||
|
||||
## 索引类型
|
||||
|
||||
### 1. Flat(精确搜索)
|
||||
|
||||
```python
|
||||
# L2(欧氏)距离
|
||||
index = faiss.IndexFlatL2(d)
|
||||
|
||||
# 内积(归一化后等同于余弦相似度)
|
||||
index = faiss.IndexFlatIP(d)
|
||||
|
||||
# 速度最慢,精度最高
|
||||
```
|
||||
|
||||
### 2. IVF(倒排文件)- 快速近似搜索
|
||||
|
||||
```python
|
||||
# 创建量化器
|
||||
quantizer = faiss.IndexFlatL2(d)
|
||||
|
||||
# 含 100 个聚类的 IVF 索引
|
||||
nlist = 100
|
||||
index = faiss.IndexIVFFlat(quantizer, d, nlist)
|
||||
|
||||
# 在数据上训练
|
||||
index.train(vectors)
|
||||
|
||||
# 添加向量
|
||||
index.add(vectors)
|
||||
|
||||
# 搜索(nprobe = 搜索的聚类数)
|
||||
index.nprobe = 10
|
||||
distances, indices = index.search(query, k)
|
||||
```
|
||||
|
||||
### 3. HNSW(分层小世界图)- 质量/速度最佳平衡
|
||||
|
||||
```python
|
||||
# HNSW 索引
|
||||
M = 32 # 每层连接数
|
||||
index = faiss.IndexHNSWFlat(d, M)
|
||||
|
||||
# 无需训练
|
||||
index.add(vectors)
|
||||
|
||||
# 搜索
|
||||
distances, indices = index.search(query, k)
|
||||
```
|
||||
|
||||
### 4. 乘积量化(Product Quantization)- 内存高效
|
||||
|
||||
```python
|
||||
# PQ 可将内存减少 16-32 倍
|
||||
m = 8 # 子量化器数量
|
||||
nbits = 8
|
||||
index = faiss.IndexPQ(d, m, nbits)
|
||||
|
||||
# 训练并添加
|
||||
index.train(vectors)
|
||||
index.add(vectors)
|
||||
```
|
||||
|
||||
## 保存与加载
|
||||
|
||||
```python
|
||||
# 保存索引
|
||||
faiss.write_index(index, "large.index")
|
||||
|
||||
# 加载索引
|
||||
index = faiss.read_index("large.index")
|
||||
|
||||
# 继续使用
|
||||
distances, indices = index.search(query, k)
|
||||
```
|
||||
|
||||
## GPU 加速
|
||||
|
||||
```python
|
||||
# 单 GPU
|
||||
res = faiss.StandardGpuResources()
|
||||
index_cpu = faiss.IndexFlatL2(d)
|
||||
index_gpu = faiss.index_cpu_to_gpu(res, 0, index_cpu) # GPU 0
|
||||
|
||||
# 多 GPU
|
||||
index_gpu = faiss.index_cpu_to_all_gpus(index_cpu)
|
||||
|
||||
# 比 CPU 快 10-100 倍
|
||||
```
|
||||
|
||||
## LangChain 集成
|
||||
|
||||
```python
|
||||
from langchain_community.vectorstores import FAISS
|
||||
from langchain_openai import OpenAIEmbeddings
|
||||
|
||||
# 创建 FAISS 向量存储
|
||||
vectorstore = FAISS.from_documents(docs, OpenAIEmbeddings())
|
||||
|
||||
# 保存
|
||||
vectorstore.save_local("faiss_index")
|
||||
|
||||
# 加载
|
||||
vectorstore = FAISS.load_local(
|
||||
"faiss_index",
|
||||
OpenAIEmbeddings(),
|
||||
allow_dangerous_deserialization=True
|
||||
)
|
||||
|
||||
# 搜索
|
||||
results = vectorstore.similarity_search("query", k=5)
|
||||
```
|
||||
|
||||
## LlamaIndex 集成
|
||||
|
||||
```python
|
||||
from llama_index.vector_stores.faiss import FaissVectorStore
|
||||
import faiss
|
||||
|
||||
# 创建 FAISS 索引
|
||||
d = 1536
|
||||
faiss_index = faiss.IndexFlatL2(d)
|
||||
|
||||
vector_store = FaissVectorStore(faiss_index=faiss_index)
|
||||
```
|
||||
|
||||
## 最佳实践
|
||||
|
||||
1. **选择合适的索引类型** — 10K 以下用 Flat,10K-1M 用 IVF,追求质量用 HNSW
|
||||
2. **余弦相似度需归一化** — 对归一化向量使用 IndexFlatIP
|
||||
3. **大数据集使用 GPU** — 速度提升 10-100 倍
|
||||
4. **保存已训练的索引** — 训练成本较高
|
||||
5. **调整 nprobe/ef_search** — 平衡速度与精度
|
||||
6. **监控内存使用** — 大数据集使用 PQ
|
||||
7. **批量查询** — 提升 GPU 利用率
|
||||
|
||||
## 性能对比
|
||||
|
||||
| 索引类型 | 构建时间 | 搜索时间 | 内存占用 | 精度 |
|
||||
|----------|----------|----------|----------|------|
|
||||
| Flat | 快 | 慢 | 高 | 100% |
|
||||
| IVF | 中等 | 快 | 中等 | 95-99% |
|
||||
| HNSW | 慢 | 最快 | 高 | 99% |
|
||||
| PQ | 中等 | 快 | 低 | 90-95% |
|
||||
|
||||
## 资源
|
||||
|
||||
- **GitHub**:https://github.com/facebookresearch/faiss ⭐ 31,700+
|
||||
- **Wiki**:https://github.com/facebookresearch/faiss/wiki
|
||||
- **许可证**:MIT
|
||||
+381
@@ -0,0 +1,381 @@
|
||||
---
|
||||
title: "优化注意力 Flash"
|
||||
sidebar_label: "优化注意力 Flash"
|
||||
description: "通过 Flash Attention 优化 Transformer 注意力机制,实现 2-4 倍加速和 10-20 倍内存减少"
|
||||
---
|
||||
|
||||
{/* This page is auto-generated from the skill's SKILL.md by website/scripts/generate-skill-docs.py. Edit the source SKILL.md, not this page. */}
|
||||
|
||||
# 优化注意力 Flash
|
||||
|
||||
通过 Flash Attention 优化 Transformer 注意力机制,实现 2-4 倍加速和 10-20 倍内存减少。适用于以下场景:使用长序列(>512 token)训练/运行 Transformer、遇到注意力相关的 GPU 内存问题,或需要更快的推理速度。支持 PyTorch 原生 SDPA、flash-attn 库、H100 FP8 以及滑动窗口注意力。
|
||||
|
||||
## Skill 元数据
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| 来源 | 可选 — 通过 `hermes skills install official/mlops/flash-attention` 安装 |
|
||||
| 路径 | `optional-skills/mlops/flash-attention` |
|
||||
| 版本 | `1.0.0` |
|
||||
| 作者 | Orchestra Research |
|
||||
| 许可证 | MIT |
|
||||
| 依赖项 | `flash-attn`, `torch`, `transformers` |
|
||||
| 平台 | linux, macos |
|
||||
| 标签 | `Optimization`, `Flash Attention`, `Attention Optimization`, `Memory Efficiency`, `Speed Optimization`, `Long Context`, `PyTorch`, `SDPA`, `H100`, `FP8`, `Transformers` |
|
||||
|
||||
## 参考:完整 SKILL.md
|
||||
|
||||
:::info
|
||||
以下是 Hermes 在触发该 skill 时加载的完整 skill 定义。这是 agent 在 skill 激活时所看到的指令内容。
|
||||
:::
|
||||
|
||||
# Flash Attention - 快速内存高效注意力
|
||||
|
||||
## 快速开始
|
||||
|
||||
Flash Attention 通过 IO 感知分块(IO-aware tiling)和重计算(recomputation)技术,为 Transformer 注意力提供 2-4 倍加速和 10-20 倍内存减少。
|
||||
|
||||
**PyTorch 原生方式(最简单,PyTorch 2.2+)**:
|
||||
```python
|
||||
import torch
|
||||
import torch.nn.functional as F
|
||||
|
||||
q = torch.randn(2, 8, 512, 64, device='cuda', dtype=torch.float16) # [batch, heads, seq, dim]
|
||||
k = torch.randn(2, 8, 512, 64, device='cuda', dtype=torch.float16)
|
||||
v = torch.randn(2, 8, 512, 64, device='cuda', dtype=torch.float16)
|
||||
|
||||
# 如果可用,自动使用 Flash Attention
|
||||
out = F.scaled_dot_product_attention(q, k, v)
|
||||
```
|
||||
|
||||
**flash-attn 库(功能更多)**:
|
||||
```bash
|
||||
pip install flash-attn --no-build-isolation
|
||||
```
|
||||
|
||||
```python
|
||||
from flash_attn import flash_attn_func
|
||||
|
||||
# q, k, v: [batch, seqlen, nheads, headdim]
|
||||
out = flash_attn_func(q, k, v, dropout_p=0.0, causal=True)
|
||||
```
|
||||
|
||||
## 常见工作流
|
||||
|
||||
### 工作流 1:在现有 PyTorch 模型中启用
|
||||
|
||||
复制此检查清单:
|
||||
|
||||
```
|
||||
Flash Attention 集成:
|
||||
- [ ] 步骤 1:检查 PyTorch 版本(≥2.2)
|
||||
- [ ] 步骤 2:启用 Flash Attention 后端
|
||||
- [ ] 步骤 3:通过性能分析验证加速效果
|
||||
- [ ] 步骤 4:测试精度与基线一致
|
||||
```
|
||||
|
||||
**步骤 1:检查 PyTorch 版本**
|
||||
|
||||
```bash
|
||||
python -c "import torch; print(torch.__version__)"
|
||||
# 应为 ≥2.2.0
|
||||
```
|
||||
|
||||
如果 <2.2,请升级:
|
||||
```bash
|
||||
pip install --upgrade torch
|
||||
```
|
||||
|
||||
**步骤 2:启用 Flash Attention 后端**
|
||||
|
||||
替换标准注意力:
|
||||
```python
|
||||
# 之前(标准注意力)
|
||||
attn_weights = torch.softmax(q @ k.transpose(-2, -1) / math.sqrt(d_k), dim=-1)
|
||||
out = attn_weights @ v
|
||||
|
||||
# 之后(Flash Attention)
|
||||
import torch.nn.functional as F
|
||||
out = F.scaled_dot_product_attention(q, k, v, attn_mask=mask)
|
||||
```
|
||||
|
||||
强制使用 Flash Attention 后端:
|
||||
```python
|
||||
with torch.backends.cuda.sdp_kernel(
|
||||
enable_flash=True,
|
||||
enable_math=False,
|
||||
enable_mem_efficient=False
|
||||
):
|
||||
out = F.scaled_dot_product_attention(q, k, v)
|
||||
```
|
||||
|
||||
**步骤 3:通过性能分析验证加速效果**
|
||||
|
||||
```python
|
||||
import torch.utils.benchmark as benchmark
|
||||
|
||||
def test_attention(use_flash):
|
||||
q, k, v = [torch.randn(2, 8, 2048, 64, device='cuda', dtype=torch.float16) for _ in range(3)]
|
||||
|
||||
if use_flash:
|
||||
with torch.backends.cuda.sdp_kernel(enable_flash=True):
|
||||
return F.scaled_dot_product_attention(q, k, v)
|
||||
else:
|
||||
attn = (q @ k.transpose(-2, -1) / 8.0).softmax(dim=-1)
|
||||
return attn @ v
|
||||
|
||||
# 基准测试
|
||||
t_flash = benchmark.Timer(stmt='test_attention(True)', globals=globals())
|
||||
t_standard = benchmark.Timer(stmt='test_attention(False)', globals=globals())
|
||||
|
||||
print(f"Flash: {t_flash.timeit(100).mean:.3f}s")
|
||||
print(f"Standard: {t_standard.timeit(100).mean:.3f}s")
|
||||
```
|
||||
|
||||
预期效果:序列长度 >512 token 时有 2-4 倍加速。
|
||||
|
||||
**步骤 4:测试精度与基线一致**
|
||||
|
||||
```python
|
||||
# 比较输出
|
||||
q, k, v = [torch.randn(1, 8, 512, 64, device='cuda', dtype=torch.float16) for _ in range(3)]
|
||||
|
||||
# Flash Attention
|
||||
out_flash = F.scaled_dot_product_attention(q, k, v)
|
||||
|
||||
# 标准注意力
|
||||
attn_weights = torch.softmax(q @ k.transpose(-2, -1) / 8.0, dim=-1)
|
||||
out_standard = attn_weights @ v
|
||||
|
||||
# 检查差异
|
||||
diff = (out_flash - out_standard).abs().max()
|
||||
print(f"Max difference: {diff:.6f}")
|
||||
# float16 下应 <1e-3
|
||||
```
|
||||
|
||||
### 工作流 2:使用 flash-attn 库实现高级功能
|
||||
|
||||
适用于多查询注意力(multi-query attention)、滑动窗口或 H100 FP8。
|
||||
|
||||
复制此检查清单:
|
||||
|
||||
```
|
||||
flash-attn 库安装:
|
||||
- [ ] 步骤 1:安装 flash-attn 库
|
||||
- [ ] 步骤 2:修改注意力代码
|
||||
- [ ] 步骤 3:启用高级功能
|
||||
- [ ] 步骤 4:基准测试性能
|
||||
```
|
||||
|
||||
**步骤 1:安装 flash-attn 库**
|
||||
|
||||
```bash
|
||||
# NVIDIA GPU(CUDA 12.0+)
|
||||
pip install flash-attn --no-build-isolation
|
||||
|
||||
# 验证安装
|
||||
python -c "from flash_attn import flash_attn_func; print('Success')"
|
||||
```
|
||||
|
||||
**步骤 2:修改注意力代码**
|
||||
|
||||
```python
|
||||
from flash_attn import flash_attn_func
|
||||
|
||||
# 输入:[batch_size, seq_len, num_heads, head_dim]
|
||||
# 如需要,从 [batch, heads, seq, dim] 转置
|
||||
q = q.transpose(1, 2) # [batch, seq, heads, dim]
|
||||
k = k.transpose(1, 2)
|
||||
v = v.transpose(1, 2)
|
||||
|
||||
out = flash_attn_func(
|
||||
q, k, v,
|
||||
dropout_p=0.1,
|
||||
causal=True, # 用于自回归模型
|
||||
window_size=(-1, -1), # 无滑动窗口
|
||||
softmax_scale=None # 自动缩放
|
||||
)
|
||||
|
||||
out = out.transpose(1, 2) # 转回 [batch, heads, seq, dim]
|
||||
```
|
||||
|
||||
**步骤 3:启用高级功能**
|
||||
|
||||
多查询注意力(跨 head 共享 K/V):
|
||||
```python
|
||||
from flash_attn import flash_attn_func
|
||||
|
||||
# q: [batch, seq, num_q_heads, dim]
|
||||
# k, v: [batch, seq, num_kv_heads, dim] # 更少的 KV head
|
||||
out = flash_attn_func(q, k, v) # 自动处理 MQA
|
||||
```
|
||||
|
||||
滑动窗口注意力(局部注意力):
|
||||
```python
|
||||
# 仅关注前后 256 个 token 的窗口
|
||||
out = flash_attn_func(
|
||||
q, k, v,
|
||||
window_size=(256, 256), # (左, 右) 窗口
|
||||
causal=True
|
||||
)
|
||||
```
|
||||
|
||||
**步骤 4:基准测试性能**
|
||||
|
||||
```python
|
||||
import torch
|
||||
from flash_attn import flash_attn_func
|
||||
import time
|
||||
|
||||
q, k, v = [torch.randn(4, 4096, 32, 64, device='cuda', dtype=torch.float16) for _ in range(3)]
|
||||
|
||||
# 预热
|
||||
for _ in range(10):
|
||||
_ = flash_attn_func(q, k, v)
|
||||
|
||||
# 基准测试
|
||||
torch.cuda.synchronize()
|
||||
start = time.time()
|
||||
for _ in range(100):
|
||||
out = flash_attn_func(q, k, v)
|
||||
torch.cuda.synchronize()
|
||||
end = time.time()
|
||||
|
||||
print(f"Time per iteration: {(end-start)/100*1000:.2f}ms")
|
||||
print(f"Memory allocated: {torch.cuda.max_memory_allocated()/1e9:.2f}GB")
|
||||
```
|
||||
|
||||
### 工作流 3:H100 FP8 优化(FlashAttention-3)
|
||||
|
||||
在 H100 GPU 上获得最大性能。
|
||||
|
||||
```
|
||||
FP8 设置:
|
||||
- [ ] 步骤 1:确认 H100 GPU 可用
|
||||
- [ ] 步骤 2:安装支持 FP8 的 flash-attn
|
||||
- [ ] 步骤 3:将输入转换为 FP8
|
||||
- [ ] 步骤 4:使用 FP8 注意力运行
|
||||
```
|
||||
|
||||
**步骤 1:确认 H100 GPU**
|
||||
|
||||
```bash
|
||||
nvidia-smi --query-gpu=name --format=csv
|
||||
# 应显示 "H100" 或 "H800"
|
||||
```
|
||||
|
||||
**步骤 2:安装支持 FP8 的 flash-attn**
|
||||
|
||||
```bash
|
||||
pip install flash-attn --no-build-isolation
|
||||
# H100 的 FP8 支持已包含在内
|
||||
```
|
||||
|
||||
**步骤 3:将输入转换为 FP8**
|
||||
|
||||
```python
|
||||
import torch
|
||||
|
||||
q = torch.randn(2, 4096, 32, 64, device='cuda', dtype=torch.float16)
|
||||
k = torch.randn(2, 4096, 32, 64, device='cuda', dtype=torch.float16)
|
||||
v = torch.randn(2, 4096, 32, 64, device='cuda', dtype=torch.float16)
|
||||
|
||||
# 转换为 float8_e4m3(FP8)
|
||||
q_fp8 = q.to(torch.float8_e4m3fn)
|
||||
k_fp8 = k.to(torch.float8_e4m3fn)
|
||||
v_fp8 = v.to(torch.float8_e4m3fn)
|
||||
```
|
||||
|
||||
**步骤 4:使用 FP8 注意力运行**
|
||||
|
||||
```python
|
||||
from flash_attn import flash_attn_func
|
||||
|
||||
# FlashAttention-3 在 H100 上自动使用 FP8 内核
|
||||
out = flash_attn_func(q_fp8, k_fp8, v_fp8)
|
||||
# 结果:约 1.2 PFLOPS,比 FP16 快 1.5-2 倍
|
||||
```
|
||||
|
||||
## 何时使用与替代方案
|
||||
|
||||
**使用 Flash Attention 的场景:**
|
||||
- 使用 >512 token 的序列训练 Transformer
|
||||
- 使用长上下文(>2K token)进行推理
|
||||
- GPU 内存受限(标准注意力 OOM)
|
||||
- 需要 2-4 倍加速且不损失精度
|
||||
- 使用 PyTorch 2.2+ 或可安装 flash-attn
|
||||
|
||||
**改用替代方案的场景:**
|
||||
- **标准注意力**:序列 <256 token(开销不值得)
|
||||
- **xFormers**:需要更多注意力变体(不仅仅是速度)
|
||||
- **内存高效注意力**:CPU 推理(Flash Attention 需要 GPU)
|
||||
|
||||
## 常见问题
|
||||
|
||||
**问题:ImportError: cannot import flash_attn**
|
||||
|
||||
使用 no-build-isolation 标志安装:
|
||||
```bash
|
||||
pip install flash-attn --no-build-isolation
|
||||
```
|
||||
|
||||
或先安装 CUDA toolkit:
|
||||
```bash
|
||||
conda install cuda -c nvidia
|
||||
pip install flash-attn --no-build-isolation
|
||||
```
|
||||
|
||||
**问题:速度低于预期(无加速效果)**
|
||||
|
||||
Flash Attention 的收益随序列长度增加而提升:
|
||||
- <512 token:加速极小(10-20%)
|
||||
- 512-2K token:2-3 倍加速
|
||||
- >2K token:3-4 倍加速
|
||||
|
||||
请确认序列长度是否足够。
|
||||
|
||||
**问题:RuntimeError: CUDA error**
|
||||
|
||||
验证 GPU 是否支持 Flash Attention:
|
||||
```python
|
||||
import torch
|
||||
print(torch.cuda.get_device_capability())
|
||||
# 应为 ≥(7, 5),即 Turing 及以上
|
||||
```
|
||||
|
||||
Flash Attention 要求:
|
||||
- Ampere(A100、A10):✅ 完全支持
|
||||
- Turing(T4):✅ 支持
|
||||
- Volta(V100):❌ 不支持
|
||||
|
||||
**问题:精度下降**
|
||||
|
||||
检查 dtype 是否为 float16 或 bfloat16(而非 float32):
|
||||
```python
|
||||
q = q.to(torch.float16) # 或 torch.bfloat16
|
||||
```
|
||||
|
||||
Flash Attention 使用 float16/bfloat16 以提升速度,不支持 float32。
|
||||
|
||||
## 高级主题
|
||||
|
||||
**与 HuggingFace Transformers 集成**:参见 [references/transformers-integration.md](https://github.com/NousResearch/hermes-agent/blob/main/optional-skills/mlops/flash-attention/references/transformers-integration.md),了解如何在 BERT、GPT、Llama 模型中启用 Flash Attention。
|
||||
|
||||
**性能基准测试**:参见 [references/benchmarks.md](https://github.com/NousResearch/hermes-agent/blob/main/optional-skills/mlops/flash-attention/references/benchmarks.md),查看跨 GPU 和序列长度的详细速度与内存对比。
|
||||
|
||||
## 硬件要求
|
||||
|
||||
- **GPU**:NVIDIA Ampere 及以上(A100、A10、A30)或 AMD MI200 及以上
|
||||
- **显存**:与标准注意力相同(Flash Attention 不增加内存占用)
|
||||
- **CUDA**:12.0+(最低 11.8)
|
||||
- **PyTorch**:2.2+ 以获得原生支持
|
||||
|
||||
**不支持**:V100(Volta)、CPU 推理
|
||||
|
||||
## 资源
|
||||
|
||||
- 论文:"FlashAttention: Fast and Memory-Efficient Exact Attention with IO-Awareness"(NeurIPS 2022)
|
||||
- 论文:"FlashAttention-2: Faster Attention with Better Parallelism and Work Partitioning"(ICLR 2024)
|
||||
- 博客:https://tridao.me/blog/2024/flash3/
|
||||
- GitHub:https://github.com/Dao-AILab/flash-attention
|
||||
- PyTorch 文档:https://pytorch.org/docs/stable/generated/torch.nn.functional.scaled_dot_product_attention.html
|
||||
+591
@@ -0,0 +1,591 @@
|
||||
---
|
||||
title: "Guidance"
|
||||
sidebar_label: "Guidance"
|
||||
description: "使用正则表达式和语法控制 LLM 输出,保证生成有效的 JSON/XML/代码,强制结构化格式,并使用 Guidance(微软研究院的约束生成框架)构建多步骤工作流..."
|
||||
---
|
||||
|
||||
{/* This page is auto-generated from the skill's SKILL.md by website/scripts/generate-skill-docs.py. Edit the source SKILL.md, not this page. */}
|
||||
|
||||
# Guidance
|
||||
|
||||
使用正则表达式和语法控制 LLM 输出,保证生成有效的 JSON/XML/代码,强制结构化格式,并使用 Guidance(微软研究院的约束生成框架)构建多步骤工作流
|
||||
|
||||
## Skill 元数据
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| 来源 | 可选 — 通过 `hermes skills install official/mlops/guidance` 安装 |
|
||||
| 路径 | `optional-skills/mlops/guidance` |
|
||||
| 版本 | `1.0.0` |
|
||||
| 作者 | Orchestra Research |
|
||||
| 许可证 | MIT |
|
||||
| 依赖项 | `guidance`, `transformers` |
|
||||
| 平台 | linux, macos, windows |
|
||||
| 标签 | `Prompt Engineering`, `Guidance`, `Constrained Generation`, `Structured Output`, `JSON Validation`, `Grammar`, `Microsoft Research`, `Format Enforcement`, `Multi-Step Workflows` |
|
||||
|
||||
## 参考:完整 SKILL.md
|
||||
|
||||
:::info
|
||||
以下是 Hermes 在触发此 skill 时加载的完整 skill 定义。这是 agent 在 skill 激活时看到的指令内容。
|
||||
:::
|
||||
|
||||
# Guidance:约束 LLM 生成
|
||||
|
||||
## 何时使用此 Skill
|
||||
|
||||
在以下情况下使用 Guidance:
|
||||
- **使用正则表达式或语法控制 LLM 输出语法**
|
||||
- **保证生成有效的 JSON/XML/代码**
|
||||
- **相比传统 prompting(提示词)方式降低延迟**
|
||||
- **强制结构化格式**(日期、邮箱、ID 等)
|
||||
- **使用 Python 风格的控制流构建多步骤工作流**
|
||||
- **通过语法约束防止无效输出**
|
||||
|
||||
**GitHub Stars**:18,000+ | **来自**:微软研究院
|
||||
|
||||
## 安装
|
||||
|
||||
```bash
|
||||
# 基础安装
|
||||
pip install guidance
|
||||
|
||||
# 指定后端
|
||||
pip install guidance[transformers] # Hugging Face 模型
|
||||
pip install guidance[llama_cpp] # llama.cpp 模型
|
||||
```
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 基础示例:结构化生成
|
||||
|
||||
```python
|
||||
from guidance import models, gen
|
||||
|
||||
# 加载模型(支持 OpenAI、Transformers、llama.cpp)
|
||||
lm = models.OpenAI("gpt-4")
|
||||
|
||||
# 带约束生成
|
||||
result = lm + "The capital of France is " + gen("capital", max_tokens=5)
|
||||
|
||||
print(result["capital"]) # "Paris"
|
||||
```
|
||||
|
||||
### 使用 Anthropic Claude
|
||||
|
||||
```python
|
||||
from guidance import models, gen, system, user, assistant
|
||||
|
||||
# 配置 Claude
|
||||
lm = models.Anthropic("claude-sonnet-4-5-20250929")
|
||||
|
||||
# 使用上下文管理器实现对话格式
|
||||
with system():
|
||||
lm += "You are a helpful assistant."
|
||||
|
||||
with user():
|
||||
lm += "What is the capital of France?"
|
||||
|
||||
with assistant():
|
||||
lm += gen(max_tokens=20)
|
||||
```
|
||||
|
||||
## 核心概念
|
||||
|
||||
### 1. 上下文管理器
|
||||
|
||||
Guidance 使用 Python 风格的上下文管理器实现对话式交互。
|
||||
|
||||
```python
|
||||
from guidance import system, user, assistant, gen
|
||||
|
||||
lm = models.Anthropic("claude-sonnet-4-5-20250929")
|
||||
|
||||
# 系统消息
|
||||
with system():
|
||||
lm += "You are a JSON generation expert."
|
||||
|
||||
# 用户消息
|
||||
with user():
|
||||
lm += "Generate a person object with name and age."
|
||||
|
||||
# 助手回复
|
||||
with assistant():
|
||||
lm += gen("response", max_tokens=100)
|
||||
|
||||
print(lm["response"])
|
||||
```
|
||||
|
||||
**优势:**
|
||||
- 自然的对话流程
|
||||
- 清晰的角色分离
|
||||
- 易于阅读和维护
|
||||
|
||||
### 2. 约束生成
|
||||
|
||||
Guidance 使用正则表达式或语法确保输出符合指定模式。
|
||||
|
||||
#### 正则表达式约束
|
||||
|
||||
```python
|
||||
from guidance import models, gen
|
||||
|
||||
lm = models.Anthropic("claude-sonnet-4-5-20250929")
|
||||
|
||||
# 约束为有效邮箱格式
|
||||
lm += "Email: " + gen("email", regex=r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}")
|
||||
|
||||
# 约束为日期格式(YYYY-MM-DD)
|
||||
lm += "Date: " + gen("date", regex=r"\d{4}-\d{2}-\d{2}")
|
||||
|
||||
# 约束为电话号码
|
||||
lm += "Phone: " + gen("phone", regex=r"\d{3}-\d{3}-\d{4}")
|
||||
|
||||
print(lm["email"]) # 保证为有效邮箱
|
||||
print(lm["date"]) # 保证为 YYYY-MM-DD 格式
|
||||
```
|
||||
|
||||
**工作原理:**
|
||||
- 正则表达式在 token(词元)级别转换为语法
|
||||
- 生成过程中过滤无效 token
|
||||
- 模型只能生成符合匹配条件的输出
|
||||
|
||||
#### 选择约束
|
||||
|
||||
```python
|
||||
from guidance import models, gen, select
|
||||
|
||||
lm = models.Anthropic("claude-sonnet-4-5-20250929")
|
||||
|
||||
# 约束为特定选项
|
||||
lm += "Sentiment: " + select(["positive", "negative", "neutral"], name="sentiment")
|
||||
|
||||
# 多选题选择
|
||||
lm += "Best answer: " + select(
|
||||
["A) Paris", "B) London", "C) Berlin", "D) Madrid"],
|
||||
name="answer"
|
||||
)
|
||||
|
||||
print(lm["sentiment"]) # 其中之一:positive、negative、neutral
|
||||
print(lm["answer"]) # 其中之一:A、B、C 或 D
|
||||
```
|
||||
|
||||
### 3. Token 修复(Token Healing)
|
||||
|
||||
Guidance 自动"修复" prompt 与生成内容之间的 token 边界。
|
||||
|
||||
**问题:** 分词会产生不自然的边界。
|
||||
|
||||
```python
|
||||
# 不使用 token 修复
|
||||
prompt = "The capital of France is "
|
||||
# 最后一个 token:" is "
|
||||
# 第一个生成的 token 可能是 " Par"(带前导空格)
|
||||
# 结果:"The capital of France is Paris"(双空格!)
|
||||
```
|
||||
|
||||
**解决方案:** Guidance 回退一个 token 并重新生成。
|
||||
|
||||
```python
|
||||
from guidance import models, gen
|
||||
|
||||
lm = models.Anthropic("claude-sonnet-4-5-20250929")
|
||||
|
||||
# 默认启用 token 修复
|
||||
lm += "The capital of France is " + gen("capital", max_tokens=5)
|
||||
# 结果:"The capital of France is Paris"(间距正确)
|
||||
```
|
||||
|
||||
**优势:**
|
||||
- 自然的文本边界
|
||||
- 无尴尬的间距问题
|
||||
- 更好的模型性能(模型看到自然的 token 序列)
|
||||
|
||||
### 4. 基于语法的生成
|
||||
|
||||
使用上下文无关语法定义复杂结构。
|
||||
|
||||
```python
|
||||
from guidance import models, gen
|
||||
|
||||
lm = models.Anthropic("claude-sonnet-4-5-20250929")
|
||||
|
||||
# JSON 语法(简化版)
|
||||
json_grammar = """
|
||||
{
|
||||
"name": <gen name regex="[A-Za-z ]+" max_tokens=20>,
|
||||
"age": <gen age regex="[0-9]+" max_tokens=3>,
|
||||
"email": <gen email regex="[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}" max_tokens=50>
|
||||
}
|
||||
"""
|
||||
|
||||
# 生成有效 JSON
|
||||
lm += gen("person", grammar=json_grammar)
|
||||
|
||||
print(lm["person"]) # 保证为有效 JSON 结构
|
||||
```
|
||||
|
||||
**使用场景:**
|
||||
- 复杂结构化输出
|
||||
- 嵌套数据结构
|
||||
- 编程语言语法
|
||||
- 领域特定语言
|
||||
|
||||
### 5. Guidance 函数
|
||||
|
||||
使用 `@guidance` 装饰器创建可复用的生成模式。
|
||||
|
||||
```python
|
||||
from guidance import guidance, gen, models
|
||||
|
||||
@guidance
|
||||
def generate_person(lm):
|
||||
"""生成包含姓名和年龄的人物信息。"""
|
||||
lm += "Name: " + gen("name", max_tokens=20, stop="\n")
|
||||
lm += "\nAge: " + gen("age", regex=r"[0-9]+", max_tokens=3)
|
||||
return lm
|
||||
|
||||
# 使用该函数
|
||||
lm = models.Anthropic("claude-sonnet-4-5-20250929")
|
||||
lm = generate_person(lm)
|
||||
|
||||
print(lm["name"])
|
||||
print(lm["age"])
|
||||
```
|
||||
|
||||
**有状态函数:**
|
||||
|
||||
```python
|
||||
@guidance(stateless=False)
|
||||
def react_agent(lm, question, tools, max_rounds=5):
|
||||
"""带工具调用的 ReAct agent。"""
|
||||
lm += f"Question: {question}\n\n"
|
||||
|
||||
for i in range(max_rounds):
|
||||
# 思考
|
||||
lm += f"Thought {i+1}: " + gen("thought", stop="\n")
|
||||
|
||||
# 动作
|
||||
lm += "\nAction: " + select(list(tools.keys()), name="action")
|
||||
|
||||
# 执行工具
|
||||
tool_result = tools[lm["action"]]()
|
||||
lm += f"\nObservation: {tool_result}\n\n"
|
||||
|
||||
# 检查是否完成
|
||||
lm += "Done? " + select(["Yes", "No"], name="done")
|
||||
if lm["done"] == "Yes":
|
||||
break
|
||||
|
||||
# 最终答案
|
||||
lm += "\nFinal Answer: " + gen("answer", max_tokens=100)
|
||||
return lm
|
||||
```
|
||||
|
||||
## 后端配置
|
||||
|
||||
### Anthropic Claude
|
||||
|
||||
```python
|
||||
from guidance import models
|
||||
|
||||
lm = models.Anthropic(
|
||||
model="claude-sonnet-4-5-20250929",
|
||||
api_key="your-api-key" # 或设置 ANTHROPIC_API_KEY 环境变量
|
||||
)
|
||||
```
|
||||
|
||||
### OpenAI
|
||||
|
||||
```python
|
||||
lm = models.OpenAI(
|
||||
model="gpt-4o-mini",
|
||||
api_key="your-api-key" # 或设置 OPENAI_API_KEY 环境变量
|
||||
)
|
||||
```
|
||||
|
||||
### 本地模型(Transformers)
|
||||
|
||||
```python
|
||||
from guidance.models import Transformers
|
||||
|
||||
lm = Transformers(
|
||||
"microsoft/Phi-4-mini-instruct",
|
||||
device="cuda" # 或 "cpu"
|
||||
)
|
||||
```
|
||||
|
||||
### 本地模型(llama.cpp)
|
||||
|
||||
```python
|
||||
from guidance.models import LlamaCpp
|
||||
|
||||
lm = LlamaCpp(
|
||||
model_path="/path/to/model.gguf",
|
||||
n_ctx=4096,
|
||||
n_gpu_layers=35
|
||||
)
|
||||
```
|
||||
|
||||
## 常用模式
|
||||
|
||||
### 模式 1:JSON 生成
|
||||
|
||||
```python
|
||||
from guidance import models, gen, system, user, assistant
|
||||
|
||||
lm = models.Anthropic("claude-sonnet-4-5-20250929")
|
||||
|
||||
with system():
|
||||
lm += "You generate valid JSON."
|
||||
|
||||
with user():
|
||||
lm += "Generate a user profile with name, age, and email."
|
||||
|
||||
with assistant():
|
||||
lm += """{
|
||||
"name": """ + gen("name", regex=r'"[A-Za-z ]+"', max_tokens=30) + """,
|
||||
"age": """ + gen("age", regex=r"[0-9]+", max_tokens=3) + """,
|
||||
"email": """ + gen("email", regex=r'"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}"', max_tokens=50) + """
|
||||
}"""
|
||||
|
||||
print(lm) # 保证为有效 JSON
|
||||
```
|
||||
|
||||
### 模式 2:分类
|
||||
|
||||
```python
|
||||
from guidance import models, gen, select
|
||||
|
||||
lm = models.Anthropic("claude-sonnet-4-5-20250929")
|
||||
|
||||
text = "This product is amazing! I love it."
|
||||
|
||||
lm += f"Text: {text}\n"
|
||||
lm += "Sentiment: " + select(["positive", "negative", "neutral"], name="sentiment")
|
||||
lm += "\nConfidence: " + gen("confidence", regex=r"[0-9]+", max_tokens=3) + "%"
|
||||
|
||||
print(f"Sentiment: {lm['sentiment']}")
|
||||
print(f"Confidence: {lm['confidence']}%")
|
||||
```
|
||||
|
||||
### 模式 3:多步骤推理
|
||||
|
||||
```python
|
||||
from guidance import models, gen, guidance
|
||||
|
||||
@guidance
|
||||
def chain_of_thought(lm, question):
|
||||
"""逐步推理生成答案。"""
|
||||
lm += f"Question: {question}\n\n"
|
||||
|
||||
# 生成多个推理步骤
|
||||
for i in range(3):
|
||||
lm += f"Step {i+1}: " + gen(f"step_{i+1}", stop="\n", max_tokens=100) + "\n"
|
||||
|
||||
# 最终答案
|
||||
lm += "\nTherefore, the answer is: " + gen("answer", max_tokens=50)
|
||||
|
||||
return lm
|
||||
|
||||
lm = models.Anthropic("claude-sonnet-4-5-20250929")
|
||||
lm = chain_of_thought(lm, "What is 15% of 200?")
|
||||
|
||||
print(lm["answer"])
|
||||
```
|
||||
|
||||
### 模式 4:ReAct Agent
|
||||
|
||||
```python
|
||||
from guidance import models, gen, select, guidance
|
||||
|
||||
@guidance(stateless=False)
|
||||
def react_agent(lm, question):
|
||||
"""带工具调用的 ReAct agent。"""
|
||||
tools = {
|
||||
"calculator": lambda expr: eval(expr),
|
||||
"search": lambda query: f"Search results for: {query}",
|
||||
}
|
||||
|
||||
lm += f"Question: {question}\n\n"
|
||||
|
||||
for round in range(5):
|
||||
# 思考
|
||||
lm += f"Thought: " + gen("thought", stop="\n") + "\n"
|
||||
|
||||
# 动作选择
|
||||
lm += "Action: " + select(["calculator", "search", "answer"], name="action")
|
||||
|
||||
if lm["action"] == "answer":
|
||||
lm += "\nFinal Answer: " + gen("answer", max_tokens=100)
|
||||
break
|
||||
|
||||
# 动作输入
|
||||
lm += "\nAction Input: " + gen("action_input", stop="\n") + "\n"
|
||||
|
||||
# 执行工具
|
||||
if lm["action"] in tools:
|
||||
result = tools[lm["action"]](lm["action_input"])
|
||||
lm += f"Observation: {result}\n\n"
|
||||
|
||||
return lm
|
||||
|
||||
lm = models.Anthropic("claude-sonnet-4-5-20250929")
|
||||
lm = react_agent(lm, "What is 25 * 4 + 10?")
|
||||
print(lm["answer"])
|
||||
```
|
||||
|
||||
### 模式 5:数据提取
|
||||
|
||||
```python
|
||||
from guidance import models, gen, guidance
|
||||
|
||||
@guidance
|
||||
def extract_entities(lm, text):
|
||||
"""从文本中提取结构化实体。"""
|
||||
lm += f"Text: {text}\n\n"
|
||||
|
||||
# 提取人物
|
||||
lm += "Person: " + gen("person", stop="\n", max_tokens=30) + "\n"
|
||||
|
||||
# 提取组织
|
||||
lm += "Organization: " + gen("organization", stop="\n", max_tokens=30) + "\n"
|
||||
|
||||
# 提取日期
|
||||
lm += "Date: " + gen("date", regex=r"\d{4}-\d{2}-\d{2}", max_tokens=10) + "\n"
|
||||
|
||||
# 提取地点
|
||||
lm += "Location: " + gen("location", stop="\n", max_tokens=30) + "\n"
|
||||
|
||||
return lm
|
||||
|
||||
text = "Tim Cook announced at Apple Park on 2024-09-15 in Cupertino."
|
||||
|
||||
lm = models.Anthropic("claude-sonnet-4-5-20250929")
|
||||
lm = extract_entities(lm, text)
|
||||
|
||||
print(f"Person: {lm['person']}")
|
||||
print(f"Organization: {lm['organization']}")
|
||||
print(f"Date: {lm['date']}")
|
||||
print(f"Location: {lm['location']}")
|
||||
```
|
||||
|
||||
## 最佳实践
|
||||
|
||||
### 1. 使用正则表达式进行格式验证
|
||||
|
||||
```python
|
||||
# ✅ 好:正则表达式确保格式有效
|
||||
lm += "Email: " + gen("email", regex=r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}")
|
||||
|
||||
# ❌ 差:自由生成可能产生无效邮箱
|
||||
lm += "Email: " + gen("email", max_tokens=50)
|
||||
```
|
||||
|
||||
### 2. 对固定类别使用 select()
|
||||
|
||||
```python
|
||||
# ✅ 好:保证为有效类别
|
||||
lm += "Status: " + select(["pending", "approved", "rejected"], name="status")
|
||||
|
||||
# ❌ 差:可能生成拼写错误或无效值
|
||||
lm += "Status: " + gen("status", max_tokens=20)
|
||||
```
|
||||
|
||||
### 3. 利用 Token 修复
|
||||
|
||||
```python
|
||||
# 默认启用 token 修复
|
||||
# 无需特殊操作——自然拼接即可
|
||||
lm += "The capital is " + gen("capital") # 自动修复
|
||||
```
|
||||
|
||||
### 4. 使用停止序列
|
||||
|
||||
```python
|
||||
# ✅ 好:在换行处停止,适用于单行输出
|
||||
lm += "Name: " + gen("name", stop="\n")
|
||||
|
||||
# ❌ 差:可能生成多行内容
|
||||
lm += "Name: " + gen("name", max_tokens=50)
|
||||
```
|
||||
|
||||
### 5. 创建可复用函数
|
||||
|
||||
```python
|
||||
# ✅ 好:可复用模式
|
||||
@guidance
|
||||
def generate_person(lm):
|
||||
lm += "Name: " + gen("name", stop="\n")
|
||||
lm += "\nAge: " + gen("age", regex=r"[0-9]+")
|
||||
return lm
|
||||
|
||||
# 多次使用
|
||||
lm = generate_person(lm)
|
||||
lm += "\n\n"
|
||||
lm = generate_person(lm)
|
||||
```
|
||||
|
||||
### 6. 平衡约束力度
|
||||
|
||||
```python
|
||||
# ✅ 好:合理的约束
|
||||
lm += gen("name", regex=r"[A-Za-z ]+", max_tokens=30)
|
||||
|
||||
# ❌ 过于严格:可能失败或非常缓慢
|
||||
lm += gen("name", regex=r"^(John|Jane)$", max_tokens=10)
|
||||
```
|
||||
|
||||
## 与替代方案的对比
|
||||
|
||||
| 特性 | Guidance | Instructor | Outlines | LMQL |
|
||||
|---------|----------|------------|----------|------|
|
||||
| 正则表达式约束 | ✅ 支持 | ❌ 不支持 | ✅ 支持 | ✅ 支持 |
|
||||
| 语法支持 | ✅ CFG | ❌ 不支持 | ✅ CFG | ✅ CFG |
|
||||
| Pydantic 验证 | ❌ 不支持 | ✅ 支持 | ✅ 支持 | ❌ 不支持 |
|
||||
| Token 修复 | ✅ 支持 | ❌ 不支持 | ✅ 支持 | ❌ 不支持 |
|
||||
| 本地模型 | ✅ 支持 | ⚠️ 有限 | ✅ 支持 | ✅ 支持 |
|
||||
| API 模型 | ✅ 支持 | ✅ 支持 | ⚠️ 有限 | ✅ 支持 |
|
||||
| Python 风格语法 | ✅ 支持 | ✅ 支持 | ✅ 支持 | ❌ 类 SQL |
|
||||
| 学习曲线 | 低 | 低 | 中 | 高 |
|
||||
|
||||
**何时选择 Guidance:**
|
||||
- 需要正则表达式/语法约束
|
||||
- 需要 token 修复
|
||||
- 构建带控制流的复杂工作流
|
||||
- 使用本地模型(Transformers、llama.cpp)
|
||||
- 偏好 Python 风格语法
|
||||
|
||||
**何时选择替代方案:**
|
||||
- Instructor:需要带自动重试的 Pydantic 验证
|
||||
- Outlines:需要 JSON schema 验证
|
||||
- LMQL:偏好声明式查询语法
|
||||
|
||||
## 性能特性
|
||||
|
||||
**延迟降低:**
|
||||
- 对于约束输出,比传统 prompting 快 30–50%
|
||||
- Token 修复减少不必要的重新生成
|
||||
- 语法约束防止无效 token 的生成
|
||||
|
||||
**内存占用:**
|
||||
- 相比无约束生成,额外开销极小
|
||||
- 语法编译结果在首次使用后缓存
|
||||
- 推理时高效过滤 token
|
||||
|
||||
**Token 效率:**
|
||||
- 防止在无效输出上浪费 token
|
||||
- 无需重试循环
|
||||
- 直接生成有效输出
|
||||
|
||||
## 资源
|
||||
|
||||
- **文档**:https://guidance.readthedocs.io
|
||||
- **GitHub**:https://github.com/guidance-ai/guidance(18k+ stars)
|
||||
- **Notebooks**:https://github.com/guidance-ai/guidance/tree/main/notebooks
|
||||
- **Discord**:提供社区支持
|
||||
|
||||
## 另请参阅
|
||||
|
||||
- `references/constraints.md` — 全面的正则表达式和语法模式
|
||||
- `references/backends.md` — 后端专项配置
|
||||
- `references/examples.md` — 生产就绪示例
|
||||
+535
@@ -0,0 +1,535 @@
|
||||
---
|
||||
title: "Huggingface Tokenizers — 为研究和生产优化的快速 tokenizer"
|
||||
sidebar_label: "Huggingface Tokenizers"
|
||||
description: "为研究和生产优化的快速 tokenizer"
|
||||
---
|
||||
|
||||
{/* This page is auto-generated from the skill's SKILL.md by website/scripts/generate-skill-docs.py. Edit the source SKILL.md, not this page. */}
|
||||
|
||||
# Huggingface Tokenizers
|
||||
|
||||
为研究和生产优化的快速 tokenizer(分词器)。基于 Rust 的实现可在 <20 秒内对 1GB 文本完成分词。支持 BPE、WordPiece 和 Unigram 算法。可训练自定义词表、追踪对齐关系、处理 padding(填充)/truncation(截断)。与 transformers 无缝集成。当需要高性能分词或训练自定义 tokenizer 时使用。
|
||||
|
||||
## Skill 元数据
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| 来源 | 可选 — 通过 `hermes skills install official/mlops/huggingface-tokenizers` 安装 |
|
||||
| 路径 | `optional-skills/mlops/huggingface-tokenizers` |
|
||||
| 版本 | `1.0.0` |
|
||||
| 作者 | Orchestra Research |
|
||||
| 许可证 | MIT |
|
||||
| 依赖 | `tokenizers`, `transformers`, `datasets` |
|
||||
| 平台 | linux, macos, windows |
|
||||
| 标签 | `Tokenization`, `HuggingFace`, `BPE`, `WordPiece`, `Unigram`, `Fast Tokenization`, `Rust`, `Custom Tokenizer`, `Alignment Tracking`, `Production` |
|
||||
|
||||
## 参考:完整 SKILL.md
|
||||
|
||||
:::info
|
||||
以下是 Hermes 在触发此 skill 时加载的完整 skill 定义。这是 skill 激活时 agent 所看到的指令内容。
|
||||
:::
|
||||
|
||||
# HuggingFace Tokenizers — 高性能 NLP 分词
|
||||
|
||||
具备 Rust 性能与 Python 易用性的快速、生产就绪 tokenizer。
|
||||
|
||||
## 何时使用 HuggingFace Tokenizers
|
||||
|
||||
**在以下情况下使用 HuggingFace Tokenizers:**
|
||||
- 需要极快的分词速度(每 GB 文本 <20 秒)
|
||||
- 从头训练自定义 tokenizer
|
||||
- 需要对齐追踪(token → 原始文本位置)
|
||||
- 构建生产级 NLP 流水线
|
||||
- 需要高效地对大型语料库进行分词
|
||||
|
||||
**性能**:
|
||||
- **速度**:CPU 上对 1GB 文本分词 <20 秒
|
||||
- **实现**:Rust 核心,提供 Python/Node.js 绑定
|
||||
- **效率**:比纯 Python 实现快 10–100 倍
|
||||
|
||||
**改用其他方案的情况**:
|
||||
- **SentencePiece**:语言无关,被 T5/ALBERT 使用
|
||||
- **tiktoken**:OpenAI 用于 GPT 模型的 BPE tokenizer
|
||||
- **transformers AutoTokenizer**:仅加载预训练模型时使用(内部使用本库)
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 安装
|
||||
|
||||
```bash
|
||||
# 安装 tokenizers
|
||||
pip install tokenizers
|
||||
|
||||
# 与 transformers 集成
|
||||
pip install tokenizers transformers
|
||||
```
|
||||
|
||||
### 加载预训练 tokenizer
|
||||
|
||||
```python
|
||||
from tokenizers import Tokenizer
|
||||
|
||||
# 从 HuggingFace Hub 加载
|
||||
tokenizer = Tokenizer.from_pretrained("bert-base-uncased")
|
||||
|
||||
# 对文本编码
|
||||
output = tokenizer.encode("Hello, how are you?")
|
||||
print(output.tokens) # ['hello', ',', 'how', 'are', 'you', '?']
|
||||
print(output.ids) # [7592, 1010, 2129, 2024, 2017, 1029]
|
||||
|
||||
# 解码还原
|
||||
text = tokenizer.decode(output.ids)
|
||||
print(text) # "hello, how are you?"
|
||||
```
|
||||
|
||||
### 训练自定义 BPE tokenizer
|
||||
|
||||
```python
|
||||
from tokenizers import Tokenizer
|
||||
from tokenizers.models import BPE
|
||||
from tokenizers.trainers import BpeTrainer
|
||||
from tokenizers.pre_tokenizers import Whitespace
|
||||
|
||||
# 使用 BPE 模型初始化 tokenizer
|
||||
tokenizer = Tokenizer(BPE(unk_token="[UNK]"))
|
||||
tokenizer.pre_tokenizer = Whitespace()
|
||||
|
||||
# 配置训练器
|
||||
trainer = BpeTrainer(
|
||||
vocab_size=30000,
|
||||
special_tokens=["[UNK]", "[CLS]", "[SEP]", "[PAD]", "[MASK]"],
|
||||
min_frequency=2
|
||||
)
|
||||
|
||||
# 在文件上训练
|
||||
files = ["train.txt", "validation.txt"]
|
||||
tokenizer.train(files, trainer)
|
||||
|
||||
# 保存
|
||||
tokenizer.save("my-tokenizer.json")
|
||||
```
|
||||
|
||||
**训练时间**:100MB 语料约 1–2 分钟,1GB 语料约 10–20 分钟
|
||||
|
||||
### 批量编码与 padding
|
||||
|
||||
```python
|
||||
# 启用 padding
|
||||
tokenizer.enable_padding(pad_id=3, pad_token="[PAD]")
|
||||
|
||||
# 批量编码
|
||||
texts = ["Hello world", "This is a longer sentence"]
|
||||
encodings = tokenizer.encode_batch(texts)
|
||||
|
||||
for encoding in encodings:
|
||||
print(encoding.ids)
|
||||
# [101, 7592, 2088, 102, 3, 3, 3]
|
||||
# [101, 2023, 2003, 1037, 2936, 6251, 102]
|
||||
```
|
||||
|
||||
## 分词算法
|
||||
|
||||
### BPE(字节对编码)
|
||||
|
||||
**工作原理**:
|
||||
1. 从字符级词表开始
|
||||
2. 找出最频繁的字符对
|
||||
3. 合并为新 token,加入词表
|
||||
4. 重复直到达到词表大小
|
||||
|
||||
**使用者**:GPT-2、GPT-3、RoBERTa、BART、DeBERTa
|
||||
|
||||
```python
|
||||
from tokenizers import Tokenizer
|
||||
from tokenizers.models import BPE
|
||||
from tokenizers.trainers import BpeTrainer
|
||||
from tokenizers.pre_tokenizers import ByteLevel
|
||||
|
||||
tokenizer = Tokenizer(BPE(unk_token="<|endoftext|>"))
|
||||
tokenizer.pre_tokenizer = ByteLevel()
|
||||
|
||||
trainer = BpeTrainer(
|
||||
vocab_size=50257,
|
||||
special_tokens=["<|endoftext|>"],
|
||||
min_frequency=2
|
||||
)
|
||||
|
||||
tokenizer.train(files=["data.txt"], trainer=trainer)
|
||||
```
|
||||
|
||||
**优点**:
|
||||
- 能较好地处理 OOV 词(拆分为子词)
|
||||
- 词表大小灵活
|
||||
- 适合形态丰富的语言
|
||||
|
||||
**权衡**:
|
||||
- 分词结果依赖合并顺序
|
||||
- 可能意外拆分常见词
|
||||
|
||||
### WordPiece
|
||||
|
||||
**工作原理**:
|
||||
1. 从字符词表开始
|
||||
2. 对合并对打分:`frequency(pair) / (frequency(first) × frequency(second))`
|
||||
3. 合并得分最高的对
|
||||
4. 重复直到达到词表大小
|
||||
|
||||
**使用者**:BERT、DistilBERT、MobileBERT
|
||||
|
||||
```python
|
||||
from tokenizers import Tokenizer
|
||||
from tokenizers.models import WordPiece
|
||||
from tokenizers.trainers import WordPieceTrainer
|
||||
from tokenizers.pre_tokenizers import Whitespace
|
||||
from tokenizers.normalizers import BertNormalizer
|
||||
|
||||
tokenizer = Tokenizer(WordPiece(unk_token="[UNK]"))
|
||||
tokenizer.normalizer = BertNormalizer(lowercase=True)
|
||||
tokenizer.pre_tokenizer = Whitespace()
|
||||
|
||||
trainer = WordPieceTrainer(
|
||||
vocab_size=30522,
|
||||
special_tokens=["[UNK]", "[CLS]", "[SEP]", "[PAD]", "[MASK]"],
|
||||
continuing_subword_prefix="##"
|
||||
)
|
||||
|
||||
tokenizer.train(files=["corpus.txt"], trainer=trainer)
|
||||
```
|
||||
|
||||
**优点**:
|
||||
- 优先进行有意义的合并(高分 = 语义相关)
|
||||
- 在 BERT 中取得了最优结果
|
||||
|
||||
**权衡**:
|
||||
- 若无子词匹配,未知词变为 `[UNK]`
|
||||
- 保存词表而非合并规则(文件较大)
|
||||
|
||||
### Unigram
|
||||
|
||||
**工作原理**:
|
||||
1. 从大词表(所有子串)开始
|
||||
2. 用当前词表计算语料损失
|
||||
3. 移除对损失影响最小的 token
|
||||
4. 重复直到达到词表大小
|
||||
|
||||
**使用者**:ALBERT、T5、mBART、XLNet(通过 SentencePiece)
|
||||
|
||||
```python
|
||||
from tokenizers import Tokenizer
|
||||
from tokenizers.models import Unigram
|
||||
from tokenizers.trainers import UnigramTrainer
|
||||
|
||||
tokenizer = Tokenizer(Unigram())
|
||||
|
||||
trainer = UnigramTrainer(
|
||||
vocab_size=8000,
|
||||
special_tokens=["<unk>", "<s>", "</s>"],
|
||||
unk_token="<unk>"
|
||||
)
|
||||
|
||||
tokenizer.train(files=["data.txt"], trainer=trainer)
|
||||
```
|
||||
|
||||
**优点**:
|
||||
- 概率化(找到最可能的分词方式)
|
||||
- 适合无词边界的语言
|
||||
- 能处理多样的语言学上下文
|
||||
|
||||
**权衡**:
|
||||
- 训练计算开销较大
|
||||
- 需要调整的超参数更多
|
||||
|
||||
## 分词流水线
|
||||
|
||||
完整流水线:**归一化 → 预分词 → 模型 → 后处理**
|
||||
|
||||
### 归一化(Normalization)
|
||||
|
||||
清洗并标准化文本:
|
||||
|
||||
```python
|
||||
from tokenizers.normalizers import NFD, StripAccents, Lowercase, Sequence
|
||||
|
||||
tokenizer.normalizer = Sequence([
|
||||
NFD(), # Unicode 归一化(分解)
|
||||
Lowercase(), # 转为小写
|
||||
StripAccents() # 去除重音符号
|
||||
])
|
||||
|
||||
# 输入:"Héllo WORLD"
|
||||
# 归一化后:"hello world"
|
||||
```
|
||||
|
||||
**常用归一化器**:
|
||||
- `NFD`, `NFC`, `NFKD`, `NFKC` — Unicode 归一化形式
|
||||
- `Lowercase()` — 转为小写
|
||||
- `StripAccents()` — 去除重音(é → e)
|
||||
- `Strip()` — 去除空白
|
||||
- `Replace(pattern, content)` — 正则替换
|
||||
|
||||
### 预分词(Pre-tokenization)
|
||||
|
||||
将文本拆分为类词单元:
|
||||
|
||||
```python
|
||||
from tokenizers.pre_tokenizers import Whitespace, Punctuation, Sequence, ByteLevel
|
||||
|
||||
# 按空白和标点拆分
|
||||
tokenizer.pre_tokenizer = Sequence([
|
||||
Whitespace(),
|
||||
Punctuation()
|
||||
])
|
||||
|
||||
# 输入:"Hello, world!"
|
||||
# 预分词后:["Hello", ",", "world", "!"]
|
||||
```
|
||||
|
||||
**常用预分词器**:
|
||||
- `Whitespace()` — 按空格、制表符、换行符拆分
|
||||
- `ByteLevel()` — GPT-2 风格的字节级拆分
|
||||
- `Punctuation()` — 隔离标点
|
||||
- `Digits(individual_digits=True)` — 逐个拆分数字
|
||||
- `Metaspace()` — 将空格替换为 ▁(SentencePiece 风格)
|
||||
|
||||
### 后处理(Post-processing)
|
||||
|
||||
为模型输入添加特殊 token:
|
||||
|
||||
```python
|
||||
from tokenizers.processors import TemplateProcessing
|
||||
|
||||
# BERT 风格:[CLS] sentence [SEP]
|
||||
tokenizer.post_processor = TemplateProcessing(
|
||||
single="[CLS] $A [SEP]",
|
||||
pair="[CLS] $A [SEP] $B [SEP]",
|
||||
special_tokens=[
|
||||
("[CLS]", 1),
|
||||
("[SEP]", 2),
|
||||
],
|
||||
)
|
||||
```
|
||||
|
||||
**常见模式**:
|
||||
```python
|
||||
# GPT-2:sentence <|endoftext|>
|
||||
TemplateProcessing(
|
||||
single="$A <|endoftext|>",
|
||||
special_tokens=[("<|endoftext|>", 50256)]
|
||||
)
|
||||
|
||||
# RoBERTa:<s> sentence </s>
|
||||
TemplateProcessing(
|
||||
single="<s> $A </s>",
|
||||
pair="<s> $A </s> </s> $B </s>",
|
||||
special_tokens=[("<s>", 0), ("</s>", 2)]
|
||||
)
|
||||
```
|
||||
|
||||
## 对齐追踪
|
||||
|
||||
追踪 token 在原始文本中的位置:
|
||||
|
||||
```python
|
||||
output = tokenizer.encode("Hello, world!")
|
||||
|
||||
# 获取 token 偏移量
|
||||
for token, offset in zip(output.tokens, output.offsets):
|
||||
start, end = offset
|
||||
print(f"{token:10} → [{start:2}, {end:2}): {text[start:end]!r}")
|
||||
|
||||
# 输出:
|
||||
# hello → [ 0, 5): 'Hello'
|
||||
# , → [ 5, 6): ','
|
||||
# world → [ 7, 12): 'world'
|
||||
# ! → [12, 13): '!'
|
||||
```
|
||||
|
||||
**使用场景**:
|
||||
- 命名实体识别(将预测结果映射回文本)
|
||||
- 问答(提取答案片段)
|
||||
- Token 分类(将标签对齐到原始位置)
|
||||
|
||||
## 与 transformers 集成
|
||||
|
||||
### 使用 AutoTokenizer 加载
|
||||
|
||||
```python
|
||||
from transformers import AutoTokenizer
|
||||
|
||||
# AutoTokenizer 自动使用快速 tokenizer
|
||||
tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased")
|
||||
|
||||
# 检查是否使用快速 tokenizer
|
||||
print(tokenizer.is_fast) # True
|
||||
|
||||
# 访问底层 tokenizers.Tokenizer
|
||||
fast_tokenizer = tokenizer.backend_tokenizer
|
||||
print(type(fast_tokenizer)) # <class 'tokenizers.Tokenizer'>
|
||||
```
|
||||
|
||||
### 将自定义 tokenizer 转换为 transformers 格式
|
||||
|
||||
```python
|
||||
from tokenizers import Tokenizer
|
||||
from transformers import PreTrainedTokenizerFast
|
||||
|
||||
# 训练自定义 tokenizer
|
||||
tokenizer = Tokenizer(BPE())
|
||||
# ... 训练 tokenizer ...
|
||||
tokenizer.save("my-tokenizer.json")
|
||||
|
||||
# 封装为 transformers 格式
|
||||
transformers_tokenizer = PreTrainedTokenizerFast(
|
||||
tokenizer_file="my-tokenizer.json",
|
||||
unk_token="[UNK]",
|
||||
pad_token="[PAD]",
|
||||
cls_token="[CLS]",
|
||||
sep_token="[SEP]",
|
||||
mask_token="[MASK]"
|
||||
)
|
||||
|
||||
# 像使用任何 transformers tokenizer 一样使用
|
||||
outputs = transformers_tokenizer(
|
||||
"Hello world",
|
||||
padding=True,
|
||||
truncation=True,
|
||||
max_length=512,
|
||||
return_tensors="pt"
|
||||
)
|
||||
```
|
||||
|
||||
## 常见模式
|
||||
|
||||
### 从迭代器训练(大型数据集)
|
||||
|
||||
```python
|
||||
from datasets import load_dataset
|
||||
|
||||
# 加载数据集
|
||||
dataset = load_dataset("wikitext", "wikitext-103-raw-v1", split="train")
|
||||
|
||||
# 创建批量迭代器
|
||||
def batch_iterator(batch_size=1000):
|
||||
for i in range(0, len(dataset), batch_size):
|
||||
yield dataset[i:i + batch_size]["text"]
|
||||
|
||||
# 训练 tokenizer
|
||||
tokenizer.train_from_iterator(
|
||||
batch_iterator(),
|
||||
trainer=trainer,
|
||||
length=len(dataset) # 用于进度条
|
||||
)
|
||||
```
|
||||
|
||||
**性能**:约 10–20 分钟处理 1GB
|
||||
|
||||
### 启用 truncation 和 padding
|
||||
|
||||
```python
|
||||
# 启用 truncation
|
||||
tokenizer.enable_truncation(max_length=512)
|
||||
|
||||
# 启用 padding
|
||||
tokenizer.enable_padding(
|
||||
pad_id=tokenizer.token_to_id("[PAD]"),
|
||||
pad_token="[PAD]",
|
||||
length=512 # 固定长度,或 None 表示批次最大长度
|
||||
)
|
||||
|
||||
# 同时编码
|
||||
output = tokenizer.encode("This is a long sentence that will be truncated...")
|
||||
print(len(output.ids)) # 512
|
||||
```
|
||||
|
||||
### 多进程处理
|
||||
|
||||
```python
|
||||
from tokenizers import Tokenizer
|
||||
from multiprocessing import Pool
|
||||
|
||||
# 加载 tokenizer
|
||||
tokenizer = Tokenizer.from_file("tokenizer.json")
|
||||
|
||||
def encode_batch(texts):
|
||||
return tokenizer.encode_batch(texts)
|
||||
|
||||
# 并行处理大型语料库
|
||||
with Pool(8) as pool:
|
||||
# 将语料库拆分为块
|
||||
chunk_size = 1000
|
||||
chunks = [corpus[i:i+chunk_size] for i in range(0, len(corpus), chunk_size)]
|
||||
|
||||
# 并行编码
|
||||
results = pool.map(encode_batch, chunks)
|
||||
```
|
||||
|
||||
**加速比**:8 核下约 5–8 倍
|
||||
|
||||
## 性能基准
|
||||
|
||||
### 训练速度
|
||||
|
||||
| 语料大小 | BPE(30k 词表) | WordPiece(30k) | Unigram(8k) |
|
||||
|----------|----------------|-----------------|--------------|
|
||||
| 10 MB | 15 秒 | 18 秒 | 25 秒 |
|
||||
| 100 MB | 1.5 分钟 | 2 分钟 | 4 分钟 |
|
||||
| 1 GB | 15 分钟 | 20 分钟 | 40 分钟 |
|
||||
|
||||
**硬件**:16 核 CPU,在英文 Wikipedia 上测试
|
||||
|
||||
### 分词速度
|
||||
|
||||
| 实现方式 | 1 GB 语料 | 吞吐量 |
|
||||
|----------------|-------------|--------------|
|
||||
| 纯 Python | ~20 分钟 | ~50 MB/分钟 |
|
||||
| HF Tokenizers | ~15 秒 | ~4 GB/分钟 |
|
||||
| **加速比** | **80×** | **80×** |
|
||||
|
||||
**测试**:英文文本,平均句长 20 词
|
||||
|
||||
### 内存占用
|
||||
|
||||
| 任务 | 内存 |
|
||||
|-------------------------|---------|
|
||||
| 加载 tokenizer | ~10 MB |
|
||||
| 训练 BPE(30k 词表) | ~200 MB |
|
||||
| 编码 100 万句 | ~500 MB |
|
||||
|
||||
## 支持的模型
|
||||
|
||||
可通过 `from_pretrained()` 获取的预训练 tokenizer:
|
||||
|
||||
**BERT 系列**:
|
||||
- `bert-base-uncased`, `bert-large-cased`
|
||||
- `distilbert-base-uncased`
|
||||
- `roberta-base`, `roberta-large`
|
||||
|
||||
**GPT 系列**:
|
||||
- `gpt2`, `gpt2-medium`, `gpt2-large`
|
||||
- `distilgpt2`
|
||||
|
||||
**T5 系列**:
|
||||
- `t5-small`, `t5-base`, `t5-large`
|
||||
- `google/flan-t5-xxl`
|
||||
|
||||
**其他**:
|
||||
- `facebook/bart-base`, `facebook/mbart-large-cc25`
|
||||
- `albert-base-v2`, `albert-xlarge-v2`
|
||||
- `xlm-roberta-base`, `xlm-roberta-large`
|
||||
|
||||
浏览全部:https://huggingface.co/models?library=tokenizers
|
||||
|
||||
## 参考资料
|
||||
|
||||
- **[训练指南](https://github.com/NousResearch/hermes-agent/blob/main/optional-skills/mlops/huggingface-tokenizers/references/training.md)** — 训练自定义 tokenizer、配置训练器、处理大型数据集
|
||||
- **[算法深度解析](https://github.com/NousResearch/hermes-agent/blob/main/optional-skills/mlops/huggingface-tokenizers/references/algorithms.md)** — BPE、WordPiece、Unigram 详细说明
|
||||
- **[流水线组件](https://github.com/NousResearch/hermes-agent/blob/main/optional-skills/mlops/huggingface-tokenizers/references/pipeline.md)** — 归一化器、预分词器、后处理器、解码器
|
||||
- **[Transformers 集成](https://github.com/NousResearch/hermes-agent/blob/main/optional-skills/mlops/huggingface-tokenizers/references/integration.md)** — AutoTokenizer、PreTrainedTokenizerFast、特殊 token
|
||||
|
||||
## 资源
|
||||
|
||||
- **文档**:https://huggingface.co/docs/tokenizers
|
||||
- **GitHub**:https://github.com/huggingface/tokenizers ⭐ 9,000+
|
||||
- **版本**:0.20.0+
|
||||
- **课程**:https://huggingface.co/learn/nlp-course/chapter6/1
|
||||
- **论文**:BPE(Sennrich et al., 2016)、WordPiece(Schuster & Nakajima, 2012)
|
||||
+671
@@ -0,0 +1,671 @@
|
||||
---
|
||||
title: "Outlines — Outlines:结构化 JSON/regex/Pydantic LLM 生成"
|
||||
sidebar_label: "Outlines"
|
||||
description: "Outlines:结构化 JSON/regex/Pydantic LLM 生成"
|
||||
---
|
||||
|
||||
{/* This page is auto-generated from the skill's SKILL.md by website/scripts/generate-skill-docs.py. Edit the source SKILL.md, not this page. */}
|
||||
|
||||
# Outlines
|
||||
|
||||
Outlines:结构化 JSON/regex/Pydantic LLM 生成。
|
||||
|
||||
## Skill 元数据
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| 来源 | 可选 — 使用 `hermes skills install official/mlops/outlines` 安装 |
|
||||
| 路径 | `optional-skills/mlops/inference/outlines` |
|
||||
| 版本 | `1.0.0` |
|
||||
| 作者 | Orchestra Research |
|
||||
| 许可证 | MIT |
|
||||
| 依赖项 | `outlines`, `transformers`, `vllm`, `pydantic` |
|
||||
| 平台 | linux, macos, windows |
|
||||
| 标签 | `Prompt Engineering`, `Outlines`, `Structured Generation`, `JSON Schema`, `Pydantic`, `Local Models`, `Grammar-Based Generation`, `vLLM`, `Transformers`, `Type Safety` |
|
||||
|
||||
## 参考:完整 SKILL.md
|
||||
|
||||
:::info
|
||||
以下是 Hermes 在触发此 skill 时加载的完整 skill 定义。这是 agent 在 skill 激活时看到的指令内容。
|
||||
:::
|
||||
|
||||
# Outlines:结构化文本生成
|
||||
|
||||
## 何时使用此 Skill
|
||||
|
||||
在以下情况下使用 Outlines:
|
||||
- **保证有效的 JSON/XML/代码**结构化生成
|
||||
- **使用 Pydantic 模型**获得类型安全的输出
|
||||
- **支持本地模型**(Transformers、llama.cpp、vLLM)
|
||||
- **通过零开销结构化生成最大化推理速度**
|
||||
- **自动根据 JSON schema 生成**
|
||||
- **在 grammar(语法)层面控制 token 采样**
|
||||
|
||||
**GitHub Stars**:8,000+ | **来自**:dottxt.ai(前身为 .txt)
|
||||
|
||||
## 安装
|
||||
|
||||
```bash
|
||||
# 基础安装
|
||||
pip install outlines
|
||||
|
||||
# 安装特定后端
|
||||
pip install outlines transformers # Hugging Face 模型
|
||||
pip install outlines llama-cpp-python # llama.cpp
|
||||
pip install outlines vllm # vLLM 用于高吞吐量
|
||||
```
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 基础示例:分类
|
||||
|
||||
```python
|
||||
import outlines
|
||||
from typing import Literal
|
||||
|
||||
# 加载模型
|
||||
model = outlines.models.transformers("microsoft/Phi-3-mini-4k-instruct")
|
||||
|
||||
# 带类型约束的生成
|
||||
prompt = "Sentiment of 'This product is amazing!': "
|
||||
generator = outlines.generate.choice(model, ["positive", "negative", "neutral"])
|
||||
sentiment = generator(prompt)
|
||||
|
||||
print(sentiment) # "positive"(保证为其中之一)
|
||||
```
|
||||
|
||||
### 使用 Pydantic 模型
|
||||
|
||||
```python
|
||||
from pydantic import BaseModel
|
||||
import outlines
|
||||
|
||||
class User(BaseModel):
|
||||
name: str
|
||||
age: int
|
||||
email: str
|
||||
|
||||
model = outlines.models.transformers("microsoft/Phi-3-mini-4k-instruct")
|
||||
|
||||
# 生成结构化输出
|
||||
prompt = "Extract user: John Doe, 30 years old, john@example.com"
|
||||
generator = outlines.generate.json(model, User)
|
||||
user = generator(prompt)
|
||||
|
||||
print(user.name) # "John Doe"
|
||||
print(user.age) # 30
|
||||
print(user.email) # "john@example.com"
|
||||
```
|
||||
|
||||
## 核心概念
|
||||
|
||||
### 1. 受约束的 Token 采样
|
||||
|
||||
Outlines 使用有限状态机(FSM)在 logit 层面约束 token 生成。
|
||||
|
||||
**工作原理:**
|
||||
1. 将 schema(JSON/Pydantic/regex)转换为上下文无关文法(CFG)
|
||||
2. 将 CFG 转换为有限状态机(FSM)
|
||||
3. 在生成的每一步过滤无效 token
|
||||
4. 当只有一个有效 token 时快速前进
|
||||
|
||||
**优势:**
|
||||
- **零开销**:过滤在 token 层面进行
|
||||
- **速度提升**:通过确定性路径快速前进
|
||||
- **保证有效性**:无效输出不可能产生
|
||||
|
||||
```python
|
||||
import outlines
|
||||
|
||||
# Pydantic 模型 -> JSON schema -> CFG -> FSM
|
||||
class Person(BaseModel):
|
||||
name: str
|
||||
age: int
|
||||
|
||||
model = outlines.models.transformers("microsoft/Phi-3-mini-4k-instruct")
|
||||
|
||||
# 底层流程:
|
||||
# 1. Person -> JSON schema
|
||||
# 2. JSON schema -> CFG
|
||||
# 3. CFG -> FSM
|
||||
# 4. FSM 在生成过程中过滤 token
|
||||
|
||||
generator = outlines.generate.json(model, Person)
|
||||
result = generator("Generate person: Alice, 25")
|
||||
```
|
||||
|
||||
### 2. 结构化生成器
|
||||
|
||||
Outlines 为不同输出类型提供专用生成器。
|
||||
|
||||
#### Choice 生成器
|
||||
|
||||
```python
|
||||
# 多项选择
|
||||
generator = outlines.generate.choice(
|
||||
model,
|
||||
["positive", "negative", "neutral"]
|
||||
)
|
||||
|
||||
sentiment = generator("Review: This is great!")
|
||||
# 结果:三个选项之一
|
||||
```
|
||||
|
||||
#### JSON 生成器
|
||||
|
||||
```python
|
||||
from pydantic import BaseModel
|
||||
|
||||
class Product(BaseModel):
|
||||
name: str
|
||||
price: float
|
||||
in_stock: bool
|
||||
|
||||
# 生成符合 schema 的有效 JSON
|
||||
generator = outlines.generate.json(model, Product)
|
||||
product = generator("Extract: iPhone 15, $999, available")
|
||||
|
||||
# 保证为有效的 Product 实例
|
||||
print(type(product)) # <class '__main__.Product'>
|
||||
```
|
||||
|
||||
#### Regex 生成器
|
||||
|
||||
```python
|
||||
# 生成匹配 regex 的文本
|
||||
generator = outlines.generate.regex(
|
||||
model,
|
||||
r"[0-9]{3}-[0-9]{3}-[0-9]{4}" # 电话号码模式
|
||||
)
|
||||
|
||||
phone = generator("Generate phone number:")
|
||||
# 结果:"555-123-4567"(保证匹配模式)
|
||||
```
|
||||
|
||||
#### 整数/浮点数生成器
|
||||
|
||||
```python
|
||||
# 生成特定数值类型
|
||||
int_generator = outlines.generate.integer(model)
|
||||
age = int_generator("Person's age:") # 保证为整数
|
||||
|
||||
float_generator = outlines.generate.float(model)
|
||||
price = float_generator("Product price:") # 保证为浮点数
|
||||
```
|
||||
|
||||
### 3. 模型后端
|
||||
|
||||
Outlines 支持多种本地及基于 API 的后端。
|
||||
|
||||
#### Transformers(Hugging Face)
|
||||
|
||||
```python
|
||||
import outlines
|
||||
|
||||
# 从 Hugging Face 加载
|
||||
model = outlines.models.transformers(
|
||||
"microsoft/Phi-3-mini-4k-instruct",
|
||||
device="cuda" # 或 "cpu"
|
||||
)
|
||||
|
||||
# 与任意生成器配合使用
|
||||
generator = outlines.generate.json(model, YourModel)
|
||||
```
|
||||
|
||||
#### llama.cpp
|
||||
|
||||
```python
|
||||
# 加载 GGUF 模型
|
||||
model = outlines.models.llamacpp(
|
||||
"./models/llama-3.1-8b-instruct.Q4_K_M.gguf",
|
||||
n_gpu_layers=35
|
||||
)
|
||||
|
||||
generator = outlines.generate.json(model, YourModel)
|
||||
```
|
||||
|
||||
#### vLLM(高吞吐量)
|
||||
|
||||
```python
|
||||
# 用于生产部署
|
||||
model = outlines.models.vllm(
|
||||
"meta-llama/Llama-3.1-8B-Instruct",
|
||||
tensor_parallel_size=2 # 多 GPU
|
||||
)
|
||||
|
||||
generator = outlines.generate.json(model, YourModel)
|
||||
```
|
||||
|
||||
#### OpenAI(有限支持)
|
||||
|
||||
```python
|
||||
# 基础 OpenAI 支持
|
||||
model = outlines.models.openai(
|
||||
"gpt-4o-mini",
|
||||
api_key="your-api-key"
|
||||
)
|
||||
|
||||
# 注意:API 模型部分功能受限
|
||||
generator = outlines.generate.json(model, YourModel)
|
||||
```
|
||||
|
||||
### 4. Pydantic 集成
|
||||
|
||||
Outlines 对 Pydantic 提供一流支持,可自动进行 schema 转换。
|
||||
|
||||
#### 基础模型
|
||||
|
||||
```python
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
class Article(BaseModel):
|
||||
title: str = Field(description="Article title")
|
||||
author: str = Field(description="Author name")
|
||||
word_count: int = Field(description="Number of words", gt=0)
|
||||
tags: list[str] = Field(description="List of tags")
|
||||
|
||||
model = outlines.models.transformers("microsoft/Phi-3-mini-4k-instruct")
|
||||
generator = outlines.generate.json(model, Article)
|
||||
|
||||
article = generator("Generate article about AI")
|
||||
print(article.title)
|
||||
print(article.word_count) # 保证 > 0
|
||||
```
|
||||
|
||||
#### 嵌套模型
|
||||
|
||||
```python
|
||||
class Address(BaseModel):
|
||||
street: str
|
||||
city: str
|
||||
country: str
|
||||
|
||||
class Person(BaseModel):
|
||||
name: str
|
||||
age: int
|
||||
address: Address # 嵌套模型
|
||||
|
||||
generator = outlines.generate.json(model, Person)
|
||||
person = generator("Generate person in New York")
|
||||
|
||||
print(person.address.city) # "New York"
|
||||
```
|
||||
|
||||
#### Enum 与 Literal
|
||||
|
||||
```python
|
||||
from enum import Enum
|
||||
from typing import Literal
|
||||
|
||||
class Status(str, Enum):
|
||||
PENDING = "pending"
|
||||
APPROVED = "approved"
|
||||
REJECTED = "rejected"
|
||||
|
||||
class Application(BaseModel):
|
||||
applicant: str
|
||||
status: Status # 必须为枚举值之一
|
||||
priority: Literal["low", "medium", "high"] # 必须为 literal 之一
|
||||
|
||||
generator = outlines.generate.json(model, Application)
|
||||
app = generator("Generate application")
|
||||
|
||||
print(app.status) # Status.PENDING(或 APPROVED/REJECTED)
|
||||
```
|
||||
|
||||
## 常见模式
|
||||
|
||||
### 模式 1:数据提取
|
||||
|
||||
```python
|
||||
from pydantic import BaseModel
|
||||
import outlines
|
||||
|
||||
class CompanyInfo(BaseModel):
|
||||
name: str
|
||||
founded_year: int
|
||||
industry: str
|
||||
employees: int
|
||||
|
||||
model = outlines.models.transformers("microsoft/Phi-3-mini-4k-instruct")
|
||||
generator = outlines.generate.json(model, CompanyInfo)
|
||||
|
||||
text = """
|
||||
Apple Inc. was founded in 1976 in the technology industry.
|
||||
The company employs approximately 164,000 people worldwide.
|
||||
"""
|
||||
|
||||
prompt = f"Extract company information:\n{text}\n\nCompany:"
|
||||
company = generator(prompt)
|
||||
|
||||
print(f"Name: {company.name}")
|
||||
print(f"Founded: {company.founded_year}")
|
||||
print(f"Industry: {company.industry}")
|
||||
print(f"Employees: {company.employees}")
|
||||
```
|
||||
|
||||
### 模式 2:分类
|
||||
|
||||
```python
|
||||
from typing import Literal
|
||||
import outlines
|
||||
|
||||
model = outlines.models.transformers("microsoft/Phi-3-mini-4k-instruct")
|
||||
|
||||
# 二分类
|
||||
generator = outlines.generate.choice(model, ["spam", "not_spam"])
|
||||
result = generator("Email: Buy now! 50% off!")
|
||||
|
||||
# 多分类
|
||||
categories = ["technology", "business", "sports", "entertainment"]
|
||||
category_gen = outlines.generate.choice(model, categories)
|
||||
category = category_gen("Article: Apple announces new iPhone...")
|
||||
|
||||
# 带置信度
|
||||
class Classification(BaseModel):
|
||||
label: Literal["positive", "negative", "neutral"]
|
||||
confidence: float
|
||||
|
||||
classifier = outlines.generate.json(model, Classification)
|
||||
result = classifier("Review: This product is okay, nothing special")
|
||||
```
|
||||
|
||||
### 模式 3:结构化表单
|
||||
|
||||
```python
|
||||
class UserProfile(BaseModel):
|
||||
full_name: str
|
||||
age: int
|
||||
email: str
|
||||
phone: str
|
||||
country: str
|
||||
interests: list[str]
|
||||
|
||||
model = outlines.models.transformers("microsoft/Phi-3-mini-4k-instruct")
|
||||
generator = outlines.generate.json(model, UserProfile)
|
||||
|
||||
prompt = """
|
||||
Extract user profile from:
|
||||
Name: Alice Johnson
|
||||
Age: 28
|
||||
Email: alice@example.com
|
||||
Phone: 555-0123
|
||||
Country: USA
|
||||
Interests: hiking, photography, cooking
|
||||
"""
|
||||
|
||||
profile = generator(prompt)
|
||||
print(profile.full_name)
|
||||
print(profile.interests) # ["hiking", "photography", "cooking"]
|
||||
```
|
||||
|
||||
### 模式 4:多实体提取
|
||||
|
||||
```python
|
||||
class Entity(BaseModel):
|
||||
name: str
|
||||
type: Literal["PERSON", "ORGANIZATION", "LOCATION"]
|
||||
|
||||
class DocumentEntities(BaseModel):
|
||||
entities: list[Entity]
|
||||
|
||||
model = outlines.models.transformers("microsoft/Phi-3-mini-4k-instruct")
|
||||
generator = outlines.generate.json(model, DocumentEntities)
|
||||
|
||||
text = "Tim Cook met with Satya Nadella at Microsoft headquarters in Redmond."
|
||||
prompt = f"Extract entities from: {text}"
|
||||
|
||||
result = generator(prompt)
|
||||
for entity in result.entities:
|
||||
print(f"{entity.name} ({entity.type})")
|
||||
```
|
||||
|
||||
### 模式 5:代码生成
|
||||
|
||||
```python
|
||||
class PythonFunction(BaseModel):
|
||||
function_name: str
|
||||
parameters: list[str]
|
||||
docstring: str
|
||||
body: str
|
||||
|
||||
model = outlines.models.transformers("microsoft/Phi-3-mini-4k-instruct")
|
||||
generator = outlines.generate.json(model, PythonFunction)
|
||||
|
||||
prompt = "Generate a Python function to calculate factorial"
|
||||
func = generator(prompt)
|
||||
|
||||
print(f"def {func.function_name}({', '.join(func.parameters)}):")
|
||||
print(f' """{func.docstring}"""')
|
||||
print(f" {func.body}")
|
||||
```
|
||||
|
||||
### 模式 6:批量处理
|
||||
|
||||
```python
|
||||
def batch_extract(texts: list[str], schema: type[BaseModel]):
|
||||
"""从多段文本中提取结构化数据。"""
|
||||
model = outlines.models.transformers("microsoft/Phi-3-mini-4k-instruct")
|
||||
generator = outlines.generate.json(model, schema)
|
||||
|
||||
results = []
|
||||
for text in texts:
|
||||
result = generator(f"Extract from: {text}")
|
||||
results.append(result)
|
||||
|
||||
return results
|
||||
|
||||
class Person(BaseModel):
|
||||
name: str
|
||||
age: int
|
||||
|
||||
texts = [
|
||||
"John is 30 years old",
|
||||
"Alice is 25 years old",
|
||||
"Bob is 40 years old"
|
||||
]
|
||||
|
||||
people = batch_extract(texts, Person)
|
||||
for person in people:
|
||||
print(f"{person.name}: {person.age}")
|
||||
```
|
||||
|
||||
## 后端配置
|
||||
|
||||
### Transformers
|
||||
|
||||
```python
|
||||
import outlines
|
||||
|
||||
# 基础用法
|
||||
model = outlines.models.transformers("microsoft/Phi-3-mini-4k-instruct")
|
||||
|
||||
# GPU 配置
|
||||
model = outlines.models.transformers(
|
||||
"microsoft/Phi-3-mini-4k-instruct",
|
||||
device="cuda",
|
||||
model_kwargs={"torch_dtype": "float16"}
|
||||
)
|
||||
|
||||
# 常用模型
|
||||
model = outlines.models.transformers("meta-llama/Llama-3.1-8B-Instruct")
|
||||
model = outlines.models.transformers("mistralai/Mistral-7B-Instruct-v0.3")
|
||||
model = outlines.models.transformers("Qwen/Qwen2.5-7B-Instruct")
|
||||
```
|
||||
|
||||
### llama.cpp
|
||||
|
||||
```python
|
||||
# 加载 GGUF 模型
|
||||
model = outlines.models.llamacpp(
|
||||
"./models/llama-3.1-8b.Q4_K_M.gguf",
|
||||
n_ctx=4096, # 上下文窗口
|
||||
n_gpu_layers=35, # GPU 层数
|
||||
n_threads=8 # CPU 线程数
|
||||
)
|
||||
|
||||
# 完全 GPU 卸载
|
||||
model = outlines.models.llamacpp(
|
||||
"./models/model.gguf",
|
||||
n_gpu_layers=-1 # 所有层在 GPU 上
|
||||
)
|
||||
```
|
||||
|
||||
### vLLM(生产环境)
|
||||
|
||||
```python
|
||||
# 单 GPU
|
||||
model = outlines.models.vllm("meta-llama/Llama-3.1-8B-Instruct")
|
||||
|
||||
# 多 GPU
|
||||
model = outlines.models.vllm(
|
||||
"meta-llama/Llama-3.1-70B-Instruct",
|
||||
tensor_parallel_size=4 # 4 块 GPU
|
||||
)
|
||||
|
||||
# 带量化
|
||||
model = outlines.models.vllm(
|
||||
"meta-llama/Llama-3.1-8B-Instruct",
|
||||
quantization="awq" # 或 "gptq"
|
||||
)
|
||||
```
|
||||
|
||||
## 最佳实践
|
||||
|
||||
### 1. 使用具体类型
|
||||
|
||||
```python
|
||||
# ✅ 好:具体类型
|
||||
class Product(BaseModel):
|
||||
name: str
|
||||
price: float # 非 str
|
||||
quantity: int # 非 str
|
||||
in_stock: bool # 非 str
|
||||
|
||||
# ❌ 差:全部用字符串
|
||||
class Product(BaseModel):
|
||||
name: str
|
||||
price: str # 应为 float
|
||||
quantity: str # 应为 int
|
||||
```
|
||||
|
||||
### 2. 添加约束
|
||||
|
||||
```python
|
||||
from pydantic import Field
|
||||
|
||||
# ✅ 好:带约束
|
||||
class User(BaseModel):
|
||||
name: str = Field(min_length=1, max_length=100)
|
||||
age: int = Field(ge=0, le=120)
|
||||
email: str = Field(pattern=r"^[\w\.-]+@[\w\.-]+\.\w+$")
|
||||
|
||||
# ❌ 差:无约束
|
||||
class User(BaseModel):
|
||||
name: str
|
||||
age: int
|
||||
email: str
|
||||
```
|
||||
|
||||
### 3. 对分类使用 Enum
|
||||
|
||||
```python
|
||||
# ✅ 好:固定集合使用 Enum
|
||||
class Priority(str, Enum):
|
||||
LOW = "low"
|
||||
MEDIUM = "medium"
|
||||
HIGH = "high"
|
||||
|
||||
class Task(BaseModel):
|
||||
title: str
|
||||
priority: Priority
|
||||
|
||||
# ❌ 差:自由格式字符串
|
||||
class Task(BaseModel):
|
||||
title: str
|
||||
priority: str # 可以是任意值
|
||||
```
|
||||
|
||||
### 4. 在 Prompt 中提供上下文
|
||||
|
||||
```python
|
||||
# ✅ 好:清晰的上下文
|
||||
prompt = """
|
||||
Extract product information from the following text.
|
||||
Text: iPhone 15 Pro costs $999 and is currently in stock.
|
||||
Product:
|
||||
"""
|
||||
|
||||
# ❌ 差:上下文不足
|
||||
prompt = "iPhone 15 Pro costs $999 and is currently in stock."
|
||||
```
|
||||
|
||||
### 5. 处理可选字段
|
||||
|
||||
```python
|
||||
from typing import Optional
|
||||
|
||||
# ✅ 好:对不完整数据使用可选字段
|
||||
class Article(BaseModel):
|
||||
title: str # 必填
|
||||
author: Optional[str] = None # 可选
|
||||
date: Optional[str] = None # 可选
|
||||
tags: list[str] = [] # 默认空列表
|
||||
|
||||
# 即使 author/date 缺失也能成功
|
||||
```
|
||||
|
||||
## 与替代方案的对比
|
||||
|
||||
| 特性 | Outlines | Instructor | Guidance | LMQL |
|
||||
|---------|----------|------------|----------|------|
|
||||
| Pydantic 支持 | ✅ 原生 | ✅ 原生 | ❌ 无 | ❌ 无 |
|
||||
| JSON Schema | ✅ 支持 | ✅ 支持 | ⚠️ 有限 | ✅ 支持 |
|
||||
| Regex 约束 | ✅ 支持 | ❌ 无 | ✅ 支持 | ✅ 支持 |
|
||||
| 本地模型 | ✅ 完整 | ⚠️ 有限 | ✅ 完整 | ✅ 完整 |
|
||||
| API 模型 | ⚠️ 有限 | ✅ 完整 | ✅ 完整 | ✅ 完整 |
|
||||
| 零开销 | ✅ 支持 | ❌ 无 | ⚠️ 部分 | ✅ 支持 |
|
||||
| 自动重试 | ❌ 无 | ✅ 支持 | ❌ 无 | ❌ 无 |
|
||||
| 学习曲线 | 低 | 低 | 低 | 高 |
|
||||
|
||||
**何时选择 Outlines:**
|
||||
- 使用本地模型(Transformers、llama.cpp、vLLM)
|
||||
- 需要最大推理速度
|
||||
- 需要 Pydantic 模型支持
|
||||
- 需要零开销结构化生成
|
||||
- 需要控制 token 采样过程
|
||||
|
||||
**何时选择替代方案:**
|
||||
- Instructor:需要 API 模型并支持自动重试
|
||||
- Guidance:需要 token healing 和复杂工作流
|
||||
- LMQL:偏好声明式查询语法
|
||||
|
||||
## 性能特性
|
||||
|
||||
**速度:**
|
||||
- **零开销**:结构化生成与无约束生成同样快速
|
||||
- **快速前进优化**:跳过确定性 token
|
||||
- **比生成后验证方案快 1.2–2 倍**
|
||||
|
||||
**内存:**
|
||||
- FSM 每个 schema 编译一次(已缓存)
|
||||
- 极低的运行时开销
|
||||
- 配合 vLLM 可实现高吞吐量
|
||||
|
||||
**准确性:**
|
||||
- **100% 有效输出**(由 FSM 保证)
|
||||
- 无需重试循环
|
||||
- 确定性 token 过滤
|
||||
|
||||
## 资源
|
||||
|
||||
- **文档**:https://outlines-dev.github.io/outlines
|
||||
- **GitHub**:https://github.com/outlines-dev/outlines(8k+ stars)
|
||||
- **Discord**:https://discord.gg/R9DSu34mGd
|
||||
- **博客**:https://blog.dottxt.co
|
||||
|
||||
## 另请参阅
|
||||
|
||||
- `references/json_generation.md` — 全面的 JSON 与 Pydantic 模式
|
||||
- `references/backends.md` — 后端专项配置
|
||||
- `references/examples.md` — 生产就绪示例
|
||||
+759
@@ -0,0 +1,759 @@
|
||||
---
|
||||
title: "Instructor"
|
||||
sidebar_label: "Instructor"
|
||||
description: "使用 Pydantic 验证从 LLM 响应中提取结构化数据,自动重试失败的提取,以类型安全方式解析复杂 JSON,并使用 Instructor 流式传输部分结果——经过实战检验的结构化输出库"
|
||||
---
|
||||
|
||||
{/* This page is auto-generated from the skill's SKILL.md by website/scripts/generate-skill-docs.py. Edit the source SKILL.md, not this page. */}
|
||||
|
||||
# Instructor
|
||||
|
||||
使用 Pydantic 验证从 LLM 响应中提取结构化数据,自动重试失败的提取,以类型安全方式解析复杂 JSON,并使用 Instructor 流式传输部分结果——经过实战检验的结构化输出库
|
||||
|
||||
## Skill 元数据
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| 来源 | 可选 — 通过 `hermes skills install official/mlops/instructor` 安装 |
|
||||
| 路径 | `optional-skills/mlops/instructor` |
|
||||
| 版本 | `1.0.0` |
|
||||
| 作者 | Orchestra Research |
|
||||
| 许可证 | MIT |
|
||||
| 依赖项 | `instructor`, `pydantic`, `openai`, `anthropic` |
|
||||
| 平台 | linux, macos, windows |
|
||||
| 标签 | `Prompt Engineering`, `Instructor`, `Structured Output`, `Pydantic`, `Data Extraction`, `JSON Parsing`, `Type Safety`, `Validation`, `Streaming`, `OpenAI`, `Anthropic` |
|
||||
|
||||
## 参考:完整 SKILL.md
|
||||
|
||||
:::info
|
||||
以下是 Hermes 在触发此 skill 时加载的完整 skill 定义。这是 skill 激活时 agent 所看到的指令内容。
|
||||
:::
|
||||
|
||||
# Instructor:结构化 LLM 输出
|
||||
|
||||
## 何时使用此 Skill
|
||||
|
||||
在以下情况下使用 Instructor:
|
||||
- **从 LLM 响应中可靠地提取结构化数据**
|
||||
- **根据 Pydantic schema 自动验证输出**
|
||||
- **通过自动错误处理重试失败的提取**
|
||||
- **以类型安全和验证方式解析复杂 JSON**
|
||||
- **流式传输部分结果**以进行实时处理
|
||||
- **以一致的 API 支持多个 LLM 提供商**
|
||||
|
||||
**GitHub Stars**:15,000+|**实战检验**:100,000+ 开发者
|
||||
|
||||
## 安装
|
||||
|
||||
```bash
|
||||
# 基础安装
|
||||
pip install instructor
|
||||
|
||||
# 指定提供商
|
||||
pip install "instructor[anthropic]" # Anthropic Claude
|
||||
pip install "instructor[openai]" # OpenAI
|
||||
pip install "instructor[all]" # 所有提供商
|
||||
```
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 基础示例:提取用户数据
|
||||
|
||||
```python
|
||||
import instructor
|
||||
from pydantic import BaseModel
|
||||
from anthropic import Anthropic
|
||||
|
||||
# Define output structure
|
||||
class User(BaseModel):
|
||||
name: str
|
||||
age: int
|
||||
email: str
|
||||
|
||||
# Create instructor client
|
||||
client = instructor.from_anthropic(Anthropic())
|
||||
|
||||
# Extract structured data
|
||||
user = client.messages.create(
|
||||
model="claude-sonnet-4-5-20250929",
|
||||
max_tokens=1024,
|
||||
messages=[{
|
||||
"role": "user",
|
||||
"content": "John Doe is 30 years old. His email is john@example.com"
|
||||
}],
|
||||
response_model=User
|
||||
)
|
||||
|
||||
print(user.name) # "John Doe"
|
||||
print(user.age) # 30
|
||||
print(user.email) # "john@example.com"
|
||||
```
|
||||
|
||||
### 使用 OpenAI
|
||||
|
||||
```python
|
||||
from openai import OpenAI
|
||||
|
||||
client = instructor.from_openai(OpenAI())
|
||||
|
||||
user = client.chat.completions.create(
|
||||
model="gpt-4o-mini",
|
||||
response_model=User,
|
||||
messages=[{"role": "user", "content": "Extract: Alice, 25, alice@email.com"}]
|
||||
)
|
||||
```
|
||||
|
||||
## 核心概念
|
||||
|
||||
### 1. 响应模型(Pydantic)
|
||||
|
||||
响应模型定义 LLM 输出的结构和验证规则。
|
||||
|
||||
#### 基础模型
|
||||
|
||||
```python
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
class Article(BaseModel):
|
||||
title: str = Field(description="Article title")
|
||||
author: str = Field(description="Author name")
|
||||
word_count: int = Field(description="Number of words", gt=0)
|
||||
tags: list[str] = Field(description="List of relevant tags")
|
||||
|
||||
article = client.messages.create(
|
||||
model="claude-sonnet-4-5-20250929",
|
||||
max_tokens=1024,
|
||||
messages=[{
|
||||
"role": "user",
|
||||
"content": "Analyze this article: [article text]"
|
||||
}],
|
||||
response_model=Article
|
||||
)
|
||||
```
|
||||
|
||||
**优势:**
|
||||
- 使用 Python 类型提示保证类型安全
|
||||
- 自动验证(word_count > 0)
|
||||
- 通过 Field 描述实现自文档化
|
||||
- IDE 自动补全支持
|
||||
|
||||
#### 嵌套模型
|
||||
|
||||
```python
|
||||
class Address(BaseModel):
|
||||
street: str
|
||||
city: str
|
||||
country: str
|
||||
|
||||
class Person(BaseModel):
|
||||
name: str
|
||||
age: int
|
||||
address: Address # Nested model
|
||||
|
||||
person = client.messages.create(
|
||||
model="claude-sonnet-4-5-20250929",
|
||||
max_tokens=1024,
|
||||
messages=[{
|
||||
"role": "user",
|
||||
"content": "John lives at 123 Main St, Boston, USA"
|
||||
}],
|
||||
response_model=Person
|
||||
)
|
||||
|
||||
print(person.address.city) # "Boston"
|
||||
```
|
||||
|
||||
#### 可选字段
|
||||
|
||||
```python
|
||||
from typing import Optional
|
||||
|
||||
class Product(BaseModel):
|
||||
name: str
|
||||
price: float
|
||||
discount: Optional[float] = None # Optional
|
||||
description: str = Field(default="No description") # Default value
|
||||
|
||||
# LLM doesn't need to provide discount or description
|
||||
```
|
||||
|
||||
#### 使用枚举约束值
|
||||
|
||||
```python
|
||||
from enum import Enum
|
||||
|
||||
class Sentiment(str, Enum):
|
||||
POSITIVE = "positive"
|
||||
NEGATIVE = "negative"
|
||||
NEUTRAL = "neutral"
|
||||
|
||||
class Review(BaseModel):
|
||||
text: str
|
||||
sentiment: Sentiment # Only these 3 values allowed
|
||||
|
||||
review = client.messages.create(
|
||||
model="claude-sonnet-4-5-20250929",
|
||||
max_tokens=1024,
|
||||
messages=[{
|
||||
"role": "user",
|
||||
"content": "This product is amazing!"
|
||||
}],
|
||||
response_model=Review
|
||||
)
|
||||
|
||||
print(review.sentiment) # Sentiment.POSITIVE
|
||||
```
|
||||
|
||||
### 2. 验证
|
||||
|
||||
Pydantic 自动验证 LLM 输出。若验证失败,Instructor 会自动重试。
|
||||
|
||||
#### 内置验证器
|
||||
|
||||
```python
|
||||
from pydantic import Field, EmailStr, HttpUrl
|
||||
|
||||
class Contact(BaseModel):
|
||||
name: str = Field(min_length=2, max_length=100)
|
||||
age: int = Field(ge=0, le=120) # 0 <= age <= 120
|
||||
email: EmailStr # Validates email format
|
||||
website: HttpUrl # Validates URL format
|
||||
|
||||
# If LLM provides invalid data, Instructor retries automatically
|
||||
```
|
||||
|
||||
#### 自定义验证器
|
||||
|
||||
```python
|
||||
from pydantic import field_validator
|
||||
|
||||
class Event(BaseModel):
|
||||
name: str
|
||||
date: str
|
||||
attendees: int
|
||||
|
||||
@field_validator('date')
|
||||
def validate_date(cls, v):
|
||||
"""Ensure date is in YYYY-MM-DD format."""
|
||||
import re
|
||||
if not re.match(r'\d{4}-\d{2}-\d{2}', v):
|
||||
raise ValueError('Date must be YYYY-MM-DD format')
|
||||
return v
|
||||
|
||||
@field_validator('attendees')
|
||||
def validate_attendees(cls, v):
|
||||
"""Ensure positive attendees."""
|
||||
if v < 1:
|
||||
raise ValueError('Must have at least 1 attendee')
|
||||
return v
|
||||
```
|
||||
|
||||
#### 模型级验证
|
||||
|
||||
```python
|
||||
from pydantic import model_validator
|
||||
|
||||
class DateRange(BaseModel):
|
||||
start_date: str
|
||||
end_date: str
|
||||
|
||||
@model_validator(mode='after')
|
||||
def check_dates(self):
|
||||
"""Ensure end_date is after start_date."""
|
||||
from datetime import datetime
|
||||
start = datetime.strptime(self.start_date, '%Y-%m-%d')
|
||||
end = datetime.strptime(self.end_date, '%Y-%m-%d')
|
||||
|
||||
if end < start:
|
||||
raise ValueError('end_date must be after start_date')
|
||||
return self
|
||||
```
|
||||
|
||||
### 3. 自动重试
|
||||
|
||||
当验证失败时,Instructor 会自动重试,并将错误反馈提供给 LLM。
|
||||
|
||||
```python
|
||||
# Retries up to 3 times if validation fails
|
||||
user = client.messages.create(
|
||||
model="claude-sonnet-4-5-20250929",
|
||||
max_tokens=1024,
|
||||
messages=[{
|
||||
"role": "user",
|
||||
"content": "Extract user from: John, age unknown"
|
||||
}],
|
||||
response_model=User,
|
||||
max_retries=3 # Default is 3
|
||||
)
|
||||
|
||||
# If age can't be extracted, Instructor tells the LLM:
|
||||
# "Validation error: age - field required"
|
||||
# LLM tries again with better extraction
|
||||
```
|
||||
|
||||
**工作原理:**
|
||||
1. LLM 生成输出
|
||||
2. Pydantic 进行验证
|
||||
3. 若无效:将错误信息发回给 LLM
|
||||
4. LLM 根据错误反馈重新尝试
|
||||
5. 重复直至达到 max_retries 次数
|
||||
|
||||
### 4. 流式传输
|
||||
|
||||
流式传输部分结果以进行实时处理。
|
||||
|
||||
#### 流式传输部分对象
|
||||
|
||||
```python
|
||||
from instructor import Partial
|
||||
|
||||
class Story(BaseModel):
|
||||
title: str
|
||||
content: str
|
||||
tags: list[str]
|
||||
|
||||
# Stream partial updates as LLM generates
|
||||
for partial_story in client.messages.create_partial(
|
||||
model="claude-sonnet-4-5-20250929",
|
||||
max_tokens=1024,
|
||||
messages=[{
|
||||
"role": "user",
|
||||
"content": "Write a short sci-fi story"
|
||||
}],
|
||||
response_model=Story
|
||||
):
|
||||
print(f"Title: {partial_story.title}")
|
||||
print(f"Content so far: {partial_story.content[:100]}...")
|
||||
# Update UI in real-time
|
||||
```
|
||||
|
||||
#### 流式传输可迭代对象
|
||||
|
||||
```python
|
||||
class Task(BaseModel):
|
||||
title: str
|
||||
priority: str
|
||||
|
||||
# Stream list items as they're generated
|
||||
tasks = client.messages.create_iterable(
|
||||
model="claude-sonnet-4-5-20250929",
|
||||
max_tokens=1024,
|
||||
messages=[{
|
||||
"role": "user",
|
||||
"content": "Generate 10 project tasks"
|
||||
}],
|
||||
response_model=Task
|
||||
)
|
||||
|
||||
for task in tasks:
|
||||
print(f"- {task.title} ({task.priority})")
|
||||
# Process each task as it arrives
|
||||
```
|
||||
|
||||
## 提供商配置
|
||||
|
||||
### Anthropic Claude
|
||||
|
||||
```python
|
||||
import instructor
|
||||
from anthropic import Anthropic
|
||||
|
||||
client = instructor.from_anthropic(
|
||||
Anthropic(api_key="your-api-key")
|
||||
)
|
||||
|
||||
# Use with Claude models
|
||||
response = client.messages.create(
|
||||
model="claude-sonnet-4-5-20250929",
|
||||
max_tokens=1024,
|
||||
messages=[...],
|
||||
response_model=YourModel
|
||||
)
|
||||
```
|
||||
|
||||
### OpenAI
|
||||
|
||||
```python
|
||||
from openai import OpenAI
|
||||
|
||||
client = instructor.from_openai(
|
||||
OpenAI(api_key="your-api-key")
|
||||
)
|
||||
|
||||
response = client.chat.completions.create(
|
||||
model="gpt-4o-mini",
|
||||
response_model=YourModel,
|
||||
messages=[...]
|
||||
)
|
||||
```
|
||||
|
||||
### 本地模型(Ollama)
|
||||
|
||||
```python
|
||||
from openai import OpenAI
|
||||
|
||||
# Point to local Ollama server
|
||||
client = instructor.from_openai(
|
||||
OpenAI(
|
||||
base_url="http://localhost:11434/v1",
|
||||
api_key="ollama" # Required but ignored
|
||||
),
|
||||
mode=instructor.Mode.JSON
|
||||
)
|
||||
|
||||
response = client.chat.completions.create(
|
||||
model="llama3.1",
|
||||
response_model=YourModel,
|
||||
messages=[...]
|
||||
)
|
||||
```
|
||||
|
||||
## 常用模式
|
||||
|
||||
### 模式 1:从文本中提取数据
|
||||
|
||||
```python
|
||||
class CompanyInfo(BaseModel):
|
||||
name: str
|
||||
founded_year: int
|
||||
industry: str
|
||||
employees: int
|
||||
headquarters: str
|
||||
|
||||
text = """
|
||||
Tesla, Inc. was founded in 2003. It operates in the automotive and energy
|
||||
industry with approximately 140,000 employees. The company is headquartered
|
||||
in Austin, Texas.
|
||||
"""
|
||||
|
||||
company = client.messages.create(
|
||||
model="claude-sonnet-4-5-20250929",
|
||||
max_tokens=1024,
|
||||
messages=[{
|
||||
"role": "user",
|
||||
"content": f"Extract company information from: {text}"
|
||||
}],
|
||||
response_model=CompanyInfo
|
||||
)
|
||||
```
|
||||
|
||||
### 模式 2:分类
|
||||
|
||||
```python
|
||||
class Category(str, Enum):
|
||||
TECHNOLOGY = "technology"
|
||||
FINANCE = "finance"
|
||||
HEALTHCARE = "healthcare"
|
||||
EDUCATION = "education"
|
||||
OTHER = "other"
|
||||
|
||||
class ArticleClassification(BaseModel):
|
||||
category: Category
|
||||
confidence: float = Field(ge=0.0, le=1.0)
|
||||
keywords: list[str]
|
||||
|
||||
classification = client.messages.create(
|
||||
model="claude-sonnet-4-5-20250929",
|
||||
max_tokens=1024,
|
||||
messages=[{
|
||||
"role": "user",
|
||||
"content": "Classify this article: [article text]"
|
||||
}],
|
||||
response_model=ArticleClassification
|
||||
)
|
||||
```
|
||||
|
||||
### 模式 3:多实体提取
|
||||
|
||||
```python
|
||||
class Person(BaseModel):
|
||||
name: str
|
||||
role: str
|
||||
|
||||
class Organization(BaseModel):
|
||||
name: str
|
||||
industry: str
|
||||
|
||||
class Entities(BaseModel):
|
||||
people: list[Person]
|
||||
organizations: list[Organization]
|
||||
locations: list[str]
|
||||
|
||||
text = "Tim Cook, CEO of Apple, announced at the event in Cupertino..."
|
||||
|
||||
entities = client.messages.create(
|
||||
model="claude-sonnet-4-5-20250929",
|
||||
max_tokens=1024,
|
||||
messages=[{
|
||||
"role": "user",
|
||||
"content": f"Extract all entities from: {text}"
|
||||
}],
|
||||
response_model=Entities
|
||||
)
|
||||
|
||||
for person in entities.people:
|
||||
print(f"{person.name} - {person.role}")
|
||||
```
|
||||
|
||||
### 模式 4:结构化分析
|
||||
|
||||
```python
|
||||
class SentimentAnalysis(BaseModel):
|
||||
overall_sentiment: Sentiment
|
||||
positive_aspects: list[str]
|
||||
negative_aspects: list[str]
|
||||
suggestions: list[str]
|
||||
score: float = Field(ge=-1.0, le=1.0)
|
||||
|
||||
review = "The product works well but setup was confusing..."
|
||||
|
||||
analysis = client.messages.create(
|
||||
model="claude-sonnet-4-5-20250929",
|
||||
max_tokens=1024,
|
||||
messages=[{
|
||||
"role": "user",
|
||||
"content": f"Analyze this review: {review}"
|
||||
}],
|
||||
response_model=SentimentAnalysis
|
||||
)
|
||||
```
|
||||
|
||||
### 模式 5:批量处理
|
||||
|
||||
```python
|
||||
def extract_person(text: str) -> Person:
|
||||
return client.messages.create(
|
||||
model="claude-sonnet-4-5-20250929",
|
||||
max_tokens=1024,
|
||||
messages=[{
|
||||
"role": "user",
|
||||
"content": f"Extract person from: {text}"
|
||||
}],
|
||||
response_model=Person
|
||||
)
|
||||
|
||||
texts = [
|
||||
"John Doe is a 30-year-old engineer",
|
||||
"Jane Smith, 25, works in marketing",
|
||||
"Bob Johnson, age 40, software developer"
|
||||
]
|
||||
|
||||
people = [extract_person(text) for text in texts]
|
||||
```
|
||||
|
||||
## 高级特性
|
||||
|
||||
### 联合类型
|
||||
|
||||
```python
|
||||
from typing import Union
|
||||
|
||||
class TextContent(BaseModel):
|
||||
type: str = "text"
|
||||
content: str
|
||||
|
||||
class ImageContent(BaseModel):
|
||||
type: str = "image"
|
||||
url: HttpUrl
|
||||
caption: str
|
||||
|
||||
class Post(BaseModel):
|
||||
title: str
|
||||
content: Union[TextContent, ImageContent] # Either type
|
||||
|
||||
# LLM chooses appropriate type based on content
|
||||
```
|
||||
|
||||
### 动态模型
|
||||
|
||||
```python
|
||||
from pydantic import create_model
|
||||
|
||||
# Create model at runtime
|
||||
DynamicUser = create_model(
|
||||
'User',
|
||||
name=(str, ...),
|
||||
age=(int, Field(ge=0)),
|
||||
email=(EmailStr, ...)
|
||||
)
|
||||
|
||||
user = client.messages.create(
|
||||
model="claude-sonnet-4-5-20250929",
|
||||
max_tokens=1024,
|
||||
messages=[...],
|
||||
response_model=DynamicUser
|
||||
)
|
||||
```
|
||||
|
||||
### 自定义模式
|
||||
|
||||
```python
|
||||
# For providers without native structured outputs
|
||||
client = instructor.from_anthropic(
|
||||
Anthropic(),
|
||||
mode=instructor.Mode.JSON # JSON mode
|
||||
)
|
||||
|
||||
# Available modes:
|
||||
# - Mode.ANTHROPIC_TOOLS (recommended for Claude)
|
||||
# - Mode.JSON (fallback)
|
||||
# - Mode.TOOLS (OpenAI tools)
|
||||
```
|
||||
|
||||
### 上下文管理
|
||||
|
||||
```python
|
||||
# Single-use client
|
||||
with instructor.from_anthropic(Anthropic()) as client:
|
||||
result = client.messages.create(
|
||||
model="claude-sonnet-4-5-20250929",
|
||||
max_tokens=1024,
|
||||
messages=[...],
|
||||
response_model=YourModel
|
||||
)
|
||||
# Client closed automatically
|
||||
```
|
||||
|
||||
## 错误处理
|
||||
|
||||
### 处理验证错误
|
||||
|
||||
```python
|
||||
from pydantic import ValidationError
|
||||
|
||||
try:
|
||||
user = client.messages.create(
|
||||
model="claude-sonnet-4-5-20250929",
|
||||
max_tokens=1024,
|
||||
messages=[...],
|
||||
response_model=User,
|
||||
max_retries=3
|
||||
)
|
||||
except ValidationError as e:
|
||||
print(f"Failed after retries: {e}")
|
||||
# Handle gracefully
|
||||
|
||||
except Exception as e:
|
||||
print(f"API error: {e}")
|
||||
```
|
||||
|
||||
### 自定义错误信息
|
||||
|
||||
```python
|
||||
class ValidatedUser(BaseModel):
|
||||
name: str = Field(description="Full name, 2-100 characters")
|
||||
age: int = Field(description="Age between 0 and 120", ge=0, le=120)
|
||||
email: EmailStr = Field(description="Valid email address")
|
||||
|
||||
class Config:
|
||||
# Custom error messages
|
||||
json_schema_extra = {
|
||||
"examples": [
|
||||
{
|
||||
"name": "John Doe",
|
||||
"age": 30,
|
||||
"email": "john@example.com"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 最佳实践
|
||||
|
||||
### 1. 清晰的字段描述
|
||||
|
||||
```python
|
||||
# ❌ Bad: Vague
|
||||
class Product(BaseModel):
|
||||
name: str
|
||||
price: float
|
||||
|
||||
# ✅ Good: Descriptive
|
||||
class Product(BaseModel):
|
||||
name: str = Field(description="Product name from the text")
|
||||
price: float = Field(description="Price in USD, without currency symbol")
|
||||
```
|
||||
|
||||
### 2. 使用适当的验证
|
||||
|
||||
```python
|
||||
# ✅ Good: Constrain values
|
||||
class Rating(BaseModel):
|
||||
score: int = Field(ge=1, le=5, description="Rating from 1 to 5 stars")
|
||||
review: str = Field(min_length=10, description="Review text, at least 10 chars")
|
||||
```
|
||||
|
||||
### 3. 在 prompt(提示词)中提供示例
|
||||
|
||||
```python
|
||||
messages = [{
|
||||
"role": "user",
|
||||
"content": """Extract person info from: "John, 30, engineer"
|
||||
|
||||
Example format:
|
||||
{
|
||||
"name": "John Doe",
|
||||
"age": 30,
|
||||
"occupation": "engineer"
|
||||
}"""
|
||||
}]
|
||||
```
|
||||
|
||||
### 4. 对固定类别使用枚举
|
||||
|
||||
```python
|
||||
# ✅ Good: Enum ensures valid values
|
||||
class Status(str, Enum):
|
||||
PENDING = "pending"
|
||||
APPROVED = "approved"
|
||||
REJECTED = "rejected"
|
||||
|
||||
class Application(BaseModel):
|
||||
status: Status # LLM must choose from enum
|
||||
```
|
||||
|
||||
### 5. 优雅处理缺失数据
|
||||
|
||||
```python
|
||||
class PartialData(BaseModel):
|
||||
required_field: str
|
||||
optional_field: Optional[str] = None
|
||||
default_field: str = "default_value"
|
||||
|
||||
# LLM only needs to provide required_field
|
||||
```
|
||||
|
||||
## 与其他方案的对比
|
||||
|
||||
| 特性 | Instructor | 手动 JSON | LangChain | DSPy |
|
||||
|---------|------------|-------------|-----------|------|
|
||||
| 类型安全 | ✅ 是 | ❌ 否 | ⚠️ 部分 | ✅ 是 |
|
||||
| 自动验证 | ✅ 是 | ❌ 否 | ❌ 否 | ⚠️ 有限 |
|
||||
| 自动重试 | ✅ 是 | ❌ 否 | ❌ 否 | ✅ 是 |
|
||||
| 流式传输 | ✅ 是 | ❌ 否 | ✅ 是 | ❌ 否 |
|
||||
| 多提供商 | ✅ 是 | ⚠️ 手动 | ✅ 是 | ✅ 是 |
|
||||
| 学习曲线 | 低 | 低 | 中 | 高 |
|
||||
|
||||
**何时选择 Instructor:**
|
||||
- 需要结构化、经过验证的输出
|
||||
- 需要类型安全和 IDE 支持
|
||||
- 需要自动重试
|
||||
- 构建数据提取系统
|
||||
|
||||
**何时选择其他方案:**
|
||||
- DSPy:需要 prompt 优化
|
||||
- LangChain:构建复杂链路
|
||||
- 手动:简单的一次性提取
|
||||
|
||||
## 资源
|
||||
|
||||
- **文档**:https://python.useinstructor.com
|
||||
- **GitHub**:https://github.com/jxnl/instructor(15k+ stars)
|
||||
- **Cookbook**:https://python.useinstructor.com/examples
|
||||
- **Discord**:提供社区支持
|
||||
|
||||
## 另请参阅
|
||||
|
||||
- `references/validation.md` — 高级验证模式
|
||||
- `references/providers.md` — 提供商专项配置
|
||||
- `references/examples.md` — 真实使用案例
|
||||
+568
@@ -0,0 +1,568 @@
|
||||
---
|
||||
title: "Lambda Labs Gpu Cloud — 用于 ML 训练和推理的预留及按需 GPU 云实例"
|
||||
sidebar_label: "Lambda Labs Gpu Cloud"
|
||||
description: "用于 ML 训练和推理的预留及按需 GPU 云实例"
|
||||
---
|
||||
|
||||
{/* This page is auto-generated from the skill's SKILL.md by website/scripts/generate-skill-docs.py. Edit the source SKILL.md, not this page. */}
|
||||
|
||||
# Lambda Labs Gpu Cloud
|
||||
|
||||
用于 ML 训练和推理的预留及按需 GPU 云实例。当你需要具备简单 SSH 访问的专用 GPU 实例、持久化文件系统,或用于大规模训练的高性能多节点集群时,请使用此 skill。
|
||||
|
||||
## Skill 元数据
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| 来源 | 可选 — 通过 `hermes skills install official/mlops/lambda-labs` 安装 |
|
||||
| 路径 | `optional-skills/mlops/lambda-labs` |
|
||||
| 版本 | `1.0.0` |
|
||||
| 作者 | Orchestra Research |
|
||||
| 许可证 | MIT |
|
||||
| 依赖 | `lambda-cloud-client>=1.0.0` |
|
||||
| 平台 | linux, macos, windows |
|
||||
| 标签 | `Infrastructure`, `GPU Cloud`, `Training`, `Inference`, `Lambda Labs` |
|
||||
|
||||
## 参考:完整 SKILL.md
|
||||
|
||||
:::info
|
||||
以下是 Hermes 在触发此 skill 时加载的完整 skill 定义。这是 agent 在 skill 激活时所看到的指令内容。
|
||||
:::
|
||||
|
||||
# Lambda Labs GPU Cloud
|
||||
|
||||
在 Lambda Labs GPU 云上运行 ML 工作负载的综合指南,涵盖按需实例和 1-Click Clusters。
|
||||
|
||||
## 何时使用 Lambda Labs
|
||||
|
||||
**在以下情况下使用 Lambda Labs:**
|
||||
- 需要具备完整 SSH 访问权限的专用 GPU 实例
|
||||
- 运行长时间训练任务(数小时至数天)
|
||||
- 希望简单定价且无出口费用
|
||||
- 需要跨会话的持久化存储
|
||||
- 需要高性能多节点集群(16-512 个 GPU)
|
||||
- 希望使用预装 ML 栈(Lambda Stack,含 PyTorch、CUDA、NCCL)
|
||||
|
||||
**主要特性:**
|
||||
- **GPU 种类**:B200、H100、GH200、A100、A10、A6000、V100
|
||||
- **Lambda Stack**:预装 PyTorch、TensorFlow、CUDA、cuDNN、NCCL
|
||||
- **持久化文件系统**:实例重启后数据保留
|
||||
- **1-Click Clusters**:16-512 个 GPU 的 Slurm 集群,配备 InfiniBand
|
||||
- **简单定价**:按分钟计费,无出口费用
|
||||
- **全球区域**:全球 12+ 个区域
|
||||
|
||||
**以下情况请使用替代方案:**
|
||||
- **Modal**:用于无服务器、自动扩缩容工作负载
|
||||
- **SkyPilot**:用于多云编排和成本优化
|
||||
- **RunPod**:用于更便宜的竞价实例和无服务器端点
|
||||
- **Vast.ai**:用于价格最低的 GPU 市场
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 账户设置
|
||||
|
||||
1. 在 https://lambda.ai 创建账户
|
||||
2. 添加付款方式
|
||||
3. 从控制台生成 API 密钥
|
||||
4. 添加 SSH 密钥(启动实例前必须完成)
|
||||
|
||||
### 通过控制台启动
|
||||
|
||||
1. 前往 https://cloud.lambda.ai/instances
|
||||
2. 点击"Launch instance"
|
||||
3. 选择 GPU 类型和区域
|
||||
4. 选择 SSH 密钥
|
||||
5. 可选择挂载文件系统
|
||||
6. 启动并等待 3-15 分钟
|
||||
|
||||
### 通过 SSH 连接
|
||||
|
||||
```bash
|
||||
# 从控制台获取实例 IP
|
||||
ssh ubuntu@<INSTANCE-IP>
|
||||
|
||||
# 或使用指定密钥
|
||||
ssh -i ~/.ssh/lambda_key ubuntu@<INSTANCE-IP>
|
||||
```
|
||||
|
||||
## GPU 实例
|
||||
|
||||
### 可用 GPU
|
||||
|
||||
| GPU | 显存 | 价格/GPU/小时 | 最适用场景 |
|
||||
|-----|------|--------------|----------|
|
||||
| B200 SXM6 | 180 GB | $4.99 | 最大模型,最快训练 |
|
||||
| H100 SXM | 80 GB | $2.99-3.29 | 大模型训练 |
|
||||
| H100 PCIe | 80 GB | $2.49 | 性价比 H100 |
|
||||
| GH200 | 96 GB | $1.49 | 单 GPU 大模型 |
|
||||
| A100 80GB | 80 GB | $1.79 | 生产训练 |
|
||||
| A100 40GB | 40 GB | $1.29 | 标准训练 |
|
||||
| A10 | 24 GB | $0.75 | 推理、微调 |
|
||||
| A6000 | 48 GB | $0.80 | 显存/价格比优 |
|
||||
| V100 | 16 GB | $0.55 | 低成本训练 |
|
||||
|
||||
### 实例配置
|
||||
|
||||
```
|
||||
8x GPU: 最适合分布式训练(DDP、FSDP)
|
||||
4x GPU: 大模型、多 GPU 训练
|
||||
2x GPU: 中等工作负载
|
||||
1x GPU: 微调、推理、开发
|
||||
```
|
||||
|
||||
### 启动时间
|
||||
|
||||
- 单 GPU:3-5 分钟
|
||||
- 多 GPU:10-15 分钟
|
||||
|
||||
## Lambda Stack
|
||||
|
||||
所有实例均预装 Lambda Stack:
|
||||
|
||||
```bash
|
||||
# 包含软件
|
||||
- Ubuntu 22.04 LTS
|
||||
- NVIDIA drivers (latest)
|
||||
- CUDA 12.x
|
||||
- cuDNN 8.x
|
||||
- NCCL (for multi-GPU)
|
||||
- PyTorch (latest)
|
||||
- TensorFlow (latest)
|
||||
- JAX
|
||||
- JupyterLab
|
||||
```
|
||||
|
||||
### 验证安装
|
||||
|
||||
```bash
|
||||
# 检查 GPU
|
||||
nvidia-smi
|
||||
|
||||
# 检查 PyTorch
|
||||
python -c "import torch; print(torch.cuda.is_available())"
|
||||
|
||||
# 检查 CUDA 版本
|
||||
nvcc --version
|
||||
```
|
||||
|
||||
## Python API
|
||||
|
||||
### 安装
|
||||
|
||||
```bash
|
||||
pip install lambda-cloud-client
|
||||
```
|
||||
|
||||
### 认证
|
||||
|
||||
```python
|
||||
import os
|
||||
import lambda_cloud_client
|
||||
|
||||
# 使用 API 密钥配置
|
||||
configuration = lambda_cloud_client.Configuration(
|
||||
host="https://cloud.lambdalabs.com/api/v1",
|
||||
access_token=os.environ["LAMBDA_API_KEY"]
|
||||
)
|
||||
```
|
||||
|
||||
### 列出可用实例
|
||||
|
||||
```python
|
||||
with lambda_cloud_client.ApiClient(configuration) as api_client:
|
||||
api = lambda_cloud_client.DefaultApi(api_client)
|
||||
|
||||
# 获取可用实例类型
|
||||
types = api.instance_types()
|
||||
for name, info in types.data.items():
|
||||
print(f"{name}: {info.instance_type.description}")
|
||||
```
|
||||
|
||||
### 启动实例
|
||||
|
||||
```python
|
||||
from lambda_cloud_client.models import LaunchInstanceRequest
|
||||
|
||||
request = LaunchInstanceRequest(
|
||||
region_name="us-west-1",
|
||||
instance_type_name="gpu_1x_h100_sxm5",
|
||||
ssh_key_names=["my-ssh-key"],
|
||||
file_system_names=["my-filesystem"], # 可选
|
||||
name="training-job"
|
||||
)
|
||||
|
||||
response = api.launch_instance(request)
|
||||
instance_id = response.data.instance_ids[0]
|
||||
print(f"Launched: {instance_id}")
|
||||
```
|
||||
|
||||
### 列出运行中的实例
|
||||
|
||||
```python
|
||||
instances = api.list_instances()
|
||||
for instance in instances.data:
|
||||
print(f"{instance.name}: {instance.ip} ({instance.status})")
|
||||
```
|
||||
|
||||
### 终止实例
|
||||
|
||||
```python
|
||||
from lambda_cloud_client.models import TerminateInstanceRequest
|
||||
|
||||
request = TerminateInstanceRequest(
|
||||
instance_ids=[instance_id]
|
||||
)
|
||||
api.terminate_instance(request)
|
||||
```
|
||||
|
||||
### SSH 密钥管理
|
||||
|
||||
```python
|
||||
from lambda_cloud_client.models import AddSshKeyRequest
|
||||
|
||||
# 添加 SSH 密钥
|
||||
request = AddSshKeyRequest(
|
||||
name="my-key",
|
||||
public_key="ssh-rsa AAAA..."
|
||||
)
|
||||
api.add_ssh_key(request)
|
||||
|
||||
# 列出密钥
|
||||
keys = api.list_ssh_keys()
|
||||
|
||||
# 删除密钥
|
||||
api.delete_ssh_key(key_id)
|
||||
```
|
||||
|
||||
## 使用 curl 的 CLI
|
||||
|
||||
### 列出实例类型
|
||||
|
||||
```bash
|
||||
curl -u $LAMBDA_API_KEY: \
|
||||
https://cloud.lambdalabs.com/api/v1/instance-types | jq
|
||||
```
|
||||
|
||||
### 启动实例
|
||||
|
||||
```bash
|
||||
curl -u $LAMBDA_API_KEY: \
|
||||
-X POST https://cloud.lambdalabs.com/api/v1/instance-operations/launch \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"region_name": "us-west-1",
|
||||
"instance_type_name": "gpu_1x_h100_sxm5",
|
||||
"ssh_key_names": ["my-key"]
|
||||
}' | jq
|
||||
```
|
||||
|
||||
### 终止实例
|
||||
|
||||
```bash
|
||||
curl -u $LAMBDA_API_KEY: \
|
||||
-X POST https://cloud.lambdalabs.com/api/v1/instance-operations/terminate \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"instance_ids": ["<INSTANCE-ID>"]}' | jq
|
||||
```
|
||||
|
||||
## 持久化存储
|
||||
|
||||
### 文件系统
|
||||
|
||||
文件系统在实例重启后保留数据:
|
||||
|
||||
```bash
|
||||
# 挂载位置
|
||||
/lambda/nfs/<FILESYSTEM_NAME>
|
||||
|
||||
# 示例:保存检查点
|
||||
python train.py --checkpoint-dir /lambda/nfs/my-storage/checkpoints
|
||||
```
|
||||
|
||||
### 创建文件系统
|
||||
|
||||
1. 前往 Lambda 控制台中的 Storage
|
||||
2. 点击"Create filesystem"
|
||||
3. 选择区域(必须与实例区域一致)
|
||||
4. 命名并创建
|
||||
|
||||
### 挂载到实例
|
||||
|
||||
文件系统必须在实例启动时挂载:
|
||||
- 通过控制台:启动时选择文件系统
|
||||
- 通过 API:在启动请求中包含 `file_system_names`
|
||||
|
||||
### 最佳实践
|
||||
|
||||
<!-- ascii-guard-ignore -->
|
||||
```bash
|
||||
# 存储在文件系统上(持久化)
|
||||
/lambda/nfs/storage/
|
||||
├── datasets/
|
||||
├── checkpoints/
|
||||
├── models/
|
||||
└── outputs/
|
||||
|
||||
# 本地 SSD(更快,临时)
|
||||
/home/ubuntu/
|
||||
└── working/ # 临时文件
|
||||
```
|
||||
<!-- ascii-guard-ignore-end -->
|
||||
|
||||
## SSH 配置
|
||||
|
||||
### 添加 SSH 密钥
|
||||
|
||||
```bash
|
||||
# 在本地生成密钥
|
||||
ssh-keygen -t ed25519 -f ~/.ssh/lambda_key
|
||||
|
||||
# 将公钥添加到 Lambda 控制台
|
||||
# 或通过 API 添加
|
||||
```
|
||||
|
||||
### 多个密钥
|
||||
|
||||
```bash
|
||||
# 在实例上添加更多密钥
|
||||
echo 'ssh-rsa AAAA...' >> ~/.ssh/authorized_keys
|
||||
```
|
||||
|
||||
### 从 GitHub 导入
|
||||
|
||||
```bash
|
||||
# 在实例上执行
|
||||
ssh-import-id gh:username
|
||||
```
|
||||
|
||||
### SSH 隧道
|
||||
|
||||
```bash
|
||||
# 转发 Jupyter
|
||||
ssh -L 8888:localhost:8888 ubuntu@<IP>
|
||||
|
||||
# 转发 TensorBoard
|
||||
ssh -L 6006:localhost:6006 ubuntu@<IP>
|
||||
|
||||
# 多端口
|
||||
ssh -L 8888:localhost:8888 -L 6006:localhost:6006 ubuntu@<IP>
|
||||
```
|
||||
|
||||
## JupyterLab
|
||||
|
||||
### 从控制台启动
|
||||
|
||||
1. 前往 Instances 页面
|
||||
2. 点击 Cloud IDE 列中的"Launch"
|
||||
3. JupyterLab 在浏览器中打开
|
||||
|
||||
### 手动访问
|
||||
|
||||
```bash
|
||||
# 在实例上
|
||||
jupyter lab --ip=0.0.0.0 --port=8888
|
||||
|
||||
# 在本地机器上建立隧道
|
||||
ssh -L 8888:localhost:8888 ubuntu@<IP>
|
||||
# 打开 http://localhost:8888
|
||||
```
|
||||
|
||||
## 训练工作流
|
||||
|
||||
### 单 GPU 训练
|
||||
|
||||
```bash
|
||||
# SSH 到实例
|
||||
ssh ubuntu@<IP>
|
||||
|
||||
# 克隆仓库
|
||||
git clone https://github.com/user/project
|
||||
cd project
|
||||
|
||||
# 安装依赖
|
||||
pip install -r requirements.txt
|
||||
|
||||
# 训练
|
||||
python train.py --epochs 100 --checkpoint-dir /lambda/nfs/storage/checkpoints
|
||||
```
|
||||
|
||||
### 多 GPU 训练(单节点)
|
||||
|
||||
```python
|
||||
# train_ddp.py
|
||||
import torch
|
||||
import torch.distributed as dist
|
||||
from torch.nn.parallel import DistributedDataParallel as DDP
|
||||
|
||||
def main():
|
||||
dist.init_process_group("nccl")
|
||||
rank = dist.get_rank()
|
||||
device = rank % torch.cuda.device_count()
|
||||
|
||||
model = MyModel().to(device)
|
||||
model = DDP(model, device_ids=[device])
|
||||
|
||||
# 训练循环...
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
```
|
||||
|
||||
```bash
|
||||
# 使用 torchrun 启动(8 个 GPU)
|
||||
torchrun --nproc_per_node=8 train_ddp.py
|
||||
```
|
||||
|
||||
### 检查点保存到文件系统
|
||||
|
||||
```python
|
||||
import os
|
||||
|
||||
checkpoint_dir = "/lambda/nfs/my-storage/checkpoints"
|
||||
os.makedirs(checkpoint_dir, exist_ok=True)
|
||||
|
||||
# 保存检查点
|
||||
torch.save({
|
||||
'epoch': epoch,
|
||||
'model_state_dict': model.state_dict(),
|
||||
'optimizer_state_dict': optimizer.state_dict(),
|
||||
'loss': loss,
|
||||
}, f"{checkpoint_dir}/checkpoint_{epoch}.pt")
|
||||
```
|
||||
|
||||
## 1-Click Clusters
|
||||
|
||||
### 概述
|
||||
|
||||
高性能 Slurm 集群,具备:
|
||||
- 16-512 个 NVIDIA H100 或 B200 GPU
|
||||
- NVIDIA Quantum-2 400 Gb/s InfiniBand
|
||||
- GPUDirect RDMA,速率 3200 Gb/s
|
||||
- 预装分布式 ML 栈
|
||||
|
||||
### 包含软件
|
||||
|
||||
- Ubuntu 22.04 LTS + Lambda Stack
|
||||
- NCCL、Open MPI
|
||||
- PyTorch(含 DDP 和 FSDP)
|
||||
- TensorFlow
|
||||
- OFED 驱动
|
||||
|
||||
### 存储
|
||||
|
||||
- 每个计算节点 24 TB NVMe(临时)
|
||||
- Lambda 文件系统用于持久化数据
|
||||
|
||||
### 多节点训练
|
||||
|
||||
```bash
|
||||
# 在 Slurm 集群上
|
||||
srun --nodes=4 --ntasks-per-node=8 --gpus-per-node=8 \
|
||||
torchrun --nnodes=4 --nproc_per_node=8 \
|
||||
--rdzv_backend=c10d --rdzv_endpoint=$MASTER_ADDR:29500 \
|
||||
train.py
|
||||
```
|
||||
|
||||
## 网络
|
||||
|
||||
### 带宽
|
||||
|
||||
- 实例间(同一区域):最高 200 Gbps
|
||||
- 互联网出站:最高 20 Gbps
|
||||
|
||||
### 防火墙
|
||||
|
||||
- 默认:仅开放 22 端口(SSH)
|
||||
- 在 Lambda 控制台中配置其他端口
|
||||
- 默认允许 ICMP 流量
|
||||
|
||||
### 私有 IP
|
||||
|
||||
```bash
|
||||
# 查找私有 IP
|
||||
ip addr show | grep 'inet '
|
||||
```
|
||||
|
||||
## 常见工作流
|
||||
|
||||
### 工作流 1:微调 LLM
|
||||
|
||||
```bash
|
||||
# 1. 启动带文件系统的 8x H100 实例
|
||||
|
||||
# 2. SSH 并设置环境
|
||||
ssh ubuntu@<IP>
|
||||
pip install transformers accelerate peft
|
||||
|
||||
# 3. 将模型下载到文件系统
|
||||
python -c "
|
||||
from transformers import AutoModelForCausalLM
|
||||
model = AutoModelForCausalLM.from_pretrained('meta-llama/Llama-2-7b-hf')
|
||||
model.save_pretrained('/lambda/nfs/storage/models/llama-2-7b')
|
||||
"
|
||||
|
||||
# 4. 使用文件系统上的检查点进行微调
|
||||
accelerate launch --num_processes 8 train.py \
|
||||
--model_path /lambda/nfs/storage/models/llama-2-7b \
|
||||
--output_dir /lambda/nfs/storage/outputs \
|
||||
--checkpoint_dir /lambda/nfs/storage/checkpoints
|
||||
```
|
||||
|
||||
### 工作流 2:批量推理
|
||||
|
||||
```bash
|
||||
# 1. 启动 A10 实例(推理性价比高)
|
||||
|
||||
# 2. 运行推理
|
||||
python inference.py \
|
||||
--model /lambda/nfs/storage/models/fine-tuned \
|
||||
--input /lambda/nfs/storage/data/inputs.jsonl \
|
||||
--output /lambda/nfs/storage/data/outputs.jsonl
|
||||
```
|
||||
|
||||
## 成本优化
|
||||
|
||||
### 选择合适的 GPU
|
||||
|
||||
| 任务 | 推荐 GPU |
|
||||
|------|-----------------|
|
||||
| LLM 微调(7B) | A100 40GB |
|
||||
| LLM 微调(70B) | 8x H100 |
|
||||
| 推理 | A10、A6000 |
|
||||
| 开发 | V100、A10 |
|
||||
| 最高性能 | B200 |
|
||||
|
||||
### 降低成本
|
||||
|
||||
1. **使用文件系统**:避免重复下载数据
|
||||
2. **频繁保存检查点**:恢复中断的训练
|
||||
3. **合理配置**:不要过度分配 GPU
|
||||
4. **终止空闲实例**:无自动停止,需手动终止
|
||||
|
||||
### 监控使用情况
|
||||
|
||||
- 控制台显示实时 GPU 利用率
|
||||
- 通过 API 进行程序化监控
|
||||
|
||||
## 常见问题
|
||||
|
||||
| 问题 | 解决方案 |
|
||||
|-------|----------|
|
||||
| 实例无法启动 | 检查区域可用性,尝试不同 GPU |
|
||||
| SSH 连接被拒绝 | 等待实例初始化(3-15 分钟) |
|
||||
| 终止后数据丢失 | 使用持久化文件系统 |
|
||||
| 数据传输缓慢 | 使用同一区域的文件系统 |
|
||||
| GPU 未被检测到 | 重启实例,检查驱动 |
|
||||
|
||||
## 参考资料
|
||||
|
||||
- **[高级用法](https://github.com/NousResearch/hermes-agent/blob/main/optional-skills/mlops/lambda-labs/references/advanced-usage.md)** — 多节点训练、API 自动化
|
||||
- **[故障排查](https://github.com/NousResearch/hermes-agent/blob/main/optional-skills/mlops/lambda-labs/references/troubleshooting.md)** — 常见问题及解决方案
|
||||
|
||||
## 资源
|
||||
|
||||
- **文档**:https://docs.lambda.ai
|
||||
- **控制台**:https://cloud.lambda.ai
|
||||
- **定价**:https://lambda.ai/instances
|
||||
- **支持**:https://support.lambdalabs.com
|
||||
- **博客**:https://lambda.ai/blog
|
||||
+323
@@ -0,0 +1,323 @@
|
||||
---
|
||||
title: "Llava — 大型语言与视觉助手"
|
||||
sidebar_label: "Llava"
|
||||
description: "大型语言与视觉助手"
|
||||
---
|
||||
|
||||
{/* This page is auto-generated from the skill's SKILL.md by website/scripts/generate-skill-docs.py. Edit the source SKILL.md, not this page. */}
|
||||
|
||||
# Llava
|
||||
|
||||
大型语言与视觉助手。支持视觉指令微调(instruction tuning)和基于图像的对话。将 CLIP 视觉编码器与 Vicuna/LLaMA 语言模型相结合。支持多轮图像对话、视觉问答(VQA)和指令跟随。适用于视觉语言聊天机器人或图像理解任务。最适合对话式图像分析。
|
||||
|
||||
## Skill 元数据
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| 来源 | 可选 — 通过 `hermes skills install official/mlops/llava` 安装 |
|
||||
| 路径 | `optional-skills/mlops/llava` |
|
||||
| 版本 | `1.0.0` |
|
||||
| 作者 | Orchestra Research |
|
||||
| 许可证 | MIT |
|
||||
| 依赖项 | `transformers`, `torch`, `pillow` |
|
||||
| 平台 | linux, macos, windows |
|
||||
| 标签 | `LLaVA`, `Vision-Language`, `Multimodal`, `Visual Question Answering`, `Image Chat`, `CLIP`, `Vicuna`, `Conversational AI`, `Instruction Tuning`, `VQA` |
|
||||
|
||||
## 参考:完整 SKILL.md
|
||||
|
||||
:::info
|
||||
以下是 Hermes 在触发该 skill 时加载的完整 skill 定义。这是 skill 激活时 agent 所看到的指令内容。
|
||||
:::
|
||||
|
||||
# LLaVA - 大型语言与视觉助手
|
||||
|
||||
用于对话式图像理解的开源视觉语言模型。
|
||||
|
||||
## 何时使用 LLaVA
|
||||
|
||||
**适用场景:**
|
||||
- 构建视觉语言聊天机器人
|
||||
- 视觉问答(VQA)
|
||||
- 图像描述与字幕生成
|
||||
- 多轮图像对话
|
||||
- 视觉指令跟随
|
||||
- 含图像的文档理解
|
||||
|
||||
**指标**:
|
||||
- **GitHub 23,000+ 星标**
|
||||
- GPT-4V 级别能力(目标)
|
||||
- Apache 2.0 许可证
|
||||
- 多种模型规格(7B–34B 参数)
|
||||
|
||||
**改用其他方案的情况**:
|
||||
- **GPT-4V**:质量最高,基于 API
|
||||
- **CLIP**:简单零样本分类
|
||||
- **BLIP-2**:更适合纯字幕生成
|
||||
- **Flamingo**:研究用途,非开源
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 安装
|
||||
|
||||
```bash
|
||||
# Clone repository
|
||||
git clone https://github.com/haotian-liu/LLaVA
|
||||
cd LLaVA
|
||||
|
||||
# Install
|
||||
pip install -e .
|
||||
```
|
||||
|
||||
### 基本用法
|
||||
|
||||
```python
|
||||
from llava.model.builder import load_pretrained_model
|
||||
from llava.mm_utils import get_model_name_from_path, process_images, tokenizer_image_token
|
||||
from llava.constants import IMAGE_TOKEN_INDEX, DEFAULT_IMAGE_TOKEN
|
||||
from llava.conversation import conv_templates
|
||||
from PIL import Image
|
||||
import torch
|
||||
|
||||
# Load model
|
||||
model_path = "liuhaotian/llava-v1.5-7b"
|
||||
tokenizer, model, image_processor, context_len = load_pretrained_model(
|
||||
model_path=model_path,
|
||||
model_base=None,
|
||||
model_name=get_model_name_from_path(model_path)
|
||||
)
|
||||
|
||||
# Load image
|
||||
image = Image.open("image.jpg")
|
||||
image_tensor = process_images([image], image_processor, model.config)
|
||||
image_tensor = image_tensor.to(model.device, dtype=torch.float16)
|
||||
|
||||
# Create conversation
|
||||
conv = conv_templates["llava_v1"].copy()
|
||||
conv.append_message(conv.roles[0], DEFAULT_IMAGE_TOKEN + "\nWhat is in this image?")
|
||||
conv.append_message(conv.roles[1], None)
|
||||
prompt = conv.get_prompt()
|
||||
|
||||
# Generate response
|
||||
input_ids = tokenizer_image_token(prompt, tokenizer, IMAGE_TOKEN_INDEX, return_tensors='pt').unsqueeze(0).to(model.device)
|
||||
|
||||
with torch.inference_mode():
|
||||
output_ids = model.generate(
|
||||
input_ids,
|
||||
images=image_tensor,
|
||||
do_sample=True,
|
||||
temperature=0.2,
|
||||
max_new_tokens=512
|
||||
)
|
||||
|
||||
response = tokenizer.decode(output_ids[0], skip_special_tokens=True).strip()
|
||||
print(response)
|
||||
```
|
||||
|
||||
## 可用模型
|
||||
|
||||
| 模型 | 参数量 | 显存 | 质量 |
|
||||
|-------|------------|------|---------|
|
||||
| LLaVA-v1.5-7B | 7B | ~14 GB | 良好 |
|
||||
| LLaVA-v1.5-13B | 13B | ~28 GB | 较好 |
|
||||
| LLaVA-v1.6-34B | 34B | ~70 GB | 最佳 |
|
||||
|
||||
```python
|
||||
# Load different models
|
||||
model_7b = "liuhaotian/llava-v1.5-7b"
|
||||
model_13b = "liuhaotian/llava-v1.5-13b"
|
||||
model_34b = "liuhaotian/llava-v1.6-34b"
|
||||
|
||||
# 4-bit quantization for lower VRAM
|
||||
load_4bit = True # Reduces VRAM by ~4×
|
||||
```
|
||||
|
||||
## CLI 用法
|
||||
|
||||
```bash
|
||||
# Single image query
|
||||
python -m llava.serve.cli \
|
||||
--model-path liuhaotian/llava-v1.5-7b \
|
||||
--image-file image.jpg \
|
||||
--query "What is in this image?"
|
||||
|
||||
# Multi-turn conversation
|
||||
python -m llava.serve.cli \
|
||||
--model-path liuhaotian/llava-v1.5-7b \
|
||||
--image-file image.jpg
|
||||
# Then type questions interactively
|
||||
```
|
||||
|
||||
## Web UI(Gradio)
|
||||
|
||||
```bash
|
||||
# Launch Gradio interface
|
||||
python -m llava.serve.gradio_web_server \
|
||||
--model-path liuhaotian/llava-v1.5-7b \
|
||||
--load-4bit # Optional: reduce VRAM
|
||||
|
||||
# Access at http://localhost:7860
|
||||
```
|
||||
|
||||
## 多轮对话
|
||||
|
||||
```python
|
||||
# Initialize conversation
|
||||
conv = conv_templates["llava_v1"].copy()
|
||||
|
||||
# Turn 1
|
||||
conv.append_message(conv.roles[0], DEFAULT_IMAGE_TOKEN + "\nWhat is in this image?")
|
||||
conv.append_message(conv.roles[1], None)
|
||||
response1 = generate(conv, model, image) # "A dog playing in a park"
|
||||
|
||||
# Turn 2
|
||||
conv.messages[-1][1] = response1 # Add previous response
|
||||
conv.append_message(conv.roles[0], "What breed is the dog?")
|
||||
conv.append_message(conv.roles[1], None)
|
||||
response2 = generate(conv, model, image) # "Golden Retriever"
|
||||
|
||||
# Turn 3
|
||||
conv.messages[-1][1] = response2
|
||||
conv.append_message(conv.roles[0], "What time of day is it?")
|
||||
conv.append_message(conv.roles[1], None)
|
||||
response3 = generate(conv, model, image)
|
||||
```
|
||||
|
||||
## 常见任务
|
||||
|
||||
### 图像字幕生成
|
||||
|
||||
```python
|
||||
question = "Describe this image in detail."
|
||||
response = ask(model, image, question)
|
||||
```
|
||||
|
||||
### 视觉问答
|
||||
|
||||
```python
|
||||
question = "How many people are in the image?"
|
||||
response = ask(model, image, question)
|
||||
```
|
||||
|
||||
### 目标检测(文本形式)
|
||||
|
||||
```python
|
||||
question = "List all the objects you can see in this image."
|
||||
response = ask(model, image, question)
|
||||
```
|
||||
|
||||
### 场景理解
|
||||
|
||||
```python
|
||||
question = "What is happening in this scene?"
|
||||
response = ask(model, image, question)
|
||||
```
|
||||
|
||||
### 文档理解
|
||||
|
||||
```python
|
||||
question = "What is the main topic of this document?"
|
||||
response = ask(model, document_image, question)
|
||||
```
|
||||
|
||||
## 训练自定义模型
|
||||
|
||||
```bash
|
||||
# Stage 1: Feature alignment (558K image-caption pairs)
|
||||
bash scripts/v1_5/pretrain.sh
|
||||
|
||||
# Stage 2: Visual instruction tuning (150K instruction data)
|
||||
bash scripts/v1_5/finetune.sh
|
||||
```
|
||||
|
||||
## 量化(降低显存占用)
|
||||
|
||||
```python
|
||||
# 4-bit quantization
|
||||
tokenizer, model, image_processor, context_len = load_pretrained_model(
|
||||
model_path="liuhaotian/llava-v1.5-13b",
|
||||
model_base=None,
|
||||
model_name=get_model_name_from_path("liuhaotian/llava-v1.5-13b"),
|
||||
load_4bit=True # Reduces VRAM ~4×
|
||||
)
|
||||
|
||||
# 8-bit quantization
|
||||
load_8bit=True # Reduces VRAM ~2×
|
||||
```
|
||||
|
||||
## 最佳实践
|
||||
|
||||
1. **从 7B 模型开始** — 质量良好,显存需求可控
|
||||
2. **使用 4-bit 量化** — 显著降低显存占用
|
||||
3. **需要 GPU** — CPU 推理极慢
|
||||
4. **清晰的 prompt** — 具体问题能获得更好的答案
|
||||
5. **多轮对话** — 保持对话上下文
|
||||
6. **温度 0.2–0.7** — 平衡创造性与一致性
|
||||
7. **`max_new_tokens` 512–1024** — 用于详细回复
|
||||
8. **批量处理** — 按顺序处理多张图像
|
||||
|
||||
## 性能
|
||||
|
||||
| 模型 | 显存(FP16) | 显存(4-bit) | 速度(tokens/s) |
|
||||
|-------|-------------|--------------|------------------|
|
||||
| 7B | ~14 GB | ~4 GB | ~20 |
|
||||
| 13B | ~28 GB | ~8 GB | ~12 |
|
||||
| 34B | ~70 GB | ~18 GB | ~5 |
|
||||
|
||||
*在 A100 GPU 上测试*
|
||||
|
||||
## 基准测试
|
||||
|
||||
LLaVA 在以下基准上取得了有竞争力的分数:
|
||||
- **VQAv2**:78.5%
|
||||
- **GQA**:62.0%
|
||||
- **MM-Vet**:35.4%
|
||||
- **MMBench**:64.3%
|
||||
|
||||
## 局限性
|
||||
|
||||
1. **幻觉** — 可能描述图像中不存在的内容
|
||||
2. **空间推理** — 难以精确定位位置
|
||||
3. **小字体文本** — 难以识别细小字体
|
||||
4. **目标计数** — 对大量目标计数不精确
|
||||
5. **显存需求** — 需要高性能 GPU
|
||||
6. **推理速度** — 比 CLIP 慢
|
||||
|
||||
## 与框架集成
|
||||
|
||||
### LangChain
|
||||
|
||||
```python
|
||||
from langchain.llms.base import LLM
|
||||
|
||||
class LLaVALLM(LLM):
|
||||
def _call(self, prompt, stop=None):
|
||||
# Custom LLaVA inference
|
||||
return response
|
||||
|
||||
llm = LLaVALLM()
|
||||
```
|
||||
|
||||
### Gradio 应用
|
||||
|
||||
```python
|
||||
import gradio as gr
|
||||
|
||||
def chat(image, text, history):
|
||||
response = ask_llava(model, image, text)
|
||||
return response
|
||||
|
||||
demo = gr.ChatInterface(
|
||||
chat,
|
||||
additional_inputs=[gr.Image(type="pil")],
|
||||
title="LLaVA Chat"
|
||||
)
|
||||
demo.launch()
|
||||
```
|
||||
|
||||
## 资源
|
||||
|
||||
- **GitHub**:https://github.com/haotian-liu/LLaVA ⭐ 23,000+
|
||||
- **论文**:https://arxiv.org/abs/2304.08485
|
||||
- **演示**:https://llava.hliu.cc
|
||||
- **模型**:https://huggingface.co/liuhaotian
|
||||
- **许可证**:Apache 2.0
|
||||
+362
@@ -0,0 +1,362 @@
|
||||
---
|
||||
title: "Modal Serverless Gpu — 用于运行 ML 工作负载的无服务器 GPU 云平台"
|
||||
sidebar_label: "Modal Serverless Gpu"
|
||||
description: "用于运行 ML 工作负载的无服务器 GPU 云平台"
|
||||
---
|
||||
|
||||
{/* This page is auto-generated from the skill's SKILL.md by website/scripts/generate-skill-docs.py. Edit the source SKILL.md, not this page. */}
|
||||
|
||||
# Modal Serverless Gpu
|
||||
|
||||
用于运行 ML 工作负载的无服务器 GPU 云平台。适用于需要按需 GPU 访问而无需管理基础设施、将 ML 模型部署为 API,或运行具有自动扩缩容的批处理作业的场景。
|
||||
|
||||
## Skill 元数据
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| 来源 | 可选 — 通过 `hermes skills install official/mlops/modal` 安装 |
|
||||
| 路径 | `optional-skills/mlops/modal` |
|
||||
| 版本 | `1.0.0` |
|
||||
| 作者 | Orchestra Research |
|
||||
| 许可证 | MIT |
|
||||
| 依赖 | `modal>=0.64.0` |
|
||||
| 平台 | linux, macos, windows |
|
||||
| 标签 | `Infrastructure`, `Serverless`, `GPU`, `Cloud`, `Deployment`, `Modal` |
|
||||
|
||||
## 参考:完整 SKILL.md
|
||||
|
||||
:::info
|
||||
以下是 Hermes 在触发此 skill 时加载的完整 skill 定义。这是 agent 在 skill 激活时所看到的指令内容。
|
||||
:::
|
||||
|
||||
# Modal Serverless GPU
|
||||
|
||||
在 Modal 无服务器 GPU 云平台上运行 ML 工作负载的完整指南。
|
||||
|
||||
## 何时使用 Modal
|
||||
|
||||
**在以下情况下使用 Modal:**
|
||||
- 运行 GPU 密集型 ML 工作负载而无需管理基础设施
|
||||
- 将 ML 模型部署为自动扩缩容 API
|
||||
- 运行批处理作业(训练、推理、数据处理)
|
||||
- 需要按秒计费的 GPU 定价,无空闲成本
|
||||
- 快速原型化 ML 应用
|
||||
- 运行定时作业(类 cron 工作负载)
|
||||
|
||||
**主要特性:**
|
||||
- **无服务器 GPU**:按需提供 T4、L4、A10G、L40S、A100、H100、H200、B200
|
||||
- **Python 原生**:用 Python 代码定义基础设施,无需 YAML
|
||||
- **自动扩缩容**:缩容至零,或瞬间扩容至 100+ 个 GPU
|
||||
- **亚秒级冷启动**:基于 Rust 的基础设施,实现快速容器启动
|
||||
- **容器缓存**:镜像层缓存,支持快速迭代
|
||||
- **Web 端点**:将函数部署为 REST API,支持零停机更新
|
||||
|
||||
**以下情况请使用替代方案:**
|
||||
- **RunPod**:适用于需要持久状态的长时间运行 pod
|
||||
- **Lambda Labs**:适用于预留 GPU 实例
|
||||
- **SkyPilot**:适用于多云编排和成本优化
|
||||
- **Kubernetes**:适用于复杂的多服务架构
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 安装
|
||||
|
||||
```bash
|
||||
pip install modal
|
||||
modal setup # Opens browser for authentication
|
||||
```
|
||||
|
||||
### GPU Hello World
|
||||
|
||||
```python
|
||||
import modal
|
||||
|
||||
app = modal.App("hello-gpu")
|
||||
|
||||
@app.function(gpu="T4")
|
||||
def gpu_info():
|
||||
import subprocess
|
||||
return subprocess.run(["nvidia-smi"], capture_output=True, text=True).stdout
|
||||
|
||||
@app.local_entrypoint()
|
||||
def main():
|
||||
print(gpu_info.remote())
|
||||
```
|
||||
|
||||
运行:`modal run hello_gpu.py`
|
||||
|
||||
### 基础推理端点
|
||||
|
||||
```python
|
||||
import modal
|
||||
|
||||
app = modal.App("text-generation")
|
||||
image = modal.Image.debian_slim().pip_install("transformers", "torch", "accelerate")
|
||||
|
||||
@app.cls(gpu="A10G", image=image)
|
||||
class TextGenerator:
|
||||
@modal.enter()
|
||||
def load_model(self):
|
||||
from transformers import pipeline
|
||||
self.pipe = pipeline("text-generation", model="gpt2", device=0)
|
||||
|
||||
@modal.method()
|
||||
def generate(self, prompt: str) -> str:
|
||||
return self.pipe(prompt, max_length=100)[0]["generated_text"]
|
||||
|
||||
@app.local_entrypoint()
|
||||
def main():
|
||||
print(TextGenerator().generate.remote("Hello, world"))
|
||||
```
|
||||
|
||||
## 核心概念
|
||||
|
||||
### 关键组件
|
||||
|
||||
| 组件 | 用途 |
|
||||
|-----------|---------|
|
||||
| `App` | 函数和资源的容器 |
|
||||
| `Function` | 带计算规格的无服务器函数 |
|
||||
| `Cls` | 带生命周期 hook 的基于类的函数 |
|
||||
| `Image` | 容器镜像定义 |
|
||||
| `Volume` | 用于模型/数据的持久存储 |
|
||||
| `Secret` | 安全凭证存储 |
|
||||
|
||||
### 执行模式
|
||||
|
||||
| 命令 | 描述 |
|
||||
|---------|-------------|
|
||||
| `modal run script.py` | 执行后退出 |
|
||||
| `modal serve script.py` | 开发模式,支持热重载 |
|
||||
| `modal deploy script.py` | 持久化云端部署 |
|
||||
|
||||
## GPU 配置
|
||||
|
||||
### 可用 GPU
|
||||
|
||||
| GPU | 显存 | 最适用于 |
|
||||
|-----|------|----------|
|
||||
| `T4` | 16GB | 经济型推理、小型模型 |
|
||||
| `L4` | 24GB | 推理,Ada Lovelace 架构 |
|
||||
| `A10G` | 24GB | 训练/推理,比 T4 快 3.3 倍 |
|
||||
| `L40S` | 48GB | 推荐用于推理(最佳性价比) |
|
||||
| `A100-40GB` | 40GB | 大型模型训练 |
|
||||
| `A100-80GB` | 80GB | 超大型模型 |
|
||||
| `H100` | 80GB | 最快,支持 FP8 + Transformer Engine |
|
||||
| `H200` | 141GB | 从 H100 自动升级,4.8TB/s 带宽 |
|
||||
| `B200` | 最新 | Blackwell 架构 |
|
||||
|
||||
### GPU 规格配置模式
|
||||
|
||||
```python
|
||||
# Single GPU
|
||||
@app.function(gpu="A100")
|
||||
|
||||
# Specific memory variant
|
||||
@app.function(gpu="A100-80GB")
|
||||
|
||||
# Multiple GPUs (up to 8)
|
||||
@app.function(gpu="H100:4")
|
||||
|
||||
# GPU with fallbacks
|
||||
@app.function(gpu=["H100", "A100", "L40S"])
|
||||
|
||||
# Any available GPU
|
||||
@app.function(gpu="any")
|
||||
```
|
||||
|
||||
## 容器镜像
|
||||
|
||||
```python
|
||||
# Basic image with pip
|
||||
image = modal.Image.debian_slim(python_version="3.11").pip_install(
|
||||
"torch==2.1.0", "transformers==4.36.0", "accelerate"
|
||||
)
|
||||
|
||||
# From CUDA base
|
||||
image = modal.Image.from_registry(
|
||||
"nvidia/cuda:12.1.0-cudnn8-devel-ubuntu22.04",
|
||||
add_python="3.11"
|
||||
).pip_install("torch", "transformers")
|
||||
|
||||
# With system packages
|
||||
image = modal.Image.debian_slim().apt_install("git", "ffmpeg").pip_install("whisper")
|
||||
```
|
||||
|
||||
## 持久存储
|
||||
|
||||
```python
|
||||
volume = modal.Volume.from_name("model-cache", create_if_missing=True)
|
||||
|
||||
@app.function(gpu="A10G", volumes={"/models": volume})
|
||||
def load_model():
|
||||
import os
|
||||
model_path = "/models/llama-7b"
|
||||
if not os.path.exists(model_path):
|
||||
model = download_model()
|
||||
model.save_pretrained(model_path)
|
||||
volume.commit() # Persist changes
|
||||
return load_from_path(model_path)
|
||||
```
|
||||
|
||||
## Web 端点
|
||||
|
||||
### FastAPI 端点装饰器
|
||||
|
||||
```python
|
||||
@app.function()
|
||||
@modal.fastapi_endpoint(method="POST")
|
||||
def predict(text: str) -> dict:
|
||||
return {"result": model.predict(text)}
|
||||
```
|
||||
|
||||
### 完整 ASGI 应用
|
||||
|
||||
```python
|
||||
from fastapi import FastAPI
|
||||
web_app = FastAPI()
|
||||
|
||||
@web_app.post("/predict")
|
||||
async def predict(text: str):
|
||||
return {"result": await model.predict.remote.aio(text)}
|
||||
|
||||
@app.function()
|
||||
@modal.asgi_app()
|
||||
def fastapi_app():
|
||||
return web_app
|
||||
```
|
||||
|
||||
### Web 端点类型
|
||||
|
||||
| 装饰器 | 使用场景 |
|
||||
|-----------|----------|
|
||||
| `@modal.fastapi_endpoint()` | 简单函数 → API |
|
||||
| `@modal.asgi_app()` | 完整 FastAPI/Starlette 应用 |
|
||||
| `@modal.wsgi_app()` | Django/Flask 应用 |
|
||||
| `@modal.web_server(port)` | 任意 HTTP 服务器 |
|
||||
|
||||
## 动态批处理
|
||||
|
||||
```python
|
||||
@app.function()
|
||||
@modal.batched(max_batch_size=32, wait_ms=100)
|
||||
async def batch_predict(inputs: list[str]) -> list[dict]:
|
||||
# Inputs automatically batched
|
||||
return model.batch_predict(inputs)
|
||||
```
|
||||
|
||||
## 密钥管理
|
||||
|
||||
```bash
|
||||
# Create secret
|
||||
modal secret create huggingface HF_TOKEN=hf_xxx
|
||||
```
|
||||
|
||||
```python
|
||||
@app.function(secrets=[modal.Secret.from_name("huggingface")])
|
||||
def download_model():
|
||||
import os
|
||||
token = os.environ["HF_TOKEN"]
|
||||
```
|
||||
|
||||
## 定时任务
|
||||
|
||||
```python
|
||||
@app.function(schedule=modal.Cron("0 0 * * *")) # Daily midnight
|
||||
def daily_job():
|
||||
pass
|
||||
|
||||
@app.function(schedule=modal.Period(hours=1))
|
||||
def hourly_job():
|
||||
pass
|
||||
```
|
||||
|
||||
## 性能优化
|
||||
|
||||
### 冷启动缓解
|
||||
|
||||
```python
|
||||
@app.function(
|
||||
container_idle_timeout=300, # Keep warm 5 min
|
||||
allow_concurrent_inputs=10, # Handle concurrent requests
|
||||
)
|
||||
def inference():
|
||||
pass
|
||||
```
|
||||
|
||||
### 模型加载最佳实践
|
||||
|
||||
```python
|
||||
@app.cls(gpu="A100")
|
||||
class Model:
|
||||
@modal.enter() # Run once at container start
|
||||
def load(self):
|
||||
self.model = load_model() # Load during warm-up
|
||||
|
||||
@modal.method()
|
||||
def predict(self, x):
|
||||
return self.model(x)
|
||||
```
|
||||
|
||||
## 并行处理
|
||||
|
||||
```python
|
||||
@app.function()
|
||||
def process_item(item):
|
||||
return expensive_computation(item)
|
||||
|
||||
@app.function()
|
||||
def run_parallel():
|
||||
items = list(range(1000))
|
||||
# Fan out to parallel containers
|
||||
results = list(process_item.map(items))
|
||||
return results
|
||||
```
|
||||
|
||||
## 常用配置
|
||||
|
||||
```python
|
||||
@app.function(
|
||||
gpu="A100",
|
||||
memory=32768, # 32GB RAM
|
||||
cpu=4, # 4 CPU cores
|
||||
timeout=3600, # 1 hour max
|
||||
container_idle_timeout=120,# Keep warm 2 min
|
||||
retries=3, # Retry on failure
|
||||
concurrency_limit=10, # Max concurrent containers
|
||||
)
|
||||
def my_function():
|
||||
pass
|
||||
```
|
||||
|
||||
## 调试
|
||||
|
||||
```python
|
||||
# Test locally
|
||||
if __name__ == "__main__":
|
||||
result = my_function.local()
|
||||
|
||||
# View logs
|
||||
# modal app logs my-app
|
||||
```
|
||||
|
||||
## 常见问题
|
||||
|
||||
| 问题 | 解决方案 |
|
||||
|-------|----------|
|
||||
| 冷启动延迟 | 增大 `container_idle_timeout`,使用 `@modal.enter()` |
|
||||
| GPU 内存溢出 | 使用更大 GPU(`A100-80GB`),启用梯度检查点 |
|
||||
| 镜像构建失败 | 固定依赖版本,检查 CUDA 兼容性 |
|
||||
| 超时错误 | 增大 `timeout`,添加检查点 |
|
||||
|
||||
## 参考资料
|
||||
|
||||
- **[高级用法](https://github.com/NousResearch/hermes-agent/blob/main/optional-skills/mlops/modal/references/advanced-usage.md)** - 多 GPU、分布式训练、成本优化
|
||||
- **[故障排查](https://github.com/NousResearch/hermes-agent/blob/main/optional-skills/mlops/modal/references/troubleshooting.md)** - 常见问题与解决方案
|
||||
|
||||
## 资源
|
||||
|
||||
- **文档**:https://modal.com/docs
|
||||
- **示例**:https://github.com/modal-labs/modal-examples
|
||||
- **定价**:https://modal.com/pricing
|
||||
- **Discord**:https://discord.gg/modal
|
||||
+401
@@ -0,0 +1,401 @@
|
||||
---
|
||||
title: "Nemo Curator — 用于 LLM 训练的 GPU 加速数据整理工具"
|
||||
sidebar_label: "Nemo Curator"
|
||||
description: "用于 LLM 训练的 GPU 加速数据整理工具"
|
||||
---
|
||||
|
||||
{/* This page is auto-generated from the skill's SKILL.md by website/scripts/generate-skill-docs.py. Edit the source SKILL.md, not this page. */}
|
||||
|
||||
# Nemo Curator
|
||||
|
||||
用于 LLM 训练的 GPU 加速数据整理工具。支持文本/图像/视频/音频。具备模糊去重(速度提升 16×)、质量过滤(30+ 启发式规则)、语义去重、PII 脱敏、NSFW 检测等功能。通过 RAPIDS 跨 GPU 扩展。适用于准备高质量训练数据集、清洗网络数据或对大型语料库去重。
|
||||
|
||||
## Skill 元数据
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| 来源 | 可选 — 通过 `hermes skills install official/mlops/nemo-curator` 安装 |
|
||||
| 路径 | `optional-skills/mlops/nemo-curator` |
|
||||
| 版本 | `1.0.0` |
|
||||
| 作者 | Orchestra Research |
|
||||
| 许可证 | MIT |
|
||||
| 依赖项 | `nemo-curator`, `cudf`, `dask`, `rapids` |
|
||||
| 平台 | linux, macos |
|
||||
| 标签 | `Data Processing`, `NeMo Curator`, `Data Curation`, `GPU Acceleration`, `Deduplication`, `Quality Filtering`, `NVIDIA`, `RAPIDS`, `PII Redaction`, `Multimodal`, `LLM Training Data` |
|
||||
|
||||
## 参考:完整 SKILL.md
|
||||
|
||||
:::info
|
||||
以下是 Hermes 在触发该 skill 时加载的完整 skill 定义。这是 agent 在 skill 激活时所看到的指令内容。
|
||||
:::
|
||||
|
||||
# NeMo Curator - GPU 加速数据整理
|
||||
|
||||
NVIDIA 用于为 LLM 准备高质量训练数据的工具包。
|
||||
|
||||
## 何时使用 NeMo Curator
|
||||
|
||||
**在以下情况下使用 NeMo Curator:**
|
||||
- 从网络抓取数据(Common Crawl)准备 LLM 训练数据
|
||||
- 需要快速去重(比 CPU 快 16×)
|
||||
- 整理多模态数据集(文本、图像、视频、音频)
|
||||
- 过滤低质量或有害内容
|
||||
- 跨 GPU 集群扩展数据处理
|
||||
|
||||
**性能**:
|
||||
- **16× 更快**的模糊去重(8TB RedPajama v2)
|
||||
- **降低 40% TCO**(总拥有成本),优于 CPU 方案
|
||||
- **近线性扩展**,跨 GPU 节点
|
||||
|
||||
**以下情况请使用替代方案**:
|
||||
- **datatrove**:基于 CPU 的开源数据处理
|
||||
- **dolma**:Allen AI 的数据工具包
|
||||
- **Ray Data**:通用 ML 数据处理(无数据整理专项功能)
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 安装
|
||||
|
||||
```bash
|
||||
# 文本整理(CUDA 12)
|
||||
uv pip install "nemo-curator[text_cuda12]"
|
||||
|
||||
# 所有模态
|
||||
uv pip install "nemo-curator[all_cuda12]"
|
||||
|
||||
# 仅 CPU(较慢)
|
||||
uv pip install "nemo-curator[cpu]"
|
||||
```
|
||||
|
||||
### 基础文本整理流水线
|
||||
|
||||
```python
|
||||
from nemo_curator import ScoreFilter, Modify
|
||||
from nemo_curator.datasets import DocumentDataset
|
||||
import pandas as pd
|
||||
|
||||
# 加载数据
|
||||
df = pd.DataFrame({"text": ["Good document", "Bad doc", "Excellent text"]})
|
||||
dataset = DocumentDataset(df)
|
||||
|
||||
# 质量过滤
|
||||
def quality_score(doc):
|
||||
return len(doc["text"].split()) > 5 # Filter short docs
|
||||
|
||||
filtered = ScoreFilter(quality_score)(dataset)
|
||||
|
||||
# 去重
|
||||
from nemo_curator.modules import ExactDuplicates
|
||||
deduped = ExactDuplicates()(filtered)
|
||||
|
||||
# 保存
|
||||
deduped.to_parquet("curated_data/")
|
||||
```
|
||||
|
||||
## 数据整理流水线
|
||||
|
||||
### 阶段 1:质量过滤
|
||||
|
||||
```python
|
||||
from nemo_curator.filters import (
|
||||
WordCountFilter,
|
||||
RepeatedLinesFilter,
|
||||
UrlRatioFilter,
|
||||
NonAlphaNumericFilter
|
||||
)
|
||||
|
||||
# 应用 30+ 启发式过滤器
|
||||
from nemo_curator import ScoreFilter
|
||||
|
||||
# 词数过滤
|
||||
dataset = dataset.filter(WordCountFilter(min_words=50, max_words=100000))
|
||||
|
||||
# 去除重复内容
|
||||
dataset = dataset.filter(RepeatedLinesFilter(max_repeated_line_fraction=0.3))
|
||||
|
||||
# URL 比例过滤
|
||||
dataset = dataset.filter(UrlRatioFilter(max_url_ratio=0.2))
|
||||
```
|
||||
|
||||
### 阶段 2:去重
|
||||
|
||||
**精确去重**:
|
||||
```python
|
||||
from nemo_curator.modules import ExactDuplicates
|
||||
|
||||
# 删除完全重复项
|
||||
deduped = ExactDuplicates(id_field="id", text_field="text")(dataset)
|
||||
```
|
||||
|
||||
**模糊去重**(GPU 上速度提升 16×):
|
||||
```python
|
||||
from nemo_curator.modules import FuzzyDuplicates
|
||||
|
||||
# MinHash + LSH 去重
|
||||
fuzzy_dedup = FuzzyDuplicates(
|
||||
id_field="id",
|
||||
text_field="text",
|
||||
num_hashes=260, # MinHash parameters
|
||||
num_buckets=20,
|
||||
hash_method="md5"
|
||||
)
|
||||
|
||||
deduped = fuzzy_dedup(dataset)
|
||||
```
|
||||
|
||||
**语义去重**:
|
||||
```python
|
||||
from nemo_curator.modules import SemanticDuplicates
|
||||
|
||||
# 基于 embedding(向量嵌入)的去重
|
||||
semantic_dedup = SemanticDuplicates(
|
||||
id_field="id",
|
||||
text_field="text",
|
||||
embedding_model="sentence-transformers/all-MiniLM-L6-v2",
|
||||
threshold=0.8 # Cosine similarity threshold
|
||||
)
|
||||
|
||||
deduped = semantic_dedup(dataset)
|
||||
```
|
||||
|
||||
### 阶段 3:PII 脱敏
|
||||
|
||||
```python
|
||||
from nemo_curator.modules import Modify
|
||||
from nemo_curator.modifiers import PIIRedactor
|
||||
|
||||
# 脱敏个人身份信息(PII)
|
||||
pii_redactor = PIIRedactor(
|
||||
supported_entities=["EMAIL_ADDRESS", "PHONE_NUMBER", "PERSON", "LOCATION"],
|
||||
anonymize_action="replace" # or "redact"
|
||||
)
|
||||
|
||||
redacted = Modify(pii_redactor)(dataset)
|
||||
```
|
||||
|
||||
### 阶段 4:分类器过滤
|
||||
|
||||
```python
|
||||
from nemo_curator.classifiers import QualityClassifier
|
||||
|
||||
# 质量分类
|
||||
quality_clf = QualityClassifier(
|
||||
model_path="nvidia/quality-classifier-deberta",
|
||||
batch_size=256,
|
||||
device="cuda"
|
||||
)
|
||||
|
||||
# 过滤低质量文档
|
||||
high_quality = dataset.filter(lambda doc: quality_clf(doc["text"]) > 0.5)
|
||||
```
|
||||
|
||||
## GPU 加速
|
||||
|
||||
### GPU 与 CPU 性能对比
|
||||
|
||||
| 操作 | CPU(16 核) | GPU(A100) | 加速比 |
|
||||
|-----------|----------------|------------|---------|
|
||||
| 模糊去重(8TB) | 120 小时 | 7.5 小时 | 16× |
|
||||
| 精确去重(1TB) | 8 小时 | 0.5 小时 | 16× |
|
||||
| 质量过滤 | 2 小时 | 0.2 小时 | 10× |
|
||||
|
||||
### 多 GPU 扩展
|
||||
|
||||
```python
|
||||
from nemo_curator import get_client
|
||||
import dask_cuda
|
||||
|
||||
# 初始化 GPU 集群
|
||||
client = get_client(cluster_type="gpu", n_workers=8)
|
||||
|
||||
# 使用 8 块 GPU 处理
|
||||
deduped = FuzzyDuplicates(...)(dataset)
|
||||
```
|
||||
|
||||
## 多模态数据整理
|
||||
|
||||
### 图像整理
|
||||
|
||||
```python
|
||||
from nemo_curator.image import (
|
||||
AestheticFilter,
|
||||
NSFWFilter,
|
||||
CLIPEmbedder
|
||||
)
|
||||
|
||||
# 美学评分
|
||||
aesthetic_filter = AestheticFilter(threshold=5.0)
|
||||
filtered_images = aesthetic_filter(image_dataset)
|
||||
|
||||
# NSFW 检测
|
||||
nsfw_filter = NSFWFilter(threshold=0.9)
|
||||
safe_images = nsfw_filter(filtered_images)
|
||||
|
||||
# 生成 CLIP embedding
|
||||
clip_embedder = CLIPEmbedder(model="openai/clip-vit-base-patch32")
|
||||
image_embeddings = clip_embedder(safe_images)
|
||||
```
|
||||
|
||||
### 视频整理
|
||||
|
||||
```python
|
||||
from nemo_curator.video import (
|
||||
SceneDetector,
|
||||
ClipExtractor,
|
||||
InternVideo2Embedder
|
||||
)
|
||||
|
||||
# 场景检测
|
||||
scene_detector = SceneDetector(threshold=27.0)
|
||||
scenes = scene_detector(video_dataset)
|
||||
|
||||
# 提取片段
|
||||
clip_extractor = ClipExtractor(min_duration=2.0, max_duration=10.0)
|
||||
clips = clip_extractor(scenes)
|
||||
|
||||
# 生成 embedding
|
||||
video_embedder = InternVideo2Embedder()
|
||||
video_embeddings = video_embedder(clips)
|
||||
```
|
||||
|
||||
### 音频整理
|
||||
|
||||
```python
|
||||
from nemo_curator.audio import (
|
||||
ASRInference,
|
||||
WERFilter,
|
||||
DurationFilter
|
||||
)
|
||||
|
||||
# ASR 转录
|
||||
asr = ASRInference(model="nvidia/stt_en_fastconformer_hybrid_large_pc")
|
||||
transcribed = asr(audio_dataset)
|
||||
|
||||
# 按 WER(词错误率)过滤
|
||||
wer_filter = WERFilter(max_wer=0.3)
|
||||
high_quality_audio = wer_filter(transcribed)
|
||||
|
||||
# 时长过滤
|
||||
duration_filter = DurationFilter(min_duration=1.0, max_duration=30.0)
|
||||
filtered_audio = duration_filter(high_quality_audio)
|
||||
```
|
||||
|
||||
## 常见模式
|
||||
|
||||
### 网络抓取数据整理(Common Crawl)
|
||||
|
||||
```python
|
||||
from nemo_curator import ScoreFilter, Modify
|
||||
from nemo_curator.filters import *
|
||||
from nemo_curator.modules import *
|
||||
from nemo_curator.datasets import DocumentDataset
|
||||
|
||||
# 加载 Common Crawl 数据
|
||||
dataset = DocumentDataset.read_parquet("common_crawl/*.parquet")
|
||||
|
||||
# 流水线
|
||||
pipeline = [
|
||||
# 1. 质量过滤
|
||||
WordCountFilter(min_words=100, max_words=50000),
|
||||
RepeatedLinesFilter(max_repeated_line_fraction=0.2),
|
||||
SymbolToWordRatioFilter(max_symbol_to_word_ratio=0.3),
|
||||
UrlRatioFilter(max_url_ratio=0.3),
|
||||
|
||||
# 2. 语言过滤
|
||||
LanguageIdentificationFilter(target_languages=["en"]),
|
||||
|
||||
# 3. 去重
|
||||
ExactDuplicates(id_field="id", text_field="text"),
|
||||
FuzzyDuplicates(id_field="id", text_field="text", num_hashes=260),
|
||||
|
||||
# 4. PII 脱敏
|
||||
PIIRedactor(),
|
||||
|
||||
# 5. NSFW 过滤
|
||||
NSFWClassifier(threshold=0.8)
|
||||
]
|
||||
|
||||
# 执行
|
||||
for stage in pipeline:
|
||||
dataset = stage(dataset)
|
||||
|
||||
# 保存
|
||||
dataset.to_parquet("curated_common_crawl/")
|
||||
```
|
||||
|
||||
### 分布式处理
|
||||
|
||||
```python
|
||||
from nemo_curator import get_client
|
||||
from dask_cuda import LocalCUDACluster
|
||||
|
||||
# 多 GPU 集群
|
||||
cluster = LocalCUDACluster(n_workers=8)
|
||||
client = get_client(cluster=cluster)
|
||||
|
||||
# 处理大型数据集
|
||||
dataset = DocumentDataset.read_parquet("s3://large_dataset/*.parquet")
|
||||
deduped = FuzzyDuplicates(...)(dataset)
|
||||
|
||||
# 清理
|
||||
client.close()
|
||||
cluster.close()
|
||||
```
|
||||
|
||||
## 性能基准
|
||||
|
||||
### 模糊去重(8TB RedPajama v2)
|
||||
|
||||
- **CPU(256 核)**:120 小时
|
||||
- **GPU(8× A100)**:7.5 小时
|
||||
- **加速比**:16×
|
||||
|
||||
### 精确去重(1TB)
|
||||
|
||||
- **CPU(64 核)**:8 小时
|
||||
- **GPU(4× A100)**:0.5 小时
|
||||
- **加速比**:16×
|
||||
|
||||
### 质量过滤(100GB)
|
||||
|
||||
- **CPU(32 核)**:2 小时
|
||||
- **GPU(2× A100)**:0.2 小时
|
||||
- **加速比**:10×
|
||||
|
||||
## 成本对比
|
||||
|
||||
**基于 CPU 的数据整理**(AWS c5.18xlarge × 10):
|
||||
- 费用:$3.60/小时 × 10 = $36/小时
|
||||
- 处理 8TB 耗时:120 小时
|
||||
- **合计**:$4,320
|
||||
|
||||
**基于 GPU 的数据整理**(AWS p4d.24xlarge × 2):
|
||||
- 费用:$32.77/小时 × 2 = $65.54/小时
|
||||
- 处理 8TB 耗时:7.5 小时
|
||||
- **合计**:$491.55
|
||||
|
||||
**节省**:降低 89%(节省 $3,828)
|
||||
|
||||
## 支持的数据格式
|
||||
|
||||
- **输入**:Parquet、JSONL、CSV
|
||||
- **输出**:Parquet(推荐)、JSONL
|
||||
- **WebDataset**:用于多模态的 TAR 归档
|
||||
|
||||
## 使用场景
|
||||
|
||||
**生产部署**:
|
||||
- NVIDIA 使用 NeMo Curator 准备 Nemotron-4 训练数据
|
||||
- 已整理的开源数据集:RedPajama v2、The Pile
|
||||
|
||||
## 参考资料
|
||||
|
||||
- **[过滤指南](https://github.com/NousResearch/hermes-agent/blob/main/optional-skills/mlops/nemo-curator/references/filtering.md)** - 30+ 质量过滤器与启发式规则
|
||||
- **[去重指南](https://github.com/NousResearch/hermes-agent/blob/main/optional-skills/mlops/nemo-curator/references/deduplication.md)** - 精确、模糊、语义去重方法
|
||||
|
||||
## 资源
|
||||
|
||||
- **GitHub**:https://github.com/NVIDIA/NeMo-Curator ⭐ 500+
|
||||
- **文档**:https://docs.nvidia.com/nemo-framework/user-guide/latest/datacuration/
|
||||
- **版本**:0.4.0+
|
||||
- **许可证**:Apache 2.0
|
||||
+452
@@ -0,0 +1,452 @@
|
||||
---
|
||||
title: "Peft Fine Tuning — 使用 LoRA、QLoRA 及 25+ 种方法对 LLM 进行参数高效微调"
|
||||
sidebar_label: "Peft Fine Tuning"
|
||||
description: "使用 LoRA、QLoRA 及 25+ 种方法对 LLM 进行参数高效微调"
|
||||
---
|
||||
|
||||
{/* This page is auto-generated from the skill's SKILL.md by website/scripts/generate-skill-docs.py. Edit the source SKILL.md, not this page. */}
|
||||
|
||||
# Peft Fine Tuning
|
||||
|
||||
使用 LoRA、QLoRA 及 25+ 种方法对 LLM 进行参数高效微调(Parameter-efficient fine-tuning)。适用场景:在显存有限的情况下微调大型模型(7B–70B)、需要以极低精度损失训练不足 1% 的参数,或用于多适配器(multi-adapter)服务。HuggingFace 官方库,与 transformers 生态深度集成。
|
||||
|
||||
## Skill 元数据
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| 来源 | 可选 — 通过 `hermes skills install official/mlops/peft` 安装 |
|
||||
| 路径 | `optional-skills/mlops/peft` |
|
||||
| 版本 | `1.0.0` |
|
||||
| 作者 | Orchestra Research |
|
||||
| 许可证 | MIT |
|
||||
| 依赖 | `peft>=0.13.0`, `transformers>=4.45.0`, `torch>=2.0.0`, `bitsandbytes>=0.43.0` |
|
||||
| 平台 | linux, macos, windows |
|
||||
| 标签 | `Fine-Tuning`, `PEFT`, `LoRA`, `QLoRA`, `Parameter-Efficient`, `Adapters`, `Low-Rank`, `Memory Optimization`, `Multi-Adapter` |
|
||||
|
||||
## 参考:完整 SKILL.md
|
||||
|
||||
:::info
|
||||
以下是 Hermes 在触发该 skill 时加载的完整 skill 定义。这是 agent 在 skill 激活时所看到的指令内容。
|
||||
:::
|
||||
|
||||
# PEFT(参数高效微调)
|
||||
|
||||
通过 LoRA、QLoRA 及 25+ 种适配器方法,仅训练不足 1% 的参数来微调 LLM。
|
||||
|
||||
## 何时使用 PEFT
|
||||
|
||||
**在以下情况使用 PEFT/LoRA:**
|
||||
- 在消费级 GPU(RTX 4090、A100)上微调 7B–70B 模型
|
||||
- 需要训练不足 1% 的参数(6MB 适配器 vs 14GB 完整模型)
|
||||
- 希望通过多个任务专属适配器快速迭代
|
||||
- 从单一基础模型部署多个微调变体
|
||||
|
||||
**在以下情况使用 QLoRA(PEFT + 量化):**
|
||||
- 在单张 24GB GPU 上微调 70B 模型
|
||||
- 显存是主要瓶颈
|
||||
- 可接受相比完整微调约 5% 的质量损失
|
||||
|
||||
**在以下情况改用完整微调:**
|
||||
- 训练小型模型(参数量 < 1B)
|
||||
- 需要最高质量且有充足算力预算
|
||||
- 显著的领域偏移需要更新全部权重
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 安装
|
||||
|
||||
```bash
|
||||
# 基础安装
|
||||
pip install peft
|
||||
|
||||
# 含量化支持(推荐)
|
||||
pip install peft bitsandbytes
|
||||
|
||||
# 完整工具栈
|
||||
pip install peft transformers accelerate bitsandbytes datasets
|
||||
```
|
||||
|
||||
### LoRA 微调(标准方式)
|
||||
|
||||
```python
|
||||
from transformers import AutoModelForCausalLM, AutoTokenizer, TrainingArguments, Trainer
|
||||
from peft import get_peft_model, LoraConfig, TaskType
|
||||
from datasets import load_dataset
|
||||
|
||||
# 加载基础模型
|
||||
model_name = "meta-llama/Llama-3.1-8B"
|
||||
model = AutoModelForCausalLM.from_pretrained(model_name, torch_dtype="auto", device_map="auto")
|
||||
tokenizer = AutoTokenizer.from_pretrained(model_name)
|
||||
tokenizer.pad_token = tokenizer.eos_token
|
||||
|
||||
# LoRA 配置
|
||||
lora_config = LoraConfig(
|
||||
task_type=TaskType.CAUSAL_LM,
|
||||
r=16, # 秩(Rank),范围 8-64,越高容量越大
|
||||
lora_alpha=32, # 缩放因子(通常为 2*r)
|
||||
lora_dropout=0.05, # 正则化 dropout
|
||||
target_modules=["q_proj", "v_proj", "k_proj", "o_proj"], # 注意力层
|
||||
bias="none" # 不训练偏置项
|
||||
)
|
||||
|
||||
# 应用 LoRA
|
||||
model = get_peft_model(model, lora_config)
|
||||
model.print_trainable_parameters()
|
||||
# 输出:trainable params: 13,631,488 || all params: 8,043,307,008 || trainable%: 0.17%
|
||||
|
||||
# 准备数据集
|
||||
dataset = load_dataset("databricks/databricks-dolly-15k", split="train")
|
||||
|
||||
def tokenize(example):
|
||||
text = f"### Instruction:\n{example['instruction']}\n\n### Response:\n{example['response']}"
|
||||
return tokenizer(text, truncation=True, max_length=512, padding="max_length")
|
||||
|
||||
tokenized = dataset.map(tokenize, remove_columns=dataset.column_names)
|
||||
|
||||
# 训练
|
||||
training_args = TrainingArguments(
|
||||
output_dir="./lora-llama",
|
||||
num_train_epochs=3,
|
||||
per_device_train_batch_size=4,
|
||||
gradient_accumulation_steps=4,
|
||||
learning_rate=2e-4,
|
||||
fp16=True,
|
||||
logging_steps=10,
|
||||
save_strategy="epoch"
|
||||
)
|
||||
|
||||
trainer = Trainer(
|
||||
model=model,
|
||||
args=training_args,
|
||||
train_dataset=tokenized,
|
||||
data_collator=lambda data: {"input_ids": torch.stack([f["input_ids"] for f in data]),
|
||||
"attention_mask": torch.stack([f["attention_mask"] for f in data]),
|
||||
"labels": torch.stack([f["input_ids"] for f in data])}
|
||||
)
|
||||
|
||||
trainer.train()
|
||||
|
||||
# 仅保存适配器(6MB vs 16GB)
|
||||
model.save_pretrained("./lora-llama-adapter")
|
||||
```
|
||||
|
||||
### QLoRA 微调(显存高效方式)
|
||||
|
||||
```python
|
||||
from transformers import AutoModelForCausalLM, BitsAndBytesConfig
|
||||
from peft import get_peft_model, LoraConfig, prepare_model_for_kbit_training
|
||||
|
||||
# 4-bit 量化配置
|
||||
bnb_config = BitsAndBytesConfig(
|
||||
load_in_4bit=True,
|
||||
bnb_4bit_quant_type="nf4", # NormalFloat4(最适合 LLM)
|
||||
bnb_4bit_compute_dtype="bfloat16", # 以 bf16 计算
|
||||
bnb_4bit_use_double_quant=True # 嵌套量化
|
||||
)
|
||||
|
||||
# 加载量化模型
|
||||
model = AutoModelForCausalLM.from_pretrained(
|
||||
"meta-llama/Llama-3.1-70B",
|
||||
quantization_config=bnb_config,
|
||||
device_map="auto"
|
||||
)
|
||||
|
||||
# 为训练做准备(启用梯度检查点)
|
||||
model = prepare_model_for_kbit_training(model)
|
||||
|
||||
# QLoRA 的 LoRA 配置
|
||||
lora_config = LoraConfig(
|
||||
r=64, # 70B 模型使用更高秩
|
||||
lora_alpha=128,
|
||||
lora_dropout=0.1,
|
||||
target_modules=["q_proj", "v_proj", "k_proj", "o_proj", "gate_proj", "up_proj", "down_proj"],
|
||||
bias="none",
|
||||
task_type="CAUSAL_LM"
|
||||
)
|
||||
|
||||
model = get_peft_model(model, lora_config)
|
||||
# 70B 模型现在可在单张 24GB GPU 上运行!
|
||||
```
|
||||
|
||||
## LoRA 参数选择
|
||||
|
||||
### 秩(r)——容量与效率的权衡
|
||||
|
||||
| 秩 | 可训练参数量 | 显存 | 质量 | 适用场景 |
|
||||
|------|-----------------|--------|---------|----------|
|
||||
| 4 | ~3M | 极低 | 较低 | 简单任务、原型验证 |
|
||||
| **8** | ~7M | 低 | 良好 | **推荐起始点** |
|
||||
| **16** | ~14M | 中等 | 更好 | **通用微调** |
|
||||
| 32 | ~27M | 较高 | 高 | 复杂任务 |
|
||||
| 64 | ~54M | 高 | 最高 | 领域适配、70B 模型 |
|
||||
|
||||
### Alpha(lora_alpha)——缩放因子
|
||||
|
||||
```python
|
||||
# 经验法则:alpha = 2 * rank
|
||||
LoraConfig(r=16, lora_alpha=32) # 标准
|
||||
LoraConfig(r=16, lora_alpha=16) # 保守(学习率效果较低)
|
||||
LoraConfig(r=16, lora_alpha=64) # 激进(学习率效果较高)
|
||||
```
|
||||
|
||||
### 按架构选择目标模块
|
||||
|
||||
```python
|
||||
# Llama / Mistral / Qwen
|
||||
target_modules = ["q_proj", "v_proj", "k_proj", "o_proj", "gate_proj", "up_proj", "down_proj"]
|
||||
|
||||
# GPT-2 / GPT-Neo
|
||||
target_modules = ["c_attn", "c_proj", "c_fc"]
|
||||
|
||||
# Falcon
|
||||
target_modules = ["query_key_value", "dense", "dense_h_to_4h", "dense_4h_to_h"]
|
||||
|
||||
# BLOOM
|
||||
target_modules = ["query_key_value", "dense", "dense_h_to_4h", "dense_4h_to_h"]
|
||||
|
||||
# 自动检测所有线性层
|
||||
target_modules = "all-linear" # PEFT 0.6.0+
|
||||
```
|
||||
|
||||
## 加载与合并适配器
|
||||
|
||||
### 加载已训练的适配器
|
||||
|
||||
```python
|
||||
from peft import PeftModel, AutoPeftModelForCausalLM
|
||||
from transformers import AutoModelForCausalLM
|
||||
|
||||
# 方式一:使用 PeftModel 加载
|
||||
base_model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-3.1-8B")
|
||||
model = PeftModel.from_pretrained(base_model, "./lora-llama-adapter")
|
||||
|
||||
# 方式二:直接加载(推荐)
|
||||
model = AutoPeftModelForCausalLM.from_pretrained(
|
||||
"./lora-llama-adapter",
|
||||
device_map="auto"
|
||||
)
|
||||
```
|
||||
|
||||
### 将适配器合并到基础模型
|
||||
|
||||
```python
|
||||
# 合并以用于部署(无适配器开销)
|
||||
merged_model = model.merge_and_unload()
|
||||
|
||||
# 保存合并后的模型
|
||||
merged_model.save_pretrained("./llama-merged")
|
||||
tokenizer.save_pretrained("./llama-merged")
|
||||
|
||||
# 推送到 Hub
|
||||
merged_model.push_to_hub("username/llama-finetuned")
|
||||
```
|
||||
|
||||
### 多适配器服务
|
||||
|
||||
```python
|
||||
from peft import PeftModel
|
||||
|
||||
# 加载基础模型及第一个适配器
|
||||
model = AutoPeftModelForCausalLM.from_pretrained("./adapter-task1")
|
||||
|
||||
# 加载额外适配器
|
||||
model.load_adapter("./adapter-task2", adapter_name="task2")
|
||||
model.load_adapter("./adapter-task3", adapter_name="task3")
|
||||
|
||||
# 运行时切换适配器
|
||||
model.set_adapter("task1") # 使用 task1 适配器
|
||||
output1 = model.generate(**inputs)
|
||||
|
||||
model.set_adapter("task2") # 切换到 task2
|
||||
output2 = model.generate(**inputs)
|
||||
|
||||
# 禁用适配器(使用基础模型)
|
||||
with model.disable_adapter():
|
||||
base_output = model.generate(**inputs)
|
||||
```
|
||||
|
||||
## PEFT 方法对比
|
||||
|
||||
| 方法 | 可训练参数占比 | 显存 | 速度 | 最适场景 |
|
||||
|--------|------------|--------|-------|----------|
|
||||
| **LoRA** | 0.1–1% | 低 | 快 | 通用微调 |
|
||||
| **QLoRA** | 0.1–1% | 极低 | 中等 | 显存受限场景 |
|
||||
| AdaLoRA | 0.1–1% | 低 | 中等 | 自动秩选择 |
|
||||
| IA3 | 0.01% | 极小 | 最快 | 少样本适配 |
|
||||
| Prefix Tuning | 0.1% | 低 | 中等 | 生成控制 |
|
||||
| Prompt Tuning | 0.001% | 极小 | 快 | 简单任务适配 |
|
||||
| P-Tuning v2 | 0.1% | 低 | 中等 | NLU 任务 |
|
||||
|
||||
### IA3(最少参数)
|
||||
|
||||
```python
|
||||
from peft import IA3Config
|
||||
|
||||
ia3_config = IA3Config(
|
||||
target_modules=["q_proj", "v_proj", "k_proj", "down_proj"],
|
||||
feedforward_modules=["down_proj"]
|
||||
)
|
||||
model = get_peft_model(model, ia3_config)
|
||||
# 仅训练 0.01% 的参数!
|
||||
```
|
||||
|
||||
### Prefix Tuning
|
||||
|
||||
```python
|
||||
from peft import PrefixTuningConfig
|
||||
|
||||
prefix_config = PrefixTuningConfig(
|
||||
task_type="CAUSAL_LM",
|
||||
num_virtual_tokens=20, # 前置 token 数量
|
||||
prefix_projection=True # 使用 MLP 投影
|
||||
)
|
||||
model = get_peft_model(model, prefix_config)
|
||||
```
|
||||
|
||||
## 集成模式
|
||||
|
||||
### 与 TRL(SFTTrainer)集成
|
||||
|
||||
```python
|
||||
from trl import SFTTrainer, SFTConfig
|
||||
from peft import LoraConfig
|
||||
|
||||
lora_config = LoraConfig(r=16, lora_alpha=32, target_modules="all-linear")
|
||||
|
||||
trainer = SFTTrainer(
|
||||
model=model,
|
||||
args=SFTConfig(output_dir="./output", max_seq_length=512),
|
||||
train_dataset=dataset,
|
||||
peft_config=lora_config, # 直接传入 LoRA 配置
|
||||
)
|
||||
trainer.train()
|
||||
```
|
||||
|
||||
### 与 Axolotl(YAML 配置)集成
|
||||
|
||||
```yaml
|
||||
# axolotl config.yaml
|
||||
adapter: lora
|
||||
lora_r: 16
|
||||
lora_alpha: 32
|
||||
lora_dropout: 0.05
|
||||
lora_target_modules:
|
||||
- q_proj
|
||||
- v_proj
|
||||
- k_proj
|
||||
- o_proj
|
||||
lora_target_linear: true # 针对所有线性层
|
||||
```
|
||||
|
||||
### 与 vLLM(推理)集成
|
||||
|
||||
```python
|
||||
from vllm import LLM
|
||||
from vllm.lora.request import LoRARequest
|
||||
|
||||
# 加载支持 LoRA 的基础模型
|
||||
llm = LLM(model="meta-llama/Llama-3.1-8B", enable_lora=True)
|
||||
|
||||
# 使用适配器进行推理
|
||||
outputs = llm.generate(
|
||||
prompts,
|
||||
lora_request=LoRARequest("adapter1", 1, "./lora-adapter")
|
||||
)
|
||||
```
|
||||
|
||||
## 性能基准
|
||||
|
||||
### 显存占用(Llama 3.1 8B)
|
||||
|
||||
| 方法 | GPU 显存 | 可训练参数量 |
|
||||
|--------|-----------|------------------|
|
||||
| 完整微调 | 60+ GB | 8B(100%) |
|
||||
| LoRA r=16 | 18 GB | 14M(0.17%) |
|
||||
| QLoRA r=16 | 6 GB | 14M(0.17%) |
|
||||
| IA3 | 16 GB | 800K(0.01%) |
|
||||
|
||||
### 训练速度(A100 80GB)
|
||||
|
||||
| 方法 | Tokens/秒 | 相对完整微调 |
|
||||
|--------|-----------|------------|
|
||||
| 完整微调 | 2,500 | 1x |
|
||||
| LoRA | 3,200 | 1.3x |
|
||||
| QLoRA | 2,100 | 0.84x |
|
||||
|
||||
### 质量(MMLU 基准)
|
||||
|
||||
| 模型 | 完整微调 | LoRA | QLoRA |
|
||||
|-------|---------|------|-------|
|
||||
| Llama 2-7B | 45.3 | 44.8 | 44.1 |
|
||||
| Llama 2-13B | 54.8 | 54.2 | 53.5 |
|
||||
|
||||
## 常见问题
|
||||
|
||||
### 训练时 CUDA 显存不足(OOM)
|
||||
|
||||
```python
|
||||
# 方案一:启用梯度检查点
|
||||
model.gradient_checkpointing_enable()
|
||||
|
||||
# 方案二:减小批大小 + 增大梯度累积步数
|
||||
TrainingArguments(
|
||||
per_device_train_batch_size=1,
|
||||
gradient_accumulation_steps=16
|
||||
)
|
||||
|
||||
# 方案三:使用 QLoRA
|
||||
from transformers import BitsAndBytesConfig
|
||||
bnb_config = BitsAndBytesConfig(load_in_4bit=True, bnb_4bit_quant_type="nf4")
|
||||
```
|
||||
|
||||
### 适配器未生效
|
||||
|
||||
```python
|
||||
# 验证适配器是否激活
|
||||
print(model.active_adapters) # 应显示适配器名称
|
||||
|
||||
# 检查可训练参数
|
||||
model.print_trainable_parameters()
|
||||
|
||||
# 确保模型处于训练模式
|
||||
model.train()
|
||||
```
|
||||
|
||||
### 质量下降
|
||||
|
||||
```python
|
||||
# 提高秩
|
||||
LoraConfig(r=32, lora_alpha=64)
|
||||
|
||||
# 针对更多模块
|
||||
target_modules = "all-linear"
|
||||
|
||||
# 使用更多训练数据和更多轮次
|
||||
TrainingArguments(num_train_epochs=5)
|
||||
|
||||
# 降低学习率
|
||||
TrainingArguments(learning_rate=1e-4)
|
||||
```
|
||||
|
||||
## 最佳实践
|
||||
|
||||
1. **从 r=8–16 开始**,质量不足时再提高
|
||||
2. **以 alpha = 2 * rank 为起始点**
|
||||
3. **同时针对注意力层和 MLP 层**以获得最佳质量/效率比
|
||||
4. **启用梯度检查点**以节省显存
|
||||
5. **频繁保存适配器**(文件小,便于回滚)
|
||||
6. **合并前在留出数据上评估**
|
||||
7. **70B+ 模型在消费级硬件上使用 QLoRA**
|
||||
|
||||
## 参考资料
|
||||
|
||||
- **[高级用法](https://github.com/NousResearch/hermes-agent/blob/main/optional-skills/mlops/peft/references/advanced-usage.md)** — DoRA、LoftQ、秩稳定化、自定义模块
|
||||
- **[故障排查](https://github.com/NousResearch/hermes-agent/blob/main/optional-skills/mlops/peft/references/troubleshooting.md)** — 常见错误、调试、优化
|
||||
|
||||
## 资源
|
||||
|
||||
- **GitHub**:https://github.com/huggingface/peft
|
||||
- **文档**:https://huggingface.co/docs/peft
|
||||
- **LoRA 论文**:arXiv:2106.09685
|
||||
- **QLoRA 论文**:arXiv:2305.14314
|
||||
- **模型**:https://huggingface.co/models?library=peft
|
||||
+377
@@ -0,0 +1,377 @@
|
||||
---
|
||||
title: "Pinecone — 面向生产级 AI 应用的托管向量数据库"
|
||||
sidebar_label: "Pinecone"
|
||||
description: "面向生产级 AI 应用的托管向量数据库"
|
||||
---
|
||||
|
||||
{/* This page is auto-generated from the skill's SKILL.md by website/scripts/generate-skill-docs.py. Edit the source SKILL.md, not this page. */}
|
||||
|
||||
# Pinecone
|
||||
|
||||
面向生产级 AI 应用的托管向量数据库。全托管、自动扩缩容,支持混合搜索(稠密 + 稀疏向量)、元数据过滤和命名空间。低延迟(<100ms p95)。适用于生产级 RAG、推荐系统或大规模语义搜索。最适合 serverless(无服务器)托管基础设施。
|
||||
|
||||
## Skill 元数据
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| 来源 | 可选 — 通过 `hermes skills install official/mlops/pinecone` 安装 |
|
||||
| 路径 | `optional-skills/mlops/pinecone` |
|
||||
| 版本 | `1.0.0` |
|
||||
| 作者 | Orchestra Research |
|
||||
| 许可证 | MIT |
|
||||
| 依赖 | `pinecone-client` |
|
||||
| 平台 | linux, macos, windows |
|
||||
| 标签 | `RAG`, `Pinecone`, `Vector Database`, `Managed Service`, `Serverless`, `Hybrid Search`, `Production`, `Auto-Scaling`, `Low Latency`, `Recommendations` |
|
||||
|
||||
## 参考:完整 SKILL.md
|
||||
|
||||
:::info
|
||||
以下是 Hermes 在触发此 skill 时加载的完整 skill 定义。这是 skill 激活时 agent 所看到的指令内容。
|
||||
:::
|
||||
|
||||
# Pinecone - 托管向量数据库
|
||||
|
||||
面向生产级 AI 应用的向量数据库。
|
||||
|
||||
## 何时使用 Pinecone
|
||||
|
||||
**适用场景:**
|
||||
- 需要托管的 serverless 向量数据库
|
||||
- 生产级 RAG 应用
|
||||
- 需要自动扩缩容
|
||||
- 对低延迟有严格要求(<100ms)
|
||||
- 不想自行管理基础设施
|
||||
- 需要混合搜索(稠密 + 稀疏向量)
|
||||
|
||||
**指标**:
|
||||
- 全托管 SaaS
|
||||
- 自动扩缩容至数十亿向量
|
||||
- **p95 延迟 <100ms**
|
||||
- 99.9% 正常运行时间 SLA
|
||||
|
||||
**改用其他方案的场景**:
|
||||
- **Chroma**:自托管、开源
|
||||
- **FAISS**:离线、纯相似度搜索
|
||||
- **Weaviate**:自托管、功能更丰富
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 安装
|
||||
|
||||
```bash
|
||||
pip install pinecone-client
|
||||
```
|
||||
|
||||
### 基本用法
|
||||
|
||||
```python
|
||||
from pinecone import Pinecone, ServerlessSpec
|
||||
|
||||
# Initialize
|
||||
pc = Pinecone(api_key="your-api-key")
|
||||
|
||||
# Create index
|
||||
pc.create_index(
|
||||
name="my-index",
|
||||
dimension=1536, # Must match embedding dimension
|
||||
metric="cosine", # or "euclidean", "dotproduct"
|
||||
spec=ServerlessSpec(cloud="aws", region="us-east-1")
|
||||
)
|
||||
|
||||
# Connect to index
|
||||
index = pc.Index("my-index")
|
||||
|
||||
# Upsert vectors
|
||||
index.upsert(vectors=[
|
||||
{"id": "vec1", "values": [0.1, 0.2, ...], "metadata": {"category": "A"}},
|
||||
{"id": "vec2", "values": [0.3, 0.4, ...], "metadata": {"category": "B"}}
|
||||
])
|
||||
|
||||
# Query
|
||||
results = index.query(
|
||||
vector=[0.1, 0.2, ...],
|
||||
top_k=5,
|
||||
include_metadata=True
|
||||
)
|
||||
|
||||
print(results["matches"])
|
||||
```
|
||||
|
||||
## 核心操作
|
||||
|
||||
### 创建索引
|
||||
|
||||
```python
|
||||
# Serverless (recommended)
|
||||
pc.create_index(
|
||||
name="my-index",
|
||||
dimension=1536,
|
||||
metric="cosine",
|
||||
spec=ServerlessSpec(
|
||||
cloud="aws", # or "gcp", "azure"
|
||||
region="us-east-1"
|
||||
)
|
||||
)
|
||||
|
||||
# Pod-based (for consistent performance)
|
||||
from pinecone import PodSpec
|
||||
|
||||
pc.create_index(
|
||||
name="my-index",
|
||||
dimension=1536,
|
||||
metric="cosine",
|
||||
spec=PodSpec(
|
||||
environment="us-east1-gcp",
|
||||
pod_type="p1.x1"
|
||||
)
|
||||
)
|
||||
```
|
||||
|
||||
### 插入向量(Upsert)
|
||||
|
||||
```python
|
||||
# Single upsert
|
||||
index.upsert(vectors=[
|
||||
{
|
||||
"id": "doc1",
|
||||
"values": [0.1, 0.2, ...], # 1536 dimensions
|
||||
"metadata": {
|
||||
"text": "Document content",
|
||||
"category": "tutorial",
|
||||
"timestamp": "2025-01-01"
|
||||
}
|
||||
}
|
||||
])
|
||||
|
||||
# Batch upsert (recommended)
|
||||
vectors = [
|
||||
{"id": f"vec{i}", "values": embedding, "metadata": metadata}
|
||||
for i, (embedding, metadata) in enumerate(zip(embeddings, metadatas))
|
||||
]
|
||||
|
||||
index.upsert(vectors=vectors, batch_size=100)
|
||||
```
|
||||
|
||||
### 查询向量
|
||||
|
||||
```python
|
||||
# Basic query
|
||||
results = index.query(
|
||||
vector=[0.1, 0.2, ...],
|
||||
top_k=10,
|
||||
include_metadata=True,
|
||||
include_values=False
|
||||
)
|
||||
|
||||
# With metadata filtering
|
||||
results = index.query(
|
||||
vector=[0.1, 0.2, ...],
|
||||
top_k=5,
|
||||
filter={"category": {"$eq": "tutorial"}}
|
||||
)
|
||||
|
||||
# Namespace query
|
||||
results = index.query(
|
||||
vector=[0.1, 0.2, ...],
|
||||
top_k=5,
|
||||
namespace="production"
|
||||
)
|
||||
|
||||
# Access results
|
||||
for match in results["matches"]:
|
||||
print(f"ID: {match['id']}")
|
||||
print(f"Score: {match['score']}")
|
||||
print(f"Metadata: {match['metadata']}")
|
||||
```
|
||||
|
||||
### 元数据过滤
|
||||
|
||||
```python
|
||||
# Exact match
|
||||
filter = {"category": "tutorial"}
|
||||
|
||||
# Comparison
|
||||
filter = {"price": {"$gte": 100}} # $gt, $gte, $lt, $lte, $ne
|
||||
|
||||
# Logical operators
|
||||
filter = {
|
||||
"$and": [
|
||||
{"category": "tutorial"},
|
||||
{"difficulty": {"$lte": 3}}
|
||||
]
|
||||
} # Also: $or
|
||||
|
||||
# In operator
|
||||
filter = {"tags": {"$in": ["python", "ml"]}}
|
||||
```
|
||||
|
||||
## 命名空间
|
||||
|
||||
```python
|
||||
# Partition data by namespace
|
||||
index.upsert(
|
||||
vectors=[{"id": "vec1", "values": [...]}],
|
||||
namespace="user-123"
|
||||
)
|
||||
|
||||
# Query specific namespace
|
||||
results = index.query(
|
||||
vector=[...],
|
||||
namespace="user-123",
|
||||
top_k=5
|
||||
)
|
||||
|
||||
# List namespaces
|
||||
stats = index.describe_index_stats()
|
||||
print(stats['namespaces'])
|
||||
```
|
||||
|
||||
## 混合搜索(稠密 + 稀疏向量)
|
||||
|
||||
```python
|
||||
# Upsert with sparse vectors
|
||||
index.upsert(vectors=[
|
||||
{
|
||||
"id": "doc1",
|
||||
"values": [0.1, 0.2, ...], # Dense vector
|
||||
"sparse_values": {
|
||||
"indices": [10, 45, 123], # Token IDs
|
||||
"values": [0.5, 0.3, 0.8] # TF-IDF scores
|
||||
},
|
||||
"metadata": {"text": "..."}
|
||||
}
|
||||
])
|
||||
|
||||
# Hybrid query
|
||||
results = index.query(
|
||||
vector=[0.1, 0.2, ...],
|
||||
sparse_vector={
|
||||
"indices": [10, 45],
|
||||
"values": [0.5, 0.3]
|
||||
},
|
||||
top_k=5,
|
||||
alpha=0.5 # 0=sparse, 1=dense, 0.5=hybrid
|
||||
)
|
||||
```
|
||||
|
||||
## LangChain 集成
|
||||
|
||||
```python
|
||||
from langchain_pinecone import PineconeVectorStore
|
||||
from langchain_openai import OpenAIEmbeddings
|
||||
|
||||
# Create vector store
|
||||
vectorstore = PineconeVectorStore.from_documents(
|
||||
documents=docs,
|
||||
embedding=OpenAIEmbeddings(),
|
||||
index_name="my-index"
|
||||
)
|
||||
|
||||
# Query
|
||||
results = vectorstore.similarity_search("query", k=5)
|
||||
|
||||
# With metadata filter
|
||||
results = vectorstore.similarity_search(
|
||||
"query",
|
||||
k=5,
|
||||
filter={"category": "tutorial"}
|
||||
)
|
||||
|
||||
# As retriever
|
||||
retriever = vectorstore.as_retriever(search_kwargs={"k": 10})
|
||||
```
|
||||
|
||||
## LlamaIndex 集成
|
||||
|
||||
```python
|
||||
from llama_index.vector_stores.pinecone import PineconeVectorStore
|
||||
|
||||
# Connect to Pinecone
|
||||
pc = Pinecone(api_key="your-key")
|
||||
pinecone_index = pc.Index("my-index")
|
||||
|
||||
# Create vector store
|
||||
vector_store = PineconeVectorStore(pinecone_index=pinecone_index)
|
||||
|
||||
# Use in LlamaIndex
|
||||
from llama_index.core import StorageContext, VectorStoreIndex
|
||||
|
||||
storage_context = StorageContext.from_defaults(vector_store=vector_store)
|
||||
index = VectorStoreIndex.from_documents(documents, storage_context=storage_context)
|
||||
```
|
||||
|
||||
## 索引管理
|
||||
|
||||
```python
|
||||
# List indices
|
||||
indexes = pc.list_indexes()
|
||||
|
||||
# Describe index
|
||||
index_info = pc.describe_index("my-index")
|
||||
print(index_info)
|
||||
|
||||
# Get index stats
|
||||
stats = index.describe_index_stats()
|
||||
print(f"Total vectors: {stats['total_vector_count']}")
|
||||
print(f"Namespaces: {stats['namespaces']}")
|
||||
|
||||
# Delete index
|
||||
pc.delete_index("my-index")
|
||||
```
|
||||
|
||||
## 删除向量
|
||||
|
||||
```python
|
||||
# Delete by ID
|
||||
index.delete(ids=["vec1", "vec2"])
|
||||
|
||||
# Delete by filter
|
||||
index.delete(filter={"category": "old"})
|
||||
|
||||
# Delete all in namespace
|
||||
index.delete(delete_all=True, namespace="test")
|
||||
|
||||
# Delete entire index
|
||||
index.delete(delete_all=True)
|
||||
```
|
||||
|
||||
## 最佳实践
|
||||
|
||||
1. **使用 serverless** — 自动扩缩容,成本效益高
|
||||
2. **批量 upsert** — 效率更高(每批 100-200 条)
|
||||
3. **添加元数据** — 启用过滤功能
|
||||
4. **使用命名空间** — 按用户/租户隔离数据
|
||||
5. **监控用量** — 查看 Pinecone 控制台
|
||||
6. **优化过滤器** — 对频繁过滤的字段建立索引
|
||||
7. **用免费套餐测试** — 1 个索引,10 万向量免费
|
||||
8. **使用混合搜索** — 质量更优
|
||||
9. **设置合适的维度** — 与 embedding 模型匹配
|
||||
10. **定期备份** — 导出重要数据
|
||||
|
||||
## 性能
|
||||
|
||||
| 操作 | 延迟 | 备注 |
|
||||
|-----------|---------|-------|
|
||||
| Upsert | ~50-100ms | 每批次 |
|
||||
| 查询(p50) | ~50ms | 取决于索引大小 |
|
||||
| 查询(p95) | ~100ms | SLA 目标 |
|
||||
| 元数据过滤 | ~+10-20ms | 额外开销 |
|
||||
|
||||
## 定价(截至 2025 年)
|
||||
|
||||
**Serverless**:
|
||||
- 每百万读取单元 $0.096
|
||||
- 每百万写入单元 $0.06
|
||||
- 每 GB 存储/月 $0.06
|
||||
|
||||
**免费套餐**:
|
||||
- 1 个 serverless 索引
|
||||
- 10 万向量(1536 维)
|
||||
- 非常适合原型开发
|
||||
|
||||
## 资源
|
||||
|
||||
- **官网**:https://www.pinecone.io
|
||||
- **文档**:https://docs.pinecone.io
|
||||
- **控制台**:https://app.pinecone.io
|
||||
- **定价**:https://www.pinecone.io/pricing
|
||||
+145
File diff suppressed because one or more lines are too long
+365
@@ -0,0 +1,365 @@
|
||||
---
|
||||
title: "Pytorch Lightning"
|
||||
sidebar_label: "Pytorch Lightning"
|
||||
description: "基于 PyTorch 的高层框架,提供 Trainer 类、自动分布式训练(DDP/FSDP/DeepSpeed)、回调系统及极简样板代码"
|
||||
---
|
||||
|
||||
{/* This page is auto-generated from the skill's SKILL.md by website/scripts/generate-skill-docs.py. Edit the source SKILL.md, not this page. */}
|
||||
|
||||
# Pytorch Lightning
|
||||
|
||||
基于 PyTorch 的高层框架,提供 Trainer 类、自动分布式训练(DDP/FSDP/DeepSpeed)、回调(callbacks)系统及极简样板代码。同一套代码可从笔记本扩展至超级计算机。适用于希望以内置最佳实践编写整洁训练循环的场景。
|
||||
|
||||
## Skill 元数据
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| 来源 | 可选 — 通过 `hermes skills install official/mlops/pytorch-lightning` 安装 |
|
||||
| 路径 | `optional-skills/mlops/pytorch-lightning` |
|
||||
| 版本 | `1.0.0` |
|
||||
| 作者 | Orchestra Research |
|
||||
| 许可证 | MIT |
|
||||
| 依赖项 | `lightning`, `torch`, `transformers` |
|
||||
| 平台 | linux, macos, windows |
|
||||
| 标签 | `PyTorch Lightning`, `Training Framework`, `Distributed Training`, `DDP`, `FSDP`, `DeepSpeed`, `High-Level API`, `Callbacks`, `Best Practices`, `Scalable` |
|
||||
|
||||
## 参考:完整 SKILL.md
|
||||
|
||||
:::info
|
||||
以下是 Hermes 在触发该 skill 时加载的完整 skill 定义。这是 skill 激活时 agent 所看到的指令内容。
|
||||
:::
|
||||
|
||||
# PyTorch Lightning - 高层训练框架
|
||||
|
||||
## 快速开始
|
||||
|
||||
PyTorch Lightning 对 PyTorch 代码进行组织,在保持灵活性的同时消除样板代码。
|
||||
|
||||
**安装**:
|
||||
```bash
|
||||
pip install lightning
|
||||
```
|
||||
|
||||
**将 PyTorch 转换为 Lightning**(3 步):
|
||||
|
||||
```python
|
||||
import lightning as L
|
||||
import torch
|
||||
from torch import nn
|
||||
from torch.utils.data import DataLoader, Dataset
|
||||
|
||||
# Step 1: Define LightningModule (organize your PyTorch code)
|
||||
class LitModel(L.LightningModule):
|
||||
def __init__(self, hidden_size=128):
|
||||
super().__init__()
|
||||
self.model = nn.Sequential(
|
||||
nn.Linear(28 * 28, hidden_size),
|
||||
nn.ReLU(),
|
||||
nn.Linear(hidden_size, 10)
|
||||
)
|
||||
|
||||
def training_step(self, batch, batch_idx):
|
||||
x, y = batch
|
||||
y_hat = self.model(x)
|
||||
loss = nn.functional.cross_entropy(y_hat, y)
|
||||
self.log('train_loss', loss) # Auto-logged to TensorBoard
|
||||
return loss
|
||||
|
||||
def configure_optimizers(self):
|
||||
return torch.optim.Adam(self.parameters(), lr=1e-3)
|
||||
|
||||
# Step 2: Create data
|
||||
train_loader = DataLoader(train_dataset, batch_size=32)
|
||||
|
||||
# Step 3: Train with Trainer (handles everything else!)
|
||||
trainer = L.Trainer(max_epochs=10, accelerator='gpu', devices=2)
|
||||
model = LitModel()
|
||||
trainer.fit(model, train_loader)
|
||||
```
|
||||
|
||||
**就这些!** Trainer 负责处理:
|
||||
- GPU/TPU/CPU 切换
|
||||
- 分布式训练(DDP、FSDP、DeepSpeed)
|
||||
- 混合精度(FP16、BF16)
|
||||
- 梯度累积
|
||||
- 检查点保存
|
||||
- 日志记录
|
||||
- 进度条
|
||||
|
||||
## 常见工作流
|
||||
|
||||
### 工作流 1:从 PyTorch 迁移到 Lightning
|
||||
|
||||
**原始 PyTorch 代码**:
|
||||
```python
|
||||
model = MyModel()
|
||||
optimizer = torch.optim.Adam(model.parameters())
|
||||
model.to('cuda')
|
||||
|
||||
for epoch in range(max_epochs):
|
||||
for batch in train_loader:
|
||||
batch = batch.to('cuda')
|
||||
optimizer.zero_grad()
|
||||
loss = model(batch)
|
||||
loss.backward()
|
||||
optimizer.step()
|
||||
```
|
||||
|
||||
**Lightning 版本**:
|
||||
```python
|
||||
class LitModel(L.LightningModule):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.model = MyModel()
|
||||
|
||||
def training_step(self, batch, batch_idx):
|
||||
loss = self.model(batch) # No .to('cuda') needed!
|
||||
return loss
|
||||
|
||||
def configure_optimizers(self):
|
||||
return torch.optim.Adam(self.parameters())
|
||||
|
||||
# Train
|
||||
trainer = L.Trainer(max_epochs=10, accelerator='gpu')
|
||||
trainer.fit(LitModel(), train_loader)
|
||||
```
|
||||
|
||||
**优势**:40+ 行 → 15 行,无需设备管理,自动分布式
|
||||
|
||||
### 工作流 2:验证与测试
|
||||
|
||||
```python
|
||||
class LitModel(L.LightningModule):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.model = MyModel()
|
||||
|
||||
def training_step(self, batch, batch_idx):
|
||||
x, y = batch
|
||||
y_hat = self.model(x)
|
||||
loss = nn.functional.cross_entropy(y_hat, y)
|
||||
self.log('train_loss', loss)
|
||||
return loss
|
||||
|
||||
def validation_step(self, batch, batch_idx):
|
||||
x, y = batch
|
||||
y_hat = self.model(x)
|
||||
val_loss = nn.functional.cross_entropy(y_hat, y)
|
||||
acc = (y_hat.argmax(dim=1) == y).float().mean()
|
||||
self.log('val_loss', val_loss)
|
||||
self.log('val_acc', acc)
|
||||
|
||||
def test_step(self, batch, batch_idx):
|
||||
x, y = batch
|
||||
y_hat = self.model(x)
|
||||
test_loss = nn.functional.cross_entropy(y_hat, y)
|
||||
self.log('test_loss', test_loss)
|
||||
|
||||
def configure_optimizers(self):
|
||||
return torch.optim.Adam(self.parameters(), lr=1e-3)
|
||||
|
||||
# Train with validation
|
||||
trainer = L.Trainer(max_epochs=10)
|
||||
trainer.fit(model, train_loader, val_loader)
|
||||
|
||||
# Test
|
||||
trainer.test(model, test_loader)
|
||||
```
|
||||
|
||||
**自动功能**:
|
||||
- 默认每个 epoch 运行验证
|
||||
- 指标自动记录到 TensorBoard
|
||||
- 基于 val_loss 保存最优模型检查点
|
||||
|
||||
### 工作流 3:分布式训练(DDP)
|
||||
|
||||
```python
|
||||
# Same code as single GPU!
|
||||
model = LitModel()
|
||||
|
||||
# 8 GPUs with DDP (automatic!)
|
||||
trainer = L.Trainer(
|
||||
accelerator='gpu',
|
||||
devices=8,
|
||||
strategy='ddp' # Or 'fsdp', 'deepspeed'
|
||||
)
|
||||
|
||||
trainer.fit(model, train_loader)
|
||||
```
|
||||
|
||||
**启动**:
|
||||
```bash
|
||||
# Single command, Lightning handles the rest
|
||||
python train.py
|
||||
```
|
||||
|
||||
**无需任何改动**:
|
||||
- 自动数据分发
|
||||
- 梯度同步
|
||||
- 多节点支持(只需设置 `num_nodes=2`)
|
||||
|
||||
### 工作流 4:用于监控的回调(Callbacks)
|
||||
|
||||
```python
|
||||
from lightning.pytorch.callbacks import ModelCheckpoint, EarlyStopping, LearningRateMonitor
|
||||
|
||||
# Create callbacks
|
||||
checkpoint = ModelCheckpoint(
|
||||
monitor='val_loss',
|
||||
mode='min',
|
||||
save_top_k=3,
|
||||
filename='model-{epoch:02d}-{val_loss:.2f}'
|
||||
)
|
||||
|
||||
early_stop = EarlyStopping(
|
||||
monitor='val_loss',
|
||||
patience=5,
|
||||
mode='min'
|
||||
)
|
||||
|
||||
lr_monitor = LearningRateMonitor(logging_interval='epoch')
|
||||
|
||||
# Add to Trainer
|
||||
trainer = L.Trainer(
|
||||
max_epochs=100,
|
||||
callbacks=[checkpoint, early_stop, lr_monitor]
|
||||
)
|
||||
|
||||
trainer.fit(model, train_loader, val_loader)
|
||||
```
|
||||
|
||||
**效果**:
|
||||
- 自动保存最优的 3 个模型
|
||||
- 若 5 个 epoch 内无改善则提前停止
|
||||
- 将学习率记录到 TensorBoard
|
||||
|
||||
### 工作流 5:学习率调度
|
||||
|
||||
```python
|
||||
class LitModel(L.LightningModule):
|
||||
# ... (training_step, etc.)
|
||||
|
||||
def configure_optimizers(self):
|
||||
optimizer = torch.optim.Adam(self.parameters(), lr=1e-3)
|
||||
|
||||
# Cosine annealing
|
||||
scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(
|
||||
optimizer,
|
||||
T_max=100,
|
||||
eta_min=1e-5
|
||||
)
|
||||
|
||||
return {
|
||||
'optimizer': optimizer,
|
||||
'lr_scheduler': {
|
||||
'scheduler': scheduler,
|
||||
'interval': 'epoch', # Update per epoch
|
||||
'frequency': 1
|
||||
}
|
||||
}
|
||||
|
||||
# Learning rate auto-logged!
|
||||
trainer = L.Trainer(max_epochs=100)
|
||||
trainer.fit(model, train_loader)
|
||||
```
|
||||
|
||||
## 何时使用与替代方案对比
|
||||
|
||||
**适合使用 PyTorch Lightning 的场景**:
|
||||
- 希望代码整洁、结构清晰
|
||||
- 需要生产级训练循环
|
||||
- 在单 GPU、多 GPU、TPU 之间切换
|
||||
- 希望使用内置回调和日志记录
|
||||
- 团队协作(标准化结构)
|
||||
|
||||
**核心优势**:
|
||||
- **有组织**:将研究代码与工程代码分离
|
||||
- **自动化**:一行代码启用 DDP、FSDP、DeepSpeed
|
||||
- **回调**:模块化训练扩展
|
||||
- **可复现**:样板代码更少 = 更少 bug
|
||||
- **经过验证**:每月下载量 100 万+,久经考验
|
||||
|
||||
**改用其他方案的场景**:
|
||||
- **Accelerate**:对现有代码改动最小,灵活性更高
|
||||
- **Ray Train**:多节点编排、超参数调优
|
||||
- **原生 PyTorch**:最大控制权,适合学习目的
|
||||
- **Keras**:TensorFlow 生态系统
|
||||
|
||||
## 常见问题
|
||||
|
||||
**问题:损失不下降**
|
||||
|
||||
检查数据和模型设置:
|
||||
```python
|
||||
# Add to training_step
|
||||
def training_step(self, batch, batch_idx):
|
||||
if batch_idx == 0:
|
||||
print(f"Batch shape: {batch[0].shape}")
|
||||
print(f"Labels: {batch[1]}")
|
||||
loss = ...
|
||||
return loss
|
||||
```
|
||||
|
||||
**问题:内存不足**
|
||||
|
||||
减小 batch size 或使用梯度累积:
|
||||
```python
|
||||
trainer = L.Trainer(
|
||||
accumulate_grad_batches=4, # Effective batch = batch_size × 4
|
||||
precision='bf16' # Or 'fp16', reduces memory 50%
|
||||
)
|
||||
```
|
||||
|
||||
**问题:验证未运行**
|
||||
|
||||
确保传入了 val_loader:
|
||||
```python
|
||||
# WRONG
|
||||
trainer.fit(model, train_loader)
|
||||
|
||||
# CORRECT
|
||||
trainer.fit(model, train_loader, val_loader)
|
||||
```
|
||||
|
||||
**问题:DDP 意外启动多个进程**
|
||||
|
||||
Lightning 会自动检测 GPU。请显式设置 devices:
|
||||
```python
|
||||
# Test on CPU first
|
||||
trainer = L.Trainer(accelerator='cpu', devices=1)
|
||||
|
||||
# Then GPU
|
||||
trainer = L.Trainer(accelerator='gpu', devices=1)
|
||||
```
|
||||
|
||||
## 进阶主题
|
||||
|
||||
**回调**:参见 [references/callbacks.md](https://github.com/NousResearch/hermes-agent/blob/main/optional-skills/mlops/pytorch-lightning/references/callbacks.md),了解 EarlyStopping、ModelCheckpoint、自定义回调及回调钩子(hook)。
|
||||
|
||||
**分布式策略**:参见 [references/distributed.md](https://github.com/NousResearch/hermes-agent/blob/main/optional-skills/mlops/pytorch-lightning/references/distributed.md),了解 DDP、FSDP、DeepSpeed ZeRO 集成及多节点配置。
|
||||
|
||||
**超参数调优**:参见 [references/hyperparameter-tuning.md](https://github.com/NousResearch/hermes-agent/blob/main/optional-skills/mlops/pytorch-lightning/references/hyperparameter-tuning.md),了解与 Optuna、Ray Tune 及 WandB sweeps 的集成。
|
||||
|
||||
## 硬件要求
|
||||
|
||||
- **CPU**:支持(适合调试)
|
||||
- **单 GPU**:支持
|
||||
- **多 GPU**:DDP(默认)、FSDP 或 DeepSpeed
|
||||
- **多节点**:DDP、FSDP、DeepSpeed
|
||||
- **TPU**:支持(8 核)
|
||||
- **Apple MPS**:支持
|
||||
|
||||
**精度选项**:
|
||||
- FP32(默认)
|
||||
- FP16(V100 及较旧 GPU)
|
||||
- BF16(A100/H100,推荐)
|
||||
- FP8(H100)
|
||||
|
||||
## 资源
|
||||
|
||||
- 文档:https://lightning.ai/docs/pytorch/stable/
|
||||
- GitHub:https://github.com/Lightning-AI/pytorch-lightning ⭐ 29,000+
|
||||
- 版本:2.5.5+
|
||||
- 示例:https://github.com/Lightning-AI/pytorch-lightning/tree/master/examples
|
||||
- Discord:https://discord.gg/lightning-ai
|
||||
- 使用者:Kaggle 获奖者、科研实验室、生产团队
|
||||
+514
@@ -0,0 +1,514 @@
|
||||
---
|
||||
title: "Qdrant Vector Search — 用于 RAG 和语义搜索的高性能向量相似度搜索引擎"
|
||||
sidebar_label: "Qdrant Vector Search"
|
||||
description: "用于 RAG 和语义搜索的高性能向量相似度搜索引擎"
|
||||
---
|
||||
|
||||
{/* This page is auto-generated from the skill's SKILL.md by website/scripts/generate-skill-docs.py. Edit the source SKILL.md, not this page. */}
|
||||
|
||||
# Qdrant Vector Search
|
||||
|
||||
用于 RAG 和语义搜索的高性能向量相似度搜索引擎。适用于构建需要快速最近邻搜索、带过滤的混合搜索,或基于 Rust 高性能的可扩展向量存储的生产级 RAG 系统。
|
||||
|
||||
## Skill 元数据
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| 来源 | 可选 — 使用 `hermes skills install official/mlops/qdrant` 安装 |
|
||||
| 路径 | `optional-skills/mlops/qdrant` |
|
||||
| 版本 | `1.0.0` |
|
||||
| 作者 | Orchestra Research |
|
||||
| 许可证 | MIT |
|
||||
| 依赖 | `qdrant-client>=1.12.0` |
|
||||
| 平台 | linux, macos, windows |
|
||||
| 标签 | `RAG`, `Vector Search`, `Qdrant`, `Semantic Search`, `Embeddings`, `Similarity Search`, `HNSW`, `Production`, `Distributed` |
|
||||
|
||||
## 参考:完整 SKILL.md
|
||||
|
||||
:::info
|
||||
以下是 Hermes 在触发此 skill 时加载的完整 skill 定义。这是 skill 激活时 agent 所看到的指令内容。
|
||||
:::
|
||||
|
||||
# Qdrant - 向量相似度搜索引擎
|
||||
|
||||
用 Rust 编写的高性能向量数据库,适用于生产级 RAG 和语义搜索。
|
||||
|
||||
## 何时使用 Qdrant
|
||||
|
||||
**在以下情况下使用 Qdrant:**
|
||||
- 构建需要低延迟的生产级 RAG 系统
|
||||
- 需要混合搜索(向量 + 元数据过滤)
|
||||
- 需要通过分片/副本实现水平扩展
|
||||
- 希望本地部署并完全掌控数据
|
||||
- 每条记录需要多向量存储(稠密 + 稀疏)
|
||||
- 构建实时推荐系统
|
||||
|
||||
**核心特性:**
|
||||
- **Rust 驱动**:内存安全,高性能
|
||||
- **丰富过滤**:在搜索时按任意 payload 字段过滤
|
||||
- **多向量**:每个点支持稠密、稀疏、多稠密向量
|
||||
- **量化**:标量、乘积、二值量化,节省内存
|
||||
- **分布式**:Raft 共识、分片、副本
|
||||
- **REST + gRPC**:两套 API 功能完全对等
|
||||
|
||||
**以下情况请使用替代方案:**
|
||||
- **Chroma**:更简单的配置,嵌入式使用场景
|
||||
- **FAISS**:追求极致原始速度,研究/批处理场景
|
||||
- **Pinecone**:完全托管,零运维偏好
|
||||
- **Weaviate**:偏好 GraphQL,内置向量化器
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 安装
|
||||
|
||||
```bash
|
||||
# Python 客户端
|
||||
pip install qdrant-client
|
||||
|
||||
# Docker(推荐用于开发)
|
||||
docker run -p 6333:6333 -p 6334:6334 qdrant/qdrant
|
||||
|
||||
# Docker 持久化存储
|
||||
docker run -p 6333:6333 -p 6334:6334 \
|
||||
-v $(pwd)/qdrant_storage:/qdrant/storage \
|
||||
qdrant/qdrant
|
||||
```
|
||||
|
||||
### 基本用法
|
||||
|
||||
```python
|
||||
from qdrant_client import QdrantClient
|
||||
from qdrant_client.models import Distance, VectorParams, PointStruct
|
||||
|
||||
# 连接到 Qdrant
|
||||
client = QdrantClient(host="localhost", port=6333)
|
||||
|
||||
# 创建集合
|
||||
client.create_collection(
|
||||
collection_name="documents",
|
||||
vectors_config=VectorParams(size=384, distance=Distance.COSINE)
|
||||
)
|
||||
|
||||
# 插入带 payload 的向量
|
||||
client.upsert(
|
||||
collection_name="documents",
|
||||
points=[
|
||||
PointStruct(
|
||||
id=1,
|
||||
vector=[0.1, 0.2, ...], # 384 维向量
|
||||
payload={"title": "Doc 1", "category": "tech"}
|
||||
),
|
||||
PointStruct(
|
||||
id=2,
|
||||
vector=[0.3, 0.4, ...],
|
||||
payload={"title": "Doc 2", "category": "science"}
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
# 带过滤的搜索
|
||||
results = client.search(
|
||||
collection_name="documents",
|
||||
query_vector=[0.15, 0.25, ...],
|
||||
query_filter={
|
||||
"must": [{"key": "category", "match": {"value": "tech"}}]
|
||||
},
|
||||
limit=10
|
||||
)
|
||||
|
||||
for point in results:
|
||||
print(f"ID: {point.id}, Score: {point.score}, Payload: {point.payload}")
|
||||
```
|
||||
|
||||
## 核心概念
|
||||
|
||||
### Points(点)— 基本数据单元
|
||||
|
||||
```python
|
||||
from qdrant_client.models import PointStruct
|
||||
|
||||
# Point = ID + 向量 + Payload
|
||||
point = PointStruct(
|
||||
id=123, # 整数或 UUID 字符串
|
||||
vector=[0.1, 0.2, 0.3, ...], # 稠密向量
|
||||
payload={ # 任意 JSON 元数据
|
||||
"title": "Document title",
|
||||
"category": "tech",
|
||||
"timestamp": 1699900000,
|
||||
"tags": ["python", "ml"]
|
||||
}
|
||||
)
|
||||
|
||||
# 批量 upsert(推荐)
|
||||
client.upsert(
|
||||
collection_name="documents",
|
||||
points=[point1, point2, point3],
|
||||
wait=True # 等待索引完成
|
||||
)
|
||||
```
|
||||
|
||||
### Collections(集合)— 向量容器
|
||||
|
||||
```python
|
||||
from qdrant_client.models import VectorParams, Distance, HnswConfigDiff
|
||||
|
||||
# 使用 HNSW 配置创建集合
|
||||
client.create_collection(
|
||||
collection_name="documents",
|
||||
vectors_config=VectorParams(
|
||||
size=384, # 向量维度
|
||||
distance=Distance.COSINE # COSINE、EUCLID、DOT、MANHATTAN
|
||||
),
|
||||
hnsw_config=HnswConfigDiff(
|
||||
m=16, # 每个节点的连接数(默认 16)
|
||||
ef_construct=100, # 构建时精度(默认 100)
|
||||
full_scan_threshold=10000 # 低于此值切换为暴力搜索
|
||||
),
|
||||
on_disk_payload=True # 将 payload 存储在磁盘上
|
||||
)
|
||||
|
||||
# 集合信息
|
||||
info = client.get_collection("documents")
|
||||
print(f"Points: {info.points_count}, Vectors: {info.vectors_count}")
|
||||
```
|
||||
|
||||
### 距离度量
|
||||
|
||||
| 度量 | 使用场景 | 范围 |
|
||||
|--------|----------|-------|
|
||||
| `COSINE` | 文本 embedding、归一化向量 | 0 到 2 |
|
||||
| `EUCLID` | 空间数据、图像特征 | 0 到 ∞ |
|
||||
| `DOT` | 推荐系统、非归一化向量 | -∞ 到 ∞ |
|
||||
| `MANHATTAN` | 稀疏特征、离散数据 | 0 到 ∞ |
|
||||
|
||||
## 搜索操作
|
||||
|
||||
### 基本搜索
|
||||
|
||||
```python
|
||||
# 简单最近邻搜索
|
||||
results = client.search(
|
||||
collection_name="documents",
|
||||
query_vector=[0.1, 0.2, ...],
|
||||
limit=10,
|
||||
with_payload=True,
|
||||
with_vectors=False # 不返回向量(更快)
|
||||
)
|
||||
```
|
||||
|
||||
### 带过滤的搜索
|
||||
|
||||
```python
|
||||
from qdrant_client.models import Filter, FieldCondition, MatchValue, Range
|
||||
|
||||
# 复杂过滤
|
||||
results = client.search(
|
||||
collection_name="documents",
|
||||
query_vector=query_embedding,
|
||||
query_filter=Filter(
|
||||
must=[
|
||||
FieldCondition(key="category", match=MatchValue(value="tech")),
|
||||
FieldCondition(key="timestamp", range=Range(gte=1699000000))
|
||||
],
|
||||
must_not=[
|
||||
FieldCondition(key="status", match=MatchValue(value="archived"))
|
||||
]
|
||||
),
|
||||
limit=10
|
||||
)
|
||||
|
||||
# 简写过滤语法
|
||||
results = client.search(
|
||||
collection_name="documents",
|
||||
query_vector=query_embedding,
|
||||
query_filter={
|
||||
"must": [
|
||||
{"key": "category", "match": {"value": "tech"}},
|
||||
{"key": "price", "range": {"gte": 10, "lte": 100}}
|
||||
]
|
||||
},
|
||||
limit=10
|
||||
)
|
||||
```
|
||||
|
||||
### 批量搜索
|
||||
|
||||
```python
|
||||
from qdrant_client.models import SearchRequest
|
||||
|
||||
# 单次请求中执行多个查询
|
||||
results = client.search_batch(
|
||||
collection_name="documents",
|
||||
requests=[
|
||||
SearchRequest(vector=[0.1, ...], limit=5),
|
||||
SearchRequest(vector=[0.2, ...], limit=5, filter={"must": [...]}),
|
||||
SearchRequest(vector=[0.3, ...], limit=10)
|
||||
]
|
||||
)
|
||||
```
|
||||
|
||||
## RAG 集成
|
||||
|
||||
### 与 sentence-transformers 集成
|
||||
|
||||
```python
|
||||
from sentence_transformers import SentenceTransformer
|
||||
from qdrant_client import QdrantClient
|
||||
from qdrant_client.models import VectorParams, Distance, PointStruct
|
||||
|
||||
# 初始化
|
||||
encoder = SentenceTransformer("all-MiniLM-L6-v2")
|
||||
client = QdrantClient(host="localhost", port=6333)
|
||||
|
||||
# 创建集合
|
||||
client.create_collection(
|
||||
collection_name="knowledge_base",
|
||||
vectors_config=VectorParams(size=384, distance=Distance.COSINE)
|
||||
)
|
||||
|
||||
# 索引文档
|
||||
documents = [
|
||||
{"id": 1, "text": "Python is a programming language", "source": "wiki"},
|
||||
{"id": 2, "text": "Machine learning uses algorithms", "source": "textbook"},
|
||||
]
|
||||
|
||||
points = [
|
||||
PointStruct(
|
||||
id=doc["id"],
|
||||
vector=encoder.encode(doc["text"]).tolist(),
|
||||
payload={"text": doc["text"], "source": doc["source"]}
|
||||
)
|
||||
for doc in documents
|
||||
]
|
||||
client.upsert(collection_name="knowledge_base", points=points)
|
||||
|
||||
# RAG 检索
|
||||
def retrieve(query: str, top_k: int = 5) -> list[dict]:
|
||||
query_vector = encoder.encode(query).tolist()
|
||||
results = client.search(
|
||||
collection_name="knowledge_base",
|
||||
query_vector=query_vector,
|
||||
limit=top_k
|
||||
)
|
||||
return [{"text": r.payload["text"], "score": r.score} for r in results]
|
||||
|
||||
# 在 RAG 流水线中使用
|
||||
context = retrieve("What is Python?")
|
||||
prompt = f"Context: {context}\n\nQuestion: What is Python?"
|
||||
```
|
||||
|
||||
### 与 LangChain 集成
|
||||
|
||||
```python
|
||||
from langchain_community.vectorstores import Qdrant
|
||||
from langchain_community.embeddings import HuggingFaceEmbeddings
|
||||
|
||||
embeddings = HuggingFaceEmbeddings(model_name="all-MiniLM-L6-v2")
|
||||
vectorstore = Qdrant.from_documents(documents, embeddings, url="http://localhost:6333", collection_name="docs")
|
||||
retriever = vectorstore.as_retriever(search_kwargs={"k": 5})
|
||||
```
|
||||
|
||||
### 与 LlamaIndex 集成
|
||||
|
||||
```python
|
||||
from llama_index.vector_stores.qdrant import QdrantVectorStore
|
||||
from llama_index.core import VectorStoreIndex, StorageContext
|
||||
|
||||
vector_store = QdrantVectorStore(client=client, collection_name="llama_docs")
|
||||
storage_context = StorageContext.from_defaults(vector_store=vector_store)
|
||||
index = VectorStoreIndex.from_documents(documents, storage_context=storage_context)
|
||||
query_engine = index.as_query_engine()
|
||||
```
|
||||
|
||||
## 多向量支持
|
||||
|
||||
### 命名向量(不同 embedding 模型)
|
||||
|
||||
```python
|
||||
from qdrant_client.models import VectorParams, Distance
|
||||
|
||||
# 包含多种向量类型的集合
|
||||
client.create_collection(
|
||||
collection_name="hybrid_search",
|
||||
vectors_config={
|
||||
"dense": VectorParams(size=384, distance=Distance.COSINE),
|
||||
"sparse": VectorParams(size=30000, distance=Distance.DOT)
|
||||
}
|
||||
)
|
||||
|
||||
# 插入命名向量
|
||||
client.upsert(
|
||||
collection_name="hybrid_search",
|
||||
points=[
|
||||
PointStruct(
|
||||
id=1,
|
||||
vector={
|
||||
"dense": dense_embedding,
|
||||
"sparse": sparse_embedding
|
||||
},
|
||||
payload={"text": "document text"}
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
# 搜索指定向量
|
||||
results = client.search(
|
||||
collection_name="hybrid_search",
|
||||
query_vector=("dense", query_dense), # 指定使用哪个向量
|
||||
limit=10
|
||||
)
|
||||
```
|
||||
|
||||
### 稀疏向量(BM25、SPLADE)
|
||||
|
||||
```python
|
||||
from qdrant_client.models import SparseVectorParams, SparseIndexParams, SparseVector
|
||||
|
||||
# 包含稀疏向量的集合
|
||||
client.create_collection(
|
||||
collection_name="sparse_search",
|
||||
vectors_config={},
|
||||
sparse_vectors_config={"text": SparseVectorParams(index=SparseIndexParams(on_disk=False))}
|
||||
)
|
||||
|
||||
# 插入稀疏向量
|
||||
client.upsert(
|
||||
collection_name="sparse_search",
|
||||
points=[PointStruct(id=1, vector={"text": SparseVector(indices=[1, 5, 100], values=[0.5, 0.8, 0.2])}, payload={"text": "document"})]
|
||||
)
|
||||
```
|
||||
|
||||
## 量化(内存优化)
|
||||
|
||||
```python
|
||||
from qdrant_client.models import ScalarQuantization, ScalarQuantizationConfig, ScalarType
|
||||
|
||||
# 标量量化(内存减少 4 倍)
|
||||
client.create_collection(
|
||||
collection_name="quantized",
|
||||
vectors_config=VectorParams(size=384, distance=Distance.COSINE),
|
||||
quantization_config=ScalarQuantization(
|
||||
scalar=ScalarQuantizationConfig(
|
||||
type=ScalarType.INT8,
|
||||
quantile=0.99, # 裁剪异常值
|
||||
always_ram=True # 将量化数据保留在 RAM 中
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
# 带重新评分的搜索
|
||||
results = client.search(
|
||||
collection_name="quantized",
|
||||
query_vector=query,
|
||||
search_params={"quantization": {"rescore": True}}, # 对 top 结果重新评分
|
||||
limit=10
|
||||
)
|
||||
```
|
||||
|
||||
## Payload 索引
|
||||
|
||||
```python
|
||||
from qdrant_client.models import PayloadSchemaType
|
||||
|
||||
# 创建 payload 索引以加速过滤
|
||||
client.create_payload_index(
|
||||
collection_name="documents",
|
||||
field_name="category",
|
||||
field_schema=PayloadSchemaType.KEYWORD
|
||||
)
|
||||
|
||||
client.create_payload_index(
|
||||
collection_name="documents",
|
||||
field_name="timestamp",
|
||||
field_schema=PayloadSchemaType.INTEGER
|
||||
)
|
||||
|
||||
# 索引类型:KEYWORD、INTEGER、FLOAT、GEO、TEXT(全文)、BOOL
|
||||
```
|
||||
|
||||
## 生产部署
|
||||
|
||||
### Qdrant Cloud
|
||||
|
||||
```python
|
||||
from qdrant_client import QdrantClient
|
||||
|
||||
# 连接到 Qdrant Cloud
|
||||
client = QdrantClient(
|
||||
url="https://your-cluster.cloud.qdrant.io",
|
||||
api_key="your-api-key"
|
||||
)
|
||||
```
|
||||
|
||||
### 性能调优
|
||||
|
||||
```python
|
||||
# 优化搜索速度(更高召回率)
|
||||
client.update_collection(
|
||||
collection_name="documents",
|
||||
hnsw_config=HnswConfigDiff(ef_construct=200, m=32)
|
||||
)
|
||||
|
||||
# 优化索引速度(批量加载)
|
||||
client.update_collection(
|
||||
collection_name="documents",
|
||||
optimizer_config={"indexing_threshold": 20000}
|
||||
)
|
||||
```
|
||||
|
||||
## 最佳实践
|
||||
|
||||
1. **批量操作** — 使用批量 upsert/search 提升效率
|
||||
2. **Payload 索引** — 对过滤中使用的字段建立索引
|
||||
3. **量化** — 对大型集合(>100 万向量)启用量化
|
||||
4. **分片** — 对超过 1000 万向量的集合使用分片
|
||||
5. **磁盘存储** — 对大型 payload 启用 `on_disk_payload`
|
||||
6. **连接池** — 复用客户端实例
|
||||
|
||||
## 常见问题
|
||||
|
||||
**带过滤的搜索速度慢:**
|
||||
```python
|
||||
# 为过滤字段创建 payload 索引
|
||||
client.create_payload_index(
|
||||
collection_name="docs",
|
||||
field_name="category",
|
||||
field_schema=PayloadSchemaType.KEYWORD
|
||||
)
|
||||
```
|
||||
|
||||
**内存不足:**
|
||||
```python
|
||||
# 启用量化和磁盘存储
|
||||
client.create_collection(
|
||||
collection_name="large_collection",
|
||||
vectors_config=VectorParams(size=384, distance=Distance.COSINE),
|
||||
quantization_config=ScalarQuantization(...),
|
||||
on_disk_payload=True
|
||||
)
|
||||
```
|
||||
|
||||
**连接问题:**
|
||||
```python
|
||||
# 使用超时和重试
|
||||
client = QdrantClient(
|
||||
host="localhost",
|
||||
port=6333,
|
||||
timeout=30,
|
||||
prefer_grpc=True # gRPC 性能更佳
|
||||
)
|
||||
```
|
||||
|
||||
## 参考资料
|
||||
|
||||
- **[高级用法](https://github.com/NousResearch/hermes-agent/blob/main/optional-skills/mlops/qdrant/references/advanced-usage.md)** — 分布式模式、混合搜索、推荐系统
|
||||
- **[故障排查](https://github.com/NousResearch/hermes-agent/blob/main/optional-skills/mlops/qdrant/references/troubleshooting.md)** — 常见问题、调试、性能调优
|
||||
|
||||
## 资源
|
||||
|
||||
- **GitHub**:https://github.com/qdrant/qdrant(22k+ stars)
|
||||
- **文档**:https://qdrant.tech/documentation/
|
||||
- **Python 客户端**:https://github.com/qdrant/qdrant-client
|
||||
- **Cloud**:https://cloud.qdrant.io
|
||||
- **版本**:1.12.0+
|
||||
- **许可证**:Apache 2.0
|
||||
+407
@@ -0,0 +1,407 @@
|
||||
---
|
||||
title: "稀疏自编码器训练"
|
||||
sidebar_label: "稀疏自编码器训练"
|
||||
description: "提供使用 SAELens 训练和分析稀疏自编码器(SAE)的指导,将神经网络激活分解为可解释特征"
|
||||
---
|
||||
|
||||
{/* This page is auto-generated from the skill's SKILL.md by website/scripts/generate-skill-docs.py. Edit the source SKILL.md, not this page. */}
|
||||
|
||||
# 稀疏自编码器训练
|
||||
|
||||
提供使用 SAELens 训练和分析稀疏自编码器(SAE)的指导,将神经网络激活分解为可解释特征。适用于发现可解释特征、分析叠加现象,或研究语言模型中的单义性表示。
|
||||
|
||||
## Skill 元数据
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| 来源 | 可选 — 通过 `hermes skills install official/mlops/saelens` 安装 |
|
||||
| 路径 | `optional-skills/mlops/saelens` |
|
||||
| 版本 | `1.0.0` |
|
||||
| 作者 | Orchestra Research |
|
||||
| 许可证 | MIT |
|
||||
| 依赖 | `sae-lens>=6.0.0`, `transformer-lens>=2.0.0`, `torch>=2.0.0` |
|
||||
| 平台 | linux, macos, windows |
|
||||
| 标签 | `Sparse Autoencoders`, `SAE`, `Mechanistic Interpretability`, `Feature Discovery`, `Superposition` |
|
||||
|
||||
## 参考:完整 SKILL.md
|
||||
|
||||
:::info
|
||||
以下是 Hermes 在触发该 skill 时加载的完整 skill 定义。这是 agent 在 skill 激活时所看到的指令内容。
|
||||
:::
|
||||
|
||||
# SAELens:用于机制可解释性的稀疏自编码器
|
||||
|
||||
SAELens 是训练和分析稀疏自编码器(SAE)的主要库。SAE 是一种将多义性神经网络激活分解为稀疏、可解释特征的技术,基于 Anthropic 在单义性方面的开创性研究。
|
||||
|
||||
**GitHub**:[jbloomAus/SAELens](https://github.com/jbloomAus/SAELens)(1,100+ stars)
|
||||
|
||||
## 问题背景:多义性与叠加(Superposition)
|
||||
|
||||
神经网络中的单个神经元是**多义性**的——它们在多种语义不同的上下文中激活。这是因为模型使用**叠加**(superposition)来表示比神经元数量更多的特征,从而使可解释性变得困难。
|
||||
|
||||
**SAE 的解决方案**:将密集激活分解为稀疏的单义性特征——对于任意给定输入,通常只有少量特征激活,且每个特征对应一个可解释的概念。
|
||||
|
||||
## 何时使用 SAELens
|
||||
|
||||
**在以下情况下使用 SAELens:**
|
||||
- 发现模型激活中的可解释特征
|
||||
- 理解模型学到了哪些概念
|
||||
- 研究叠加现象和特征几何结构
|
||||
- 执行基于特征的引导(steering)或消融(ablation)
|
||||
- 分析安全相关特征(欺骗、偏见、有害内容)
|
||||
|
||||
**在以下情况下考虑替代方案:**
|
||||
- 需要基础激活分析 → 直接使用 **TransformerLens**
|
||||
- 需要因果干预实验 → 使用 **pyvene** 或 **TransformerLens**
|
||||
- 需要生产环境引导 → 考虑直接激活工程
|
||||
|
||||
## 安装
|
||||
|
||||
```bash
|
||||
pip install sae-lens
|
||||
```
|
||||
|
||||
要求:Python 3.10+,transformer-lens>=2.0.0
|
||||
|
||||
## 核心概念
|
||||
|
||||
### SAE 学到了什么
|
||||
|
||||
SAE 通过稀疏瓶颈重建模型激活:
|
||||
|
||||
```
|
||||
Input Activation → Encoder → Sparse Features → Decoder → Reconstructed Activation
|
||||
(d_model) ↓ (d_sae >> d_model) ↓ (d_model)
|
||||
sparsity reconstruction
|
||||
penalty loss
|
||||
```
|
||||
|
||||
**损失函数**:`MSE(original, reconstructed) + L1_coefficient × L1(features)`
|
||||
|
||||
### 关键验证(Anthropic 研究)
|
||||
|
||||
在《Towards Monosemanticity》中,人工评估者发现 **70% 的 SAE 特征具有真正的可解释性**。发现的特征包括:
|
||||
- DNA 序列、法律语言、HTTP 请求
|
||||
- 希伯来文本、营养声明、代码语法
|
||||
- 情感、命名实体、语法结构
|
||||
|
||||
## 工作流 1:加载和分析预训练 SAE
|
||||
|
||||
### 步骤说明
|
||||
|
||||
```python
|
||||
from transformer_lens import HookedTransformer
|
||||
from sae_lens import SAE
|
||||
|
||||
# 1. 加载模型和预训练 SAE
|
||||
model = HookedTransformer.from_pretrained("gpt2-small", device="cuda")
|
||||
sae, cfg_dict, sparsity = SAE.from_pretrained(
|
||||
release="gpt2-small-res-jb",
|
||||
sae_id="blocks.8.hook_resid_pre",
|
||||
device="cuda"
|
||||
)
|
||||
|
||||
# 2. 获取模型激活
|
||||
tokens = model.to_tokens("The capital of France is Paris")
|
||||
_, cache = model.run_with_cache(tokens)
|
||||
activations = cache["resid_pre", 8] # [batch, pos, d_model]
|
||||
|
||||
# 3. 编码为 SAE 特征
|
||||
sae_features = sae.encode(activations) # [batch, pos, d_sae]
|
||||
print(f"Active features: {(sae_features > 0).sum()}")
|
||||
|
||||
# 4. 找出每个位置的顶部特征
|
||||
for pos in range(tokens.shape[1]):
|
||||
top_features = sae_features[0, pos].topk(5)
|
||||
token = model.to_str_tokens(tokens[0, pos:pos+1])[0]
|
||||
print(f"Token '{token}': features {top_features.indices.tolist()}")
|
||||
|
||||
# 5. 重建激活
|
||||
reconstructed = sae.decode(sae_features)
|
||||
reconstruction_error = (activations - reconstructed).norm()
|
||||
```
|
||||
|
||||
### 可用预训练 SAE
|
||||
|
||||
| Release | 模型 | 层 |
|
||||
|---------|-------|--------|
|
||||
| `gpt2-small-res-jb` | GPT-2 Small | 多个残差流 |
|
||||
| `gemma-2b-res` | Gemma 2B | 残差流 |
|
||||
| HuggingFace 上的各类 SAE | 搜索标签 `saelens` | 各种 |
|
||||
|
||||
### 检查清单
|
||||
- [ ] 使用 TransformerLens 加载模型
|
||||
- [ ] 为目标层加载匹配的 SAE
|
||||
- [ ] 将激活编码为稀疏特征
|
||||
- [ ] 识别每个 token 的顶部激活特征
|
||||
- [ ] 验证重建质量
|
||||
|
||||
## 工作流 2:训练自定义 SAE
|
||||
|
||||
### 步骤说明
|
||||
|
||||
```python
|
||||
from sae_lens import SAE, LanguageModelSAERunnerConfig, SAETrainingRunner
|
||||
|
||||
# 1. 配置训练
|
||||
cfg = LanguageModelSAERunnerConfig(
|
||||
# 模型
|
||||
model_name="gpt2-small",
|
||||
hook_name="blocks.8.hook_resid_pre",
|
||||
hook_layer=8,
|
||||
d_in=768, # 模型维度
|
||||
|
||||
# SAE 架构
|
||||
architecture="standard", # 或 "gated"、"topk"
|
||||
d_sae=768 * 8, # 扩展因子为 8
|
||||
activation_fn="relu",
|
||||
|
||||
# 训练
|
||||
lr=4e-4,
|
||||
l1_coefficient=8e-5, # 稀疏性惩罚
|
||||
l1_warm_up_steps=1000,
|
||||
train_batch_size_tokens=4096,
|
||||
training_tokens=100_000_000,
|
||||
|
||||
# 数据
|
||||
dataset_path="monology/pile-uncopyrighted",
|
||||
context_size=128,
|
||||
|
||||
# 日志
|
||||
log_to_wandb=True,
|
||||
wandb_project="sae-training",
|
||||
|
||||
# 检查点
|
||||
checkpoint_path="checkpoints",
|
||||
n_checkpoints=5,
|
||||
)
|
||||
|
||||
# 2. 训练
|
||||
trainer = SAETrainingRunner(cfg)
|
||||
sae = trainer.run()
|
||||
|
||||
# 3. 评估
|
||||
print(f"L0 (avg active features): {trainer.metrics['l0']}")
|
||||
print(f"CE Loss Recovered: {trainer.metrics['ce_loss_score']}")
|
||||
```
|
||||
|
||||
### 关键超参数
|
||||
|
||||
| 参数 | 典型值 | 效果 |
|
||||
|-----------|---------------|--------|
|
||||
| `d_sae` | 4–16× d_model | 特征更多,容量更大 |
|
||||
| `l1_coefficient` | 5e-5 到 1e-4 | 越高 = 越稀疏,精度越低 |
|
||||
| `lr` | 1e-4 到 1e-3 | 标准优化器学习率 |
|
||||
| `l1_warm_up_steps` | 500–2000 | 防止特征早期死亡 |
|
||||
|
||||
### 评估指标
|
||||
|
||||
| 指标 | 目标值 | 含义 |
|
||||
|--------|--------|---------|
|
||||
| **L0** | 50–200 | 每个 token 的平均激活特征数 |
|
||||
| **CE Loss Score** | 80–95% | 相对原始模型恢复的交叉熵 |
|
||||
| **Dead Features** | <5% | 从不激活的特征比例 |
|
||||
| **Explained Variance** | >90% | 重建质量 |
|
||||
|
||||
### 检查清单
|
||||
- [ ] 选择目标层和 hook 点
|
||||
- [ ] 设置扩展因子(d_sae = 4–16× d_model)
|
||||
- [ ] 调整 L1 系数以获得期望的稀疏度
|
||||
- [ ] 启用 L1 预热以防止特征死亡
|
||||
- [ ] 训练期间监控指标(W&B)
|
||||
- [ ] 验证 L0 和 CE loss 恢复情况
|
||||
- [ ] 检查死亡特征比例
|
||||
|
||||
## 工作流 3:特征分析与引导
|
||||
|
||||
### 分析单个特征
|
||||
|
||||
```python
|
||||
from transformer_lens import HookedTransformer
|
||||
from sae_lens import SAE
|
||||
import torch
|
||||
|
||||
model = HookedTransformer.from_pretrained("gpt2-small", device="cuda")
|
||||
sae, _, _ = SAE.from_pretrained(
|
||||
release="gpt2-small-res-jb",
|
||||
sae_id="blocks.8.hook_resid_pre",
|
||||
device="cuda"
|
||||
)
|
||||
|
||||
# 找出激活特定特征的内容
|
||||
feature_idx = 1234
|
||||
test_texts = [
|
||||
"The scientist conducted an experiment",
|
||||
"I love chocolate cake",
|
||||
"The code compiles successfully",
|
||||
"Paris is beautiful in spring",
|
||||
]
|
||||
|
||||
for text in test_texts:
|
||||
tokens = model.to_tokens(text)
|
||||
_, cache = model.run_with_cache(tokens)
|
||||
features = sae.encode(cache["resid_pre", 8])
|
||||
activation = features[0, :, feature_idx].max().item()
|
||||
print(f"{activation:.3f}: {text}")
|
||||
```
|
||||
|
||||
### 特征引导(Feature Steering)
|
||||
|
||||
```python
|
||||
def steer_with_feature(model, sae, prompt, feature_idx, strength=5.0):
|
||||
"""将 SAE 特征方向添加到残差流。"""
|
||||
tokens = model.to_tokens(prompt)
|
||||
|
||||
# 从解码器获取特征方向
|
||||
feature_direction = sae.W_dec[feature_idx] # [d_model]
|
||||
|
||||
def steering_hook(activation, hook):
|
||||
# 在所有位置添加缩放后的特征方向
|
||||
activation += strength * feature_direction
|
||||
return activation
|
||||
|
||||
# 带引导的生成
|
||||
output = model.generate(
|
||||
tokens,
|
||||
max_new_tokens=50,
|
||||
fwd_hooks=[("blocks.8.hook_resid_pre", steering_hook)]
|
||||
)
|
||||
return model.to_string(output[0])
|
||||
```
|
||||
|
||||
### 特征归因(Feature Attribution)
|
||||
|
||||
```python
|
||||
# 哪些特征对特定输出影响最大?
|
||||
tokens = model.to_tokens("The capital of France is")
|
||||
_, cache = model.run_with_cache(tokens)
|
||||
|
||||
# 获取最后位置的特征
|
||||
features = sae.encode(cache["resid_pre", 8])[0, -1] # [d_sae]
|
||||
|
||||
# 计算每个特征的 logit 归因
|
||||
# 特征贡献 = 特征激活 × 解码器权重 × 反嵌入
|
||||
W_dec = sae.W_dec # [d_sae, d_model]
|
||||
W_U = model.W_U # [d_model, vocab]
|
||||
|
||||
# 对 "Paris" logit 的贡献
|
||||
paris_token = model.to_single_token(" Paris")
|
||||
feature_contributions = features * (W_dec @ W_U[:, paris_token])
|
||||
|
||||
top_features = feature_contributions.topk(10)
|
||||
print("Top features for 'Paris' prediction:")
|
||||
for idx, val in zip(top_features.indices, top_features.values):
|
||||
print(f" Feature {idx.item()}: {val.item():.3f}")
|
||||
```
|
||||
|
||||
## 常见问题与解决方案
|
||||
|
||||
### 问题:死亡特征比例过高
|
||||
```python
|
||||
# 错误:无预热,特征早期死亡
|
||||
cfg = LanguageModelSAERunnerConfig(
|
||||
l1_coefficient=1e-4,
|
||||
l1_warm_up_steps=0, # 不推荐!
|
||||
)
|
||||
|
||||
# 正确:预热 L1 惩罚
|
||||
cfg = LanguageModelSAERunnerConfig(
|
||||
l1_coefficient=8e-5,
|
||||
l1_warm_up_steps=1000, # 逐步增加
|
||||
use_ghost_grads=True, # 复活死亡特征
|
||||
)
|
||||
```
|
||||
|
||||
### 问题:重建效果差(CE 恢复率低)
|
||||
```python
|
||||
# 降低稀疏性惩罚
|
||||
cfg = LanguageModelSAERunnerConfig(
|
||||
l1_coefficient=5e-5, # 越低 = 重建越好
|
||||
d_sae=768 * 16, # 更大容量
|
||||
)
|
||||
```
|
||||
|
||||
### 问题:特征不可解释
|
||||
```python
|
||||
# 提高稀疏性(更高的 L1)
|
||||
cfg = LanguageModelSAERunnerConfig(
|
||||
l1_coefficient=1e-4, # 越高 = 越稀疏,可解释性越强
|
||||
)
|
||||
# 或使用 TopK 架构
|
||||
cfg = LanguageModelSAERunnerConfig(
|
||||
architecture="topk",
|
||||
activation_fn_kwargs={"k": 50}, # 恰好 50 个激活特征
|
||||
)
|
||||
```
|
||||
|
||||
### 问题:训练时内存错误
|
||||
```python
|
||||
cfg = LanguageModelSAERunnerConfig(
|
||||
train_batch_size_tokens=2048, # 减小批次大小
|
||||
store_batch_size_prompts=4, # 缓冲区中更少的 prompt
|
||||
n_batches_in_buffer=8, # 更小的激活缓冲区
|
||||
)
|
||||
```
|
||||
|
||||
## 与 Neuronpedia 集成
|
||||
|
||||
在 [neuronpedia.org](https://neuronpedia.org) 浏览预训练 SAE 特征:
|
||||
|
||||
```python
|
||||
# 特征通过 SAE ID 索引
|
||||
# 示例:gpt2-small 第 8 层特征 1234
|
||||
# → neuronpedia.org/gpt2-small/8-res-jb/1234
|
||||
```
|
||||
|
||||
## 关键类参考
|
||||
|
||||
| 类 | 用途 |
|
||||
|-------|---------|
|
||||
| `SAE` | 稀疏自编码器模型 |
|
||||
| `LanguageModelSAERunnerConfig` | 训练配置 |
|
||||
| `SAETrainingRunner` | 训练循环管理器 |
|
||||
| `ActivationsStore` | 激活收集与批处理 |
|
||||
| `HookedSAETransformer` | TransformerLens + SAE 集成 |
|
||||
|
||||
## 参考文档
|
||||
|
||||
详细的 API 文档、教程和高级用法,请参阅 `references/` 文件夹:
|
||||
|
||||
| 文件 | 内容 |
|
||||
|------|----------|
|
||||
| [references/README.md](https://github.com/NousResearch/hermes-agent/blob/main/optional-skills/mlops/saelens/references/README.md) | 概述与快速入门指南 |
|
||||
| [references/api.md](https://github.com/NousResearch/hermes-agent/blob/main/optional-skills/mlops/saelens/references/api.md) | SAE、TrainingSAE、配置的完整 API 参考 |
|
||||
| [references/tutorials.md](https://github.com/NousResearch/hermes-agent/blob/main/optional-skills/mlops/saelens/references/tutorials.md) | 训练、分析、引导的分步教程 |
|
||||
|
||||
## 外部资源
|
||||
|
||||
### 教程
|
||||
- [基础加载与分析](https://github.com/jbloomAus/SAELens/blob/main/tutorials/basic_loading_and_analysing.ipynb)
|
||||
- [训练稀疏自编码器](https://github.com/jbloomAus/SAELens/blob/main/tutorials/training_a_sparse_autoencoder.ipynb)
|
||||
- [ARENA SAE 课程](https://www.lesswrong.com/posts/LnHowHgmrMbWtpkxx/intro-to-superposition-and-sparse-autoencoders-colab)
|
||||
|
||||
### 论文
|
||||
- [Towards Monosemanticity](https://transformer-circuits.pub/2023/monosemantic-features) — Anthropic(2023)
|
||||
- [Scaling Monosemanticity](https://transformer-circuits.pub/2024/scaling-monosemanticity/) — Anthropic(2024)
|
||||
- [Sparse Autoencoders Find Highly Interpretable Features](https://arxiv.org/abs/2309.08600) — Cunningham et al.(ICLR 2024)
|
||||
|
||||
### 官方文档
|
||||
- [SAELens 文档](https://jbloomaus.github.io/SAELens/)
|
||||
- [Neuronpedia](https://neuronpedia.org) — 特征浏览器
|
||||
|
||||
## SAE 架构
|
||||
|
||||
| 架构 | 描述 | 适用场景 |
|
||||
|--------------|-------------|----------|
|
||||
| **Standard** | ReLU + L1 惩罚 | 通用 |
|
||||
| **Gated** | 学习门控机制 | 更好的稀疏性控制 |
|
||||
| **TopK** | 恰好 K 个激活特征 | 一致的稀疏性 |
|
||||
|
||||
```python
|
||||
# TopK SAE(恰好 50 个特征激活)
|
||||
cfg = LanguageModelSAERunnerConfig(
|
||||
architecture="topk",
|
||||
activation_fn="topk",
|
||||
activation_fn_kwargs={"k": 50},
|
||||
)
|
||||
```
|
||||
+237
@@ -0,0 +1,237 @@
|
||||
---
|
||||
title: "Simpo 训练 — 用于 LLM 对齐的简单偏好优化"
|
||||
sidebar_label: "Simpo 训练"
|
||||
description: "用于 LLM 对齐的简单偏好优化"
|
||||
---
|
||||
|
||||
{/* This page is auto-generated from the skill's SKILL.md by website/scripts/generate-skill-docs.py. Edit the source SKILL.md, not this page. */}
|
||||
|
||||
# Simpo 训练
|
||||
|
||||
用于 LLM 对齐的简单偏好优化(Simple Preference Optimization)。无需参考模型的 DPO 替代方案,性能更优(在 AlpacaEval 2.0 上提升 +6.4 分)。无需参考模型,比 DPO 更高效。当需要比 DPO/PPO 更简单、更快速的训练时,可用于偏好对齐。
|
||||
|
||||
## Skill 元数据
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| 来源 | 可选 — 通过 `hermes skills install official/mlops/simpo` 安装 |
|
||||
| 路径 | `optional-skills/mlops/simpo` |
|
||||
| 版本 | `1.0.0` |
|
||||
| 作者 | Orchestra Research |
|
||||
| 许可证 | MIT |
|
||||
| 依赖项 | `torch`, `transformers`, `datasets`, `trl`, `accelerate` |
|
||||
| 平台 | linux, macos, windows |
|
||||
| 标签 | `Post-Training`, `SimPO`, `Preference Optimization`, `Alignment`, `DPO Alternative`, `Reference-Free`, `LLM Alignment`, `Efficient Training` |
|
||||
|
||||
## 参考:完整 SKILL.md
|
||||
|
||||
:::info
|
||||
以下是 Hermes 在触发此 skill 时加载的完整 skill 定义。这是 agent 在 skill 激活时所看到的指令内容。
|
||||
:::
|
||||
|
||||
# SimPO - 简单偏好优化
|
||||
|
||||
## 快速开始
|
||||
|
||||
SimPO 是一种无需参考模型的偏好优化方法,性能优于 DPO。
|
||||
|
||||
**安装**:
|
||||
```bash
|
||||
# Create environment
|
||||
conda create -n simpo python=3.10 && conda activate simpo
|
||||
|
||||
# Install PyTorch 2.2.2
|
||||
# Visit: https://pytorch.org/get-started/locally/
|
||||
|
||||
# Install alignment-handbook
|
||||
git clone https://github.com/huggingface/alignment-handbook.git
|
||||
cd alignment-handbook
|
||||
python -m pip install .
|
||||
|
||||
# Install Flash Attention 2
|
||||
python -m pip install flash-attn --no-build-isolation
|
||||
```
|
||||
|
||||
**训练**(Mistral 7B):
|
||||
```bash
|
||||
ACCELERATE_LOG_LEVEL=info accelerate launch \
|
||||
--config_file accelerate_configs/deepspeed_zero3.yaml \
|
||||
scripts/run_simpo.py \
|
||||
training_configs/mistral-7b-base-simpo.yaml
|
||||
```
|
||||
|
||||
## 常见工作流
|
||||
|
||||
### 工作流 1:从基础模型训练(Mistral 7B)
|
||||
|
||||
**配置文件**(`mistral-7b-base-simpo.yaml`):
|
||||
```yaml
|
||||
# Model
|
||||
model_name_or_path: mistralai/Mistral-7B-v0.1
|
||||
torch_dtype: bfloat16
|
||||
|
||||
# Dataset
|
||||
dataset_mixer:
|
||||
HuggingFaceH4/ultrafeedback_binarized: 1.0
|
||||
dataset_splits:
|
||||
- train_prefs
|
||||
- test_prefs
|
||||
|
||||
# SimPO hyperparameters
|
||||
beta: 2.0 # Reward scaling (2.0-10.0)
|
||||
gamma_beta_ratio: 0.5 # Target margin (0-1)
|
||||
loss_type: sigmoid # sigmoid or hinge
|
||||
sft_weight: 0.0 # Optional SFT regularization
|
||||
|
||||
# Training
|
||||
learning_rate: 5e-7 # Critical: 3e-7 to 1e-6
|
||||
num_train_epochs: 1
|
||||
per_device_train_batch_size: 1
|
||||
gradient_accumulation_steps: 8
|
||||
|
||||
# Output
|
||||
output_dir: ./outputs/mistral-7b-simpo
|
||||
```
|
||||
|
||||
**启动训练**:
|
||||
```bash
|
||||
accelerate launch --config_file accelerate_configs/deepspeed_zero3.yaml \
|
||||
scripts/run_simpo.py training_configs/mistral-7b-base-simpo.yaml
|
||||
```
|
||||
|
||||
### 工作流 2:微调指令模型(Llama 3 8B)
|
||||
|
||||
**配置文件**(`llama3-8b-instruct-simpo.yaml`):
|
||||
```yaml
|
||||
model_name_or_path: meta-llama/Meta-Llama-3-8B-Instruct
|
||||
|
||||
dataset_mixer:
|
||||
argilla/ultrafeedback-binarized-preferences-cleaned: 1.0
|
||||
|
||||
beta: 2.5
|
||||
gamma_beta_ratio: 0.5
|
||||
learning_rate: 5e-7
|
||||
sft_weight: 0.1 # Add SFT loss to preserve capabilities
|
||||
|
||||
num_train_epochs: 1
|
||||
per_device_train_batch_size: 2
|
||||
gradient_accumulation_steps: 4
|
||||
output_dir: ./outputs/llama3-8b-simpo
|
||||
```
|
||||
|
||||
**启动**:
|
||||
```bash
|
||||
accelerate launch --config_file accelerate_configs/deepspeed_zero3.yaml \
|
||||
scripts/run_simpo.py training_configs/llama3-8b-instruct-simpo.yaml
|
||||
```
|
||||
|
||||
### 工作流 3:推理密集型任务(较低学习率)
|
||||
|
||||
**适用于数学/代码任务**:
|
||||
```yaml
|
||||
model_name_or_path: deepseek-ai/deepseek-math-7b-base
|
||||
|
||||
dataset_mixer:
|
||||
argilla/distilabel-math-preference-dpo: 1.0
|
||||
|
||||
beta: 5.0 # Higher for stronger signal
|
||||
gamma_beta_ratio: 0.7 # Larger margin
|
||||
learning_rate: 3e-7 # Lower LR for reasoning
|
||||
sft_weight: 0.0
|
||||
|
||||
num_train_epochs: 1
|
||||
per_device_train_batch_size: 1
|
||||
gradient_accumulation_steps: 16
|
||||
```
|
||||
|
||||
## 何时使用及替代方案
|
||||
|
||||
**适合使用 SimPO 的场景**:
|
||||
- 希望比 DPO 训练更简单(无需参考模型)
|
||||
- 拥有偏好数据(chosen/rejected 对)
|
||||
- 需要比 DPO 更好的性能
|
||||
- 计算资源有限
|
||||
- 单节点训练即可满足需求
|
||||
|
||||
**算法选择**:
|
||||
- **SimPO**:最简单、性能最优、无需参考模型
|
||||
- **DPO**:需要参考模型基线,更为保守
|
||||
- **PPO**:最大控制度,需要奖励模型,配置复杂
|
||||
- **GRPO**:内存高效的 RL,无需 critic
|
||||
|
||||
**改用其他方案的场景**:
|
||||
- **OpenRLHF**:多节点分布式训练,PPO/GRPO
|
||||
- **TRL**:需要在单一框架中使用多种方法
|
||||
- **DPO**:需要建立已有基线对比
|
||||
|
||||
## 常见问题
|
||||
|
||||
**问题:损失发散**
|
||||
|
||||
降低学习率:
|
||||
```yaml
|
||||
learning_rate: 3e-7 # Reduce from 5e-7
|
||||
```
|
||||
|
||||
降低 beta:
|
||||
```yaml
|
||||
beta: 1.0 # Reduce from 2.0
|
||||
```
|
||||
|
||||
**问题:模型遗忘原有能力**
|
||||
|
||||
添加 SFT 正则化:
|
||||
```yaml
|
||||
sft_weight: 0.1 # Add SFT loss component
|
||||
```
|
||||
|
||||
**问题:偏好分离效果差**
|
||||
|
||||
提高 beta 和 margin:
|
||||
```yaml
|
||||
beta: 5.0 # Increase from 2.0
|
||||
gamma_beta_ratio: 0.8 # Increase from 0.5
|
||||
```
|
||||
|
||||
**问题:训练时显存不足(OOM)**
|
||||
|
||||
减小批次大小:
|
||||
```yaml
|
||||
per_device_train_batch_size: 1
|
||||
gradient_accumulation_steps: 16 # Maintain effective batch
|
||||
```
|
||||
|
||||
启用梯度检查点:
|
||||
```yaml
|
||||
gradient_checkpointing: true
|
||||
```
|
||||
|
||||
## 进阶主题
|
||||
|
||||
**损失函数**:参见 [references/loss-functions.md](https://github.com/NousResearch/hermes-agent/blob/main/optional-skills/mlops/simpo/references/loss-functions.md),了解 sigmoid 与 hinge 损失、数学公式及各自适用场景。
|
||||
|
||||
**超参数调优**:参见 [references/hyperparameters.md](https://github.com/NousResearch/hermes-agent/blob/main/optional-skills/mlops/simpo/references/hyperparameters.md),了解 beta、gamma、学习率选择指南及针对不同模型规模的建议。
|
||||
|
||||
**数据集准备**:参见 [references/datasets.md](https://github.com/NousResearch/hermes-agent/blob/main/optional-skills/mlops/simpo/references/datasets.md),了解偏好数据格式、质量过滤及自定义数据集创建方法。
|
||||
|
||||
## 硬件要求
|
||||
|
||||
- **GPU**:推荐 NVIDIA A100/H100
|
||||
- **显存**:
|
||||
- 7B 模型:1× A100 40GB(DeepSpeed ZeRO-3)
|
||||
- 8B 模型:2× A100 40GB
|
||||
- 70B 模型:8× A100 80GB
|
||||
- **单节点**:DeepSpeed ZeRO-3 即可满足
|
||||
- **混合精度**:推荐 BF16
|
||||
|
||||
**内存优化**:
|
||||
- DeepSpeed ZeRO-3(默认配置)
|
||||
- 梯度检查点
|
||||
- Flash Attention 2
|
||||
|
||||
## 资源
|
||||
|
||||
- 论文:https://arxiv.org/abs/2405.14734(NeurIPS 2024)
|
||||
- GitHub:https://github.com/princeton-nlp/SimPO
|
||||
- 模型:https://huggingface.co/princeton-nlp
|
||||
- Alignment Handbook:https://github.com/huggingface/alignment-handbook
|
||||
+486
@@ -0,0 +1,486 @@
|
||||
---
|
||||
title: "Slime Rl Training — 使用 slime(Megatron+SGLang 框架)进行 LLM RL 后训练的指导"
|
||||
sidebar_label: "Slime Rl Training"
|
||||
description: "使用 slime(Megatron+SGLang 框架)进行 LLM RL 后训练的指导"
|
||||
---
|
||||
|
||||
{/* This page is auto-generated from the skill's SKILL.md by website/scripts/generate-skill-docs.py. Edit the source SKILL.md, not this page. */}
|
||||
|
||||
# Slime Rl Training
|
||||
|
||||
使用 slime(Megatron+SGLang 框架)进行 LLM RL(强化学习)后训练的指导。适用于训练 GLM 模型、实现自定义数据生成工作流,或需要 Megatron-LM 紧密集成以进行 RL 扩展的场景。
|
||||
|
||||
## Skill 元数据
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| 来源 | 可选 — 通过 `hermes skills install official/mlops/slime` 安装 |
|
||||
| 路径 | `optional-skills/mlops/slime` |
|
||||
| 版本 | `1.0.0` |
|
||||
| 作者 | Orchestra Research |
|
||||
| 许可证 | MIT |
|
||||
| 依赖 | `sglang-router>=0.2.3`, `ray`, `torch>=2.0.0`, `transformers>=4.40.0` |
|
||||
| 平台 | linux, macos |
|
||||
| 标签 | `Reinforcement Learning`, `Megatron-LM`, `SGLang`, `GRPO`, `Post-Training`, `GLM` |
|
||||
|
||||
## 参考:完整 SKILL.md
|
||||
|
||||
:::info
|
||||
以下是 Hermes 在触发此 skill 时加载的完整 skill 定义。这是 agent 在 skill 激活时所看到的指令内容。
|
||||
:::
|
||||
|
||||
# slime:面向 RL 扩展的 LLM 后训练框架
|
||||
|
||||
slime 是清华大学 THUDM 团队开发的 LLM 后训练框架,为 GLM-4.5、GLM-4.6 和 GLM-4.7 提供支持。它将 Megatron-LM(用于训练)与 SGLang(用于高吞吐量 rollout 生成)相连接。
|
||||
|
||||
## 何时使用 slime
|
||||
|
||||
**在以下情况下选择 slime:**
|
||||
- 需要 Megatron-LM 原生训练配合 SGLang 推理
|
||||
- 需要带有灵活数据缓冲区的自定义数据生成工作流
|
||||
- 训练 GLM、Qwen3、DeepSeek V3 或 Llama 3 模型
|
||||
- 需要具有生产级支持(Z.ai)的研究级框架
|
||||
|
||||
**在以下情况下考虑替代方案:**
|
||||
- 需要企业级稳定性功能 → 使用 **miles**
|
||||
- 需要灵活的后端切换 → 使用 **verl**
|
||||
- 需要 PyTorch 原生抽象 → 使用 **torchforge**
|
||||
|
||||
## 核心特性
|
||||
|
||||
- **训练**:Megatron-LM,支持完整并行(TP、PP、DP、SP)
|
||||
- **Rollout**:基于 SGLang 的高吞吐量生成,带 router
|
||||
- **数据缓冲区**:灵活的 prompt 管理与样本存储
|
||||
- **模型**:GLM-4.x、Qwen3、DeepSeek V3/R1、Llama 3
|
||||
|
||||
## 架构概览
|
||||
|
||||
<!-- ascii-guard-ignore -->
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ Data Buffer │
|
||||
│ - Prompt initialization and management │
|
||||
│ - Custom data generation and filtering │
|
||||
│ - Rollout sample storage │
|
||||
└─────────────┬───────────────────────────┬───────────────┘
|
||||
│ │
|
||||
┌─────────────▼───────────┐ ┌─────────────▼───────────────┐
|
||||
│ Training (Megatron-LM) │ │ Rollout (SGLang + Router) │
|
||||
│ - Actor model training │ │ - Response generation │
|
||||
│ - Critic (optional) │ │ - Reward/verifier output │
|
||||
│ - Weight sync to rollout│ │ - Multi-turn support │
|
||||
└─────────────────────────┘ └─────────────────────────────┘
|
||||
```
|
||||
<!-- ascii-guard-ignore-end -->
|
||||
|
||||
## 安装
|
||||
|
||||
```bash
|
||||
# 推荐:Docker
|
||||
docker pull slimerl/slime:latest
|
||||
docker run --rm --gpus all --ipc=host --shm-size=16g \
|
||||
-it slimerl/slime:latest /bin/bash
|
||||
|
||||
# 容器内
|
||||
cd /root/slime && pip install -e . --no-deps
|
||||
```
|
||||
|
||||
### 从源码安装
|
||||
|
||||
```bash
|
||||
git clone https://github.com/THUDM/slime.git
|
||||
cd slime
|
||||
pip install -r requirements.txt
|
||||
pip install -e .
|
||||
```
|
||||
|
||||
## 快速开始:GRPO 训练
|
||||
|
||||
```bash
|
||||
# 加载模型配置
|
||||
source scripts/models/qwen3-4B.sh
|
||||
|
||||
# 启动训练
|
||||
python train.py \
|
||||
--actor-num-nodes 1 \
|
||||
--actor-num-gpus-per-node 4 \
|
||||
--rollout-num-gpus 4 \
|
||||
--advantage-estimator grpo \
|
||||
--use-kl-loss --kl-loss-coef 0.001 \
|
||||
--rollout-batch-size 32 \
|
||||
--n-samples-per-prompt 8 \
|
||||
--global-batch-size 256 \
|
||||
--num-rollout 3000 \
|
||||
--prompt-data /path/to/data.jsonl \
|
||||
${MODEL_ARGS[@]} ${CKPT_ARGS[@]}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 工作流 1:标准 GRPO 训练
|
||||
|
||||
使用此工作流通过组相对优势(group-relative advantages)训练推理模型。
|
||||
|
||||
### 前置条件清单
|
||||
- [ ] Docker 环境,或已安装 Megatron-LM + SGLang
|
||||
- [ ] 模型检查点(HuggingFace 或 Megatron 格式)
|
||||
- [ ] JSONL 格式的训练数据
|
||||
|
||||
### 第一步:准备数据
|
||||
|
||||
```python
|
||||
# data.jsonl 格式
|
||||
{"prompt": "What is 2 + 2?", "label": "4"}
|
||||
{"prompt": "Solve: 3x = 12", "label": "x = 4"}
|
||||
```
|
||||
|
||||
或使用对话格式:
|
||||
```python
|
||||
{
|
||||
"prompt": [
|
||||
{"role": "system", "content": "You are a math tutor."},
|
||||
{"role": "user", "content": "What is 15 + 27?"}
|
||||
],
|
||||
"label": "42"
|
||||
}
|
||||
```
|
||||
|
||||
### 第二步:配置模型
|
||||
|
||||
选择预配置的模型脚本:
|
||||
|
||||
```bash
|
||||
# 列出可用模型
|
||||
ls scripts/models/
|
||||
# glm4-9B.sh, qwen3-4B.sh, qwen3-30B-A3B.sh, deepseek-v3.sh, llama3-8B.sh, ...
|
||||
|
||||
# 加载你的模型
|
||||
source scripts/models/qwen3-4B.sh
|
||||
```
|
||||
|
||||
### 第三步:启动训练
|
||||
|
||||
```bash
|
||||
python train.py \
|
||||
--actor-num-nodes 1 \
|
||||
--actor-num-gpus-per-node 8 \
|
||||
--rollout-num-gpus 8 \
|
||||
--advantage-estimator grpo \
|
||||
--use-kl-loss \
|
||||
--kl-loss-coef 0.001 \
|
||||
--prompt-data /path/to/train.jsonl \
|
||||
--input-key prompt \
|
||||
--label-key label \
|
||||
--apply-chat-template \
|
||||
--rollout-batch-size 32 \
|
||||
--n-samples-per-prompt 8 \
|
||||
--global-batch-size 256 \
|
||||
--num-rollout 3000 \
|
||||
--save-interval 100 \
|
||||
--eval-interval 50 \
|
||||
${MODEL_ARGS[@]}
|
||||
```
|
||||
|
||||
### 第四步:监控训练
|
||||
- [ ] 查看 TensorBoard:`tensorboard --logdir outputs/`
|
||||
- [ ] 确认奖励曲线持续上升
|
||||
- [ ] 监控各节点 GPU 利用率
|
||||
|
||||
---
|
||||
|
||||
## 工作流 2:异步训练
|
||||
|
||||
使用异步模式通过重叠 rollout 与训练来提高吞吐量。
|
||||
|
||||
### 何时使用异步模式
|
||||
- 大型模型生成时间较长
|
||||
- 同步模式下 GPU 空闲时间较多
|
||||
- 有足够内存用于缓冲
|
||||
|
||||
### 启动异步训练
|
||||
|
||||
```bash
|
||||
python train_async.py \
|
||||
--actor-num-nodes 1 \
|
||||
--actor-num-gpus-per-node 8 \
|
||||
--rollout-num-gpus 8 \
|
||||
--advantage-estimator grpo \
|
||||
--async-buffer-size 4 \
|
||||
--prompt-data /path/to/train.jsonl \
|
||||
${MODEL_ARGS[@]}
|
||||
```
|
||||
|
||||
### 异步专用参数
|
||||
|
||||
```bash
|
||||
--async-buffer-size 4 # 缓冲的 rollout 数量
|
||||
--update-weights-interval 2 # 每 N 次 rollout 同步一次权重
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 工作流 3:多轮 Agentic 训练
|
||||
|
||||
使用此工作流训练具备工具调用或多步推理能力的 agent。
|
||||
|
||||
### 前置条件
|
||||
- [ ] 用于多轮逻辑的自定义 generate 函数
|
||||
- [ ] 工具/环境接口
|
||||
|
||||
### 第一步:定义自定义 Generate 函数
|
||||
|
||||
```python
|
||||
# custom_generate.py
|
||||
async def custom_generate(args, samples, evaluation=False):
|
||||
"""带工具调用的多轮生成。"""
|
||||
for sample in samples:
|
||||
conversation = sample.prompt
|
||||
|
||||
for turn in range(args.max_turns):
|
||||
# 生成响应
|
||||
response = await generate_single(conversation)
|
||||
|
||||
# 检查工具调用
|
||||
tool_call = extract_tool_call(response)
|
||||
if tool_call:
|
||||
tool_result = execute_tool(tool_call)
|
||||
conversation.append({"role": "assistant", "content": response})
|
||||
conversation.append({"role": "tool", "content": tool_result})
|
||||
else:
|
||||
break
|
||||
|
||||
sample.response = response
|
||||
sample.reward = compute_reward(sample)
|
||||
|
||||
return samples
|
||||
```
|
||||
|
||||
### 第二步:使用自定义函数启动
|
||||
|
||||
```bash
|
||||
python train.py \
|
||||
--custom-generate-function-path custom_generate.py \
|
||||
--max-turns 5 \
|
||||
--prompt-data /path/to/agent_data.jsonl \
|
||||
${MODEL_ARGS[@]}
|
||||
```
|
||||
|
||||
完整的多轮搜索示例请参见 `examples/search-r1/`。
|
||||
|
||||
---
|
||||
|
||||
## 配置参考
|
||||
|
||||
### 三类参数
|
||||
|
||||
slime 使用三种类型的参数:
|
||||
|
||||
**1. Megatron 参数**(直接传入):
|
||||
```bash
|
||||
--tensor-model-parallel-size 2
|
||||
--pipeline-model-parallel-size 1
|
||||
--num-layers 32
|
||||
--hidden-size 4096
|
||||
```
|
||||
|
||||
**2. SGLang 参数**(以 `--sglang-` 为前缀):
|
||||
```bash
|
||||
--sglang-mem-fraction-static 0.8
|
||||
--sglang-context-length 8192
|
||||
--sglang-log-level INFO
|
||||
```
|
||||
|
||||
**3. slime 参数**:
|
||||
```bash
|
||||
# 资源分配
|
||||
--actor-num-nodes 1
|
||||
--actor-num-gpus-per-node 8
|
||||
--rollout-num-gpus 8
|
||||
--colocate # 训练与推理共享 GPU
|
||||
|
||||
# 数据
|
||||
--prompt-data /path/to/data.jsonl
|
||||
--input-key prompt
|
||||
--label-key label
|
||||
|
||||
# 训练循环
|
||||
--num-rollout 3000
|
||||
--rollout-batch-size 32
|
||||
--n-samples-per-prompt 8
|
||||
--global-batch-size 256
|
||||
|
||||
# 算法
|
||||
--advantage-estimator grpo # 或:gspo, ppo, reinforce_plus_plus
|
||||
--use-kl-loss
|
||||
--kl-loss-coef 0.001
|
||||
```
|
||||
|
||||
### 关键约束
|
||||
|
||||
```
|
||||
rollout_batch_size × n_samples_per_prompt = global_batch_size × num_steps_per_rollout
|
||||
```
|
||||
|
||||
示例:32 × 8 = 256 × 1
|
||||
|
||||
---
|
||||
|
||||
## 数据缓冲区系统
|
||||
|
||||
slime 的数据缓冲区支持灵活的数据管理:
|
||||
|
||||
### 基础数据源
|
||||
|
||||
```python
|
||||
class RolloutDataSource:
|
||||
def get_samples(self, num_samples):
|
||||
"""从数据集中获取 prompt。"""
|
||||
return self.dataset.sample(num_samples)
|
||||
|
||||
def add_samples(self, samples):
|
||||
"""生成后调用(默认为空操作)。"""
|
||||
pass
|
||||
```
|
||||
|
||||
### 带缓冲区的数据源(离线策略)
|
||||
|
||||
```python
|
||||
class RolloutDataSourceWithBuffer(RolloutDataSource):
|
||||
def __init__(self):
|
||||
self.buffer = []
|
||||
|
||||
def add_samples(self, samples):
|
||||
"""存储已生成的样本以供复用。"""
|
||||
self.buffer.extend(samples)
|
||||
|
||||
def buffer_filter(self, args, buffer, num_samples):
|
||||
"""自定义选择逻辑(优先级、分层等)。"""
|
||||
return select_best(buffer, num_samples)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 常见问题与解决方案
|
||||
|
||||
### 问题:SGLang 引擎崩溃
|
||||
|
||||
**现象**:推理引擎在训练中途退出
|
||||
|
||||
**解决方案**:
|
||||
```bash
|
||||
# 启用容错
|
||||
--use-fault-tolerance
|
||||
|
||||
# 增加内存分配
|
||||
--sglang-mem-fraction-static 0.85
|
||||
|
||||
# 减小批大小
|
||||
--rollout-batch-size 16
|
||||
```
|
||||
|
||||
### 问题:权重同步超时
|
||||
|
||||
**现象**:rollout 后训练挂起
|
||||
|
||||
**解决方案**:
|
||||
```bash
|
||||
# 增大同步间隔
|
||||
--update-weights-interval 5
|
||||
|
||||
# 使用 colocate 模式(无网络传输)
|
||||
--colocate
|
||||
```
|
||||
|
||||
### 问题:训练时 OOM
|
||||
|
||||
**现象**:反向传播时 CUDA OOM
|
||||
|
||||
**解决方案**:
|
||||
```bash
|
||||
# 启用梯度检查点
|
||||
--recompute-activations
|
||||
|
||||
# 减小 micro-batch 大小
|
||||
--micro-batch-size 1
|
||||
|
||||
# 启用序列并行
|
||||
--sequence-parallel
|
||||
```
|
||||
|
||||
### 问题:数据加载缓慢
|
||||
|
||||
**现象**:数据获取期间 GPU 空闲
|
||||
|
||||
**解决方案**:
|
||||
```bash
|
||||
# 增加数据 worker 数量
|
||||
--num-data-workers 4
|
||||
|
||||
# 使用流式数据集
|
||||
--streaming-data
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 支持的模型
|
||||
|
||||
| 模型系列 | 配置 |
|
||||
|--------------|----------------|
|
||||
| GLM | GLM-4.5、GLM-4.6、GLM-4.7、GLM-Z1-9B |
|
||||
| Qwen | Qwen3(4B、8B、30B-A3B)、Qwen3-MoE、Qwen2.5 |
|
||||
| DeepSeek | V3、V3.1、R1 |
|
||||
| Llama | Llama 3(8B、70B) |
|
||||
| 其他 | Kimi K2、Moonlight-16B |
|
||||
|
||||
每个模型在 `scripts/models/` 中均有预配置脚本。
|
||||
|
||||
---
|
||||
|
||||
## 进阶主题
|
||||
|
||||
### Co-location 模式
|
||||
|
||||
训练与推理共享 GPU 以减少内存占用:
|
||||
|
||||
```bash
|
||||
python train.py \
|
||||
--colocate \
|
||||
--actor-num-gpus-per-node 8 \
|
||||
--sglang-mem-fraction-static 0.4 \
|
||||
${MODEL_ARGS[@]}
|
||||
```
|
||||
|
||||
### 自定义奖励模型
|
||||
|
||||
```python
|
||||
# custom_rm.py
|
||||
class CustomRewardModel:
|
||||
def __init__(self, model_path):
|
||||
self.model = load_model(model_path)
|
||||
|
||||
def compute_reward(self, prompts, responses):
|
||||
inputs = self.tokenize(prompts, responses)
|
||||
scores = self.model(inputs)
|
||||
return scores.tolist()
|
||||
```
|
||||
|
||||
```bash
|
||||
--custom-rm-path custom_rm.py
|
||||
```
|
||||
|
||||
### 多任务评估
|
||||
|
||||
```bash
|
||||
--eval-prompt-data aime /path/to/aime.jsonl \
|
||||
--eval-prompt-data gsm8k /path/to/gsm8k.jsonl \
|
||||
--n-samples-per-eval-prompt 16
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 资源
|
||||
|
||||
- **文档**:https://thudm.github.io/slime/
|
||||
- **GitHub**:https://github.com/THUDM/slime
|
||||
- **博客**:https://lmsys.org/blog/2025-07-09-slime/
|
||||
- **示例**:参见 `examples/` 目录,包含 14+ 个完整示例
|
||||
+542
@@ -0,0 +1,542 @@
|
||||
---
|
||||
title: "Stable Diffusion 图像生成"
|
||||
sidebar_label: "Stable Diffusion 图像生成"
|
||||
description: "通过 HuggingFace Diffusers 使用 Stable Diffusion 模型实现最先进的文本到图像生成"
|
||||
---
|
||||
|
||||
{/* This page is auto-generated from the skill's SKILL.md by website/scripts/generate-skill-docs.py. Edit the source SKILL.md, not this page. */}
|
||||
|
||||
# Stable Diffusion 图像生成
|
||||
|
||||
通过 HuggingFace Diffusers 使用 Stable Diffusion 模型实现最先进的文本到图像生成。适用于从文本 prompt(提示词)生成图像、执行图像到图像转换、图像修复(inpainting),或构建自定义扩散 pipeline。
|
||||
|
||||
## Skill 元数据
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| 来源 | 可选 — 通过 `hermes skills install official/mlops/stable-diffusion` 安装 |
|
||||
| 路径 | `optional-skills/mlops/stable-diffusion` |
|
||||
| 版本 | `1.0.0` |
|
||||
| 作者 | Orchestra Research |
|
||||
| 许可证 | MIT |
|
||||
| 依赖项 | `diffusers>=0.30.0`, `transformers>=4.41.0`, `accelerate>=0.31.0`, `torch>=2.0.0` |
|
||||
| 平台 | linux, macos, windows |
|
||||
| 标签 | `Image Generation`, `Stable Diffusion`, `Diffusers`, `Text-to-Image`, `Multimodal`, `Computer Vision` |
|
||||
|
||||
## 参考:完整 SKILL.md
|
||||
|
||||
:::info
|
||||
以下是 Hermes 在触发此 skill 时加载的完整 skill 定义。这是 agent 在 skill 激活时所看到的指令内容。
|
||||
:::
|
||||
|
||||
# Stable Diffusion 图像生成
|
||||
|
||||
使用 HuggingFace Diffusers 库通过 Stable Diffusion 生成图像的综合指南。
|
||||
|
||||
## 何时使用 Stable Diffusion
|
||||
|
||||
**在以下情况下使用 Stable Diffusion:**
|
||||
- 从文本描述生成图像
|
||||
- 执行图像到图像转换(风格迁移、增强)
|
||||
- Inpainting(填充遮罩区域)
|
||||
- Outpainting(将图像扩展至边界之外)
|
||||
- 创建现有图像的变体
|
||||
- 构建自定义图像生成工作流
|
||||
|
||||
**核心功能:**
|
||||
- **文本到图像**:从自然语言 prompt 生成图像
|
||||
- **图像到图像**:在文本引导下转换现有图像
|
||||
- **Inpainting**:用上下文感知内容填充遮罩区域
|
||||
- **ControlNet**:添加空间条件控制(边缘、姿态、深度)
|
||||
- **LoRA 支持**:高效微调与风格适配
|
||||
- **多模型支持**:支持 SD 1.5、SDXL、SD 3.0、Flux
|
||||
|
||||
**改用以下替代方案:**
|
||||
- **DALL-E 3**:无需 GPU 的 API 生成
|
||||
- **Midjourney**:艺术化、风格化输出
|
||||
- **Imagen**:Google Cloud 集成
|
||||
- **Leonardo.ai**:基于 Web 的创意工作流
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 安装
|
||||
|
||||
```bash
|
||||
pip install diffusers transformers accelerate torch
|
||||
pip install xformers # Optional: memory-efficient attention
|
||||
```
|
||||
|
||||
### 基础文本到图像
|
||||
|
||||
```python
|
||||
from diffusers import DiffusionPipeline
|
||||
import torch
|
||||
|
||||
# Load pipeline (auto-detects model type)
|
||||
pipe = DiffusionPipeline.from_pretrained(
|
||||
"stable-diffusion-v1-5/stable-diffusion-v1-5",
|
||||
torch_dtype=torch.float16
|
||||
)
|
||||
pipe.to("cuda")
|
||||
|
||||
# Generate image
|
||||
image = pipe(
|
||||
"A serene mountain landscape at sunset, highly detailed",
|
||||
num_inference_steps=50,
|
||||
guidance_scale=7.5
|
||||
).images[0]
|
||||
|
||||
image.save("output.png")
|
||||
```
|
||||
|
||||
### 使用 SDXL(更高质量)
|
||||
|
||||
```python
|
||||
from diffusers import AutoPipelineForText2Image
|
||||
import torch
|
||||
|
||||
pipe = AutoPipelineForText2Image.from_pretrained(
|
||||
"stabilityai/stable-diffusion-xl-base-1.0",
|
||||
torch_dtype=torch.float16,
|
||||
variant="fp16"
|
||||
)
|
||||
pipe.to("cuda")
|
||||
|
||||
# Enable memory optimization
|
||||
pipe.enable_model_cpu_offload()
|
||||
|
||||
image = pipe(
|
||||
prompt="A futuristic city with flying cars, cinematic lighting",
|
||||
height=1024,
|
||||
width=1024,
|
||||
num_inference_steps=30
|
||||
).images[0]
|
||||
```
|
||||
|
||||
## 架构概览
|
||||
|
||||
### 三支柱设计
|
||||
|
||||
Diffusers 围绕三个核心组件构建:
|
||||
|
||||
<!-- ascii-guard-ignore -->
|
||||
```
|
||||
Pipeline (orchestration)
|
||||
├── Model (neural networks)
|
||||
│ ├── UNet / Transformer (noise prediction)
|
||||
│ ├── VAE (latent encoding/decoding)
|
||||
│ └── Text Encoder (CLIP/T5)
|
||||
└── Scheduler (denoising algorithm)
|
||||
```
|
||||
<!-- ascii-guard-ignore-end -->
|
||||
|
||||
### Pipeline 推理流程
|
||||
|
||||
```
|
||||
Text Prompt → Text Encoder → Text Embeddings
|
||||
↓
|
||||
Random Noise → [Denoising Loop] ← Scheduler
|
||||
↓
|
||||
Predicted Noise
|
||||
↓
|
||||
VAE Decoder → Final Image
|
||||
```
|
||||
|
||||
## 核心概念
|
||||
|
||||
### Pipeline
|
||||
|
||||
Pipeline 编排完整工作流:
|
||||
|
||||
| Pipeline | 用途 |
|
||||
|----------|---------|
|
||||
| `StableDiffusionPipeline` | 文本到图像(SD 1.x/2.x) |
|
||||
| `StableDiffusionXLPipeline` | 文本到图像(SDXL) |
|
||||
| `StableDiffusion3Pipeline` | 文本到图像(SD 3.0) |
|
||||
| `FluxPipeline` | 文本到图像(Flux 模型) |
|
||||
| `StableDiffusionImg2ImgPipeline` | 图像到图像 |
|
||||
| `StableDiffusionInpaintPipeline` | Inpainting |
|
||||
|
||||
### Scheduler
|
||||
|
||||
Scheduler 控制去噪过程:
|
||||
|
||||
| Scheduler | 步数 | 质量 | 适用场景 |
|
||||
|-----------|-------|---------|----------|
|
||||
| `EulerDiscreteScheduler` | 20-50 | 良好 | 默认选择 |
|
||||
| `EulerAncestralDiscreteScheduler` | 20-50 | 良好 | 更多变化 |
|
||||
| `DPMSolverMultistepScheduler` | 15-25 | 优秀 | 快速、高质量 |
|
||||
| `DDIMScheduler` | 50-100 | 良好 | 确定性生成 |
|
||||
| `LCMScheduler` | 4-8 | 良好 | 极速生成 |
|
||||
| `UniPCMultistepScheduler` | 15-25 | 优秀 | 快速收敛 |
|
||||
|
||||
### 切换 Scheduler
|
||||
|
||||
```python
|
||||
from diffusers import DPMSolverMultistepScheduler
|
||||
|
||||
# Swap for faster generation
|
||||
pipe.scheduler = DPMSolverMultistepScheduler.from_config(
|
||||
pipe.scheduler.config
|
||||
)
|
||||
|
||||
# Now generate with fewer steps
|
||||
image = pipe(prompt, num_inference_steps=20).images[0]
|
||||
```
|
||||
|
||||
## 生成参数
|
||||
|
||||
### 关键参数
|
||||
|
||||
| 参数 | 默认值 | 说明 |
|
||||
|-----------|---------|-------------|
|
||||
| `prompt` | 必填 | 目标图像的文本描述 |
|
||||
| `negative_prompt` | None | 图像中需要避免的内容 |
|
||||
| `num_inference_steps` | 50 | 去噪步数(越多质量越好) |
|
||||
| `guidance_scale` | 7.5 | Prompt 遵循程度(通常为 7-12) |
|
||||
| `height`, `width` | 512/1024 | 输出尺寸(8 的倍数) |
|
||||
| `generator` | None | 用于可复现性的 Torch generator |
|
||||
| `num_images_per_prompt` | 1 | 批量大小 |
|
||||
|
||||
### 可复现生成
|
||||
|
||||
```python
|
||||
import torch
|
||||
|
||||
generator = torch.Generator(device="cuda").manual_seed(42)
|
||||
|
||||
image = pipe(
|
||||
prompt="A cat wearing a top hat",
|
||||
generator=generator,
|
||||
num_inference_steps=50
|
||||
).images[0]
|
||||
```
|
||||
|
||||
### Negative prompt
|
||||
|
||||
```python
|
||||
image = pipe(
|
||||
prompt="Professional photo of a dog in a garden",
|
||||
negative_prompt="blurry, low quality, distorted, ugly, bad anatomy",
|
||||
guidance_scale=7.5
|
||||
).images[0]
|
||||
```
|
||||
|
||||
## 图像到图像
|
||||
|
||||
在文本引导下转换现有图像:
|
||||
|
||||
```python
|
||||
from diffusers import AutoPipelineForImage2Image
|
||||
from PIL import Image
|
||||
|
||||
pipe = AutoPipelineForImage2Image.from_pretrained(
|
||||
"stable-diffusion-v1-5/stable-diffusion-v1-5",
|
||||
torch_dtype=torch.float16
|
||||
).to("cuda")
|
||||
|
||||
init_image = Image.open("input.jpg").resize((512, 512))
|
||||
|
||||
image = pipe(
|
||||
prompt="A watercolor painting of the scene",
|
||||
image=init_image,
|
||||
strength=0.75, # How much to transform (0-1)
|
||||
num_inference_steps=50
|
||||
).images[0]
|
||||
```
|
||||
|
||||
## Inpainting
|
||||
|
||||
填充遮罩区域:
|
||||
|
||||
```python
|
||||
from diffusers import AutoPipelineForInpainting
|
||||
from PIL import Image
|
||||
|
||||
pipe = AutoPipelineForInpainting.from_pretrained(
|
||||
"runwayml/stable-diffusion-inpainting",
|
||||
torch_dtype=torch.float16
|
||||
).to("cuda")
|
||||
|
||||
image = Image.open("photo.jpg")
|
||||
mask = Image.open("mask.png") # White = inpaint region
|
||||
|
||||
result = pipe(
|
||||
prompt="A red car parked on the street",
|
||||
image=image,
|
||||
mask_image=mask,
|
||||
num_inference_steps=50
|
||||
).images[0]
|
||||
```
|
||||
|
||||
## ControlNet
|
||||
|
||||
添加空间条件控制以实现精确控制:
|
||||
|
||||
```python
|
||||
from diffusers import StableDiffusionControlNetPipeline, ControlNetModel
|
||||
import torch
|
||||
|
||||
# Load ControlNet for edge conditioning
|
||||
controlnet = ControlNetModel.from_pretrained(
|
||||
"lllyasviel/control_v11p_sd15_canny",
|
||||
torch_dtype=torch.float16
|
||||
)
|
||||
|
||||
pipe = StableDiffusionControlNetPipeline.from_pretrained(
|
||||
"stable-diffusion-v1-5/stable-diffusion-v1-5",
|
||||
controlnet=controlnet,
|
||||
torch_dtype=torch.float16
|
||||
).to("cuda")
|
||||
|
||||
# Use Canny edge image as control
|
||||
control_image = get_canny_image(input_image)
|
||||
|
||||
image = pipe(
|
||||
prompt="A beautiful house in the style of Van Gogh",
|
||||
image=control_image,
|
||||
num_inference_steps=30
|
||||
).images[0]
|
||||
```
|
||||
|
||||
### 可用的 ControlNet
|
||||
|
||||
| ControlNet | 输入类型 | 适用场景 |
|
||||
|------------|------------|----------|
|
||||
| `canny` | 边缘图 | 保留结构 |
|
||||
| `openpose` | 姿态骨架 | 人体姿态 |
|
||||
| `depth` | 深度图 | 3D 感知生成 |
|
||||
| `normal` | 法线图 | 表面细节 |
|
||||
| `mlsd` | 线段 | 建筑线条 |
|
||||
| `scribble` | 粗略草图 | 草图到图像 |
|
||||
|
||||
## LoRA 适配器
|
||||
|
||||
加载微调风格适配器:
|
||||
|
||||
```python
|
||||
from diffusers import DiffusionPipeline
|
||||
|
||||
pipe = DiffusionPipeline.from_pretrained(
|
||||
"stable-diffusion-v1-5/stable-diffusion-v1-5",
|
||||
torch_dtype=torch.float16
|
||||
).to("cuda")
|
||||
|
||||
# Load LoRA weights
|
||||
pipe.load_lora_weights("path/to/lora", weight_name="style.safetensors")
|
||||
|
||||
# Generate with LoRA style
|
||||
image = pipe("A portrait in the trained style").images[0]
|
||||
|
||||
# Adjust LoRA strength
|
||||
pipe.fuse_lora(lora_scale=0.8)
|
||||
|
||||
# Unload LoRA
|
||||
pipe.unload_lora_weights()
|
||||
```
|
||||
|
||||
### 多个 LoRA
|
||||
|
||||
```python
|
||||
# Load multiple LoRAs
|
||||
pipe.load_lora_weights("lora1", adapter_name="style")
|
||||
pipe.load_lora_weights("lora2", adapter_name="character")
|
||||
|
||||
# Set weights for each
|
||||
pipe.set_adapters(["style", "character"], adapter_weights=[0.7, 0.5])
|
||||
|
||||
image = pipe("A portrait").images[0]
|
||||
```
|
||||
|
||||
## 内存优化
|
||||
|
||||
### 启用 CPU 卸载
|
||||
|
||||
```python
|
||||
# Model CPU offload - moves models to CPU when not in use
|
||||
pipe.enable_model_cpu_offload()
|
||||
|
||||
# Sequential CPU offload - more aggressive, slower
|
||||
pipe.enable_sequential_cpu_offload()
|
||||
```
|
||||
|
||||
### Attention 切片
|
||||
|
||||
```python
|
||||
# Reduce memory by computing attention in chunks
|
||||
pipe.enable_attention_slicing()
|
||||
|
||||
# Or specific chunk size
|
||||
pipe.enable_attention_slicing("max")
|
||||
```
|
||||
|
||||
### xFormers 内存高效 Attention
|
||||
|
||||
```python
|
||||
# Requires xformers package
|
||||
pipe.enable_xformers_memory_efficient_attention()
|
||||
```
|
||||
|
||||
### 大图像的 VAE 切片
|
||||
|
||||
```python
|
||||
# Decode latents in tiles for large images
|
||||
pipe.enable_vae_slicing()
|
||||
pipe.enable_vae_tiling()
|
||||
```
|
||||
|
||||
## 模型变体
|
||||
|
||||
### 加载不同精度
|
||||
|
||||
```python
|
||||
# FP16 (recommended for GPU)
|
||||
pipe = DiffusionPipeline.from_pretrained(
|
||||
"model-id",
|
||||
torch_dtype=torch.float16,
|
||||
variant="fp16"
|
||||
)
|
||||
|
||||
# BF16 (better precision, requires Ampere+ GPU)
|
||||
pipe = DiffusionPipeline.from_pretrained(
|
||||
"model-id",
|
||||
torch_dtype=torch.bfloat16
|
||||
)
|
||||
```
|
||||
|
||||
### 加载特定组件
|
||||
|
||||
```python
|
||||
from diffusers import UNet2DConditionModel, AutoencoderKL
|
||||
|
||||
# Load custom VAE
|
||||
vae = AutoencoderKL.from_pretrained("stabilityai/sd-vae-ft-mse")
|
||||
|
||||
# Use with pipeline
|
||||
pipe = DiffusionPipeline.from_pretrained(
|
||||
"stable-diffusion-v1-5/stable-diffusion-v1-5",
|
||||
vae=vae,
|
||||
torch_dtype=torch.float16
|
||||
)
|
||||
```
|
||||
|
||||
## 批量生成
|
||||
|
||||
高效生成多张图像:
|
||||
|
||||
```python
|
||||
# Multiple prompts
|
||||
prompts = [
|
||||
"A cat playing piano",
|
||||
"A dog reading a book",
|
||||
"A bird painting a picture"
|
||||
]
|
||||
|
||||
images = pipe(prompts, num_inference_steps=30).images
|
||||
|
||||
# Multiple images per prompt
|
||||
images = pipe(
|
||||
"A beautiful sunset",
|
||||
num_images_per_prompt=4,
|
||||
num_inference_steps=30
|
||||
).images
|
||||
```
|
||||
|
||||
## 常见工作流
|
||||
|
||||
### 工作流 1:高质量生成
|
||||
|
||||
```python
|
||||
from diffusers import StableDiffusionXLPipeline, DPMSolverMultistepScheduler
|
||||
import torch
|
||||
|
||||
# 1. Load SDXL with optimizations
|
||||
pipe = StableDiffusionXLPipeline.from_pretrained(
|
||||
"stabilityai/stable-diffusion-xl-base-1.0",
|
||||
torch_dtype=torch.float16,
|
||||
variant="fp16"
|
||||
)
|
||||
pipe.to("cuda")
|
||||
pipe.scheduler = DPMSolverMultistepScheduler.from_config(pipe.scheduler.config)
|
||||
pipe.enable_model_cpu_offload()
|
||||
|
||||
# 2. Generate with quality settings
|
||||
image = pipe(
|
||||
prompt="A majestic lion in the savanna, golden hour lighting, 8k, detailed fur",
|
||||
negative_prompt="blurry, low quality, cartoon, anime, sketch",
|
||||
num_inference_steps=30,
|
||||
guidance_scale=7.5,
|
||||
height=1024,
|
||||
width=1024
|
||||
).images[0]
|
||||
```
|
||||
|
||||
### 工作流 2:快速原型验证
|
||||
|
||||
```python
|
||||
from diffusers import AutoPipelineForText2Image, LCMScheduler
|
||||
import torch
|
||||
|
||||
# Use LCM for 4-8 step generation
|
||||
pipe = AutoPipelineForText2Image.from_pretrained(
|
||||
"stabilityai/stable-diffusion-xl-base-1.0",
|
||||
torch_dtype=torch.float16
|
||||
).to("cuda")
|
||||
|
||||
# Load LCM LoRA for fast generation
|
||||
pipe.load_lora_weights("latent-consistency/lcm-lora-sdxl")
|
||||
pipe.scheduler = LCMScheduler.from_config(pipe.scheduler.config)
|
||||
pipe.fuse_lora()
|
||||
|
||||
# Generate in ~1 second
|
||||
image = pipe(
|
||||
"A beautiful landscape",
|
||||
num_inference_steps=4,
|
||||
guidance_scale=1.0
|
||||
).images[0]
|
||||
```
|
||||
|
||||
## 常见问题
|
||||
|
||||
**CUDA 内存不足:**
|
||||
```python
|
||||
# Enable memory optimizations
|
||||
pipe.enable_model_cpu_offload()
|
||||
pipe.enable_attention_slicing()
|
||||
pipe.enable_vae_slicing()
|
||||
|
||||
# Or use lower precision
|
||||
pipe = DiffusionPipeline.from_pretrained(model_id, torch_dtype=torch.float16)
|
||||
```
|
||||
|
||||
**黑色/噪声图像:**
|
||||
```python
|
||||
# Check VAE configuration
|
||||
# Use safety checker bypass if needed
|
||||
pipe.safety_checker = None
|
||||
|
||||
# Ensure proper dtype consistency
|
||||
pipe = pipe.to(dtype=torch.float16)
|
||||
```
|
||||
|
||||
**生成速度慢:**
|
||||
```python
|
||||
# Use faster scheduler
|
||||
from diffusers import DPMSolverMultistepScheduler
|
||||
pipe.scheduler = DPMSolverMultistepScheduler.from_config(pipe.scheduler.config)
|
||||
|
||||
# Reduce steps
|
||||
image = pipe(prompt, num_inference_steps=20).images[0]
|
||||
```
|
||||
|
||||
## 参考资料
|
||||
|
||||
- **[高级用法](https://github.com/NousResearch/hermes-agent/blob/main/optional-skills/mlops/stable-diffusion/references/advanced-usage.md)** - 自定义 pipeline、微调、部署
|
||||
- **[故障排查](https://github.com/NousResearch/hermes-agent/blob/main/optional-skills/mlops/stable-diffusion/references/troubleshooting.md)** - 常见问题与解决方案
|
||||
|
||||
## 资源
|
||||
|
||||
- **文档**:https://huggingface.co/docs/diffusers
|
||||
- **代码仓库**:https://github.com/huggingface/diffusers
|
||||
- **模型中心**:https://huggingface.co/models?library=diffusers
|
||||
- **Discord**:https://discord.gg/diffusers
|
||||
+206
@@ -0,0 +1,206 @@
|
||||
---
|
||||
title: "Tensorrt Llm — 使用 NVIDIA TensorRT 优化 LLM 推理以实现最大吞吐量和最低延迟"
|
||||
sidebar_label: "Tensorrt Llm"
|
||||
description: "使用 NVIDIA TensorRT 优化 LLM 推理以实现最大吞吐量和最低延迟"
|
||||
---
|
||||
|
||||
{/* This page is auto-generated from the skill's SKILL.md by website/scripts/generate-skill-docs.py. Edit the source SKILL.md, not this page. */}
|
||||
|
||||
# Tensorrt Llm
|
||||
|
||||
使用 NVIDIA TensorRT 优化 LLM 推理,实现最大吞吐量和最低延迟。适用于在 NVIDIA GPU(A100/H100)上进行生产部署、需要比 PyTorch 快 10-100 倍的推理速度,或需要使用量化(FP8/INT4)、in-flight batching(动态批处理)和多 GPU 扩展来服务模型的场景。
|
||||
|
||||
## Skill 元数据
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| 来源 | 可选 — 通过 `hermes skills install official/mlops/tensorrt-llm` 安装 |
|
||||
| 路径 | `optional-skills/mlops/tensorrt-llm` |
|
||||
| 版本 | `1.0.0` |
|
||||
| 作者 | Orchestra Research |
|
||||
| 许可证 | MIT |
|
||||
| 依赖项 | `tensorrt-llm`, `torch` |
|
||||
| 平台 | linux, macos |
|
||||
| 标签 | `Inference Serving`, `TensorRT-LLM`, `NVIDIA`, `Inference Optimization`, `High Throughput`, `Low Latency`, `Production`, `FP8`, `INT4`, `In-Flight Batching`, `Multi-GPU` |
|
||||
|
||||
## 参考:完整 SKILL.md
|
||||
|
||||
:::info
|
||||
以下是 Hermes 在触发此 skill 时加载的完整 skill 定义。这是 skill 激活时 agent 所看到的指令内容。
|
||||
:::
|
||||
|
||||
# TensorRT-LLM
|
||||
|
||||
NVIDIA 的开源库,用于在 NVIDIA GPU 上以最先进的性能优化 LLM 推理。
|
||||
|
||||
## 何时使用 TensorRT-LLM
|
||||
|
||||
**在以下情况下使用 TensorRT-LLM:**
|
||||
- 在 NVIDIA GPU(A100、H100、GB200)上部署
|
||||
- 需要最大吞吐量(Llama 3 上 24,000+ tokens/sec)
|
||||
- 实时应用需要低延迟
|
||||
- 使用量化模型(FP8、INT4、FP4)
|
||||
- 跨多个 GPU 或节点扩展
|
||||
|
||||
**在以下情况下改用 vLLM:**
|
||||
- 需要更简单的设置和 Python 优先的 API
|
||||
- 希望使用 PagedAttention 而无需 TensorRT 编译
|
||||
- 使用 AMD GPU 或非 NVIDIA 硬件
|
||||
|
||||
**在以下情况下改用 llama.cpp:**
|
||||
- 在 CPU 或 Apple Silicon 上部署
|
||||
- 需要无 NVIDIA GPU 的边缘部署
|
||||
- 希望使用更简单的 GGUF 量化格式
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 安装
|
||||
|
||||
```bash
|
||||
# Docker(推荐)
|
||||
docker pull nvidia/tensorrt_llm:latest
|
||||
|
||||
# pip 安装
|
||||
pip install tensorrt_llm==1.2.0rc3
|
||||
|
||||
# 需要 CUDA 13.0.0、TensorRT 10.13.2、Python 3.10-3.12
|
||||
```
|
||||
|
||||
### 基本推理
|
||||
|
||||
```python
|
||||
from tensorrt_llm import LLM, SamplingParams
|
||||
|
||||
# 初始化模型
|
||||
llm = LLM(model="meta-llama/Meta-Llama-3-8B")
|
||||
|
||||
# 配置采样参数
|
||||
sampling_params = SamplingParams(
|
||||
max_tokens=100,
|
||||
temperature=0.7,
|
||||
top_p=0.9
|
||||
)
|
||||
|
||||
# 生成
|
||||
prompts = ["Explain quantum computing"]
|
||||
outputs = llm.generate(prompts, sampling_params)
|
||||
|
||||
for output in outputs:
|
||||
print(output.text)
|
||||
```
|
||||
|
||||
### 使用 trtllm-serve 提供服务
|
||||
|
||||
```bash
|
||||
# 启动服务器(自动下载和编译模型)
|
||||
trtllm-serve meta-llama/Meta-Llama-3-8B \
|
||||
--tp_size 4 \ # 张量并行(4 个 GPU)
|
||||
--max_batch_size 256 \
|
||||
--max_num_tokens 4096
|
||||
|
||||
# 客户端请求
|
||||
curl -X POST http://localhost:8000/v1/chat/completions \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"model": "meta-llama/Meta-Llama-3-8B",
|
||||
"messages": [{"role": "user", "content": "Hello!"}],
|
||||
"temperature": 0.7,
|
||||
"max_tokens": 100
|
||||
}'
|
||||
```
|
||||
|
||||
## 核心特性
|
||||
|
||||
### 性能优化
|
||||
- **In-flight batching**:生成过程中的动态批处理
|
||||
- **Paged KV cache**:高效内存管理
|
||||
- **Flash Attention**:优化的注意力计算核
|
||||
- **量化**:FP8、INT4、FP4,推理速度提升 2-4 倍
|
||||
- **CUDA graphs**:降低内核启动开销
|
||||
|
||||
### 并行化
|
||||
- **张量并行(TP)**:跨 GPU 拆分模型
|
||||
- **流水线并行(PP)**:按层分布
|
||||
- **专家并行**:用于混合专家(Mixture-of-Experts)模型
|
||||
- **多节点**:扩展至单机以外
|
||||
|
||||
### 高级特性
|
||||
- **推测解码(Speculative decoding)**:使用草稿模型加速生成
|
||||
- **LoRA serving**:高效多适配器部署
|
||||
- **分离式服务(Disaggregated serving)**:预填充与生成分离
|
||||
|
||||
## 常见模式
|
||||
|
||||
### 量化模型(FP8)
|
||||
|
||||
```python
|
||||
from tensorrt_llm import LLM
|
||||
|
||||
# 加载 FP8 量化模型(速度提升 2 倍,内存减少 50%)
|
||||
llm = LLM(
|
||||
model="meta-llama/Meta-Llama-3-70B",
|
||||
dtype="fp8",
|
||||
max_num_tokens=8192
|
||||
)
|
||||
|
||||
# 推理方式与之前相同
|
||||
outputs = llm.generate(["Summarize this article..."])
|
||||
```
|
||||
|
||||
### 多 GPU 部署
|
||||
|
||||
```python
|
||||
# 跨 8 个 GPU 的张量并行
|
||||
llm = LLM(
|
||||
model="meta-llama/Meta-Llama-3-405B",
|
||||
tensor_parallel_size=8,
|
||||
dtype="fp8"
|
||||
)
|
||||
```
|
||||
|
||||
### 批量推理
|
||||
|
||||
```python
|
||||
# 高效处理 100 个 prompt
|
||||
prompts = [f"Question {i}: ..." for i in range(100)]
|
||||
|
||||
outputs = llm.generate(
|
||||
prompts,
|
||||
sampling_params=SamplingParams(max_tokens=200)
|
||||
)
|
||||
|
||||
# 自动 in-flight batching 以实现最大吞吐量
|
||||
```
|
||||
|
||||
## 性能基准
|
||||
|
||||
**Meta Llama 3-8B**(H100 GPU):
|
||||
- 吞吐量:24,000 tokens/sec
|
||||
- 延迟:每 token 约 10ms
|
||||
- 对比 PyTorch:**快 100 倍**
|
||||
|
||||
**Llama 3-70B**(8× A100 80GB):
|
||||
- FP8 量化:比 FP16 快 2 倍
|
||||
- 内存:FP8 减少 50%
|
||||
|
||||
## 支持的模型
|
||||
|
||||
- **LLaMA 系列**:Llama 2、Llama 3、CodeLlama
|
||||
- **GPT 系列**:GPT-2、GPT-J、GPT-NeoX
|
||||
- **Qwen**:Qwen、Qwen2、QwQ
|
||||
- **DeepSeek**:DeepSeek-V2、DeepSeek-V3
|
||||
- **Mixtral**:Mixtral-8x7B、Mixtral-8x22B
|
||||
- **视觉模型**:LLaVA、Phi-3-vision
|
||||
- **100+ 模型**,可在 HuggingFace 上获取
|
||||
|
||||
## 参考文档
|
||||
|
||||
- **[优化指南](https://github.com/NousResearch/hermes-agent/blob/main/optional-skills/mlops/tensorrt-llm/references/optimization.md)** — 量化、批处理、KV cache 调优
|
||||
- **[多 GPU 配置](https://github.com/NousResearch/hermes-agent/blob/main/optional-skills/mlops/tensorrt-llm/references/multi-gpu.md)** — 张量/流水线并行、多节点
|
||||
- **[服务指南](https://github.com/NousResearch/hermes-agent/blob/main/optional-skills/mlops/tensorrt-llm/references/serving.md)** — 生产部署、监控、自动扩缩容
|
||||
|
||||
## 资源
|
||||
|
||||
- **文档**:https://nvidia.github.io/TensorRT-LLM/
|
||||
- **GitHub**:https://github.com/NVIDIA/TensorRT-LLM
|
||||
- **模型**:https://huggingface.co/models?library=tensorrt_llm
|
||||
+378
@@ -0,0 +1,378 @@
|
||||
---
|
||||
title: "Distributed Llm Pretraining Torchtitan"
|
||||
sidebar_label: "Distributed Llm Pretraining Torchtitan"
|
||||
description: "使用 torchtitan 提供 PyTorch 原生分布式 LLM 预训练,支持 4D 并行(FSDP2、TP、PP、CP)"
|
||||
---
|
||||
|
||||
{/* This page is auto-generated from the skill's SKILL.md by website/scripts/generate-skill-docs.py. Edit the source SKILL.md, not this page. */}
|
||||
|
||||
# Distributed Llm Pretraining Torchtitan
|
||||
|
||||
使用 torchtitan 提供 PyTorch 原生分布式 LLM 预训练,支持 4D 并行(FSDP2、TP、PP、CP)。适用于在 8 到 512+ GPU 规模下预训练 Llama 3.1、DeepSeek V3 或自定义模型,支持 Float8、torch.compile 及分布式检查点。
|
||||
|
||||
## Skill 元数据
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| 来源 | 可选 — 通过 `hermes skills install official/mlops/torchtitan` 安装 |
|
||||
| 路径 | `optional-skills/mlops/torchtitan` |
|
||||
| 版本 | `1.0.0` |
|
||||
| 作者 | Orchestra Research |
|
||||
| 许可证 | MIT |
|
||||
| 依赖 | `torch>=2.6.0`, `torchtitan>=0.2.0`, `torchao>=0.5.0` |
|
||||
| 平台 | linux, macos |
|
||||
| 标签 | `Model Architecture`, `Distributed Training`, `TorchTitan`, `FSDP2`, `Tensor Parallel`, `Pipeline Parallel`, `Context Parallel`, `Float8`, `Llama`, `Pretraining` |
|
||||
|
||||
## 参考:完整 SKILL.md
|
||||
|
||||
:::info
|
||||
以下是 Hermes 在触发该 skill 时加载的完整 skill 定义。这是 agent 在 skill 激活时所看到的指令内容。
|
||||
:::
|
||||
|
||||
# TorchTitan - PyTorch 原生分布式 LLM 预训练
|
||||
|
||||
## 快速开始
|
||||
|
||||
TorchTitan 是 PyTorch 官方的大规模 LLM 预训练平台,支持可组合的 4D 并行(FSDP2、TP、PP、CP),在 H100 GPU 上相比基线可实现 65%+ 的加速。
|
||||
|
||||
**安装**:
|
||||
```bash
|
||||
# 从 PyPI 安装(稳定版)
|
||||
pip install torchtitan
|
||||
|
||||
# 从源码安装(最新特性,需要 PyTorch nightly)
|
||||
git clone https://github.com/pytorch/torchtitan
|
||||
cd torchtitan
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
**下载 tokenizer**:
|
||||
```bash
|
||||
# 从 https://huggingface.co/settings/tokens 获取 HF token
|
||||
python scripts/download_hf_assets.py --repo_id meta-llama/Llama-3.1-8B --assets tokenizer --hf_token=...
|
||||
```
|
||||
|
||||
**在 8 个 GPU 上启动训练**:
|
||||
```bash
|
||||
CONFIG_FILE="./torchtitan/models/llama3/train_configs/llama3_8b.toml" ./run_train.sh
|
||||
```
|
||||
|
||||
## 常用工作流
|
||||
|
||||
### 工作流 1:在单节点上预训练 Llama 3.1 8B
|
||||
|
||||
复制此检查清单:
|
||||
|
||||
```
|
||||
单节点预训练:
|
||||
- [ ] 步骤 1:下载 tokenizer
|
||||
- [ ] 步骤 2:配置训练
|
||||
- [ ] 步骤 3:启动训练
|
||||
- [ ] 步骤 4:监控与检查点
|
||||
```
|
||||
|
||||
**步骤 1:下载 tokenizer**
|
||||
|
||||
```bash
|
||||
python scripts/download_hf_assets.py \
|
||||
--repo_id meta-llama/Llama-3.1-8B \
|
||||
--assets tokenizer \
|
||||
--hf_token=YOUR_HF_TOKEN
|
||||
```
|
||||
|
||||
**步骤 2:配置训练**
|
||||
|
||||
编辑或创建 TOML 配置文件:
|
||||
|
||||
```toml
|
||||
# llama3_8b_custom.toml
|
||||
[job]
|
||||
dump_folder = "./outputs"
|
||||
description = "Llama 3.1 8B training"
|
||||
|
||||
[model]
|
||||
name = "llama3"
|
||||
flavor = "8B"
|
||||
hf_assets_path = "./assets/hf/Llama-3.1-8B"
|
||||
|
||||
[optimizer]
|
||||
name = "AdamW"
|
||||
lr = 3e-4
|
||||
|
||||
[lr_scheduler]
|
||||
warmup_steps = 200
|
||||
|
||||
[training]
|
||||
local_batch_size = 2
|
||||
seq_len = 8192
|
||||
max_norm = 1.0
|
||||
steps = 1000
|
||||
dataset = "c4"
|
||||
|
||||
[parallelism]
|
||||
data_parallel_shard_degree = -1 # Use all GPUs for FSDP
|
||||
|
||||
[activation_checkpoint]
|
||||
mode = "selective"
|
||||
selective_ac_option = "op"
|
||||
|
||||
[checkpoint]
|
||||
enable = true
|
||||
folder = "checkpoint"
|
||||
interval = 500
|
||||
```
|
||||
|
||||
**步骤 3:启动训练**
|
||||
|
||||
```bash
|
||||
# 单节点 8 个 GPU
|
||||
CONFIG_FILE="./llama3_8b_custom.toml" ./run_train.sh
|
||||
|
||||
# 或显式使用 torchrun
|
||||
torchrun --nproc_per_node=8 \
|
||||
-m torchtitan.train \
|
||||
--job.config_file ./llama3_8b_custom.toml
|
||||
```
|
||||
|
||||
**步骤 4:监控与检查点**
|
||||
|
||||
TensorBoard 日志保存至 `./outputs/tb/`:
|
||||
```bash
|
||||
tensorboard --logdir ./outputs/tb
|
||||
```
|
||||
|
||||
### 工作流 2:使用 SLURM 进行多节点训练
|
||||
|
||||
```
|
||||
多节点训练:
|
||||
- [ ] 步骤 1:为规模配置并行度
|
||||
- [ ] 步骤 2:设置 SLURM 脚本
|
||||
- [ ] 步骤 3:提交作业
|
||||
- [ ] 步骤 4:从检查点恢复
|
||||
```
|
||||
|
||||
**步骤 1:为规模配置并行度**
|
||||
|
||||
在 256 个 GPU(32 个节点)上训练 70B 模型:
|
||||
```toml
|
||||
[parallelism]
|
||||
data_parallel_shard_degree = 32 # FSDP across 32 ranks
|
||||
tensor_parallel_degree = 8 # TP within node
|
||||
pipeline_parallel_degree = 1 # No PP for 70B
|
||||
context_parallel_degree = 1 # Increase for long sequences
|
||||
```
|
||||
|
||||
**步骤 2:设置 SLURM 脚本**
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
#SBATCH --job-name=llama70b
|
||||
#SBATCH --nodes=32
|
||||
#SBATCH --ntasks-per-node=8
|
||||
#SBATCH --gpus-per-node=8
|
||||
|
||||
srun torchrun \
|
||||
--nnodes=32 \
|
||||
--nproc_per_node=8 \
|
||||
--rdzv_backend=c10d \
|
||||
--rdzv_endpoint=$MASTER_ADDR:$MASTER_PORT \
|
||||
-m torchtitan.train \
|
||||
--job.config_file ./llama3_70b.toml
|
||||
```
|
||||
|
||||
**步骤 3:提交作业**
|
||||
|
||||
```bash
|
||||
sbatch multinode_trainer.slurm
|
||||
```
|
||||
|
||||
**步骤 4:从检查点恢复**
|
||||
|
||||
若配置的文件夹中存在检查点,训练将自动恢复。
|
||||
|
||||
### 工作流 3:为 H100 启用 Float8 训练
|
||||
|
||||
Float8 在 H100 GPU 上可提供 30-50% 的加速。
|
||||
|
||||
```
|
||||
Float8 训练:
|
||||
- [ ] 步骤 1:安装 torchao
|
||||
- [ ] 步骤 2:配置 Float8
|
||||
- [ ] 步骤 3:启动并开启 compile
|
||||
```
|
||||
|
||||
**步骤 1:安装 torchao**
|
||||
|
||||
```bash
|
||||
USE_CPP=0 pip install git+https://github.com/pytorch/ao.git
|
||||
```
|
||||
|
||||
**步骤 2:配置 Float8**
|
||||
|
||||
在 TOML 配置中添加:
|
||||
```toml
|
||||
[model]
|
||||
converters = ["quantize.linear.float8"]
|
||||
|
||||
[quantize.linear.float8]
|
||||
enable_fsdp_float8_all_gather = true
|
||||
precompute_float8_dynamic_scale_for_fsdp = true
|
||||
filter_fqns = ["output"] # Exclude output layer
|
||||
|
||||
[compile]
|
||||
enable = true
|
||||
components = ["model", "loss"]
|
||||
```
|
||||
|
||||
**步骤 3:启动并开启 compile**
|
||||
|
||||
```bash
|
||||
CONFIG_FILE="./llama3_8b.toml" ./run_train.sh \
|
||||
--model.converters="quantize.linear.float8" \
|
||||
--quantize.linear.float8.enable_fsdp_float8_all_gather \
|
||||
--compile.enable
|
||||
```
|
||||
|
||||
### 工作流 4:405B 模型的 4D 并行
|
||||
|
||||
```
|
||||
4D 并行(FSDP + TP + PP + CP):
|
||||
- [ ] 步骤 1:创建种子检查点
|
||||
- [ ] 步骤 2:配置 4D 并行
|
||||
- [ ] 步骤 3:在 512 个 GPU 上启动
|
||||
```
|
||||
|
||||
**步骤 1:创建种子检查点**
|
||||
|
||||
跨 PP 阶段一致初始化所必需:
|
||||
```bash
|
||||
NGPU=1 CONFIG_FILE=./llama3_405b.toml ./run_train.sh \
|
||||
--checkpoint.enable \
|
||||
--checkpoint.create_seed_checkpoint \
|
||||
--parallelism.data_parallel_shard_degree 1 \
|
||||
--parallelism.tensor_parallel_degree 1 \
|
||||
--parallelism.pipeline_parallel_degree 1
|
||||
```
|
||||
|
||||
**步骤 2:配置 4D 并行**
|
||||
|
||||
```toml
|
||||
[parallelism]
|
||||
data_parallel_shard_degree = 8 # FSDP
|
||||
tensor_parallel_degree = 8 # TP within node
|
||||
pipeline_parallel_degree = 8 # PP across nodes
|
||||
context_parallel_degree = 1 # CP for long sequences
|
||||
|
||||
[training]
|
||||
local_batch_size = 32
|
||||
seq_len = 8192
|
||||
```
|
||||
|
||||
**步骤 3:在 512 个 GPU 上启动**
|
||||
|
||||
```bash
|
||||
# 64 节点 x 8 GPU = 512 GPU
|
||||
srun torchrun --nnodes=64 --nproc_per_node=8 \
|
||||
-m torchtitan.train \
|
||||
--job.config_file ./llama3_405b.toml
|
||||
```
|
||||
|
||||
## 何时使用 vs 替代方案
|
||||
|
||||
**使用 TorchTitan 的场景:**
|
||||
- 从头预训练 LLM(8B 到 405B+)
|
||||
- 需要无第三方依赖的 PyTorch 原生方案
|
||||
- 需要可组合的 4D 并行(FSDP2、TP、PP、CP)
|
||||
- 在支持 Float8 的 H100 上训练
|
||||
- 需要与 torchtune/HuggingFace 互操作的检查点
|
||||
|
||||
**使用替代方案的场景:**
|
||||
- **Megatron-LM**:仅限 NVIDIA 部署时追求最高性能
|
||||
- **DeepSpeed**:更广泛的 ZeRO 优化生态,支持推理
|
||||
- **Axolotl/TRL**:微调而非预训练
|
||||
- **LitGPT**:教学用途,小规模训练
|
||||
|
||||
## 常见问题
|
||||
|
||||
**问题:大模型内存不足**
|
||||
|
||||
启用激活检查点并减小批次大小:
|
||||
```toml
|
||||
[activation_checkpoint]
|
||||
mode = "full" # Instead of "selective"
|
||||
|
||||
[training]
|
||||
local_batch_size = 1
|
||||
```
|
||||
|
||||
或使用梯度累积:
|
||||
```toml
|
||||
[training]
|
||||
local_batch_size = 1
|
||||
global_batch_size = 32 # Accumulates gradients
|
||||
```
|
||||
|
||||
**问题:TP 异步集合通信导致内存占用过高**
|
||||
|
||||
设置环境变量:
|
||||
```bash
|
||||
export TORCH_NCCL_AVOID_RECORD_STREAMS=1
|
||||
```
|
||||
|
||||
**问题:Float8 训练未见加速**
|
||||
|
||||
Float8 仅对大型 GEMM 有效。过滤小层:
|
||||
```toml
|
||||
[quantize.linear.float8]
|
||||
filter_fqns = ["attention.wk", "attention.wv", "output", "auto_filter_small_kn"]
|
||||
```
|
||||
|
||||
**问题:更改并行度后检查点加载失败**
|
||||
|
||||
使用 DCP 的重分片功能:
|
||||
```bash
|
||||
# 将分片检查点转换为单文件
|
||||
python -m torch.distributed.checkpoint.format_utils \
|
||||
dcp_to_torch checkpoint/step-1000 checkpoint.pt
|
||||
```
|
||||
|
||||
**问题:Pipeline 并行初始化失败**
|
||||
|
||||
请先创建种子检查点(参见工作流 4,步骤 1)。
|
||||
|
||||
## 支持的模型
|
||||
|
||||
| 模型 | 规模 | 状态 |
|
||||
|-------|-------|--------|
|
||||
| Llama 3.1 | 8B, 70B, 405B | 生产可用 |
|
||||
| Llama 4 | 多种 | 实验性 |
|
||||
| DeepSeek V3 | 16B, 236B, 671B (MoE) | 实验性 |
|
||||
| GPT-OSS | 20B, 120B (MoE) | 实验性 |
|
||||
| Qwen 3 | 多种 | 实验性 |
|
||||
| Flux | 扩散模型 | 实验性 |
|
||||
|
||||
## 性能基准(H100)
|
||||
|
||||
| 模型 | GPU 数 | 并行策略 | TPS/GPU | 技术 |
|
||||
|-------|------|-------------|---------|------------|
|
||||
| Llama 8B | 8 | FSDP | 5,762 | 基线 |
|
||||
| Llama 8B | 8 | FSDP+compile+FP8 | 8,532 | +48% |
|
||||
| Llama 70B | 256 | FSDP+TP+AsyncTP | 876 | 2D 并行 |
|
||||
| Llama 405B | 512 | FSDP+TP+PP | 128 | 3D 并行 |
|
||||
|
||||
## 进阶主题
|
||||
|
||||
**FSDP2 配置**:参见 [references/fsdp.md](https://github.com/NousResearch/hermes-agent/blob/main/optional-skills/mlops/torchtitan/references/fsdp.md),了解 FSDP2 与 FSDP1 的详细对比及 ZeRO 等价关系。
|
||||
|
||||
**Float8 训练**:参见 [references/float8.md](https://github.com/NousResearch/hermes-agent/blob/main/optional-skills/mlops/torchtitan/references/float8.md),了解 tensorwise 与 rowwise 缩放方案。
|
||||
|
||||
**检查点**:参见 [references/checkpoint.md](https://github.com/NousResearch/hermes-agent/blob/main/optional-skills/mlops/torchtitan/references/checkpoint.md),了解 HuggingFace 转换与异步检查点。
|
||||
|
||||
**添加自定义模型**:参见 [references/custom-models.md](https://github.com/NousResearch/hermes-agent/blob/main/optional-skills/mlops/torchtitan/references/custom-models.md),了解 TrainSpec 协议。
|
||||
|
||||
## 资源
|
||||
|
||||
- GitHub:https://github.com/pytorch/torchtitan
|
||||
- 论文:https://arxiv.org/abs/2410.06511
|
||||
- ICLR 2025:https://iclr.cc/virtual/2025/poster/29620
|
||||
- PyTorch 论坛:https://discuss.pytorch.org/c/distributed/torchtitan/44
|
||||
+181
@@ -0,0 +1,181 @@
|
||||
---
|
||||
title: "Axolotl — Axolotl:基于 YAML 的 LLM 微调(LoRA、DPO、GRPO)"
|
||||
sidebar_label: "Axolotl"
|
||||
description: "Axolotl:基于 YAML 的 LLM 微调(LoRA、DPO、GRPO)"
|
||||
---
|
||||
|
||||
{/* This page is auto-generated from the skill's SKILL.md by website/scripts/generate-skill-docs.py. Edit the source SKILL.md, not this page. */}
|
||||
|
||||
# Axolotl
|
||||
|
||||
Axolotl:基于 YAML 的 LLM 微调(LoRA、DPO、GRPO)。
|
||||
|
||||
## Skill 元数据
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| 来源 | 可选 — 通过 `hermes skills install official/mlops/axolotl` 安装 |
|
||||
| 路径 | `optional-skills/mlops/training/axolotl` |
|
||||
| 版本 | `1.0.0` |
|
||||
| 作者 | Orchestra Research |
|
||||
| 许可证 | MIT |
|
||||
| 依赖项 | `axolotl`, `torch`, `transformers`, `datasets`, `peft`, `accelerate`, `deepspeed` |
|
||||
| 平台 | linux, macos |
|
||||
| 标签 | `Fine-Tuning`, `Axolotl`, `LLM`, `LoRA`, `QLoRA`, `DPO`, `KTO`, `ORPO`, `GRPO`, `YAML`, `HuggingFace`, `DeepSpeed`, `Multimodal` |
|
||||
|
||||
## 参考:完整 SKILL.md
|
||||
|
||||
:::info
|
||||
以下是 Hermes 在触发此 skill 时加载的完整 skill 定义。这是 agent 在 skill 激活时所看到的指令内容。
|
||||
:::
|
||||
|
||||
# Axolotl Skill
|
||||
|
||||
## 内容概览
|
||||
|
||||
使用 Axolotl 微调 LLM 的专家指导 — YAML 配置、100+ 模型、LoRA/QLoRA、DPO/KTO/ORPO/GRPO、多模态支持。
|
||||
|
||||
基于官方文档生成的 axolotl 开发全面辅助。
|
||||
|
||||
## 何时使用此 Skill
|
||||
|
||||
以下情况应触发此 skill:
|
||||
- 使用 axolotl 进行开发
|
||||
- 询问 axolotl 功能或 API
|
||||
- 实现 axolotl 解决方案
|
||||
- 调试 axolotl 代码
|
||||
- 学习 axolotl 最佳实践
|
||||
|
||||
## 快速参考
|
||||
|
||||
### 常用模式
|
||||
|
||||
**模式 1:** 若要验证训练任务是否具备可接受的数据传输速度,运行 NCCL Tests 有助于定位瓶颈,例如:
|
||||
|
||||
```
|
||||
./build/all_reduce_perf -b 8 -e 128M -f 2 -g 3
|
||||
```
|
||||
|
||||
**模式 2:** 在 Axolotl yaml 中配置模型以使用 FSDP,例如:
|
||||
|
||||
```
|
||||
fsdp_version: 2
|
||||
fsdp_config:
|
||||
offload_params: true
|
||||
state_dict_type: FULL_STATE_DICT
|
||||
auto_wrap_policy: TRANSFORMER_BASED_WRAP
|
||||
transformer_layer_cls_to_wrap: LlamaDecoderLayer
|
||||
reshard_after_forward: true
|
||||
```
|
||||
|
||||
**模式 3:** `context_parallel_size` 应为 GPU 总数的因数,例如:
|
||||
|
||||
```
|
||||
context_parallel_size
|
||||
```
|
||||
|
||||
**模式 4:** 例如:- 使用 8 块 GPU 且不启用序列并行时:每步处理 8 个不同批次 - 使用 8 块 GPU 且 `context_parallel_size=4` 时:每步仅处理 2 个不同批次(每个批次跨 4 块 GPU 拆分)- 若每块 GPU 的 `micro_batch_size` 为 2,全局批次大小将从 16 降至 4
|
||||
|
||||
```
|
||||
context_parallel_size=4
|
||||
```
|
||||
|
||||
**模式 5:** 在配置中设置 `save_compressed: true` 可启用压缩格式保存模型,效果如下:- 磁盘空间占用减少约 40% - 保持与 vLLM 的兼容性以加速推理 - 保持与 llmcompressor 的兼容性以进行进一步优化(例如:量化)
|
||||
|
||||
```
|
||||
save_compressed: true
|
||||
```
|
||||
|
||||
**模式 6:** 注意:无需将集成放置在 `integrations` 文件夹中。只要安装在 Python 环境的某个包中,可位于任意位置。参见此示例仓库:https://github.com/axolotl-ai-cloud/diff-transformer
|
||||
|
||||
```
|
||||
integrations
|
||||
```
|
||||
|
||||
**模式 7:** 同时处理单样本和批量数据。- 单样本:`sample['input_ids']` 为 `list[int]` - 批量数据:`sample['input_ids']` 为 `list[list[int]]`
|
||||
|
||||
```
|
||||
utils.trainer.drop_long_seq(sample, sequence_len=2048, min_sequence_len=2)
|
||||
```
|
||||
|
||||
### 代码示例模式
|
||||
|
||||
**示例 1**(python):
|
||||
```python
|
||||
cli.cloud.modal_.ModalCloud(config, app=None)
|
||||
```
|
||||
|
||||
**示例 2**(python):
|
||||
```python
|
||||
cli.cloud.modal_.run_cmd(cmd, run_folder, volumes=None)
|
||||
```
|
||||
|
||||
**示例 3**(python):
|
||||
```python
|
||||
core.trainers.base.AxolotlTrainer(
|
||||
*_args,
|
||||
bench_data_collator=None,
|
||||
eval_data_collator=None,
|
||||
dataset_tags=None,
|
||||
**kwargs,
|
||||
)
|
||||
```
|
||||
|
||||
**示例 4**(python):
|
||||
```python
|
||||
core.trainers.base.AxolotlTrainer.log(logs, start_time=None)
|
||||
```
|
||||
|
||||
**示例 5**(python):
|
||||
```python
|
||||
prompt_strategies.input_output.RawInputOutputPrompter()
|
||||
```
|
||||
|
||||
## 参考文件
|
||||
|
||||
此 skill 在 `references/` 中包含完整文档:
|
||||
|
||||
- **api.md** - API 文档
|
||||
- **dataset-formats.md** - Dataset-Formats 文档
|
||||
- **other.md** - 其他文档
|
||||
|
||||
需要详细信息时,使用 `view` 读取特定参考文件。
|
||||
|
||||
## 使用此 Skill
|
||||
|
||||
### 初学者
|
||||
从 `getting_started` 或 `tutorials` 参考文件入手,了解基础概念。
|
||||
|
||||
### 特定功能
|
||||
使用对应分类的参考文件(api、guides 等)获取详细信息。
|
||||
|
||||
### 代码示例
|
||||
上方快速参考部分包含从官方文档中提取的常用模式。
|
||||
|
||||
## 资源
|
||||
|
||||
### references/
|
||||
从官方来源提取的有组织文档,包含:
|
||||
- 详细说明
|
||||
- 带语言标注的代码示例
|
||||
- 原始文档链接
|
||||
- 便于快速导航的目录
|
||||
|
||||
### scripts/
|
||||
在此添加常见自动化任务的辅助脚本。
|
||||
|
||||
### assets/
|
||||
在此添加模板、样板代码或示例项目。
|
||||
|
||||
## 说明
|
||||
|
||||
- 此 skill 由官方文档自动生成
|
||||
- 参考文件保留了源文档的结构与示例
|
||||
- 代码示例包含语言检测以提供更好的语法高亮
|
||||
- 快速参考模式从文档中的常见用法示例中提取
|
||||
|
||||
## 更新
|
||||
|
||||
若要使用最新文档刷新此 skill:
|
||||
1. 使用相同配置重新运行爬取程序
|
||||
2. Skill 将以最新信息重新构建
|
||||
+477
@@ -0,0 +1,477 @@
|
||||
---
|
||||
title: "使用 TRL 进行微调 — TRL:面向 LLM RLHF 的 SFT、DPO、PPO、GRPO 及奖励建模"
|
||||
sidebar_label: "使用 TRL 进行微调"
|
||||
description: "TRL:面向 LLM RLHF 的 SFT、DPO、PPO、GRPO 及奖励建模"
|
||||
---
|
||||
|
||||
{/* This page is auto-generated from the skill's SKILL.md by website/scripts/generate-skill-docs.py. Edit the source SKILL.md, not this page. */}
|
||||
|
||||
# 使用 TRL 进行微调
|
||||
|
||||
TRL:面向 LLM RLHF 的 SFT、DPO、PPO、GRPO 及奖励建模。
|
||||
|
||||
## Skill 元数据
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| 来源 | 可选 — 通过 `hermes skills install official/mlops/trl-fine-tuning` 安装 |
|
||||
| 路径 | `optional-skills/mlops/training/trl-fine-tuning` |
|
||||
| 版本 | `1.0.0` |
|
||||
| 作者 | Orchestra Research |
|
||||
| 许可证 | MIT |
|
||||
| 依赖项 | `trl`, `transformers`, `datasets`, `peft`, `accelerate`, `torch` |
|
||||
| 平台 | linux, macos, windows |
|
||||
| 标签 | `Post-Training`, `TRL`, `Reinforcement Learning`, `Fine-Tuning`, `SFT`, `DPO`, `PPO`, `GRPO`, `RLHF`, `Preference Alignment`, `HuggingFace` |
|
||||
|
||||
## 参考:完整 SKILL.md
|
||||
|
||||
:::info
|
||||
以下是 Hermes 在触发此 skill 时加载的完整 skill 定义。这是 agent 在 skill 激活时所看到的指令内容。
|
||||
:::
|
||||
|
||||
# TRL - Transformer Reinforcement Learning
|
||||
|
||||
## 快速开始
|
||||
|
||||
TRL 提供用于将语言模型与人类偏好对齐的后训练(post-training)方法。
|
||||
|
||||
**安装**:
|
||||
```bash
|
||||
pip install trl transformers datasets peft accelerate
|
||||
```
|
||||
|
||||
**监督微调(SFT)**(指令微调):
|
||||
```python
|
||||
from trl import SFTTrainer
|
||||
|
||||
trainer = SFTTrainer(
|
||||
model="Qwen/Qwen2.5-0.5B",
|
||||
train_dataset=dataset, # Prompt-completion pairs
|
||||
)
|
||||
trainer.train()
|
||||
```
|
||||
|
||||
**DPO**(偏好对齐):
|
||||
```python
|
||||
from trl import DPOTrainer, DPOConfig
|
||||
|
||||
config = DPOConfig(output_dir="model-dpo", beta=0.1)
|
||||
trainer = DPOTrainer(
|
||||
model=model,
|
||||
args=config,
|
||||
train_dataset=preference_dataset, # chosen/rejected pairs
|
||||
processing_class=tokenizer
|
||||
)
|
||||
trainer.train()
|
||||
```
|
||||
|
||||
## 常见工作流
|
||||
|
||||
### 工作流 1:完整 RLHF 流水线(SFT → 奖励模型 → PPO)
|
||||
|
||||
从基础模型到人类对齐模型的完整流水线。
|
||||
|
||||
复制此检查清单:
|
||||
|
||||
```
|
||||
RLHF Training:
|
||||
- [ ] Step 1: Supervised fine-tuning (SFT)
|
||||
- [ ] Step 2: Train reward model
|
||||
- [ ] Step 3: PPO reinforcement learning
|
||||
- [ ] Step 4: Evaluate aligned model
|
||||
```
|
||||
|
||||
**第 1 步:监督微调**
|
||||
|
||||
在指令跟随数据上训练基础模型:
|
||||
|
||||
```python
|
||||
from transformers import AutoModelForCausalLM, AutoTokenizer
|
||||
from trl import SFTTrainer, SFTConfig
|
||||
from datasets import load_dataset
|
||||
|
||||
# Load model
|
||||
model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen2.5-0.5B")
|
||||
tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen2.5-0.5B")
|
||||
|
||||
# Load instruction dataset
|
||||
dataset = load_dataset("trl-lib/Capybara", split="train")
|
||||
|
||||
# Configure training
|
||||
training_args = SFTConfig(
|
||||
output_dir="Qwen2.5-0.5B-SFT",
|
||||
per_device_train_batch_size=4,
|
||||
num_train_epochs=1,
|
||||
learning_rate=2e-5,
|
||||
logging_steps=10,
|
||||
save_strategy="epoch"
|
||||
)
|
||||
|
||||
# Train
|
||||
trainer = SFTTrainer(
|
||||
model=model,
|
||||
args=training_args,
|
||||
train_dataset=dataset,
|
||||
tokenizer=tokenizer
|
||||
)
|
||||
trainer.train()
|
||||
trainer.save_model()
|
||||
```
|
||||
|
||||
**第 2 步:训练奖励模型**
|
||||
|
||||
训练模型以预测人类偏好:
|
||||
|
||||
```python
|
||||
from transformers import AutoModelForSequenceClassification
|
||||
from trl import RewardTrainer, RewardConfig
|
||||
|
||||
# Load SFT model as base
|
||||
model = AutoModelForSequenceClassification.from_pretrained(
|
||||
"Qwen2.5-0.5B-SFT",
|
||||
num_labels=1 # Single reward score
|
||||
)
|
||||
tokenizer = AutoTokenizer.from_pretrained("Qwen2.5-0.5B-SFT")
|
||||
|
||||
# Load preference data (chosen/rejected pairs)
|
||||
dataset = load_dataset("trl-lib/ultrafeedback_binarized", split="train")
|
||||
|
||||
# Configure training
|
||||
training_args = RewardConfig(
|
||||
output_dir="Qwen2.5-0.5B-Reward",
|
||||
per_device_train_batch_size=2,
|
||||
num_train_epochs=1,
|
||||
learning_rate=1e-5
|
||||
)
|
||||
|
||||
# Train reward model
|
||||
trainer = RewardTrainer(
|
||||
model=model,
|
||||
args=training_args,
|
||||
processing_class=tokenizer,
|
||||
train_dataset=dataset
|
||||
)
|
||||
trainer.train()
|
||||
trainer.save_model()
|
||||
```
|
||||
|
||||
**第 3 步:PPO 强化学习**
|
||||
|
||||
使用奖励模型优化策略:
|
||||
|
||||
```bash
|
||||
python -m trl.scripts.ppo \
|
||||
--model_name_or_path Qwen2.5-0.5B-SFT \
|
||||
--reward_model_path Qwen2.5-0.5B-Reward \
|
||||
--dataset_name trl-internal-testing/descriptiveness-sentiment-trl-style \
|
||||
--output_dir Qwen2.5-0.5B-PPO \
|
||||
--learning_rate 3e-6 \
|
||||
--per_device_train_batch_size 64 \
|
||||
--total_episodes 10000
|
||||
```
|
||||
|
||||
**第 4 步:评估**
|
||||
|
||||
```python
|
||||
from transformers import pipeline
|
||||
|
||||
# Load aligned model
|
||||
generator = pipeline("text-generation", model="Qwen2.5-0.5B-PPO")
|
||||
|
||||
# Test
|
||||
prompt = "Explain quantum computing to a 10-year-old"
|
||||
output = generator(prompt, max_length=200)[0]["generated_text"]
|
||||
print(output)
|
||||
```
|
||||
|
||||
### 工作流 2:使用 DPO 进行简单偏好对齐
|
||||
|
||||
无需奖励模型即可对齐模型偏好。
|
||||
|
||||
复制此检查清单:
|
||||
|
||||
```
|
||||
DPO Training:
|
||||
- [ ] Step 1: Prepare preference dataset
|
||||
- [ ] Step 2: Configure DPO
|
||||
- [ ] Step 3: Train with DPOTrainer
|
||||
- [ ] Step 4: Evaluate alignment
|
||||
```
|
||||
|
||||
**第 1 步:准备偏好数据集**
|
||||
|
||||
数据集格式:
|
||||
```json
|
||||
{
|
||||
"prompt": "What is the capital of France?",
|
||||
"chosen": "The capital of France is Paris.",
|
||||
"rejected": "I don't know."
|
||||
}
|
||||
```
|
||||
|
||||
加载数据集:
|
||||
```python
|
||||
from datasets import load_dataset
|
||||
|
||||
dataset = load_dataset("trl-lib/ultrafeedback_binarized", split="train")
|
||||
# Or load your own
|
||||
# dataset = load_dataset("json", data_files="preferences.json")
|
||||
```
|
||||
|
||||
**第 2 步:配置 DPO**
|
||||
|
||||
```python
|
||||
from trl import DPOConfig
|
||||
|
||||
config = DPOConfig(
|
||||
output_dir="Qwen2.5-0.5B-DPO",
|
||||
per_device_train_batch_size=4,
|
||||
num_train_epochs=1,
|
||||
learning_rate=5e-7,
|
||||
beta=0.1, # KL penalty strength
|
||||
max_prompt_length=512,
|
||||
max_length=1024,
|
||||
logging_steps=10
|
||||
)
|
||||
```
|
||||
|
||||
**第 3 步:使用 DPOTrainer 训练**
|
||||
|
||||
```python
|
||||
from transformers import AutoModelForCausalLM, AutoTokenizer
|
||||
from trl import DPOTrainer
|
||||
|
||||
model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen2.5-0.5B-Instruct")
|
||||
tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen2.5-0.5B-Instruct")
|
||||
|
||||
trainer = DPOTrainer(
|
||||
model=model,
|
||||
args=config,
|
||||
train_dataset=dataset,
|
||||
processing_class=tokenizer
|
||||
)
|
||||
|
||||
trainer.train()
|
||||
trainer.save_model()
|
||||
```
|
||||
|
||||
**CLI 替代方式**:
|
||||
```bash
|
||||
trl dpo \
|
||||
--model_name_or_path Qwen/Qwen2.5-0.5B-Instruct \
|
||||
--dataset_name argilla/Capybara-Preferences \
|
||||
--output_dir Qwen2.5-0.5B-DPO \
|
||||
--per_device_train_batch_size 4 \
|
||||
--learning_rate 5e-7 \
|
||||
--beta 0.1
|
||||
```
|
||||
|
||||
### 工作流 3:使用 GRPO 进行内存高效的在线 RL
|
||||
|
||||
以最小内存占用进行强化学习训练。
|
||||
|
||||
关于深入的 GRPO 指导——奖励函数设计、关键训练洞察(损失行为、模式崩溃、调参)以及高级多阶段模式——请参阅 **[references/grpo-training.md](https://github.com/NousResearch/hermes-agent/blob/main/optional-skills/mlops/training/trl-fine-tuning/references/grpo-training.md)**。生产就绪的训练脚本位于 **[templates/basic_grpo_training.py](https://github.com/NousResearch/hermes-agent/blob/main/optional-skills/mlops/training/trl-fine-tuning/templates/basic_grpo_training.py)**。
|
||||
|
||||
复制此检查清单:
|
||||
|
||||
```
|
||||
GRPO Training:
|
||||
- [ ] Step 1: Define reward function
|
||||
- [ ] Step 2: Configure GRPO
|
||||
- [ ] Step 3: Train with GRPOTrainer
|
||||
```
|
||||
|
||||
**第 1 步:定义奖励函数**
|
||||
|
||||
```python
|
||||
def reward_function(completions, **kwargs):
|
||||
"""
|
||||
Compute rewards for completions.
|
||||
|
||||
Args:
|
||||
completions: List of generated texts
|
||||
|
||||
Returns:
|
||||
List of reward scores (floats)
|
||||
"""
|
||||
rewards = []
|
||||
for completion in completions:
|
||||
# Example: reward based on length and unique words
|
||||
score = len(completion.split()) # Favor longer responses
|
||||
score += len(set(completion.lower().split())) # Reward unique words
|
||||
rewards.append(score)
|
||||
return rewards
|
||||
```
|
||||
|
||||
或使用奖励模型:
|
||||
```python
|
||||
from transformers import pipeline
|
||||
|
||||
reward_model = pipeline("text-classification", model="reward-model-path")
|
||||
|
||||
def reward_from_model(completions, prompts, **kwargs):
|
||||
# Combine prompt + completion
|
||||
full_texts = [p + c for p, c in zip(prompts, completions)]
|
||||
# Get reward scores
|
||||
results = reward_model(full_texts)
|
||||
return [r["score"] for r in results]
|
||||
```
|
||||
|
||||
**第 2 步:配置 GRPO**
|
||||
|
||||
```python
|
||||
from trl import GRPOConfig
|
||||
|
||||
config = GRPOConfig(
|
||||
output_dir="Qwen2-GRPO",
|
||||
per_device_train_batch_size=4,
|
||||
num_train_epochs=1,
|
||||
learning_rate=1e-5,
|
||||
num_generations=4, # Generate 4 completions per prompt
|
||||
max_new_tokens=128
|
||||
)
|
||||
```
|
||||
|
||||
**第 3 步:使用 GRPOTrainer 训练**
|
||||
|
||||
```python
|
||||
from datasets import load_dataset
|
||||
from trl import GRPOTrainer
|
||||
|
||||
# Load prompt-only dataset
|
||||
dataset = load_dataset("trl-lib/tldr", split="train")
|
||||
|
||||
trainer = GRPOTrainer(
|
||||
model="Qwen/Qwen2-0.5B-Instruct",
|
||||
reward_funcs=reward_function, # Your reward function
|
||||
args=config,
|
||||
train_dataset=dataset
|
||||
)
|
||||
|
||||
trainer.train()
|
||||
```
|
||||
|
||||
**CLI**:
|
||||
```bash
|
||||
trl grpo \
|
||||
--model_name_or_path Qwen/Qwen2-0.5B-Instruct \
|
||||
--dataset_name trl-lib/tldr \
|
||||
--output_dir Qwen2-GRPO \
|
||||
--num_generations 4
|
||||
```
|
||||
|
||||
## 何时使用 TRL 及替代方案
|
||||
|
||||
**适合使用 TRL 的场景:**
|
||||
- 需要将模型与人类偏好对齐
|
||||
- 拥有偏好数据(chosen/rejected 对)
|
||||
- 希望使用强化学习(PPO、GRPO)
|
||||
- 需要训练奖励模型
|
||||
- 执行完整 RLHF 流水线
|
||||
|
||||
**方法选择**:
|
||||
- **SFT**:拥有 prompt-completion 对,需要基础指令跟随
|
||||
- **DPO**:拥有偏好数据,需要简单对齐(无需奖励模型)
|
||||
- **PPO**:拥有奖励模型,需要对 RL 进行最大程度的控制
|
||||
- **GRPO**:内存受限,需要在线 RL
|
||||
- **奖励模型**:构建 RLHF 流水线,需要对生成内容评分
|
||||
|
||||
**改用替代方案的场景:**
|
||||
- **HuggingFace Trainer**:无需 RL 的基础微调
|
||||
- **Axolotl**:基于 YAML 的训练配置
|
||||
- **LitGPT**:教学用途、极简微调
|
||||
- **Unsloth**:快速 LoRA 训练
|
||||
|
||||
## 常见问题
|
||||
|
||||
**问题:DPO 训练时显存溢出(OOM)**
|
||||
|
||||
减小批次大小和序列长度:
|
||||
```python
|
||||
config = DPOConfig(
|
||||
per_device_train_batch_size=1, # Reduce from 4
|
||||
max_length=512, # Reduce from 1024
|
||||
gradient_accumulation_steps=8 # Maintain effective batch
|
||||
)
|
||||
```
|
||||
|
||||
或启用梯度检查点:
|
||||
```python
|
||||
model.gradient_checkpointing_enable()
|
||||
```
|
||||
|
||||
**问题:对齐质量差**
|
||||
|
||||
调整 beta 参数:
|
||||
```python
|
||||
# Higher beta = more conservative (stays closer to reference)
|
||||
config = DPOConfig(beta=0.5) # Default 0.1
|
||||
|
||||
# Lower beta = more aggressive alignment
|
||||
config = DPOConfig(beta=0.01)
|
||||
```
|
||||
|
||||
**问题:奖励模型无法学习**
|
||||
|
||||
检查损失类型和学习率:
|
||||
```python
|
||||
config = RewardConfig(
|
||||
learning_rate=1e-5, # Try different LR
|
||||
num_train_epochs=3 # Train longer
|
||||
)
|
||||
```
|
||||
|
||||
确保偏好数据集有明确的优劣区分:
|
||||
```python
|
||||
# Verify dataset
|
||||
print(dataset[0])
|
||||
# Should have clear chosen > rejected
|
||||
```
|
||||
|
||||
**问题:PPO 训练不稳定**
|
||||
|
||||
调整 KL 系数:
|
||||
```python
|
||||
config = PPOConfig(
|
||||
kl_coef=0.1, # Increase from 0.05
|
||||
cliprange=0.1 # Reduce from 0.2
|
||||
)
|
||||
```
|
||||
|
||||
## 高级主题
|
||||
|
||||
**SFT 训练指南**:参阅 [references/sft-training.md](https://github.com/NousResearch/hermes-agent/blob/main/optional-skills/mlops/training/trl-fine-tuning/references/sft-training.md),了解数据集格式、chat template、packing 策略及多 GPU 训练。
|
||||
|
||||
**DPO 变体**:参阅 [references/dpo-variants.md](https://github.com/NousResearch/hermes-agent/blob/main/optional-skills/mlops/training/trl-fine-tuning/references/dpo-variants.md),了解 IPO、cDPO、RPO 及其他 DPO 损失函数与推荐超参数。
|
||||
|
||||
**奖励建模**:参阅 [references/reward-modeling.md](https://github.com/NousResearch/hermes-agent/blob/main/optional-skills/mlops/training/trl-fine-tuning/references/reward-modeling.md),了解结果奖励与过程奖励、Bradley-Terry 损失及奖励模型评估。
|
||||
|
||||
**在线 RL 方法**:参阅 [references/online-rl.md](https://github.com/NousResearch/hermes-agent/blob/main/optional-skills/mlops/training/trl-fine-tuning/references/online-rl.md),了解 PPO、GRPO、RLOO 及 OnlineDPO 的详细配置。
|
||||
|
||||
**GRPO 深度解析**:参阅 [references/grpo-training.md](https://github.com/NousResearch/hermes-agent/blob/main/optional-skills/mlops/training/trl-fine-tuning/references/grpo-training.md),获取专家级 GRPO 模式——奖励函数设计理念、训练洞察(为何损失上升、模式崩溃检测)、超参数调优、多阶段训练及故障排查。生产就绪模板位于 [templates/basic_grpo_training.py](https://github.com/NousResearch/hermes-agent/blob/main/optional-skills/mlops/training/trl-fine-tuning/templates/basic_grpo_training.py)。
|
||||
|
||||
## 硬件要求
|
||||
|
||||
- **GPU**:NVIDIA(需要 CUDA)
|
||||
- **显存(VRAM)**:取决于模型和方法
|
||||
- SFT 7B:16GB(使用 LoRA)
|
||||
- DPO 7B:24GB(存储参考模型)
|
||||
- PPO 7B:40GB(策略模型 + 奖励模型)
|
||||
- GRPO 7B:24GB(内存效率更高)
|
||||
- **多 GPU**:通过 `accelerate` 支持
|
||||
- **混合精度**:推荐 BF16(A100/H100)
|
||||
|
||||
**内存优化**:
|
||||
- 所有方法均可使用 LoRA/QLoRA
|
||||
- 启用梯度检查点
|
||||
- 使用更小的批次大小配合梯度累积
|
||||
|
||||
## 资源
|
||||
|
||||
- 文档:https://huggingface.co/docs/trl/
|
||||
- GitHub:https://github.com/huggingface/trl
|
||||
- 论文:
|
||||
- "Training language models to follow instructions with human feedback"(InstructGPT,2022)
|
||||
- "Direct Preference Optimization: Your Language Model is Secretly a Reward Model"(DPO,2023)
|
||||
- "Group Relative Policy Optimization"(GRPO,2024)
|
||||
- 示例:https://github.com/huggingface/trl/tree/main/examples/scripts
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
---
|
||||
title: "Unsloth — Unsloth:2-5倍更快的 LoRA/QLoRA 微调,更少显存"
|
||||
sidebar_label: "Unsloth"
|
||||
description: "Unsloth:2-5倍更快的 LoRA/QLoRA 微调,更少显存"
|
||||
---
|
||||
|
||||
{/* This page is auto-generated from the skill's SKILL.md by website/scripts/generate-skill-docs.py. Edit the source SKILL.md, not this page. */}
|
||||
|
||||
# Unsloth
|
||||
|
||||
Unsloth:2-5倍更快的 LoRA/QLoRA 微调,更少显存。
|
||||
|
||||
## Skill 元数据
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| 来源 | 可选 — 通过 `hermes skills install official/mlops/unsloth` 安装 |
|
||||
| 路径 | `optional-skills/mlops/training/unsloth` |
|
||||
| 版本 | `1.0.0` |
|
||||
| 作者 | Orchestra Research |
|
||||
| 许可证 | MIT |
|
||||
| 依赖项 | `unsloth`, `torch`, `transformers`, `trl`, `datasets`, `peft` |
|
||||
| 平台 | linux, macos |
|
||||
| 标签 | `Fine-Tuning`, `Unsloth`, `Fast Training`, `LoRA`, `QLoRA`, `Memory-Efficient`, `Optimization`, `Llama`, `Mistral`, `Gemma`, `Qwen` |
|
||||
|
||||
## 参考:完整 SKILL.md
|
||||
|
||||
:::info
|
||||
以下是 Hermes 在触发此 skill 时加载的完整 skill 定义。这是 skill 激活时 agent 所看到的指令内容。
|
||||
:::
|
||||
|
||||
# Unsloth Skill
|
||||
|
||||
基于官方文档生成的 unsloth 开发综合辅助。
|
||||
|
||||
## 何时使用此 Skill
|
||||
|
||||
以下情况应触发此 skill:
|
||||
- 使用 unsloth 进行开发
|
||||
- 询问 unsloth 功能或 API
|
||||
- 实现 unsloth 解决方案
|
||||
- 调试 unsloth 代码
|
||||
- 学习 unsloth 最佳实践
|
||||
|
||||
## 快速参考
|
||||
|
||||
### 常用模式
|
||||
|
||||
*随着你使用此 skill,快速参考模式将逐步添加。*
|
||||
|
||||
## 参考文件
|
||||
|
||||
此 skill 在 `references/` 中包含完整文档:
|
||||
|
||||
- **llms-txt.md** - Llms-Txt 文档
|
||||
|
||||
需要详细信息时,使用 `view` 读取特定参考文件。
|
||||
|
||||
## 使用此 Skill
|
||||
|
||||
### 面向初学者
|
||||
从 getting_started 或 tutorials 参考文件入手,了解基础概念。
|
||||
|
||||
### 针对特定功能
|
||||
使用相应分类的参考文件(api、guides 等)获取详细信息。
|
||||
|
||||
### 获取代码示例
|
||||
上方快速参考部分包含从官方文档中提取的常用模式。
|
||||
|
||||
## 资源
|
||||
|
||||
### references/
|
||||
从官方来源提取的有组织文档,包含:
|
||||
- 详细说明
|
||||
- 带语言标注的代码示例
|
||||
- 原始文档链接
|
||||
- 便于快速导航的目录
|
||||
|
||||
### scripts/
|
||||
在此添加用于常见自动化任务的辅助脚本。
|
||||
|
||||
### assets/
|
||||
在此添加模板、样板代码或示例项目。
|
||||
|
||||
## 说明
|
||||
|
||||
- 此 skill 由官方文档自动生成
|
||||
- 参考文件保留了源文档的结构和示例
|
||||
- 代码示例包含语言检测以提供更好的语法高亮
|
||||
- 快速参考模式从文档中的常见用法示例中提取
|
||||
|
||||
## 更新
|
||||
|
||||
如需使用最新文档刷新此 skill:
|
||||
1. 使用相同配置重新运行爬取程序
|
||||
2. Skill 将以最新信息重新构建
|
||||
|
||||
<!-- Trigger re-upload 1763621536 -->
|
||||
+336
@@ -0,0 +1,336 @@
|
||||
---
|
||||
title: "Whisper — OpenAI 的通用语音识别模型"
|
||||
sidebar_label: "Whisper"
|
||||
description: "OpenAI 的通用语音识别模型"
|
||||
---
|
||||
|
||||
{/* This page is auto-generated from the skill's SKILL.md by website/scripts/generate-skill-docs.py. Edit the source SKILL.md, not this page. */}
|
||||
|
||||
# Whisper
|
||||
|
||||
OpenAI 的通用语音识别模型。支持 99 种语言、转录、翻译为英语及语言识别。提供六种模型规格,从 tiny(3900 万参数)到 large(15.5 亿参数)。适用于语音转文字、播客转录或多语言音频处理。是鲁棒多语言 ASR(自动语音识别)的首选。
|
||||
|
||||
## Skill 元数据
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| 来源 | 可选 — 通过 `hermes skills install official/mlops/whisper` 安装 |
|
||||
| 路径 | `optional-skills/mlops/whisper` |
|
||||
| 版本 | `1.0.0` |
|
||||
| 作者 | Orchestra Research |
|
||||
| 许可证 | MIT |
|
||||
| 依赖项 | `openai-whisper`, `transformers`, `torch` |
|
||||
| 平台 | linux, macos |
|
||||
| 标签 | `Whisper`, `Speech Recognition`, `ASR`, `Multimodal`, `Multilingual`, `OpenAI`, `Speech-To-Text`, `Transcription`, `Translation`, `Audio Processing` |
|
||||
|
||||
## 参考:完整 SKILL.md
|
||||
|
||||
:::info
|
||||
以下是 Hermes 在触发此 skill 时加载的完整 skill 定义。这是 agent 在 skill 激活时所看到的指令内容。
|
||||
:::
|
||||
|
||||
# Whisper - 鲁棒语音识别
|
||||
|
||||
OpenAI 的多语言语音识别模型。
|
||||
|
||||
## 何时使用 Whisper
|
||||
|
||||
**适用场景:**
|
||||
- 语音转文字转录(99 种语言)
|
||||
- 播客/视频转录
|
||||
- 会议记录自动化
|
||||
- 翻译为英语
|
||||
- 嘈杂音频转录
|
||||
- 多语言音频处理
|
||||
|
||||
**指标**:
|
||||
- **GitHub 72,900+ 星**
|
||||
- 支持 99 种语言
|
||||
- 基于 68 万小时音频训练
|
||||
- MIT 许可证
|
||||
|
||||
**改用其他替代方案的情况**:
|
||||
- **AssemblyAI**:托管 API,支持说话人分离
|
||||
- **Deepgram**:实时流式 ASR
|
||||
- **Google Speech-to-Text**:基于云端
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 安装
|
||||
|
||||
```bash
|
||||
# Requires Python 3.8-3.11
|
||||
pip install -U openai-whisper
|
||||
|
||||
# Requires ffmpeg
|
||||
# macOS: brew install ffmpeg
|
||||
# Ubuntu: sudo apt install ffmpeg
|
||||
# Windows: choco install ffmpeg
|
||||
```
|
||||
|
||||
### 基本转录
|
||||
|
||||
```python
|
||||
import whisper
|
||||
|
||||
# Load model
|
||||
model = whisper.load_model("base")
|
||||
|
||||
# Transcribe
|
||||
result = model.transcribe("audio.mp3")
|
||||
|
||||
# Print text
|
||||
print(result["text"])
|
||||
|
||||
# Access segments
|
||||
for segment in result["segments"]:
|
||||
print(f"[{segment['start']:.2f}s - {segment['end']:.2f}s] {segment['text']}")
|
||||
```
|
||||
|
||||
## 模型规格
|
||||
|
||||
```python
|
||||
# Available models
|
||||
models = ["tiny", "base", "small", "medium", "large", "turbo"]
|
||||
|
||||
# Load specific model
|
||||
model = whisper.load_model("turbo") # Fastest, good quality
|
||||
```
|
||||
|
||||
| 模型 | 参数量 | 仅英语 | 多语言 | 速度 | 显存 |
|
||||
|-------|------------|--------------|--------------|-------|------|
|
||||
| tiny | 39M | ✓ | ✓ | ~32x | ~1 GB |
|
||||
| base | 74M | ✓ | ✓ | ~16x | ~1 GB |
|
||||
| small | 244M | ✓ | ✓ | ~6x | ~2 GB |
|
||||
| medium | 769M | ✓ | ✓ | ~2x | ~5 GB |
|
||||
| large | 1550M | ✗ | ✓ | 1x | ~10 GB |
|
||||
| turbo | 809M | ✗ | ✓ | ~8x | ~6 GB |
|
||||
|
||||
**推荐**:追求最佳速度/质量比使用 `turbo`,原型开发使用 `base`
|
||||
|
||||
## 转录选项
|
||||
|
||||
### 语言指定
|
||||
|
||||
```python
|
||||
# Auto-detect language
|
||||
result = model.transcribe("audio.mp3")
|
||||
|
||||
# Specify language (faster)
|
||||
result = model.transcribe("audio.mp3", language="en")
|
||||
|
||||
# Supported: en, es, fr, de, it, pt, ru, ja, ko, zh, and 89 more
|
||||
```
|
||||
|
||||
### 任务选择
|
||||
|
||||
```python
|
||||
# Transcription (default)
|
||||
result = model.transcribe("audio.mp3", task="transcribe")
|
||||
|
||||
# Translation to English
|
||||
result = model.transcribe("spanish.mp3", task="translate")
|
||||
# Input: Spanish audio → Output: English text
|
||||
```
|
||||
|
||||
### 初始 prompt(提示词)
|
||||
|
||||
```python
|
||||
# Improve accuracy with context
|
||||
result = model.transcribe(
|
||||
"audio.mp3",
|
||||
initial_prompt="This is a technical podcast about machine learning and AI."
|
||||
)
|
||||
|
||||
# Helps with:
|
||||
# - Technical terms
|
||||
# - Proper nouns
|
||||
# - Domain-specific vocabulary
|
||||
```
|
||||
|
||||
### 时间戳
|
||||
|
||||
```python
|
||||
# Word-level timestamps
|
||||
result = model.transcribe("audio.mp3", word_timestamps=True)
|
||||
|
||||
for segment in result["segments"]:
|
||||
for word in segment["words"]:
|
||||
print(f"{word['word']} ({word['start']:.2f}s - {word['end']:.2f}s)")
|
||||
```
|
||||
|
||||
### 温度回退
|
||||
|
||||
```python
|
||||
# Retry with different temperatures if confidence low
|
||||
result = model.transcribe(
|
||||
"audio.mp3",
|
||||
temperature=(0.0, 0.2, 0.4, 0.6, 0.8, 1.0)
|
||||
)
|
||||
```
|
||||
|
||||
## 命令行用法
|
||||
|
||||
```bash
|
||||
# Basic transcription
|
||||
whisper audio.mp3
|
||||
|
||||
# Specify model
|
||||
whisper audio.mp3 --model turbo
|
||||
|
||||
# Output formats
|
||||
whisper audio.mp3 --output_format txt # Plain text
|
||||
whisper audio.mp3 --output_format srt # Subtitles
|
||||
whisper audio.mp3 --output_format vtt # WebVTT
|
||||
whisper audio.mp3 --output_format json # JSON with timestamps
|
||||
|
||||
# Language
|
||||
whisper audio.mp3 --language Spanish
|
||||
|
||||
# Translation
|
||||
whisper spanish.mp3 --task translate
|
||||
```
|
||||
|
||||
## 批量处理
|
||||
|
||||
```python
|
||||
import os
|
||||
|
||||
audio_files = ["file1.mp3", "file2.mp3", "file3.mp3"]
|
||||
|
||||
for audio_file in audio_files:
|
||||
print(f"Transcribing {audio_file}...")
|
||||
result = model.transcribe(audio_file)
|
||||
|
||||
# Save to file
|
||||
output_file = audio_file.replace(".mp3", ".txt")
|
||||
with open(output_file, "w") as f:
|
||||
f.write(result["text"])
|
||||
```
|
||||
|
||||
## 实时转录
|
||||
|
||||
```python
|
||||
# For streaming audio, use faster-whisper
|
||||
# pip install faster-whisper
|
||||
|
||||
from faster_whisper import WhisperModel
|
||||
|
||||
model = WhisperModel("base", device="cuda", compute_type="float16")
|
||||
|
||||
# Transcribe with streaming
|
||||
segments, info = model.transcribe("audio.mp3", beam_size=5)
|
||||
|
||||
for segment in segments:
|
||||
print(f"[{segment.start:.2f}s -> {segment.end:.2f}s] {segment.text}")
|
||||
```
|
||||
|
||||
## GPU 加速
|
||||
|
||||
```python
|
||||
import whisper
|
||||
|
||||
# Automatically uses GPU if available
|
||||
model = whisper.load_model("turbo")
|
||||
|
||||
# Force CPU
|
||||
model = whisper.load_model("turbo", device="cpu")
|
||||
|
||||
# Force GPU
|
||||
model = whisper.load_model("turbo", device="cuda")
|
||||
|
||||
# 10-20× faster on GPU
|
||||
```
|
||||
|
||||
## 与其他工具集成
|
||||
|
||||
### 字幕生成
|
||||
|
||||
```bash
|
||||
# Generate SRT subtitles
|
||||
whisper video.mp4 --output_format srt --language English
|
||||
|
||||
# Output: video.srt
|
||||
```
|
||||
|
||||
### 与 LangChain 集成
|
||||
|
||||
```python
|
||||
from langchain.document_loaders import WhisperTranscriptionLoader
|
||||
|
||||
loader = WhisperTranscriptionLoader(file_path="audio.mp3")
|
||||
docs = loader.load()
|
||||
|
||||
# Use transcription in RAG
|
||||
from langchain_chroma import Chroma
|
||||
from langchain_openai import OpenAIEmbeddings
|
||||
|
||||
vectorstore = Chroma.from_documents(docs, OpenAIEmbeddings())
|
||||
```
|
||||
|
||||
### 从视频中提取音频
|
||||
|
||||
```bash
|
||||
# Use ffmpeg to extract audio
|
||||
ffmpeg -i video.mp4 -vn -acodec pcm_s16le audio.wav
|
||||
|
||||
# Then transcribe
|
||||
whisper audio.wav
|
||||
```
|
||||
|
||||
## 最佳实践
|
||||
|
||||
1. **使用 turbo 模型** — 英语场景下速度/质量最优
|
||||
2. **指定语言** — 比自动检测更快
|
||||
3. **添加初始 prompt** — 提升专业术语识别准确率
|
||||
4. **使用 GPU** — 速度提升 10–20 倍
|
||||
5. **批量处理** — 效率更高
|
||||
6. **转换为 WAV** — 兼容性更好
|
||||
7. **切分长音频** — 每段不超过 30 分钟
|
||||
8. **确认语言支持情况** — 不同语言质量有差异
|
||||
9. **使用 faster-whisper** — 比 openai-whisper 快 4 倍
|
||||
10. **监控显存** — 根据硬件配置选择模型规格
|
||||
|
||||
## 性能
|
||||
|
||||
| 模型 | 实时倍率(CPU) | 实时倍率(GPU) |
|
||||
|-------|------------------------|------------------------|
|
||||
| tiny | ~0.32 | ~0.01 |
|
||||
| base | ~0.16 | ~0.01 |
|
||||
| turbo | ~0.08 | ~0.01 |
|
||||
| large | ~1.0 | ~0.05 |
|
||||
|
||||
*实时倍率:0.1 表示比实时速度快 10 倍*
|
||||
|
||||
## 语言支持
|
||||
|
||||
主要支持语言:
|
||||
- 英语(en)
|
||||
- 西班牙语(es)
|
||||
- 法语(fr)
|
||||
- 德语(de)
|
||||
- 意大利语(it)
|
||||
- 葡萄牙语(pt)
|
||||
- 俄语(ru)
|
||||
- 日语(ja)
|
||||
- 韩语(ko)
|
||||
- 中文(zh)
|
||||
|
||||
完整列表:共 99 种语言
|
||||
|
||||
## 局限性
|
||||
|
||||
1. **幻觉问题** — 可能重复或生成不存在的文本
|
||||
2. **长音频准确率** — 超过 30 分钟后质量下降
|
||||
3. **说话人识别** — 不支持说话人分离
|
||||
4. **口音** — 质量因口音而异
|
||||
5. **背景噪音** — 可能影响准确率
|
||||
6. **实时延迟** — 不适合实时字幕场景
|
||||
|
||||
## 资源
|
||||
|
||||
- **GitHub**:https://github.com/openai/whisper ⭐ 72,900+
|
||||
- **论文**:https://arxiv.org/abs/2212.04356
|
||||
- **模型卡片**:https://github.com/openai/whisper/blob/main/model-card.md
|
||||
- **Colab**:可在仓库中获取
|
||||
- **许可证**:MIT
|
||||
Reference in New Issue
Block a user