从零玩转 Hugging Face:用 BERT 做中文分类、用 GPT-2 做中文文本生成
一篇个人学习记录:Hugging Face 生态入门,覆盖环境安装、模型下载、在线 API 与本地调用两种方式、两个实战 Demo、生成参数详解与常见坑。
1. 为什么是 Hugging Face
Hugging Face(以及国内的 ModelScope 魔搭社区)是目前最主流的开源模型仓库与社区。2019 年时社区里基本只有自然语言模型,如今已经覆盖了几乎所有模态:
| 分类 | 说明 | 典型任务 |
|---|---|---|
| Multimodal | 多模态 | 图文理解、图文生成 |
| Computer Vision | 计算机视觉 | 图像分类、目标检测 |
| Natural Language Processing | 自然语言处理 | 分类、生成、问答 |
| Audio | 音频 | 语音识别、语音合成 |
| Tabular | 表格数据 | 表格预测 |
| Other | 其他 | 强化学习、图模型等 |
配合 transformers 库,把「下载模型 + 加载 + 推理」压缩成了几行代码,这就是入门门槛低的原因。
2. 环境准备(Windows)
# 1. 安装 Python 与 Anaconda(官网下载对应版本并配置环境变量)
# 2. 安装 CUDA(以 12.6 为例,Windows 网络安装包)
# https://developer.download.nvidia.com/compute/cuda/12.6.0/network_installers/cuda_12.6.0_windows_network.exe
# 3. 安装 PyTorch(需与 CUDA 版本匹配,这里是 cu126)
pip3 install --pre torch torchvision --index-url https://download.pytorch.org/whl/cu126
# 4. 安装 transformers(模型加载与推理)
pip install transformers
# 5. 数据集库(可选,加载数据集时使用)
pip install datasets
小提示:国内网络下载 Hugging Face 模型较慢时,可改用 ModelScope 魔搭下载,或使用 HF 镜像站
hf-mirror.com。
3. 两种使用模型的方式
方式一:Inference API 在线调用(不推荐)
import requests
API_URL = "https://api-inference.huggingface.co/models/uer/gpt2-chinese-cluecorpussmall"
# 不使用 Token 进行匿名访问
response = requests.post(API_URL, json={"input": "你好,hugging face"})
print(response.json())
为什么不推荐:在线 API 依赖网络环境,国内访问不稳定、速度慢,还有免费额度限制。示例代码只是为了展示「先有模型可用」的最快路径,真正使用请走方式二。
方式二:把模型下载到本地调用(推荐)
基于 transformers 构建,模型和分词器一一对应,用 cache_dir 指定本地缓存位置:
from transformers import AutoModelForCausalLM, AutoTokenizer
model_name = "uer/gpt2-chinese-cluecorpussmall" # 注意拼写:cluecorpussmall
cache_dir = "model/uer/gpt2-chinese-cluecorpussmall"
AutoModelForCausalLM.from_pretrained(model_name, cache_dir=cache_dir) # 下载模型
AutoTokenizer.from_pretrained(model_name, cache_dir=cache_dir) # 下载分词器
下载一次之后即可离线使用,也便于反复实验,不依赖网络。
4. 实战一:GPT-2 中文文本生成
4.1 本地离线调用
from transformers import AutoModelForCausalLM, AutoTokenizer, pipeline
# 设置模型路径:要找 config.json 所在目录
# Windows 路径含反斜杠,字符串前加 r 防止转义
model_dir = r"D:\PycharmProjects\demo_1\transformers_test\model\uer\gpt2-chinese-cluecorpussmall\models--uer--gpt2-chinese-cluecorpussmall\snapshots\c2c0249d8a2731f269414cc3b22dff021f8e07a3"
model = AutoModelForCausalLM.from_pretrained(model_dir) # 加载模型
tokenizer = AutoTokenizer.from_pretrained(model_dir) # 加载分词器
generator = pipeline("text-generation", model=model, tokenizer=tokenizer, device="cuda")
output = generator(
"你好,我是一款语言模型,", # 种子文本(prompt)
max_length=50, # 生成文本最大长度(token 数)
num_return_sequences=1, # 返回几段独立生成的文本
truncation=True, # 输入超长时是否截断
temperature=0.7, # 随机性:越低越保守,越高越多样
top_k=50, # 每步只从概率最高的 k 个候选词中选
top_p=0.9, # 核采样:从累积概率达 p 的词集合中采样
clean_up_tokenization_spaces=True # 是否清理分词引入的多余空格
)
print(output)
注意:
device参数不支持字符串"gpu",请用"cuda"(或0、"cpu");新版 transformers 也可用device_map="auto"。
4.2 生成参数详解
| -- -- --参 数-- -- -- | 作用 | 典型值 / 说明 |
|---|---|---|
max_length | 生成文本的最大长度(token 数,含输入) | 50~100;想只算新增内容可用 max_new_tokens |
num_return_sequences | 返回几段独立生成的文本 | 1~3,用于对比多种生成效果 |
truncation | 输入超过模型上限时是否截断 | True,避免报错 |
temperature | 采样温度:先对 logits 除以 T 再做 softmax | 0.7~1.0;T 越小越保守稳定,越大越多样,T=0 退化为贪心 |
top_k | 每步只从概率最高的 k 个候选词中采样 | 40~50;k=1 等于贪心 |
top_p | 核采样:从累积概率达到 p 的候选集里采样 | 0.9;候选数自适应,比固定 k 更灵活 |
clean_up_tokenization_spaces | 是否清理分词器拼接产生的多余空格 | True |
关键点:temperature / top_k / top_p 只在采样模式下生效,pipeline 中建议显式传 do_sample=True 确保生效;三者可以组合使用(先用 top_k/top_p 圈定候选,再用温度调节分布形状)。
4.3 特殊字符与模型局限
- 特殊 token:
UNK(未知)、SEP(分隔)、PAD(填充)、CLS(分类)、MASK(掩码) - 该模型词表 21128 个字符,权重文件约 401M,属于 small 版本
- 效果不好是正常的:生成参数只能改善多样性与重复度,能力上限由模型规模决定;想要更好效果,可以换更大的中文模型(更大的 GPT2-chinese 版本、CPM、中文 Llama 等),但对显存要求也更高
5. 实战二:BERT 中文文本分类
5.1 下载并加载 bert-base-chinese
from transformers import BertTokenizer, BertForSequenceClassification, pipeline
model_dir = r"model\bert-base-chinese"
model = BertForSequenceClassification.from_pretrained("bert-base-chinese", cache_dir=model_dir)
tokenizer = BertTokenizer.from_pretrained("bert-base-chinese", cache_dir=model_dir)
classifier = pipeline("text-classification", model=model, tokenizer=tokenizer, device="cuda")
result = classifier("你好,我是一款语言模型")
print(result)
5.2 分层术语的作用
BertForSequenceClassification 内部 = BERT 编码器 + 一个分类头:
| 术语 | 作用 |
|---|---|
| Embedding 词嵌入 | 把 token id 查表映射成稠密向量,文本进入模型的入口 |
| Encoder 编码器 | 12 层 Transformer,把整句上下文编码进每个 token |
| Pooling 池化 | 把整句浓缩成一个定长句向量(分类场景常用 [CLS] 位的输出) |
| Dropout 随机失活 | 训练时按概率随机置零部分神经元防过拟合,推理时关闭 |
| Classifier 分类头 | 线性层,把 hidden_size 压缩到 num_labels 个 logits |
| Softmax 归一化 | 把 logits 转成和为 1 的概率分布,即输出的 score |
5.3 流程示意
flowchart TD
A["输入文本:你好,我是一款语言模型"] --> B["BertTokenizer 分词 + [CLS]/[SEP]"]
B --> C["Encoder 12 层 Transformer"]
C --> D["Pooling 取 [CLS] 句向量"]
D --> E["Dropout(训练时随机失活)"]
E --> F["Classifier 分类头 → 2 个 logits"]
F --> G["Softmax → 概率输出 [{'label': 'LABEL_1', 'score': 0.98}]"]
5.4 模型输出概率
pipeline("text-classification") 返回 [{'label': 'LABEL_0'/'LABEL_1', 'score': 0.98}],score 就是 Softmax 后的概率;也可以自己取 model(...).logits 再手动 softmax。外部替代方案(如百度大脑 AI 开放平台的文本情感分析)走的是 API 路线,与本地 transformers 调用是两条路。
6. 加载数据集
from datasets import load_dataset, load_from_disk
# 在线加载数据集
dataset = load_dataset("glue", "mrpc")
print(dataset)
# 从本地磁盘加载数据集
dataset = load_from_disk("./my_dataset")
print(dataset)
在线加载需要网络;load_from_disk 适合先下载保存好、后续离线复用的场景。
7. 常见坑速查
| 报错 / 问题 | 原因 | 解决 |
|---|---|---|
device="gpu" 报错 | pipeline 不识别字符串 "gpu" | 用 device="cuda" / 0 / "cpu",或 device_map="auto" |
max_lengh 报错 | 参数拼写错误 | 改为 max_length |
| 下载 404 | 模型名拼错 | 正确仓库名:uer/gpt2-chinese-cluecorpussmall |
| Windows 路径报错 | \ 被当作转义符 | 字符串前加 r 前缀 |
| 本地加载失败 | 目录不指向模型 | 指向含 config.json 的目录(snapshots 内那一层) |
| 生成长度不符预期 | max_length 把输入也计入 | 改用 max_new_tokens |
8. 结语
Hugging Face 把「下载模型、加载、推理」压缩成了几行代码,但真正的学习重点在 pipeline 背后:模型与分词器的对应关系、分类头与生成采样的区别、参数如何影响输出。下一步建议:换更大的中文模型试试效果差异、用 GLUE 数据集微调自己的分类器、读一读 BERT / GPT-2 的原始论文。
