这是一个面向小白(比如,本人)的关于情感分析的系列教程 [1]。老鸽子整理了“4 - Convolutional Sentiment Analysis.ipynb”中的内容。
本文任务:使用卷积神经网络(CNN)来实现句子分类。
简介
CNN用于分析图像,包含一个或多个卷积层,紧跟一个或多个线性层。在卷积层中,使用滤波器扫描图像。扫描后的图像送入另一个卷积层或线性层。每个滤波器都有大小,如:每次使用大小的滤波器来扫描大小的图像区域,滤波器有9个对应的权重。
类似于使用滤波器查看图像区域,使用大小的滤波器来查看文本中两个连续的词(bi-gram)。
准备数据
不同于FastText模型,不用明确创建bi-grams并添加到句尾。
因为卷积层的第一个维度是batch,所以可以设置field中的batch_first为True。
划分训练集和验证集;构建词汇表;创建迭代器。
import torch
from torchtext import data
from torchtext import datasets
import random
import numpy as np
SEED = 1234
random.seed(SEED)
np.random.seed(SEED)
torch.manual_seed(SEED)
torch.backends.cudnn.deterministic = True
TEXT = data.Field(tokenize='spacy', batch_first=True)
LABEL = data.LabelField(dtype=torch.float)
train_data, test_data = datasets.IMDB.splits(TEXT, LABEL)
train_data, valid_data = train_data.split(random_state = random.seed(SEED))
#-----------------------------
MAX_VOCAB_SIZE = 25_000
TEXT.build_vocab(
train_data,
max_size = MAX_VOCAB_SIZE,
vectors = "glove.6B.100d",
unk_init = torch.Tensor.normal_
)
LABEL.build_vocab(train_data)
#-----------------------------
BATCH_SIZE = 64
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
train_iterator, valid_iterator, test_iterator = data.BucketIterator.splits(
(train_data, valid_data, test_data),
batch_size=BATCH_SIZE,
device=device
)
构建模型
在二维中可视化句中的词。每个词沿一个轴,嵌入沿另一个轴。
使用一个大小的滤波器,每次扫描n个词。
下图有4个词,每个词有5维嵌入,因此得到一个大小的“图像”张量。使用一个大小的滤波器,每次扫描两个词(黄色)。滤波器的每个元素包含一个权重,它的输出为10个嵌入元素的加权和。滤波器向下扫描(跨句)到下一个bi-gram,输出另一个加权和。滤波器再次向下扫描,计算最后的加权和。
滤波器的宽度等于“图像”的宽度,输出一个向量,它的长度等于“图像”的高度减滤波器的高度加1:。
![854e2571747f6d2f56f97f73949c2080.png](https://i-blog.csdnimg.cn/blog_migrate/50ba4d37479ff5ea7c9a379b5e38fed4.png)
本文所用的模型将有不同大小的滤波器,它们的高度分别为3、4和5,每个大小有100个,从而能够寻找与评论的情感相关的不同的tri-grams、4-grams和5-grams。
为了确定与情绪相关的最重要的n-gram,最大池化卷积层的输出。
因为模型有300个不同且重要的n-grams,所以可以认为全连接层用于加权这些n-grams,从而给出最终的判断。