transformers基础组件之Model
·
一:什么是Model Head
- Model Head是连接在模型后的层,通常为1个或多个全连接层。
- Model Head将模型的编码表示结果进行映射,以解决不同类型的任务。
二:Model的基本使用方法
2.1 模型的加载与保存
from transformers import AutoConfig, AutoModel, AutoTokenizer
2.1.1 在线加载
model = AutoModel.from_pretrained("hfl/rbt3")
2.1.2 模型下载
# 方法1:该方法会下载仓库下的所有文件
!git clone "https://huggingface.co/hfl/rbt3"
# 方法2:指定只下载某些文件,比如只下载pytorch框架的模型,而不下载TensorFlow的模型。因为有的仓库会提供几种框架的模型。
!git lfs clone "https://huggingface.co/hfl/rbt3" --include="*.bin"
# 方法3:排除掉仓库中的一些文件
!git lfs clone "https://huggingface.co/hfl/rbt3" --exclude="*.bin"
2.1.3 加载本地保存的模型
model = AutoModel.from_pretrained("rbt3") # 引号内填写模型的存储地址
2.14 模型加载参数
model.config
输出:
BertConfig {
"_attn_implementation_autoset": true,
"_name_or_path": "hfl/rbt3",
"architectures": [
"BertForMaskedLM"
],
"attention_probs_dropout_prob": 0.1,
"classifier_dropout": null,
"directionality": "bidi",
"hidden_act": "gelu",
"hidden_dropout_prob": 0.1,
"hidden_size": 768,
"initializer_range": 0.02,
"intermediate_size": 3072,
"layer_norm_eps": 1e-12,
"max_position_embeddings": 512,
"model_type": "bert",
"num_attention_heads": 12,
"num_hidden_layers": 3,
"output_past": true,
"pad_token_id": 0,
"pooler_fc_size": 768,
"pooler_num_attention_heads": 12,
"pooler_num_fc_layers": 3,
"pooler_size_per_head": 128,
"pooler_type": "first_token_transform",
"position_embedding_type": "absolute",
"transformers_version": "4.47.1",
"type_vocab_size": 2,
"use_cache": true,
"vocab_size": 21128
}
2.2 模型的调用
sen = "弱小的我也有大梦想!"
tokenizer = AutoTokenizer.from_pretrained("hfl/rbt3")
inputs = tokenizer(sen, return_tensors="pt")
inputs
输出:
{'input_ids': tensor([[ 101, 2483, 2207, 4638, 2769, 738, 3300, 1920, 3457, 2682, 8013, 102]]), 'token_type_ids': tensor([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]), 'attention_mask': tensor([[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]])}
2.2.1 不带Model Head的模型调用
model = AutoModel.from_pretrained("hfl/rbt3", output_attentions=True)
output = model(**inputs)
output
输出:
BaseModelOutputWithPoolingAndCrossAttentions(last_hidden_state=tensor([[[ 0.6804, 0.6664, 0.7170, ..., -0.4102, 0.7839, -0.0262],
[-0.7378, -0.2748, 0.5034, ..., -0.1359, -0.4331, -0.5874],
[-0.0212, 0.5642, 0.1032, ..., -0.3617, 0.4646, -0.4747],
...,
...,
[4.8866e-01, 2.6738e-04, 3.1088e-04, ..., 9.8990e-04,
1.7911e-02, 4.8672e-01],
[4.0732e-01, 3.8137e-02, 9.6832e-03, ..., 4.4490e-02,
2.2998e-02, 4.0793e-01],
[1.7047e-01, 3.6989e-02, 2.3646e-02, ..., 4.6833e-02,
2.5233e-01, 1.6721e-01]]]], grad_fn=<SoftmaxBackward0>)), cross_attentions=None)
2.2.2 带Model Head的模型调用
from transformers import AutoModelForSequenceClassification, BertForSequenceClassification
clz_model = AutoModelForSequenceClassification.from_pretrained("rbt3", num_labels=10)
clz_model(**inputs)
输出:
SequenceClassifierOutput(loss=None, logits=tensor([[ 0.3620, -0.2555, 0.3777, 0.0050, -0.0971, -0.0394, -0.8333, -0.0203,
0.0979, 0.5094]], grad_fn=<AddmmBackward0>), hidden_states=None, attentions=None)
从输出结果可以看到,输出的维度是我们指定的10维。也可以从模型的配置中查看到最后的输出维度。
clz_model.config.num_labels
输出:
10
三:BERT文本分类代码实例
step1 导入相关包
from transformers import AutoTokenizer, AutoModelForSequenceClassification
step2 加载数据
import pandas as pd
data = pd.read_csv("./ChnSentiCorp_htl_all.csv")
data
# 删除空数据
data = data.dropna()
data
step3 创建Dataset
from torch.utils.data import Dataset
"""
1. 创建自己的Dataset,继承torch中的Dataset
2. 实现三个必要的方法:
初始化方法__init__():初始化父类,加载自己的数据集。
__getitem__():定义如何返回一条数据。
__len__():返回数据集中数据的数量。
"""
class MyDataset(Dataset):
def __init__(self):
super().__init__()
self.data = pd.read_csv("./ChnSentiCorp_htl_all.csv")
self.data = self.data.dropna()
def __getitem__(self, index):
return self.data.iloc[index]["review"], self.data.iloc[index]["label"]
def __len__(self):
return len(self.data)
Step4 划分数据集
有了Dataset数据集后,还需要对数据集进行划分,一部分用于训练,一部分用于验证。
from torch.utils.data import random_split
# random_split 函数:该函数接受一个数据集和一个长度列表,并返回两个(或多个)子集。
# lengths=[0.9, 0.1]:指定分割的比例。在这个例子中,数据集将被分割为 90% 的训练集和 10% 的验证集。
trainset, validset = random_split(dataset, lengths=[0.9, 0.1])
len(trainset), len(validset)
Step5 创建Dataloader
有了划分后的Dataset还不够,因为Dataset中的__getitem__()一次只能取出一条数据,而我们训练时,需要按批次取出数据,所以需要一个数据加载器来满足我们的需求。
在创建数据加载器之前,我们需要定义一个函数来告诉数据加载器如何来处理批次数据(如:一条数据处理成多少维的向量,维度不够如何补全,维度超了是否截断等等)
import torch
tokenizer = AutoTokenizer.from_pretrained("hfl/rbt3")
def collate_func(batch):
texts, labels = [], []
for item in batch:
texts.append(item[0])
labels.append(item[1])
inputs = tokenizer(texts, max_length=128, padding="max_length", truncation=True, return_tensors="pt")
# inputs是一个字典,所以可以直接将labels放入字典中
inputs["labels"] = torch.tensor(labels)
return inputs
创建数据加载器:
from torch.utils.data import DataLoader
trainloader = DataLoader(trainset, batch_size=32, shuffle=True, collate_fn=collate_func)
validloader = DataLoader(validset, batch_size=64, shuffle=False, collate_fn=collate_func)
Step6 创建模型及优化器
from torch.optim import Adam
model = AutoModelForSequenceClassification.from_pretrained("hfl/rbt3")
if torch.cuda.is_available():
model = model.cuda()
# 优化器需要知道优化什么,以及如何优化。所以需要传入模型的参数和学习率
optimizer = Adam(model.parameters(), lr=2e-5)
Step7 训练与验证
def evaluate():
model.eval()
acc_num = 0
with torch.inference_mode():
for batch in validloader:
if torch.cuda.is_available():
batch = {k: v.cuda() for k, v in batch.items()}
output = model(**batch)
pred = torch.argmax(output.logits, dim=-1)
acc_num += (pred.long() == batch["labels"].long()).float().sum()
return acc_num / len(validset)
def train(epoch=3, log_step=100):
global_step = 0
for ep in range(epoch):
model.train()
for batch in trainloader:
if torch.cuda.is_available():
batch = {k: v.cuda() for k, v in batch.items()}
optimizer.zero_grad()
output = model(**batch)
output.loss.backward()
optimizer.step()
if global_step % log_step == 0:
print(f"ep: {ep}, global_step: {global_step}, loss: {output.loss.item()}")
global_step += 1
acc = evaluate()
print(f"ep: {ep}, acc: {acc}")
Step8 模型训练
train()
Step9 模型预测
sen = "我觉得这家酒店不错,饭很好吃!"
id2_label = {0: "差评!", 1: "好评!"}
model.eval()
with torch.inference_mode():
inputs = tokenizer(sen, return_tensors="pt")
inputs = {k: v.cuda() for k, v in inputs.items()}
logits = model(**inputs).logits
pred = torch.argmax(logits, dim=-1)
print(f"输入:{sen}\n模型预测结果:{id2_label.get(pred.item())}")
更简单的方法:使用之前我们讲解过的pipeline()
from transformers import pipeline
model.config.id2label = id2_label
pipe = pipeline("text-classification", model=model, tokenizer=tokenizer, device=0)
pipe(sen)
更多推荐

所有评论(0)