情感分析:使用卷积神经网络

情感分析:使用卷积神经网络

卷积神经网络最初是为计算机视觉设计的,但它也被广泛用于自然语言处理。简单地说,只要将任何文本序列想象成一维图像即可,通过这种方式,一维卷积神经网络可以处理文本中的局部特征,例如n元语法

在本节中,我们将使用textCNN模型来演示如何设计一个表示单个文本的卷积神经网络架构

import torch
from torch import nn
from d2l import torch as d2l

batch_size = 64
train_iter,test_iter,vocab = d2l.load_data_imdb(batch_size)

1 - 一维卷积

在介绍该模型之前,让我们现看看一维卷积是如何工作的,请记住,这只是基于互相关运算的二维卷积特例

如上图所示,在一维情况下,卷积窗口在输入张量上从左向右滑动。在滑动期间,卷积窗口中某个位置包含的输入子张量和核张量按元素相乘。这些乘法的总和在输出张量的相应位置给出单个标量值

我们在下面的corr1d函数中实现了一维互相关。给定输入张量X和核张量K,它返回输出张量Y

def corr1d(X,K):
    w = K.shape[0]
    Y = torch.zeros((X.shape[0] - w + 1))
    for i in range(Y.shape[0]):
        Y[i] = (X[i: i + w] * K).sum()
    return Y

构造输入张量X、核张量K来验证上述一维互相关实现的输出

X,K = torch.tensor([0,1,2,3,4,5,6]),torch.tensor([1,2])
corr1d(X,K)
tensor([ 2.,  5.,  8., 11., 14., 17.])

对于任何具有多个通道的一维输入,卷积核需要具有相同数量的输入通道。然后,对于每个通道,对输入的一维张量和卷积核的一维张量进行互相关运算,将所有通道上的结果相加以产生一维输出张量。下面演示了具有3各输入通道的一维互相关操作

我们可以实现多个输入通道的一维互相关运算

def corr1d_multi_in(X,K):
    # 首先,遍历'X'和'K'的第0维(通道维)。然后,把他们加在一起
    return sum(corr1d(x,k) for x,k in zip(X,K))

X = torch.tensor([[0, 1, 2, 3, 4, 5, 6],
                    [1, 2, 3, 4, 5, 6, 7],
                    [2, 3, 4, 5, 6, 7, 8]])
K = torch.tensor([[1, 2], [3, 4], [-1, -3]])

corr1d_multi_in(X, K)
tensor([ 2.,  8., 14., 20., 26., 32.])

注意,多输入通道的一维互相关等同于单输入通道的二维互相关。其中卷积核的高度必须与输入张量的高度相同

2 - 最大时间汇聚层

类似地,我们可以使用汇聚层从序列表示中提取最大值,作为跨时间步的最重要特征,textCNN中使用的最大时间胡汇聚层的工作原理类似于一维全局汇聚。对于每个通道在不同时间步存储值的多通道输入,每个通道的输出是该通道的最大值。请注意,最大时间汇聚允许在不同通道上使用不同数量的时间步

3- textCNN模型

使用一维卷积核最大时间汇聚,textCNN模型将单个预训练的词元表示作为输入,然后获得并转换用于下游应用的序列表示。

对于具有d维向量表示的n各词元的单个文本序列,输入张量的宽度、高度核通道数分别维n、1和d。textCNN模型将输入转换为输入,如下所示:

  1. 定义多个一维卷积核,并分别对输入执行卷积运算。具有不同宽度的卷积核可以捕获不同数目的相邻词元之间的局部特征
  2. 在所有输出通道上执行最大时间汇聚层,然后将所有标量汇聚输出连结为向量
  3. 使用全连接层将连结后的向量转换为输出类别,Dropout可以用来减少过拟合

定义模型

在下面的类中实现textCNN模型,与双向循环神经网络模型相比,除了用卷积层代替循环神经网络层外,还使用了两个嵌入层:一个是可训练权重,另一个是固定权重

class TextCNN(nn.Module):
    def __init__(self,vocab_size,embed_size,kernel_sizes,num_channels,**kwargs):
        super(TextCNN,self).__init__(**kwargs)
        self.embedding = nn.Embedding(vocab_size,embed_size)
        
        # 这个嵌入层不需要训练
        self.constant_embedding = nn.Embedding(vocab_size,embed_size)
        self.dropout = nn.Dropout(0.5)
        self.decoder = nn.Linear(sum(num_channels),2)
        
        # 最大时间汇聚层没有参数,因此可以共享此实例
        self.pool = nn.AdaptiveAvgPool1d(1)
        self.relu = nn.ReLU()
        
        # 创建多个一维卷积层
        self.convs = nn.ModuleList()
        for c,k in zip(num_channels,kernel_sizes):
            self.convs.append(nn.Conv1d(2 * embed_size,c,k))
            
    def forward(self,inputs):
        # 沿着向量维度将两个嵌入层连结起来
        # 每个嵌入层的输出形状都是(批量大小,词元数量,词元向量维度)连结起来
        embeddings = torch.cat((
            self.embedding(inputs),self.constant_embedding(inputs)),dim=2)
        
        # 根据一维卷积层的输入格式,重新排列张量,以便通作为第2维
        embeddings = embeddings.permute(0,2,1)
        
        # 每个一维卷积层在最大时间汇聚层合并后,获得的张量形状是(批量大小,通道数,1)
        # 删除最后一个维度并沿通道维度连结
        encoding = torch.cat([
            torch.squeeze(self.relu(self.pool(conv(embeddings))),dim=-1)
            for conv in self.convs
        ],dim = 1)
        outputs = self.decoder(self.dropout(encoding))
        return outputs

创建一个textCNN实例,它有3个卷积层,卷积核宽度分别为3、4和5,均有100个输出通道

embed_size,kernel_sizes,nums_channels = 100,[3,4,5],[100,100,100]
devices = d2l.try_all_gpus()
net = TextCNN(len(vocab),embed_size,kernel_sizes,nums_channels)

def init_weights(m):
    if type(m) in (nn.Linear,nn.Conv1d):
        nn.init.xavier_uniform_(m.weight)
        
net.apply(init_weights)
TextCNN(
  (embedding): Embedding(49346, 100)
  (constant_embedding): Embedding(49346, 100)
  (dropout): Dropout(p=0.5, inplace=False)
  (decoder): Linear(in_features=300, out_features=2, bias=True)
  (pool): AdaptiveAvgPool1d(output_size=1)
  (relu): ReLU()
  (convs): ModuleList(
    (0): Conv1d(200, 100, kernel_size=(3,), stride=(1,))
    (1): Conv1d(200, 100, kernel_size=(4,), stride=(1,))
    (2): Conv1d(200, 100, kernel_size=(5,), stride=(1,))
  )
)

加载预训练词向量

我们加载预训练的100维GloVe嵌入作为初始化的词元表示,这些词元表示(嵌入权重)在embedding中将被训练,在constant_embedding中将被固定

glove_embedding = d2l.TokenEmbedding('glove.6b.100d')
embeds = glove_embedding[vocab.idx_to_token]
net.embedding.weight.data.copy_(embeds)
net.constant_embedding.weight.data.copy_(embeds)
net.constant_embedding.weight.requires_grad = False

训练和评估模型

现在我们可以训练textCNN模型进行情感分析

lr,num_epochs = 0.001,5
trainer = torch.optim.Adam(net.parameters(),lr=lr)
loss = nn.CrossEntropyLoss(reduction="none")
d2l.train_ch13(net,train_iter,test_iter,loss,trainer,num_epochs,devices)
loss 0.065, train acc 0.978, test acc 0.873
3404.2 examples/sec on [device(type='cuda', index=0)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C4DpM0DJ-1665320489196)(https://yingziimage.oss-cn-beijing.aliyuncs.com/img/202210092055699.svg)]

下面,我们使用训练好的模型来预测两个简单句子的情感

d2l.predict_sentiment(net,vocab,"this movie is so great")
'positive'
d2l.predict_sentiment(net, vocab, 'this movie is so bad')
'negative'

4 - 小结

  • 一维卷积神经网络可以处理文本中的局部特征,比如n元语法
  • 多输入通道的一维互相关等价于单输入通道的二维互相关
  • 最大时间汇聚层允许在不同通道上使用不同数量的时间步长
  • textCNN模型使用一维卷积层和最大时间汇聚层将单个次元表示转换为下游应用输出
  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值