赞
踩
近年来,深度学习技术在自然语言处理、计算机视觉等多个人工智能领域得 到了广泛的应用,获得了很大的成功。传统的机器学习算法通常结构较浅,比如支持向量机和逻辑回归等算法。浅结构模型很难学习复杂的功能,对自然语言处理等复杂任务的学习能力比较有限,通常需要手动定义特征。
深度学习模型表现力强,比如循环神经网络、卷积神经网络、长短期记忆神经网络、门控循环单元等,能很好地适应复杂的函数,从数据中自动学习有用的功能,从而减轻人为的干预。
多层感知机是具有深层结构的初期神经网络,通常由输入层、隐藏层、输出层三个层次构成,下图就是一个标准的三层神经网络模型。但是,由于梯度消失和梯度爆炸的缺点,难以优化具有深层结构的神经网络。到 2006 年为止, Hinton 等提出了可靠的神经网络模型。使用无监督的方法预先训练各层的参数,并将其作为深度模型的初始参数使用,从而解决了深度神经网络难以优化的问题。
下图是一个神经元结构图,其中
x
i
x_i
xi 代表输入信息,一般为外部信息或者上层的输出部分,
w
i
w_i
wi 对应到每个
x
i
x_i
xi 的权值。
首先将输入部分进行加权求和,并加上神经网络的额外输入偏移值,最后利用下面公式的表征函数进行转换。
g
(
x
)
=
f
(
∑
i
=
1
n
x
i
w
i
−
b
)
g(x)=f(\sum_{i=1}^{n}x_iw_i-b)
g(x)=f(i=1∑nxiwi−b)
转换完之后,利用激活函数将非线性引入神经网络,通常用到的激活函数包括
s
i
g
m
o
i
d
sigmoid
sigmoid函数、
t
a
n
h
tanh
tanh函数等,不同的激活函数的计算方法与值域也不同。下面公式是
t
a
n
h
tanh
tanh函数的计算方法,其输出范围是
(
−
1
,
1
)
(-1,1)
(−1,1)。
t
a
n
h
(
x
)
=
e
x
−
e
−
x
e
x
+
e
−
x
tanh(x)=\frac{e^x-e^{-x}}{e^x+e^{-x}}
tanh(x)=ex+e−xex−e−x
将多个上述基本神经元进行组合,就可以构成一个神经网络。
循环神经网络(Recurrent Neural Networks,RNN)是指一个随着时间的推移, 重复发生的结构。RNN 对具有序列特性的数据非常有效,它能挖掘数据中的时序信息以及语义信息。RNN 之所以被称之为循环,是因为它对序列的每一个部分都执行相同的任务,从而能够充分利用上下文的信息,而传统的神经网络的输入都是彼此相互独立的。除此之外,RNN 能够记忆处理过的信息,在处理长序列信息时效果更显著。
上图是RNN的展开图,其中,
X
X
X 表示输入的向量,
U
U
U表示从输入到隐藏层计算需要的权值矩阵,
S
S
S表示由上一时刻的隐藏层输出的权值矩阵,
V
V
V表示从隐藏层到输出之间计算需要的权值矩阵。
t
t
t时刻的输入向量
s
t
s_t
st首先通过
U
U
U与
S
S
S两个矩阵计算出其隐藏层的状态,计算过程如下面公示所示。
s
t
=
f
(
U
x
t
+
S
s
t
−
1
)
s_t=f(U_{x_t}+S_{s_{t-1}})
st=f(Uxt+Sst−1)
然后通过
V
V
V计算并归一化,得到输出结果
o
t
o_t
ot,其计算过程如下面公式所示。
o
t
=
s
o
f
t
m
a
x
(
V
s
t
)
o_t=softmax(Vs_t)
ot=softmax(Vst)
与前馈神经网络模型相比,循环神经网络能够让隐藏层的神经元相互交流, 但它也存在一些问题,比如梯度爆炸和梯度消失等问题。
长短期记忆神经网络(Long-Short Term Memory,LSTM)是一种特殊的 RNN, 它能够学习长期的依赖关系,是为了解决 RNN 长时期依赖出现的梯度爆炸和梯 度消失的问题而出现的。它在处理各种各样的问题上表现出色,现在自然语言处理等领域已广泛使用。双向长短期记忆神经网络(Bi-directional Long Short Term Memory, BiLSTM)在 LSTM的基础上,结合了输入序列在前向和后向两个方向上的信息,而能够更充分的考虑到未来的上下文信息。
下图是LSTM的模块结构图。
LSTM有三个不同的门来控制信息的交互:输入门
i
t
i_t
it、遗忘门
f
t
f_t
ft、输出门
o
t
o_t
ot。对于
t
t
t时刻的输入
x
t
x_t
xt,在
t
−
1
t-1
t−1时刻生成
h
t
−
1
h_{t-1}
ht−1、
c
t
−
1
c_{t-1}
ct−1,其中
c
t
−
1
c_{t-1}
ct−1的状态决定
t
t
t时刻的输入是否可用,遗忘
t
−
1
t-1
t−1时刻存储的记忆,并输出生成的状态。以下公式描述了上述过程:
i
t
=
σ
(
W
x
i
x
t
+
W
h
i
h
t
−
1
+
W
c
i
c
t
−
1
+
b
i
)
i_t=\sigma (W_{xi}x_t+W_{hi}h_{t-1}+W_{ci}c_{t-1}+b_i)
it=σ(Wxixt+Whiht−1+Wcict−1+bi)
f
t
=
σ
(
W
x
f
x
t
+
W
h
f
h
t
−
1
+
W
c
f
c
t
−
1
+
b
f
)
f_t=\sigma (W_{xf}x_t+W_{hf}h_{t-1}+W_{cf}c_{t-1}+b_f)
ft=σ(Wxfxt+Whfht−1+Wcfct−1+bf)
g
t
=
t
a
n
h
(
W
x
c
x
t
+
W
h
c
h
i
−
1
+
W
c
c
c
t
−
1
+
b
c
)
g_t=tanh(W_{xc}x_t+W_{hc}h_{i-1}+W_{cc}c_{t-1}+b_c)
gt=tanh(Wxcxt+Whchi−1+Wccct−1+bc)
c
t
=
i
t
g
t
+
f
t
c
t
−
1
c_t=i_tg_t+f_tc_{t-1}
ct=itgt+ftct−1
o
t
=
σ
(
W
x
o
x
t
+
W
h
o
h
i
−
1
+
W
c
o
c
t
+
b
o
)
o_t=\sigma(W_{xo}x_t+W_{ho}h_{i-1}+W_{co}c_{t}+b_o)
ot=σ(Wxoxt+Whohi−1+Wcoct+bo)
h
t
=
o
t
t
a
n
h
(
c
t
)
h_t=o_ttanh(c_t)
ht=ottanh(ct)
BiLSTM由两个LSTM所组成,一个正向的LSTM利用过去的信息进行计算,一个逆向的LSTM利用未来的信息进行计算,最后将同一位置的两个输出拼接进行输出。这样在某一时刻,能够同时利用该时刻与前一时刻的信息。由于BiLSTM 能够同时利用过去时刻和未来时刻的信息,因此相较于单向的LSTM, 其得到的结果更加准确。下图是BiLSTM的示意图。
门控循环单元(Gated Recurrent Unit,GRU) 是经改进的一种RNN。和 LSTM 一样,也是为了解决长期记忆和反向传播中的梯度等问题而提出来的。除了GRU的输入输出部分与RNN 相同,GRU 模型首先利用上一个传输下来的状态 h t − 1 h_{t-1} ht−1与当前节点的输入 x t x_t xt来获取两个门控状态,再使用重置门控来得到重置后的数据 r t r_t rt,以及更新后的数据 z t z_t zt,最后将单元状态与输出合并为一个状态 h t h_t ht,下图是具体的模型。
一个 GRU 模型可以形式化的表示为:
r
t
=
σ
(
w
r
⋅
)
r_t=\sigma (w_r\cdot )
rt=σ(wr⋅)
z
t
=
σ
(
w
z
⋅
[
h
t
−
1
,
x
t
]
)
z_t=\sigma(w_z\cdot [h_{t-1},x_t])
zt=σ(wz⋅[ht−1,xt])
h
t
^
=
t
a
n
h
(
w
h
⋅
[
r
t
⋅
h
t
−
1
,
x
t
)
\widehat{h_t}=tanh(w_h\cdot[r_t\cdot h_ {t-1},x_t)
ht
=tanh(wh⋅[rt⋅ht−1,xt)
y
t
=
σ
(
w
o
⋅
h
t
)
y_t=\sigma(w_o\cdot h_t)
yt=σ(wo⋅ht)
h
t
=
(
1
−
z
t
)
⋅
h
t
−
1
+
z
t
⋅
h
t
^
h_t=(1-z_t)\cdot h_{t-1}+z_t\cdot \widehat{h_t}
ht=(1−zt)⋅ht−1+zt⋅ht
其中,σ 表示模型用到的激活函数,一般设置为sigmoid函数;重置之后的数据用 tanh 函数进行激活;
x
t
x_t
xt代表运行到t时刻的的输入部分;
h
t
h_t
ht代表 t 时刻的输出部分;
z
t
z_t
zt代表更新门;
r
t
r_t
rt代表重置门,GRU 的参数更新方式是基于沿时间反向传播的算法。
LeCun 等在1989年提出了卷积神经网络(Convolutional Neural Networks,CNN ),该网络能够对输入的内容进行局部感知,提取出事物的特征。早先 CNN 大多在图像处理这一领域大量使用,后来很多学者利用其对该事物进行分类、识别、预测和决策。
如上图所示,CNN 由卷积层、池化层、全连接层组成。对于输入的信息,首先利用不同的卷积核对输入的信息进行特征提取。其次经过池化层筛选卷积层输出中的局部信息,有效控制过拟合。最后通过全连接层将前面经过多次 卷积后高度抽象化的特征进行整合和归一化。
以一个解决文本分类任务的卷积神经网络为例介绍其每一层的实现。假设该网络模型的输入是含有 n 个词的文本 T=(x1,x2,…,xn),首先利用下面公式进行卷积运算。
x
1
n
=
x
1
⊕
x
2
⊕
…
⊕
x
n
x_{1n}=x_1\oplus x_2\oplus…\oplus x_n
x1n=x1⊕x2⊕…⊕xn
其中
⊕
\oplus
⊕表示卷积操作,
x
i
:
i
+
j
x_{i:i+j}
xi:i+j 表示从第 i 个词语到第 i+j 个词语进行卷积运算。w 代表卷积核,h 代表卷积核的长度,b代表卷积核的偏移值,f 代表一个非线性函数。则计算从第 i 个词语到第 i+h个词语的特征的公式如下所示。
c
i
=
f
(
w
⋅
x
i
:
i
+
h
+
b
)
c_i=f(w\cdot x_{i:i+h}+b)
ci=f(w⋅xi:i+h+b)
将每个词语在不同窗口大小中计算出的特征值整合在一个集合中,接下来进行最大池化操作,如以下公式所示。
c
^
=
m
a
x
(
c
1
,
c
2
,
…
,
c
n
−
h
)
\widehat {c}=max(c_1,c_2,…,c_{n-h})
c
=max(c1,c2,…,cn−h)
这个最大值
c
^
\widehat {c}
c
就是该卷积核对应的特征值。最后经过全连接层进行整合和归一化,对文本的各种分类情况输出一个概率,根据得到的概率就能实现文本分类任务。
情感分析的对象最小粒度是词汇,但是表达一个情感的最基本的单位则是句子,词汇虽然能描述情感的基本信息,但是单一的词汇缺少对象及关联程度,且不同的词汇组合起来得到的情感程度不同甚至倾向都相反,因此以句子为基本单位是最为合理的。
目前情感分析使用的方法有:
(1)基于词典的方法:通过预先定义一系列的情感词典和规则,对文本进行分词分句,计算情感值来作为文本的情感倾向判断依据。
(2)基于机器学习的方法:对于情感极性的判断,将目标情感分为三类:正(positive)、中(neutral)、负(negative)。对训练文本进行人工标注,然后进行有监督的机器学习过程,并对测试结果用模型来预测结果。
(3)基于深度学习的方法:基于机器学习的方法需要手动设计特征,工作量较大,而深度学习模型(如LSTM)可以从文本中自动提取特征。
下面分别采用机器学习和深度学习的方法进行情感分析,并对比性能。
数据为从京东爬取的产品评论数据,原始数据共215033条,下图为数据示例:
从原始数据集中抽取品牌为美的的产品评论数据,共55774条。再对原始数据去除重复的评论并对用词进行压缩,去重后的评论共53049条。
利用SnowNLP包对评论进行类标标注,节省人工标注成本。
import csv, codecs
from snownlp import SnowNLP
with codes.open(inputfile, 'r', encoding = 'utf-8') as inf:
for line in inf:
if not line.strip():
continue
sentscore = round((SnowNLP(line.strip()).sentiments-0.5)*20)
if sentscore > 0:
outf_pos.write(str(sentscore)+'\t'+line.strip()+'\n')
else sentscore < 0:
outf_neg.write(str(sentscore)+'\t'+line.strip()+'\n')
读入正负例数据并拼接完成之后,利用正则表达式替换标点符号。
data_combine['word_punc'] = data_combine['words'].apply(lambda s: re.sub(r'[%s]+'%desl, "",s))
data_combine['word_cuts'] = data_combine['words_punc'].apply(lambda s: list(jieba.cut(s)))
去除评论中的停用词:
data_combine['word_cuts_stop'] = data_combine['words_cuts'].apply(lambda s: [i for i in s if i not in stop_list])
经过上述预处理操作后,得到最终的数据集,下图为数据集中情感倾向为正和负的评论截图:
数据集中正负评论的中位数分布如下图所示,可以看出负向评论较多。
使用TF-IDF特征进行抽取:
from sklearn.feature_extraction.text import TfidVectorizer
vectorizer = TfidVectorizer()
X = vectorizer.fit_transform(data_combine['space_words'])
Y = np.array(list(data_combine['label']), dtype=np.int32)
划分数据集并训练以及测试模型,得到最终分类结果:
from sklearn.model_selection import train_test_split from sklearn.svm import LinearSVC from sklearn.metrics import accuracy_score #划分数据集 X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size=0.2) #分类器 clf = LinearSVC() #训练模型 clf.fit(X_train, Y_train) #测试模型 prediction = clf.predict(X_test) accuracy_score(prediction, Y_test)
最终实验准确率为:
0.8854
在基于深度学习的方法中,采用基于LSTM的模型进行训练测试。
一个句子包含多个词,句子的长度不同,因此,直接把句子所有词的向量拼接,则句子向量长度就不统一,后续算法无法进行。因此,需要将句子固定相同的长度。将长度超过16的字符串截断,长度不足16的字符串补零。
from gensim.models import Word2Vec
def return_w2vvalue(s):
try:
return emotion_w2v[s]
except:
return [0]*60
def modify_words_lenth(s):
if len(s)<=16:
return s+[' ']*(16-len(s))
else:
return s[:16]
将截取后的词按照训练好的词向量转换:
data_combine['words_cut_stop_modify'] = data_combine['words_cuts_stop'].apply(lambda s: modify_words_lenth(s))
data_combine['words_trans_w2v'] = data_combine['words_cuts_stop_modify'].apply(lambda s: [return_w2v_value(i) for i in s])
划分数据集为训练集和测试集,其中,将特征数据x转换成NLM维度,N表示语句长度,L表示每句话长度,M表示每句话中每个词对应的词向量长度。将目标数据y转换成N* class维度,其中,N表示语句个数,class代表分类个数。
import numpy as np
x_train, x_test, y_train, y_test = train_test_split(data_combine['words_trans_w2v'], data_combine['label'],test_size=0.2)
x_train_modify = np.array(list(x_train))
x_test_modify = np.array(list(x_test))
y_train_modify = np.array(pd.get_dummies(y_train))
y_test_modify = np.array(pd.get_dummies(y_test))
构建神经网络模型,模型的第一层输入参数为(16,60),表示句子长度为16,词向量维度为60。输出层为2个节点,使用softmax激活函数。
from keras.models import Sequential from keras.layer.core import Dense, Activation import time start = time.time() #构建模型 model = Sequential() model.add(LSTM(22, imput_shape = (16,60), dropout = 0.5, activation = 'sigmoid')) model.add(Dense(2, activation = 'softmax')) model.compile(loss='categorical_crossentropy', optimizer = 'adam', metrics = ['accuracy']) #训练模型 history = model.fit(x_train_modify, y_train_modify, batch_size = 64, epochs = 10) end = time.time()
训练过程截图:
预测代码及结果如下所示:
from sklearn.metrics import accuracy_score
prediction = [np.argmax(i) for i in model.predict(x_test_modify)]
accuracy_score(prediction, y_test)
0.8912
通过分析上述实验结果,可以看出基于深度学习的方法结果更好。同时,神经网络的应用更加广泛,在其他领域的各项任务中也取得了不错的效果。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。