从零玩转 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 再做 softmax0.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 的原始论文。