动手学pytorch-文本情感分类

文本情感分类

1.文本情感分类数据集

2.使用循环神经网络进行情感分类

3.使用卷积神经网络进行情感分类

1.文本情感分类数据

在本中,将应用预训练的词向量和含多个隐藏层的双向循环神经网络与卷积神经网络,来判断一段不定长的文本序列中包含的是正面还是负面的情绪。

使用斯坦福的IMDb数据集(Stanford’s Large Movie Review Dataset)作为文本情感分类的数据集。

读取数据

数据集文件夹结构:

预处理数据

读取数据后,先根据文本的格式进行单词的切分,再利用 torchtext.vocab.Vocab 创建词典。

词典和词语的索引创建好后,就可以将数据集的文本从字符串的形式转换为单词下标序列的形式,以待之后的使用。

创建数据迭代器

利用 torch.utils.data.TensorDataset,可以创建 PyTorch 格式的数据集,从而创建数据迭代器。

2.使用循环神经网络进行情感分类

使用双向循环神经网络:

Image Name

Image Name

给定输入序列 \(\{\boldsymbol{X}_1,\boldsymbol{X}_2,\dots,\boldsymbol{X}_T\}\),其中 \(\boldsymbol{X}_t\in\mathbb{R}^{n\times d}\) 为时间步(批量大小为 \(n\),输入维度为 \(d\))。在双向循环神经网络的架构中,设时间步 \(t\) 上的正向隐藏状态为 \(\overrightarrow{\boldsymbol{H}}_{t} \in \mathbb{R}^{n \times h}\) (正向隐藏状态维度为 \(h\)),反向隐藏状态为 \(\overleftarrow{\boldsymbol{H}}_{t} \in \mathbb{R}^{n \times h}\) (反向隐藏状态维度为 \(h\))。我们可以分别计算正向隐藏状态和反向隐藏状态:

\[\begin{aligned} &\overrightarrow{\boldsymbol{H}}_{t}=\phi\left(\boldsymbol{X}_{t} \boldsymbol{W}_{x h}^{(f)}+\overrightarrow{\boldsymbol{H}}_{t-1} \boldsymbol{W}_{h h}^{(f)}+\boldsymbol{b}_{h}^{(f)}\right)\\ &\overleftarrow{\boldsymbol{H}}_{t}=\phi\left(\boldsymbol{X}_{t} \boldsymbol{W}_{x h}^{(b)}+\overleftarrow{\boldsymbol{H}}_{t+1} \boldsymbol{W}_{h h}^{(b)}+\boldsymbol{b}_{h}^{(b)}\right) \end{aligned} \]

其中权重 \(\boldsymbol{W}_{x h}^{(f)} \in \mathbb{R}^{d \times h}, \boldsymbol{W}_{h h}^{(f)} \in \mathbb{R}^{h \times h}, \boldsymbol{W}_{x h}^{(b)} \in \mathbb{R}^{d \times h}, \boldsymbol{W}_{h h}^{(b)} \in \mathbb{R}^{h \times h}\) 和偏差 \(\boldsymbol{b}_{h}^{(f)} \in \mathbb{R}^{1 \times h}, \boldsymbol{b}_{h}^{(b)} \in \mathbb{R}^{1 \times h}\) 均为模型参数,\(\phi\) 为隐藏层激活函数。

然后我们连结两个方向的隐藏状态 \(\overrightarrow{\boldsymbol{H}}_{t}\)\(\overleftarrow{\boldsymbol{H}}_{t}\) 来得到隐藏状态 \(\boldsymbol{H}_{t} \in \mathbb{R}^{n \times 2 h}\),并将其输入到输出层。输出层计算输出 \(\boldsymbol{O}_{t} \in \mathbb{R}^{n \times q}\)(输出维度为 \(q\)):

\[\boldsymbol{O}_{t}=\boldsymbol{H}_{t} \boldsymbol{W}_{h q}+\boldsymbol{b}_{q} \]

其中权重 \(\boldsymbol{W}_{h q} \in \mathbb{R}^{2 h \times q}\) 和偏差 \(\boldsymbol{b}_{q} \in \mathbb{R}^{1 \times q}\) 为输出层的模型参数。不同方向上的隐藏单元维度也可以不同。

利用 torch.nn.RNNtorch.nn.LSTM 模组,可以很方便地实现双向循环神经网络,下面是以 LSTM 为例的代码。

加载预训练的词向量

由于预训练词向量的词典及词语索引与我们使用的数据集并不相同,所以需要根据目前的词典及索引的顺序来加载预训练词向量。

训练模型

由于嵌入层的参数是不需要在训练过程中被更新的,所以我们利用 filter 函数和 lambda 表达式来过滤掉模型中不需要更新参数的部分。

评价模型

3.使用卷积神经网络进行情感分类

一维卷积层

在介绍模型前我们先来解释一维卷积层的工作原理。与二维卷积层一样,一维卷积层使用一维的互相关运算。在一维互相关运算中,卷积窗口从输入数组的最左方开始,按从左往右的顺序,依次在输入数组上滑动。当卷积窗口滑动到某一位置时,窗口中的输入子数组与核数组按元素相乘并求和,得到输出数组中相应位置的元素。如图所示,输入是一个宽为 7 的一维数组,核数组的宽为 2。可以看到输出的宽度为 7−2+1=6,且第一个元素是由输入的最左边的宽为 2 的子数组与核数组按元素相乘后再相加得到的:0×1+1×2=2。

Image Name

多输入通道的一维互相关运算也与多输入通道的二维互相关运算类似:在每个通道上,将核与相应的输入做一维互相关运算,并将通道之间的结果相加得到输出结果。下图展示了含 3 个输入通道的一维互相关运算,其中阴影部分为第一个输出元素及其计算所使用的输入和核数组元素:0×1+1×2+1×3+2×4+2×(−1)+3×(−3)=2。

Image Name

由二维互相关运算的定义可知,多输入通道的一维互相关运算可以看作单输入通道的二维互相关运算。如图所示,我们也可以将图中多输入通道的一维互相关运算以等价的单输入通道的二维互相关运算呈现。这里核的高等于输入的高。图中的阴影部分为第一个输出元素及其计算所使用的输入和核数组元素:2×(−1)+3×(−3)+1×3+2×4+0×1+1×2=2。

Image Name

注:反之仅当二维卷积核的高度等于输入的高度时才成立。

之前的例子中输出都只有一个通道。我们在“多输入通道和多输出通道”一节中介绍了如何在二维卷积层中指定多个输出通道。类似地,我们也可以在一维卷积层指定多个输出通道,从而拓展卷积层中的模型参数。

时序最大池化层

类似地,我们有一维池化层。TextCNN 中使用的时序最大池化(max-over-time pooling)层实际上对应一维全局最大池化层:假设输入包含多个通道,各通道由不同时间步上的数值组成,各通道的输出即该通道所有时间步中最大的数值。因此,时序最大池化层的输入在各个通道上的时间步数可以不同。

Image Name

注:自然语言中还有一些其他的池化操作,可参考这篇博文

为提升计算性能,我们常常将不同长度的时序样本组成一个小批量,并通过在较短序列后附加特殊字符(如0)令批量中各时序样本长度相同。这些人为添加的特殊字符当然是无意义的。由于时序最大池化的主要目的是抓取时序中最重要的特征,它通常能使模型不受人为添加字符的影响。

TextCNN 模型

TextCNN 模型主要使用了一维卷积层和时序最大池化层。假设输入的文本序列由 \(n\) 个词组成,每个词用 \(d\) 维的词向量表示。那么输入样本的宽为 \(n\),输入通道数为 \(d\)。TextCNN 的计算主要分为以下几步。

  1. 定义多个一维卷积核,并使用这些卷积核对输入分别做卷积计算。宽度不同的卷积核可能会捕捉到不同个数的相邻词的相关性。
  2. 对输出的所有通道分别做时序最大池化,再将这些通道的池化输出值连结为向量。
  3. 通过全连接层将连结后的向量变换为有关各类别的输出。这一步可以使用丢弃层应对过拟合。

下图用一个例子解释了 TextCNN 的设计。这里的输入是一个有 11 个词的句子,每个词用 6 维词向量表示。因此输入序列的宽为 11,输入通道数为 6。给定 2 个一维卷积核,核宽分别为 2 和 4,输出通道数分别设为 4 和 5。因此,一维卷积计算后,4 个输出通道的宽为 11−2+1=10,而其他 5 个通道的宽为 11−4+1=8。尽管每个通道的宽不同,我们依然可以对各个通道做时序最大池化,并将 9 个通道的池化输出连结成一个 9 维向量。最终,使用全连接将 9 维向量变换为 2 维输出,即正面情感和负面情感的预测。

Image Name

下面我们来实现 TextCNN 模型。与上一节相比,除了用一维卷积层替换循环神经网络外,这里我们还使用了两个嵌入层,一个的权重固定,另一个则参与训练。

训练并评价模型

posted @   hou永胜  阅读(2844)  评论(0编辑  收藏  举报
编辑推荐:
· 用 C# 插值字符串处理器写一个 sscanf
· Java 中堆内存和栈内存上的数据分布和特点
· 开发中对象命名的一点思考
· .NET Core内存结构体系(Windows环境)底层原理浅谈
· C# 深度学习:对抗生成网络(GAN)训练头像生成模型
阅读排行:
· 趁着过年的时候手搓了一个低代码框架
· 本地部署DeepSeek后,没有好看的交互界面怎么行!
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· 用 C# 插值字符串处理器写一个 sscanf
· 乌龟冬眠箱湿度监控系统和AI辅助建议功能的实现
点击右上角即可分享
微信分享提示