模型加载与使用
本章将深入介绍如何在 Transformers 中加载和使用预训练模型,包括 AutoClass 的使用、模型配置的读取和修改、以及不同任务类型模型的选择。
模型架构概述
三个核心类
每个预训练模型都由三个核心类组成:
┌─────────────────────────────────────────────────────────────┐
│ 模型核心架构 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────┐ │
│ │ PreTrainedConfig │ 模型配置:定义模型的所有超参数 │
│ │ │ - 隐藏层维度 │
│ │ │ - 注意力头数量 │
│ │ │ - 层数 │
│ │ │ - 词汇表大小 │
│ └────────┬─────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ PreTrainedModel │ 模型实现:具体的神经网络架构 │
│ │ │ - Transformer 层 │
│ │ │ - 注意力机制 │
│ │ │ - 任务输出层 │
│ └────────┬─────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ Preprocessor │ 预处理器:将原始输入转换为模型输入 │
│ │ (Tokenizer) │ - 分词 │
│ │ │ - 构建 token 序列 │
│ │ │ - 添加特殊标记 │
│ └─────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
模型命名规范
Transformers 中的模型类遵循统一的命名规则:
| 后缀 | 用途 | 示例 |
|---|---|---|
Model | 基础编码器/解码器 | BertModel, GPT2Model |
ForCausalLM | 因果语言建模(自回归生成) | GPT2LMHeadModel |
ForMaskedLM | 掩码语言建模 | BertForMaskedLM |
ForSequenceClassification | 序列分类 | BertForSequenceClassification |
ForTokenClassification | Token 分类(NER 等) | BertForTokenClassification |
ForQuestionAnswering | 问答任务 | BertForQuestionAnswering |
ForConditionalGeneration | 条件生成(翻译/摘要) | T5ForConditionalGeneration |
ForMultipleChoice | 多选任务 | BertForMultipleChoice |
ForImageClassification | 图像分类 | ViTForImageClassification |
AutoClass 自动加载
AutoModel 和 AutoTokenizer
使用 AutoClass 可以自动推断模型架构,无需手动指定模型类:
from transformers import AutoModel, AutoTokenizer, AutoConfig
# 模型标识符
model_name = "bert-base-uncased"
# 自动加载模型(返回基础编码器)
model = AutoModel.from_pretrained(model_name)
# 自动加载分词器
tokenizer = AutoTokenizer.from_pretrained(model_name)
# 自动加载配置
config = AutoConfig.from_pretrained(model_name)
print(f"模型类型: {type(model)}")
print(f"分词器类型: {type(tokenizer)}")
print(f"隐藏层维度: {config.hidden_size}")
print(f"注意力头数: {config.num_attention_heads}")
print(f"层数: {config.num_hidden_layers}")
任务特定模型加载
根据任务类型选择对应的模型类:
from transformers import (
AutoModel, # 基础编码器
AutoModelForSequenceClassification, # 文本分类
AutoModelForTokenClassification, # Token 分类
AutoModelForQuestionAnswering, # 问答
AutoModelForCausalLM, # 因果语言模型
AutoModelForMaskedLM, # 掩码语言模型
AutoModelForSeq2SeqLM, # 序列到序列模型
)
# 加载用于特征提取的编码器
encoder_model = AutoModel.from_pretrained("bert-base-uncased")
# 加载用于文本分类的模型
clf_model = AutoModelForSequenceClassification.from_pretrained("bert-base-uncased")
# 加载用于命名实体识别的模型
ner_model = AutoModelForTokenClassification.from_pretrained("bert-base-uncased", num_labels=9)
# 加载用于文本生成的模型
gen_model = AutoModelForCausalLM.from_pretrained("gpt2")
模型配置
读取配置
from transformers import AutoConfig
# 加载完整配置
config = AutoConfig.from_pretrained("bert-base-uncased")
# 查看配置属性
print(f"模型名称: {config.model_type}")
print(f"隐藏层维度: {config.hidden_size}")
print(f"中间层维度: {config.intermediate_size}")
print(f"注意力头数: {config.num_attention_heads}")
print(f"隐藏层数: {config.num_hidden_layers}")
print(f"词汇表大小: {config.vocab_size}")
print(f"最大位置嵌入: {config.max_position_embeddings}")
print(f"隐藏层 dropout: {config.hidden_dropout_prob}")
print(f"注意力 dropout: {config.attention_probs_dropout_prob}")
修改配置
from transformers import AutoConfig, AutoModel
# 加载基础配置并修改
config = AutoConfig.from_pretrained("bert-base-uncased")
config.num_labels = 5 # 修改为 5 类分类
# 使用修改后的配置初始化模型
model = AutoModel.from_pretrained("bert-base-uncased", config=config)
从头创建配置
from transformers import BertConfig, BertModel
# 创建自定义配置
config = BertConfig(
vocab_size=30000, # 词汇表大小
hidden_size=768, # 隐藏层维度
num_hidden_layers=12, # Transformer 层数
num_attention_heads=12, # 注意力头数
intermediate_size=3072, # FFN 中间层维度
hidden_dropout_prob=0.1, # Dropout 概率
attention_probs_dropout_prob=0.1,
max_position_embeddings=512,
)
# 使用自定义配置创建模型
model = BertModel(config)
模型加载参数
基本参数
from transformers import AutoModel
model = AutoModel.from_pretrained(
pretrained_model_name_or_path="bert-base-uncased",
config=config, # 可选:自定义配置
cache_dir=None, # 模型缓存目录
force_download=False, # 强制重新下载
resume_download=False, # 断点续传
proxies=None, # 代理设置
output_loading_info=False, # 是否返回加载信息
local_files_only=False, # 仅使用本地文件
use_safetensors=False, # 使用安全张量格式
)
设备和数据类型
import torch
from transformers import AutoModel
# CPU 加载
model = AutoModel.from_pretrained("bert-base-uncased", device_map="cpu")
# GPU 加载
model = AutoModel.from_pretrained("bert-base-uncased")
model = model.to("cuda")
# 自动设备映射(用于大模型)
model = AutoModel.from_pretrained(
"bert-base-uncased",
device_map="auto" # 自动分配到可用设备
)
# 数据类型控制
model = AutoModel.from_pretrained(
"bert-base-uncased",
torch_dtype=torch.float16, # 使用半精度
dtype="auto", # 自动选择数据类型
)
量化加载
# 8-bit 量化(需要 bitsandbytes 库)
model = AutoModel.from_pretrained(
"bert-base-uncased",
load_in_8bit=True
)
# 4-bit 量化
model = AutoModel.from_pretrained(
"meta-llama/Llama-2-7b-hf",
load_in_4bit=True,
bnb_4bit_compute_dtype=torch.float16
)
模型使用
基本推理
import torch
from transformers import AutoModel, AutoTokenizer
# 加载模型和分词器
model_name = "bert-base-uncased"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModel.from_pretrained(model_name)
# 准备输入
text = "The quick brown fox jumps over the lazy dog"
inputs = tokenizer(text, return_tensors="pt")
# 移动到 GPU(如果有)
if torch.cuda.is_available():
model = model.to("cuda")
inputs = {k: v.to("cuda") for k, v in inputs.items()}
# 推理
with torch.no_grad():
outputs = model(**inputs)
# outputs.last_hidden_state: [batch_size, seq_len, hidden_size]
# outputs.pooler_output: [batch_size, hidden_size] (如果模型有 pooler)
print(f"隐藏状态形状: {outputs.last_hidden_state.shape}")
print(f"池化输出形状: {outputs.pooler_output.shape}")
特征提取
# 提取句子的特征向量表示
import torch
from transformers import AutoModel, AutoTokenizer
model = AutoModel.from_pretrained("bert-base-uncased")
tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased")
text = "I love natural language processing"
inputs = tokenizer(text, return_tensors="pt")
with torch.no_grad():
outputs = model(**inputs)
# 方法1:使用 [CLS] token 的表示
cls_embedding = outputs.last_hidden_state[:, 0, :]
print(f"CLS 嵌入形状: {cls_embedding.shape}")
# 方法2:使用平均池化
attention_mask = inputs['attention_mask']
hidden_states = outputs.last_hidden_state
# 扩展 attention_mask
mask_expanded = attention_mask.unsqueeze(-1).expand(hidden_states.size()).float()
sum_embeddings = torch.sum(hidden_states * mask_expanded, 1)
sum_mask = mask_expanded.sum(1)
sum_mask = torch.clamp(sum_mask, min=1e-9)
mean_pooled = sum_embeddings / sum_mask
print(f"平均池化嵌入形状: {mean_pooled.shape}")
分类任务
from transformers import AutoModelForSequenceClassification, AutoTokenizer
import torch
# 加载预训练的分类模型
model_name = "distilbert-base-uncased-finetuned-sst-2-english"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForSequenceClassification.from_pretrained(model_name)
# 准备输入
texts = [
"I love this movie!",
"This is terrible."
]
inputs = tokenizer(texts, return_tensors="pt", padding=True, truncation=True)
# 推理
with torch.no_grad():
outputs = model(**inputs)
logits = outputs.logits
# 获取预测结果
predictions = torch.nn.functional.softmax(logits, dim=-1)
labels = ["NEGATIVE", "POSITIVE"]
for text, pred in zip(texts, predictions):
label_idx = pred.argmax().item()
print(f"{text} -> {labels[label_idx]} ({pred[label_idx]:.4f})")
模型保存和加载
保存模型
from transformers import AutoModel, AutoTokenizer
model = AutoModel.from_pretrained("bert-base-uncased")
tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased")
# 保存到本地
output_dir = "./my_model"
model.save_pretrained(output_dir)
tokenizer.save_pretrained(output_dir)
# 上传到 Hugging Face Hub
model.push_to_hub("my-username/my-model")
tokenizer.push_to_hub("my-username/my-model")
加载本地模型
from transformers import AutoModel, AutoTokenizer
# 加载本地保存的模型
model = AutoModel.from_pretrained("./my_model")
tokenizer = AutoTokenizer.from_pretrained("./my_model")
# 验证
text = "Hello, world!"
inputs = tokenizer(text, return_tensors="pt")
outputs = model(**inputs)
print(outputs.last_hidden_state.shape)
模型结构对比
BERT vs GPT vs T5
┌─────────────────────────────────────────────────────────────┐
│ 模型架构对比 │
├─────────────────────────────────────────────────────────────┤
│ │
│ BERT (Encoder-only) │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Input → [CLS] token1 token2 token3 → Output │ │
│ │ ↓ ↓ ↓ │ │
│ │ Self-Attn Self-Attn Self-Attn │ │
│ │ ↑ ↑ ↑ │ │
│ │ Bidirectional Context │ │
│ └─────────────────────────────────────────────────────┘ │
│ 特点:双向上下文理解,适用于理解任务 │
│ │
│ GPT (Decoder-only) │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Input → [SOS] token1 → token2 → token3 → [EOS] │ │
│ │ ↓ ↓ ↓ │ │
│ │ Masked Masked Masked │ │
│ │ Self-Attn Self-Attn Self-Attn │ │
│ │ ↑ ↑ ↑ │ │
│ │ Causal (只能看到左侧) │ │
│ └─────────────────────────────────────────────────────┘ │
│ 特点:单向自回归,适用于生成任务 │
│ │
│ T5 (Encoder-Decoder) │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Encoder: Input → [CLS] token1 token2 → Enc Output │ │
│ │ Decoder: [SOS] → token1 → token2 → [EOS] │ │
│ │ ↓ ↓ ↓ │ │
│ │ Cross-Attn Cross-Attn Cross-Attn │ │
│ │ ↑ ↑ ↑ │ │
│ │ Enc Output Enc Output Enc Output │ │
│ └─────────────────────────────────────────────────────┘ │
│ 特点:序列到序列,适用于转换任务 │
│ │
└─────────────────────────────────────────────────────────────┘
常见问题
1. 模型加载失败
# 检查网络连接
import os
os.environ['HF_ENDPOINT'] = 'https://hf-mirror.com' # 国内镜像
# 或使用代理
import requests
proxies = {
'http': 'http://proxy.example.com:8080',
'https': 'http://proxy.example.com:8080'
}
2. 显存不足
# 方案1:使用更小的模型
model = AutoModel.from_pretrained("distilbert-base-uncased")
# 方案2:使用量化
model = AutoModel.from_pretrained("bert-base-uncased", load_in_8bit=True)
# 方案3:使用 CPU
model = AutoModel.from_pretrained("bert-base-uncased", device_map="cpu")
3. 模型版本控制
# 使用特定的模型版本/提交
model = AutoModel.from_pretrained(
"bert-base-uncased",
revision="v1.0.0" # 指定版本标签或 commit hash
)
下一步
掌握模型加载和使用后,你可以继续学习: