tnblog
首页
视频
资源
登录

HugginFace 中文填空(学习笔记)

2369人阅读 2023/10/28 13:48 总访问:3511412 评论:0 收藏:0 手机
分类: HuggingFace

HugginFace 中文填空(学习笔记)

数据集介绍


本章使用的仍然是情感分类数据集,每条包括一句购物评价一集以及是不是好评的标识。
唯一不同的是将其中的句子字符串进行替换,然后通过模型进行训练后进行填空。

实现代码

安装环境

  1. %pip install -q transformers datasets torchtext

准备数据集

使用编码工具


首先需要加载编码工具。

  1. from transformers import BertTokenizer
  2. token = BertTokenizer.from_pretrained('bert-base-chinese')
  3. token


进行试算。

  1. out = token.batch_encode_plus(
  2. batch_text_or_text_pairs=['轻轻的我走了,正如我轻轻地来。', '我轻轻的招手,作别西天的云彩。'],
  3. truncation=True,
  4. padding='max_length',
  5. max_length=18,
  6. return_tensors='pt',
  7. return_length=True)
  8. #查看编码输出
  9. for k, v in out.items():
  10. print(k, v.shape)
  11. #把编码还原为句子
  12. print(token.decode(out['input_ids'][0]))

定义数据集


本次任务中,依然将使用ChnSentiCorp数据集,但需要对数据集进行一些操作,它变成一个填空任务数据集。
在开始处理之前,首先需要加载数据集,代码如下:

  1. from datasets import load_dataset
  2. dataset = load_dataset('lansinuote/ChnSentiCorp')
  3. dataset


接下来对这些文本数据进行编码,便于后续的处理,代码如下:

  1. def f(data):
  2. return token.batch_encode_plus(batch_text_or_text_pairs=data['text'],
  3. truncation=True,
  4. padding='max_length',
  5. max_length=30,
  6. return_length=True)
  7. # 丢掉'text', 'label'字段
  8. dataset = dataset.map(function=f,
  9. batched=True,
  10. batch_size=1000,
  11. num_proc=4,
  12. remove_columns=['text', 'label'])
  13. dataset


truncation=Truemax_length=30编码结果的长度不会长于30个词,超出30个词的部分会被截断。
padding=max_length表明不足会补充[PAD]到30个词为止。
return_length=True会让编码结果中多出一个length字段,表明这段数据的长度,由于PAD不会被计算在长度内,所以length一定小于或等于30,这个字段方便了后续数据过滤。


接下来我们将丢弃句子长度小于30个词的句子给过滤掉。

  1. def f(data):
  2. return [i >= 30 for i in data['length']]
  3. dataset = dataset.filter(function=f, batched=True, batch_size=1000, num_proc=4)
  4. dataset


训练集中少了314条数据,测试集合中少了47条数据。

定义计算设备

  1. import torch
  2. device = 'cpu'
  3. if torch.cuda.is_available():
  4. device = 'cuda'
  5. device

定义数据整理函数


我们把第15个词给挖出来,替换成[MASK]同时擦掉正确的答案。
模型通过[MASK]将其中进行预测出来。

  1. def collate_fn(data):
  2. #取出编码结果
  3. input_ids = [i['input_ids'] for i in data]
  4. attention_mask = [i['attention_mask'] for i in data]
  5. token_type_ids = [i['token_type_ids'] for i in data]
  6. #转换为tensor格式
  7. input_ids = torch.LongTensor(input_ids)
  8. attention_mask = torch.LongTensor(attention_mask)
  9. token_type_ids = torch.LongTensor(token_type_ids)
  10. #把第15个词替换为mask
  11. labels = input_ids[:, 15].reshape(-1).clone()
  12. input_ids[:, 15] = token.get_vocab()[token.mask_token]
  13. #移动到计算设备
  14. input_ids = input_ids.to(device)
  15. attention_mask = attention_mask.to(device)
  16. token_type_ids = token_type_ids.to(device)
  17. labels = labels.to(device)
  18. return input_ids, attention_mask, token_type_ids, labels


试算。

  1. data = [{
  2. 'input_ids': [
  3. 101, 2769, 3221, 3791, 6427, 1159, 2110, 5442, 117, 2110, 749, 8409,
  4. 702, 6440, 3198, 4638, 1159, 5277, 4408, 119, 1728, 711, 2769, 3221,
  5. 5439, 2399, 782, 117, 3791, 102
  6. ],
  7. 'token_type_ids': [0] * 30,
  8. 'attention_mask': [1] * 30
  9. }, {
  10. 'input_ids': [
  11. 101, 679, 7231, 8024, 2376, 3301, 1351, 6848, 4638, 8024, 3301, 1351,
  12. 3683, 6772, 4007, 2692, 8024, 2218, 3221, 100, 2970, 1366, 2208, 749,
  13. 8024, 5445, 684, 1059, 3221, 102
  14. ],
  15. 'token_type_ids': [0] * 30,
  16. 'attention_mask': [1] * 30
  17. }]
  18. #试算
  19. input_ids, attention_mask, token_type_ids, labels = collate_fn(data)
  20. #把编码还原为句子
  21. print(token.decode(input_ids[0]))
  22. print(token.decode(labels[0]))
  23. input_ids.shape, attention_mask.shape, token_type_ids.shape, labels

定义数据集加载器

  1. loader = torch.utils.data.DataLoader(dataset=dataset['train'],
  2. batch_size=16,
  3. collate_fn=collate_fn,
  4. shuffle=True,
  5. drop_last=True)
  6. len(loader)

  1. for i, (input_ids, attention_mask, token_type_ids,
  2. labels) in enumerate(loader):
  3. break
  4. print(token.decode(input_ids[0]))
  5. print(token.decode(labels[0]))
  6. input_ids.shape, attention_mask.shape, token_type_ids.shape, labels

定义模型

加载预训练模型

  1. # 加载预训练模型
  2. from transformers import BertModel
  3. pretrained = BertModel.from_pretrained('bert-base-chinese')
  4. #统计参数量
  5. sum(i.numel() for i in pretrained.parameters()) / 10000


该模型有大约1个亿的参数量。

  1. # 不训练预训练模型,不需要计算梯度
  2. for param in pretrained.parameters():
  3. param.requires_grad_(False)


预训练的之后,可以进行一次试算。

  1. #预训练模型试算
  2. #设定计算设备
  3. pretrained.to(device)
  4. #模型试算
  5. out = pretrained(input_ids=input_ids,
  6. attention_mask=attention_mask,
  7. token_type_ids=token_type_ids)
  8. out.last_hidden_state.shape


这里输出了16句话的结果,每句话包括了30个词,每个词被抽成了768维的向量。

定义下游任务模型

  1. #定义下游任务模型
  2. class Model(torch.nn.Module):
  3. def __init__(self):
  4. super().__init__()
  5. self.decoder = torch.nn.Linear(in_features=768,
  6. out_features=token.vocab_size,
  7. bias=False)
  8. #重新初始化decode中的bias参数为全0
  9. self.bias = torch.nn.Parameter(data=torch.zeros(token.vocab_size))
  10. self.decoder.bias = self.bias
  11. #定义Dropout层,防止过拟合
  12. self.dropout = torch.nn.Dropout(p=0.5)
  13. def forward(self, input_ids, attention_mask, token_type_ids):
  14. #使用预训练模型抽取数据特征
  15. with torch.no_grad():
  16. out = pretrained(input_ids=input_ids,
  17. attention_mask=attention_mask,
  18. token_type_ids=token_type_ids)
  19. #把第15个词的特征,投影到全字典范围内
  20. out = self.dropout(out.last_hidden_state[:, 15])
  21. out = self.decoder(out)
  22. return out
  23. model = Model()
  24. #设定计算设备
  25. model.to(device)
  26. #试算
  27. model(input_ids=input_ids,
  28. attention_mask=attention_mask,
  29. token_type_ids=token_type_ids).shape


在这段代码中,定义了下游任务模型,该模型只包括一个全连接的线性神经网络,权重矩阵为768x21128,所以它能够把一个768维度的向量转换到21128维空间中。
可以把backbone抽取的数据特征还原为字典中的任何一个字。型做分类下游任务模型的计算过程为,获取一批数据之后,使用backbone将这批数据抽取成特征矩阵,抽取的特征矩阵的形状应该是16x30x768,这在之前预训练模型的试算中已经看到。这3个维度分别代表了16句话、30个词、768 维度的特征向量。
是对baci 在本次的填空任务中,填空处固定出现在每句话的第15个词的位置,所以只取出每句来讲,需话的第15个词的特征,再尝试把这个词的特征投影到全体词表空间中,即还原为词典中的结果为数据 某个词。
在投影到全体词表空间中时,由于768x21128是一个很大的矩阵,如果直接计算,则很容易导致过拟合,所以对backbone抽取的数据特征要接入一个DropOut 网络,把其中的数据以一定的概率置为0,防止网络的过拟合。
在代码的最后对该模型进行了试算,运行结果如下:


可见,预测结果为16句的填空结果,如果在该结果上再套用Softmax()函数,则为在全体词表中每个词的概率。

训练和测试


训练模型代码如下:

  1. from transformers import AdamW
  2. from transformers.optimization import get_scheduler
  3. def train():
  4. #定义优化器
  5. optimizer = AdamW(model.parameters(), lr=5e-4, weight_decay=1.0)
  6. #定义loss函数
  7. criterion = torch.nn.CrossEntropyLoss()
  8. #定义学习率调节器
  9. scheduler = get_scheduler(name='linear',
  10. num_warmup_steps=0,
  11. num_training_steps=len(loader) * 5,
  12. optimizer=optimizer)
  13. #模型切换到训练模式
  14. model.train()
  15. #共训练5个epoch
  16. for epoch in range(5):
  17. #按批次遍历训练集中的数据
  18. for i, (input_ids, attention_mask, token_type_ids,
  19. labels) in enumerate(loader):
  20. #模型计算
  21. out = model(input_ids=input_ids,
  22. attention_mask=attention_mask,
  23. token_type_ids=token_type_ids)
  24. #计算loss并使用梯度下降法优化模型参数
  25. loss = criterion(out, labels)
  26. loss.backward()
  27. optimizer.step()
  28. scheduler.step()
  29. optimizer.zero_grad()
  30. #输出各项数据的情况,便于观察
  31. if i % 50 == 0:
  32. out = out.argmax(dim=1)
  33. accuracy = (out == labels).sum().item() / len(labels)
  34. lr = optimizer.state_dict()['param_groups'][0]['lr']
  35. print(epoch, i, loss.item(), lr, accuracy)
  36. train()

测试

  1. def test():
  2. #定义测试数据集加载器
  3. loader_test = torch.utils.data.DataLoader(dataset=dataset['test'],
  4. batch_size=32,
  5. collate_fn=collate_fn,
  6. shuffle=True,
  7. drop_last=True)
  8. #下游任务模型切换到运行模式
  9. model.eval()
  10. correct = 0
  11. total = 0
  12. #按批次遍历测试集中的数据
  13. for i, (input_ids, attention_mask, token_type_ids,
  14. labels) in enumerate(loader_test):
  15. #计算15个批次即可,不需要全部遍历
  16. if i == 15:
  17. break
  18. print(i)
  19. #计算
  20. with torch.no_grad():
  21. out = model(input_ids=input_ids,
  22. attention_mask=attention_mask,
  23. token_type_ids=token_type_ids)
  24. #统计正确率
  25. out = out.argmax(dim=1)
  26. correct += (out == labels).sum().item()
  27. total += len(labels)
  28. print(correct / total)
  29. test()


测试出的正确率如下:


欢迎加群讨论技术,1群:677373950(满了,可以加,但通过不了),2群:656732739

评价

HugginFace 初探

HugginFace 初探[TOC] 安装环境python环境是3.6。import sys sys.version 安装torch,简单起见,避免环境问题,并且计...

HugginFace 使用编码工具(学习笔记)

HugginFace 使用编码工具(学习笔记)[TOC] 安装环境# 我这里的python是3.11 %pip install -q transformers==4.18 datasets...

HugginFace 使用数据集(学习笔记)

HugginFace 使用数据集(学习笔记)[TOC] 数据集工具介绍HuggingFace 提供了统一的数据集处理工具,让不同的数据集通过统一...

HugginFace 使用评价指标工具(学习笔记)

HugginFace 使用评价指标工具(学习笔记)[TOC] 评价指标工具介绍在训练和测试一个模型时往往需要计算不同的评价指标,如正...

HugginFace 使用管道工具(学习笔记)

HugginFace 使用管道工具(学习笔记)[TOC] 管道工具介绍HuggingFace 有一个巨大的模型库,其中一些是已经非常成熟的经典模...

HugginFace 使用训练工具(学习笔记)

HugginFace 使用训练工具(学习笔记)[TOC] 训练工具介绍HuggingFace提供了巨大的模型库,但我们往往还需要对特定的数据集进...

HugginFace 中文情感分类(学习笔记)

HugginFace 中文情感分类(学习笔记)[TOC] 数据集介绍本章使用的是lansinuote/ChnSentiCorp数据集,这是一个情感分类数据集...

HugginFace 中文数据关系推断(学习笔记)

HugginFace 中文数据关系推断(学习笔记)[TOC] 实现代码安装包加载的环境可以通过如下命令进行安装。%pip install -q trans...

HugginFace 中文命名实体识别(学习笔记)

HugginFace 中文命名实体识别(学习笔记)[TOC] 任务简介简单来说就是的识别人名、机构名、地名。数据集的介绍本章所使用的...
这一世以无限游戏为使命!
排名
2
文章
642
粉丝
44
评论
93
docker中Sware集群与service
尘叶心繁 : 想学呀!我教你呀
一个bug让程序员走上法庭 索赔金额达400亿日元
叼着奶瓶逛酒吧 : 所以说做程序员也要懂点法律知识
.net core 塑形资源
剑轩 : 收藏收藏
映射AutoMapper
剑轩 : 好是好,这个对效率影响大不大哇,效率高不高
ASP.NET Core 服务注册生命周期
剑轩 : http://www.tnblog.net/aojiancc2/article/details/167
ICP备案 :渝ICP备18016597号-1
网站信息:2018-2025TNBLOG.NET
技术交流:群号656732739
联系我们:contact@tnblog.net
公网安备:50010702506256
欢迎加群交流技术