情感分析教程+心法!如何用 Apache MXNet 看懂电影影评

更多深度文章,请关注云计算频道:https://yq.aliyun.com/cloud

handwriting_2630118_1920_crop_45ff7b8abafe157115cc38ef969b9743
情感分析已经在数据科学界占有一席之地。企业可以在社交媒体上对其产品的评价,并主动出击,解决满意度问题。不过,人类的情感和语言非常复杂,机器学习的各种技术中,就数深度学习最有能力处理这些复杂的输入数据。
这份教程中,我们将使用 Apache MXNet 打造神经网络,目的是创造一个电影影评的分类器,能够根据一段简评判断作者对电影的评价是好是坏。之所以选择 Apache MXNet 而不是 TensorFlow等其他深度学习框架,是因为 Apache MXNet 有很好的灵活度,能在多个 GPU 上扩展使用,它也因此越来越普及。
我建议你下载这份完整心法,我们在这里创建和运行了所有的代码。
我鼓励大家自己调整一下超参数,试验一下神经网络架构和数据准备的各种方法,看看你能否超越我们的精准度。

要阅读这份心法,你必须对一下领域有基本了解:卷积运算、神经网络、激活单元、梯度下降和 NumPy。

完成心法,你将获得以下技能:

  1. 理解情感分析的复杂度;
  2. 理解词嵌入及其用法;
  3. 准备用于训练神经网络的数据库;
  4. 完成定制神经网络架构,用于在各种模型中分类情感;
  5. 将结果视觉化,利用 t-sne 理解我们的模型;
  6. 使用 glove 等预制嵌入,训练带有限制条件的数据,例如小数据库或者短句。

**情感分析
**
虽然只是分类“好评”、“差评”,但是情感分析很复杂。试想你上豆瓣看到这条影评:“这部电影主题很蠢,制作粗糙,情节粗俗——我超爱。”虽然这句话里有很多负面的词语(“蠢”、“粗糙”、“粗俗”),但是情感却是正面的(“我超爱”)。再试想另一条影评:“毫无内涵、幽默、或者任何形式的智商。”虽然这句话里有很多积极的词汇,但却是一条负面影评。还有一些影评包涵讽刺:“看完《飓风营救3》,《飓风2》就好像一部史诗巨作。”如果你理解语境(《飓风2》其实也不咋滴),你就知道这是一条负面影评了。
正是由于语境,情感分析才不容易。情感分析器在某一数据库上表现还行,但换一个数据库可能就不行了。

嵌入数据库
表格数据的编码是简单的。甚至图片编码都比文字更简单——每一个像素的值都在 0-225 的 RGB 值之间,是一个二维数组。改变图像的大小也不会改变其内容。但是,要把自然语言编码为数字就没这么直接了。每一种语言的词汇量都很惊人,改变句子的长度也可能改变句子的意思。
举个例子。假设以下词语构成我们全部的词汇量:{我,爱,蛋糕,讨厌,披萨}。我们可以组两个句子:“我爱蛋糕”和“我讨厌披萨”。
如何将这些句子编码成数字呢?有一种表征词汇的方法是使用热独编码:
1

这种表征中,如果我门有 N 个单词,就需要 NxN 大小的矩阵,成为词汇矩阵,构成了单词的查找表格。
现在,我们来试试编码整个句子。“我讨厌披萨”就变成以下的这个矩阵:
2

MNNet 神经网络中的嵌入层也进行同样的查找运算,这与词嵌入方法不同。
词嵌入是一种更好的方法,是一种连续而非离散的词语表征。词嵌入矩阵长这样:
3

我们使用 Nx3、而非 NxN 矩阵,3是嵌入的大小。因此,每个词语都可以表征为一个3维、而非 N 维的矢量。
词嵌入不仅减少了词汇矩阵的表征大小,也将词语之间的语义联系进行了编码。例如,“蛋糕”和“披萨”的嵌入矢量相似,因为两者都是食物;“爱”和“讨厌”在第二维度的量级相同,因为两者都是情感。不过,“爱”和“讨厌”在第一维度的量级不同,因为两者代表了相反的情绪。
深度神经网络可以在情感分类中自动学会这些词嵌入。某些词语的嵌入矢量可以看作是权重,可以让深度神经网络去学习。这些嵌入技术还可以用在图像或其他数据上,通常被称为自动编码网。简单来说,自动编码器会在信息损失最小的前提下,尽可能表征低维度空间的输入。详细解释请点击这里

句子卷积
用嵌入层把句子编码成矩阵之后,就可以进行1D卷积,这与2D图像上的2D卷积类似。卷积滤镜的大小取决于我们想用的 n-gram。
4
接下来,我们来看看到底如何用 MXNet 上使用真实的影评句子进行情感分类。

**准备环境
**
如果你使用 AWS 云服务,可以使用专为深度学习配置的 Amazon Machine Image,这样你可以跳过以下步骤中的 1-5。
如果你是在 Conda 环境下,激活环境后需要在 Conda 里安装PIP,方法是输入 “conda install pip”。
详细安装步骤如下:

  1. 安装包管理器 Anaconda,能帮你轻松安装相关的 Python 软件库。
  2. 安装 scikit learn,这是一个通用的科学计算软件库,用来处理我们的数据。安装方法是“conda install scikit-learn”。
  3. 打开 Jupiter Notebook,输入“conda install jupiter notebook”。
  4. 然后,安装开源深度学习库 MXNet。

接下来的三个步骤是为了将词嵌入视觉化。视觉化不是必须的,但是我强烈推荐。

  1. 为了 bhtsne,使用 cython。
  2. 我们需要 bhtsne,它是 tnse 在 C++ 和 Python 里的操作。不要用 scikit-learn 里的 tnse 操作,会损坏 Python 内核。
  3. 最后,我们需要 matplotlib 用于绘图和视觉化。

以下是一些在 anaconda 环境下你所需要的代码。

conda install pip
pip install opencv-python
conda install scikit-learn
conda install jupyter notebook
pip install mxnet
conda install -c anaconda cython
pip install bhtsne
conda install -c anaconda matplotlib

**数据库
**
现在我们使用一个斯坦福的电影评论数据库,你可以在这里下载
数据库中,训练库和测试库各有 25,000 个样本,每个库中都各有 12,500 个正面和负面情感。为了简单起见,我们只用训练库。
以下是用于加载数据的代码。我们用 1 标记正面情感,用 0 标记负面情感。因为我们用 MXnet 的 softmaxoutput 来运行分类,就不用热独编码标签。如果使用其他框架,热独编码就可能是必须的。
Screen_Shot_2017_10_07_at_07_15_28

**准备数据库和编码
**
我们从标准的数据准备开始。清理数据,清除链接和特殊字符等。然后打造词汇库,也就是数据库中所有不重复的词语。
我们需要找出评论中最常见的词,这样一些相对少见的词语(例如导演的名字)不会影响分类器的结果。把每一个词根据出现频率进行倒序排序,配对其排序的数字(idx),保存在词典里,称为 word_dict。此外,我们进行从 idx 到词语的反响映射。我们只处理最常见的 5,000 个词,句子长度为 500 个词,嵌入维度是 50。
Screen_Shot_2017_10_07_at_07_18_04
Screen_Shot_2017_10_07_at_07_18_47
Screen_Shot_2017_10_07_at_07_19_47

接下来,使用 word_dict 将句子编码为数字。以下为所需代码:
Screen_Shot_2017_10_07_at_07_20_22

然后,把句子长度变为 500 词,可以根据句子的实际数据选择不同的长度。
Screen_Shot_2017_10_07_at_07_20_42

然后,将数据分为训练、验证和测试数据。
Screen_Shot_2017_10_07_at_07_21_32

**打造深度网络
**
打造神经网络需要多多试验,我们也可以选择一个其他研究人员用于解决相似问题的神经网络。我们从一个简单的网络开始,然后转移到更复杂的神经网络架构。
多亏了 MXNet 标志性的 API,神经网络的代码非常简洁:
Screen_Shot_2017_10_07_at_07_22_25

我们来分解一下代码。首先,创造一个数据层(输入层),在训练中存放数据库:data = mx.symbol.Variable('data')
vocab_embed 层在嵌入矩阵中运行查找:
embed_layer_1 = mx.sym.Embedding (data=input_x_1, input_dim=vocab_size, output_dim=embedding_dim, name='vocab_embed')

平面化图层使用维度为 seq_len x 嵌入维度,将嵌入层权重放到一个 1 x (seq_len*embedding)的栏矢量,作为下一个全连接层的输入。
flatten_1 = mx.sym.Flatten(data=embed_layer_1)

全连接层将每一个神经元(输出)从平面化图层连接到目前的层:
mx.sym.FullyConnected(data=flatten_1, num_hidden=500,name="fc1")

relu3_1 层在学习复杂函数的输入上进行非线性激活:
relu3_1 = mx.sym.Activation(data=fc1_1, act_type="relu" , name="relu3")

最终的全连接层(softmax)进行分类。MXNet 里的 SoftmaxOutput 层进行输出的热独编码,然后应用到 softmax 函数。

训练网络
使用 GPU 训练最多可以减少 91% 的训练时间。我们把过一遍训练库,称为一个 “epoch” (纪元),我们将网络训练三个“纪元”,即“num_epoch = 3”。训练过的模型定期存在一个 JSON 文件中,并测量训练和验证精度,来看看神经网络学习得如何。
以下是所需代码:
Screen_Shot_2017_10_07_at_07_27_05

视觉化
以下代码能帮助将结果视觉化,让我们对模型有更直观的认识。我们可以获得模型生成的嵌入权重,然后用 tnse 视觉化。
要在 2-d 里将 vocab-size*embedding_dim 矢量视觉化是不可能的。我们需要减少数据的维度。以下代码可以抽取嵌入权重,并将其视觉化为一个散点图。
Screen_Shot_2017_10_07_at_07_28_13

以下是 t-sne 将排名最高的 500 个词的权重视觉化的结果:
5

我们可以看出,模型自动学会了“出色、很棒、优秀”等词的意思是类似的。然后,我们写一个简单的预测函数来使用生成的模型。

样本预测
我们需要加载以下的保存模型:
Screen_Shot_2017_10_07_at_07_29_43

然后使用 word_dict 的指数将句子编码,把它作为分类器交给模型。
Screen_Shot_2017_10_07_at_07_30_01

输出是:[0.09290998 0.90709001],这意味着分类器以 0.9 的概率预测情感。
不过,这个模型在预测时只考虑了单个词语。如果考虑词与词之间的关系就更好了,这就需要打造一个卷积神经网络,同时考虑多个联系词语。

打造卷积模型
这和之前的模型类似,只是需要大小为 5 的卷积滤镜。
Screen_Shot_2017_10_07_at_07_32_05

唯一困难的是 conv_input_2 输入层,会将嵌入层的输出格式改为适合卷积层的格式。其他部分都是一样的。

**打造“多个卷积”模型
**
这与之前的模型类似,出了使用不同大小的卷积(3,4,5)来创建模型,然后将输出连接起来并平面化。增加一个 maxpool 层来避免过度拟合。以下是所需的 python 代码:
Screen_Shot_2017_10_07_at_07_32_42
Screen_Shot_2017_10_07_at_07_34_00

**利用 glove 进行转移学习
**
生成嵌入需要很多数据,但如果只有少量数据怎么办?我们可以从另一个预先训练的神经网络中转移权重。
我们在这儿使用斯坦福开发的 Wikipedia -2014 glove 嵌入,是使用维基百科的六十亿词语训练而来的。我们使用 50 维度嵌入来训练神经网络,这也是一个超参数,你可以试试不同的值,看看什么结果最好。以下函数将嵌入矢量加载到一个嵌入矩阵中(numPy 矩阵):
Screen_Shot_2017_10_07_at_07_35_17
Screen_Shot_2017_10_07_at_07_35_38

我们可以使用 t-sne 来将 glove 嵌入视觉化:
Screen_Shot_2017_10_07_at_07_36_54

如下:
6

如你所见,相似的词语归为了一组(“差,糟糕,超烂”)。我们可以用它来创建神经网络用语分类句子。增加预先训练的权重可能有点难,以下是所需的代码:
Screen_Shot_2017_10_07_at_07_38_19

我们先将 glove embedding_matrix 转换为 mx.nd.array。然后,创建一个名为权重的变量,值为 the_emb_3,作为参数传递给 mx.sym.Embedding 中的 embed_layer_3。
接下来,将 weight_matrix 作为 embed_layer_3 的默认值进行训练。另外,我门需要冻结嵌入层的权重,这样在返向传播的时候 embed_matrix 的值就不会更新。要记得将 API 模块中的 fixed_param_names = [‘weights’] 传递,冻结嵌入层的权重。以下是 Python 代码:
Screen_Shot_2017_10_07_at_07_39_51

可以看出,对于这个数据库来说 glove 词嵌入(预先训练的词嵌入)没有生成更好的模型。试试不同维度的词嵌入、使用神经元更多的模型可能会更好。还可以试试 LTSM 和 GRU 等递归神经网络。

**总结
**
这个教程中,我们用一个影评数据库进行了情感分类。我们使用 MXNet 开发了不同复杂度的模型,理解了嵌入的概念,尝试了模型所学的权重进行视觉化。最后,我们还使用 glove 嵌入进行了转移学习。

**作者信息
**
Manu Jeevan 是自学的数据科学家、 AI Solutions 的联合创始人,公司为其他企业提供人工智能解决方案。
Suresh Rathnaraj 是机器学习工程师,热爱深度学习应用、足球和瑜伽,也是 AI Solutions 的联合创始人。

本文由北邮@爱可可-爱生活老师推荐,阿里云云栖社区组织翻译。
文章原标题《Sentiment analysis with Apache MXNet》
作者:Manu Jeevan、Suresh Rathnaraj, 译者:炫。

文章为简译,更为详细的内容,请查看原文

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值