快速教程
1. pipeline 支持的任务
| 任务 | 描述 | 模态 | Pipeline |
|---|---|---|---|
| 文本分类 | 为给定的文本序列分配一个标签 | NLP | pipeline(task="sentiment-analysis") |
| 文本生成 | 根据给定的提示生成文本 | NLP | pipeline(task="text-generation") |
| 命名实体识别 | 为序列里的每个 token 分配一个标签(人, 组织, 地址等等) | NLP | pipeline(task="ner") |
| 问答系统 | 通过给定的上下文和问题, 在文本中提取答案 | NLP | pipeline(task="question-answering") |
| 掩盖填充 | 预测出正确的在序列中被掩盖的 token | NLP | pipeline(task="fill-mask") |
| 文本摘要 | 为文本序列或文档生成总结 | NLP | pipeline(task="summarization") |
| 文本翻译 | 将文本从一种语言翻译为另一种语言 | NLP | pipeline(task="translation") |
| 图像分类 | 为图像分配一个标签 | Computer vision | pipeline(task="image-classification") |
| 图像分割 | 为图像中每个独立的像素分配标签(支持语义、全景和实例分割) | Computer vision | pipeline(task="image-segmentation") |
| 目标检测 | 预测图像中目标对象的边界框和类别 | Computer vision | pipeline(task="object-detection") |
| 音频分类 | 给音频文件分配一个标签 | Audio | pipeline(task="audio-classification") |
| 自动语音识别 | 将音频文件中的语音提取为文本 | Audio | pipeline(task="automatic-speech-recognition") |
| 视觉问答 | 给定一个图像和一个问题,正确地回答有关图像的问题 | Multimodal | pipeline(task="vqa") |
pipeline 使用示例:
# 加载
from transformers import pipeline
classifier = pipeline("sentiment-analysis")
# 测试单个文本
classifier("We are very happy to show you the 🤗 Transformers library.")
# 测试多个文本
results = classifier(["We are very happy to show you the 🤗 Transformers library.", "We hope you don't hate it."])
for result in results:
print(f"label: {result['label']}, with score: {round(result['score'], 4)}")
# 加载模型与分词器
model_name = "nlptown/bert-base-multilingual-uncased-sentiment"
from transformers import AutoTokenizer, AutoModelForSequenceClassification
model = AutoModelForSequenceClassification.from_pretrained(model_name)
tokenizer = AutoTokenizer.from_pretrained(model_name)
# 测试
classifier = pipeline("sentiment-analysis", model=model, tokenizer=tokenizer)
classifier("Nous sommes très heureux de vous présenter la bibliothèque 🤗 Transformers.")
2. AutoClass
a. AutoTokenizer
from transformers import AutoTokenizer
model_name = "nlptown/bert-base-multilingual-uncased-sentiment"
tokenizer = AutoTokenizer.from_pretrained(model_name)
# 测试-处理单个文本
encoding = tokenizer("We are very happy to show you the 🤗 Transformers library.")
print(encoding)
分词器返回了含有如下内容的字典:
input_ids:用数字表示的 token。attention_mask:应该关注哪些 token 的指示。
# 测试-处理多个文本
pt_batch = tokenizer(
["We are very happy to show you the 🤗 Transformers library.", "We hope you don't hate it."],
padding=True,
truncation=True,
max_length=512,
return_tensors="pt",
)
b. AutoModel
from transformers import AutoModelForSequenceClassification
model_name = "nlptown/bert-base-multilingual-uncased-sentiment"
pt_model = AutoModelForSequenceClassification.from_pretrained(model_name)
pt_outputs = pt_model(**pt_batch)
# 应用softmax将logits转换为概率
from torch import nn
pt_predictions = nn.functional.softmax(pt_outputs.logits, dim=-1)
print(pt_predictions)
c. 保存模型
# 保存
pt_save_directory = "./pt_save_pretrained"
tokenizer.save_pretrained(pt_save_directory)
pt_model.save_pretrained(pt_save_directory)
# 加载
pt_model = AutoModelForSequenceClassification.from_pretrained("./pt_save_pretrained")
# 模型类型转换
from transformers import AutoModel
tokenizer = AutoTokenizer.from_pretrained(pt_save_directory)
pt_model = AutoModelForSequenceClassification.from_pretrained(pt_save_directory, from_pt=True)
3. 自定义模型构建
# 导入参数
from transformers import AutoConfig
my_config = AutoConfig.from_pretrained("distilbert/distilbert-base-uncased", n_heads=12)
# 根据config创建模型
from transformers import AutoModel
my_model = AutoModel.from_config(my_config)
4. Trainer - PyTorch 优化训练循环
a. 加载模型
from transformers import AutoModelForSequenceClassification
model = AutoModelForSequenceClassification.from_pretrained("distilbert/distilbert-base-uncased")
b. 修改模型参数
from transformers import TrainingArguments
training_args = TrainingArguments(
output_dir="path/to/save/folder/",
learning_rate=2e-5,
per_device_train_batch_size=8,
per_device_eval_batch_size=8,
num_train_epochs=2,
)
c. 分词器
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("distilbert/distilbert-base-uncased")
d. 加载数据集
from datasets import load_dataset
dataset = load_dataset("rotten_tomatoes") # doctest: +IGNORE_RESULT
e. 创建数据集处理函数,使用 map 对数据集进行处理
def tokenize_dataset(dataset):
return tokenizer(dataset["text"])
dataset = dataset.map(tokenize_dataset, batched=True)
f. 创建数据整理器
from transformers import DataCollatorWithPadding
data_collator = DataCollatorWithPadding(tokenizer=tokenizer)
g. 完善 Trainer,启动训练
from transformers import Trainer
trainer = Trainer(
model=model,
args=training_args,
train_dataset=dataset["train"],
eval_dataset=dataset["test"],
processing_class=tokenizer,
data_collator=data_collator,
) # doctest: +SKIP
trainer.train()
安装:https://huggingface.co/docs/transformers/v4.52.3/zh/installation
使用 pipeline 进行推理
1. pipeline 的使用
a. 创建 pipeline
from transformers import pipeline
transcriber = pipeline(task="automatic-speech-recognition")
b. 使用 pipeline
# 处理单个输入
transcriber("https://huggingface.co/datasets/Narsil/asr_dummy/resolve/main/mlk.flac")
# 处理多个输入
transcriber(
[
"https://huggingface.co/datasets/Narsil/asr_dummy/resolve/main/mlk.flac",
"https://huggingface.co/datasets/Narsil/asr_dummy/resolve/main/1.flac",
]
)
2. 参数
a. 指定设备上创建 pipeline
transcriber = pipeline(model="openai/whisper-large-v2", device=0)
b. 指定批量大小
transcriber = pipeline(model="openai/whisper-large-v2", device=0, batch_size=2)
audio_filenames = [f"https://huggingface.co/datasets/Narsil/asr_dummy/resolve/main/{i}.flac" for i in range(1, 5)]
texts = transcriber(audio_filenames)
c. 指定任务参数
transcriber = pipeline(model="openai/whisper-large-v2", chunk_length_s=30, return_timestamps=True)
transcriber("https://huggingface.co/datasets/sanchit-gandhi/librispeech_long/resolve/main/audio.wav")
3. 在数据集上使用 pipeline
# 从迭代器中获取数据
def data():
for i in range(1000):
yield f"My example {i}"
pipe = pipeline(model="openai-community/gpt2", device=0)
generated_characters = 0
for out in pipe(data()):
generated_characters += len(out[0]["generated_text"])
# 从数据集中获取数据
# KeyDataset is a util that will just output the item we're interested in.
from transformers.pipelines.pt_utils import KeyDataset
from datasets import load_dataset
pipe = pipeline(model="hf-internal-testing/tiny-random-wav2vec2", device=0)
dataset = load_dataset("hf-internal-testing/librispeech_asr_dummy", "clean", split="validation[:10]")
for out in pipe(KeyDataset(dataset, "audio")):
print(out)
4. 在 Web 服务器上使用 pipeline
a. 视觉 pipeline
from transformers import pipeline
vision_classifier = pipeline(model="google/vit-base-patch16-224")
preds = vision_classifier(
images="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/pipeline-cat-chonk.jpeg"
)
preds = [{"score": round(pred["score"], 4), "label": pred["label"]} for pred in preds]
preds
b. 文本 pipeline
from transformers import pipeline
# This model is a `zero-shot-classification` model.
# It will classify text, except you are free to choose any label you might imagine
classifier = pipeline(model="facebook/bart-large-mnli")
classifier(
"I have a problem with my iphone that needs to be resolved asap!!",
candidate_labels=["urgent", "not urgent", "phone", "tablet", "computer"],
)
c. 多模态 pipeline
from transformers import pipeline
vqa = pipeline(model="impira/layoutlm-document-qa")
output = vqa(
image="https://huggingface.co/spaces/impira/docquery/resolve/2359223c1837a7587402bda0f2643382a6eefeab/invoice.png",
question="What is the invoice number?",
)
output[0]["score"] = round(output[0]["score"], 3)
output
5. 使用 Accelerate 在大模型上运行 pipeline
# 加载moxing
# pip install accelerate
import torch
from transformers import pipeline
pipe = pipeline(model="facebook/opt-1.3b", torch_dtype=torch.bfloat16, device_map="auto")
output = pipe("This is a cool example!", do_sample=True, top_p=0.95)
# 安装bitsandbytes并添加参数Accelerate=True
# pip install accelerate bitsandbytes
import torch
from transformers import pipeline
pipe = pipeline(model="facebook/opt-1.3b", device_map="auto", model_kwargs={"load_in_8bit": True})
output = pipe("This is a cool example!", do_sample=True, top_p=0.95)
使用 AutoClass 编写可移植的代码
1. 加载预训练的分词器
# 加载
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("google-bert/bert-base-uncased")
# 测试
sequence = "In a hole in the ground there lived a hobbit."
print(tokenizer(sequence))
2. 加载预训练的图像处理器
# 加载
from transformers import AutoImageProcessor
image_processor = AutoImageProcessor.from_pretrained("google/vit-base-patch16-224")
3. 加载预训练的特征提取器
# 加载
from transformers import AutoFeatureExtractor
feature_extractor = AutoFeatureExtractor.from_pretrained(
"ehcalabres/wav2vec2-lg-xlsr-en-speech-emotion-recognition"
)
4. 加载预训练的处理器
# 加载
from transformers import AutoProcessor
processor = AutoProcessor.from_pretrained("microsoft/layoutlmv2-base-uncased")
5. 加载预训练的模型
# 加载
from transformers import AutoModelForSequenceClassification
model = AutoModelForSequenceClassification.from_pretrained("distilbert/distilbert-base-uncased")
预处理数据
| 任务 | 预处理 | 类型 | 作用 |
|---|---|---|---|
| 自然语言处理 | 分词器 | Tokenizer | 将文本转换为一系列标记(tokens),并创建 tokens 的数字表示,将它们组合成张量 |
| 音频处理 | 特征提取器 | Feature extractor | 从音频波形中提取顺序特征并将其转换为张量 |
| 图像处理 | 图像处理器 | ImageProcessor | 将图像转换为张量 |
| 多模态输入 | 处理器 | Processor | 结合了 Tokenizer 和 ImageProcessor 或 Processor |
1. 自然语言处理
# 加载分词器
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("google-bert/bert-base-cased")
# 处理单个文本
encoded_input = tokenizer("Do not meddle in the affairs of wizards, for they are subtle and quick to anger.")
print(encoded_input)
# 处理多个文本
batch_sentences = [
"But what about second breakfast?",
"Don't think he knows about second breakfast, Pip.",
"What about elevensies?",
]
encoded_inputs = tokenizer(batch_sentences)
print(encoded_inputs)
# 解码器
tokenizer.decode(encoded_input["input_ids"])
分词器返回内容:
input_ids是与句子中每个 token 对应的索引。attention_mask指示是否应该关注一个 token。token_type_ids在存在多个序列时标识一个 token 属于哪个序列。
a. 填充
# 将 padding 参数设置为 True,以使批次中较短的序列填充到与最长序列相匹配的长度
batch_sentences = [
"But what about second breakfast?",
"Don't think he knows about second breakfast, Pip.",
"What about elevensies?",
]
encoded_input = tokenizer(batch_sentences, padding=True)
print(encoded_input)
b. 截断
# 将 truncation 参数设置为 True,以将序列截断为模型接受的最大长度
batch_sentences = [
"But what about second breakfast?",
"Don't think he knows about second breakfast, Pip.",
"What about elevensies?",
]
encoded_input = tokenizer(batch_sentences, padding=True, truncation=True)
print(encoded_input)
c. 构建张量
# 将 return_tensors 参数设置为 pt(对于PyTorch)或 tf(对于TensorFlow)
batch_sentences = [
"But what about second breakfast?",
"Don't think he knows about second breakfast, Pip.",
"What about elevensies?",
]
encoded_input = tokenizer(batch_sentences, padding=True, truncation=True, return_tensors="pt")
print(encoded_input)
2. 音频
# 加载数据集
from datasets import load_dataset, Audio
dataset = load_dataset("PolyAI/minds14", name="en-US", split="train")
# 查看输入
dataset[0]["audio"]
返回内容:
array是加载的语音信号 - 并在必要时重新采为 1D array。path指向音频文件的位置。sampling_rate是每秒测量的语音信号数据点数量。
# 使用🤗 Datasets的cast_column方法将采样率提升到16kHz:
dataset = dataset.cast_column("audio", Audio(sampling_rate=16_000))
# 再次调用 audio 列以重新采样音频文件:
dataset[0]["audio"]
# 加载特征提取器
from transformers import AutoFeatureExtractor
feature_extractor = AutoFeatureExtractor.from_pretrained("facebook/wav2vec2-base")
# 使用
audio_input = [dataset[0]["audio"]["array"]]
feature_extractor(audio_input, sampling_rate=16000)
# 填充与截断
def preprocess_function(examples):
audio_arrays = [x["array"] for x in examples["audio"]]
inputs = feature_extractor(
audio_arrays,
sampling_rate=16000,
padding=True,
max_length=100000,
truncation=True,
)
return inputs
processed_dataset = preprocess_function(dataset[:5])
# 查看填充、截断效果
processed_dataset["input_values"][0].shape
processed_dataset["input_values"][1].shape
3. 计算机视觉
# 数据集加载
from datasets import load_dataset
dataset = load_dataset("food101", split="train[:100]")
# 查看图像
dataset[0]["image"]
# 加载图像处理器
from transformers import AutoImageProcessor
image_processor = AutoImageProcessor.from_pretrained("google/vit-base-patch16-224")
# 调整大小、随机裁剪、调整颜色
from torchvision.transforms import RandomResizedCrop, ColorJitter, Compose
size = (
image_processor.size["shortest_edge"]
if "shortest_edge" in image_processor.size
else (image_processor.size["height"], image_processor.size["width"])
)
_transforms = Compose([RandomResizedCrop(size), ColorJitter(brightness=0.5, hue=0.5)])
# 图像标准化
def transforms(examples):
images = [_transforms(img.convert("RGB")) for img in examples["image"]]
examples["pixel_values"] = image_processor(images, do_resize=False, return_tensors="pt")["pixel_values"]
return examples
# 应用变换
dataset.set_transform(transforms)
# 查看变换结果
import numpy as np
import matplotlib.pyplot as plt
img = dataset[0]["pixel_values"]
plt.imshow(img.permute(1, 2, 0))
# 填充
def collate_fn(batch):
pixel_values = [item["pixel_values"] for item in batch]
encoding = image_processor.pad(pixel_values, return_tensors="pt")
labels = [item["labels"] for item in batch]
batch = {}
batch["pixel_values"] = encoding["pixel_values"]
batch["pixel_mask"] = encoding["pixel_mask"]
batch["labels"] = labels
return batch
4. 多模态
# 加载数据集
from datasets import load_dataset
lj_speech = load_dataset("lj_speech", split="train")
# 删除多余列
lj_speech = lj_speech.map(remove_columns=["file", "id", "normalized_text"])
# 查看列
lj_speech[0]["audio"]
lj_speech[0]["text"]
# 重采样,改变采样率
lj_speech = lj_speech.cast_column("audio", Audio(sampling_rate=16_000))
# 加载处理器
from transformers import AutoProcessor
processor = AutoProcessor.from_pretrained("facebook/wav2vec2-base-960h")
# 构建数据集
def prepare_dataset(example):
audio = example["audio"]
example.update(processor(audio=audio["array"], text=example["text"], sampling_rate=16000))
return example
# 测试
prepare_dataset(lj_speech[0])
微调预训练模型
1. 准备数据集
# 加载Yelp评论集
from datasets import load_dataset
dataset = load_dataset("yelp_review_full")
dataset["train"][100]
# 加载分词器,处理数据集
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("google-bert/bert-base-cased")
def tokenize_function(examples):
return tokenizer(examples["text"], padding="max_length", truncation=True)
tokenized_datasets = dataset.map(tokenize_function, batched=True)
# 数据集抽取
small_train_dataset = tokenized_datasets["train"].shuffle(seed=42).select(range(1000))
small_eval_dataset = tokenized_datasets["test"].shuffle(seed=42).select(range(1000))
2. 训练
a. 使用 Trainer 进行训练
# 模型加载
from transformers import AutoModelForSequenceClassification
model = AutoModelForSequenceClassification.from_pretrained("google-bert/bert-base-cased", num_labels=5)
i. 训练超参数
# 默认超参数
from transformers import TrainingArguments
training_args = TrainingArguments(output_dir="test_trainer")
ii. 评估
# 加载accuracy函数
import numpy as np
import evaluate
metric = evaluate.load("accuracy")
# 评估函数
def compute_metrics(eval_pred):
logits, labels = eval_pred
predictions = np.argmax(logits, axis=-1)
return metric.compute(predictions=predictions, references=labels)
# 微调过程中监控评估指标
from transformers import TrainingArguments, Trainer
training_args = TrainingArguments(output_dir="test_trainer", eval_strategy="epoch")
iii. 训练器
# 创建训练器
trainer = Trainer(
model=model,
args=training_args,
train_dataset=small_train_dataset,
eval_dataset=small_eval_dataset,
compute_metrics=compute_metrics,
)
# 微调模型
trainer.train()
b. 使用 Keras 训练 TensorFlow 模型
i. 加载用于 Keras 的数据
# 加载数据集
from datasets import load_dataset
dataset = load_dataset("glue", "cola")
dataset = dataset["train"] # Just take the training split for now
# 加载分词器
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("google-bert/bert-base-cased")
tokenized_data = tokenizer(dataset["sentence"], return_tensors="np", padding=True)
# Tokenizer returns a BatchEncoding, but we convert that to a dict for Keras
tokenized_data = dict(tokenized_data)
labels = np.array(dataset["label"]) # Label is already an array of 0 and 1
# 加载、编译、使用模型
from transformers import TFAutoModelForSequenceClassification
from tensorflow.keras.optimizers import Adam
# Load and compile our model
model = TFAutoModelForSequenceClassification.from_pretrained("google-bert/bert-base-cased")
# Lower learning rates are often better for fine-tuning transformers
model.compile(optimizer=Adam(3e-5)) # No loss argument!
model.fit(tokenized_data, labels)
ii. 将数据加载为 tf.data.Dataset
# 处理tokenizer输出,添加到数据集
def tokenize_dataset(data):
# Keys of the returned dictionary will be added to the dataset as columns
return tokenizer(data["text"])
dataset = dataset.map(tokenize_dataset)
# 流式传输批次数据
tf_dataset = model.prepare_tf_dataset(dataset["train"], batch_size=16, shuffle=True, tokenizer=tokenizer)
# 编译、训练模型
model.compile(optimizer=Adam(3e-5)) # No loss argument!
model.fit(tf_dataset)
c. 在原生 PyTorch 中训练
# 释放内存
del model
del trainer
torch.cuda.empty_cache()
# 移除text列
tokenized_datasets = tokenized_datasets.remove_columns(["text"])
# label列重命名为labels
tokenized_datasets = tokenized_datasets.rename_column("label", "labels")
# 转换数据集格式为PyTorch张量
tokenized_datasets.set_format("torch")
# 数据集抽取
small_train_dataset = tokenized_datasets["train"].shuffle(seed=42).select(range(1000))
small_eval_dataset = tokenized_datasets["test"].shuffle(seed=42).select(range(1000))
i. DataLoader
# 创建数据集
from torch.utils.data import DataLoader
train_dataloader = DataLoader(small_train_dataset, shuffle=True, batch_size=8)
eval_dataloader = DataLoader(small_eval_dataset, batch_size=8)
# 加载模型,指定标签数量
from transformers import AutoModelForSequenceClassification
model = AutoModelForSequenceClassification.from_pretrained("google-bert/bert-base-cased", num_labels=5)
ii. Optimizer、lr_scheduler
# 创建优化器
from torch.optim import AdamW
optimizer = AdamW(model.parameters(), lr=5e-5)
# 创建学习率调度器
from transformers import get_scheduler
num_epochs = 3
num_training_steps = num_epochs * len(train_dataloader)
lr_scheduler = get_scheduler(
name="linear", optimizer=optimizer, num_warmup_steps=0, num_training_steps=num_training_steps
)
# 指定训练设备
import torch
device = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu")
model.to(device)
iii. 训练循环
from tqdm.auto import tqdm
progress_bar = tqdm(range(num_training_steps))
model.train()
for epoch in range(num_epochs):
for batch in train_dataloader:
batch = {k: v.to(device) for k, v in batch.items()}
outputs = model(**batch)
loss = outputs.loss
loss.backward()
optimizer.step()
lr_scheduler.step()
optimizer.zero_grad()
progress_bar.update(1)
iv. 评估
# 使用 add_batch 累积所有批次,并在最后计算指标
import evaluate
metric = evaluate.load("accuracy")
model.eval()
for batch in eval_dataloader:
batch = {k: v.to(device) for k, v in batch.items()}
with torch.no_grad():
outputs = model(**batch)
logits = outputs.logits
predictions = torch.argmax(logits, dim=-1)
metric.add_batch(predictions=predictions, references=batch["labels"])
metric.compute()
通过脚本训练模型:https://huggingface.co/docs/transformers/v4.52.3/zh/run_scripts
使用 Accelerate 进行分布式训练
1. 设置
# 安装
pip install accelerate
# 创建Accelerate对象
from accelerate import Accelerator
accelerator = Accelerator()
2. 准备加速
# 用加速的backward替换训练循环中的loss.backward()
for epoch in range(num_epochs):
for batch in train_dataloader:
outputs = model(**batch)
loss = outputs.loss
accelerator.backward(loss)
optimizer.step()
lr_scheduler.step()
optimizer.zero_grad()
progress_bar.update(1)
3. 反向传播
Accelerate 加速代码与原代码的区别(+ 为 Accelerate 代码,- 为原代码):
+ from accelerate import Accelerator
from transformers import AdamW, AutoModelForSequenceClassification, get_scheduler
+ accelerator = Accelerator()
model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2)
optimizer = AdamW(model.parameters(), lr=3e-5)
- device = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu")
- model.to(device)
+ train_dataloader, eval_dataloader, model, optimizer = accelerator.prepare(
+ train_dataloader, eval_dataloader, model, optimizer
+ )
num_epochs = 3
num_training_steps = num_epochs * len(train_dataloader)
lr_scheduler = get_scheduler(
"linear",
optimizer=optimizer,
num_warmup_steps=0,
num_training_steps=num_training_steps
)
progress_bar = tqdm(range(num_training_steps))
model.train()
for epoch in range(num_epochs):
for batch in train_dataloader:
- batch = {k: v.to(device) for k, v in batch.items()}
outputs = model(**batch)
loss = outputs.loss
- loss.backward()
+ accelerator.backward(loss)
optimizer.step()
lr_scheduler.step()
optimizer.zero_grad()
progress_bar.update(1)
4. 训练
a. 用脚本训练
# 命令行进行配置
accelerate config
# 命令行启动训练
accelerate launch train.py
b. 用 Notebook 训练
from accelerate import notebook_launcher
notebook_launcher(training_function)
使用 PEFT 加载和训练 adapters
参数高效微调(PEFT)方法:在微调过程中冻结预训练模型的参数,并在其顶部添加少量可训练参数(adapters)。adapters 被训练以学习特定任务的信息。这种方法已被证明非常节省内存,同时具有较低的计算使用量,同时产生与完全微调模型相当的结果。
1. 设置
# 安装peft
pip install peft
# 或者安装新版本
pip install git+https://github.com/huggingface/peft.git
2. 支持的 PEFT 模型
Transformers 库支持以下 PEFT 方法:
- Low Rank Adapters
- IA3
- AdaLoRA
3. 加载 PEFT adapter
从 huggingface 的 Transformers 库中加载并使用 PEFT adapter 模型,Hub 仓库或本地目录中包含一个 adapter_config.json 文件和 adapter 权重。
# 加载PEFT adapter模型
from transformers import AutoModelForCausalLM, AutoTokenizer
peft_model_id = "ybelkada/opt-350m-lora"
model = AutoModelForCausalLM.from_pretrained(peft_model_id)
# 通过load_adapter方法加载PEFT adapter
from transformers import AutoModelForCausalLM, AutoTokenizer
model_id = "facebook/opt-350m"
peft_model_id = "ybelkada/opt-350m-lora"
model = AutoModelForCausalLM.from_pretrained(model_id)
model.load_adapter(peft_model_id)
4. 基于 8bit 或 4bit 进行加载
bitsandbytes 集成支持 8bit 和 4bit 精度数据类型,这对于加载大模型非常有用,因为它可以节省内存。
from_pretrained() 中添加 load_in_8bit 或 load_in_4bit 参数,并将 device_map 设置为 "auto"。
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
peft_model_id = "ybelkada/opt-350m-lora"
model = AutoModelForCausalLM.from_pretrained(peft_model_id, quantization_config=BitsAndBytesConfig(load_in_8bit=True))
5. 添加新的 adapter
添加新的 adapter,新的 adapter 类型需要和当前 adapter 相同。
from transformers import AutoModelForCausalLM, OPTForCausalLM, AutoTokenizer
from peft import PeftConfig
model_id = "facebook/opt-350m"
model = AutoModelForCausalLM.from_pretrained(model_id)
lora_config = LoraConfig(
target_modules=["q_proj", "k_proj"],
init_lora_weights=False
)
model.add_adapter(lora_config, adapter_name="adapter_1")
# 添加新的adapter
# attach new adapter with same config
model.add_adapter(lora_config, adapter_name="adapter_2")
# 使用~peft.PeftModel.set_adapter来设置要使用的adapter
# use adapter_1
model.set_adapter("adapter_1")
output = model.generate(**inputs)
print(tokenizer.decode(output_disabled[0], skip_special_tokens=True))
# use adapter_2
model.set_adapter("adapter_2")
output_enabled = model.generate(**inputs)
print(tokenizer.decode(output_enabled[0], skip_special_tokens=True))
6. 启用和禁用 adapter
# 启用adapter模块
from transformers import AutoModelForCausalLM, OPTForCausalLM, AutoTokenizer
from peft import PeftConfig
model_id = "facebook/opt-350m"
adapter_model_id = "ybelkada/opt-350m-lora"
tokenizer = AutoTokenizer.from_pretrained(model_id)
text = "Hello"
inputs = tokenizer(text, return_tensors="pt")
model = AutoModelForCausalLM.from_pretrained(model_id)
peft_config = PeftConfig.from_pretrained(adapter_model_id)
# to initiate with random weights
peft_config.init_lora_weights = False
model.add_adapter(peft_config)
model.enable_adapters()
output = model.generate(**inputs)
# 禁用adapter模块
model.disable_adapters()
output = model.generate(**inputs)
7. 训练一个 PEFT adapter
训练一个 LoRA adapter:
# 定义adapter配置
from peft import LoraConfig
peft_config = LoraConfig(
lora_alpha=16,
lora_dropout=0.1,
r=64,
bias="none",
task_type="CAUSAL_LM",
)
# 将adapter添加到模型中
model.add_adapter(peft_config)
# 将模型传递给Trainer
trainer = Trainer(model=model, ...)
trainer.train()
# 保存训练好的adapter并重新加载
model.save_pretrained(save_dir)
model = AutoModelForCausalLM.from_pretrained(save_dir)
分享模型
1. 仓库功能
仓库通过 revision 参数,提供版本控制功能:
model = AutoModel.from_pretrained(
"julien-c/EsperBERTo-small", revision="4c77982" # tag name, or branch name, or commit hash
)
2. 设置
在命令行执行以下命令,在 Hugging Face 缓存文件夹(默认为 ~/.cache/)中存储 access token:
huggingface-cli login
如果在 Notebook 中,可以安装 huggingface_hub 库进行交互:
pip install huggingface_hub
在 Notebook 中,生成 token 并登录:
from huggingface_hub import notebook_login
notebook_login()
3. 转换模型适用于所有框架
建议将 PyTorch 和 TensorFlow checkpoint 都互相转换,一起上传,省去其他用户在下载时进行实时转化的时间。
# 指定from_tf=True将checkpoint从TensorFlow转换为PyTorch。
pt_model = DistilBertForSequenceClassification.from_pretrained("path/to/awesome-name-you-picked", from_tf=True)
pt_model.save_pretrained("path/to/awesome-name-you-picked")
# 指定from_pt=True将checkpoint从PyTorch转换为TensorFlow。
tf_model = TFDistilBertForSequenceClassification.from_pretrained("path/to/awesome-name-you-picked", from_pt=True)
tf_model.save_pretrained("path/to/awesome-name-you-picked")
4. 在训练过程中推送模型
TrainingArguments 中设置 push_to_hub=True,可以将模型推送至 Hub:
training_args = TrainingArguments(output_dir="my-awesome-model", push_to_hub=True)
# 将TrainingArguments传递给Trainer
trainer = Trainer(
model=model,
args=training_args,
train_dataset=small_train_dataset,
eval_dataset=small_eval_dataset,
compute_metrics=compute_metrics,
)
# 微调结束后,将训练好的模型推送至Hub,超参数、训练结果、框架版本添加到模型卡片中
trainer.push_to_hub()
5. 使用 push_to_hub 功能
# 通过模型名称上传至Hub
pt_model.push_to_hub("my-awesome-model")
# 加载Hub仓库中的模型
from transformers import AutoModel
model = AutoModel.from_pretrained("your_username/my-awesome-model")
# 可以指定组织名称前缀
pt_model.push_to_hub("my-awesome-org/my-awesome-model")
# 将tokenizer上传至模型仓库
tokenizer.push_to_hub("my-awesome-model")
6. 使用 Web 界面上传
【不推荐】Web 界面上传有模型大小限制。
7. 添加模型卡片
通过以下方式添加模型卡片:
- 手动创建并上传一个
README.md文件。 - 在你的模型仓库中点击编辑模型卡片按钮。
使用 LLMs 进行生成
1. 使用 LLM 生成文本
# 安装必要的库
pip install transformers bitsandbytes>=0.39.0 -q
一个用于因果语言建模训练的语言模型,将文本 tokens 序列作为输入,并返回下一个 token 的概率分布。
使用 LLM 进行自回归生成的一个关键方面是如何从这个概率分布中选择下一个 token。这个步骤可以随意进行,只要最终得到下一个迭代的 token。这意味着可以简单的从概率分布中选择最可能的 token,也可以复杂的在对结果分布进行采样之前应用多种变换,这取决于你的需求。
上述过程是迭代重复的,直到达到某个停止条件。理想情况下,停止条件由模型决定,该模型应学会在何时输出一个结束序列(EOS)标记。如果不是这种情况,生成将在达到某个预定义的最大长度时停止。
正确设置 token 选择步骤和停止条件对于让你的模型按照预期的方式执行任务至关重要。这就是为什么我们为每个模型都有一个 [~generation.GenerationConfig] 文件,它包含一个效果不错的默认生成参数配置,并与模型一起加载。
# 加载模型
from transformers import AutoModelForCausalLM
model = AutoModelForCausalLM.from_pretrained(
"mistralai/Mistral-7B-v0.1", device_map="auto", load_in_4bit=True
)
参数说明:from_pretrained 调用中的两个参数:
device_map确保模型被移动到您的 GPU(s) 上load_in_4bit应用 4 位动态量化来极大地减少资源需求
# 加载tokenizer
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("mistralai/Mistral-7B-v0.1", padding_side="left")
model_inputs = tokenizer(["A list of colors: red, blue"], return_tensors="pt").to("cuda")
model_inputs 变量保存着分词后的文本输入以及注意力掩码。
尽管 generate() 在未传递注意力掩码时会尽其所能推断出注意力掩码,但建议尽可能传递它以获得最佳结果。
在对输入进行分词后,可以调用 generate() 方法来返回生成的 tokens。生成的 tokens 应该在打印之前转换为文本。
generated_ids = model.generate(**model_inputs)
tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
不需要一次处理一个序列!可以批量输入,这将在小延迟和低内存成本下显著提高吞吐量。只需要确保正确地填充输入:
tokenizer.pad_token = tokenizer.eos_token # Most LLMs don't have a pad token by default
model_inputs = tokenizer(
["A list of colors: red, blue", "Portugal is"], return_tensors="pt", padding=True
).to("cuda")
generated_ids = model.generate(**model_inputs)
tokenizer.batch_decode(generated_ids, skip_special_tokens=True)
2. 避免常见陷阱
# 加载模型作为样例
from transformers import AutoModelForCausalLM, AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("mistralai/Mistral-7B-v0.1")
tokenizer.pad_token = tokenizer.eos_token # Most LLMs don't have a pad token by default
model = AutoModelForCausalLM.from_pretrained(
"mistralai/Mistral-7B-v0.1", device_map="auto", load_in_4bit=True
)
陷阱:生成的输出太短/太长
建议:generate 调用中手动设置 max_new_tokens 以控制它可以返回的最大新 tokens 数量。
model_inputs = tokenizer(["A sequence of numbers: 1, 2"], return_tensors="pt").to("cuda")
# By default, the output will contain up to 20 tokens
generated_ids = model.generate(**model_inputs)
tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
# Setting `max_new_tokens` allows you to control the maximum length
generated_ids = model.generate(**model_inputs, max_new_tokens=50)
tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
陷阱:错误的生成模式
建议:通过将 do_sample=True 启用采样。
# Set seed or reproducibility -- you don't need this unless you want full reproducibility
from transformers import set_seed
set_seed(42)
model_inputs = tokenizer(["I am a cat."], return_tensors="pt").to("cuda")
# LLM + greedy decoding = repetitive, boring output
generated_ids = model.generate(**model_inputs)
tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
# With sampling, the output becomes more creative!
generated_ids = model.generate(**model_inputs, do_sample=True)
tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
陷阱:错误的填充位置
建议:输入长度不相同,则需要对它们进行填充,LLMs 没有接受过从 pad tokens 继续训练,因此您的输入需要左填充。确保在生成时不要忘记传递注意力掩码。
# The tokenizer initialized above has right-padding active by default: the 1st sequence,
# which is shorter, has padding on the right side. Generation fails to capture the logic.
model_inputs = tokenizer(
["1, 2, 3", "A, B, C, D, E"], padding=True, return_tensors="pt"
).to("cuda")
generated_ids = model.generate(**model_inputs)
tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
# With left-padding, it works as expected!
tokenizer = AutoTokenizer.from_pretrained("mistralai/Mistral-7B-v0.1", padding_side="left")
tokenizer.pad_token = tokenizer.eos_token # Most LLMs don't have a pad token by default
model_inputs = tokenizer(
["1, 2, 3", "A, B, C, D, E"], padding=True, return_tensors="pt"
).to("cuda")
generated_ids = model.generate(**model_inputs)
tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
陷阱:错误的提示
建议:一些模型和任务期望某种输入提示格式才能正常工作。当未应用此格式时,模型性能会下降:模型能工作,但不如预期提示那样好。
tokenizer = AutoTokenizer.from_pretrained("HuggingFaceH4/zephyr-7b-alpha")
model = AutoModelForCausalLM.from_pretrained(
"HuggingFaceH4/zephyr-7b-alpha", device_map="auto", load_in_4bit=True
)
set_seed(0)
prompt = """How many helicopters can a human eat in one sitting? Reply as a thug."""
model_inputs = tokenizer([prompt], return_tensors="pt").to("cuda")
input_length = model_inputs.input_ids.shape[1]
generated_ids = model.generate(**model_inputs, max_new_tokens=20)
print(tokenizer.batch_decode(generated_ids[:, input_length:], skip_special_tokens=True)[0])
# Oh no, it did not follow our instruction to reply as a thug! Let's see what happens when we write
# a better prompt and use the right template for this model (through `tokenizer.apply_chat_template`)
set_seed(0)
messages = [
{
"role": "system",
"content": "You are a friendly chatbot who always responds in the style of a thug",
},
{"role": "user", "content": "How many helicopters can a human eat in one sitting?"},
]
model_inputs = tokenizer.apply_chat_template(messages, add_generation_prompt=True, return_tensors="pt").to("cuda")
input_length = model_inputs.shape[1]
generated_ids = model.generate(model_inputs, do_sample=True, max_new_tokens=20)
print(tokenizer.batch_decode(generated_ids[:, input_length:], skip_special_tokens=True)[0])
# As we can see, it followed a proper thug style 😎
使用 Tokenizers 中的分词器
1. 自定义分词器
# 创建虚拟的分词器
from tokenizers import Tokenizer
from tokenizers.models import BPE
from tokenizers.trainers import BpeTrainer
from tokenizers.pre_tokenizers import Whitespace
tokenizer = Tokenizer(BPE(unk_token="[UNK]"))
trainer = BpeTrainer(special_tokens=["[UNK]", "[CLS]", "[SEP]", "[PAD]", "[MASK]"])
tokenizer.pre_tokenizer = Whitespace()
files = [...]
tokenizer.train(files, trainer)
2. 从分词器对象加载
from transformers import PreTrainedTokenizerFast
fast_tokenizer = PreTrainedTokenizerFast(tokenizer_object=tokenizer)
3. 从 JSON 文件加载
# 将分词器对象保存为JSON文件
tokenizer.save("tokenizer.json")
# 使用PreTrainedTokenizerFast加载
from transformers import PreTrainedTokenizerFast
fast_tokenizer = PreTrainedTokenizerFast(tokenizer_file="tokenizer.json")
使用多语言模型进行推理
1. XLM
XLM 有十个不同的 checkpoint,其中只有一个是单语言的,剩下的九个 checkpoint 可以归为两类:使用语言嵌入的 checkpoint、不使用语言嵌入的 checkpoint。
a. 带有语言嵌入的 XLM
| XLM 版本 | 建模类型 | 支持语言 |
|---|---|---|
| FacebookAI/xlm-mlm-ende-1024 | 掩码语言建模 | 英语-德语 |
| FacebookAI/xlm-mlm-enfr-1024 | 掩码语言建模 | 英语-法语 |
| FacebookAI/xlm-mlm-enro-1024 | 掩码语言建模 | 英语-罗马尼亚语 |
| FacebookAI/xlm-mlm-xnli15-1024 | 掩码语言建模 | XNLI 数据集语言 |
| FacebookAI/xlm-mlm-tlm-xnli15-1024 | 掩码语言建模+翻译 | XNLI 数据集语言 |
| FacebookAI/xlm-clm-enfr-1024 | 因果语言建模 | 英语-法语 |
| FacebookAI/xlm-clm-ende-1024 | 因果语言建模 | 英语-德语 |
语言嵌入被表示为一个张量,形状与传递给模型的 input_ids 相同,这些张量中的值取决于所使用的语言,并由分词器的 lang2id 和 id2lang 属性识别。
# 模型加载,示例:加载 FacebookAI/xlm-clm-enfr-1024 检查点(因果语言建模,英语-法语)
import torch
from transformers import XLMTokenizer, XLMWithLMHeadModel
tokenizer = XLMTokenizer.from_pretrained("FacebookAI/xlm-clm-enfr-1024")
model = XLMWithLMHeadModel.from_pretrained("FacebookAI/xlm-clm-enfr-1024")
# 分词器的lang2id属性显示了该模型的语言及其对应的id
print(tokenizer.lang2id)
# 示例输入
input_ids = torch.tensor([tokenizer.encode("Wikipedia was used to")]) # batch size 为 1
# 将语言id设置为"en"并用其定义语言嵌入。语言嵌入式用0填充的张量,张量大小与input_ids相同
language_id = tokenizer.lang2id["en"] # 0
langs = torch.tensor([language_id] * input_ids.shape[1]) # torch.tensor([0, 0, 0, ..., 0])
# 我们将其 reshape 为 (batch_size, sequence_length) 大小
langs = langs.view(1, -1) # 现在的形状是 [1, sequence_length] (我们的 batch size 为 1)
# 将input_ids和语言嵌入传递给模型
outputs = model(input_ids, langs=langs)
run_generation.py 脚本可以使用 xlm-clm 检查点生成带有语言嵌入的文本。
b. 不带语言嵌入的 XLM
以下 XLM 模型在推理时不需要语言嵌入:
| XLM 版本 | 模型类型 | 支持语言 |
|---|---|---|
| FacebookAI/xlm-mlm-17-1280 | 掩码语言建模 | 支持 17 种语言 |
| FacebookAI/xlm-mlm-100-1280 | 掩码语言建模 | 支持 100 种语言 |
与之前的 XLM 版本不同,这些模型用于通用句子表示。
2. BERT
以下 BERT 模型可用于多语言任务:
| BERT 版本 | 模型类型 | 支持语言 |
|---|---|---|
| google-bert/bert-base-multilingual-uncased | 掩码语言建模 + 下一句预测 | 支持 102 种语言 |
| google-bert/bert-base-multilingual-cased | 掩码语言建模 + 下一句预测 | 支持 104 种语言 |
这些模型在推理时不需要语言嵌入,能够从上下文中识别语言并进行相应的推理。
3. XLM-RoBERTa
以下 XLM-RoBERTa 模型可用于多语言任务:
| XLM-RoBERTa 版本 | 模型类型 | 支持语言 |
|---|---|---|
| FacebookAI/xlm-roberta-base | 掩码语言建模 | 支持 100 种语言 |
| FacebookAI/xlm-roberta-large | 掩码语言建模 | 支持 100 种语言 |
XLM-RoBERTa 使用 100 种语言的 2.5TB 新创建和清理的 CommonCrawl 数据进行了训练。
与之前发布的 mBERT 或 XLM 等多语言模型相比,它在分类、序列标记和问答等下游任务上提供了更强大的优势。
4. M2M100
以下 M2M100 模型可用于多语言翻译:
| M2M100 模型 | 模型类型 |
|---|---|
| facebook/m2m100_418M | 翻译 |
| facebook/m2m100_1.2B | 翻译 |
# 加载 facebook/m2m100_418M 检查点以将中文翻译为英文
# 在分词器中设置源语言为中文
from transformers import M2M100ForConditionalGeneration, M2M100Tokenizer
en_text = "Do not meddle in the affairs of wizards, for they are subtle and quick to anger."
chinese_text = "不要插手巫師的事務, 因為他們是微妙的, 很快就會發怒."
tokenizer = M2M100Tokenizer.from_pretrained("facebook/m2m100_418M", src_lang="zh")
model = M2M100ForConditionalGeneration.from_pretrained("facebook/m2m100_418M")
# 分词
encoded_zh = tokenizer(chinese_text, return_tensors="pt")
# M2M100强制将目标语言ID作为第一个生成的标记,以进行到目标语言的翻译
# 在generate方法中将forced_bos_token_id设置为en以翻译成英语
generated_tokens = model.generate(**encoded_zh, forced_bos_token_id=tokenizer.get_lang_id("en"))
tokenizer.batch_decode(generated_tokens, skip_special_tokens=True)
5. MBart
| MBart 版本 | 模型类型 | 支持语言 |
|---|---|---|
| facebook/mbart-large-50-one-to-many-mmt | 一对多多语言机器翻译 | 支持 50 种语言 |
| facebook/mbart-large-50-many-to-many-mmt | 多对多多语言机器翻译 | 支持 50 种语言 |
| facebook/mbart-large-50-many-to-one-mmt | 多对一多语言机器翻译 | 支持 50 种语言 |
| facebook/mbart-large-50 | 多语言翻译 | 支持 50 种语言 |
| facebook/mbart-large-cc25 | 多语言翻译 | - |
# 加载 facebook/mbart-large-50-many-to-many-mmt 检查点以将芬兰语翻译为英语
# 在分词器中设置源语言:
from transformers import AutoTokenizer, AutoModelForSeq2SeqLM
en_text = "Do not meddle in the affairs of wizards, for they are subtle and quick to anger."
fi_text = "Älä sekaannu velhojen asioihin, sillä ne ovat hienovaraisia ja nopeasti vihaisia."
tokenizer = AutoTokenizer.from_pretrained("facebook/mbart-large-50-many-to-many-mmt", src_lang="fi_FI")
model = AutoModelForSeq2SeqLM.from_pretrained("facebook/mbart-large-50-many-to-many-mmt")
# 对文本进行分词
encoded_en = tokenizer(en_text, return_tensors="pt")
# MBart 强制将目标语言 id 作为第一个生成的标记,以进行到目标语言的翻译
# 在 generate 方法中将 forced_bos_token_id 设置为 en 以翻译成英语
generated_tokens = model.generate(**encoded_en, forced_bos_token_id=tokenizer.lang_code_to_id["en_XX"])
tokenizer.batch_decode(generated_tokens, skip_special_tokens=True)
# 如果使用的是 facebook/mbart-large-50-many-to-one-mmt 检查点,则无需强制目标语言 id 作为第一个生成的令牌,否则用法是相同的
使用特定模型的 API
1. 加载并自定义模型配置
# 创建默认的DistilBertConfig配置
from transformers import DistilBertConfig
config = DistilBertConfig()
print(config)
# DistilBertConfig 显示了构建基础 DistilBertModel 所使用的所有默认属性。所有属性都可以进行自定义
模型参数自定义:
# activation参数尝试不同的激活函数
# attention_dropout参数为attention probabilities指定更高的dropout ratio
my_config = DistilBertConfig(activation="relu", attention_dropout=0.4)
print(my_config)
# 预训练模型属性可以在from_pretrained()函数中进行修改
my_config = DistilBertConfig.from_pretrained("distilbert/distilbert-base-uncased", activation="relu", attention_dropout=0.4)
# 模型配置完成后,可以使用save_pretrained()保存配置
# 配置文件以JSON文件的形式保存在指定的保存目录中
my_config.save_pretrained(save_directory="./your_model_save_path")
# 重新加载模型配置文件
my_config = DistilBertConfig.from_pretrained("./your_model_save_path/config.json")
2. 创建模型
模型定义了架构,定义了每一层网络的行为以及进行的操作。例如,配置中的 num_hidden_layers 等属性用于定义架构。
每个模型都共享基类 PreTrainedModel 和一些常用方法,例如输入嵌入的大小、修剪自注意力头等。
所有模型都是 torch.nn.Module、tf.keras.Model、flax.linen.Module 的子类,意味着模型与各自框架的用法兼容。
# 加载自定义配置属性到模型中
from transformers import DistilBertModel
my_config = DistilBertConfig.from_pretrained("./your_model_save_path/config.json")
model = DistilBertModel(my_config)
这里加载了一个具有随机参数的、未经过预训练权重的模型。
训练是一项昂贵且耗时的过程,通常来说,使用预训练模型可以更快获得更好的结果,同时仅需要很小的训练资源。
使用 from_pretrained() 创建预训练模型:
model = DistilBertModel.from_pretrained("distilbert/distilbert-base-uncased")
# 当加载预训练权重时,如果模型是由Transformers提供的,自动加载默认模型配置,也可以使用config加载自定义配置
model = DistilBertModel.from_pretrained("distilbert/distilbert-base-uncased", config=my_config)
a. 模型头
Transformers 为每个任务提供不同的模型头,只要模型支持该任务(例如,不能使用 DistilBERT 执行类似翻译这种序列到序列任务)。
# 添加模型头,DistilBertForSequenceClassification是一个带有序列分类头的DistilBERT模型。序列分类头是池化输出之上的线性层
from transformers import DistilBertForSequenceClassification
model = DistilBertForSequenceClassification.from_pretrained("distilbert/distilbert-base-uncased")
# 通过切换不同的模型头,可以将checkpoint复用于其他任务,对于问答任务,可以使用DistilBertForQuestionAnswering模型头
# 问答头与序列分类头相似,不同点在于它是隐藏状态输出之上的线性层
from transformers import DistilBertForQuestionAnswering
model = DistilBertForQuestionAnswering.from_pretrained("distilbert/distilbert-base-uncased")
3. 为文本创建慢速和快速分词器
分词器(tokenizer):用于将原始文本转换为张量。
Transformers 支持两种分词器,两种分词器都支持常用的方法,如编码和解码、添加新标记、管理特殊标记:
PreTrainedTokenizer:分词器的 Python 实现PreTrainedTokenizerFast:来自基于 Rust 的 Tokenizer 库的分词器。因为其使用了 Rust 实现,这种分词器类型的速度要快得多,尤其是在批量分词(batch tokenization)的时候。快速分词器还提供其他的方法,例如偏移映射(offset mapping),它将标记(token)映射到其原始单词或字符。
# 假设已经训练了分词器,可以从词表文件创建分词器
from transformers import DistilBertTokenizer
my_tokenizer = DistilBertTokenizer(vocab_file="my_vocab_file.txt", do_lower_case=False, padding_side="left")
注意:如果使用预训练模型,必须使用预训练模型的词表,否则输入将没有意义,因为自定义分词器生成的词表与预训练模型分词器生成的词表是不同的。
# 加载预训练模型的分词器
from transformers import DistilBertTokenizer
slow_tokenizer = DistilBertTokenizer.from_pretrained("distilbert/distilbert-base-uncased")
# 使用DistilBertTokenizerFast类创建快速分词器
from transformers import DistilBertTokenizerFast
fast_tokenizer = DistilBertTokenizerFast.from_pretrained("distilbert/distilbert-base-uncased")
# 注意:默认情况下,AutoTokenizer 将尝试加载快速标记生成器。你可以通过在 from_pretrained 中设置 use_fast=False 以禁用此行为
4. 为视觉任务创建图像处理器
# 创建图像处理器:需要创建一个与使用的模型关联的图像处理器,例如,如果使用ViT进行图像分类,则需要创建一个ViTImageProcessor
from transformers import ViTImageProcessor
vit_extractor = ViTImageProcessor()
print(vit_extractor)
# 修改图像处理器的参数
from transformers import ViTImageProcessor
my_vit_extractor = ViTImageProcessor(resample="PIL.Image.BOX", do_normalize=False, image_mean=[0.3, 0.3, 0.3])
print(my_vit_extractor)
5. 为音频任务创建特征提取器
# 创建特征提取器:需要创建一个是使用的模型关联的特征提取器,例如,如果使用Wav2Vec2进行音频分类,则需要创建一个Wav2Vec2FeatureExtractor
from transformers import Wav2Vec2FeatureExtractor
w2v2_extractor = Wav2Vec2FeatureExtractor()
print(w2v2_extractor)
# 修改特征提取器的参数
from transformers import Wav2Vec2FeatureExtractor
w2v2_extractor = Wav2Vec2FeatureExtractor(sampling_rate=8000, do_normalize=False)
print(w2v2_extractor)
6. 为多模态任务创建处理器
为支持多模式任务的模型,Transformers 提供了处理类,可以将特征提取器和分词器等处理类包装到单个对象中。
例如,使用 Wav2Vec2Processor 执行自动语音识别任务(ASR)。ASR 将语音转录为文本,因此需要创建一个特征提取器和一个分词器。
# 创建一个特征提取器用于处理音频输入
from transformers import Wav2Vec2FeatureExtractor
feature_extractor = Wav2Vec2FeatureExtractor(padding_value=1.0, do_normalize=True)
# 创建一个分词器用于处理文本输入
from transformers import Wav2Vec2CTCTokenizer
tokenizer = Wav2Vec2CTCTokenizer(vocab_file="my_vocab_file.txt")
# 将特征提取器和分词器合并到Wav2Vec2Processor中
from transformers import Wav2Vec2Processor
processor = Wav2Vec2Processor(feature_extractor=feature_extractor, tokenizer=tokenizer)
通过两个基类 - 配置类和模型类 - 以及一个附加的预处理类(分词器、图像处理器、特征提取器或处理器),你可以创建 Transformers 支持的任何模型。每个基类都是可配置的,允许你使用所需的特定属性。你可以轻松设置模型进行训练或修改现有的预训练模型进行微调。
共享自定义模型
Transformers 库设计得易于扩展。每个模型的代码都在仓库给定的子文件夹中,没有进行抽象,因此你可以轻松复制模型代码文件并根据需要进行调整。
1. 编写自定义配置
编写自定义配置的注意事项:
- 必须继承自
PretrainedConfig PretrainedConfig的__init__方法必须接受任何kwargs- 这些
kwargs需要传递给超类的__init__方法
# 自定义ResNet配置
from transformers import PretrainedConfig
from typing import List
class ResnetConfig(PretrainedConfig): # 注意事项1:必须继承PretrainedConfig
model_type = "resnet"
def __init__(
self,
block_type="bottleneck",
layers: List[int] = [3, 4, 6, 3],
num_classes: int = 1000,
input_channels: int = 3,
cardinality: int = 1,
base_width: int = 64,
stem_width: int = 64,
stem_type: str = "",
avg_down: bool = False,
**kwargs, # 注意事项2:必须能够接受任何kwargs
):
if block_type not in ["basic", "bottleneck"]:
raise ValueError(f"`block_type` must be 'basic' or bottleneck', got {block_type}.")
if stem_type not in ["", "deep", "deep-tiered"]:
raise ValueError(f"`stem_type` must be '', 'deep' or 'deep-tiered', got {stem_type}.")
self.block_type = block_type
self.layers = layers
self.num_classes = num_classes
self.input_channels = input_channels
self.cardinality = cardinality
self.base_width = base_width
self.stem_width = stem_width
self.stem_type = stem_type
self.avg_down = avg_down
super().__init__(**kwargs) # 注意事项3:kwargs 需要传递给超类的 __init__ 方法
# 使用自定义配置,创建和保存配置
resnet50d_config = ResnetConfig(block_type="bottleneck", stem_width=32, stem_type="deep", avg_down=True)
resnet50d_config.save_pretrained("custom-resnet")
# 这行代码将在custom-resnet文件夹内保存config.json文件
# 重新加载配置
resnet50d_config = ResnetConfig.from_pretrained("custom-resnet")
# 上传至Hub
ResnetConfig.push_to_hub()
2. 编写自定义模型
# 自定义模型用于提取隐藏特征,类似BertModel
from transformers import PreTrainedModel
from timm.models.resnet import BasicBlock, Bottleneck, ResNet
from .configuration_resnet import ResnetConfig
# 建立块类型(block types)与实际块类(block classes)之间的映射
BLOCK_MAPPING = {"basic": BasicBlock, "bottleneck": Bottleneck}
# 继承PreTrainedModel
class ResnetModel(PreTrainedModel):
# 这一行非必需
config_class = ResnetConfig
# 使用config调用超类的初始化方法
def __init__(self, config):
super().__init__(config)
block_layer = BLOCK_MAPPING[config.block_type]
self.model = ResNet(
block_layer,
config.layers,
num_classes=config.num_classes,
in_chans=config.input_channels,
cardinality=config.cardinality,
base_width=config.base_width,
stem_width=config.stem_width,
stem_type=config.stem_type,
avg_down=config.avg_down,
)
def forward(self, tensor):
return self.model.forward_features(tensor)
# 自定义模型用于图像分类,类似BertForSequenceClassification
import torch
class ResnetModelForImageClassification(PreTrainedModel):
# 这一行非必需
config_class = ResnetConfig
def __init__(self, config):
super().__init__(config)
block_layer = BLOCK_MAPPING[config.block_type]
self.model = ResNet(
block_layer,
config.layers,
num_classes=config.num_classes,
in_chans=config.input_channels,
cardinality=config.cardinality,
base_width=config.base_width,
stem_width=config.stem_width,
stem_type=config.stem_type,
avg_down=config.avg_down,
)
# 需要更改前向方法
def forward(self, tensor, labels=None):
logits = self.model(tensor)
if labels is not None:
loss = torch.nn.functional.cross_entropy(logits, labels)
return {"loss": loss, "logits": logits}
return {"logits": logits}
# 创建自定义模型
resnet50d = ResnetModelForImageClassification(resnet50d_config)
# 自定义模型支持使用 PreTrainedModel 的任何方法,比如 save_pretrained() 或者 push_to_hub()
# 使用timm,加载预训练模型
import timm
pretrained_model = timm.create_model("resnet50d", pretrained=True)
resnet50d.model.load_state_dict(pretrained_model.state_dict())
3. 将代码发送到 Hub
自定义模型代码的项目结构:
- 确保模型都在一个
.py文件中定义 - 所有文件都位于同一目录,方便依赖文件的相对导入
__init__.py:可以为空,这个文件是为了让 Python 将resnet_model目录作为模块configuration_resnet.py:配置文件,包含ResnetConfig代码modeling_resnet.py:模型文件,包含ResnetModel和ResnetModelForImageClassfication代码
.
└── resnet_model
├── __init__.py
├── configuration_resnet.py
└── modeling_resnet.py
# 重用现有模型,导入自定义配置和模型
from resnet_model.configuration_resnet import ResnetConfig
from resnet_model.modeling_resnet import ResnetModel, ResnetModelForImageClassification
# 将自定义模型注册为Auto类
ResnetConfig.register_for_auto_class()
ResnetModel.register_for_auto_class("AutoModel")
ResnetModelForImageClassification.register_for_auto_class("AutoModelForImageClassification")
注意:
- 对于配置,只有一个自动类
AutoConfig,不需要指定自动类的类型 - 对于模型,需要特定类型的自动类,例如
AutoModelForImageClassification
# 使用注册的自动类,创建配置和模型
resnet50d_config = ResnetConfig(block_type="bottleneck", stem_width=32, stem_type="deep", avg_down=True)
resnet50d = ResnetModelForImageClassification(resnet50d_config)
pretrained_model = timm.create_model("resnet50d", pretrained=True)
resnet50d.model.load_state_dict(pretrained_model.state_dict())
# 命令行登录到hub
huggingface-cli login
# 或在笔记本中运行以下代码
from huggingface_hub import notebook_login
notebook_login()
# 推送到远程仓库:包含模型权重、JSON格式配置文件、.py代码文件
resnet50d.push_to_hub("custom-resnet50d")
4. 使用带有自定义代码的模型
# 使用自动类(AutoClass)和from_pretrained方法,使用模型仓库里的自定义代码的配置、模型、分词器文件
# 所有上传、下载都会进行恶意软件扫描,设置trust_remote_code=True使用自定义代码的模型
from transformers import AutoModelForImageClassification
model = AutoModelForImageClassification.from_pretrained("sgugger/custom-resnet50d", trust_remote_code=True)
# 【建议】:使用revision参数提交哈希(commit hash),限定模型版本,确保模型作者没有更新恶意代码
commit_hash = "ed94a7c6247d8aedce4647f00f20de6875b5b292"
model = AutoModelForImageClassification.from_pretrained(
"sgugger/custom-resnet50d", trust_remote_code=True, revision=commit_hash
)
# 提示:在 Hub 上浏览模型仓库的提交历史时,有一个按钮可以轻松复制任何提交的提交哈希
5. 将自定义代码的模型注册到自动类
# 将自定义模型添加到自动类中
# 注意:自定义模型配置的model_type属性与现有模型类型不同,且模型类具有正确的config_class属性
from transformers import AutoConfig, AutoModel, AutoModelForImageClassification
AutoConfig.register("resnet", ResnetConfig)
AutoModel.register(ResnetConfig, ResnetModel)
AutoModelForImageClassification.register(ResnetConfig, ResnetModelForImageClassification)
# 注意:
# 将自定义配置注册到AutoConfig时,使用的第一个参数需要与自定义配置的model_type匹配
# 将自定义模型注册到任何自动模型类时,使用的第一个参数需要与config_class相匹配
聊天模型的模板
1. 介绍
LLM 的常见应用场景是聊天。聊天上下文中,不再是连续的文本字符串构成的语句,而是由一条或多条消息组成的对话,每条消息都有一个”用户”或”助手”等角色,还包括消息文本。
不同的模型对聊天的输入格式要求不同,这是添加聊天模板作为功能的原因。
聊天模板是 Tokenizer 的一部分,用来把问答的对话内容转换为模型的输入 prompt。
示例:BlenderBot 模型
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("facebook/blenderbot-400M-distill")
chat = [
{"role": "user", "content": "Hello, how are you?"},
{"role": "assistant", "content": "I'm doing great. How can I help you today?"},
{"role": "user", "content": "I'd like to show off how chat templating works!"},
]
tokenizer.apply_chat_template(chat, tokenize=False)
注意:整个聊天对话内容被压缩成了一个字符串。如果使用默认设置的 tokenizer=True,那么字符串也将被 tokenized 处理。
# 加载mistralai/Mistral-7B-Instruct-v0.1模型,演示模板的实际运行
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("mistralai/Mistral-7B-Instruct-v0.1")
chat = [
{"role": "user", "content": "Hello, how are you?"},
{"role": "assistant", "content": "I'm doing great. How can I help you today?"},
{"role": "user", "content": "I'd like to show off how chat templating works!"},
]
tokenizer.apply_chat_template(chat, tokenize=False)
说明:tokenizer 添加了 [INST] 和 [/INST] 来表示用户消息的开始和结束。Mistral-instruct 使用这些 token 进行训练,但 BlenderBot 没有。
2. 使用聊天模板
使用聊天模板:构建一系列带有 role 和 content 的字典,传递给 apply_chat_template() 方法。将聊天模板用作模型预测的输入时,建议使用 add_generation_prompt=True 来添加 generation prompt。
# 示例:使用Zephyr模型,调用model.generate()方法
from transformers import AutoModelForCausalLM, AutoTokenizer
checkpoint = "HuggingFaceH4/zephyr-7b-beta"
tokenizer = AutoTokenizer.from_pretrained(checkpoint)
model = AutoModelForCausalLM.from_pretrained(checkpoint) # You may want to use bfloat16 and/or move to GPU here
messages = [
{
"role": "system",
"content": "You are a friendly chatbot who always responds in the style of a pirate",
},
{"role": "user", "content": "How many helicopters can a human eat in one sitting?"},
]
tokenized_chat = tokenizer.apply_chat_template(messages, tokenize=True, add_generation_prompt=True, return_tensors="pt")
print(tokenizer.decode(tokenized_chat[0]))
# 输出:生成Zephyr期望的输入格式的字符串
<|system|>
You are a friendly chatbot who always responds in the style of a pirate</s>
<|user|>
How many helicopters can a human eat in one sitting?</s>
<|assistant|>
按照 Zephyr 的要求传入 prompt,使用模型生成对用户问题的回复:
outputs = model.generate(tokenized_chat, max_new_tokens=128)
print(tokenizer.decode(outputs[0]))
# 输出结果:
<|system|>
You are a friendly chatbot who always responds in the style of a pirate</s>
<|user|>
How many helicopters can a human eat in one sitting?</s>
<|assistant|>
Matey, I'm afraid I must inform ye that humans cannot eat helicopters. Helicopters are not food, they are flying machines. Food is meant to be eaten, like a hearty plate o' grog, a savory bowl o' stew, or a delicious loaf o' bread. But helicopters, they be for transportin' and movin' around, not for eatin'. So, I'd say none, me hearties. None at all.
3. 自动化的聊天 pipeline
TextGenerationPipeline:这个 pipeline 设计用于方便使用聊天模型。
# 使用示例:
from transformers import pipeline
pipe = pipeline("text-generation", "HuggingFaceH4/zephyr-7b-beta")
messages = [
{
"role": "system",
"content": "You are a friendly chatbot who always responds in the style of a pirate",
},
{"role": "user", "content": "How many helicopters can a human eat in one sitting?"},
]
print(pipe(messages, max_new_tokens=256)['generated_text'][-1])
# 输出:
{'role': 'assistant', 'content': "Matey, I'm afraid I must inform ye that humans cannot eat helicopters. Helicopters are not food, they are flying machines. Food is meant to be eaten, like a hearty plate o' grog, a savory bowl o' stew, or a delicious loaf o' bread. But helicopters, they be for transportin' and movin' around, not for eatin'. So, I'd say none, me hearties. None at all."}
TextGenerationPipeline 将负责处理所有的 tokenized 并调用 apply_chat_template,一旦模型有了聊天模板,您只需要初始化 pipeline 并传递消息列表!
4. generation prompts
# 示例对话:
messages = [
{"role": "user", "content": "Hi there!"},
{"role": "assistant", "content": "Nice to meet you!"},
{"role": "user", "content": "Can I ask a question?"}
]
# apply_chat_template方法,指定add_generation_prompt=False时,输出结果:
tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=False)
"""<|im_start|>user
Hi there!<|im_end|>
<|im_start|>assistant
Nice to meet you!<|im_end|>
<|im_start|>user
Can I ask a question?<|im_end|>
"""
# apply_chat_template方法,指定add_generation_prompt=True时,输出结果:
tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
"""<|im_start|>user
Hi there!<|im_end|>
<|im_start|>assistant
Nice to meet you!<|im_end|>
<|im_start|>user
Can I ask a question?<|im_end|>
<|im_start|>assistant
"""
两者区别:指定 add_generation_prompt 为 True 时,会添加模型开始答复的标记,确保模型生成文本时只会给出答复,而不会做出意外的行为。
聊天模型只是语言模型,他们被训练来继续文本,聊天对于他们来说是一种特殊的文本,需要用适当的控制标记来引导,让模型知道自己应该做什么。
并非所有模型都需要生成提示,例如 BlenderBot 和 LLaMA,在模型回复之前没有任何特殊标记,这种情况下,add_generation_prompt 参数将不起作用,add_generation_prompt 参数是否生效取决于你所使用的模板。
5. 训练中使用聊天模板
聊天模板应用为数据集的预处理步骤,之后,可以像进行任何其他语言模型训练任务一样继续。
训练时,通常应该设置 add_generation_prompt=False,因为添加的助手标记在训练过程中并不会有帮助。
from transformers import AutoTokenizer
from datasets import Dataset
tokenizer = AutoTokenizer.from_pretrained("HuggingFaceH4/zephyr-7b-beta")
chat1 = [
{"role": "user", "content": "Which is bigger, the moon or the sun?"},
{"role": "assistant", "content": "The sun."}
]
chat2 = [
{"role": "user", "content": "Which is bigger, a virus or a bacterium?"},
{"role": "assistant", "content": "A bacterium."}
]
dataset = Dataset.from_dict({"chat": [chat1, chat2]})
dataset = dataset.map(lambda x: {"formatted_chat": tokenizer.apply_chat_template(x["chat"], tokenize=False, add_generation_prompt=False)})
print(dataset['formatted_chat'][0])
# 输出:
<|user|>
Which is bigger, the moon or the sun?</s>
<|assistant|>
The sun.</s>
# 后续可以使用formatted_chat列,跟标准语言建模任务中一样训练即可
6. 聊天模板的工作方式
模型的聊天模板存储在 tokenizer.chat_template 属性上,属于 tokenizer 的一部分。如果没有设置,则使用该模型的默认模板。
# 示例:BlenderBot的聊天模板
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("facebook/blenderbot-400M-distill")
tokenizer.chat_template
# 输出:模板使用Jinja模板生成,使用换行和缩进美化后的输出如下
{% for message in messages %}
{% if message['role'] == 'user' %}
{{ ' ' }}
{% endif %}
{{ message['content'] }}
{% if not loop.last %}
{{ ' ' }}
{% endif %}
{% endfor %}
{{ eos_token }}
Jinja 是一种模板语言,允许编写简单的代码来生成文本,代码和语法类似于 Python,使用 Python 语法实现模板如下:
for idx, message in enumerate(messages):
if message['role'] == 'user':
print(' ')
print(message['content'])
if not idx == len(messages) - 1: # Check for the last message in the conversation
print(' ')
print(eos_token)
这里使用 Jinja 模板处理如下三步:
- 对于每条消息,如果消息是用户消息,则在前面加一个空格,否则不打印任何内容
- 添加消息内容
- 如果消息不是最后一条,在消息后面添加两个空格;如果是最后一条消息,在消息后面打印 EOS
Jinja 模板,可以实现类似于 LLaMA 的 prompt 输入。模板的作用:它根据每条消息的”角色”添加对应的消息。user、assistant、system 的消息需要分别处理,因为它们代表不同的角色输入。
{% for message in messages %}
{% if message['role'] == 'user' %}
{{ bos_token + '[INST] ' + message['content'] + ' [/INST]' }}
{% elif message['role'] == 'system' %}
{{ '<<SYS>>\\n' + message['content'] + '\\n<</SYS>>\\n\\n' }}
{% elif message['role'] == 'assistant' %}
{{ ' ' + message['content'] + ' ' + eos_token }}
{% endif %}
{% endfor %}
7. 聊天模板的自定义
a. 创建聊天模板
创建聊天模板:编写一个 Jinja 模板并设置 tokenizer.chat_template。
复用上面的 LLaMA 模板,在助手消息中添加 [ASST] 和 [/ASST]:
{% for message in messages %}
{% if message['role'] == 'user' %}
{{ bos_token + '[INST] ' + message['content'].strip() + ' [/INST]' }}
{% elif message['role'] == 'system' %}
{{ '<<SYS>>\\n' + message['content'].strip() + '\\n<</SYS>>\\n\\n' }}
{% elif message['role'] == 'assistant' %}
{{ '[ASST] ' + message['content'] + ' [/ASST]' + eos_token }}
{% endif %}
{% endfor %}
设置 tokenizer.chat_template 属性:
# 设置tokenizer.chat_template属性,这里简单替换原有的模板属性
template = tokenizer.chat_template
template = template.replace("SYS", "SYSTEM") # Change the system token
tokenizer.chat_template = template # Set the new template
tokenizer.push_to_hub("model_name") # Upload your new template to the Hub!
b. 默认模板
默认模板:聊天 prompt 是在模型中通过硬编码处理的。如果一个模型没有设置聊天模板,但模型有默认模板,TextGenerationPipeline 类和 apply_chat_template 方法将使用该模型的聊天模板。聊天模板可以通过 tokenizer.default_chat_template 属性查看。
默认聊天模板是向前兼容的功能,建议通过显示设置 chat_template 属性覆盖默认模板,以防未来默认模板被修改或弃用的情况。
c. 选用模板
在为已经训练过的聊天模型设置模板时,应确保模板与模型在训练期间看到的信息格式完全匹配,否则可能导致性能下降。
即使继续对模型进行训练,也应保持聊天模板不变,以便获得最佳性能。与 tokenization 类似,推断时,应选用训练时一样的 tokenization,通常会获得最佳性能。
默认模板的形式:
{% for message in messages %}
{{'<|im_start|>' + message['role'] + '\n' + message['content'] + '<|im_end|>' + '\n'}}
{% endfor %}
使用默认模板显式覆盖 tokenizer.chat_template 属性:
tokenizer.chat_template = "{% if not add_generation_prompt is defined %}{% set add_generation_prompt = false %}{% endif %}{% for message in messages %}{{'<|im_start|>' + message['role'] + '\n' + message['content'] + '<|im_end|>' + '\n'}}{% endfor %}{% if add_generation_prompt %}{{ '<|im_start|>assistant\n' }}{% endif %}"
# 模板输出:
<|im_start|>system
You are a helpful chatbot that will do its best not to say anything so stupid that people tweet about it.<|im_end|>
<|im_start|>user
How are you?<|im_end|>
<|im_start|>assistant
I'm doing great!<|im_end|>
d. 添加模板
设置 tokenizer.chat_template 属性,通过 apply_chat_template 方法调用。
8. 聊天模板的开发技巧
使用 Jinja 代码语法创建模板。
a. for 循环
# jinja的for循环
{% for message in messages %}
{{ message['content'] }}
{% endfor %}
# 在表达式块中可以使用+连接字符串
b. if 语句
# jinja的if语句
{% if message['role'] == 'user' %}
{{ message['content'] }}
{% endif %}
# jinja使用{% endfor %}和{% endif %}表示for和if的结束
c. 特殊变量
# 示例:设置add_generation_prompt=True,在对话结束时添加generate_prompt
{% if loop.last and add_generation_prompt %}
{{ bos_token + 'Assistant:\n' }}
{% endif %}
d. 空格的注意事项
建议:忽略除 {{ expressions }} 之外的空格,Jinja 是一个通用的模板引擎,可能会将同一行文本块之间的空格视为重要,并将其打印到输出中。
## 导出为 ONNX
### 1. ONNX 简介
ONNX (Open Neural Network eXchange) 是一个开放的标准,它定义了一组通用的运算符和一种通用的文件格式,用于表示包括 PyTorch 和 TensorFlow 在内的各种框架中的深度学习模型。
ONNX 使得模型能够轻松在不同深度学习框架间切换。例如,在 PyTorch 中训练的模型可以被导出为 ONNX,然后再导入到 TensorFlow(反之亦然)。
导出 ONNX 后,模型可以:
- 通过**图优化(graph optimization)**和**量化(quantization)**等技术进行推理优化
- 通过 `ORTModelForXXX` 类使用 ONNX Runtime 运行,它同样遵循 Transformers 中的 `AutoModel` API
- 使用**优化推理流水线(pipeline)**运行,其 API 与 Transformers 中的 `pipeline()` 函数相同
有两种方式可以将 Transformers 模型导出为 ONNX:
- 使用 Optimum 的 CLI(命令行)导出
- 使用 Optimum 的 `optimum.onnxruntime` 模块导出
### 2. 使用 CLI 将 Transformers 模型导出为 ONNX
安装依赖:
```bash
pip install optimum[exporters]
查看帮助:
optimum-cli export onnx --help
从 Hub 导出模型的检查点,以 distilbert/distilbert-base-uncased-distilled-squad 为例:
optimum-cli export onnx --model distilbert/distilbert-base-uncased-distilled-squad distilbert_base_uncased_squad_onnx/
从日志中查看导出进度以及生成对 model.onnx 文件的保存位置:
Validating ONNX model distilbert_base_uncased_squad_onnx/model.onnx...
-[✓] ONNX model output names match reference model (start_logits, end_logits)
- Validating ONNX Model output "start_logits":
-[✓] (2, 16) matches (2, 16)
-[✓] all values close (atol: 0.0001)
- Validating ONNX Model output "end_logits":
-[✓] (2, 16) matches (2, 16)
-[✓] all values close (atol: 0.0001)
The ONNX export succeeded and the exported model was saved at: distilbert_base_uncased_squad_onnx
从本地导出模型的检查点,需要提供 --task 参数,如果未提供 task 参数,将默认导出不带特定任务头的模型架构:
optimum-cli export onnx --model local_path --task question-answering distilbert_base_uncased_squad_onnx/
使用 ONNX Runtime 加载和运行模型:
from transformers import AutoTokenizer
from optimum.onnxruntime import ORTModelForQuestionAnswering
tokenizer = AutoTokenizer.from_pretrained("distilbert_base_uncased_squad_onnx")
model = ORTModelForQuestionAnswering.from_pretrained("distilbert_base_uncased_squad_onnx")
inputs = tokenizer("What am I using?", "Using DistilBERT with ONNX Runtime!", return_tensors="pt")
outputs = model(**inputs)
从 Hub 导出 TensorFlow 检查点:
optimum-cli export onnx --model keras-io/transformers-qa distilbert_base_cased_squad_onnx/
3. 使用 optimum.onnxruntime 将 Transformers 模型导出为 ONNX
使用代码将 Transformers 模型导出为 ONNX:
from optimum.onnxruntime import ORTModelForSequenceClassification
from transformers import AutoTokenizer
model_checkpoint = "distilbert_base_uncased_squad"
save_directory = "onnx/"
# 从 transformers 加载模型并将其导出为 ONNX
ort_model = ORTModelForSequenceClassification.from_pretrained(model_checkpoint, export=True)
tokenizer = AutoTokenizer.from_pretrained(model_checkpoint)
# 保存 onnx 模型以及分词器
ort_model.save_pretrained(save_directory)
tokenizer.save_pretrained(save_directory)
4. 使用 transformers.onnx 导出模型
使用 transformers.onnx 将 Transformers 模型导出为 ONNX,需要安装额外依赖:
pip install transformers[onnx]
将 transformers.onnx 包作为 Python 模块使用:
python -m transformers.onnx --model=distilbert/distilbert-base-uncased onnx/
使用 ONNX Runtime 加载并运行模型:
from transformers import AutoTokenizer
from onnxruntime import InferenceSession
tokenizer = AutoTokenizer.from_pretrained("distilbert/distilbert-base-uncased")
session = InferenceSession("onnx/model.onnx")
# ONNX Runtime expects NumPy arrays as input
inputs = tokenizer("Using DistilBERT with ONNX Runtime!", return_tensors="np")
outputs = session.run(output_names=["last_hidden_state"], input_feed=dict(inputs))
通过查看每个模型对 ONNX 配置来获取所需的输出名(例如 ["last_hidden_state"])。例如,对于 DistilBERT,可以使用以下代码获取输出名称:
from transformers.models.distilbert import DistilBertConfig, DistilBertOnnxConfig
config = DistilBertConfig()
onnx_config = DistilBertOnnxConfig(config)
print(list(onnx_config.outputs.keys()))
从 Hub 导出 TensorFlow 检查点:
python -m transformers.onnx --model=keras-io/transformers-qa onnx/
导出本地存储的模型,需要将模型权重和分词器文件保存在同一目录中(例如 local-pt-checkpoint),然后将 transformers.onnx 的 --model 参数指向该目录,将其导出为 ONNX:
python -m transformers.onnx --model=local-pt-checkpoint onnx/
导出为 TFLite
TensorFlow Lite 是一个轻量级框架,用于资源受限的设备上,如手机、嵌入式系统和物联网(IoT)设备,部署机器学习模型。TFLite 旨在在计算能力、内存和功耗有限的设备上优化和高效运行模型。模型以一种特殊的高效可移植格式表示,其文件扩展名为 .tflite。
Optimum 通过 exporters.tflite 模块提供将 Transformers 模型导出至 TFLite 格式的功能。
导出 TFLite 格式前,需要安装依赖:
pip install optimum[exporters-tf]
命令行中查看帮助:
optimum-cli export tflite --help
从 Hub 导出模型检查点,以 google-bert/bert-base-uncased 为例:
optimum-cli export tflite --model google-bert/bert-base-uncased --sequence_length 128 bert_tflite/
在日志中查看导出进度以及生成对 model.tflite 文件的保存位置:
Validating TFLite model...
-[✓] TFLite model output names match reference model (logits)
- Validating TFLite Model output "logits":
-[✓] (1, 128, 30522) matches (1, 128, 30522)
-[x] values not close enough, max diff: 5.817413330078125e-05 (atol: 1e-05)
The TensorFlow Lite export succeeded with the warning: The maximum absolute difference between the output of the reference model and the TFLite exported model is not within the set tolerance 1e-05:
- logits: max diff = 5.817413330078125e-05.
The exported model was saved at: bert_tflite
导出本地模型时,需要确保将模型的权重和分词器文件保存在同一目录 local_path 中,在使用 CLI(命令行)时,将 local_path 传递给 model 参数。
导出为 TorchScript
TorchScript 是从 PyTorch 代码创建可序列化和可优化的模型的一种方式。
有两个 PyTorch 模块:JIT 和 TRACE。这两个模块允许开发人员将其模型导出到其他程序中重用,比如面向效率的 C++ 程序。
导出模型需要两个步骤:
- 使用
torchscript参数实例化模型 - 使用虚拟输入进行前向传递
1. TorchScript 参数和绑定权重
torchscript 参数是必需的,因为大多数 🤗 Transformers 语言模型的 Embedding 层和 Decoding 层之间有绑定权重。TorchScript 不允许导出具有绑定权重的模型,因此必须事先解绑和克隆权重。
使用 torchscript 参数实例化的模型将其 Embedding 层和 Decoding 层分开,这意味着它们不应该在后续进行训练。训练将导致这两层不同步,产生意外结果。
对于没有语言模型头部的模型,情况不同,因为这些模型没有绑定权重。这些模型可以安全地导出而无需 torchscript 参数。
2. 虚拟输入和标准长度
虚拟输入用于模型的前向传递。当输入的值传播到各层时,PyTorch 会跟踪在每个张量上执行的不同操作。然后使用记录的操作来创建模型的 trace。
跟踪是相对于输入的维度创建的。因此,它受到虚拟输入的维度限制,对于任何其他序列长度或批量大小都不起作用。当尝试使用不同大小时,会引发以下错误:
The expanded size of the tensor (3) must match the existing size (7) at non-singleton dimension 2
我们建议使用至少与推断期间将馈送到模型的最大输入一样大的虚拟输入大小进行跟踪。填充可以帮助填补缺失的值。然而,由于模型是使用更大的输入大小进行跟踪的,矩阵的维度也会很大,导致更多的计算。
在每个输入上执行的操作总数要仔细考虑,并在导出不同序列长度模型时密切关注性能。
3. 在 Python 中使用 TorchScript
a. 保存模型
要使用 TorchScript 导出 BertModel,请从 BertConfig 类实例化 BertModel,然后将其保存到名为 traced_bert.pt 的磁盘文件中:
from transformers import BertModel, BertTokenizer, BertConfig
import torch
enc = BertTokenizer.from_pretrained("google-bert/bert-base-uncased")
# 对输入文本分词
text = "[CLS] Who was Jim Henson ? [SEP] Jim Henson was a puppeteer [SEP]"
tokenized_text = enc.tokenize(text)
# 屏蔽一个输入 token
masked_index = 8
tokenized_text[masked_index] = "[MASK]"
indexed_tokens = enc.convert_tokens_to_ids(tokenized_text)
segments_ids = [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1]
# 创建虚拟输入
tokens_tensor = torch.tensor([indexed_tokens])
segments_tensors = torch.tensor([segments_ids])
dummy_input = [tokens_tensor, segments_tensors]
# 使用 torchscript 参数初始化模型
# 即使此模型没有 LM Head,也将参数设置为 True。
config = BertConfig(
vocab_size_or_config_json_file=32000,
hidden_size=768,
num_hidden_layers=12,
num_attention_heads=12,
intermediate_size=3072,
torchscript=True,
)
# 实例化模型
model = BertModel(config)
# 模型需要处于评估模式
model.eval()
# 如果您使用 *from_pretrained* 实例化模型,还可以轻松设置 TorchScript 参数
model = BertModel.from_pretrained("google-bert/bert-base-uncased", torchscript=True)
# 创建 trace
traced_model = torch.jit.trace(model, [tokens_tensor, segments_tensors])
torch.jit.save(traced_model, "traced_bert.pt")
b. 加载模型
从磁盘加载先前保存的 BertModel、traced_bert.pt,并在先前初始化的 dummy_input 上使用:
loaded_model = torch.jit.load("traced_bert.pt")
loaded_model.eval()
all_encoder_layers, pooled_output = loaded_model(*dummy_input)
c. 使用 trace 模型进行推断
通过使用其 __call__ dunder 方法使用 trace 模型进行推断:
traced_model(tokens_tensor, segments_tensors)
4. 使用 Neuron SDK 将 Hugging Face TorchScript 模型部署到 AWS
AWS 引入了用于云端低成本、高性能机器学习推理的 Amazon EC2 Inf1 实例系列。Inf1 实例由 AWS Inferentia 芯片提供支持,这是一款专为深度学习推理工作负载而构建的定制硬件加速器。
AWS Neuron 是 Inferentia 的 SDK,支持对 transformers 模型进行跟踪和优化,以便在 Inf1 上部署。Neuron SDK 提供:
- 简单易用的 API,只需更改一行代码即可为云端推理跟踪和优化 TorchScript 模型
- 针对改进的性能成本的即插即用性能优化
- 支持使用 PyTorch 或 TensorFlow 构建的 Hugging Face transformers 模型
a. 影响
基于 BERT(来自 Transformers 的双向编码器表示)架构的 transformers 模型,或其变体,如 distilBERT 和 roBERTa 在 Inf1 上运行最佳,可用于生成抽取式问答、序列分类和标记分类等任务。
b. 依赖关系
使用 AWS Neuron 将模型转换为模型需要一个 Neuron SDK 环境,它已经预先配置在 AWS 深度学习 AMI 上。
c. 将模型转换为 AWS Neuron
导入 torch.neuron 框架扩展,通过 Python API 访问 Neuron SDK 组件,只需要修改一行代码即可:
from transformers import BertModel, BertTokenizer, BertConfig
import torch
import torch.neuron
# 只需要修改一行代码,使用Neuron SDK跟踪模型并进行优化,以在Inf1实例上运行
# 原始代码:
# torch.jit.trace(model, [tokens_tensor, segments_tensors])
# 替换为:
torch.neuron.trace(model, [token_tensor, segments_tensors])
性能与扩展
1. 训练
| 训练方式 | 文档链接 |
|---|---|
| 单 GPU 训练 | perf_train_gpu_one |
| 多 GPU 训练 | perf_train_gpu_many |
| 单 CPU 训练 | perf_train_cpu |
| 多 CPU 训练 | perf_train_cpu_many |
| TPU 训练 | perf_train_tpu_tf |
| 自定义硬件训练 | perf_hardware |
| Trainer 超参数搜索 | hpo_train |
2. 推理
| 推理方式 | 文档链接 |
|---|---|
| 单 CPU 推理 | perf_infer_cpu |
| 单 GPU 推理 | perf_infer_gpu_one |
| 多 GPU 推理 | perf_infer_gpu_one |
| TensorFlow 模型 XLA 集成 | tf_xla |
3. 训练和推理的技巧
| 技巧 | 文档链接 |
|---|---|
| 实例化大型模型 | big_models |
| 性能优化 | debugging |
安全分片数据并行
1. 简介
**完全分片数据并行(FSDP)**将模型的参数、梯度和优化器状态,在每个 GPU 上进行分片,单卡仅保留部分分片。
**分布式数据并行(DDP)**将模型的参数、梯度和优化器状态,在每个 GPU 上复制完整模型副本。
FSDP 已经集成到 Accelerate 中,这是一个用于在分布式环境中轻松管理训练的库,这意味着可以从 Trainer 类中调用这个库。
2. FSDP 配置
运行 accelerate config 命令,创建一个配置文件。运行 accelerate config 时,将被提示一系列选项来配置训练环境。
3. 分片策略
FSDP 提供了多种可选择的分片策略:
| 策略 | 描述 | 选项 |
|---|---|---|
FULL_SHARD | 将模型参数、梯度和优化器状态跨 Worker 进行分片 | 选择 1 |
SHARD_GRAD_OP | 将梯度和优化器状态跨 Worker 进行分片 | 选择 2 |
NO_SHARD | 不分片任何内容(这等同于 DDP) | 选择 3 |
HYBRID_SHARD | 在每个 Worker 中分片模型参数、梯度和优化器状态,其中每个 Worker 也有完整副本 | 选择 4 |
HYBRID_SHARD_ZERO2 | 在每个 Worker 中分片梯度和优化器状态,其中每个 Worker 也有完整副本 | 选择 5 |
由 fsdp_sharding_strategy 标志启用。
4. CPU 卸载
当参数和梯度在不使用时可以卸载到 CPU 上,以节省更多 GPU 内存。运行 accelerate config 时,通过设置 fsdp_offload_params: true 来启用此功能。
5. 包装策略
通常,包装是以嵌套方式应用的,其中完整的权重在每次前向传递后被丢弃,以便为下一层节省内存。
自动包装策略:
fsdp_auto_wrap_policy: TRANSFORMER_BASED_WRAP来包装一个 Transformer 层fsdp_transformer_layer_cls_to_wrap来指定要包装的层(例如BertLayer)
6. 检查点
应该使用 fsdp_state_dict_type: SHARDED_STATE_DICT 来保存中间检查点,因为保存完整状态字典需要很长时间,通常会导致 NCCL Timeout 错误,因为在广播过程中会无限期挂起。
可以使用 load_state 方法加载分片状态字典以恢复训练:
# ckpt是包含检查点的目录
accelerator.load_state("ckpt")
当训练结束,希望保存完整状态字典,因为分片状态字典仅与 FSDP 兼容:
if trainer.is_fsdp_enabled:
trainer.accelerator.state.fsdp_plugin.set_state_dict_type("FULL_STATE_DICT")
trainer.save_model(script_args.output_dir)
7. TPU
PyTorch XLA 支持用于 TPUs 的 FSDP 训练,可以通过修改由 accelerate config 生成的 FSDP 配置文件来启用。
除了上面指定的分片策略和包装选项外,还可以将以下参数添加到文件中:
xla: True # 必须设置为 True 以启用 PyTorch/XLA
xla_fsdp_settings: # XLA 特定的 FSDP 参数
xla_fsdp_grad_ckpt: True # 使用梯度检查点
8. 启动训练
FSDP 配置文件示例:
compute_environment: LOCAL_MACHINE
debug: false
distributed_type: FSDP
downcast_bf16: "no"
fsdp_config:
fsdp_auto_wrap_policy: TRANSFORMER_BASED_WRAP
fsdp_backward_prefetch_policy: BACKWARD_PRE
fsdp_cpu_ram_efficient_loading: true
fsdp_forward_prefetch: false
fsdp_offload_params: true
fsdp_sharding_strategy: 1
fsdp_state_dict_type: SHARDED_STATE_DICT
fsdp_sync_module_states: true
fsdp_transformer_layer_cls_to_wrap: BertLayer
fsdp_use_orig_params: true
machine_rank: 0
main_training_function: main
mixed_precision: bf16
num_machines: 1
num_processes: 2
rdzv_backend: static
same_network: true
tpu_env: []
tpu_use_cluster: false
tpu_use_sudo: false
use_cpu: false
启动训练,使用默认配置:
accelerate launch my-trainer-script.py
启动训练,使用自定义 FSDP 配置文件:
accelerate launch --fsdp="full shard" --fsdp_config="path/to/fsdp_config/ my-trainer-script.py
多 GPU 推理
启用张量并行,只需在调用 from_pretrained() 时传递参数 tp_plan="auto":
import os
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
model_id = "meta-llama/Meta-Llama-3-8B-Instruct"
# 初始化分布式环境
rank = int(os.environ["RANK"])
device = torch.device(f"cuda:{rank}")
torch.cuda.set_device(device)
torch.distributed.init_process_group("nccl", device_id=device)
# 获取支持张量并行的模型
model = AutoModelForCausalLM.from_pretrained(
model_id,
tp_plan="auto",
)
# 准备输入tokens
tokenizer = AutoTokenizer.from_pretrained(model_id)
prompt = "Can I help"
inputs = tokenizer(prompt, return_tensors="pt").input_ids.to(device)
# 分布式运行
outputs = model(inputs)
使用 torchrun 命令启动上述脚本,多进程模式会自动将每个进程映射到一张 GPU:
torchrun --nproc-per-node 4 demo.py
多 CPU 训练
1. 使用 IPEX 进行混合精度训练
混合精度训练在模型中可以同时使用单精度(fp32)和半精度(bf16/fp16)的数据类型来加速训练或推理过程,并且仍然能保留大部分单精度的准确性。
例如:
- 第三代、第四代和第五代 Intel® Xeon® Scalable 处理器,原生支持 bf16
- 第六代 Intel® Xeon® Scalable 处理器原生支持 bf16 和 fp16
- 在训练时启用 bf16 或 fp16 的混合精度训练可以直接提高处理性能
为了进一步最大化训练性能,可以使用 Intel® PyTorch 扩展(IPEX)。
IPEX 是一个基于 PyTorch 构建的库,增加了额外的 CPU 指令集架构(ISA)级别的支持。
例如:
- Intel® 高级向量扩展 512(Intel® AVX512-VNNI)和 Intel® 高级矩阵扩展(Intel® AMX),为 Intel CPU 提供额外的性能提升
- 仅支持 AVX2 的 CPU(例如 AMD 或较旧的 Intel CPU)在使用 IPEX 时并不保证能提高性能
2. IPEX 安装
IPEX 的发布与 PyTorch 一致,可以通过 pip 安装:
| PyTorch Version | IPEX version |
|---|---|
| 2.5.0 | 2.5.0+cpu |
| 2.4.0 | 2.4.0+cpu |
| 2.3.0 | 2.3.0+cpu |
| 2.2.0 | 2.2.0+cpu |
运行 pip list | grep torch 以获取您的 pytorch_version,然后根据该版本安装相应的 IPEX version_name:
pip install intel_extension_for_pytorch==<version_name> -f https://developer.intel.com/ipex-whl-stable-cpu
3. 在 Trainer 中使用 IPEX
命令行的方式,CPU 上使用 BF16 自动混合精度训练,以 Transformers 问答任务为例:
python examples/pytorch/question-answering/run_qa.py \
--model_name_or_path google-bert/bert-base-uncased \
--dataset_name squad \
--do_train \
--do_eval \
--per_device_train_batch_size 12 \
--learning_rate 3e-5 \
--num_train_epochs 2 \
--max_seq_length 384 \
--doc_stride 128 \
--output_dir /tmp/debug_squad/ \
--use_ipex \
--bf16 \
--use_cpu
代码的方式,CPU 上使用 BF16 自动混合精度训练,将 use_ipex 和 bf16 参数添加到 TrainingArguments 中:
training_args = TrainingArguments(
output_dir=args.output_path,
bf16=True,
use_ipex=True,
use_cpu=True,
**kwargs
)
用于训练的定制硬件
1. GPU
当你训练更大的模型时,基本上有三种选择:
- 更大的 GPU
- 更多的 GPU
- 更多的 CPU 和 NVMe(通过 DeepSpeed-Infinity 实现)
2. 供电
高端消费者级 GPU 卡具有 2 个,有时甚至 3 个 PCI-E-8 针电源插口。请确保将与插口数量相同的独立 12V PCI-E-8 针线缆插入卡中。不要使用同一根线缆两端的 2 个分叉(也称为 pigtail cable)。
也就是说,如果您的 GPU 上有 2 个插口,您需要使用 2 条单独的 PCI-E-8 针线缆连接电源和显卡,而不是使用一条末端有 2 个 PCI-E-8 针连接器的线缆!否则,您无法充分发挥卡的性能。
每个 PCI-E-8 针电源线缆需要插入电源侧的 12V 轨上,并且可以提供最多 150W 的功率。如果可以使用 PCI-E-12 针连接器,可以提供最多 500-600W 的功率。低端卡可能使用 6 针连接器,可以提供最多 75W 的功率。
3. 散热
当 GPU 过热时,将开始降频,不会提供完整的性能。如果温度过高,可能会缩短 GPU 的使用寿命。
当 GPU 负载很重时,温度越低越好:
- 在 70-75 度之间最佳
- 尽量保持在 80 度以下
- 大约 84-90 度之间,GPU 开始降频
4. 多 GPU 连接
使用多个 GPU,则卡之间的互连方式可能会对总训练时间产生巨大影响。
如果 GPU 位于同一物理节点,可以运行如下代码查看连接方式:
nvidia-smi topo -m
在具有双 GPU 并通过 NVLink 连接的机器,可能看到如下内容(NV2 表示 GPU 通过 2 个 NVLink 互连):
GPU0 GPU1 CPU Affinity NUMA Affinity
GPU0 X NV2 0-23 N/A
GPU1 NV2 X 0-23 N/A
如果没有 NVLink,可能看到如下内容(PHB 表示 PCIe+Bridge 连接):
GPU0 GPU1 CPU Affinity NUMA Affinity
GPU0 X PHB 0-11 N/A
GPU1 PHB X 0-11 N/A
总之,NVLink 通信速度较快,PHB 通信速度较慢。如果 GPU 很少需要同步,就像在 DDP 中一样,那么较慢的连接的影响将不那么显著。如果 GPU 经常需要相互发送消息,就像在 FSDP 中一样,那么更快的连接对于实现更快的训练变得非常重要。
5. NVlink
NVLink 是由 Nvidia 开发的一种基于线缆的串行多通道近程通信链接。
在 nvidia-smi topo -m 输出的 NVX 报告中获取到的更高的 X 值意味着更好的性能。生成的结果将取决于 GPU 架构。
基准测试代码和输出样例:
硬件: 2x TITAN RTX 24GB each + NVlink with 2 NVLinks (NV2 in nvidia-smi topo -m)
软件: pytorch-1.8-to-be + cuda-11.0 / transformers==4.3.0.dev0
DDP w/ NVLink:
rm -r /tmp/test-clm; CUDA_VISIBLE_DEVICES=0,1 torchrun \
--nproc_per_node 2 examples/pytorch/language-modeling/run_clm.py --model_name_or_path openai-community/gpt2 \
--dataset_name wikitext --dataset_config_name wikitext-2-raw-v1 --do_train \
--output_dir /tmp/test-clm --per_device_train_batch_size 4 --max_steps 200
# {'train_runtime': 101.9003, 'train_samples_per_second': 1.963, 'epoch': 0.69}
DDP w/o NVLink:
rm -r /tmp/test-clm; CUDA_VISIBLE_DEVICES=0,1 NCCL_P2P_DISABLE=1 torchrun \
--nproc_per_node 2 examples/pytorch/language-modeling/run_clm.py --model_name_or_path openai-community/gpt2 \
--dataset_name wikitext --dataset_config_name wikitext-2-raw-v1 --do_train
--output_dir /tmp/test-clm --per_device_train_batch_size 4 --max_steps 200
# {'train_runtime': 131.4367, 'train_samples_per_second': 1.522, 'epoch': 0.69}
使用 Trainer API 进行超参数搜索
1. 超参数搜索后端
Trainer 目前支持四种超参数搜索后端:optuna、sigopt、raytune、wandb。
安装依赖:
pip install optuna/sigopt/wandb/ray[tune]
2. 启用超参数搜索
不同后端需要不同的格式:
a. sigopt
def sigopt_hp_space(trial):
return [
{"bounds": {"min": 1e-6, "max": 1e-4}, "name": "learning_rate", "type": "double"},
{
"categorical_values": ["16", "32", "64", "128"],
"name": "per_device_train_batch_size",
"type": "categorical",
},
]
b. optuna
def optuna_hp_space(trial):
return {
"learning_rate": trial.suggest_float("learning_rate", 1e-6, 1e-4, log=True),
"per_device_train_batch_size": trial.suggest_categorical("per_device_train_batch_size", [16, 32, 64, 128]),
}
optuna 提供了多目标 HPO,向 hyperparameter_search 中传递 direction 参数,定义自己的 compute_objective 返回多个目标值:
best_trials = trainer.hyperparameter_search(
direction=["minimize", "maximize"],
backend="optuna",
hp_space=optuna_hp_space,
n_trials=20,
compute_objective=compute_objective,
)
c. raytune
def ray_hp_space(trial):
return {
"learning_rate": tune.loguniform(1e-6, 1e-4),
"per_device_train_batch_size": tune.choice([16, 32, 64, 128]),
}
d. wandb
def wandb_hp_space(trial):
return {
"method": "random",
"metric": {"name": "objective", "goal": "minimize"},
"parameters": {
"learning_rate": {"distribution": "uniform", "min": 1e-6, "max": 1e-4},
"per_device_train_batch_size": {"values": [16, 32, 64, 128]},
},
}
e. 定义 model_init 用于初始化
def model_init(trial):
return AutoModelForSequenceClassification.from_pretrained(
model_args.model_name_or_path,
from_tf=bool(".ckpt" in model_args.model_name_or_path),
config=config,
cache_dir=model_args.cache_dir,
revision=model_args.model_revision,
use_auth_token=True if model_args.use_auth_token else None,
)
f. 创建 Trainer
trainer = Trainer(
model=None,
args=training_args,
train_dataset=small_train_dataset,
eval_dataset=small_eval_dataset,
compute_metrics=compute_metrics,
processing_class=tokenizer,
model_init=model_init,
data_collator=data_collator,
)
调用超参数搜索,获取最佳试验参数,后端可以是 "optuna" / "sigopt" / "wandb" / "ray"。方向可以是 "minimize" 或 "maximize",表示是否优化更大或更低的目标。
g. 将评估指标之和作为目标值返回
best_trial = trainer.hyperparameter_search(
direction="maximize",
backend="optuna",
hp_space=optuna_hp_space,
n_trials=20,
compute_objective=compute_objective,
)
3. 针对 DDP 微调的超参数搜索
Optuna 和 Sigopt 已启用针对 DDP 的超参数搜索。只有 rank-zero 进程会进行超参数搜索并将参数传递给其他进程。
实例化大模型
1. 启动分布式训练时的问题
使用一个非常大的预训练模型时,一个挑战是尽量减少对内存的使用。从 PyTorch 开始的实例化过程如下:
- 用随机权重创建你的模型
- 加载你的预训练权重
- 将这些预训练权重放入你的随机模型中
遇到的问题:
- 当模型达到几个 GB 大小,模型权重和预训练权重的副本会超出内存限制
- 如果使用
torch.distributed启动分布式训练,每个进程都会加载预训练模型,并将这两个副本存储在内存中
2. 分片 checkpoint
自 4.18.0 版本起,占用空间超过 10GB 的模型检查点将自动分成较小的片段。
在使用 model.save_pretrained(save_dir) 时,最终会得到几个部分 checkpoints(每个的大小都小于 10GB)以及一个索引,该索引将参数名称映射到存储它们的文件。
加载示例模型:
from transformers import AutoModel
model = AutoModel.from_pretrained("google-bert/bert-base-cased")
模型保存,得到新的文件夹,以及模型配置和模型权重文件:
import os
import tempfile
with tempfile.TemporaryDirectory() as tmp_dir:
model.save_pretrained(tmp_dir)
print(sorted(os.listdir(tmp_dir)))
# 输出:单个模型权重文件
# ['config.json', 'pytorch_model.bin']
使用 max_shard_size 参数来控制分片大小:
with tempfile.TemporaryDirectory() as tmp_dir:
model.save_pretrained(tmp_dir, max_shard_size="200MB")
print(sorted(os.listdir(tmp_dir)))
# 输出:多个分片文件
# ['config.json', 'pytorch_model-00001-of-00003.bin', 'pytorch_model-00002-of-00003.bin', 'pytorch_model-00003-of-00003.bin', 'pytorch_model.bin.index.json']
使用 from_pretrained() 方法加载分片文件:
with tempfile.TemporaryDirectory() as tmp_dir:
model.save_pretrained(tmp_dir, max_shard_size="200MB")
new_model = AutoModel.from_pretrained(tmp_dir)
查看索引文件,包含了模型的元数据和权重:
import json
with tempfile.TemporaryDirectory() as tmp_dir:
model.save_pretrained(tmp_dir, max_shard_size="200MB")
with open(os.path.join(tmp_dir, "pytorch_model.bin.index.json"), "r") as f:
index = json.load(f)
print(index.keys())
print(index["metadata"])
print(index["weight_map"])
# 输出:json文件的键、元数据、权重映射
# dict_keys(['metadata', 'weight_map'])
# {'total_size': 433245184}
# {'embeddings.LayerNorm.bias': 'pytorch_model-00001-of-00003.bin',
# 'embeddings.LayerNorm.weight': 'pytorch_model-00001-of-00003.bin',
# ...
或者使用 load_sharded_checkpoint() 方法加载分片后的 checkpoint:
from transformers.modeling_utils import load_sharded_checkpoint
with tempfile.TemporaryDirectory() as tmp_dir:
model.save_pretrained(tmp_dir, max_shard_size="200MB")
load_sharded_checkpoint(model, tmp_dir)
3. 低内存加载
使用 Accelerate 进行大模型加载,参考:Large model loading
使用 torch.compile() 优化推理
根据模型和 GPU 的不同,torch.compile() 在推理过程中可以提高多达 30% 的速度。要使用 torch.compile(),只需安装 2.0 及以上版本的 torch 即可。
调用 torch.compile(model) 编译模型:
from transformers import AutoModelForImageClassification
model = AutoModelForImageClassification.from_pretrained(MODEL_ID).to("cuda")
model = torch.compile(model, mode="default")
compile() 提供多种编译模式:
| 模式 | 触发指令 | 优化目标 | 适用场景 | 编译时间 | 显存占用 |
|---|---|---|---|---|---|
| default | mode="default" | 平衡编译开销与加速比 | 通用场景 | ⭐⭐ | ⭐⭐ |
| reduce-overhead | mode="reduce-overhead" | 最小化框架开销 | 小模型/小批量 | ⭐ | ⭐⭐⭐ |
| max-autotune | mode="max-autotune" | 极致性能优化 | 计算密集型大模型 | ⭐⭐⭐ | ⭐ |
主要类型
1. Callbacks
Callbacks 本质:用于自定义 PyTorch Trainer 训练循环行为的可插拔组件,通过只读方式访问训练状态并控制训练流程(如提前停止),但不能直接修改训练逻辑。
核心特性:
- 只读访问:可查看训练状态(
TrainerState),但不能修改训练逻辑 - 流程控制:通过返回
TrainerControl对象影响训练流程 - 事件驱动:在训练循环关键节点触发回调
- 模块化:支持多回调组合,互不干扰
TrainerCallback 事件接口
| 事件方法 | 触发时机 | 适用场景 | 关键参数作用 |
|---|---|---|---|
on_init_end | Trainer 初始化完成后 | 环境检查/资源分配 | args: 训练配置, state: 训练状态, control: 流程控制 |
on_train_begin | 训练循环开始时 | 初始化自定义指标 | args, state, control |
on_epoch_begin | 每个 epoch 开始时 | 动态调整学习率/数据采样 | args, state, control |
on_step_begin | 每个优化步骤开始前 | 梯度裁剪/输入预处理 | args, state, control |
on_step_end | 每个优化步骤完成后 | 梯度监控/自定义日志 | args, state, control |
on_substep_end | 梯度累积子步骤完成 | 自定义梯度累积逻辑 | args, state, control |
on_optimizer_step | 优化器更新后 | 梯度分析/权重监控 | optimizer: 当前优化器实例 |
on_epoch_end | 每个 epoch 结束时 | 模型验证/检查点保存 | args, state, control |
on_evaluate | 评估阶段 | 自定义评估指标 | metrics: 评估指标字典 |
on_log | 日志记录后 | 日志增强/第三方集成 | logs: 待记录日志字典 |
on_save | 保存检查点后 | 模型压缩/云存储同步 | args, state, control |
on_train_end | 训练完全结束时 | 资源释放/模型导出 | args, state, control |
接口调用样例:
- 环境初始化检查
class EnvCheckCallback(TrainerCallback):
def on_init_end(self, args, state, control, **kwargs):
if not torch.cuda.is_available():
print("警告: 未检测到GPU,训练性能将受限")
- 训练开始通知
class TrainingStartCallback(TrainerCallback):
def on_train_begin(self, args, state, control, **kwargs):
slack_notify(f"训练启动: 模型 {args.model_name}")
- 动态学习率调整
class DynamicLRCallback(TrainerCallback):
def on_epoch_begin(self, args, state, control, **kwargs):
if state.epoch > 5:
for pg in state.optimizer.param_groups:
pg['lr'] *= 0.95 # 5轮后每轮衰减5%
- 梯度裁剪
class GradientClipCallback(TrainerCallback):
def on_step_begin(self, args, state, control, **kwargs):
torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
- 梯度监控
class GradMonitorCallback(TrainerCallback):
def on_step_end(self, args, state, control, **kwargs):
if state.global_step % 100 == 0:
grads = [p.grad.norm() for p in model.parameters()]
print(f"Step {state.global_step} | 梯度均值: {np.mean(grads):.4f}")
- 梯度累积控制
class AccumulationCallback(TrainerCallback):
def on_substep_end(self, args, state, control, **kwargs):
if state.gradient_step == args.grad_accum_steps // 2:
print("50%梯度累积完成")
- 权重监控
class WeightMonitorCallback(TrainerCallback):
def on_optimizer_step(self, args, state, control, **kwargs):
weights = [p.data.mean() for p in model.parameters()]
wandb.log({"weights/mean": np.mean(weights)})
- 自动保存最佳模型
class BestModelSaver(TrainerCallback):
def on_epoch_end(self, args, state, control, **kwargs):
if state.metrics['eval_acc'] > state.best_metric:
torch.save(model.state_dict(), "best_model.pt")
control.should_save = True # 触发官方保存
- 自定义评估指标
class F1ScoreCallback(TrainerCallback):
def on_evaluate(self, args, state, control, metrics, **kwargs):
predictions, labels = gather_predictions()
metrics["eval_f1"] = calculate_f1(predictions, labels)
- 日志增强
class MemoryLogger(TrainerCallback):
def on_log(self, args, state, control, logs, **kwargs):
logs["memory_usage"] = torch.cuda.memory_allocated() / 1e9
- 检查点云同步
class CloudSyncCallback(TrainerCallback):
def on_save(self, args, state, control, **kwargs):
upload_to_s3(f"{args.output_dir}/checkpoint-{state.global_step}")
- 训练完成处理
class CleanupCallback(TrainerCallback):
def on_train_end(self, args, state, control, **kwargs):
compress_folder(args.output_dir)
send_email("训练完成通知")
内置 Callbacks 功能对照
| Callback 类 | 核心用途 | 关键配置参数 | 适用场景 |
|---|---|---|---|
EarlyStoppingCallback | 验证损失无改善时停止训练 | early_stopping_patience: 容忍轮次, early_stopping_threshold: 最小改善阈值 | 防止过拟合/资源优化 |
TensorBoardCallback | 记录指标到 TensorBoard | tb_writer: SummaryWriter 实例 | 训练可视化/性能分析 |
WandbCallback | 集成 Weights & Biases | wandb_project: 项目名, wandb_run_name: 实验名 | 实验追踪/团队协作 |
MLflowCallback | 集成 MLflow 实验管理 | MLFLOW_EXPERIMENT_NAME: 实验名, MLFLOW_TAGS: 标签字典 | 企业级模型管理 |
CodeCarbonCallback | 跟踪训练碳排放量 | measure_power_secs: 功耗测量间隔 | 绿色 AI/能效优化 |
ProgressCallback | 显示训练进度条 | max_str_len: 日志截断长度 | 交互式训练监控 |
DefaultFlowCallback | 处理默认日志/保存/评估 | 无 | 基础训练流程管理 |
使用技巧
i. 多回调组合:
trainer = Trainer(
callbacks=[EarlyStoppingCallback(patience=3),
WandbCallback(project="exp1"),
CustomMetricsCallback()]
)
ii. 动态流程控制:
def on_step_end(self, args, state, control, **kwargs):
if state.global_step > 1000 and loss > 10:
control.should_training_stop = True # 异常终止
iii. 状态访问:
def on_epoch_end(self, args, state, control, **kwargs):
print(f"Epoch {state.epoch} | LR: {state.optimizer.param_groups[0]['lr']}")
2. Configuration
PretrainedConfig 本质:Transformers 库中所有模型配置的基类,用于管理模型的结构参数和训练设置,支持从本地/Hugging Face Hub 加载、保存和共享配置。
核心特性:
- 统一配置管理:标准化处理模型超参数
- 跨框架兼容:支持 PyTorch/TensorFlow 的专用参数
- 序列化能力:支持 JSON 格式的保存/加载
- Hub 集成:直接推送/拉取云端配置
PretrainedConfig 关键属性
| 属性类别 | 属性名称 | 数据类型 | 作用 | 适用场景 |
|---|---|---|---|---|
| 通用架构 | hidden_size | int | 隐藏层维度 | 所有 Transformer 模型 |
num_attention_heads | int | 注意力头数 | 多头注意力机制 | |
num_hidden_layers | int | 隐藏层数量 | 模型深度控制 | |
| 文本模型 | vocab_size | int | 词表大小 | NLP 模型 |
max_position_embeddings | int | 最大序列长度 | 位置编码 | |
| 输出控制 | output_hidden_states | bool | 是否输出所有隐藏状态 | 特征提取任务 |
output_attentions | bool | 是否输出注意力权重 | 可解释性分析 | |
| 任务适配 | num_labels | int | 分类标签数 | 分类任务微调 |
id2label | Dict[int, str] | ID 到标签映射 | 分类头配置 | |
problem_type | str | 问题类型(回归/分类) | 自动适配损失函数 | |
| 分词器关联 | bos_token_id | int | 起始符 ID | 文本生成 |
eos_token_id | int | 结束符 ID | 文本生成控制 | |
pad_token_id | int | 填充符 ID | 批量处理 |
PretrainedConfig 核心 API
| 方法名称 | 用途 | 关键参数 | 参数作用 |
|---|---|---|---|
from_pretrained | 加载预训练配置 | pretrained_model_name_or_path: 模型 ID/本地路径 | 初始化模型 |
cache_dir: 自定义缓存目录 | cache_dir="./model_cache" | ||
revision: Git 分支/标签 | revision="v2.0" | ||
save_pretrained | 保存配置 | save_directory: 保存路径 | 本地存储配置 |
push_to_hub: 是否推送至 Hub | push_to_hub=True | ||
push_to_hub | 推送至 Hub | repo_id: 仓库 ID | 共享配置 |
private: 是否私有仓库 | private=True | ||
to_dict | 转为字典 | 无 | 内存操作配置 |
from_dict | 从字典创建 | config_dict: 配置字典 | 动态配置 |
to_json_string | 转为 JSON | use_diff: 是否仅输出差异 | 配置传输 |
from_json_file | 从 JSON 加载 | json_file: JSON 文件路径 | 本地加载 |
update | 更新配置 | config_dict: 更新参数字典 | 动态修改 |
register_for_auto_class | 注册自动类 | auto_class: 自动类名 | 自定义模型 |
配置使用示例
- 基础加载与保存
from transformers import BertConfig
# 从Hub加载配置
config = BertConfig.from_pretrained("bert-base-uncased")
# 修改配置
config.num_hidden_layers = 8
config.hidden_size = 512
# 本地保存
config.save_pretrained("./custom_bert")
# 推送到Hub
config.push_to_hub("my-org/custom-bert", private=True)
- 动态创建配置
from transformers import PretrainedConfig
# 从字典创建
custom_config = PretrainedConfig.from_dict({
"vocab_size": 32000,
"hidden_size": 1024,
"num_attention_heads": 16
})
# 更新配置
custom_config.update({"num_hidden_layers": 24})
- 任务适配配置
from transformers import AutoConfig
# 分类任务配置
config = AutoConfig.from_pretrained("roberta-base")
config.update({
"num_labels": 5,
"id2label": {0: "体育", 1: "科技", 2: "政治", 3: "娱乐", 4: "经济"},
"problem_type": "single_label_classification"
})
最佳实践建议
- 配置继承:自定义配置应继承
PretrainedConfig
class MyModelConfig(PretrainedConfig):
model_type = "mymodel"
def __init__(self, custom_param=128, **kwargs):
self.custom_param = custom_param
super().__init__(**kwargs)
- 云配置管理:团队协作时使用 Hub 存储配置
# 推送配置
config.push_to_hub("team-project/model-v1")
# 其他成员加载
remote_config = AutoConfig.from_pretrained("team-project/model-v1")
- 配置版本控制:结合
revision参数管理迭代
# 加载特定版本
config_v2 = AutoConfig.from_pretrained(
"my-model",
revision="v2.0",
num_labels=10 # 覆盖原配置
)
Data Collator
Data Collators 用于将数据集元素(如文本、标签)组合成批次,支持预处理(如填充)和数据增强(如随机掩码)。
1. DefaultDataCollator
| 属性 | 说明 |
|---|---|
| 名称 | DefaultDataCollator / transformers.default_data_collator |
| 用途 | 基础数据整理器,仅合并字典类对象,不进行额外预处理 |
| 场景 | 通用任务(如 GLUE、NER),输入数据已预处理,只需简单批次合并 |
| 参数 | return_tensors:返回张量类型("pt" / "np" / "tf"),默认为 PyTorch |
使用样例:
collator = DefaultDataCollator(return_tensors="pt")
2. DataCollatorWithPadding
| 属性 | 说明 |
|---|---|
| 名称 | DataCollatorWithPadding |
| 用途 | 动态填充输入序列至批次内最大长度 |
| 场景 | 需处理变长序列的任务(如文本分类) |
| 参数 | tokenizer: 分词器, padding: 填充策略(True / 'longest' / 'max_length'), max_length: 最大填充长度, pad_to_multiple_of: 填充至该值的倍数, return_tensors: 返回张量类型 |
使用样例:
collator = DataCollatorWithPadding(tokenizer, padding='max_length', max_length=128)
3. DataCollatorForTokenClassification
| 属性 | 说明 |
|---|---|
| 名称 | DataCollatorForTokenClassification |
| 用途 | 动态填充输入序列和标签,支持标签掩码 |
| 场景 | 序列标注任务(如命名实体识别) |
| 参数 | 同 DataCollatorWithPadding,新增 label_pad_token_id: 标签填充 ID(默认为 -100,被 PyTorch 忽略) |
使用样例:
collator = DataCollatorForTokenClassification(tokenizer, label_pad_token_id=-100)
4. DataCollatorForSeq2Seq
| 属性 | 说明 |
|---|---|
| 名称 | DataCollatorForSeq2Seq |
| 用途 | 动态填充输入序列和标签,支持序列到序列任务 |
| 场景 | 机器翻译、文本生成等 Seq2Seq 任务 |
| 参数 | 同 DataCollatorForTokenClassification,新增 model: 用于生成 decoder_input_ids 的模型 |
使用样例:
collator = DataCollatorForSeq2Seq(tokenizer, model=model)
5. DataCollatorForLanguageModeling
| 属性 | 说明 |
|---|---|
| 名称 | DataCollatorForLanguageModeling |
| 用途 | 动态填充输入,并应用掩码语言建模(MLM)增强 |
| 场景 | BERT 等掩码语言模型预训练 |
| 参数 | tokenizer: 分词器, mlm: 是否启用 MLM, mlm_probability: 掩码概率, mask_replace_prob: 掩码替换概率(默认 0.8), random_replace_prob: 随机替换概率(默认 0.1), return_tensors: 返回张量类型 |
使用样例:
collator = DataCollatorForLanguageModeling(tokenizer, mlm_probability=0.15)
掩码行为:
- 80% 替换为
[MASK] - 10% 替换为随机词
- 10% 保持原词
6. DataCollatorForWholeWordMask
| 属性 | 说明 |
|---|---|
| 名称 | DataCollatorForWholeWordMask |
| 用途 | 对整个单词进行掩码(而非子词),增强语言模型训练 |
| 场景 | 需整词掩码的任务(如 BERT 整词掩码策略) |
| 参数 | 同 DataCollatorForLanguageModeling |
使用样例:
collator = DataCollatorForWholeWordMask(tokenizer)
7. DataCollatorForPermutationLanguageModeling
| 属性 | 说明 |
|---|---|
| 名称 | DataCollatorForPermutationLanguageModeling |
| 用途 | 生成排列语言建模(PLM)所需的掩码序列(XLNet 专用) |
| 场景 | XLNet 等排列语言模型预训练 |
| 参数 | tokenizer: 分词器, plm_probability: 排列掩码概率(默认 1/6), max_span_length: 最大掩码跨度长度(默认 5) |
使用样例:
collator = DataCollatorForPermutationLanguageModeling(tokenizer)
掩码生成逻辑:
- 从序列开头开始,设置当前长度
cur_len=0 - 采样掩码跨度长度
span_length ∈ [1, max_span_length] - 计算上下文长度
context_length = span_length / plm_probability - 在
[cur_len, cur_len + context_length - span_length]内采样起始位置并掩码 - 更新
cur_len += context_length,重复直到覆盖整个序列
关键点总结
- 基础整理器:
DefaultDataCollator(无预处理)和DataCollatorWithPadding(动态填充) - 任务专用:序列标注(
TokenClassification)、Seq2Seq、语言建模(LanguageModeling) - 掩码策略:
- 随机子词掩码(
LanguageModeling) - 整词掩码(
WholeWordMask) - 排列掩码(
PermutationLanguageModeling,XLNet 专用)
- 随机子词掩码(
Keras Callbacks
在 Keras 中训练 Transformers 模型时,可以使用以下库特定的回调函数自动执行常见任务。
1. KerasMetricCallback
| 属性 | 说明 |
|---|---|
| 名称 | KerasMetricCallback |
| 用途 | 在每轮(epoch)结束时计算自定义指标(如 BLEU、ROUGE 等复杂指标) |
| 场景 | NLP 生成任务(文本摘要、翻译等)需要字符串操作或生成循环的指标计算 |
| 参数 | metric_fn: 自定义指标函数,接收 predictions 和 labels 返回指标字典;eval_dataset: 验证数据集;predict_with_generate: 是否用 model.generate() 生成输出(生成任务设为 True);use_xla_generation: 是否用 XLA 加速生成(提升 100x 速度,需固定输入形状);generate_kwargs: 传递给 model.generate() 的参数 |
使用样例:
callback = KerasMetricCallback(
metric_fn=rouge_fn,
eval_dataset=val_data,
predict_with_generate=True
)
model.fit(..., callbacks=[callback])
指标函数示例(ROUGE):
def rouge_fn(predictions, labels):
decoded_preds = tokenizer.batch_decode(predictions, skip_special_tokens=True)
decoded_labels = tokenizer.batch_decode(labels, skip_special_tokens=True)
result = rouge_metric.compute(predictions=decoded_preds, references=decoded_labels)
return {k: v.mid.fmeasure * 100 for k, v in result.items()} # 返回格式: {'rouge1': 37.41}
2. PushToHubCallback
| 属性 | 说明 |
|---|---|
| 名称 | PushToHubCallback |
| 用途 | 定期将模型和分词器自动保存并推送到 Hugging Face Hub |
| 场景 | 训练过程中持续保存/共享模型到 Hub |
| 参数 | output_dir: 本地保存路径;save_strategy: 保存策略("epoch" / "steps" / "no");save_steps: 按步保存时的步数间隔;tokenizer: 需上传的分词器;hub_model_id: Hub 模型 ID(如 "user_name/model");checkpoint: 是否保存完整检查点(含优化器状态) |
使用样例:
callback = PushToHubCallback(
output_dir="./gpt5-model",
tokenizer=tokenizer,
hub_model_id="gpt5-7xlarge",
save_strategy="epoch"
)
model.fit(..., callbacks=[callback])
关键参数说明:
save_strategy:"epoch":每轮结束保存(默认)"steps":每 N 步保存(需配合save_steps)"no":仅训练结束保存
checkpoint=True:保存完整检查点(可恢复训练)
核心功能对比
| 回调函数 | 核心能力 | 典型使用场景 |
|---|---|---|
KerasMetricCallback | 计算非 TensorFlow 原生支持的复杂指标 | 文本生成任务的质量评估(ROUGE/BLEU) |
PushToHubCallback | 自动化模型版本管理与共享 | 持续训练并发布模型到 Hub |
Logging
Transformers 提供集中式日志系统,支持自定义日志详细程度、进度条控制等。
1. 日志级别设置函数
| 名称 | 用途 | 场景 | 参数 |
|---|---|---|---|
set_verbosity_error() | 设置日志级别为 ERROR (40) | 仅需查看错误信息 | 无 |
set_verbosity_warning() | 设置日志级别为 WARNING (30) | 默认级别,显示错误和警告 | 无 |
set_verbosity_info() | 设置日志级别为 INFO (20) | 查看基础训练信息 | 无 |
set_verbosity_debug() | 设置日志级别为 DEBUG (10) | 调试时查看全部信息 | 无 |
set_verbosity(verbosity) | 自定义日志级别 | 精确控制日志输出 | verbosity: 整数日志级别(10/20/30/40/50) |
使用样例:
| 函数 | 样例 |
|---|---|
set_verbosity_error | transformers.logging.set_verbosity_error() |
set_verbosity_warning | transformers.logging.set_verbosity_warning() |
set_verbosity_info | transformers.logging.set_verbosity_info() |
set_verbosity_debug | transformers.logging.set_verbosity_debug() |
set_verbosity | transformers.logging.set_verbosity(20) |
日志级别对照:
| 级别 | 整数值 | 说明 |
|---|---|---|
| CRITICAL/FATAL | 50 | 仅关键错误 |
| ERROR | 40 | 仅错误 |
| WARNING/WARN | 30 | 错误 + 警告(默认级别) |
| INFO | 20 | 基础信息 + 错误/警告 |
| DEBUG | 10 | 全部信息 |
2. 日志控制函数
| 名称 | 用途 | 场景 | 参数 |
|---|---|---|---|
get_verbosity() | 获取当前日志级别 | 检查系统状态 | 无 |
get_logger(name) | 获取指定名称的日志记录器 | 自定义模块集成日志系统 | name: 日志器名称(如 "transformers") |
enable_default_handler() | 启用根日志器的默认处理器 | 恢复默认日志输出 | 无 |
disable_default_handler() | 禁用根日志器的默认处理器 | 临时关闭日志输出 | 无 |
enable_explicit_format() | 启用显式格式化([LEVEL FILE LINE] TIME >> MSG) | 需要详细日志来源信息 | 无 |
reset_format() | 重置日志格式为默认 | 恢复简洁日志格式 | 无 |
enable_progress_bar() | 启用 tqdm 进度条 | 显示模型下载/训练进度 | 无 |
disable_progress_bar() | 禁用 tqdm 进度条 | 无干扰日志输出 | 无 |
captureWarnings(capture) | 将 warnings 捕获到日志系统 | 统一管理警告信息 | capture: 是否捕获(True/False) |
使用样例:
| 函数 | 样例 |
|---|---|
get_verbosity | level = transformers.logging.get_verbosity() |
get_logger | logger = logging.get_logger("my_module") |
enable_default_handler | logging.enable_default_handler() |
disable_default_handler | logging.disable_default_handler() |
enable_explicit_format | logging.enable_explicit_format() |
reset_format | logging.reset_format() |
enable_progress_bar | logging.enable_progress_bar() |
disable_progress_bar | logging.disable_progress_bar() |
captureWarnings | logging.captureWarnings(True) |
3. 环境变量控制
| 变量名 | 用途 | 值示例 | 效果 |
|---|---|---|---|
TRANSFORMERS_VERBOSITY | 覆盖默认日志级别 | error, info, debug | TRANSFORMERS_VERBOSITY=error ./main.py |
TRANSFORMERS_NO_ADVISORY_WARNINGS | 禁用建议类警告(如弃用警告) | 1 (true) | TRANSFORMERS_NO_ADVISORY_WARNINGS=1 ./main.py |
使用场景
- 自定义日志输出:
from transformers.utils import logging
# 设置INFO级别日志 + 显式格式
logging.set_verbosity_info()
logging.enable_explicit_format()
# 获取日志器并记录
logger = logging.get_logger("transformers")
logger.info("Training started")
- 禁用进度条:
logging.disable_progress_bar() # 静默下载模型
model = AutoModel.from_pretrained("bert-base-uncased")
- 捕获警告到日志:
logging.captureWarnings(True) # 将DeprecationWarning等转为日志
- 环境变量全局控制:
# 仅显示错误 + 禁用建议警告
TRANSFORMERS_VERBOSITY=error \
TRANSFORMERS_NO_ADVISORY_WARNINGS=1 \
python train.py
模型
1. 模型基类与通用方法
PyTorch (PreTrainedModel)
| 接口名称 | 用途 | 场景 | 关键参数 |
|---|---|---|---|
from_pretrained | 加载预训练模型 | 初始化模型 | pretrained_model_name_or_path: 模型 ID/路径;device_map="auto": 自动设备分配;torch_dtype: 数据类型(如 torch.float16);ignore_mismatched_sizes: 忽略尺寸不匹配 |
save_pretrained | 保存模型 | 模型持久化 | save_directory: 保存路径;safe_serialization=True: 使用 safetensors 格式;max_shard_size="5GB": 分片大小 |
push_to_hub | 推送模型到 Hugging Face Hub | 模型共享 | repo_id: 仓库 ID;private=True: 设为私有;token: 访问令牌 |
resize_token_embeddings | 调整词嵌入大小 | 增加新词汇 | new_num_tokens: 新词表大小;pad_to_multiple_of=128: 填充至 128 的倍数 |
gradient_checkpointing_enable | 激活梯度检查点 | 减少训练显存 | 无 |
to_bettertransformer | 转换为优化版 Transformer | 加速推理 | 无 |
使用样例:
| 接口 | 样例 |
|---|---|
from_pretrained | model = BertModel.from_pretrained("bert-base-uncased", device_map="auto") |
save_pretrained | model.save_pretrained("./model", safe_serialization=True) |
push_to_hub | model.push_to_hub("my-bert-model") |
resize_token_embeddings | model.resize_token_embeddings(32000) |
gradient_checkpointing_enable | model.gradient_checkpointing_enable() |
to_bettertransformer | model = model.to_bettertransformer() |
TensorFlow (TFPreTrainedModel)
| 接口名称 | 用途 | 关键差异点 | 样例 |
|---|---|---|---|
from_pretrained | 加载预训练模型 | 支持 from_pt=True 加载 PyTorch 权重 | model = TFBertModel.from_pretrained("bert-base-uncased", from_pt=True) |
compile | 编译模型 | Keras 特有方法 | model.compile(optimizer='adam', loss='sparse_categorical_crossentropy') |
Flax/JAX (FlaxPreTrainedModel)
| 接口名称 | 用途 | 关键特性 | 样例 |
|---|---|---|---|
from_pretrained | 加载预训练模型 | 支持 dtype=jnp.bfloat16 | model = FlaxBertModel.from_pretrained("bert-base-uncased", dtype=jnp.bfloat16) |
to_bf16/to_fp16 | 转换参数精度 | 半精度训练支持 | model.params = model.to_bf16(model.params) |
2. 模型工具类
PyTorch (ModuleUtilsMixin)
| 接口名称 | 用途 | 场景 | 参数 | 样例 |
|---|---|---|---|---|
num_parameters | 计算参数量 | 模型分析 | only_trainable=True: 仅统计可训练参数;exclude_embeddings=True: 排除嵌入层 | num_params = model.num_parameters() |
get_extended_attention_mask | 生成扩展注意力掩码 | 处理因果掩码 | attention_mask: 原始掩码;input_shape: 输入形状 | mask = model.get_extended_attention_mask(attn_mask, input_shape) |
TensorFlow (TFModelUtilsMixin)
| 接口名称 | 用途 | 样例 |
|---|---|---|
num_parameters | 计算参数量 | num_params = model.num_parameters(only_trainable=True) |
3. 大模型加载技巧 (PyTorch)
| 技术 | 参数/方法 | 效果 | 使用场景 |
|---|---|---|---|
| 设备映射 | device_map="auto" | 自动分配层到 GPU/CPU/磁盘 | 超大模型推理 |
| 自动 dtype | torch_dtype="auto" | 自动匹配权重数据类型 | 节省显存 |
| 分片加载 | max_shard_size="5GB" | 避免内存溢出 | >10B 参数模型 |
| 量化加载 | load_in_4bit=True | 4 位量化 | 低显存设备推理 |
大模型加载示例 (15B+ 参数):
model = AutoModelForSeq2SeqLM.from_pretrained(
"bigscience/T0pp",
device_map="auto", # 自动分配设备
torch_dtype="auto", # 自动推断数据类型
load_in_4bit=True, # 4位量化
max_shard_size="10GB" # 分片加载
)
4. 分片检查点工具
| 接口名称 | 用途 | 场景 | 参数 |
|---|---|---|---|
load_sharded_checkpoint | 加载分片检查点 | 超大模型加载 | folder: 分片目录;prefer_safe=True: 优先 safetensors 格式 |
save_pretrained | 分片保存模型 | 保存超大模型 | max_shard_size="5GB": 分片大小 |
# 分片保存与加载
model.save_pretrained("./big_model", max_shard_size="5GB")
loaded_model = load_sharded_checkpoint(model, "./big_model")
关键特性对比
| 功能 | PyTorch | TensorFlow | Flax/JAX |
|---|---|---|---|
设备映射 (device_map) | ✅ | ❌ | ❌ |
| 半精度自动转换 | ✅ (torch_dtype="auto") | ❌ | ✅ (dtype=jnp.bfloat16) |
| 梯度检查点 | ✅ | ✅ | ✅ |
| 分片加载/保存 | ✅ | ✅ | ✅ |
| 量化支持 (4/8 bit) | ✅ | ❌ | ❌ |
典型工作流示例
# PyTorch 完整流程
from transformers import BertModel
# 1. 加载模型 (自动设备分配 + 半精度)
model = BertModel.from_pretrained(
"bert-base-uncased",
device_map="auto",
torch_dtype=torch.float16
)
# 2. 训练配置
model.gradient_checkpointing_enable() # 激活梯度检查点
model.train() # 训练模式
# 3. 保存与共享
model.save_pretrained("./my_bert", safe_serialization=True)
model.push_to_hub("my-bert-finetuned")
文本生成
1. GenerationConfig 配置类
控制生成行为的参数集合,可通过 JSON 保存/加载。
| 参数类别 | 关键参数 | 作用 | 典型值 |
|---|---|---|---|
| 长度控制 | max_length、max_new_tokens | 控制生成的最大长度 | max_new_tokens=100 |
| 解码策略 | do_sample、num_beams、penalty_alpha | 选择贪婪/采样/束搜索/对比搜索等策略 | do_sample=True, num_beams=4 |
| 采样控制 | temperature、top_k、top_p | 调整采样随机性 | temperature=0.7, top_p=0.9 |
| 重复惩罚 | repetition_penalty、no_repeat_ngram_size | 减少重复生成 | repetition_penalty=1.2 |
| 日志处理 | bad_words_ids、force_words_ids | 禁止或强制某些词生成 | bad_words_ids=[[暴力词ID]] |
| 辅助生成 | assistant_model、num_assistant_tokens | 使用草稿模型加速生成 | num_assistant_tokens=5 |
| 输出控制 | num_return_sequences、output_scores | 返回序列数量和分数 | num_return_sequences=3 |
主要方法:
| 方法 | 用途 | 样例 |
|---|---|---|
from_pretrained() | 从 Hub 加载配置 | config = GenerationConfig.from_pretrained("gpt2") |
save_pretrained() | 保存配置到本地 | config.save_pretrained("./my_config") |
2. 生成方法 (generate)
各框架统一接口,支持多种解码策略。
PyTorch (GenerationMixin.generate):
outputs = model.generate(
inputs,
generation_config=config,
do_sample=True,
num_beams=4,
max_new_tokens=50
)
TensorFlow (TFGenerationMixin.generate):
outputs = model.generate(
inputs,
do_sample=True,
temperature=0.8,
num_return_sequences=2
)
Flax/JAX (FlaxGenerationMixin.generate):
outputs = model.generate(
input_ids,
prng_key=jax.random.PRNGKey(0),
max_length=100
)
通用参数:
| 参数 | 作用 | 特殊场景 |
|---|---|---|
generation_config | 预定义的配置对象 | 复用配置 |
logits_processor | 自定义 logit 处理逻辑 | 高级控制采样 |
stopping_criteria | 自定义停止条件 | 特殊停止规则 |
assistant_model | 加速生成的草稿模型 | 大模型加速 |
streamer | 流式输出处理器 | 实时显示生成结果 |
3. 分数计算工具
计算生成序列的转移分数(token 级概率)。
PyTorch (compute_transition_scores):
# 生成时返回分数
outputs = model.generate(..., output_scores=True)
# 计算转移分数
scores = model.compute_transition_scores(
outputs.sequences,
outputs.scores,
normalize_logits=True
)
TensorFlow (compute_transition_scores):
scores = model.compute_transition_scores(
sequences,
scores_tuple,
beam_indices=beam_indices
)
参数说明:
| 参数 | 作用 | 注意 |
|---|---|---|
sequences | 生成的序列 | shape: (batch_size, seq_length) |
scores | 生成过程中的分数元组 | 每个元素对应一个生成步的 logits |
beam_indices | 束搜索的索引(束搜索时必需) | shape: (batch_size*num_beams, seq_len) |
normalize_logits | 是否归一化 logits | 建议设为 True |
4. 解码策略对照表
| 策略 | 启用条件 | 适用场景 |
|---|---|---|
| 贪婪解码 | num_beams=1, do_sample=False | 确定性输出 |
| 对比搜索 | penalty_alpha>0, top_k>1 | 高质量长文本 |
| 采样生成 | num_beams=1, do_sample=True | 创造性文本 |
| 束搜索 | num_beams>1, do_sample=False | 精确性任务(翻译等) |
| 束搜索采样 | num_beams>1, do_sample=True | 多样性与精确性平衡 |
| 辅助生成 | assistant_model 非空 | 加速大模型推理 |
| DoLa 解码 | dola_layers 指定层 | 分层推理优化 |
典型工作流
from transformers import AutoModelForCausalLM, GenerationConfig
# 1. 加载模型
model = AutoModelForCausalLM.from_pretrained("gpt2")
# 2. 配置生成参数
config = GenerationConfig.from_pretrained("gpt2")
config.update(
max_new_tokens=100,
do_sample=True,
top_k=50,
temperature=0.7
)
# 3. 生成文本
inputs = tokenizer("The future of AI is", return_tensors="pt")
outputs = model.generate(**inputs, generation_config=config)
# 4. 解码输出
print(tokenizer.decode(outputs[0]))
关键特性
- 统一接口:PyTorch/TensorFlow/Flax 保持相同参数名
- 策略丰富:支持 7+ 解码策略
- 精细控制:提供 token 级概率分析工具
- 性能优化:辅助生成加速推理 2-3 倍
- 配置持久化:通过
GenerationConfig保存/加载配置
ONNX
1. ONNX 配置抽象类
定义模型导出到 ONNX 的元数据和结构。
| 类名 | 继承模型类型 | 核心方法 | 用途 | 参数说明 |
|---|---|---|---|---|
OnnxConfig | 编码器模型(如 BERT) | generate_dummy_inputs()、use_external_data_format() | 基础配置 | config: 模型配置;task: 任务类型(如 'default') |
OnnxConfigWithPast | 解码器模型(如 GPT) | with_past()、fill_with_past_key_values_() | 处理 past_key_values | use_past=True: 启用 KV 缓存 |
OnnxSeq2SeqConfigWithPast | 编码器-解码器模型(如 T5) | 同 OnnxConfigWithPast | Seq2Seq 结构支持 | 额外处理编码器-解码器交互 |
关键方法说明:
generate_dummy_inputs(): 生成用于导出的虚拟输入
dummy_inputs = config.generate_dummy_inputs(
tokenizer,
batch_size=1,
seq_length=128
)
use_external_data_format(): 检查是否需要外部数据格式(>2GB 模型)
if config.use_external_data_format(num_parameters=100e6):
# 处理大模型
2. ONNX 特性管理器 (FeaturesManager)
管理不同模型架构的 ONNX 导出支持。
| 方法名 | 用途 | 参数 | 返回 | 使用场景 |
|---|---|---|---|---|
get_config(model_type, feature) | 获取模型类型的 ONNX 配置 | model_type: 模型类型(如 'bert');feature: 特性名(如 'default') | OnnxConfig 实例 | 初始化导出配置 |
get_supported_features_for_model_type() | 获取模型支持的特性列表 | model_type: 模型类型 | 特性名字典 | 检查导出兼容性 |
check_supported_model_or_raise() | 验证模型是否支持导出特性 | model: 模型实例;feature: 特性名 | 无(异常验证) | 导出前预检查 |
get_model_from_feature() | 通过特性名加载模型 | feature: 特性名;model: 模型名;framework: 框架 | 模型实例 | 动态加载兼容模型 |
特性列表示例:
from transformers.onnx import FeaturesManager
# 获取 BERT 支持的特性
features = FeaturesManager.get_supported_features_for_model_type("bert")
print(features) # 输出: {'default', 'masked-lm', 'sequence-classification'}
3. 导出工作流
步骤 1:获取配置
from transformers.onnx import FeaturesManager
# 获取模型类型的 ONNX 配置
model_type = "gpt2"
feature = "causal-lm"
onnx_config = FeaturesManager.get_config(model_type, feature)
步骤 2:生成虚拟输入
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("gpt2")
dummy_inputs = onnx_config.generate_dummy_inputs(tokenizer, batch_size=1, seq_length=128)
步骤 3:执行导出
from pathlib import Path
from transformers.onnx import export
output_path = Path("model.onnx")
export(
pretrained_model="gpt2",
onnx_config=onnx_config,
output=output_path,
dummy_inputs=dummy_inputs
)
大模型特殊处理:
if onnx_config.use_external_data_format(model.num_parameters()):
export(..., use_external_data_format=True) # 分割权重文件
4. 高级场景支持
带 KV 缓存的解码器:
# 启用 past_key_values 支持
onnx_config = OnnxConfigWithPast.with_past(config, task="causal-lm")
# 生成带缓存的虚拟输入
dummy_inputs = onnx_config.generate_dummy_inputs(
tokenizer,
batch_size=1,
seq_length=128,
past_seq_length=64 # 历史长度
)
Seq2Seq 模型导出:
from transformers.onnx import OnnxSeq2SeqConfigWithPast
# 初始化 T5 配置
onnx_config = OnnxSeq2SeqConfigWithPast(config, task="seq2seq-lm")
5. 特性对照表
| 模型类型 | ONNX 特性名 | 适用任务 | 对应配置类 |
|---|---|---|---|
| BERT/RoBERTa | default | 基础编码器 | OnnxConfig |
masked-lm | 掩码语言建模 | OnnxConfig | |
| GPT/LLaMA | causal-lm | 因果语言建模 | OnnxConfigWithPast |
| T5/BART | seq2seq-lm | 序列到序列生成 | OnnxSeq2SeqConfigWithPast |
| ViT | image-classification | 图像分类 | OnnxConfig |
| Whisper | speech2seq-lm | 语音到文本 | OnnxSeq2SeqConfigWithPast |
Optimization
1. 优化器接口
| 名称 | 用途 | 场景 | 参数作用 |
|---|---|---|---|
Adafactor | 自适应学习率优化器,内存效率高 | 微调大模型(如 T5),资源受限场景 | lr: 外部学习率;eps: 梯度/参数的正则化常数;clip_threshold: 梯度更新阈值;decay_rate: 平方梯度平均系数;scale_parameter: 是否按 RMS 缩放学习率;relative_step: 是否使用时间依赖学习率 |
AdamWeightDecay | Adam 优化器 + 解耦权重衰减(L2 正则) | TensorFlow 模型训练 | learning_rate: 基础学习率;beta_1/beta_2: 动量衰减率;weight_decay_rate: 权重衰减系数;include/exclude_from_weight_decay: 指定参数是否参与权重衰减 |
使用样例:
# Adafactor
Adafactor(
model.parameters(),
scale_parameter=False,
relative_step=False,
lr=1e-3
)
# AdamWeightDecay
AdamWeightDecay(
learning_rate=1e-3,
weight_decay_rate=0.01,
exclude_from_weight_decay=["bias"]
)
2. 调度器接口
| 名称 | 用途 | 场景 | 参数作用 |
|---|---|---|---|
get_constant_schedule | 恒定学习率 | 稳定训练阶段 | optimizer: 关联的优化器 |
get_linear_schedule_with_warmup | 线性预热后线性衰减 | 微调 Transformer 模型 | num_warmup_steps: 预热步数;num_training_steps: 总训练步数 |
get_cosine_schedule_with_warmup | 余弦衰减学习率 | 图像分类/生成任务 | num_cycles: 余弦周期数(默认 0.5) |
AdafactorSchedule | 适配 Adafactor 的时间依赖学习率 | 搭配 Adafactor 优化器 | optimizer: 已配置的 Adafactor 优化器 |
WarmUp (TensorFlow) | 多项式预热学习率 | TensorFlow 模型预热阶段 | initial_learning_rate: 基础学习率;warmup_steps: 预热步数;power: 多项式指数(默认 1.0 线性) |
使用样例:
# 恒定学习率
get_constant_schedule(optimizer)
# 线性预热后线性衰减
get_linear_schedule_with_warmup(
optimizer,
num_warmup_steps=100,
num_training_steps=1000
)
# 余弦衰减
get_cosine_schedule_with_warmup(
optimizer,
num_warmup_steps=100,
num_training_steps=1000
)
# AdafactorSchedule
optimizer = Adafactor(...)
lr_scheduler = AdafactorSchedule(optimizer)
# WarmUp (TensorFlow)
lr_schedule = WarmUp(
initial_learning_rate,
decay_schedule_fn,
warmup_steps=500
)
3. 梯度策略接口
| 名称 | 用途 | 场景 | 参数作用 |
|---|---|---|---|
GradientAccumulator | 无同步梯度累积 | 大批次训练(内存不足时) | 无参数 |
使用样例:
accumulator = GradientAccumulator()
accumulator.reset()
关键说明
-
Adafactor 优化器建议:
- 禁用梯度裁剪(与内置
clip_threshold冲突) - T5 微调推荐配置:
scale_parameter=False, relative_step=False, lr=1e-3
- 禁用梯度裁剪(与内置
-
调度器选择:
SchedulerType提供枚举值(如"cosine","polynomial"),通过get_scheduler统一创建- 示例:
get_scheduler("cosine", optimizer, num_warmup_steps=100, num_training_steps=1000)
-
TensorFlow 工具:
create_optimizer整合预热+线性衰减:
create_optimizer(init_lr=5e-5, num_train_steps=10000, num_warmup_steps=500)
模型输出
1. 基础输出类
| 名称 | 用途 | 场景 | 参数作用 | 样例 |
|---|---|---|---|---|
ModelOutput | 所有模型输出的基类,支持字典/元组访问 | 所有模型的通用输出 | 无特定参数;自动处理非 None 属性 | outputs["last_hidden_state"] |
BaseModelOutput | 基础模型输出,含最后隐藏状态 | 编码器模型(如 BERT) | last_hidden_state: 末层隐藏状态;hidden_states: 各层隐藏状态(可选);attentions: 注意力权重(可选) | BERT、RoBERTa 的输出 |
BaseModelOutputWithPooling | 增加池化层输出的基础输出 | 需池化操作的模型(如分类) | 在 BaseModelOutput 基础上增加 pooler_output: 首词符的池化表示 | BERT 用于句子分类时的输出 |
BaseModelOutputWithCrossAttentions | 含交叉注意力的输出 | 解码器模型(如 GPT-2) | 在 BaseModelOutput 基础上增加 cross_attentions: 解码器对编码器的注意力权重 | 多模态模型、生成任务的解码器输出 |
BaseModelOutputWithPast | 含过去键值缓存的输出,加速序列生成 | 自回归模型(如 GPT) | 在 BaseModelOutput 基础上增加 past_key_values: 预先计算的键/值缓存 | GPT 生成文本时的输出 |
Seq2SeqModelOutput | 序列到序列模型的完整输出 | 编码器-解码器模型(如 T5) | 包含编码器/解码器的 last_hidden_state、hidden_states、attentions 及 past_key_values | T5、BART 的编码器-解码器输出 |
2. 语言建模输出
| 名称 | 用途 | 场景 | 参数作用 | 样例 |
|---|---|---|---|---|
CausalLMOutput | 因果语言模型输出 | GPT 类模型 | loss: 语言建模损失;logits: 词汇预测分数;hidden_states/attentions: 隐藏状态和注意力权重 | model(**inputs, labels=labels) |
MaskedLMOutput | 掩码语言模型输出 | BERT 类预训练 | loss: MLM 损失;logits: 掩码位置预测分数 | BERT 的 fill-mask 任务输出 |
Seq2SeqLMOutput | 序列到序列语言模型输出 | 文本生成(如 T5) | 在 Seq2SeqModelOutput 基础上增加 loss 和 logits | T5 的文本生成输出 |
3. 分类任务输出
| 名称 | 用途 | 场景 | 参数作用 | 样例 |
|---|---|---|---|---|
SequenceClassifierOutput | 单句分类输出 | 情感分析、文本分类 | loss: 分类损失;logits: 分类分数;hidden_states/attentions: 可选 | BERT 分类模型的输出 |
MultipleChoiceModelOutput | 多项选择任务输出 | SWAG、ReCoRD | loss: 选择损失;logits: 选项分数 (batch_size, num_choices) | 多项选择题模型输出 |
TokenClassifierOutput | 词符级分类输出 | NER、词性标注 | loss: 分类损失;logits: 每个词符的分类分数 (batch_size, seq_len, num_labels) | BERT 的 NER 任务输出 |
NextSentencePredictorOutput | 下一句预测输出 | BERT 预训练任务 | loss: NSP 损失;logits: 句子连续性分数 (batch_size, 2) | BERT 的 NSP 任务输出 |
4. 问答任务输出
| 名称 | 用途 | 场景 | 参数作用 | 样例 |
|---|---|---|---|---|
QuestionAnsweringModelOutput | 问答模型输出 | SQuAD、抽取式问答 | loss: 跨度损失;start_logits/end_logits: 答案开始/结束位置分数 | BERT 的问答模型输出 |
Seq2SeqQuestionAnsweringModelOutput | 序列到序列问答输出 | 生成式问答(如 T5) | 在 Seq2SeqModelOutput 基础上增加 loss、start_logits、end_logits | T5 的问答任务输出 |
5. 多模态/音频输出
| 名称 | 用途 | 场景 | 参数作用 | 样例 |
|---|---|---|---|---|
Wav2Vec2BaseModelOutput | Wav2Vec2 基础输出 | 音频特征提取 | last_hidden_state: 音频特征;extract_features: 卷积层特征 | Wav2Vec2 预训练模型输出 |
XVectorOutput | 说话人识别输出 | 声纹识别 | loss: 分类损失;logits: 说话人分数;embeddings: 说话人嵌入向量 | 说话人验证模型输出 |
6. 计算机视觉输出
| 名称 | 用途 | 场景 | 参数作用 | 样例 |
|---|---|---|---|---|
ImageClassifierOutput | 图像分类输出 | ImageNet 分类 | loss: 分类损失;logits: 分类分数;hidden_states: 各阶段特征图 | ViT、ResNet 图像分类输出 |
SemanticSegmenterOutput | 语义分割输出 | 图像分割 | loss: 分割损失;logits: 像素级分类分数 (batch_size, num_labels, height, width) | SegFormer、DeepLabV3 输出 |
DepthEstimatorOutput | 深度估计输出 | 单目深度估计 | loss: 估计损失;predicted_depth: 深度图 (batch_size, height, width) | DPT 深度估计模型输出 |
关键特性说明
通用行为:
- 所有输出类继承自
ModelOutput,支持字典式访问(output["key"])和元组式访问(output[0]),自动忽略None值 - 使用
to_tuple()方法可转换为元组
参数说明:
loss:仅当提供标签(labels)时返回hidden_states/attentions:需设置output_hidden_states=True或output_attentions=Truepast_key_values:用于加速自回归生成(use_cache=True)
示例代码:
# 序列分类输出示例
outputs = model(**inputs, labels=labels)
print(outputs.loss) # 分类损失
print(outputs.logits) # 分类分数
# 启用隐藏状态和注意力
outputs = model(**inputs, output_hidden_states=True, output_attentions=True)
print(outputs.hidden_states[-1]) # 最后一层隐藏状态
Pipelines
Pipelines 总览
| 名称 | 用途 | 场景 | 参数作用 | 样例 |
|---|---|---|---|---|
pipeline() | 模型推理的高级抽象 | 封装所有任务管道,提供统一接口 | task: 任务类型(如文本分类);model: 模型标识符;device: 运行设备(CPU/GPU) | pipe = pipeline("text-classification");pipe("This restaurant is awesome") |
音频任务 Pipelines
| 名称 | 用途 | 场景 | 参数作用 | 样例 |
|---|---|---|---|---|
AudioClassificationPipeline | 音频分类 | 预测音频类别(如音乐类型) | inputs: 音频文件路径/原始波形;top_k: 返回概率最高的标签数量 | classifier = pipeline("audio-classification");classifier("audio.flac") |
AutomaticSpeechRecognitionPipeline | 语音转文本 | 转录语音内容(ASR) | inputs: 音频文件;return_timestamps: 是否返回时间戳 | transcriber = pipeline("automatic-speech-recognition");transcriber("speech.wav") |
TextToAudioPipeline | 文本转语音 | 生成语音/音频内容 | text_inputs: 输入文本;forward_params: 控制生成质量 | pipe = pipeline("text-to-audio");pipe("Hello world") |
ZeroShotAudioClassificationPipeline | 零样本音频分类 | 无训练数据时分类音频 | audios: 音频文件;candidate_labels: 候选标签列表 | classifier = pipeline("zero-shot-audio-classification");classifier(audio, labels=["sound", "silence"]) |
计算机视觉 Pipelines
| 名称 | 用途 | 场景 | 参数作用 | 样例 |
|---|---|---|---|---|
DepthEstimationPipeline | 深度估计 | 预测图像深度图(3D 重建) | inputs: 图像文件/PIL 对象 | depth_estimator = pipeline("depth-estimation");depth_estimator("image.jpg") |
ImageClassificationPipeline | 图像分类 | 识别图像内容类别 | inputs: 图像;top_k: 返回概率最高的类别数 | classifier = pipeline("image-classification");classifier("cat.jpg") |
ImageSegmentationPipeline | 图像分割 | 分割图像中的对象/区域 | inputs: 图像;threshold: 过滤低概率掩码 | segmenter = pipeline("image-segmentation");segmenter("street.jpg") |
ObjectDetectionPipeline | 目标检测 | 检测图像中的对象及位置 | inputs: 图像;threshold: 置信度阈值 | detector = pipeline("object-detection");detector("cars.jpg") |
ZeroShotImageClassificationPipeline | 零样本图像分类 | 无训练数据时分类图像 | image: 图像;candidate_labels: 候选标签列表 | classifier = pipeline("zero-shot-image-classification");classifier(img, labels=["cat", "dog"]) |
自然语言处理 Pipelines
| 名称 | 用途 | 场景 | 参数作用 | 样例 |
|---|---|---|---|---|
FillMaskPipeline | 掩码填充 | 预测被遮盖的词汇 | inputs: 含 [MASK] 的文本;top_k: 返回最佳预测数量 | fill_masker = pipeline("fill-mask");fill_masker("The capital of France is [MASK].") |
TokenClassificationPipeline | 标记分类 | 命名实体识别(NER) | inputs: 文本;aggregation_strategy: 实体分组策略 | ner = pipeline("ner");ner("John works in New York") |
QuestionAnsweringPipeline | 问答系统 | 从文本中提取答案 | question: 问题;context: 背景文本;top_k: 返回最佳答案数量 | qa = pipeline("question-answering");qa(question="Where?", context="Paris is in France") |
TextGenerationPipeline | 文本生成 | 生成连贯文本(如对话) | text_inputs: 提示文本;max_new_tokens: 生成最大长度 | generator = pipeline("text-generation");generator("Once upon a time") |
TranslationPipeline | 文本翻译 | 语言翻译(如英译法) | src_lang/tgt_lang: 源/目标语言 | translator = pipeline("translation_en_to_fr");translator("Hello world") |
多模态 Pipelines
| 名称 | 用途 | 场景 | 参数作用 | 样例 |
|---|---|---|---|---|
DocumentQuestionAnsweringPipeline | 文档问答 | 从图像文档中提取答案 | image: 文档图像;question: 问题 | doc_qa = pipeline("document-question-answering");doc_qa(image="invoice.png", question="Total amount?") |
ImageToTextPipeline | 图像描述生成 | 为图像生成文本描述 | inputs: 图像;generate_kwargs: 控制生成质量 | captioner = pipeline("image-to-text");captioner("landscape.jpg") |
VisualQuestionAnsweringPipeline | 视觉问答 | 回答关于图像的问题 | image: 图像;question: 问题 | vqa = pipeline("visual-question-answering");vqa(image="photo.jpg", question="What color is the car?") |
关键参数说明
通用参数:
device:指定计算设备(如device=0使用第一块 GPU)batch_size:批量处理输入(提升 GPU 利用率)framework:强制使用 PyTorch("pt")或 TensorFlow("tf")
任务特定参数:
- 文本生成:
max_new_tokens控制输出长度 - 目标检测:
threshold过滤低置信度预测 - 零样本分类:
candidate_labels提供自定义标签列表
使用示例
# 文本情感分析
from transformers import pipeline
sentiment_analyzer = pipeline("text-classification")
result = sentiment_analyzer("I love this product!")
# 输出: [{'label': 'POSITIVE', 'score': 0.9998}]
# 图像描述生成
caption_generator = pipeline("image-to-text")
caption = caption_generator("https://huggingface.co/datasets/Narsil/image_dummy/raw/main/parrots.png")
# 输出: [{'generated_text': 'Two colorful parrots standing on a branch'}]
Processors
1. 多模态 Processors
用于处理多模态模型(如文本+图像/音频)的输入预处理,组合多个处理组件(如 tokenizer、image processor)。
核心类:ProcessorMixin
| 名称 | 用途 | 场景 | 参数作用 | 样例 |
|---|---|---|---|---|
ProcessorMixin | 提供处理器的保存/加载功能 | 所有处理器类的基类 | 无直接参数 | 通过子类如 CLIPProcessor 使用 |
apply_chat_template() | 格式化多模态对话 | 处理含文本/图像/视频的对话 | conversation: 对话内容;chat_template: Jinja 模板 | processor.apply_chat_template([{"role":"user", "content": [...]}]) |
from_pretrained() | 加载预训练处理器 | 初始化多模态处理器 | pretrained_model_name_or_path: 模型 ID 或路径;token: 访问令牌 | processor = AutoProcessor.from_pretrained("openai/clip-vit-base-patch32") |
save_pretrained() | 保存处理器配置 | 本地存储或共享处理器 | save_directory: 存储路径;push_to_hub: 是否上传到 Hub | processor.save_pretrained("my_processor") |
push_to_hub() | 上传处理器到 Hub | 分享自定义处理器 | repo_id: 仓库 ID;private: 是否私有 | processor.push_to_hub("my-username/my-processor") |
2. 已弃用的 Processors
用于旧版 GLUE/SQuAD 数据预处理(不再推荐使用)。
核心类:
| 名称 | 用途 | 场景 | 参数作用 | 样例 |
|---|---|---|---|---|
DataProcessor | 处理序列分类数据集 | GLUE/SQuAD 数据转换 | data_dir: 数据目录路径 | processor.get_train_examples("data/") |
InputExample | 存储单个样本 | 表示训练/测试样本 | guid: 唯一 ID;text_a/text_b: 文本;label: 标签 | InputExample(guid="0", text_a="Hello", label="positive") |
InputFeatures | 存储模型输入特征 | 转换为模型输入格式 | input_ids: 分词 ID;attention_mask: 注意力掩码 | InputFeatures(input_ids=[1,2,3], label=1) |
数据集特定 Processors:
| 名称 | 用途 | 场景 | 参数作用 | 样例 |
|---|---|---|---|---|
GLUE Processors(如 MrpcProcessor) | 处理 GLUE 任务数据 | MRPC/MNLI 等文本分类 | data_dir: 数据路径 | processor = MrpcProcessor() |
XnliProcessor | 处理跨语言 NLI 数据 | XNLI 多语言文本蕴含 | 同 DataProcessor | 同 GLUE 使用方式 |
SquadProcessor | 处理问答数据 | SQuAD v1.1/v2.0 | data_dir: 数据路径;filename: 自定义文件名 | processor.get_dev_examples(squad_dir) |
转换函数:
| 名称 | 用途 | 场景 | 参数作用 | 样例 |
|---|---|---|---|---|
glue_convert_examples_to_features | 转换 GLUE 样本为特征 | 准备 GLUE 模型输入 | examples: 样本列表;tokenizer: 分词器;max_length: 最大长度 | features = glue_convert_examples_to_features(examples, tokenizer, max_length=128) |
squad_convert_examples_to_features | 转换 SQuAD 样本为特征 | 准备问答模型输入 | doc_stride: 滑动窗口步长;max_query_length: 问题最大长度 | features = squad_convert_examples_to_features(examples, tokenizer, max_seq_length=384) |
使用示例对比
多模态处理器示例:
# 加载CLIP处理器(文本+图像)
from transformers import AutoProcessor
processor = AutoProcessor.from_pretrained("openai/clip-vit-base-patch32")
# 处理多模态输入
image_input = processor(images=image, return_tensors="pt") # 图像处理
text_input = processor(text="a photo of a cat", return_tensors="pt") # 文本处理
已弃用处理器示例(旧版):
# GLUE数据预处理(已弃用)
from transformers import glue_convert_examples_to_features, MrpcProcessor
processor = MrpcProcessor()
examples = processor.get_train_examples("data/MRPC")
features = glue_convert_examples_to_features(
examples,
tokenizer,
max_length=128,
task="mrpc"
)
# SQuAD数据预处理(已弃用)
from transformers import squad_convert_examples_to_features, SquadV2Processor
processor = SquadV2Processor()
examples = processor.get_dev_examples("data/SQuAD")
features = squad_convert_examples_to_features(
examples,
tokenizer,
max_seq_length=384,
doc_stride=128
)
关键区别
| 特性 | 多模态 Processors | 已弃用 Processors |
|---|---|---|
| 适用场景 | 多模态模型(文本+图像/音频) | 单模态文本任务(GLUE/SQuAD) |
| 状态 | 当前推荐使用 | 已弃用,推荐改用 datasets 库 |
| 核心功能 | 组合多个处理组件 | 转换原始数据为 InputExample |
| 依赖关系 | 与多模态模型强绑定 | 独立数据预处理流程 |
| 示例模型 | CLIP, Wav2Vec2, LayoutLM | BERT 用于 GLUE/SQuAD |
Quantization
1. AWQ (Activation-aware Weight Quantization)
在保留原始性能的前提下,将模型量化为 4 位精度,实现高吞吐量推理。
核心类与接口:
| 名称 | 用途 | 场景 | 参数作用 | 样例 |
|---|---|---|---|---|
AwqConfig | 配置 AWQ 量化参数 | 加载/量化 AWQ 模型 | bits: 量化位数(默认 4);group_size: 量化组大小;version: 算法版本(GEMM/GEMV) | config = AwqConfig(bits=4, group_size=128) |
from_pretrained(load_in_4bit=True) | 加载 AWQ 量化模型 | 推理优化 | device_map: 设备映射策略;attn_implementation: 注意力实现方式 | model = AutoModelForCausalLM.from_pretrained("TheBloke/zephyr-7B-AWQ", load_in_4bit=True) |
apply_chat_template() | 格式化多模态输入 | 含图像的对话场景 | conversation: 对话内容列表;chat_template: Jinja 模板 | processor.apply_chat_template([{"role":"user", "content": [...]}]) |
2. GPTQ (GPT Quantization)
通过权重校准实现 8/4/3/2 位量化,平衡精度与效率。
核心类与接口:
| 名称 | 用途 | 场景 | 参数作用 | 样例 |
|---|---|---|---|---|
GPTQConfig | 配置 GPTQ 量化参数 | 模型量化与加载 | bits: 量化位数;dataset: 校准数据集;use_exllama: 启用 Exllama 内核 | config = GPTQConfig(bits=4, dataset="c4") |
from_pretrained(quantization_config) | 加载 GPTQ 模型 | 减少内存占用 | device_map: 设备映射策略 | model = AutoModelForCausalLM.from_pretrained(model_id, quantization_config=config) |
push_to_hub() | 推送量化模型到 Hub | 模型共享 | repo_id: 仓库 ID | quantized_model.push_to_hub("my-model-gptq") |
3. bitsandbytes
支持 8 位和 4 位量化,广泛兼容 GPU 硬件。
核心类与接口:
| 名称 | 用途 | 场景 | 参数作用 | 样例 |
|---|---|---|---|---|
BitsAndBytesConfig | 配置 bitsandbytes 参数 | 8/4 位量化 | load_in_4bit: 启用 4 位量化;bnb_4bit_quant_type: 量化类型(fp4/nf4) | config = BitsAndBytesConfig(load_in_4bit=True, bnb_4bit_quant_type="nf4") |
from_pretrained(load_in_4bit=True) | 加载 4 位量化模型 | 超大规模模型部署 | device_map: 设备映射策略 | model = AutoModelForCausalLM.from_pretrained("bigscience/bloom-1b7", load_in_4bit=True) |
get_memory_footprint() | 获取模型内存占用 | 资源监控 | 无参数 | print(model.get_memory_footprint()) |
llm_int8_threshold | 设置异常值阈值 | 提升不稳定模型性能 | 阈值范围(建议 6.0) | config = BitsAndBytesConfig(llm_int8_threshold=10.0) |
关键特性对比
| 特性 | AWQ | GPTQ | bitsandbytes |
|---|---|---|---|
| 量化位数 | 4 位 | 2/3/4/8 位 | 4/8 位 |
| 精度损失 | 接近无损 | 极小损失 | 可控损失 |
| 推理速度 | 超快(类 float16) | 快 | 平衡 |
| 硬件要求 | NVIDIA GPU | NVIDIA GPU | 多数 GPU |
| 训练支持 | 配合 PEFT 微调 | 配合 PEFT 微调 | 直接训练受限 |
| 典型场景 | 生产环境部署 | 研究/实验 | 通用优化 |
使用示例
AWQ 示例:
from transformers import AutoModelForCausalLM, AwqConfig
# 加载AWQ量化模型
model = AutoModelForCausalLM.from_pretrained(
"TheBloke/zephyr-7B-alpha-AWQ",
device_map="auto",
quantization_config=AwqConfig(bits=4)
)
GPTQ 示例:
from transformers import AutoModelForCausalLM, GPTQConfig
# 配置GPTQ量化
gptq_config = GPTQConfig(bits=4, dataset="c4")
model = AutoModelForCausalLM.from_pretrained(
"facebook/opt-125m",
quantization_config=gptq_config
)
# 推送量化模型到Hub
model.push_to_hub("opt-125m-gptq")
bitsandbytes 示例:
from transformers import BitsAndBytesConfig, AutoModelForCausalLM
# 配置4位NF4量化
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_use_double_quant=True
)
# 加载量化模型
model = AutoModelForCausalLM.from_pretrained(
"bigscience/bloom-1b7",
quantization_config=bnb_config,
device_map="auto"
)
混合精度推理:
# AWQ + Flash Attention
model = AutoModelForCausalLM.from_pretrained(
"TheBloke/zephyr-7B-AWQ",
attn_implementation="flash_attention_2",
device_map="auto"
)
最佳实践建议
- 生产部署:优先选择 AWQ(最高吞吐量)
- 实验研究:GPTQ 支持灵活位数选择
- 资源受限环境:bitsandbytes 4 位量化 + 嵌套量化
- 大模型微调:所有方法均需配合 PEFT 库
- 硬件兼容:bitsandbytes 支持最广泛 GPU 硬件
注:量化模型不支持直接训练,但可通过参数高效微调(PEFT)技术适配新任务。
Tokenizer
Tokenizer 核心类
| 名称 | 用途 | 场景 | 参数作用 | 样例 |
|---|---|---|---|---|
PreTrainedTokenizer | Python 实现的慢速分词器基类 | 需要纯 Python 分词逻辑时 | model_max_length(最大长度)、special_tokens(特殊标记)、padding_side(填充方向) | tokenizer = BertTokenizer.from_pretrained("bert-base-uncased") |
PreTrainedTokenizerFast | 基于 Rust 的快速分词器基类 | 需要高性能分词/批量处理/字符映射时 | tokenizer_object(🤗 Tokenizers 对象)、tokenizer_file(本地文件路径) | tokenizer = BertTokenizerFast.from_pretrained("bert-base-uncased") |
BatchEncoding | 存储编码结果的数据容器 | 处理分词器输出时 | encoding(原始编码数据)、tensor_type(张量转换类型) | inputs = tokenizer("text"); type(inputs) # BatchEncoding |
核心方法
| 名称 | 用途 | 场景 | 参数作用 | 样例 |
|---|---|---|---|---|
__call__ | 主要分词编码方法 | 文本转模型输入 | text(输入文本)、padding(填充策略)、truncation(截断策略)、return_tensors(返回张量类型) | inputs = tokenizer("Hello world!", padding=True) |
add_tokens | 添加新词汇 | 扩展领域专有词汇 | new_tokens(新词列表)、special_tokens(是否特殊标记) | num_added = tokenizer.add_tokens(["new_word"]) |
add_special_tokens | 添加特殊标记 | 自定义 [CLS]/[SEP] 等 | special_tokens_dict(特殊标记字典) | tokenizer.add_special_tokens({"cls_token": "<CLS>"}) |
batch_decode | 批量 ID 转文本 | 模型输出解码 | sequences(ID 序列)、skip_special_tokens(跳过特殊标记) | texts = tokenizer.batch_decode([[101, 2023, 2000, 102]]) |
decode | 单序列 ID 转文本 | 单个结果解码 | token_ids(ID 序列) | text = tokenizer.decode([101, 2023, 2000, 102]) |
encode | 文本转 ID 序列 | 快速编码文本 | text(输入文本)、max_length(最大长度) | ids = tokenizer.encode("Hello world!") |
convert_ids_to_tokens | ID 转单词片段 | 可视化分词结果 | ids(标记 ID) | tokens = tokenizer.convert_ids_to_tokens([2023, 2000]) |
token_to_chars | 标记定位字符位置 | 实体识别/文本对齐 | token_index(标记索引) | char_span = inputs.token_to_chars(0, 3) |
word_to_tokens | 单词定位标记范围 | 词级分析 | word_index(单词索引) | token_span = inputs.word_to_tokens(0, 2) |
push_to_hub | 上传至 HuggingFace Hub | 模型分享/部署 | repo_id(仓库 ID)、private(是否私有) | tokenizer.push_to_hub("my-model") |
关键参数说明
padding 策略:
True/'longest':按批次最长序列填充'max_length':按指定max_length填充False:不填充
truncation 策略:
True/'longest_first':从最长序列截断'only_first':仅截断首序列'only_second':仅截断次序列
特殊标记:
bos_token:序列开始,eos_token:序列结束unk_token:未知词,pad_token:填充标记mask_token:掩码标记(MLM 任务)
Trainer
核心训练类
| 名称 | 用途 | 场景 | 参数作用 | 样例 |
|---|---|---|---|---|
Trainer | 提供标准训练循环 | 通用模型训练/微调 | 见下方 TrainingArguments | trainer = Trainer(model, args, train_dataset) |
Seq2SeqTrainer | 序列到序列任务专用训练器 | 翻译/摘要/文本生成 | 继承 Trainer 并扩展生成方法 | trainer = Seq2SeqTrainer(..., predict_with_generate=True) |
参数配置类
| 名称 | 用途 | 场景 | 关键参数 | 样例 |
|---|---|---|---|---|
TrainingArguments | 训练过程配置容器 | 控制训练行为 | output_dir(输出路径)、per_device_train_batch_size(批次大小)、learning_rate(学习率)、fp16(混合精度) | 示例配置 |
Seq2SeqTrainingArguments | 序列任务专用配置 | 控制生成任务行为 | predict_with_generate(使用生成指标)、generation_max_length(最大生成长度) | 同 TrainingArguments |
TrainingArguments 示例:
training_args = TrainingArguments(
output_dir="./results",
per_device_train_batch_size=32,
learning_rate=2e-5,
num_train_epochs=3,
fp16=True,
fsdp="full_shard auto_wrap", # FSDP配置
neftune_noise_alpha=0.1 # NEFTune噪声
)
高级训练功能
| 功能名称 | 用途 | 激活方式 | 关键配置参数 | 适用场景 |
|---|---|---|---|---|
| FSDP (PyTorch) | 完全分片数据并行 | --fsdp + 配置文件 | fsdp_transformer_layer_cls_to_wrap(包装层)、fsdp_min_num_params(最小参数量) | 超大模型训练(>10B) |
| PyTorch/XLA FSDP | TPU 分片训练 | xla=True + xla_fsdp_settings | xla_fsdp_grad_ckpt(梯度检查点)、fsdp_transformer_layer_cls_to_wrap | TPU 集群训练 |
| MPS 加速 (Mac) | Apple Silicon GPU 加速 | 自动启用 | PYTORCH_ENABLE_MPS_FALLBACK=1(回退 CPU) | Mac M1/M2 训练 |
| NEFTune | 噪声嵌入提升性能 | neftune_noise_alpha | 噪声系数(建议 0.1) | 指令微调任务 |
工具与集成
| 名称 | 用途 | 使用方式 | 关键命令/配置 | 优势 |
|---|---|---|---|---|
| Accelerate Launcher | 统一分布式启动器 | accelerate config + accelerate launch | 生成统一配置模板 | 简化多 GPU/TPU 部署 |
| DeepSpeed 集成 | 深度学习优化库 | --deepspeed + 配置文件 | zero_stage(优化级别)、offload_optimizer(卸载优化器) | 内存优化/巨大模型 |
| Checkpoint 恢复 | 断点续训 | resume_from_checkpoint | checkpoint-xxx 目录路径 | 训练中断恢复 |
关键功能详解
1. FSDP 分片策略 (PyTorch):
# 启用方式(命令行)
python script.py --fsdp "full_shard auto_wrap" \
--fsdp_config fsdp_config.json
fsdp_config.json 示例:
{
"fsdp_transformer_layer_cls_to_wrap": ["BertLayer"],
"fsdp_min_num_params": 1e8,
"activation_checkpointing": true
}
2. 分布式训练环境变量:
| 变量名 | 功能 | 示例值 | 效果 |
|---|---|---|---|
CUDA_VISIBLE_DEVICES | 可见 GPU 选择 | 0,2 | 仅使用 GPU 0 和 2 |
CUDA_DEVICE_ORDER | GPU 排序策略 | FASTEST_FIRST | 性能强的 GPU 优先 |
PYTORCH_ENABLE_MPS_FALLBACK | Mac GPU 回退 | 1 | 不支持操作回退 CPU |
3. 日志控制参数:
TrainingArguments(
log_level="warning", # 主进程日志级别
log_level_replica="error", # 副本进程日志级别
log_on_each_node=False # 仅主节点记录
)
4. 自定义训练器示例(加权损失):
class CustomTrainer(Trainer):
def compute_loss(self, model, inputs, return_outputs=False):
labels = inputs.pop("labels")
outputs = model(**inputs)
loss_fct = nn.CrossEntropyLoss(weight=[1.0, 2.0, 3.0])
loss = loss_fct(outputs.logits, labels)
return (loss, outputs) if return_outputs else loss
DeepSpeed 集成
核心启动与配置接口
| 名称 | 用途 | 场景 | 参数作用 | 样例 |
|---|---|---|---|---|
deepspeed | DeepSpeed 启动器 | 分布式训练/推理 | --num_gpus:GPU 数量;--hostfile:多节点配置;--master_addr:主节点地址 | deepspeed --num_gpus=2 run.py --deepspeed ds_config.json |
HfDeepSpeedConfig | Transformers 与 DeepSpeed 桥接 | ZeRO-3 模型加载 | config_file_or_dict:配置文件路径或字典 | dschf = HfDeepSpeedConfig(ds_config) |
ZeRO 核心配置(zero_optimization 部分)
| 参数 | 用途 | 场景 | 推荐值 | 注意事项 |
|---|---|---|---|---|
stage | ZeRO 优化阶段 | 内存优化选择 | 0(禁用)、1(优化器状态)、2(梯度)、3(参数) | Stage 3 支持万亿参数模型 |
offload_optimizer | 优化器卸载目标 | CPU/NVMe 卸载 | device: "cpu" 或 "nvme" | 需配合 pin_memory: true |
offload_param | 参数卸载目标 | 超大模型支持 | nvme_path:NVMe 路径 | 需要高速 NVMe 设备 |
stage3_gather_16bit_weights | 保存完整权重 | ZeRO-3 模型导出 | true/false | 必须开启才能生成 pytorch_model.bin |
reduce_bucket_size | 通信缓冲区大小 | 性能调优 | auto 或模型 hidden_size² | 值越大通信越快,内存占用越高 |
精度与训练配置
| 配置组 | 关键参数 | 用途 | 场景 | 样例值 |
|---|---|---|---|---|
fp16 | enabled | FP16 混合精度 | 旧 GPU 架构 | {"enabled": true, "loss_scale": 0} |
bf16 | enabled | BF16 混合精度 | Ampere+ 新 GPU | {"enabled": true} |
optimizer | type, params | 优化器配置 | 训练优化 | {"type": "AdamW", "params": {"lr": "auto"}} |
scheduler | type, params | 学习率调度 | 训练优化 | {"type": "WarmupLR", "params": {"warmup_num_steps": "auto"}} |
gradient_accumulation | steps | 梯度累积步数 | 小批量训练 | "auto" 或整数 |
train_micro_batch_size | per_gpu | 单 GPU 批大小 | 内存不足时减小 | "auto" 或整数 |
工具与转换接口
| 名称 | 用途 | 场景 | 参数 | 使用样例 |
|---|---|---|---|---|
zero_to_fp32.py | ZeRO 权重转换 | 模型导出 | .:checkpoint 目录;pytorch_model.bin:输出文件 | python zero_to_fp32.py . pytorch_model.bin |
load_state_dict_from_zero | 加载完整权重 | Python 环境转换 | model:空模型;checkpoint_dir:路径 | load_state_dict_from_zero_checkpoint(model, dir) |
estimate_zero3_model_mem | 内存预估 | 资源规划 | model:模型对象;num_gpus:GPU 数量 | 见文档示例代码 |
典型配置样例
ZeRO-2 最小配置:
{
"zero_optimization": {
"stage": 2,
"offload_optimizer": {"device": "cpu"},
"allgather_bucket_size": 5e8
},
"fp16": {"enabled": true},
"train_batch_size": "auto"
}
ZeRO-3 NVMe 卸载配置:
{
"zero_optimization": {
"stage": 3,
"offload_optimizer": {
"device": "nvme",
"nvme_path": "/local_nvme"
},
"offload_param": {
"device": "nvme",
"nvme_path": "/local_nvme"
},
"stage3_gather_16bit_weights": true
},
"bf16": {"enabled": true},
"aio": {"block_size": 262144}
}
单 GPU CPU 卸载推理:
# 初始化配置
dschf = HfDeepSpeedConfig({
"zero_optimization": {
"stage": 3,
"offload_param": {"device": "cpu"}
}
})
# 加载模型
model = AutoModel.from_pretrained("bigscience/T0_3B")
关键使用场景对照表
| 场景 | 推荐配置 | 启动命令 | 内存优化 |
|---|---|---|---|
| 单 GPU 微调 | ZeRO-2 + CPU 卸载 | deepspeed --num_gpus=1 | 减少约 60% GPU 内存 |
| 多节点训练 | ZeRO-3 + BF16 | deepspeed --hostfile hostfile | 千亿参数支持 |
| 超大模型推理 | ZeRO-Infinity | 同上 | CPU/NVMe 分级存储 |
| Mac M1 训练 | Stage 0 + MPS | 无需 DeepSpeed | 苹果芯片优化 |
| 8GB GPU 训练 | ZeRO-3 + 双卸载 | deepspeed --num_gpus=1 | 支持 30B+ 模型 |
Feature Extractor
核心特征提取类
| 名称 | 用途 | 场景 | 参数作用 | 样例 |
|---|---|---|---|---|
FeatureExtractionMixin | 特征提取器基类 | 提供保存/加载功能 | 见下方方法 | feature_extractor = Wav2Vec2FeatureExtractor.from_pretrained("facebook/wav2vec2-base-960h") |
SequenceFeatureExtractor | 序列特征处理器 | 音频特征处理 | feature_size:特征维度;sampling_rate:采样率;padding_value:填充值 | processor = Wav2Vec2FeatureExtractor(feature_size=1, sampling_rate=16000) |
ImageFeatureExtractionMixin | 图像处理工具集 | 图像预处理 | 见下方方法 | 用于 ViT 等视觉模型的特征提取 |
核心方法
| 名称 | 所属类 | 用途 | 关键参数 | 样例 |
|---|---|---|---|---|
from_pretrained | FeatureExtractionMixin | 加载预训练配置 | pretrained_model_name_or_path:模型 ID/路径;cache_dir:缓存目录;revision:版本号 | extractor = Wav2Vec2FeatureExtractor.from_pretrained("facebook/wav2vec2-base-960h") |
save_pretrained | FeatureExtractionMixin | 保存配置 | save_directory:保存路径;push_to_hub:是否推送 Hub | extractor.save_pretrained("./my_model") |
pad | SequenceFeatureExtractor | 填充序列 | processed_features:输入特征;padding:填充策略;max_length:最大长度 | 见下方示例 |
convert_to_tensors | BatchFeature | 转为张量 | tensor_type:张量类型(pt/tf/np) | tensors = batch_feature.convert_to_tensors("pt") |
center_crop | ImageFeatureExtractionMixin | 中心裁剪图像 | size:裁剪尺寸 | cropped_img = feature_extractor.center_crop(image, (224,224)) |
normalize | ImageFeatureExtractionMixin | 图像归一化 | mean:均值;std:标准差 | norm_img = feature_extractor.normalize(img, [0.5], [0.5]) |
图像处理工具方法
| 名称 | 用途 | 关键参数 | 返回类型 |
|---|---|---|---|
resize | 调整图像尺寸 | size:目标尺寸;resample:重采样方法 | PIL.Image |
rotate | 旋转图像 | angle:旋转角度;resample:重采样方法 | PIL.Image |
convert_rgb | 转为 RGB 格式 | image:输入图像 | RGB 格式图像 |
to_numpy_array | 转为 NumPy 数组 | rescale:是否缩放;channel_first:通道优先 | np.ndarray |
to_pil_image | 转为 PIL 图像 | rescale:是否缩放 | PIL.Image |
flip_channel_order | 翻转通道顺序 | image:输入图像 | BGR/RGB 转换图像 |
典型使用示例
音频特征处理:
from transformers import Wav2Vec2FeatureExtractor
# 加载预训练特征提取器
feature_extractor = Wav2Vec2FeatureExtractor.from_pretrained("facebook/wav2vec2-base-960h")
# 处理音频
audio_input = [...] # 原始音频数据
processed = feature_extractor(audio_input, sampling_rate=16000, return_tensors="pt")
# 填充序列
padded = feature_extractor.pad(
processed,
padding=True,
max_length=1000,
return_tensors="pt"
)
图像特征处理:
from transformers import ViTFeatureExtractor
from PIL import Image
# 加载预训练特征提取器
feature_extractor = ViTFeatureExtractor.from_pretrained("google/vit-base-patch16-224")
# 处理图像
image = Image.open("cat.jpg")
processed = feature_extractor(
images=image,
return_tensors="pt",
do_resize=True,
size=224,
do_normalize=True
)
# 图像预处理流程
image = feature_extractor.convert_rgb(image)
image = feature_extractor.resize(image, (256, 256))
image = feature_extractor.center_crop(image, (224, 224))
image = feature_extractor.to_numpy_array(image)
批特征操作:
# 假设 batch_features 是 BatchFeature 对象
batch_features.convert_to_tensors("pt") # 转为 PyTorch 张量
batch_features.to("cuda") # 转移到 GPU(PyTorch)
参数详解
pad 方法关键参数:
padding:True/'longest'(按最长序列填充)、'max_length'(固定长度填充)max_length:填充目标长度truncation:是否截断超长序列pad_to_multiple_of:填充至指定倍数(优化硬件性能)return_tensors:返回张量类型('pt'/'tf'/'np')
图像归一化参数:
normalize(
image,
mean=[0.485, 0.456, 0.406], # ImageNet 均值
std=[0.229, 0.224, 0.225] # ImageNet 标准差
)
Image Processor
核心图像处理类
| 名称 | 用途 | 场景 | 参数作用 | 样例 |
|---|---|---|---|---|
ImageProcessingMixin | 图像处理器基类 | 提供保存/加载功能 | 见下方方法 | processor = CLIPImageProcessor.from_pretrained("openai/clip-vit-base-patch32") |
BaseImageProcessor | 图像处理基类 | 基础图像处理操作 | 见下方方法 | 用于自定义图像处理器 |
核心方法
| 名称 | 所属类 | 用途 | 关键参数 | 样例 |
|---|---|---|---|---|
from_pretrained | ImageProcessingMixin | 加载预训练配置 | pretrained_model_name_or_path:模型 ID/路径;cache_dir:缓存目录 | processor = CLIPImageProcessor.from_pretrained("google/vit-base-patch16-224") |
save_pretrained | ImageProcessingMixin | 保存配置 | save_directory:保存路径;push_to_hub:是否推送 Hub | processor.save_pretrained("./my_model") |
center_crop | BaseImageProcessor | 中心裁剪图像 | size:目标尺寸字典;data_format:通道格式 | cropped = processor.center_crop(image, size={"height":224,"width":224}) |
normalize | BaseImageProcessor | 图像归一化 | mean:均值;std:标准差 | norm_img = processor.normalize(img, mean=[0.5], std=[0.5]) |
rescale | BaseImageProcessor | 像素值缩放 | scale:缩放因子 | rescaled = processor.rescale(img, scale=1/255.0) |
批特征操作类
| 名称 | 用途 | 关键方法 | 场景 |
|---|---|---|---|
BatchFeature | 存储处理结果 | convert_to_tensors():转为张量;to():设备转移 | 模型输入处理 |
典型使用示例
加载和使用图像处理器:
from transformers import CLIPImageProcessor
# 加载预训练处理器
processor = CLIPImageProcessor.from_pretrained(
"openai/clip-vit-base-patch32",
do_normalize=False # 自定义参数
)
# 处理图像
inputs = processor(
images=image,
return_tensors="pt",
do_resize=True,
size=(224, 224),
do_normalize=True
)
# 保存配置
processor.save_pretrained("./my_model")
基础图像处理操作:
# 中心裁剪
cropped = processor.center_crop(
image,
size={"height": 256, "width": 256},
data_format="channels_last"
)
# 图像归一化
normalized = processor.normalize(
cropped,
mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225]
)
# 像素值缩放
rescaled = processor.rescale(
normalized,
scale=2.0
)
批特征操作:
# 创建批特征对象
batch = BatchFeature(data={"pixel_values": [img1, img2]})
# 转为 PyTorch 张量
tensors = batch.convert_to_tensors("pt")
# 转移到 GPU
gpu_batch = batch.to("cuda")
参数详解
center_crop 参数:
center_crop(
image,
size={"height": 224, "width": 224}, # 目标尺寸
data_format="channels_first", # 通道格式
input_data_format="channels_last" # 输入格式
)
normalize 参数:
normalize(
image,
mean=[0.485, 0.456, 0.406], # 各通道均值
std=[0.229, 0.224, 0.225], # 各通道标准差
data_format="channels_last" # 输出格式
)
rescale 参数:
rescale(
image,
scale=0.5, # 缩放因子
data_format="channels_first" # 通道格式
)
辅助工具
自定义层和工具
PyTorch 自定义模块
| 名称 | 用途 | 场景 | 参数作用 | 样例 |
|---|---|---|---|---|
Conv1D | 1D 转置卷积层 | GPT 系列模型 | nf:输出特征数;nx:输入特征数 | layer = Conv1D(768, 3072) |
PyTorch 帮助函数
| 名称 | 用途 | 场景 | 参数作用 | 样例 |
|---|---|---|---|---|
apply_chunking_to_forward | 分块前向传播 | 大模型内存优化 | chunk_size:分块大小;chunk_dim:分块维度 | 见下方示例 |
find_pruneable_heads_and_indices | 查找可修剪注意力头 | 模型压缩 | heads:待修剪头索引;n_heads:总头数 | 见下方示例 |
prune_layer | 通用层修剪 | 模型压缩 | layer:待修剪层;index:保留索引 | pruned_layer = prune_layer(linear_layer, keep_indices) |
prune_conv1d_layer | Conv1D 层专用修剪 | GPT 模型压缩 | dim:修剪维度 | pruned_conv = prune_conv1d_layer(conv1d, keep_indices, dim=1) |
prune_linear_layer | 线性层专用修剪 | 通用模型压缩 | dim:修剪维度 | pruned_linear = prune_linear_layer(linear, keep_indices, dim=0) |
TensorFlow 自定义层
| 名称 | 用途 | 场景 | 参数作用 | 样例 |
|---|---|---|---|---|
TFConv1D | TF 版 1D 转置卷积 | GPT 系列模型 | initializer_range:权重初始化范围 | layer = TFConv1D(768, 3072, initializer_range=0.02) |
TFSequenceSummary | 序列摘要生成 | 分类任务特征提取 | summary_type:摘要类型;summary_use_proj:是否投影 | 见下方示例 |
TensorFlow 损失函数
| 名称 | 用途 | 场景 | 特殊处理 |
|---|---|---|---|
TFCausalLanguageModelingLoss | 因果语言建模损失 | GPT 类模型 | 忽略 -100 标签 |
TFMaskedLanguageModelingLoss | 掩码语言建模损失 | BERT 类模型 | 忽略 -100 标签 |
TFMultipleChoiceLoss | 多项选择损失 | 选择题任务 | - |
TFQuestionAnsweringLoss | 问答损失 | 阅读理解任务 | - |
TFSequenceClassificationLoss | 序列分类损失 | 文本分类任务 | - |
TFTokenClassificationLoss | 令牌分类损失 | NER 任务 | 忽略 -100 标签 |
TensorFlow 帮助函数
| 名称 | 用途 | 场景 | 参数作用 | 样例 |
|---|---|---|---|---|
get_initializer | 初始化器生成 | 权重初始化 | initializer_range:标准差 | init = get_initializer(0.02) |
keras_serializable | 序列化装饰器 | 自定义层保存 | 类装饰器 | @keras_serializable() class CustomLayer: |
shape_list | 动态形状处理 | TF 张量操作 | tensor:输入张量 | dims = shape_list(tensor) |
典型使用示例
PyTorch 分块处理:
# 定义分块前向传播
def forward_chunk(self, hidden_states):
return self.decoder(hidden_states)
# 应用分块处理
def forward(self, hidden_states):
return apply_chunking_to_forward(
self.forward_chunk,
chunk_size=128,
chunk_dim=1,
hidden_states
)
注意力头修剪:
# 查找可修剪头
prune_heads, keep_indices = find_pruneable_heads_and_indices(
heads=[3,5],
n_heads=12,
head_size=64,
already_pruned_heads=set()
)
# 修剪线性层
pruned_layer = prune_linear_layer(
layer=attention.query,
index=keep_indices,
dim=0
)
TensorFlow 序列摘要:
summary = TFSequenceSummary(
config=model.config,
summary_type='first', # 取首个 token
summary_use_proj=True
)(sequence_output)
TensorFlow 自定义层:
@keras_serializable()
class CustomLayer(tf.keras.layers.Layer):
def __init__(self, config):
super().__init__()
self.dense = tf.keras.layers.Dense(config.hidden_size)
def call(self, inputs):
return self.dense(inputs)
关键参数详解
TFSequenceSummary 配置:
TFSequenceSummary(
summary_type='cls_index', # 支持 last/first/mean/cls_index
summary_use_proj=True, # 是否添加投影层
summary_proj_to_labels=False, # 投影到标签维度
summary_activation='tanh', # 激活函数
summary_first_dropout=0.1, # 投影前 dropout
summary_last_dropout=0.1 # 投影后 dropout
)
分块处理参数:
apply_chunking_to_forward(
forward_fn, # 分块处理函数
chunk_size=64, # 每块大小
chunk_dim=1, # 分块维度(通常是序列维度)
*input_tensors # 输入张量
)
修剪函数参数:
prune_linear_layer(
layer, # 待修剪层
index, # 保留索引
dim=0 # 权重矩阵维度
)
Pipelines 工具
参数处理类(Argument Handling)
| 名称 | 用途 | 场景 | 参数作用 | 样例 |
|---|---|---|---|---|
ArgumentHandler | 处理 Pipeline 参数的基础接口 | 自定义 Pipeline 参数解析 | 无直接参数 | 基类,需子类化使用 |
ZeroShotClassificationArgumentHandler | 将分类标签转为 NLI 前提/假设对 | 零样本文本分类任务 | 无公开参数 | 自动处理标签格式:("This is a premise", "This is a hypothesis") |
QuestionAnsweringArgumentHandler | 将用户输入映射为 SquadExample 对象 | 问答任务(需问题+上下文) | 无公开参数 | 输入:{"question": "...", "context": "..."} → 输出 SquadExample |
数据格式类(Data Format)
| 名称 | 用途 | 场景 | 参数作用 | 样例 |
|---|---|---|---|---|
PipelineDataFormat | 处理 Pipeline 输入/输出数据的基类 | 统一管理数据格式(JSON/CSV/管道) | output_path:输出路径;input_path:输入路径;column:读取列名;overwrite:是否覆盖输出文件 | 通过 from_str() 动态创建子类实例 |
CsvPipelineDataFormat | 读写 CSV 格式数据 | CSV 文件处理 | 同上 | 保存数据:save([{"text": "example"}]) → 生成 CSV 文件 |
JsonPipelineDataFormat | 读写 JSON 格式数据 | JSON 文件处理 | 同上 | 保存数据:save({"key": "value"}) → 生成 JSON 文件 |
PipedPipelineDataFormat | 从标准输入/输出读写数据 | 命令行管道操作 | 同上 | 输入:echo "data" | pipeline → 输出打印到终端 |
实用函数(Utility Functions)
| 名称 | 用途 | 场景 | 参数作用 | 样例 |
|---|---|---|---|---|
PipelineException | 抛出 Pipeline 处理异常 | Pipeline 执行错误时 | task:任务名称;model:模型名称;reason:错误原因 | 抛出异常:PipelineException(task="text-classification", model="BERT", reason="Invalid input") |
关键方法说明
PipelineDataFormat.from_str():
| 参数 | 作用 |
|---|---|
format | 数据格式("json"/"csv"/"pipe") |
output_path | 输出文件路径(可选) |
input_path | 输入文件路径(可选) |
column | 需读取的数据列(可选) |
overwrite | 覆盖输出文件(默认 False) |
样例:
format = PipelineDataFormat.from_str("csv", output_path="out.csv", column="text")
PipelineDataFormat.save():
| 参数 | 作用 |
|---|---|
data | 要保存的数据(字典或字典列表) |
样例:
csv_format.save([{"label": 1, "text": "example"}])
PipelineDataFormat.save_binary():
| 参数 | 作用 |
|---|---|
data | 要保存的数据(字典或字典列表) |
| 返回 | 保存后的文件路径(二进制格式) |
使用场景总结
- 参数处理类:解析任务特定输入(如零样本分类标签、问答对)
- 数据格式类:
- CSV/JSON:文件读写场景(如批量处理数据集)
- Pipe:命令行流式处理(如
cat data.txt | pipeline)
- 异常类:统一处理 Pipeline 运行时错误
Tokenizers 工具
核心类:PreTrainedTokenizerBase
| 名称 | 用途 | 场景 | 关键参数作用 | 样例 |
|---|---|---|---|---|
__call__ | 主入口:分词并准备模型输入 | 文本编码(单句/句对) | text:输入文本;padding:填充策略(True/'longest'/'max_length');truncation:截断策略(True/'longest_first');return_tensors:返回张量类型('pt'/'tf'/'np') | tokenizer("Hello world", return_tensors="pt") → 输出包含 input_ids 和 attention_mask 的字典 |
apply_chat_template | 格式化对话历史为模型输入 | 对话模型(ChatGPT 等) | conversation:对话历史(角色+内容);tools:可调用函数列表(函数调用场景);add_generation_prompt:是否添加助理响应提示 | tokenizer.apply_chat_template([{"role":"user","content":"Hello"}]) → 格式化的对话字符串或 ID 列表 |
batch_decode | 批量 ID 序列解码为文本 | 模型输出后处理 | skip_special_tokens:是否跳过特殊标记(如 [CLS]);clean_up_tokenization_spaces:清理多余空格 | tokenizer.batch_decode([[101, 7592, 102]]) → ["[CLS] hello [SEP]"] |
from_pretrained | 加载预训练分词器 | 初始化模型 | pretrained_model_name_or_path:模型 ID 或本地路径;token:HuggingFace 认证令牌;trust_remote_code:是否信任远程自定义代码 | BertTokenizer.from_pretrained("google-bert/bert-base-uncased") |
save_pretrained | 保存分词器到本地 | 模型持久化 | save_directory:保存路径;legacy_format:是否保存旧格式(兼容慢速分词器) | tokenizer.save_pretrained("./my_model") → 生成 vocab.txt 和 tokenizer_config.json |
add_tokens | 添加新词到词表 | 扩展自定义词汇 | new_tokens:新词(字符串或 AddedToken 对象);special_tokens:是否标记为特殊词 | tokenizer.add_tokens(["new_word"], special_tokens=False) → 返回添加词数(1) |
encode | 文本 → ID 序列(单条) | 快速编码 | text_pair:第二段文本(如问答);max_length:最大序列长度 | tokenizer.encode("Hello") → [101, 7592, 102] |
decode | ID 序列 → 文本(单条) | 快速解码 | skip_special_tokens:跳过特殊标记 | tokenizer.decode([101, 7592, 102]) → "[CLS] hello [SEP]" |
pad | 填充批处理数据 | 批处理对齐 | encoded_inputs:批输入数据;pad_to_multiple_of:填充至倍数(如 8 的倍数加速 GPU) | 见 __call__ 的 padding 参数 |
特殊标记处理:SpecialTokensMixin
| 名称 | 用途 | 场景 | 关键参数作用 | 样例 |
|---|---|---|---|---|
add_special_tokens | 添加/更新特殊标记 | 自定义特殊标记 | special_tokens_dict:字典(如 {"cls_token":"<CLS>"}) | tokenizer.add_special_tokens({"cls_token": "<CLS>"}) → 更新 tokenizer.cls_token |
bos_token | 句子开头标记 | 文本生成 | 类属性(可修改) | tokenizer.bos_token = "<BOS>" |
eos_token | 句子结束标记 | 文本生成 | 类属性 | tokenizer.eos_token_id 获取 ID |
pad_token | 填充标记 | 批处理 | 类属性 | 设置 tokenizer.pad_token = tokenizer.eos_token(GPT-2 场景) |
枚举和命名元组
| 名称 | 用途 | 场景 | 关键值/属性 | 样例 |
|---|---|---|---|---|
TruncationStrategy | 截断策略枚举 | 控制文本截断方式 | longest_first:优先截断较长句;only_first:仅截断第一句;do_not_truncate:不截断 | truncation="only_first" |
CharSpan | 字符级位置标记 | 原始文本定位 | start:起始字符索引;end:结束字符索引 | 用于问答任务定位答案位置 |
TokenSpan | 词元级位置标记 | 分词后定位 | start:起始词元索引;end:结束词元索引 | 用于序列标注任务(如 NER) |
关键方法详解
__call__ 核心参数:
| 参数 | 作用 |
|---|---|
text | 输入文本(支持字符串、字符串列表、分词后列表) |
text_pair | 第二段文本(用于句对任务如 NLI) |
max_length | 最大序列长度(如 512) |
return_attention_mask | 是否返回注意力掩码(默认 True) |
return_token_type_ids | 是否返回段落标记(如 BERT 句对任务) |
apply_chat_template 核心参数:
| 参数 | 作用 |
|---|---|
conversation | 对话历史(例如:[{"role":"user", "content":"Hello"}]) |
tokenize | 是否返回分词后 ID(默认 True) |
add_generation_prompt | 是否添加助理响应提示(如 <|im_start|>assistant) |
使用场景示例
1. 基础编码:
inputs = tokenizer("Hello world!", padding=True, return_tensors="pt")
# 输出: {'input_ids': tensor([[101, 7592, 2088, 999, 102]]), 'attention_mask': tensor([[1, 1, 1, 1, 1]])}
2. 对话模型格式化:
messages = [{"role": "user", "content": "Hello!"}]
inputs = tokenizer.apply_chat_template(messages, add_generation_prompt=True, return_tensors="pt")
# 输出: tensor([1, 367, 1234, ...]) # 包含助理响应提示的 ID 序列
3. 添加自定义词:
num_added = tokenizer.add_tokens(["<SPECIAL>"])
model.resize_token_embeddings(len(tokenizer)) # 调整模型词嵌入层大小
4. 批处理填充:
batch = [["Hello"], ["Hi there!"]]
inputs = tokenizer(batch, padding='max_length', max_length=10, return_tensors="pt")
# 所有序列填充至长度 10
训练器工具
核心工具类
| 名称 | 用途 | 场景 | 关键参数作用 | 样例 |
|---|---|---|---|---|
EvalPrediction | 封装评估预测结果 | 自定义评估指标计算 | predictions:模型预测值;label_ids:真实标签;inputs:原始输入数据 | 用于计算准确率:accuracy = (preds == labels).mean() |
IntervalStrategy | 训练策略枚举 | 控制评估/保存频率 | STEPS:按步数间隔;EPOCH:按轮次间隔 | evaluation_strategy="steps" |
enable_full_determinism | 启用完全确定性训练 | 可复现性实验 | seed:随机种子;warn_only:仅警告不强制 | enable_full_determinism(42) |
set_seed | 设置随机种子 | 实验可复现 | seed:随机种子;deterministic:启用确定性算法 | set_seed(42) |
torch_distributed_zero_first | 分布式训练同步 | 多 GPU/多节点训练 | local_rank:本地进程 ID | with torch_distributed_zero_first(local_rank): preprocess_data() |
DistributedTensorGatherer | 分布式张量收集 | 分布式评估 | world_size:进程数;num_samples:样本总数;padding_index:填充值索引 | gatherer.add_arrays(predictions) |
HfArgumentParser | 参数解析器 | 解析命令行到数据类 | dataclass_types:目标数据类 | parser = HfArgumentParser(TrainingArguments); args = parser.parse_args() |
DebugUnderflowOverflow | 数值异常检测 | FP16 混合精度训练调试 | model:待监控模型;trace_batch_nums:追踪批次号;abort_after_batch_num:终止批次 | debugger = DebugUnderflowOverflow(model) |
参数解析方法
| 名称 | 用途 | 关键参数 | 返回值 |
|---|---|---|---|
parse_args_into_dataclasses | 解析命令行参数 | look_for_args_file:自动查找 .args 文件 | 数据类实例元组 |
parse_dict | 解析字典到数据类 | allow_extra_keys:是否允许额外键 | 数据类实例元组 |
parse_json_file | 解析 JSON 文件 | json_file:JSON 文件路径 | 数据类实例元组 |
parse_yaml_file | 解析 YAML 文件 | yaml_file:YAML 文件路径 | 数据类实例元组 |
调试工具详解
DebugUnderflowOverflow 工作模式:
| 模式 | 触发条件 | 输出内容 | 使用场景 |
|---|---|---|---|
| 异常检测 | 自动检测 NaN/Inf | 打印导致异常的调用栈(默认 21 帧) | 定位 FP16 训练崩溃点 |
| 指定批次追踪 | 设置 trace_batch_nums | 输出指定批次各层的绝对值 min/max | 分析特定批次数值问题 |
典型检测报告片段:
Detected inf/nan during batch_number=5
Last 5 forward frames:
abs min abs max metadata
layer.4.attention.dense Linear
1.23e-07 2.50e+00 weight
3.45e-06 4.80e+00 input[0]
2.78e-06 3.60e+01 output <-- 接近FP16上限(64K)
layer.4.dropout Dropout
2.78e-06 3.60e+01 input[0]
0.00e+00 inf output <-- 检测到溢出
使用场景示例
1. 分布式评估收集:
gatherer = DistributedTensorGatherer(world_size=4, num_samples=1000)
for batch in eval_dataloader:
preds = model(**batch).logits
gatherer.add_arrays(preds.cpu().numpy())
all_preds = gatherer.finalize() # 收集所有进程结果
2. 参数解析:
parser = HfArgumentParser((ModelArguments, DataArguments, TrainingArguments))
model_args, data_args, training_args = parser.parse_json_file("config.json")
3. FP16 训练调试:
# 监控第10-15批次
debugger = DebugUnderflowOverflow(
model,
trace_batch_nums=[10, 11, 12, 13, 14, 15],
abort_after_batch_num=15
)
trainer = Trainer(..., debug=debugger)
trainer.train()
生成工具
生成输出接口(ModelOutput 子类)
| 名称 | 用途 | 场景 | 参数作用 | 样例 |
|---|---|---|---|---|
GenerateDecoderOnlyOutput | 存储 decoder-only 模型非 beam 搜索生成结果 | GPT 类模型生成 | sequences:生成的 token 序列;scores:预测分数;attentions:注意力权重 | model.generate(return_dict_in_generate=True) |
GenerateEncoderDecoderOutput | 存储 encoder-decoder 模型非 beam 搜索生成结果 | T5/BART 类模型生成 | 增加 encoder_attentions 和 cross_attentions 等 encoder 特有属性 | 同上 |
GenerateBeamDecoderOnlyOutput | 存储 decoder-only 模型 beam 搜索生成结果 | GPT 类模型的 beam 搜索 | 增加 sequences_scores 和 beam_indices 等 beam 特有属性 | model.generate(num_beams=4) |
GenerateBeamEncoderDecoderOutput | 存储 encoder-decoder 模型 beam 搜索生成结果 | T5/BART 类模型的 beam 搜索 | 包含 encoder 和 decoder 的 beam 相关信息 | 同上 |
生成工具(LogitsProcessor)
| 名称 | 用途 | 场景 | 参数作用 | 样例 |
|---|---|---|---|---|
TemperatureLogitsWarper | 控制输出随机性 | 提高/降低生成多样性 | temperature:>1 增加随机性,<1 降低随机性 | generate(temperature=0.7) |
TopKLogitsWarper | 限制采样到 Top K token | 提高生成质量 | top_k:保留的最高概率 token 数量 | generate(top_k=50) |
TopPLogitsWarper | 限制采样到累计概率 Top P 的 token | 平衡生成多样性和质量 | top_p:概率累计阈值(0.9-0.95) | generate(top_p=0.92) |
RepetitionPenaltyProcessor | 惩罚重复 token | 减少重复生成 | penalty:>1 惩罚重复,<1 鼓励重复 | generate(repetition_penalty=1.2) |
NoRepeatNGramProcessor | 禁止 n-gram 重复 | 避免短语重复 | ngram_size:禁止重复的 n-gram 长度 | generate(no_repeat_ngram_size=3) |
流式输出工具
| 名称 | 用途 | 场景 | 参数作用 | 样例 |
|---|---|---|---|---|
TextStreamer | 实时打印生成文本 | 控制台实时输出 | tokenizer:用于解码;skip_prompt:是否跳过提示 | generate(streamer=TextStreamer(tokenizer)) |
TextIteratorStreamer | 异步生成文本迭代器 | Gradio 等交互应用 | timeout:队列超时设置 | for text in streamer: ... |
使用示例
基础生成:
from transformers import GPT2LMHeadModel, GPT2Tokenizer
model = GPT2LMHeadModel.from_pretrained("gpt2")
tokenizer = GPT2Tokenizer.from_pretrained("gpt2")
inputs = tokenizer("Hello, my dog is", return_tensors="pt")
outputs = model.generate(**inputs)
带参数的高级生成:
outputs = model.generate(
**inputs,
do_sample=True,
top_k=50,
temperature=0.7,
max_length=100,
repetition_penalty=1.2
)
流式输出:
from transformers import TextStreamer
streamer = TextStreamer(tokenizer)
model.generate(**inputs, streamer=streamer, max_new_tokens=100)
关键点总结
- 输出结构:
generate()返回ModelOutput子类对象,可通过属性/元组/字典访问结果 - 参数控制:
output_scores=True获取预测分数return_dict_in_generate=True获取结构化输出max_length控制最大长度
- 处理器应用:
LogitsProcessor修改预测分数LogitsWarper调整采样分布
- 流式处理:
TextStreamer实时输出文本TextIteratorStreamer支持异步迭代
注意:完整接口列表包含 PyTorch/TensorFlow/FLAX 的实现变体,此处展示核心 PyTorch 接口。实际应用需根据框架选择对应实现。
图像处理工具
图像变换工具(image_transforms)
| 名称 | 用途 | 场景 | 参数作用 | 样例 |
|---|---|---|---|---|
center_crop | 中心裁剪图像 | 图像预处理 | size:目标尺寸;data_format:通道格式(channels_first/last) | center_crop(image, (224,224)) |
normalize | 标准化图像 | 输入归一化 | mean/std:均值/标准差;支持单值或通道级参数 | normalize(image, mean=0.5, std=0.5) |
resize | 调整图像尺寸 | 尺寸统一化 | size:目标尺寸;resample:重采样方法(如 BILINEAR) | resize(image, (256,256), resample=PILImageResampling.BICUBIC) |
pad | 图像填充 | 尺寸标准化 | padding:填充量;mode:填充模式(constant/reflect 等) | pad(image, ((10,20),(5,15)), mode='constant') |
rescale | 缩放像素值 | 数值范围调整 | scale:缩放因子 | rescale(image, scale=1/255) |
to_pil_image | 转为 PIL 图像对象 | 格式转换 | do_rescale:是否缩放至 0-255;image_mode:PIL 模式 | to_pil_image(tensor) |
center_to_corners_format | 边界框中心格式 → 角点格式 | 目标检测 | bboxes_center:(center_x, center_y, width, height) | corners = center_to_corners_format(bboxes) |
corners_to_center_format | 边界框角点格式 → 中心格式 | 目标检测 | bboxes_corners:(x1, y1, x2, y2) | centers = corners_to_center_format(corners) |
id_to_rgb/rgb_to_id | ID 与 RGB 互转 | 语义分割 | id_map/color:映射数据 | rgb = id_to_rgb(id_map) |
图像处理器基类(ImageProcessingMixin)
| 名称 | 用途 | 场景 | 参数作用 | 样例 |
|---|---|---|---|---|
from_pretrained | 加载预训练处理器 | 模型部署 | pretrained_model_name_or_path:模型 ID/路径;revision:版本 | CLIPImageProcessor.from_pretrained("openai/clip-vit-base-patch32") |
save_pretrained | 保存处理器配置 | 模型保存 | save_directory:保存路径;push_to_hub:是否上传到 Hub | processor.save_pretrained("./my_model") |
push_to_hub | 上传处理器到 Hub | 模型共享 | repo_id:仓库 ID;private:是否私有;token:访问令牌 | processor.push_to_hub("my-org/my-processor") |
fetch_images | 下载 URL 转 PIL 图像 | 远程数据预处理 | image_url_or_urls:单个/多个 URL | imgs = fetch_images(["http://example.com/img.jpg"]) |
to_dict | 序列化为字典 | 配置导出 | 无参数 | config_dict = processor.to_dict() |
to_json_string | 序列化为 JSON 字符串 | 配置传输 | 无参数 | json_str = processor.to_json_string() |
register_for_auto_class | 注册自定义处理器到 AutoClass | 扩展框架 | auto_class:目标自动类(默认 AutoImageProcessor) | processor.register_for_auto_class() |
使用示例
图像预处理流程:
from transformers import CLIPImageProcessor, image_transforms
# 加载预训练处理器
processor = CLIPImageProcessor.from_pretrained("openai/clip-vit-base-patch32")
# 图像变换组合
def process_image(image):
image = image_transforms.resize(image, (256,256))
image = image_transforms.center_crop(image, (224,224))
image = image_transforms.normalize(image, mean=[0.485,0.456,0.406], std=[0.229,0.224,0.225])
return processor(image, return_tensors="pt")
# 保存自定义配置
processor.save_pretrained("custom_processor")
核心功能总结
- 图像变换:
- 几何变换:裁剪/缩放/填充
- 数值变换:归一化/标准化
- 格式转换:tensor/PIL/边界框格式互转
- 处理器管理:
- 支持从 Hub 加载/保存预训练配置
- 无缝集成到 transformers pipeline
- 支持自定义处理器注册
- 边界框处理:
- 中心格式 ↔ 角点格式转换
- 适用于目标检测任务
- 远程数据支持:
- 直接从 URL 获取图像
- 自动转换为 PIL 格式
注意:所有函数支持多种输入格式(numpy array/PIL/tensor)并自动处理通道维度(
channels_first/last)。
音频处理工具
音频特征提取工具(audio_utils)
| 名称 | 用途 | 场景 | 参数作用 | 样例 |
|---|---|---|---|---|
hertz_to_mel | 赫兹转梅尔频率 | 语音特征提取 | freq:输入频率;mel_scale:梅尔尺度类型(htk/kaldi/slaney) | mel = hertz_to_mel(1000.0) |
mel_to_hertz | 梅尔频率转赫兹 | 频率尺度转换 | mels:梅尔值;mel_scale:梅尔尺度类型 | hz = mel_to_hertz(1000.0) |
mel_filter_bank | 生成梅尔滤波器组 | 梅尔频谱计算 | num_frequency_bins:频率 bin 数;num_mel_filters:滤波器数量;min/max_frequency:频率范围 | filters = mel_filter_bank(257, 80, 20, 8000, 16000) |
optimal_fft_length | 计算最佳 FFT 长度 | 频谱分析优化 | window_length:窗口长度(自动取最近的 2 的幂) | fft_len = optimal_fft_length(400) # 返回512 |
window_function | 生成窗函数 | 信号加窗 | window_length:窗口长度;name:窗类型(hann/hamming 等);periodic:周期窗 | window = window_function(400, 'hann') |
spectrogram | 计算频谱图 | 音频特征提取 | waveform:输入波形;window:窗函数;frame/hop_length:帧参数;power:幅度/功率谱 | spec = spectrogram(waveform, window, 400, 160) |
power_to_db | 功率谱转分贝 | 特征归一化/可视化 | spectrogram:功率谱;reference:参考值;min_value:最小阈值 | db_spec = power_to_db(spec, reference=np.max(spec)) |
amplitude_to_db | 幅度谱转分贝 | 特征归一化/可视化 | spectrogram:幅度谱;reference:参考值;min_value:最小阈值 | db_spec = amplitude_to_db(spec) |
关键参数详解
-
梅尔滤波器组:
mel_scale:支持三种标准:htk:HTK 工具包标准kaldi:Kaldi 语音识别工具包标准slaney:MATLAB Auditory Toolbox 标准
triangularize_in_mel_space:True时在梅尔空间应用三角滤波器
-
频谱计算:
dither:添加高斯噪声(>0)避免数值下溢preemphasis:预加重滤波器系数log_mel:支持"log"、"log10"、"dB"三种对数转换remove_dc_offset:移除直流偏移
-
分贝转换:
reference:0dB 对应的参考值db_range:动态范围限制(如 80dB)min_value:避免log(0)的阈值
使用示例
完整的梅尔频谱提取流程:
import numpy as np
from transformers.audio_utils import *
# 生成汉宁窗
window = window_function(400, 'hann')
# 计算最佳 FFT 长度
fft_len = optimal_fft_length(400) # 512
# 创建梅尔滤波器组
mel_filters = mel_filter_bank(
num_frequency_bins=fft_len//2 + 1,
num_mel_filters=80,
min_frequency=20,
max_frequency=8000,
sampling_rate=16000,
mel_scale='htk'
)
# 生成示例音频(1秒,16kHz)
waveform = np.random.randn(16000)
# 计算梅尔频谱
mel_spec = spectrogram(
waveform,
window=window,
frame_length=400,
hop_length=160,
fft_length=fft_len,
mel_filters=mel_filters,
power=2.0, # 功率谱
log_mel='dB' # 分贝梅尔谱
)
# 转换为分贝尺度(备选方案)
db_mel = power_to_db(mel_spec, reference=1.0, min_value=1e-10)
核心功能总结
- 频率尺度转换:
- 线性赫兹 ↔ 感知梅尔尺度
- 支持三种行业标准转换方式
- 滤波器设计:
- 梅尔滤波器组生成
- 可定制滤波器数量和频率范围
- 频谱分析:
- 短时傅里叶变换(STFT)
- 支持幅度谱/功率谱
- 可选的预加重/加噪处理
- 特征后处理:
- 线性 → 对数尺度转换
- 分贝归一化
- 动态范围控制
这些工具通常被集成在音频特征提取器(如
WhisperFeatureExtractor)中,用于语音识别、音频分类等任务的预处理。
通用工具
通用工具总结
| 类别 | 名称 | 用途 | 场景 | 参数作用 | 样例 |
|---|---|---|---|---|---|
| 枚举类 | ExplicitEnum | 提供更明确的错误消息 | 需要精确错误提示的枚举场景 | value:枚举值;其他参数用于元数据 | class ModelType(ExplicitEnum): TF="tf"; PT="pt" |
PaddingStrategy | 定义 tokenizer 的 padding 策略 | tokenizer 调用时的 padding 参数 | 预定义值:LONGEST、MAX_LENGTH、DO_NOT_PAD 等 | tokenizer(text, padding=PaddingStrategy.MAX_LENGTH) | |
TensorType | 定义 tokenizer 返回张量类型 | tokenizer 调用时的 return_tensors 参数 | 预定义值:PYTORCH、TENSORFLOW、NUMPY、JAX 等 | tokenizer(text, return_tensors=TensorType.PYTORCH) | |
| 文档装饰器 | add_start_docstrings | 为类/函数添加起始文档字符串 | 统一 API 文档格式 | *docstr:要添加的文档字符串 | @add_start_docstrings("模型说明") class BertModel: |
add_end_docstrings | 为类/函数添加结束文档字符串 | 统一 API 文档格式 | *docstr:要添加的文档字符串 | @add_end_docstrings("\n返回: 输出张量") | |
add_code_sample_docstrings | 添加含代码示例的文档 | 提供使用示例 | checkpoint:模型名;output_type:输出类型;expected_output:预期输出 | 用于模型前向传播方法的装饰 | |
replace_return_docstrings | 替换返回类型文档 | 统一返回说明格式 | output_type:输出类型描述;config_class:配置类 | 用于模型 forward 方法的文档装饰 | |
| 特殊属性 | cached_property | 缓存属性计算结果 | 避免重复计算昂贵操作 | 无直接参数,作为装饰器使用 | @cached_property def config(self): return load_config() |
| 惰性加载 | _LazyModule | 按需导入模块内容 | 减少大型库的初始化时间 | name:模块名;module_file:文件路径;import_structure:导入结构 | 内部使用,用于组织 transformers 库的子模块 |
关键工具详解
-
枚举类:
- 提供 IDE 自动补全支持
- 确保参数值合法性
- 示例:
PaddingStrategy.MAX_LENGTH确保使用有效的填充策略
-
文档装饰器:
- 自动生成统一格式的 API 文档
- 支持代码示例插入
- 示例:为模型类添加标准化的说明文档
-
缓存属性:
- 首次访问时计算并缓存结果
- 后续访问直接返回缓存值
- 示例:模型配置加载只需执行一次
-
惰性模块:
- 延迟导入子模块直到实际使用
- 显著减少库导入时间
- 示例:
transformers.models按需加载具体模型实现
使用示例
枚举类使用:
from transformers import PaddingStrategy, TensorType
from transformers.utils import ExplicitEnum
class ModelType(ExplicitEnum):
TF = "tf"
PT = "pt"
# 在 tokenizer 中使用枚举
encoded = tokenizer(
text,
padding=PaddingStrategy.MAX_LENGTH,
return_tensors=TensorType.PYTORCH
)
缓存属性示例:
class ModelLoader:
@cached_property
def heavy_config(self):
print("Loading config...")
return load_huge_config_file()
loader = ModelLoader()
config1 = loader.heavy_config # 首次加载
config2 = loader.heavy_config # 直接返回缓存
文档装饰器示例:
@add_start_docstrings("BERT模型实现")
@add_end_docstrings("\n返回: <torch.Tensor>")
class BertModel:
@add_code_sample_docstrings(
checkpoint="bert-base-uncased",
output_type="last_hidden_state"
)
def forward(self, inputs):
return outputs
这些工具主要服务于库开发者,用于构建一致、高效的 API 接口,普通用户更多是通过预定义枚举值(如
PaddingStrategy)和装饰生成的文档来受益。
时序数据工具
时间序列核心工具总结
| 名称 | 用途 | 场景 | 参数作用 | 样例 |
|---|---|---|---|---|
NormalOutput | 定义正态分布输出 | 适用于连续值预测,如销售额预测、温度预测等 | dim:输出维度(默认 1 维) | model.output_distribution = NormalOutput(dim=1) |
StudentTOutput | 定义学生 T 分布输出 | 适用于存在异常值的预测场景,如金融数据预测 | dim:输出维度(默认 1 维) | model.output_distribution = StudentTOutput() |
NegativeBinomialOutput | 定义负二项分布输出 | 适用于计数数据预测,如客流量预测、事件发生率预测等 | dim:输出维度(默认 1 维) | model.output_distribution = NegativeBinomialOutput(dim=2) |
关键特性详解
-
分布类型:
- 正态分布:对称钟形曲线,适用于大多数连续变量预测
- 学生 T 分布:重尾分布,对异常值更鲁棒
- 负二项分布:离散分布,适用于过离散计数数据
-
参数作用:
dim:控制输出分布的维度dim=1:单变量预测dim>1:多变量联合预测
使用示例
from transformers import TimeSeriesTransformerForPrediction
from transformers.time_series_utils import NormalOutput, StudentTOutput
# 使用正态分布输出的时间序列模型
model_normal = TimeSeriesTransformerForPrediction(
config=config,
output_distribution=NormalOutput(dim=1)
)
# 使用学生T分布输出的金融预测模型
model_studentt = TimeSeriesTransformerForPrediction(
config=config,
output_distribution=StudentTOutput(dim=3) # 3维联合预测
)
# 使用负二项分布的客流量预测模型
model_negbin = TimeSeriesTransformerForPrediction(
config=config,
output_distribution=NegativeBinomialOutput(dim=1)
)
# 预测并获取分布参数
outputs = model_normal(inputs)
loc = outputs.loc # 均值参数
scale = outputs.scale # 标准差参数
典型应用场景
-
零售预测:
- 正态分布:预测商品日销售额
- 负二项分布:预测顾客到店人数
-
气象预测:
- 正态分布:预测温度变化
- 学生 T 分布:预测极端天气事件概率
-
经济预测:
- 学生 T 分布:预测股票收益率(处理肥尾特性)
- 正态分布:预测 GDP 增长
这些分布输出类通常与
TimeSeriesTransformerForPrediction等时间序列预测模型结合使用,为模型提供概率预测能力,不仅能预测未来值,还能量化预测的不确定性。