13
HuggingFace Transformers 入门
HuggingFace: BERT / GPT / PEFT
HuggingFace 是"AI 界的 GitHub":几十万预训练模型 + 统一 API。你不用自己训 BERT,三行代码下载别人训好的,微调几轮就能用。
核心三件套
| 组件 | 干什么 |
|---|---|
| AutoTokenizer | 把文本切成模型认识的 token id。 |
| AutoModelForXxx | 加载预训练模型,按任务选(ForSequenceClassification / ForCausalLM / ForTokenClassification ...)。 |
| Trainer | 封装好的训练循环,一行 fit。 |
Transformer 一句话原理
论注意力机制
Transformer 的核心是自注意力(Self-Attention):序列里每个词都和其他所有词算一个"相关度"权重,然后加权求和得到新的表示。一句话里,"它"这个词会自动关注到前文最近的名词。BERT 用双向注意力(看左右上下文),GPT 用单向注意力(只看左边)。多头注意力(Multi-Head)相当于多个角度看关系。
BERT 架构速览
# BERT-base 结构:
# - 12 层 Transformer Encoder
# - 隐藏维度 768
# - 12 个注意力头
# - 总参数 110M
# - 最大序列长度 512 token
# 特殊 token:
# [CLS] 句首,分类任务用它的输出
# [SEP] 句尾/句间分隔
# [PAD] padding
# [MASK] MLM 预训练时遮住的词
# 预训练任务:
# 1. MLM(Masked Language Model):遮住 15% 的词让模型猜
# 2. NSP(Next Sentence Prediction):判断两句话是否连续
一行代码用模型:pipeline
from transformers import pipeline
# 情感分析
classifier = pipeline("sentiment-analysis")
print(classifier("这个产品真的太好用了!"))
# [{'label': 'POSITIVE', 'score': 0.9998}]
# 文本生成
generator = pipeline("text-generation", model="gpt2")
print(generator("今天天气真不错,我们", max_new_tokens=30))
Tokenizer:文本 → token id
from transformers import AutoTokenizer
tok = AutoTokenizer.from_pretrained("bert-base-chinese")
out = tok("今天天气真不错", padding=True, truncation=True,
max_length=32, return_tensors="pt")
print(out.keys())
# dict_keys(['input_ids', 'token_type_ids', 'attention_mask'])
print(out["input_ids"])
# tensor([[ 101, 1962, 3698, 1962, 3362, 4696, 102]]) 101=[CLS], 102=[SEP]
完整案例:BERT 中文情感分析微调
from datasets import load_dataset
from transformers import (AutoTokenizer, AutoModelForSequenceClassification,
Trainer, TrainingArguments)
# 1. 加载数据集(比如 ChnSentiCorp 中文影评)
dataset = load_dataset("seamew/ChnSentiCorp")
model_name = "bert-base-chinese"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForSequenceClassification.from_pretrained(
model_name, num_labels=2
)
def tokenize(ex):
return tokenizer(ex["text"], truncation=True, max_length=128)
dataset = dataset.map(tokenize, batched=True)
dataset = dataset.rename_column("label", "labels")
dataset.set_format("torch", columns=["input_ids", "attention_mask", "labels"])
args = TrainingArguments(
output_dir="./bert-chinese",
learning_rate=2e-5,
per_device_train_batch_size=16,
num_train_epochs=3,
evaluation_strategy="epoch",
save_strategy="epoch",
load_best_model_at_end=True,
logging_steps=50,
)
trainer = Trainer(model=model, args=args,
train_dataset=dataset["train"],
eval_dataset=dataset["validation"])
trainer.train()
metrics = trainer.evaluate()
print(metrics)
# {'eval_accuracy': 0.94, 'eval_loss': 0.18}
Datasets 库:加载和处理数据集
from datasets import load_dataset
# 1. 加载 HuggingFace Hub 上的数据集
ds = load_dataset("imdb", split="train")
print(ds)
# Dataset({features: ['text', 'label'], num_rows: 25000})
# 2. map:批量预处理
def tokenize_fn(example):
return tokenizer(example["text"], truncation=True, max_length=128)
ds = ds.map(tokenize_fn, batched=True)
# 3. filter:按条件过滤
ds = ds.filter(lambda x: len(x["text"]) > 10)
# 4. shuffle + train_test_split
ds = ds.shuffle(seed=42)
split = ds.train_test_split(test_size=0.1)
# 5. 保存到磁盘,下次直接加载
ds.save_to_disk("./processed_dataset")
# 加载:load_from_disk("./processed_dataset")
Tokenizer 算法对比
| 算法 | 说明 |
|---|---|
| WordPiece | BERT 用,贪心合并高频子词。 |
| BPE | GPT 用,字节对编码,从字符开始合并。 |
| Unigram | T5 用,概率模型。 |
| SentencePiece | 多语言,直接处理原始文本(不预分词)。 |
文本生成:generate 的采样参数
from transformers import AutoModelForCausalLM, AutoTokenizer
model = AutoModelForCausalLM.from_pretrained("gpt2")
tok = AutoTokenizer.from_pretrained("gpt2")
inputs = tok("Once upon a time", return_tensors="pt")
out = model.generate(**inputs,
max_new_tokens=50,
do_sample=True,
temperature=0.7, # 越小越确定
top_p=0.9, # 核采样
top_k=50,
num_beams=3,
no_repeat_ngram_size=2 # 防止重复
)
print(tok.decode(out[0], skip_special_tokens=True))
PEFT / LoRA:微调大模型只训 0.1% 参数
论为什么需要 LoRA
7B 模型全微调要几十 GB 显存,普通人玩不起。LoRA(Low-Rank Adaptation):冻结原模型权重,只在旁边挂两个小矩阵(低秩分解),训练时只训这两个小矩阵。QLoRA 更进一步:把原模型量化到 4 位,再训 LoRA,一张 16GB 显卡就能微调 7B 模型。
from peft import LoraConfig, get_peft_model
peft_config = LoraConfig(
r=8, lora_alpha=32,
target_modules=["query", "value"],
lora_dropout=0.05, bias="none",
task_type="SEQ_CLS"
)
model = get_peft_model(model, peft_config)
model.print_trainable_parameters()
# trainable params: 294,912 || all params: 102,269,186 || trainable%: 0.288%
本章面试题
面试 · HuggingFace
Q1. BERT 和 GPT 的区别?
查看答案
BERT 是双向编码器(看上下文左右),适合理解类任务(分类/NER);GPT 是单向解码器(只看左边),适合生成类任务。
Q2. temperature 怎么调?
查看答案
温度低(0.1~0.3)确定、重复;温度高(0.8~1.0)随机、多样。创造性任务调高,事实性任务调低。
Q3. LoRA 为什么省显存?
查看答案
冻结原模型,只训低秩小矩阵,优化器状态和梯度只存小矩阵那部分。
Q4. padding 和 truncation 为什么要同时设?
查看答案
不定长文本批量喂入需要 padding 到同长;超过模型最大长度要 truncation。不设会报错或被截断丢信息。