赞
踩
Bert基于Transformer架构是解决自然语言处理的深度学习模型,常使用在文本分类、情感分析、词性标注等场合。
本文将使用Bert模型对中文文本进行分类,其中训练集数据18W条,验证集数据1W条,包含10个类别的文本数据,数据可以自己从Kaggel上下载。
中文新闻标题 | 类别标签 | 类别名 |
锌价难续去年辉煌 | 0 | 金融 |
金科西府 名墅天成 | 1 | 房地产 |
同步A股首秀:港股缩量回调 | 2 | 经济 |
状元心经:考前一周重点是回顾和整理 | 3 | 教育 |
一年网事扫荡10年纷扰开心网李鬼之争和平落幕 | 4 | 科技 |
60年铁树开花形状似玉米芯(组图) | 5 | 社会 |
发改委治理涉企收费每年为企业减负超百亿 | 6 | 国际 |
布拉特:放球员一条生路吧 FIFA能消化俱乐部的攻击 | 7 | 体育 |
体验2D巅峰 倚天屠龙记十大创新概览 | 8 | 游戏 |
Rain入伍前最后开唱 本周六“雨”润京城(图) | 9 | 娱乐 |
分类模型的结构比较简单,示意图如下:
Dataset是我们用的数据集的库,是Pytorch中所有数据集加载类中应该继承的父类。其中父类中的两个私有成员函数必须被重载,否则将会触发错误提示。其中__len__应该返回数据集的大小,而__getitem__应该编写支持数据集索引的函数。
DataLoader是PyTorch提供的一个数据加载器,它可以将数据分成小批次进行加载,并自动完成数据的批量加载、随机洗牌、并发预取等操作。在神经网络的训练过程中,我们通常需要处理大量的数据。如果一次性将所有数据加载到内存中,不仅会消耗大量的内存资源,还可能导致程序运行缓慢甚至崩溃。因此,我们需要一种机制来将数据分成小批次进行加载,而DataLoader正是为了满足这一需求而诞生的。
- #首先导入需要用到的数据包
-
- from transformers import BertModel, BertTokenizer
- import torch.nn as nn
- import torch
- from torch.utils.data import Dataset, DataLoader
- from torch import optim
- import os
-
- class BertClassifier(nn.Module):
- def __init__(self, bert_model, output_size):
- super(BertClassifier, self).__init__()
- self.bert = bert_model
- self.classifier = nn.Linear(bert_model.config.hidden_size, output_size)
-
- def forward(self, input_ids, attention_mask):
- # 获取BERT模型的CLS输出
- text_output = self.bert(input_ids=input_ids, attention_mask=attention_mask)
- #得到线性层的结果
- logits=self.classifier(text_output.pooler_output)
- return logits
-
-
- #读取数据
- class data_load(Dataset):
- def __init__(self,path):
- self.data=list()
- file=open(path,'r',encoding='utf-8')
- for line in file:
- text,label=line.strip().split('\t')
- self.data.append((text,int(label)))
- file.close()
- def __len__(self):
- return len(self.data)
- def __getitem__(self, index):
- return self.data[index]
-
-
- #用于dataloader,对于每个小批量的数据,进行分词和填充
- def collate_fn(batch,tokenizer):
- texts=[text[0] for text in batch]
- labels=[text[1] for text in batch]
- labels=torch.tensor(labels,dtype=torch.long)
- tokens=tokenizer(
- texts,
- add_special_tokens=True,
- max_length=512,
- padding=True,
- truncation=True,
- return_tensors='pt',
- )
- return tokens['input_ids'],tokens['attention_mask'],labels
-
- if __name__=="__main__":
- dataset=data_load('./train.txt')
-
- print(len(dataset))
-
- output :180000
-
-
- #加载模型,生成分词器
- tokenizer=BertTokenizer.from_pretrained('bert-base-chinese')
- bert_model = BertModel.from_pretrained('bert-base-chinese')
-
- #dataset:要加载的数据集对象,必须是实现了len()和getitem()方法的对象
- data_loader=DataLoader(dataset,
- batch_size=128,
- shuffle=True,
- collate_fn=lambda x:collate_fn(x,tokenizer))
-
- # 指定机器
- device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
-
- #打印分词器支持的最大长度,输入的中文数据不能超过512
- #如果进行长文本分类,需要进行文本截断或分块处理
- # print(tokenizer.model_max_length)
-
-
- #定义bertclassifier模型为10分类
- model=BertClassifier(bert_model,output_size=10).to(device)
- model.train()
- #优化器
- optimizer=optim.AdamW(model.parameters(),lr=5e-5)
- #交叉熵损失误差
- criterion=nn.CrossEntropyLoss()
- #存放模型
- os.makedirs('output_models',exist_ok=True)
- epoch_n=10
- for epoch in range(1,epoch_n+1):
- for batch_index,data in enumerate(data_loader):
- input_ids=data[0].to(device)
- attention_mask=data[1].to(device)
- label=data[2].to(device)
- #清空梯度
- optimizer.zero_grad()
- #前向传播
- output=model(input_ids,attention_mask)
- loss=criterion(output,label)
- loss.backward() #计算梯度
- optimizer.step() #更新模型参数
-
- #计算正确率,用于观察模型结果
- predict=torch.argmax(output,dim=1)
- correct=(predict==label).sum().item()
- acc=correct/output.size(0)
- print(f"Epoch {epoch}/{epoch_n}") #迭代轮数
- print(f"Batch {batch_index+1}/{len(data_loader)}")
- print(f"Loss: {loss.item():.4f}") #损失
- print((f"Acc {correct}/{output.size(0)}=={acc:.3f}")) #正确率
- #每一次迭代都保存一次模型结果
- model_name=f'./output_models/chinese_news_classify{epoch}.pth'
- print("saved model: %s" % (model_name))
- torch.save(model.state_dict(),model_name)
可以看到随着训练的进行,模型的准确率越来越高。由于数据量和机器内存原因,训练的时间比较长,就没有全部跑完。
- Epoch 1/10
- Batch 59/1407
- Loss: 0.4286
- Acc 113/128==0.883
- saved model: ./output_models/chinese_news_classify1.pth
- Epoch 1/10
- Batch 60/1407
- Loss: 0.4399
- Acc 114/128==0.891
- saved model: ./output_models/chinese_news_classify1.pth
- Epoch 1/10
- Batch 61/1407
- Loss: 0.5028
- Acc 109/128==0.852
- saved model: ./output_models/chinese_news_classify1.pth
- Epoch 1/10
- Batch 62/1407
- Loss: 0.3180
- Acc 120/128==0.938
使用训练好的模型预测中文文本
- from kaggel_chinese_text import BertClassifier
- from transformers import BertModel, BertTokenizer
- import torch
-
- test_text='铁血铸辉煌 天骄3公会战唤起新激情'
- bert_model = BertModel.from_pretrained('bert-base-chinese')
- tokenizer = BertTokenizer.from_pretrained('bert-base-chinese')
- model=BertClassifier(bert_model,10)
- device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
- model.load_state_dict(torch.load('./output_models/chinese_news_classify1.pth',map_location=device))
- model.to(torch.device(device))
- model.eval()
- inputs = tokenizer.encode_plus(
- test_text,
- add_special_tokens=True,
- max_length=128,
- padding='max_length',
- truncation=True,
- return_tensors='pt'
- )
- input_ids = inputs['input_ids']
- # print("shape of inut_ids:",input_ids.shape)
- attention_mask = inputs['attention_mask']
- with torch.no_grad():
- input_ids = input_ids.to(device)
- attention_mask = attention_mask.to(device)
- outputs = model(input_ids,attention_mask)
- _, predicted = torch.max(outputs, 1)
- print(predicted.item())
-
- #能正确预测文本属于游戏类型
- output: 8
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。