(四)使用CNN实现文本情感分析(Pytorch)

更新时间:2023-06-06 02:54:27 阅读: 评论:0

(四)使⽤CNN实现⽂本情感分析(Pytorch)
⽂章⽬录
在之前的笔记中,我们设法使⽤RNNs和 中的FastText模型实现了约85%的测试准确率。在这篇笔记中,我们将使⽤卷积神经⽹络(CNN)进⾏情感分析,实现 这篇论⽂中的模型。
注意:本教程不是为了全⾯介绍和解释cnn。要获得更好更深⼊的解释,请点击和。
传统上,cnn是⽤来分析图像的,它由⼀个或多个卷积层和⼀个或多个线性层组成。卷积层使⽤过滤器(也称为内核或接受域)扫描⼀张图像,并⽣成⼀张经过处理的图像。这个处理过的图像版本可以被送⼊另⼀个卷积层或线性层。每个滤镜都有⼀个形状,例如,⼀个3x3滤镜覆盖图像的3像素宽X3像素⾼的区域,滤镜的每个元素都有⼀个权重,3x3滤镜有9个权重。在传统的图像处理中,这些权值是由⼯程师⼿⼯指定的,然⽽,神经⽹络中的卷积层的主要优点是这些权值是通过反向传播学习的。
学习权重背后的直觉思想是你的卷积层表现得像特征提取器,提取图像的部分是你的CNN最重要的⽬标,例如,如果使⽤⼀个CNN在⼀个图像中检测⾯部,CNN可能在图像中寻找⿐⼦,嘴巴和⼀双眼睛的特征。
那么,为什么要在⽂本上使⽤cnn呢?以同样的⽅式,⼀个3x3滤镜可以查看⼀个图像的碎⽚,⼀个1x2
滤镜可以查看⼀段⽂本中的2个连续的单词,即bi-gram。在前⾯的教程中我们看FastText模型使⽤bi-grams通过显式地将它们添加到⼀个⽂本,在CNN模型中,我们将使⽤多个⼤⼩不同的过滤器来观察bi-grams (1 x2 filter),tri-grams (1 x3 filter)和n-grams(1 x n filter)内的⽂本。
这⾥的直觉是,在评论中出现某些 bi-grams, tri-grams 和 n-grams是最终情感的良好指⽰。
准备数据
与之前的笔记⼀样,我们将先准备数据。
与前⾯使⽤FastText模型的笔记不同,我们将不再显式地创建bi-grams并将它们附加到句⼦末尾。
因为卷积层希望batch维度是第⼀个,所以我们可以告诉TorchText使⽤字段(field)上的batch_first = True参数返回已经排列过的数据。
import torch
from torchtext import data
from torchtext import datats
美国偶像冠军import random
import numpy as np
SEED =1234
random.ed(SEED)
np.random.ed(SEED)
torch.manual_ed(SEED)
torch.backends.cudnn.deterministic =True
TEXT = data.Field(tokenize='spacy', tokenizer_language='en_core_web_sm', batch_first=True)
LABEL = data.LabelField(dtype = torch.float)
train_data, test_data = datats.IMDB.splits(TEXT, LABEL)
train_data, valid_data = train_data.split(random_state = random.ed(SEED))
晴朗
构建词汇表并加载预先训练的单词嵌⼊。
MAX_VOCAB_SIZE = 25_000
TEXT.build_vocab(train_data,
max_size = MAX_VOCAB_SIZE,
vectors ="glove.6B.100d",
unk_init = al_)
LABEL.build_vocab(train_data)
与之前⼀样,我们创建迭代器。
BATCH_SIZE =64
device = torch.device('cuda'if torch.cuda.is_available()el'cpu')
train_iterator, valid_iterator, test_iterator = data.BucketIterator.splits( (train_data, valid_data, test_data),
batch_size = BATCH_SIZE,
device = device)
搭建模型
漂移是什么意思现在来搭建我们的模型。
第⼀个主要障碍是如何将cnn⽤于⽂本可视化。图像通常是⼆维的(我们现在将忽略存在第三个“颜⾊”维度的事实),⽽⽂本是⼀维的。然⽽,我们知道,在我们之前的教程中(以及⼏乎所有的NLP管道),第⼀步都是将单词转换为词嵌⼊。这就是我们在⼆维空间中可视化单词的⽅法,每个单词沿着⼀个轴,向量元素沿着另⼀个轴。观察下⾯嵌⼊句⼦的⼆维表⽰:
然后我们可以使⽤[n x emb_dim]的过滤器。这将完全覆盖顺序单词,因为它们的宽度将是emb_dim维
度。观察下⾯的图像,我们的单词向量是⽤绿⾊表⽰的。这⾥我们有4个5维嵌⼊的单词,创建⼀个[4x5]“图像”张量。⼀次覆盖两个单词的过滤器(例如bi-grams)将是iac
[2x5]过滤器,⽤黄⾊表⽰,过滤器的每个元素都有⼀个权重与它相关联。这个过滤器的输出(⽤红⾊显⽰)将是⼀个单个实数,它是过滤器
覆盖的所有元素的加权和。
然后,过滤器将“下移”图像(或在句⼦中移动)以覆盖下⼀个bi-gram,并计算另⼀个输出(加权和)。
最后,过滤器再次向下移动,并计算该过滤器的最终输出。
在我们的例⼦中(在⼀般情况下,滤镜的宽度等于“图像”的宽度),我们的输出将会是⼀个向量的元素个数等于图像的⾼度(或句⼦中单词的
个数)减去滤镜的⾼度再加 1,⽐如在上⾯例⼦中的4 - 2 + 1 = 3。
这个例⼦展⽰了如何计算⼀个过滤器的输出。我们的模型(以及⼏乎所有的cnn)会有很多这样的过滤器。其理念是,每个过滤器将学习不同
的特征来提取。在上⾯的例⼦中,我们希望每个[2 x emb_dim]的过滤器将寻找不同bi-grams的出现。
新东方在线网站在我们的模型中,我们也将有不同⼤⼩的过滤器,⾼度为3、4和5,每⼀个都有100个。直觉告诉我们,我们将寻找与分析电影评论情绪相
关的不同的 tri-grams, 4-grams 和 5-grams。
我们模型中的下⼀步是在卷积层的输出上使⽤池化(特别是最⼤池化)。这类似于FastText模型,在该模型中,我们对每个单词向量执⾏平均值(由F.avg_pool2d函数实现),但在这不是对维度进⾏平均值,我们是取⼀个维度上的最⼤值。下⾯是⼀个从卷积层的输出中取最⼤值(0.9)的例⼦(没有显⽰的是应⽤到卷积输出的激活函数)。
这⾥的想法是,最⼤值是决定评论情绪的“最重要”特征,对应于评论中“最重要”的n-gram。我们怎么知道“最重要的”n-gram是什么?幸运的是,我们不需要这样做!通过反向传播,过滤器的权值被改变,因此每当看到某些n-grams⾼度象征情绪时,过滤器的输出是⼀
个“⾼”值。如果这个“⾼”值是输出中的最⼤值,那么它将通过最⼤池化层。
因为我们的模型有100个3种不同尺⼨的过滤器,这意味着我们有300个不同的模型认为重要的n-grams。我们把这些连接在⼀起成为⼀个单⼀的向量,并通过⼀个线性层来预测情感。我们可以将这⼀线性层的权重看作是对每⼀个300个中n-grams的“加权证据”,然后做出最终决定。
实现细节
我们⽤nn.Conv2d来实现卷积层。in_channels参数是图像进⼊卷积层的“通道”的数量。在实际的图像中,这通常是3个通道(红⾊、蓝⾊和绿⾊通道各⼀个通道),然⽽,当使⽤⽂本时,我们只有⼀个通道,即⽂本本⾝。out_channels是过滤器的数量,kernel_size是过滤器的
n
⼤⼩。每个kernel_sizes⼤⼩都是[n x emb_dim],其中是 n-grams的⼤⼩。
在PyTorch中,RNNs想要batch维度在第⼆位,⽽CNNs想要batch维度在第⼀位——我们不必在这⾥对数据进⾏排列,因为我们已经在⽂本字段中设置了batch_first = True。然后我们通过嵌⼊层传递句⼦来获得嵌⼊。输⼊到nn.Conv2d层的第⼆个维度必须是通道维数。由于⽂本在技术上没有通道维度,我们将张量unsqueeze 以创建⼀个通道维度。这与卷积层初始化时的in_channels=1相匹配。
然后我们将张量通过卷积层和池化层,在卷积层之后使⽤ReLU激活函数。池化层的另⼀个很好的特性是它们处理不同长度的句⼦。卷积层输出的⼤⼩取决于对卷积层输⼊的⼤⼩,不同批次包含不同长度的句⼦。如果没有最⼤池化层,线性层的输⼊将取决于输⼊句⼦的⼤⼩(⽽不是我们想要的⼤⼩)。解决这个问题的⼀种⽅法是将所有的句⼦修剪成相同的长度,但是对于最⼤池化层,我们总是知道线
性层的输⼊将是过滤器的总数。注意:那么有⼀个例外,如果你的句⼦长度⽐使⽤的最⼤的过滤器短,然后你将不得不填充你的句⼦到最⼤的过滤器的长度。在IMDb数据中没有只有5个词长的评论,所以我们不需要担⼼,但如果你使⽤⾃⼰的数据,你会担⼼的。
最后,我们对过滤器的输出进⾏串联并执⾏dropout,然后将它们通过线性层来做出我们的预测。
as nn
functional as F
class CNN(nn.Module):
def__init__(lf, vocab_size, embedding_dim, n_filters, filter_sizes, output_dim,
dropout, pad_idx):
super().__init__()
某年某月某日英文
out_channels = n_filters,
kernel_size =(filter_sizes[0], embedding_dim))
out_channels = n_filters,
kernel_size =(filter_sizes[1], embedding_dim))
out_channels = n_filters,
kernel_size =(filter_sizes[2], embedding_dim))
lf.fc = nn.Linear(len(filter_sizes)* n_filters, output_dim)
lf.dropout = nn.Dropout(dropout)
def forward(lf, text):
#text = [batch size, nt len]
embedded = lf.embedding(text)
#embedded = [batch size, nt len, emb dim]
embedded = embedded.unsqueeze(1)
badminton的音标#embedded = [batch size, 1, nt len, emb dim]
conved_0 = F.v_0(embedded).squeeze(3))
conved_1 = F.v_1(embedded).squeeze(3))
pictures是什么意思
respectedconved_2 = F.v_2(embedded).squeeze(3))
#conved_n = [batch size, n_filters, nt len - filter_sizes[n] + 1]
pooled_0 = F.max_pool1d(conved_0, conved_0.shape[2]).squeeze(2)
pooled_1 = F.max_pool1d(conved_1, conved_1.shape[2]).squeeze(2)
pooled_2 = F.max_pool1d(conved_2, conved_2.shape[2]).squeeze(2)
#pooled_n = [batch size, n_filters]
eruptioncat = lf.dropout(torch.cat((pooled_0, pooled_1, pooled_2), dim =1))
#cat = [batch size, n_filters * len(filter_sizes)]
return lf.fc(cat)
⽬前CNN模型只能使⽤3个不同⼤⼩的过滤器,但我们实际上可以改进我们模型的代码,使其更通⽤,并采取任何数量的过滤器。
我们把所有的卷积层放到⼀个nn.ModuleList中,nn.ModuleList是⼀个⽤来保存PyTorch 列表的函数。如果我们只是简单地使⽤⼀个标准的Python列表,列表中的模块不能被列表之外的任何模块“看到”,这会导致⼀些错误。

本文发布于:2023-06-06 02:54:27,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/90/135460.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:过滤器   图像   卷积   模型   单词   输出   维度   评论
相关文章
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图