(深度学习记录)第N4周:中文文本分类——Pytorch实现

🏡我的环境:

  • 语言环境:Python3.11.4
  • 编译器:Jupyter Notebook
  • torcch版本:2.0.1

一、准备工作

import torch
import torch.nn as nn
import torchvision
from torchvision import transforms,datasets
import os,PIL,pathlib,warnings

warnings.filterwarnings("ignore")


device = torch.device("cuda"if torch.cuda.is_available() else"cpu")
device
import pandas as pd
train_data = pd.read_csv('/Users/wendyweng/Desktop/train.csv',sep='\t',header=None)
train_data.head()

·前期进行数据准备工作,并查看数据的前几行

#构建数据的迭代器
def coustom_data_iter(texts,labels):
    for x,y in zip(texts,labels):
        yield x,y
        
train_iter = coustom_data_iter(train_data[0].values[:],train_data[1].values[:])

二、数据的预处理

1.构建词典

from torchtext.data.utils import get_tokenizer
from torchtext.vocab import build_vocab_from_iterator
import jieba 

tokenizer =jieba.lcut

def yield_tokens(data_iter):
    for text,_ in data_iter:
        yield tokenizer(text)  
vocab = build_vocab_from_iterator(yield_tokens(train_iter),specials=["<unk>"])
vocab.set_default_index(vocab["<unk>"])
label_name =list(set(train_data[1].values[:]))
print(label_name)
text_pipeline = lambda x: vocab(tokenizer(x))
label_pipeline = lambda x: label_name.index(x)

创建了两个lambda函数,一个用于将文本转换成词汇索引,另一个用于将标签文本转换成它们在label_name列表中的索引。

2.生成数据批次和迭代器

from torch.utils.data import DataLoader

def collate_batch(batch):
    label_list,text_list,offsets=[],[],[0]
    
    for(_text,_label)in batch:
        label_list.append(label_pipeline(_label))
        
        processed_text= torch.tensor(text_pipeline(_text),dtype=torch.int64)
        text_list.append(processed_text)
        
        offsets.append(processed_text.size(0))
    
    label_list=torch.tensor(label_list,dtype=torch.int64)
    text_list=torch.cat(text_list)
    offsets=torch.tensor(offsets[:-1]).cumsum(dim=0)
    
    return text_list.to(device),label_list.to(device),offsets.to(device)

dataloader=DataLoader(train_iter,
                     batch_size=8,
                     shuffle =False,
                     collate_fn=collate_batch)

·collate_batch函数用于处理数据加载器中的批次。它接收一个批次的数据,处理它,并返回适合模型训练的数据格式。在这个函数内部,它遍历批次中的每个文本和标签对,将标签添加到label_list,将文本通过text_pipeline函数处理后转换为tensor,并添加到text_list。
·offsets列表用于存储每个文本的长度,这对于后续的文本处理非常有用,尤其是当你需要知道每个文本在拼接的大tensor中的起始位置时。
·text_list用torch.cat进行拼接,形成一个连续的tensor。

三、模型构建

1.搭建模型

from torch import nn

class TextClassificationModel(nn.Module):
    
    def __init__(self,vocab_size,embed_dim,num_class):
       super(TextClassificationModel,self).__init__()
        
       self.embedding = nn.EmbeddingBag(vocab_size,
                                        embed_dim,
                                        sparse=False)
        
       self.fc = nn.Linear(embed_dim,num_class)
       self.init_weights()

    def init_weights(self):
        initrange = 0.5
        self.embedding.weight.data.uniform_(-initrange,initrange)
        self.fc.weight.data.uniform_(-initrange,initrange)
        self.fc.bias.data.zero_()

    def forward(self,text,offsets):
        embedded=self.embedding(text,offsets)
        return self.fc(embedded)

2.初始化模型

num_class = len(label_name)
vocab_size = len(vocab)
em_size = 64
model = TextClassificationModel(vocab_size,em_size,num_class).to(device)

3.定义训练和评估函数

import time

def train(dataloader):
    model.train()
    total_acc,train_loss,total_count =0,0,0
    log_interval = 50
    start_time =time.time()
    
    for idx,(text,label,offsets) in enumerate(dataloader):
        
        predicted_label = model(text,offsets)
        
        optimizer.zero_grad()
        loss= criterion(predicted_label,label)
        loss.backward()
        torch.nn.utils.clip_grad_norm_(model.parameters(),0.1)
        optimizer.step()
    
        total_acc +=(predicted_label.argmax(1)==label).sum().item()
        train_loss += loss.item()
        total_count += label.size(0)
        
        if idx % log_interval == 0 and idx >0:
            elapsed = time.time() - start_time
            print('| epoch {:1d}|{:4d}/{:4d} batches'
                  '| train_acc {:4.3f} train_loss{:4.5f}'.format(epoch,idx,len(dataloader),
                                             total_acc/total_count,train_loss/total_count))
            total_acc,train_loss,total_count = 0,0,0
            start_time =time.time()

def evaluate(dataloader):
    model.eval()
    total_acc,train_loss,total_count = 0,0,0
    
    with torch.no_grad():
        for idx, (text,label,offsets) in enumerate(dataloader):
            predicted_label =model(text,offsets)
            
            loss = criterion(predicted_label,label)
            
            total_acc +=(predicted_label.argmax(1) == label).sum().item()
            train_loss +=loss.item()
            total_count +=label.size(0)
            
    return total_acc/total_count,train_loss/total_count

train 和 evaluate分别用于训练和评估文本分类模型。

·训练函数 train 的工作流程如下:将模型设置为训练模式。初始化总准确率、训练损失和总计数变量。记录训练开始的时间。遍历数据加载器,对每个批次:进行预测、清零优化器的梯度、计算损失(使用一个损失函数,例如交叉熵)、反向传播计算梯度、通过梯度裁剪防止梯度爆炸、执行一步优化器更新模型权重、更新总准确率和总损失、每隔一定间隔,打印训练进度和统计信息。

·评估函数 evaluate 的工作流程如下:将模型设置为评估模式、初始化总准确率和总损失、不计算梯度(为了节省内存和计算资源)、遍历数据加载器,对每个批次:进行预测、计算损失、
更新总准确率和总损失、返回整体的准确率和平均损失。

四、训练模型

1.拆分数据集并运行模型

from torch.utils.data.dataset import random_split
from torchtext.data.functional import to_map_style_dataset

EPOCHS = 10
LR = 5
BATCH_SIZE= 64


criterion = torch.nn.CrossEntropyLoss()
optimizer =torch.optim.SGD(model.parameters(),lr=LR)
scheduler =torch.optim.lr_scheduler.StepLR(optimizer,1.0,gamma=0.1)
total_accu =None

train_iter = coustom_data_iter(train_data[0].values[:],train_data[1].values[:])
train_dataset = to_map_style_dataset(train_iter)


split_train_,split_valid_=random_split(train_dataset,
                                      [int(len(train_dataset)*0.8),int(len(train_dataset)*0.2)])

train_dataloader =DataLoader(split_train_,batch_size=BATCH_SIZE,
                             shuffle=True,collate_fn=collate_batch)
valid_dataloader = DataLoader(split_valid_,batch_size=BATCH_SIZE,
                              shuffle=True,collate_fn=collate_batch)
for epoch in range(1,EPOCHS + 1):
    epoch_start_time =time.time()
    train(train_dataloader)
    val_acc,val_loss = evaluate(valid_dataloader)
    
    lr= optimizer.state_dict()['param_groups'][0]['lr']
    
    if total_accu is not None and total_accu > val_acc:
        scheduler.step()
    else:
        total_accu = val_acc
    print('-'* 69)
    print('|epoch {:1d} |time: {:4.2f}s | '
          'valid_acc{:4.3f} valid_loss{:4.3f} | lr{:4.6f}'.format(epoch,
                                       time.time()- epoch_start_time,
                                       val_acc,val_loss,lr))
    print('-'* 69)

设置训练的轮数、学习率和批次大小。
定义交叉熵损失函数、随机梯度下降优化器和学习率调度器。
将训练数据转换为一个map样式的数据集,并将其分成训练集和验证集。
创建训练和验证的数据加载器。
开始训练循环,每个epoch都会训练模型并在验证集上评估模型的准确率和损失。
如果验证准确率没有提高,则按计划降低学习率。
打印每个epoch结束时的统计信息,包括时间、准确率、损失和学习率。

 

test_acc,text_loss = evaluate(valid_dataloader)
print('模型准确率为:{:5.4f}'.format(test_acc))

 

def predict(text,text_pipeline):
    with torch.no_grad():
        text = torch.tensor(text_pipeline(text))
        output =model(text,torch.tensor([0]))
        return output.argmax(1).item()

ex_text_str="还有双鸭山到淮阴的汽车票吗13号的"

model =model.to("cpu")
print("该文本的类别是:%s"%label_name[predict(ex_text_str,text_pipeline)])

五、小结 

代码细节错误解析:

1.“ def __init__(self,vocab_size,embed_dim,num_class):
       super(TextClassificationModel,self).__init__()”注意init前后两条下划线

2.“,”和“.”的运用

  • 26
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值