利用huggingface尝试的第一个简单的文本分类任务

'''
这是一个简单的文本分类任务,基本的流程步骤还是挺清晰完整的,和之前那个简单的cnn差不多,
用到了transformers包,还需用到huggingface的模型rbt3,
但是好像连接不上
'''
'''
遇到的问题:
1.导入的包不可用,从AutoModelForTokenClassification换成了AutoModelForSequenceClassification
2.模型加载不出来,然后选择将模型下载到本地进行加载,但是这样的话会非常耗内存
3.数据处理的问题,在处理完数据,进行训练的时候,没有处理好设备选择问题,导致部分数据在cpu,部分数据在gpu
'''
## step1 导入相关包
from transformers import AutoTokenizer, AutoModelForSequenceClassification
import torch

## step2 加载数据
import pandas as pd

data = pd.read_csv("./ChnSentiCorp_htl_all.csv")    # data的数据类型是DataFrame
data = data.dropna()

## step3 创建Dataset
'''
在这里将数据转换为dataset的格式,使得在训练过程中能够通过DataLoader按批次读取数据。
'''
from torch.utils.data import Dataset
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)


dataset = MyDataset()
## step4 划分数据集
from torch.utils.data import random_split

trainset, validset = random_split(dataset, lengths=[0.9, 0.1])

## step5 创建Dataloader
tokenizer = AutoTokenizer.from_pretrained("./hfl/rbt3") #加载一个预训练的分词器(Tokenizer),用于将输入的文本数据转换为模型可以理解的格式
def collate_func(batch):  # 自定义的数据合并函数,负责将一个批次(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")

    # 确保把所有输入移到正确的设备
    device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
    inputs = {key: value.to(device) for key, value in inputs.items()}
    inputs["labels"] = torch.tensor(labels).to(device)  # 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

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model = AutoModelForSequenceClassification.from_pretrained("./hfl/rbt3").to(device)
optimizer = Adam(model.parameters(), lr=2e-5)


# step7 训练与验证
def evaluate():
    model.eval()  # 设置模型为评估模式
    acc_num = 0
    # 打印模型设备信息(只在验证开始时打印一次)
    print(f"验证开始:\n模型设备: {next(model.parameters()).device}")
    with torch.no_grad():
        for batch in validloader:
            batch = {k: v.to(device) for k, v in batch.items()}  # 将数据移到指定设备
            # 只需要在第一次 batch 时打印一次输入数据设备信息
            if acc_num == 0:
                print(f"输入数据设备: {batch['input_ids'].device}")
            output = model(**batch)     #**是用来解包字典的操作符,**batch用于将batch字典中的所有键值对作为关键字参数传递给模型,使得代码更加简洁。它可以自动解包并传递所有需要的输入参数,避免了手动指定每个参数的麻烦
            pred = torch.argmax(output.logits, dim=-1)#logits是指神经网络最后一层的原始输出,通常是未经激活函数处理的原始分数
            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()  # 设置模型为训练模式
        # 打印模型和输入数据设备信息(只在每个 epoch 开始时打印一次)
        print(f"训练开始:第{ep}轮")
        print(f"模型设备: {next(model.parameters()).device}")#用next获取模型参数的第一个元素,从而能够获取该参数所在的设备
        for batch in trainloader:
            batch = {k: v.to(device) for k, v in batch.items()}  # 移动到正确设备
            # 只需要在第一次 batch 时打印一次输入数据设备信息
            if global_step == 0:
                print(f"输入数据设备: {batch['input_ids'].device}")
            optimizer.zero_grad()
            output = model(**batch)
            output.loss.backward()
            optimizer.step()
            if global_step % log_step == 0:
                print(f"global_step:{global_step}, 模型损失loss:{output.loss.item()}")
            global_step += 1
        acc = evaluate()  # 调用evaluate函数
        print(f"训练轮次epoch:{ep}, 模型准确率acc:{acc}")


# step8 模型训练
train()

# step9 模型预测
sen = "我觉得这家酒店真不错,饭很好吃!"
id2_label = {0: "差评", 1: "好评"}
model.eval()

with torch.no_grad():
    inputs = tokenizer(sen, return_tensors="pt")
    inputs = {k: v.to(device) for k, v in inputs.items()}  # 确保输入在正确的设备
    # 只在预测开始时打印一次设备信息
    print(f"预测开始:\n模型设备: {next(model.parameters()).device}")
    print(f"输入数据设备: {inputs['input_ids'].device}")
    logits = model(**inputs).logits
    pred = torch.argmax(logits, dim=-1)
    print(f"输入:{sen}\n模型预测结果:{id2_label.get(pred.item())}")

# 更简单的做法
from transformers import pipeline

model.config.id2label = id2_label
pipe = pipeline("text-classification", model=model, tokenizer=tokenizer, device=0 if torch.cuda.is_available() else -1)
print(pipe(sen))

最终运行的结果

posted @   小蔡姬  阅读(11)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
点击右上角即可分享
微信分享提示