当前位置:   article > 正文

BERT+textCNN+aclImdb文本情感分析_aclimdb数据集

aclimdb数据集

目录

环境配置

数据集解压

huggingfaceBERT下载

正式开始

import 相应的包

导入BERT-base

读取数据

数据预处理

网络定义

开始训练

输入文字进行测试

结果


代码参考《动手学深度学习》(Pytorch版)10.8节改动词向量部分。

文本情感分类:使用卷积神经网络(textCNN)

github地址代码中需要用到d2l包中的函数

aclImdb数据集地址

环境配置

对于《动手学深度学习》(Pytorch版)可以使用的环境是,cuda10+pytorch1.2+torchtext0.4

由于torchtext0.4和现在的新版有函数不同,下面是torchtext0.4的官方文档,用于查阅

torchtext0.4官方文档

cuda10+pytorch的配置参照这位大佬的文章

https://blog.csdn.net/weixin_44791964/article/details/106037141?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522163178646416780269847175%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=163178646416780269847175&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_v2~rank_v29-1-106037141.pc_v2_rank_blog_default&utm_term=windows&spm=1018.2226.3001.4450https://blog.csdn.net/weixin_44791964/article/details/106037141?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522163178646416780269847175%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=163178646416780269847175&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_v2~rank_v29-1-106037141.pc_v2_rank_blog_default&utm_term=windows&spm=1018.2226.3001.4450https://blog.csdn.net/weixin_44791964/article/details/106037141?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522163178646416780269847175%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=163178646416780269847175&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_v2~rank_v29-1-106037141.pc_v2_rank_blog_default&utm_term=windows&spm=1018.2226.3001.4450torchtext0.4请进入官网,下载正确版本

torchtext官网

pip install torchtext==0.4.0

数据集解压

  1. fname = os.path.join(DATA_ROOT, "aclImdb_v1.tar.gz")
  2. if not os.path.exists(os.path.join(DATA_ROOT, "aclImdb")):
  3. print("从压缩包解压...")
  4. with tarfile.open(fname, 'r') as f:
  5. f.extractall(DATA_ROOT)

huggingfaceBERT下载

  1. !pip install transformers
  2. import torch
  3. from transformers import BertModel, BertTokenizer
  4. # 下载bert-base不区分大小写,768维
  5. tokenizer = BertTokenizer.from_pretrained('bert-base-uncased', cache_dir='./transformers/bert-base-uncased/')
  6. model = BertModel.from_pretrained('bert-base-uncased', cache_dir='./transformers/bert-base-uncased/')

正式开始

import 相应的包

  1. import os
  2. import torch
  3. from torch import nn
  4. import torchtext.vocab as Vocab
  5. import torch.utils.data as Data
  6. import torch.nn.functional as F
  7. import sys
  8. sys.path.append("..")
  9. import d2lzh_pytorch as d2l
  10. device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
  11. DATA_ROOT = "../../data" # 此处根据自己的情况更改,就是有解压好的数据集的目录
  12. print(torch.__version__, device)

导入BERT-base

  1. from transformers import BertModel, BertTokenizer
  2. # 这里我们调用bert-base模型,同时模型的词典经过小写处理
  3. model_name = 'bert-base-uncased'
  4. # 读取模型对应的tokenizer
  5. tokenizer = BertTokenizer.from_pretrained(model_name, cache_dir='./transformers/bert-base-uncased/')
  6. # 载入模型
  7. model = BertModel.from_pretrained(model_name, cache_dir='./transformers/bert-base-uncased/')
  1. model.to(device)
  2. model.eval()

读取数据

  1. train_data = d2l.read_imdb('train', data_root=os.path.join(DATA_ROOT, "aclImdb"))
  2. test_data = d2l.read_imdb('test', data_root=os.path.join(DATA_ROOT, "aclImdb"))

数据预处理

此处写了一堆for来使数据的格式和《动手学深度学习》(Pytorch版)相同,很傻的方法,轻喷

  1. def pretreatment(original_data):
  2. i = 0
  3. for element in original_data:
  4. temporary = []
  5. original_data[i][0] = torch.tensor(tokenizer.encode(element[0], add_special_tokens=True))
  6. if (original_data[i][0].shape)[0] > 500:
  7. original_data[i][0] = original_data[i][0][:500]
  8. original_data[i][0][499] = 102
  9. elif (original_data[i][0].shape)[0] < 500:
  10. n = torch.zeros(500)
  11. n[: (original_data[i][0].shape)[0]-1] = original_data[i][0][:(original_data[i][0].shape)[0]-1]
  12. original_data[i][0] = n
  13. original_data[i][0][499] = 102
  14. temporary.append(element[1])
  15. original_data[i][1] = torch.tensor(temporary)
  16. i = i+1
  17. features = torch.cat([original_data[i][0].unsqueeze(0).long() for i in range(len(test_data))])
  18. labels = torch.cat( [original_data[i][1] for i in range(len(test_data))], 0)
  19. return features, labels
  1. train_set = Data.TensorDataset(*(pretreatment(train_data)))
  2. test_set = Data.TensorDataset(*(pretreatment(test_data)))
  1. batch_size = 2 # batch_size根据自己的显卡情况改动
  2. train_iter = Data.DataLoader(train_set, batch_size, shuffle=True)
  3. test_iter = Data.DataLoader(test_set, batch_size, shuffle=True)

我的显卡是1050 4G的显存,可以承受住batch_size=2,但是刚开始的时候只用batch_size=1训练了5个epoch。

网络定义

  1. class TextCNN(nn.Module):
  2. def __init__(self, embed_size, kernel_sizes, num_channels):
  3. super(TextCNN, self).__init__()
  4. self.dropout = nn.Dropout(0.5)
  5. self.decoder = nn.Linear(sum(num_channels), 2)
  6. # 时序最大池化层没有权重,所以可以共用一个实例
  7. self.pool = GlobalMaxPool1d()
  8. self.convs = nn.ModuleList() # 创建多个一维卷积层
  9. for c, k in zip(num_channels, kernel_sizes):
  10. self.convs.append(nn.Conv1d(in_channels = 2*embed_size,
  11. out_channels = c,
  12. kernel_size = k))
  13. def forward(self, inputs):
  14. outputs = model(inputs)[0] #shape(batchsize, 500, 768)
  15. embeddings = torch.cat((
  16. outputs,
  17. outputs), dim=2) # (batch, seq_len, 2*embed_size)
  18. # 根据Conv1D要求的输入格式,将词向量维,即一维卷积层的通道维(即词向量那一维),变换到前一维
  19. embeddings = embeddings.permute(0, 2, 1) # 交换维度的函数
  20. # 对于每个一维卷积层,在时序最大池化后会得到一个形状为(批量大小, 通道大小, 1)的
  21. # Tensor。使用flatten函数去掉最后一维,然后在通道维上连结
  22. encoding = torch.cat([self.pool(F.relu(conv(embeddings))).squeeze(-1) for conv in self.convs], dim=1)
  23. # 应用丢弃法后使用全连接层得到输出
  24. outputs = self.decoder(self.dropout(encoding))
  25. return outputs

这个地方有一点改动,自己的思路也不是很清晰,可能写的不对,但是可以跑

  1. embed_size, kernel_sizes, nums_channels = 768, [3, 4, 5], [100, 100, 100]
  2. net = TextCNN(embed_size, kernel_sizes, nums_channels)
  3. lr, num_epochs = 0.001, 5
  4. optimizer = torch.optim.Adam(filter(lambda p: p.requires_grad, net.parameters()), lr=lr)
  5. loss = nn.CrossEntropyLoss()

开始训练

d2l.train(train_iter, test_iter, net, loss, optimizer, device, num_epochs)

输入文字进行测试

  1. def predict_sentiment(net, sentence):
  2. """sentence是词语的列表"""
  3. device = list(net.parameters())[0].device
  4. sentence = torch.tensor(tokenizer.encode(s, add_special_tokens=True), device=device)
  5. label = torch.argmax(net(sentence.view((1, -1))), dim=1)
  6. return 'positive' if label.item() == 1 else 'negative'
  1. print("请输入一句评价电影的英文:")
  2. s = input()
  3. # 此处没有设置填充或截断到500,可以试一下
  4. print(predict_sentiment(net, s))

结果

这个结果的超参数,除了batch_size = 1,其他的参数和上面给出的代码是一样的 ,在睡觉的时候训练的,对于这个时间很佛系。关于这个结果我的感觉是训练5个epoch这个模型并没有过拟合,而且train acc和test acc之间的gap是是挺小的,可以再训练几个epoch╭(╯^╰)╮。

同样的网络使用glove300明显过拟合了

transformer我的个人电脑实在是带不动啊,太慢了。

关于输入句子进行测试的结果

 我都感觉自己写的代码有点离谱,这只是我的一个小练习,肯定有许多不对劲的地方,毕竟我BERT还没有学明白,继续努力。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/677854
推荐阅读
相关标签
  

闽ICP备14008679号