当前位置: 首页 > news >正文

HuggingFace学习笔记--利用API实现简单的NLP任务

目录

1--中文分类

1-1--使用预训练模型推理

1-2--基于预训练模型实现下游任务

2--中文填空

3--中文句子关系推断


1--中文分类

1-1--使用预训练模型推理

代码实例:

import torch
from datasets import load_dataset
from transformers import BertTokenizer, BertModel# 定义全局分词工具
tokenizer = BertTokenizer.from_pretrained('bert-base-chinese')# 定义数据集
class Dataset(torch.utils.data.Dataset):def __init__(self, split):self.dataset = load_dataset(path = 'lansinuote/ChnSentiCorp', split = split) # 加载数据集def __len__(self):return len(self.dataset)def __getitem__(self, i):text = self.dataset[i]['text']label = self.dataset[i]['label']return text, label# 自定义数据的处理(加载)方式
def my_collate_fn(data): # data 的类型与 dataset 的返回值相同,本例中dataset返回一个列表[text, label]# 根据dataset的返回结果,取出对应的text和labelsents = [i[0] for i in data]labels = [i[1] for i in data]# 使用全局的分词工具进行编码data = tokenizer.batch_encode_plus(batch_text_or_text_pairs = sents,truncation = True,padding = 'max_length',max_length = 500,return_tensors = 'pt',return_length = True)input_ids = data['input_ids']attention_mask = data['attention_mask']token_type_ids = data['token_type_ids']labels = torch.LongTensor(labels)return input_ids, attention_mask, token_type_ids, labelsdef main():dataset = Dataset('train') # 初始化训练集# print(len(dataset), dataset[0])# 定义dataloaderloader = torch.utils.data.DataLoader(dataset = dataset,batch_size = 16,collate_fn = my_collate_fn,shuffle = True,drop_last = True)# 遍历dataloader加载数据for i, (input_ids, attention_mask, token_type_ids, labels) in enumerate(loader):breakprint(len(loader))print(input_ids.shape, attention_mask.shape, token_type_ids.shape, labels) # 打印一个样本# 加载预训练模型model = BertModel.from_pretrained('bert-base-chinese')for param in model.parameters(): # 不进行梯度计算和反向传播param.requires_grad_(False)# 调用预训练模型推理一个样本    output = model(input_ids = input_ids, attention_mask = attention_mask, token_type_ids = token_type_ids)print(output.last_hidden_state.shape) # 打印最后一个隐层输出特征的维度if __name__ == "__main__":main()print("All done!")

输出结果:

# dataloader单个样本:
torch.Size([16, 500]) 
torch.Size([16, 500]) 
torch.Size([16, 500]) 
tensor([1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1])
# 最后一个隐层的输出特征:
torch.Size([16, 500, 768])

1-2--基于预训练模型实现下游任务

        利用预训练 bert 模型最后一个隐层的[cls] token的特征进行中文分类;

代码:

import torch
from datasets import load_dataset
from transformers import BertTokenizer, BertModel, AdamW# 定义全局分词工具
tokenizer = BertTokenizer.from_pretrained('bert-base-chinese')# 定义数据集
class Dataset(torch.utils.data.Dataset):def __init__(self, split):self.dataset = load_dataset(path = 'lansinuote/ChnSentiCorp', split = split) # 加载数据集def __len__(self):return len(self.dataset)def __getitem__(self, i):text = self.dataset[i]['text']label = self.dataset[i]['label']return text, label# 自定义数据的处理(加载)方式
def my_collate_fn(data): # data 的类型与 dataset 的返回值相同,本例中dataset返回一个列表[text, label]# 根据dataset的返回结果,取出对应的text和labelsents = [i[0] for i in data]labels = [i[1] for i in data]# 使用全局的分词工具进行编码data = tokenizer.batch_encode_plus(batch_text_or_text_pairs = sents,truncation = True,padding = 'max_length',max_length = 500,return_tensors = 'pt',return_length = True)input_ids = data['input_ids']attention_mask = data['attention_mask']token_type_ids = data['token_type_ids']labels = torch.LongTensor(labels)return input_ids, attention_mask, token_type_ids, labels# 定义下游任务模型
class Model(torch.nn.Module):def __init__(self):super().__init__()self.pretrained_model = BertModel.from_pretrained('bert-base-chinese') # 加载预训练模型self.fc = torch.nn.Linear(768, 2)# 固定预训练模型for param in self.pretrained_model.parameters():param.requires_grad = Falsedef forward(self, input_ids, attention_mask, token_type_ids):with torch.no_grad():output = self.pretrained_model(input_ids=input_ids,attention_mask=attention_mask,token_type_ids=token_type_ids)output = self.fc(output.last_hidden_state[:, 0]) # 利用最后一个隐层的[cls]token特征进行分类output = output.softmax(dim=1)return output# 定义测试函数
def test(model, dataset):model.eval()correct = 0total = 0# 定义加载测试集的dataloaderloader_test = torch.utils.data.DataLoader(dataset = dataset,batch_size = 32,collate_fn = my_collate_fn,shuffle = True,drop_last = True)for idx, (input_ids, attention_mask, token_type_ids, labels) in enumerate(loader_test):if idx == 5: # 测试5个batchbreakprint(idx)with torch.no_grad():input_ids = input_ids.cuda()attention_mask = attention_mask.cuda()token_type_ids = token_type_ids.cuda()labels = labels.cuda()output = model(input_ids=input_ids, attention_mask=attention_mask, token_type_ids=token_type_ids)output = output.argmax(dim=1)correct += (output == labels).sum().item()total += len(labels)print("Acc: ", correct / total) # 打印5个batch的总体准确率def main():dataset = Dataset('train') # 初始化训练集# print(len(dataset), dataset[0])# 定义dataloaderloader = torch.utils.data.DataLoader(dataset = dataset,batch_size = 16,num_workers = 8,collate_fn = my_collate_fn,shuffle = True,drop_last = True)# 初始化模型model = Model()model = model.cuda() # 使用GPU# 初始化优化器和损失函数optimizer = AdamW(model.parameters(), lr=5e-4)criterion = torch.nn.CrossEntropyLoss().cuda()# 训练模型model.train()for idx, (input_ids, attention_mask, token_type_ids, labels) in enumerate(loader): # 遍历加载数据input_ids = input_ids.cuda()attention_mask = attention_mask.cuda()token_type_ids = token_type_ids.cuda()labels = labels.cuda()output = model(input_ids=input_ids, attention_mask=attention_mask, token_type_ids=token_type_ids)loss = criterion(output, labels)loss.backward()optimizer.step()optimizer.zero_grad()if idx % 5 == 0: # 每5个batch打印当前准确率和损失output = output.argmax(dim=1)accuracy = (output == labels).sum().item() / len(labels)print(idx, loss.item(), accuracy)if idx == 300: # 使用300个batch进行训练break# 测试模型test(model, Dataset('validation'))if __name__ == "__main__":main()

部分输出结果:

...
260 0.5995925664901733 0.75
265 0.3791050910949707 1.0
270 0.42692136764526367 0.9375
275 0.4765201210975647 0.875
280 0.4071955382823944 0.9375
285 0.4194560945034027 0.875
290 0.449373722076416 0.9375
295 0.38813596963882446 1.0
300 0.5164415240287781 0.875
Acc:  0.89375

2--中文填空

        对训练数据的第15个词进行 mask 掉,预测第15个词;

        利用 bert 模型提取特征,对最后一个隐层的第15个token特征进行分类;

        分类用的是一个简单的线性层,其维度为(768, token.vocab_size),其中token.vocab_sized的大小为21128,即预测21128个词的分类分数,再与真实标签进行损失计算;

代码:

import torch
from datasets import load_dataset, load_from_disk
from transformers import BertTokenizer, BertModel, AdamW# 定义全局分词工具
token = BertTokenizer.from_pretrained('bert-base-chinese')# 定义数据集
class Dataset(torch.utils.data.Dataset):def __init__(self, split):dataset = load_dataset(path = 'lansinuote/ChnSentiCorp', split = split)# dataset = load_from_disk('./data/ChnSentiCorp')# dataset = dataset[split]def f(data):return len(data['text']) > 30self.dataset = dataset.filter(f) # 筛选数据集def __len__(self):return len(self.dataset)def __getitem__(self, i):text = self.dataset[i]['text']return textdef collate_fn(data):# batch编码data = token.batch_encode_plus(batch_text_or_text_pairs = data,truncation = True,padding = 'max_length',max_length = 30, # padding到30个词return_tensors = 'pt', # 返回pytorch格式return_length = True)input_ids = data['input_ids']attention_mask = data['attention_mask']token_type_ids = data['token_type_ids']# 把第15个词固定替换为masklabels = input_ids[:, 15].reshape(-1).clone() # 记录真实标签input_ids[:, 15] = token.get_vocab()[token.mask_token]return input_ids, attention_mask, token_type_ids, labels# 定义下游任务模型
class Model(torch.nn.Module):def __init__(self):super().__init__()self.decoder = torch.nn.Linear(768, token.vocab_size, bias=False) # token.vocab_size为21128,预测21128个词的分类分数self.bias = torch.nn.Parameter(torch.zeros(token.vocab_size))self.decoder.bias = self.biasself.pretrained = BertModel.from_pretrained('bert-base-chinese')# 固定预训练模型for param in self.pretrained.parameters():param.requires_grad = Falsedef forward(self, input_ids, attention_mask, token_type_ids):# 使用bert模型提取特征with torch.no_grad():output = self.pretrained(input_ids=input_ids, attention_mask=attention_mask, token_type_ids=token_type_ids)output = self.decoder(output.last_hidden_state[:, 15])return output# 测试
def test(model):model.eval()correct = 0total = 0loader_test = torch.utils.data.DataLoader(dataset = Dataset('test'), batch_size = 32, collate_fn = collate_fn, shuffle = True, drop_last = True)for idx, (input_ids, attention_mask, token_type_ids, labels) in enumerate(loader_test):input_ids = input_ids.cuda()attention_mask = attention_mask.cuda()token_type_ids = token_type_ids.cuda()labels = labels.cuda()if idx == 15: # 测试15个batchbreakwith torch.no_grad():output = model(input_ids=input_ids, attention_mask=attention_mask, token_type_ids=token_type_ids)output = output.argmax(dim=1)correct += (output == labels).sum().item()total += len(labels)print(token.decode(input_ids[0])) # 打印测试数据print("真实标签: ", token.decode(labels[0]), "预测标签: ", token.decode(output[0]))print("Acc: ", correct / total)def main():# 初始化训练集dataset = Dataset('train')# 定义dataloaderloader = torch.utils.data.DataLoader(dataset = dataset,batch_size = 16,collate_fn = collate_fn,shuffle = True,drop_last = True)# 初始化模型model = Model().cuda()# 训练optimizer = AdamW(model.parameters(), lr=5e-4)criterion = torch.nn.CrossEntropyLoss().cuda()model.train()for epoch in range(5):for idx, (input_ids, attention_mask, token_type_ids, labels) in enumerate(loader):input_ids = input_ids.cuda()attention_mask = attention_mask.cuda()token_type_ids = token_type_ids.cuda()labels = labels.cuda()output = model(input_ids=input_ids, attention_mask=attention_mask, token_type_ids=token_type_ids)loss = criterion(output, labels)loss.backward()optimizer.step()optimizer.zero_grad()if idx % 50 == 0:output = output.argmax(dim=1)accuracy = (output == labels).sum().item() / len(labels)print(epoch, idx, loss.item(), accuracy)# 测试模型            test(model)if __name__ == "__main__":main()

部分输出结果:

4 200 0.7910566329956055 0.75
4 250 0.9690109491348267 0.8125
4 300 0.4056988060474396 0.9375
4 350 0.31916332244873047 1.0
4 400 0.8943865895271301 0.6875
4 450 0.4540601968765259 0.9375
4 500 0.7437821626663208 0.75
4 550 0.3669029474258423 0.9375
[CLS] 之 前 看 到 很 多 评 论 , 说 很 好 兴 冲 [MASK] 买 了 , 看 了 看 感 觉 非 常 失 望 炒 [SEP]
真实标签:  冲 预测标签:  冲
[CLS] 刚 看 了 一 章 就 丢 边 上 了 , 光 盘 也 [MASK] 知 道 放 哪 里 了 , 很 垃 圾 , 很 多 [SEP]
真实标签:  不 预测标签:  不
[CLS] 酒 店 生 意 清 淡 , 大 堂 里 都 没 几 个 [MASK] 人 。 房 间 倒 是 不 小 , 但 觉 得 被 [SEP]
真实标签:  客 预测标签:  客
[CLS] 选 购 的 时 候 , 还 是 有 货 的 。 最 后 [MASK] 通 知 我 说 , 没 货 了 。 当 当 的 服 [SEP]
真实标签:  却 预测标签:  ,
[CLS] 简 单 , 大 方 , 在 同 类 尺 寸 的 款 型 [MASK] 笔 记 本 中 不 显 厚 重 , 轻 薄 感 ! [SEP]
真实标签:  的 预测标签:  的
[CLS] 当 时 是 同 事 极 力 推 荐 这 本 书 。 我 [MASK] 到 网 上 的 介 绍 和 那 么 多 的 [UNK] 名 [SEP]
真实标签:  看 预测标签:  看
[CLS] 酒 店 位 置 离 火 车 站 很 近 , 走 路 10 [MASK] 钟 不 到 就 能 到 。 。 。 服 务 不 错 [SEP]
真实标签:  分 预测标签:  分
[CLS] 买 之 前 也 没 见 过 这 本 书, 听 他 们 [MASK] 的 天 花 乱 坠, 翻 了 几 页 就 够 了 [SEP]
真实标签:  说 预测标签:  写
[CLS] 看 了 百 家 讲 坛 , 来 了 兴 趣 。 因 为 [MASK] 作 忙 , 只 看 了 一 点 点 , 因 此 买 [SEP]
真实标签:  工 预测标签:  工
[CLS] 第 一 次 买 的 拉 拉 升 职 记 , 三 天 到 [MASK] ( 我 住 北 京 三 环 边 上 ) , 还 比 [SEP]
真实标签:  货 预测标签:  手
[CLS] 房 间 隔 音 效 果 极 差 , 深 夜 如 果 隔 [MASK] 客 人 大 声 喧 哗 的 话 [UNK] [UNK] 服 务 员 [SEP]
真实标签:  壁 预测标签:  音
[CLS] 读 过 她 的 《 茶 人 三 部 曲 》 , 一 口 [MASK] 读 完 的 。 一 直 在 搜 寻 她 的 文 字 [SEP]
真实标签:  气 预测标签:  气
[CLS] 条 件 、 服 务 、 设 施 都 很 好 , 房 间 [MASK] 干 净 、 很 舒 适 , 尤 其 是 前 台 服 [SEP]
真实标签:  很 预测标签:  很
[CLS] 大 俗 即 大 雅 ! 这 是 看 郑 振 铎 先 生 [MASK] 部 书 后 最 由 衷 的 感 想 , 看 过 中 [SEP]
真实标签:  三 预测标签:  这
[CLS] 觉 得 相 当 没 意 思 的 一 本 书 。 不 伦 [MASK] 类 的 。 看 的 时 候 很 纠 结 , 看 完 [SEP]
真实标签:  不 预测标签:  不
Acc:  0.6979166666666666

3--中文句子关系推断

代码:

import torch
import random
from datasets import load_dataset, load_from_disk
from transformers import BertTokenizer, BertModel, AdamW# 定义全局分词工具
token = BertTokenizer.from_pretrained('bert-base-chinese')# 定义数据集
class Dataset(torch.utils.data.Dataset):def __init__(self, split):# dataset = load_dataset(path='lansinuote/ChnSentiCorp', split=split)dataset = load_from_disk('./data/ChnSentiCorp')dataset = dataset[split]def f(data):return len(data['text']) > 40self.dataset = dataset.filter(f)def __len__(self):return len(self.dataset)def __getitem__(self, i):text = self.dataset[i]['text']# 切分一句话为前半句和后半句sentence1 = text[:20]sentence2 = text[20:40]label = 0 # label为0表示为同一句# 有一半的概率把后半句替换为一句无关的话if random.randint(0, 1) == 0:j = random.randint(0, len(self.dataset) - 1)sentence2 = self.dataset[j]['text'][20:40]label = 1return sentence1, sentence2, labeldef collate_fn(data):sents = [i[:2] for i in data]labels = [i[2] for i in data]# 编码data = token.batch_encode_plus(batch_text_or_text_pairs = sents,truncation = True,padding = 'max_length',max_length = 45,return_tensors = 'pt',return_length = True,add_special_tokens = True)input_ids = data['input_ids']attention_mask = data['attention_mask']token_type_ids = data['token_type_ids']labels = torch.LongTensor(labels)return input_ids, attention_mask, token_type_ids, labels# 定义下游任务模型
class Model(torch.nn.Module):def __init__(self):super().__init__()self.fc = torch.nn.Linear(768, 2) # 二分类self.pretrained = BertModel.from_pretrained('bert-base-chinese')# 固定预训练模型for param in self.pretrained.parameters():param.requires_grad = Falsedef forward(self, input_ids, attention_mask, token_type_ids):with torch.no_grad():output = self.pretrained(input_ids = input_ids, attention_mask = attention_mask, token_type_ids = token_type_ids)output = self.fc(output.last_hidden_state[:, 0])output = output.softmax(dim=1)return outputdef main():model = Model().cuda()optimizer = AdamW(model.parameters(), lr=5e-4)criterion = torch.nn.CrossEntropyLoss().cuda() # dataloaderloader = torch.utils.data.DataLoader(dataset = Dataset('train'),batch_size = 8,collate_fn = collate_fn,shuffle = True,drop_last = True)  # 训练model.train()for idx, (input_ids, attention_mask, token_type_ids, labels) in enumerate(loader):input_ids = input_ids.cuda()attention_mask = attention_mask.cuda()token_type_ids = token_type_ids.cuda()labels = labels.cuda()output = model(input_ids=input_ids, attention_mask=attention_mask, token_type_ids=token_type_ids)loss = criterion(output, labels)loss.backward()optimizer.step()optimizer.zero_grad()if idx % 5 == 0: # 每5个batch打印output = output.argmax(dim=1)accuracy = (output == labels).sum().item() / len(labels)print(idx, loss.item(), accuracy)if idx == 300: # 训练300个batchbreak# 测试test(model)# 定义测试函数
def test(model):model.eval()correct = 0total = 0loader_test = torch.utils.data.DataLoader(dataset = Dataset('test'),batch_size = 32,collate_fn = collate_fn,shuffle = True,drop_last = True)for idx, (input_ids, attention_mask, token_type_ids, labels) in enumerate(loader_test):input_ids = input_ids.cuda()attention_mask = attention_mask.cuda()token_type_ids = token_type_ids.cuda()labels = labels.cuda()if idx == 5: # 测试5个batchbreakwith torch.no_grad():output = model(input_ids=input_ids, attention_mask=attention_mask, token_type_ids=token_type_ids)pred = output.argmax(dim=1)correct += (pred == labels).sum().item()total += len(labels)print('acc:', correct / total)if __name__ == "__main__":main()

部分运行结果:

240 0.39283961057662964 0.875
245 0.7069525122642517 0.5
250 0.41953372955322266 0.875
255 0.5032698512077332 0.75
260 0.6422066688537598 0.75
265 0.5467717051506042 0.75
270 0.4452913701534271 0.875
275 0.5998544096946716 0.625
280 0.4301206171512604 0.875
285 0.5177156329154968 0.75
290 0.3987200856208801 0.875
295 0.33609679341316223 1.0
300 0.3723036050796509 0.875
acc: 0.925

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Unity UGUI控件之Horizontal Layout Group
  • shareMouse 使用中遇到的问题
  • Vue3集成ThreeJS实现3D效果,threejs+Vite+Vue3+TypeScript 实战课程【一篇文章精通系列】
  • [FUNC]判断窗口在哪一个屏幕上
  • docker 安装nginx
  • 【华为OD题库-056】矩阵元素的边界值-java
  • 如何使用内网穿透将Tomcat网页发布到公共互联网上【内网穿透】
  • 04 # 第一个 TypeScript 程序
  • 解决VSCode按住Ctrl(or Command) 点击鼠标左键不跳转的问题(不能Go to Definition)
  • Java(119):ExcelUtil工具类(org.apache.poi读取和写入Excel)
  • okhttp导致的内存溢出(OOM)sun.security.ssl.SSLSocketImpl
  • 西南科技大学数字电子技术实验二(SSI逻辑器件设计组合逻辑电路及FPGA实现 )FPGA部分
  • day3 移出链表中值为x的节点
  • python每日一题——19螺旋矩阵
  • 【分布式事务】Seata 开源的分布式事务解决方案
  • 2018一半小结一波
  • Date型的使用
  • Docker下部署自己的LNMP工作环境
  • fetch 从初识到应用
  • hadoop集群管理系统搭建规划说明
  • PHP 使用 Swoole - TaskWorker 实现异步操作 Mysql
  • vue--为什么data属性必须是一个函数
  • vue中实现单选
  • WinRAR存在严重的安全漏洞影响5亿用户
  • 不发不行!Netty集成文字图片聊天室外加TCP/IP软硬件通信
  • 好的网址,关于.net 4.0 ,vs 2010
  • 基于Mobx的多页面小程序的全局共享状态管理实践
  • 记一次删除Git记录中的大文件的过程
  • 马上搞懂 GeoJSON
  • 使用 QuickBI 搭建酷炫可视化分析
  • 使用agvtool更改app version/build
  • 在GitHub多个账号上使用不同的SSH的配置方法
  • 深度学习之轻量级神经网络在TWS蓝牙音频处理器上的部署
  • RDS-Mysql 物理备份恢复到本地数据库上
  • ​ 无限可能性的探索:Amazon Lightsail轻量应用服务器引领数字化时代创新发展
  • ​ArcGIS Pro 如何批量删除字段
  • ​LeetCode解法汇总2304. 网格中的最小路径代价
  • ​香农与信息论三大定律
  • (14)目标检测_SSD训练代码基于pytorch搭建代码
  • (7)STL算法之交换赋值
  • (二十九)STL map容器(映射)与STL pair容器(值对)
  • (二十一)devops持续集成开发——使用jenkins的Docker Pipeline插件完成docker项目的pipeline流水线发布
  • (个人笔记质量不佳)SQL 左连接、右连接、内连接的区别
  • (译) 理解 Elixir 中的宏 Macro, 第四部分:深入化
  • (转)C#调用WebService 基础
  • (转)memcache、redis缓存
  • (转)mysql使用Navicat 导出和导入数据库
  • (转)shell调试方法
  • *2 echo、printf、mkdir命令的应用
  • .Net 6.0 处理跨域的方式
  • .net core开源商城系统源码,支持可视化布局小程序
  • .net redis定时_一场由fork引发的超时,让我们重新探讨了Redis的抖动问题
  • .net开发引用程序集提示没有强名称的解决办法
  • :O)修改linux硬件时间
  • @cacheable 是否缓存成功_让我们来学习学习SpringCache分布式缓存,为什么用?