基于Transformer(卷积神经网络、循环神经网络)的情感分类研究

Requirements:

* Python: 3.8.5
* PyTorch: 1.8.0
* Transformers: 4.9.0
* NLTK: 3.5
* LTP: 4.0

 Model:

Attention:

 论文解读参考:
 

https://blog.csdn.net/Magical_Bubble/article/details/89083225

实验步骤:

1)下载VSstudio2019

注意:安装时勾选“Python开发”和“C++桌面开发”

2) 下载和安装nvidia显卡驱动

下载之后就是简单的下一步直到完成。

完成之后,在cmd中输入执行:

nvidia-smi

如果有错误:

‘nvidia-smi’ 不是内部或外部命令,也不是可运行的程序

或批处理文件。

把C:\Program Files\NVIDIA Corporation\NVSMI添加到环境变量的path中。再重新打开cmd窗口。

3) 下载和安装CUDA和cuDNN

 

安装完后,可以执行nvcc -V 来验证gpu是否可以等待应用,下图表示cuda安装好了

4) 安装Anaconda

搭建虚拟环境和pytorch软件平台


5)添加Aanaconda国内镜像配置

清华TUNA提供了 Anaconda 仓库的镜像,运行以下命令:

conda config –add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/

conda config –add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/

conda config –set show_channel_urls yes
 

6)建立虚拟环境,安装软件pytorch,transformer

(这个很重要,可以保证不同版本的包独立环境)

创建虚拟环境:conda create -n nlp-book python=3.8.5(虚拟环境安装不上的话:conda config –add channels conda-forge)

激活虚拟环境nlp-book,输入: conda activate nlp-book 

删除虚拟环境:conda remove -n your_env_name –all

激活虚拟环境nlp-book: 

在所创建的pytorch环境下安装pytorch, 执行命令:

(conda install pytorch=1.8 torchvision cudatoolkit=10.2 -c pytorch)

conda install pytorch=1.8.0 torchvision cudatoolkit -c pytorch(笔记本)

conda install pytorch==1.8.0 torchvision==0.9.0 torchaudio==0.8.0 cudatoolkit=11.1 -c pytorch -c conda-forge(台式机)

【注意:在虚拟环境下,安装pytorch,可能会碰到包的不兼容性,会报错

    anaconda search -t conda libcublas >=11.10.1.25,<11.11.3.6

                                (and similarly for the other packages)

于是在cmd命令行,输入:

anaconda search -t conda pytorch

结果只有1.8.2版本,也就是在不同的cuda版本下,对应的pytorch库居然不一样

于是输入安装命令: conda install -c https://conda.anaconda.org/conda-forge pytorch=1.8.2

不断地报错,不断通过类似以下命令安装补全: D:\nlp-code-main\chp5> conda install -c https://conda.anaconda.org/conda-forge python_abi 

之后,就可以安装pytorch。特别是之前安装的pytorch版本过高,无法兼容新的项目下的pytorch,就必须在虚拟环境下重新安装。

小结:(1)在安装pytorch曾出现多种版本大小不兼容的情况,改了很久无法纠错,于是后来重新卸载anaconda,缘由是自带的python3.5版本,无法满足后面高版本的python所需要的库,重新安装了最新版的anaconda,之后创建虚拟环境,安装pytorch都可以。

     (2)查看安装的版本,pytorch,transformers
import torch
import numpy as np
import transformers
print(torch.__version__)  
print(transformers.__version__) 

接下来安装模型

conda install transformer=4.9.0

安装时报错:

缺乏镜像

执行安装命令

pip install transformers==4.9.0 -i https://pypi.doubanio.com/simple

pip install nltk==3.5 -i https://pypi.doubanio.com/simple

pip install ltp==4.0.2 -i https://pypi.doubanio.com/simple

7)进入项目所在目录

(nlp-book) D:\nlp-book-master\chp4>python transformer_sent_polarity.py

报错

       无法在线下载sentence_polarity数据,通常无法下载这个包nltk_data下的很多数据集以及xml文件。一般的方法可以自己下载放到本地目录。链接地址:GitHub – nltk/nltk_data: NLTK Data

于是改正上面报错:

解决方法:
离线下载
github:nltk_data(或pip install nltk -i https://pypi.tuna.tsinghua.edu.cn/simple)进入清华镜像安装后,也无法安装预训练的情感数据集,于是还是进入gitub下载

GitHub – nltk/nltk_data: NLTK Data,

       进入下载页面:/tree/gh-pages/packages/corpora,在corpora下面可以进行下载具体的数据集格式,

      将下载的文件中的sentence_polarity.zip放在上面报错中的目录的任意一个子目录下,程序调用时依次搜寻这些路径,一旦在某个路径下,找到数据格式,即可完成数据的加载。

       这里报错是无法加载到数据:

# 加载数据2023.4.7(见transformers代码)
train_data, test_data, vocab = load_sentence_polarity()

       数据包下载后,大概整个nltk_data有706兆,于是把该包放在项目所在的环境目录env下的D:\\soft\\anaconda3\\envs\\nlp-book\\nltk_data下面,之前这里通过清华镜像没有安装到位。这里有个奇怪的现象,进入包的子目录下下载sentence_polarity.zip,无法下载,但是整个包nltk_data可以全部下载到位。这个在上机的实践课上要小心一点。2023.4.7中广班

       复制包的数据后重新执行 python transformer_sent_polarity.py还是报错,类似前一个错误,无法加载数据。根据报错提示Attempted to load corpora/sentence_polarity.zip/sentence_polarity/。于是改写路径目录nltk_data/corpora/sentence_polarity

       现在可以执行了,也就是可以加载数据了。

      8)训练,测试数据

加载情感数据集sentence_polarity,然后分割数据集

9)结果:

Testing: 100%|██████████| 2662/2662 [00:05<00:00, 468.51it/s]
Acc: 0.68

附录:transformer情感分类代码

import math
import torch
from torch import nn, optim
from torch.nn import functional as F
from torch.utils.data import Dataset, DataLoader
from torch.nn.utils.rnn import pad_sequence, pack_padded_sequence
from collections import defaultdict
from vocab import Vocab
from utils import load_sentence_polarity, length_to_mask

# tqdm是一个Pyth模块,能以进度条的方式显式迭代的进度
from tqdm.auto import tqdm

class TransformerDataset(Dataset):
    def __init__(self, data):
        self.data = data
    def __len__(self):
        return len(self.data)
    def __getitem__(self, i):
        return self.data[i]

def collate_fn(examples):
    lengths = torch.tensor([len(ex[0]) for ex in examples])
    inputs = [torch.tensor(ex[0]) for ex in examples]
    targets = torch.tensor([ex[1] for ex in examples], dtype=torch.long)
    # 对batch内的样本进行padding,使其具有相同长度
    inputs = pad_sequence(inputs, batch_first=True)
    return inputs, lengths, targets

class PositionalEncoding(nn.Module):
    def __init__(self, d_model, dropout=0.1, max_len=512):
        super(PositionalEncoding, self).__init__()

        pe = torch.zeros(max_len, d_model)
        position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1)
        div_term = torch.exp(torch.arange(0, d_model, 2).float() * (-math.log(10000.0) / d_model))
        pe[:, 0::2] = torch.sin(position * div_term)
        pe[:, 1::2] = torch.cos(position * div_term)
        pe = pe.unsqueeze(0).transpose(0, 1)
        self.register_buffer(‘pe’, pe)

    def forward(self, x):
        x = x + self.pe[:x.size(0), :]
        return x

class Transformer(nn.Module):
    def __init__(self, vocab_size, embedding_dim, hidden_dim, num_class,
                 dim_feedforward=512, num_head=2, num_layers=2, dropout=0.1, max_len=128, activation: str = “relu”):
        super(Transformer, self).__init__()
        # 词嵌入层
        self.embedding_dim = embedding_dim
        self.embeddings = nn.Embedding(vocab_size, embedding_dim)
        self.position_embedding = PositionalEncoding(embedding_dim, dropout, max_len)
        # 编码层:使用Transformer
        encoder_layer = nn.TransformerEncoderLayer(hidden_dim, num_head, dim_feedforward, dropout, activation)
        self.transformer = nn.TransformerEncoder(encoder_layer, num_layers)
        # 输出层
        self.output = nn.Linear(hidden_dim, num_class)


    def forward(self, inputs, lengths):
        inputs = torch.transpose(inputs, 0, 1)
        hidden_states = self.embeddings(inputs)
        hidden_states = self.position_embedding(hidden_states)
        attention_mask = length_to_mask(lengths) == False
        hidden_states = self.transformer(hidden_states, src_key_padding_mask=attention_mask)
        hidden_states = hidden_states[0, :, :]
        output = self.output(hidden_states)
        log_probs = F.log_softmax(output, dim=1)
        return log_probs

embedding_dim = 128
hidden_dim = 128
num_class = 2
batch_size = 32
num_epoch = 5

# 加载数据
train_data, test_data, vocab = load_sentence_polarity()
train_dataset = TransformerDataset(train_data)
test_dataset = TransformerDataset(test_data)
train_data_loader = DataLoader(train_dataset, batch_size=batch_size, collate_fn=collate_fn, shuffle=True)
test_data_loader = DataLoader(test_dataset, batch_size=1, collate_fn=collate_fn, shuffle=False)

# 加载模型
device = torch.device(‘cuda’ if torch.cuda.is_available() else ‘cpu’)
model = Transformer(len(vocab), embedding_dim, hidden_dim, num_class)
model.to(device) # 将模型加载到GPU中(如果已经正确安装)

# 训练过程
nll_loss = nn.NLLLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001) # 使用Adam优化器

model.train()
for epoch in range(num_epoch):
    total_loss = 0
    for batch in tqdm(train_data_loader, desc=f”Training Epoch {epoch}”):
        inputs, lengths, targets = [x.to(device) for x in batch]
        log_probs = model(inputs, lengths)
        loss = nll_loss(log_probs, targets)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        total_loss += loss.item()
    print(f”Loss: {total_loss:.2f}”)

# 测试过程
acc = 0
for batch in tqdm(test_data_loader, desc=f”Testing”):
    inputs, lengths, targets = [x.to(device) for x in batch]
    with torch.no_grad():
        output = model(inputs, lengths)
        acc += (output.argmax(dim=1) == targets).sum().item()

# 输出在测试集上的准确率
print(f”Acc: {acc / len(test_data_loader):.2f}”)

项目总结:

(1)

在执行代码 python  transformer_sent_polarity.py 可能会报错。

RuntimeError: Expected all tensors to be on the same device, but found at least two devices, cuda:0 and cpu!

仔细想了一下,参考了车万翔老师的建议。

在下列位置修改了代码:

def length_to_mask(lengths):
    device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
    max_len = torch.max(lengths).to(device)
    mask = torch.arange(max_len).expand(lengths.shape[0], max_len).to(device)< lengths.unsqueeze(1).to(device)
    return mask

目的是将torch.arrange(max_len)的设备加载到gpu。然后运行就成功了

(2)  执行lstm_postag.py 长短期记忆神经网络数据标注时会报错,length是一维的cpu设备计算的,此时必须修改代码:

for epoch in range(num_epoch):
    total_loss = 0
    for batch in tqdm(train_data_loader, desc=f"Training Epoch {epoch}"):
        inputs, lengths, targets, mask = [x for x in batch]
        # 因为lengths是cpu设备
        inputs=inputs.to(device)
        targets=targets.to(device)

 修改后,代码可以完成训练测试标注。

3)在3070显卡上通过skipgram生成word2vec, 需要十分钟。但是在笔记本上执行要6个小时。

下载修改好的代码:

(363条消息) transformer执行情感分析,CBOW,Skipgram生成词向量代码资源-CSDN文库

文章出处登录后可见!

已经登录?立即刷新

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
xiaoxingxing的头像xiaoxingxing管理团队
上一篇 2023年9月17日
下一篇 2023年9月17日

相关推荐