本教程为原创,转载请注明教学视频地址,

视频教程链接:https://www.bilibili.com/video/av30543613

书面教程和代码链接:https://github.com/aespresso/chinese_sentiment 如果想在本地运行代码,请下载书面教程中的词向量库,并解压"语料.zip"覆盖根目录

用Tensorflow进行中文自然语言处理--情感分析
f(′真好喝′)=1
f(′太难喝了′)=0
简介
大家好,我是Espresso,这是我制作的第一个教程,是一个简单的中文自然语言处理的分类实践。
制作此教程的目的是什么呢?虽然现在自然语言处理的学习资料很多,英文的资料更多,但是网上资源很乱,尤其是中文的系统的学习资料稀少,而且知识点非常分散,缺少比较系统的实践学习资料,就算有一些代码但因为缺少注释导致要花费很长时间才能理解,我个人在学习过程中,在网络搜索花费了一整天时间,才把处理中文的步骤和需要的软件梳理出来。
所以我觉得自己有义务制作一个入门教程把零散的资料结合成一个实践案例方便各位同学学习,在这个教程中我注重的是实践部分,理论部分我推荐学习deeplearning.ai的课程,在下面的代码部分,涉及到哪方面知识的,我推荐一些学习资料并附上链接,如有侵权请e-mail:a66777@188.com。
另外我对自然语言处理并没有任何深入研究,欢迎各位大牛吐槽,希望能指出不足和改善方法。
需要的库
numpy
jieba
gensim
tensorflow
matplotlib
In [2]:# 首先加载必用的库
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
import re
import jieba # 结巴分词
# gensim用来加载预训练word vector
from gensim.models import KeyedVectors
import warnings
warnings.filterwarnings("ignore")
c:\users\jinan\appdata\local\programs\python\python36\lib\site-packages\gensim\utils.py:1209: UserWarning: detected Windows; aliasing chunkize to chunkize_serialwarnings.warn("detected Windows; aliasing chunkize to chunkize_serial")
预训练词向量
本教程使用了北京师范大学中文信息处理研究所与中国人民大学 DBIIR 实验室的研究者开源的"chinese-word-vectors" github链接为:
https://github.com/Embedding/Chinese-Word-Vectors
如果你不知道word2vec是什么,我推荐以下一篇文章:
https://zhuanlan.zhihu.com/p/26306795
这里我们使用了"chinese-word-vectors"知乎Word + Ngram的词向量,可以从上面github链接下载,我们先加载预训练模型并进行一些简单测试:
In [3]:# 使用gensim加载预训练中文分词embedding
cn_model = KeyedVectors.load_word2vec_format('chinese_word_vectors/sgns.zhihu.bigram', binary=False)
词向量模型
在这个词向量模型里,每一个词是一个索引,对应的是一个长度为300的向量,我们今天需要构建的LSTM神经网络模型并不能直接处理汉字文本,需要先进行分次并把词汇转换为词向量,步骤请参考下图,步骤的讲解会跟着代码一步一步来,如果你不知道RNN,GRU,LSTM是什么,我推荐deeplearning.ai的课程,网易公开课有免费中文字幕版,但我还是推荐有习题和练习代码部分的的coursera原版:In [29]:# 由此可见每一个词都对应一个长度为300的向量
embedding_dim = cn_model['山东大学'].shape[0]
print('词向量的长度为{}'.format(embedding_dim))
cn_model['山东大学']
词向量的长度为300
Out[29]:
array([-2.603470e-01,  3.677500e-01, -2.379650e-01,  5.301700e-02,-3.628220e-01, -3.212010e-01, -1.903330e-01,  1.587220e-01,-7.156200e-02, -4.625400e-02, -1.137860e-01,  3.515600e-01,-6.408200e-02, -2.184840e-01,  3.286950e-01, -7.110330e-01,1.620320e-01,  1.627490e-01,  5.528180e-01,  1.016860e-01,1.060080e-01,  7.820700e-01, -7.537310e-01, -2.108400e-02,-4.758250e-01, -1.130420e-01, -2.053000e-01,  6.624390e-01,2.435850e-01,  9.171890e-01, -2.090610e-01, -5.290000e-02,-7.969340e-01,  2.394940e-01, -9.028100e-02,  1.537360e-01,-4.003980e-01, -2.456100e-02, -1.717860e-01,  2.037790e-01,-4.344710e-01, -3.850430e-01, -9.366000e-02,  3.775310e-01,2.659690e-01,  8.879800e-02,  2.493440e-01,  4.914900e-02,5.996000e-03,  3.586430e-01, -1.044960e-01, -5.838460e-01,3.093280e-01, -2.828090e-01, -8.563400e-02, -5.745400e-02,-2.075230e-01,  2.845980e-01,  1.414760e-01,  1.678570e-01,1.957560e-01,  7.782140e-01, -2.359000e-01, -6.833100e-02,2.560170e-01, -6.906900e-02, -1.219620e-01,  2.683020e-01,1.678810e-01,  2.068910e-01,  1.987520e-01,  6.720900e-02,-3.975290e-01, -7.123140e-01,  5.613200e-02,  2.586000e-03,5.616910e-01,  1.157000e-03, -4.341190e-01,  1.977480e-01,2.519540e-01,  8.835000e-03, -3.554600e-01, -1.573500e-02,-2.526010e-01,  9.355900e-02, -3.962500e-02, -1.628350e-01,2.980950e-01,  1.647900e-01, -5.454270e-01,  3.888790e-01,1.446840e-01, -7.239600e-02, -7.597800e-02, -7.803000e-03,2.020520e-01, -4.424750e-01,  3.911580e-01,  2.115100e-01,6.516760e-01,  5.668030e-01,  5.065500e-02, -1.259650e-01,-3.720640e-01,  2.330470e-01,  6.659900e-02,  8.300600e-02,2.540460e-01, -5.279760e-01, -3.843280e-01,  3.366460e-01,2.336500e-01,  3.564750e-01, -4.884160e-01, -1.183910e-01,1.365910e-01,  2.293420e-01, -6.151930e-01,  5.212050e-01,3.412000e-01,  5.757940e-01,  2.354480e-01, -3.641530e-01,7.373400e-02,  1.007380e-01, -3.211410e-01, -3.040480e-01,-3.738440e-01, -2.515150e-01,  2.633890e-01,  3.995490e-01,4.461880e-01,  1.641110e-01,  1.449590e-01, -4.191540e-01,2.297840e-01,  6.710600e-02,  3.316430e-01, -6.026500e-02,-5.130610e-01,  1.472570e-01,  2.414060e-01,  2.011000e-03,-3.823410e-01, -1.356010e-01,  3.112300e-01,  9.177830e-01,-4.511630e-01,  1.272190e-01, -9.431600e-02, -8.216000e-03,-3.835440e-01,  2.589400e-02,  6.374980e-01,  4.931630e-01,-1.865070e-01,  4.076900e-01, -1.841000e-03,  2.213160e-01,2.253950e-01, -2.159220e-01, -7.611480e-01, -2.305920e-01,1.296890e-01, -1.304100e-01, -4.742270e-01,  2.275500e-02,4.255050e-01,  1.570280e-01,  2.975300e-02,  1.931830e-01,1.304340e-01, -3.179800e-02,  1.516650e-01, -2.154310e-01,-4.681410e-01,  1.007326e+00, -6.698940e-01, -1.555240e-01,1.797170e-01,  2.848660e-01,  6.216130e-01,  1.549510e-01,6.225000e-02, -2.227800e-02,  2.561270e-01, -1.006380e-01,2.807900e-02,  4.597710e-01, -4.077750e-01, -1.777390e-01,1.920500e-02, -4.829300e-02,  4.714700e-02, -3.715200e-01,-2.995930e-01, -3.719710e-01,  4.622800e-02, -1.436460e-01,2.532540e-01, -9.334000e-02, -4.957400e-02, -3.803850e-01,5.970110e-01,  3.578450e-01, -6.826000e-02,  4.735200e-02,-3.707590e-01, -8.621300e-02, -2.556480e-01, -5.950440e-01,-4.757790e-01,  1.079320e-01,  9.858300e-02,  8.540300e-01,3.518370e-01, -1.306360e-01, -1.541590e-01,  1.166775e+00,2.048860e-01,  5.952340e-01,  1.158830e-01,  6.774400e-02,6.793920e-01, -3.610700e-01,  1.697870e-01,  4.118530e-01,4.731000e-03, -7.516530e-01, -9.833700e-02, -2.312220e-01,-7.043300e-02,  1.576110e-01, -4.780500e-02, -7.344390e-01,-2.834330e-01,  4.582690e-01,  3.957010e-01, -8.484300e-02,-3.472550e-01,  1.291660e-01,  3.838960e-01, -3.287600e-02,-2.802220e-01,  5.257030e-01, -3.609300e-02, -4.842220e-01,3.690700e-02,  3.429560e-01,  2.902490e-01, -1.624650e-01,-7.513700e-02,  2.669300e-01,  5.778230e-01, -3.074020e-01,-2.183790e-01, -2.834050e-01,  1.350870e-01,  1.490070e-01,1.438400e-02, -2.509040e-01, -3.376100e-01,  1.291880e-01,-3.808700e-01, -4.420520e-01, -2.512300e-01, -1.328990e-01,-1.211970e-01,  2.532660e-01,  2.757050e-01, -3.382040e-01,1.178070e-01,  3.860190e-01,  5.277960e-01,  4.581920e-01,1.502310e-01,  1.226320e-01,  2.768540e-01, -4.502080e-01,-1.992670e-01,  1.689100e-02,  1.188860e-01,  3.502440e-01,-4.064770e-01,  2.610280e-01, -1.934990e-01, -1.625660e-01,2.498400e-02, -1.867150e-01, -1.954400e-02, -2.281900e-01,-3.417670e-01, -5.222770e-01, -9.543200e-02, -3.500350e-01,2.154600e-02,  2.318040e-01,  5.395310e-01, -4.223720e-01],dtype=float32)
Cosine Similarity for Vector Space Models by Christian S. Perone http://blog.christianperone.com/2013/09/machine-learning-cosine-similarity-for-vector-space-models-part-iii/
In [33]:# 计算相似度
cn_model.similarity('橘子', '橙子')
Out[33]:
0.66128117
In [34]:# dot('橘子'/|'橘子'|, '橙子'/|'橙子'| )
np.dot(cn_model['橘子']/np.linalg.norm(cn_model['橘子']),
cn_model['橙子']/np.linalg.norm(cn_model['橙子']))
Out[34]:
0.66128117
In [35]:# 找出最相近的词,余弦相似度
cn_model.most_similar(positive=['大学'], topn=10)
Out[35]:
[('高中', 0.7247823476791382),('本科', 0.6768535375595093),('研究生', 0.6244412660598755),('中学', 0.6088204979896545),('大学本科', 0.595908522605896),('初中', 0.5883588790893555),('读研', 0.5778335332870483),('职高', 0.5767995119094849),('大学毕业', 0.5767451524734497),('师范大学', 0.5708829760551453)]
In [36]:# 找出不同的词
test_words = '老师 会计师 程序员 律师 医生 老人'
test_words_result = cn_model.doesnt_match(test_words.split())
print('在 '+test_words+' 中:\n不是同一类别的词为: %s' %test_words_result)
在 老师 会计师 程序员 律师 医生 老人 中:
不是同一类别的词为: 老人
In [ ]:cn_model.most_similar(positive=['女人','出轨'], negative=['男人'], topn=1)
训练语料
本教程使用了谭松波老师的酒店评论语料,即使是这个语料也很难找到下载链接,在某博客还得花积分下载,而我不知道怎么赚取积分,后来好不容易找到一个链接但竟然是失效的,再后来尝试把链接粘贴到迅雷上终于下载了下来,希望大家以后多多分享资源。
训练样本分别被放置在两个文件夹里: 分别的pos和neg,每个文件夹里有2000个txt文件,每个文件内有一段评语,共有4000个训练样本,这样大小的样本数据在NLP中属于非常迷你的:
In [38]:# 获得样本的索引,样本存放于两个文件夹中,
# 分别为 正面评价'pos'文件夹 和 负面评价'neg'文件夹
# 每个文件夹中有2000个txt文件,每个文件中是一例评价
import os
pos_txts = os.listdir('pos')
neg_txts = os.listdir('neg')
In [39]:print( '样本总共: '+ str(len(pos_txts) + len(neg_txts)) )
样本总共: 4000
In [40]:# 现在我们将所有的评价内容放置到一个list里
​
train_texts_orig = [] # 存储所有评价,每例评价为一条string
​
# 添加完所有样本之后,train_texts_orig为一个含有4000条文本的list
# 其中前2000条文本为正面评价,后2000条为负面评价
​
for i in range(len(pos_txts)):with open('pos/'+pos_txts[i], 'r', errors='ignore') as f:text = f.read().strip()train_texts_orig.append(text)f.close()
for i in range(len(neg_txts)):with open('neg/'+neg_txts[i], 'r', errors='ignore') as f:text = f.read().strip()train_texts_orig.append(text)f.close()
In [41]:len(train_texts_orig)
Out[41]:
4000
In [42]:# 我们使用tensorflow的keras接口来建模
from tensorflow.python.keras.models import Sequential
from tensorflow.python.keras.layers import Dense, GRU, Embedding, LSTM, Bidirectional
from tensorflow.python.keras.preprocessing.text import Tokenizer
from tensorflow.python.keras.preprocessing.sequence import pad_sequences
from tensorflow.python.keras.optimizers import RMSprop
from tensorflow.python.keras.optimizers import Adam
from tensorflow.python.keras.callbacks import EarlyStopping, ModelCheckpoint, TensorBoard, ReduceLROnPlateau
分词和tokenize
首先我们去掉每个样本的标点符号,然后用jieba分词,jieba分词返回一个生成器,没法直接进行tokenize,所以我们将分词结果转换成一个list,并将它索引化,这样每一例评价的文本变成一段索引数字,对应着预训练词向量模型中的词。
In [43]:# 进行分词和tokenize
# train_tokens是一个长长的list,其中含有4000个小list,对应每一条评价
train_tokens = []
for text in train_texts_orig:# 去掉标点text = re.sub("[\s+\.\!\/_,$%^*(+\"\']+|[+——!,。?、~@#¥%……&*()]+", "",text)# 结巴分词cut = jieba.cut(text)# 结巴分词的输出结果为一个生成器# 把生成器转换为listcut_list = [ i for i in cut ]for i, word in enumerate(cut_list):try:# 将词转换为索引indexcut_list[i] = cn_model.vocab[word].indexexcept KeyError:# 如果词不在字典中,则输出0cut_list[i] = 0train_tokens.append(cut_list)
Building prefix dict from the default dictionary ...
Loading model from cache C:\Users\jinan\AppData\Local\Temp\jieba.cache
Loading model cost 0.672 seconds.
Prefix dict has been built succesfully.
索引长度标准化
因为每段评语的长度是不一样的,我们如果单纯取最长的一个评语,并把其他评填充成同样的长度,这样十分浪费计算资源,所以我们取一个折衷的长度。
In [44]:# 获得所有tokens的长度
num_tokens = [ len(tokens) for tokens in train_tokens ]
num_tokens = np.array(num_tokens)
In [45]:# 平均tokens的长度
np.mean(num_tokens)
Out[45]:
71.4495
In [46]:# 最长的评价tokens的长度
np.max(num_tokens)
Out[46]:
1540
In [89]:plt.hist(np.log(num_tokens), bins = 100)
plt.xlim((0,10))
plt.ylabel('number of tokens')
plt.xlabel('length of tokens')
plt.title('Distribution of tokens length')
plt.show()In [48]:# 取tokens平均值并加上两个tokens的标准差,
# 假设tokens长度的分布为正态分布,则max_tokens这个值可以涵盖95%左右的样本
max_tokens = np.mean(num_tokens) + 2 * np.std(num_tokens)
max_tokens = int(max_tokens)
max_tokens
Out[48]:
236
In [49]:# 取tokens的长度为236时,大约95%的样本被涵盖
# 我们对长度不足的进行padding,超长的进行修剪
np.sum( num_tokens < max_tokens ) / len(num_tokens)
Out[49]:
0.9565
反向tokenize
我们定义一个function,用来把索引转换成可阅读的文本,这对于debug很重要。
In [50]:# 用来将tokens转换为文本
def reverse_tokens(tokens):text = ''for i in tokens:if i != 0:text = text + cn_model.index2word[i]else:text = text + ' 'return text
In [51]:reverse = reverse_tokens(train_tokens[0])
以下可见,训练样本的极性并不是那么精准,比如说下面的样本,对早餐并不满意,但被定义为正面评价,这会迷惑我们的模型,不过我们暂时不对训练样本进行任何修改。
In [52]:# 经过tokenize再恢复成文本
# 可见标点符号都没有了
reverse
Out[52]:
'早餐太差无论去多少人那边也不加食品的酒店应该重视一下这个问题了房间本身很好'
In [53]:# 原始文本
train_texts_orig[0]
Out[53]:
'早餐太差,无论去多少人,那边也不加食品的。酒店应该重视一下这个问题了。\n\n房间本身很好。'
准备Embedding Matrix
现在我们来为模型准备embedding matrix(词向量矩阵),根据keras的要求,我们需要准备一个维度为(numwords,embeddingdim)
的矩阵,num words代表我们使用的词汇的数量,emdedding dimension在我们现在使用的预训练词向量模型中是300,每一个词汇都用一个长度为300的向量表示。
注意我们只选择使用前50k个使用频率最高的词,在这个预训练词向量模型中,一共有260万词汇量,如果全部使用在分类问题上会很浪费计算资源,因为我们的训练样本很小,一共只有4k,如果我们有100k,200k甚至更多的训练样本时,在分类问题上可以考虑减少使用的词汇量。
In [90]:embedding_dim
Out[90]:
300
In [55]:# 只使用前20000个词
num_words = 50000
# 初始化embedding_matrix,之后在keras上进行应用
embedding_matrix = np.zeros((num_words, embedding_dim))
# embedding_matrix为一个 [num_words,embedding_dim] 的矩阵
# 维度为 50000 * 300
for i in range(num_words):embedding_matrix[i,:] = cn_model[cn_model.index2word[i]]
embedding_matrix = embedding_matrix.astype('float32')
In [56]:# 检查index是否对应,
# 输出300意义为长度为300的embedding向量一一对应
np.sum( cn_model[cn_model.index2word[333]] == embedding_matrix[333] )
Out[56]:
300
In [57]:# embedding_matrix的维度,
# 这个维度为keras的要求,后续会在模型中用到
embedding_matrix.shape
Out[57]:
(50000, 300)
padding(填充)和truncating(修剪)
我们把文本转换为tokens(索引)之后,每一串索引的长度并不相等,所以为了方便模型的训练我们需要把索引的长度标准化,上面我们选择了236这个可以涵盖95%训练样本的长度,接下来我们进行padding和truncating,我们一般采用'pre'的方法,这会在文本索引的前面填充0,因为根据一些研究资料中的实践,如果在文本索引后面填充0的话,会对模型造成一些不良影响。
In [58]:# 进行padding和truncating, 输入的train_tokens是一个list
# 返回的train_pad是一个numpy array
train_pad = pad_sequences(train_tokens, maxlen=max_tokens,padding='pre', truncating='pre')
In [59]:# 超出五万个词向量的词用0代替
train_pad[ train_pad>=num_words ] = 0
In [60]:# 可见padding之后前面的tokens全变成0,文本在最后面
train_pad[33]
Out[60]:
array([    0,     0,     0,     0,     0,     0,     0,     0,     0,0,     0,     0,     0,     0,     0,     0,     0,     0,0,     0,     0,     0,     0,     0,     0,     0,     0,0,     0,     0,     0,     0,     0,     0,     0,     0,0,     0,     0,     0,     0,     0,     0,     0,     0,0,     0,     0,     0,     0,     0,     0,     0,     0,0,     0,     0,     0,     0,     0,     0,     0,     0,0,     0,     0,     0,     0,     0,     0,     0,     0,0,     0,     0,     0,     0,     0,     0,     0,     0,0,     0,     0,     0,     0,     0,     0,     0,     0,0,     0,     0,     0,     0,     0,     0,     0,     0,0,     0,     0,     0,     0,     0,     0,     0,     0,0,     0,     0,     0,     0,     0,     0,     0,     0,0,     0,     0,     0,     0,     0,     0,     0,     0,0,     0,     0,     0,     0,     0,     0,     0,     0,0,     0,     0,     0,     0,     0,     0,     0,     0,0,     0,     0,     0,     0,     0,     0,     0,     0,290,  3053,    57,   169,    73,     1,    25, 11216,    49,163, 15985,     0,     0,    30,     8,     0,     1,   228,223,    40,    35,   653,     0,     5,  1642,    29, 11216,2751,   500,    98,    30,  3159,  2225,  2146,   371,  6285,169, 27396,     1,  1191,  5432,  1080, 20055,    57,   562,1, 22671,    40,    35,   169,  2567,     0, 42665,  7761,110,     0,     0, 41281,     0,   110,     0, 35891,   110,0, 28781,    57,   169,  1419,     1, 11670,     0, 19470,1,     0,     0,   169, 35071,    40,   562,    35, 12398,657,  4857])
In [61]:# 准备target向量,前2000样本为1,后2000为0
train_target = np.concatenate( (np.ones(2000),np.zeros(2000)) )
In [62]:# 进行训练和测试样本的分割
from sklearn.model_selection import train_test_split
In [63]:# 90%的样本用来训练,剩余10%用来测试
X_train, X_test, y_train, y_test = train_test_split(train_pad,train_target,test_size=0.1,random_state=12)
In [64]:# 查看训练样本,确认无误
print(reverse_tokens(X_train[35]))
print('class: ',y_train[35])房间很大还有海景阳台走出酒店就是沙滩非常不错唯一遗憾的就是不能刷 不方便
class:  1.0
现在我们用keras搭建LSTM模型,模型的第一层是Embedding层,只有当我们把tokens索引转换为词向量矩阵之后,才可以用神经网络对文本进行处理。 keras提供了Embedding接口,避免了繁琐的稀疏矩阵操作。
在Embedding层我们输入的矩阵为:
(batchsize,maxtokens)
输出矩阵为:
(batchsize,maxtokens,embeddingdim)
In [65]:# 用LSTM对样本进行分类
model = Sequential()
In [66]:# 模型第一层为embedding
model.add(Embedding(num_words,embedding_dim,weights=[embedding_matrix],input_length=max_tokens,trainable=False))
In [67]:model.add(Bidirectional(LSTM(units=32, return_sequences=True)))
model.add(LSTM(units=16, return_sequences=False))
构建模型
我在这个教程中尝试了几种神经网络结构,因为训练样本比较少,所以我们可以尽情尝试,训练过程等待时间并不长:
GRU:如果使用GRU的话,测试样本可以达到87%的准确率,但我测试自己的文本内容时发现,GRU最后一层激活函数的输出都在0.5左右,说明模型的判断不是很明确,信心比较低,而且经过测试发现模型对于否定句的判断有时会失误,我们期望对于负面样本输出接近0,正面样本接近1而不是都徘徊于0.5之间。
BiLSTM:测试了LSTM和BiLSTM,发现BiLSTM的表现最好,LSTM的表现略好于GRU,这可能是因为BiLSTM对于比较长的句子结构有更好的记忆,有兴趣的朋友可以深入研究一下。
Embedding之后第,一层我们用BiLSTM返回sequences,然后第二层16个单元的LSTM不返回sequences,只返回最终结果,最后是一个全链接层,用sigmoid激活函数输出结果。
In [68]:# GRU的代码
# model.add(GRU(units=32, return_sequences=True))
# model.add(GRU(units=16, return_sequences=True))
# model.add(GRU(units=4, return_sequences=False))
In [69]:model.add(Dense(1, activation='sigmoid'))
# 我们使用adam以0.001的learning rate进行优化
optimizer = Adam(lr=1e-3)
In [70]:model.compile(loss='binary_crossentropy',optimizer=optimizer,metrics=['accuracy'])
In [71]:# 我们来看一下模型的结构,一共90k左右可训练的变量
model.summary()
_________________________________________________________________
Layer (type)                 Output Shape              Param #
=================================================================
embedding_1 (Embedding)      (None, 236, 300)          15000000
_________________________________________________________________
bidirectional_1 (Bidirection (None, 236, 64)           85248
_________________________________________________________________
lstm_2 (LSTM)                (None, 16)                5184
_________________________________________________________________
dense_1 (Dense)              (None, 1)                 17
=================================================================
Total params: 15,090,449
Trainable params: 90,449
Non-trainable params: 15,000,000
_________________________________________________________________
In [72]:# 建立一个权重的存储点
path_checkpoint = 'sentiment_checkpoint.keras'
checkpoint = ModelCheckpoint(filepath=path_checkpoint, monitor='val_loss',verbose=1, save_weights_only=True,save_best_only=True)
In [73]:# 尝试加载已训练模型
try:model.load_weights(path_checkpoint)
except Exception as e:print(e)
In [74]:# 定义early stoping如果3个epoch内validation loss没有改善则停止训练
earlystopping = EarlyStopping(monitor='val_loss', patience=3, verbose=1)
In [75]:# 自动降低learning rate
lr_reduction = ReduceLROnPlateau(monitor='val_loss',factor=0.1, min_lr=1e-5, patience=0,verbose=1)
In [76]:# 定义callback函数
callbacks = [earlystopping, checkpoint,lr_reduction
]
In [77]:# 开始训练
model.fit(X_train, y_train,validation_split=0.1, epochs=20,batch_size=128,callbacks=callbacks)
结论
我们首先对测试样本进行预测,得到了还算满意的准确度。
之后我们定义一个预测函数,来预测输入的文本的极性,可见模型对于否定句和一些简单的逻辑结构都可以进行准确的判断。
In [78]:result = model.evaluate(X_test, y_test)
print('Accuracy:{0:.2%}'.format(result[1]))
400/400 [==============================] - 5s 12ms/step
Accuracy:87.50%
In [79]:def predict_sentiment(text):print(text)# 去标点text = re.sub("[\s+\.\!\/_,$%^*(+\"\']+|[+——!,。?、~@#¥%……&*()]+", "",text)# 分词cut = jieba.cut(text)cut_list = [ i for i in cut ]# tokenizefor i, word in enumerate(cut_list):try:cut_list[i] = cn_model.vocab[word].indexexcept KeyError:cut_list[i] = 0# paddingtokens_pad = pad_sequences([cut_list], maxlen=max_tokens,padding='pre', truncating='pre')# 预测result = model.predict(x=tokens_pad)coef = result[0][0]if coef >= 0.5:print('是一例正面评价','output=%.2f'%coef)else:print('是一例负面评价','output=%.2f'%coef)
In [80]:test_list = ['酒店设施不是新的,服务态度很不好','酒店卫生条件非常不好','床铺非常舒适','房间很凉,不给开暖气','房间很凉爽,空调冷气很足','酒店环境不好,住宿体验很不好','房间隔音不到位' ,'晚上回来发现没有打扫卫生','因为过节所以要我临时加钱,比团购的价格贵'
]
for text in test_list:predict_sentiment(text)
酒店设施不是新的,服务态度很不好
是一例负面评价 output=0.14
酒店卫生条件非常不好
是一例负面评价 output=0.09
床铺非常舒适
是一例正面评价 output=0.76
房间很凉,不给开暖气
是一例负面评价 output=0.17
房间很凉爽,空调冷气很足
是一例正面评价 output=0.66
酒店环境不好,住宿体验很不好
是一例负面评价 output=0.06
房间隔音不到位
是一例负面评价 output=0.17
晚上回来发现没有打扫卫生
是一例负面评价 output=0.25
因为过节所以要我临时加钱,比团购的价格贵
是一例负面评价 output=0.06
错误分类的文本 经过查看,发现错误分类的文本的含义大多比较含糊,就算人类也不容易判断极性,如index为101的这个句子,好像没有一点满意的成分,但这例子评价在训练样本中被标记成为了正面评价,而我们的模型做出的负面评价的预测似乎是合理的。
In [81]:y_pred = model.predict(X_test)
y_pred = y_pred.T[0]
y_pred = [1 if p>= 0.5 else 0 for p in y_pred]
y_pred = np.array(y_pred)
In [82]:y_actual = np.array(y_test)
In [83]:# 找出错误分类的索引
misclassified = np.where( y_pred != y_actual )[0]
In [92]:# 输出所有错误分类的索引
len(misclassified)
print(len(X_test))
400
In [85]:# 我们来找出错误分类的样本看看
idx=101
print(reverse_tokens(X_test[idx]))
print('预测的分类', y_pred[idx])
print('实际的分类', y_actual[idx])由于2007年 有一些新问题可能还没来得及解决我因为工作需要经常要住那里所以慎重的提出以下 :1 后 的 淋浴喷头的位置都太高我换了房间还是一样很不好用2 后的一些管理和服务还很不到位尤其是前台入住和 时代效率太低每次 都超过10分钟好像不符合 宾馆的要求
预测的分类 0
实际的分类 1.0
In [86]:idx=1
print(reverse_tokens(X_test[idx]))
print('预测的分类', y_pred[idx])
print('实际的分类', y_actual[idx])还是很 设施也不错但是 和以前 比急剧下滑了 和客房 的服务极差幸好我不是很在乎
预测的分类 0
实际的分类 1.0

逐步视频讲解--用Tensorflow进行中文自然语言处理--情感分析相关推荐

  1. 自然语言之情感分析(中文)

    自然语言之情感分析(中文) 数据来源:香港金融新闻平台 处理工具:python3.5 处理结果:分析语言的积极/消极意义 领域:金融/炒股 请随意观看表演 数据准备 数据清洗 情感分析 报错处理 成果 ...

  2. 如何做中文文本的情感分析?

    如何做中文文本的情感分析? 这是本学期在大数据哲学与社会科学实验室做的第三次分享了. 第一次分享的是:如何利用"wordcloud+jieba"制作中文词云? 第二次分享的是:如何 ...

  3. EDG夺冠,用爬虫+数据分析+自然语言处理(情感分析)+数据可视化分析3万条数据:粉丝都疯了(唯一原创)

    原创不易,本文禁止抄袭.转载,违权必究! 目录 一.EDG夺冠信息 二.实战目标 2.1 网络爬虫 2.2 数据可视化(词云图) 2.3 自然语言处理(情感分析) 三.bilibili接口分析 四.编 ...

  4. python电影评论情感分析_20行Tensorflow代码实现电影评论情感分析

    原标题:20行Tensorflow代码实现电影评论情感分析 背景 情感分析有很多的应用场景,比如做一个电商网站,卖家需要时刻关心用户对于商品的评论是否是正面的.再比如做一个电影的宣传和策划,电影在键盘 ...

  5. 自然语言11_情感分析

    sklearn实战-乳腺癌细胞数据挖掘(博主亲自录制视频教程) https://study.163.com/course/introduction.htm?courseId=1005269003&am ...

  6. 在 TensorFlow 上使用 LSTM 进行情感分析

    你可以从 Github 上面下载到所有的源代码. 在这篇教程中,我们将介绍如何将深度学习技术应用到情感分析中.该任务可以被认为是从一个句子,一段话,或者是从一个文档中,将作者的情感分为积极的,消极的或 ...

  7. 基于python的情感分析案例-python自然语言处理情感分析案例

    产品价值 自然语言处理是为各类企业及开发者提供的用于文本分析及挖掘的核心工具,已经广泛应用在电商.文化娱乐.金融.物流等行业客户的多项业务中.自然语言处理API可帮助用户搭建内容搜索.内容推荐.舆情识 ...

  8. 基于LSTM的中文多分类情感分析

    趁着国庆假期,玩了一下深度学习(主要是LSTM这个网络),顺便做了一个中文多分类的情感分析.中文情感分析相对英文来说,难度太大,所以最后分析的结果,准确度也不是太高,但基本还是没啥问题的. 对应的ap ...

  9. 基于BERT做中文文本分类(情感分析)

    Bert: BERT是一种预训练语言表示的方法,这意味着我们在大型文本语料库(例如Wikipedia)上训练通用的"语言理解"模型,然后将该模型用于我们关心的下游NLP任务,BER ...

最新文章

  1. python常见的错误总结
  2. Unity屏幕射线碰撞
  3. Ubuntu16.04 + ROS kinetic + 激光slam-cartographer ROS + 数据仿真 + Turtlebot3仿真
  4. .NET Core 3.0愈加成熟,微软将不再把.NET Framework API移植给它
  5. “老师,请您多关注一下我吧!!!”
  6. 从事java编程技能要求_5道Java视频课程,提高您的编程技能
  7. Python--Python--类和对象
  8. 高质量实时渲染课程笔记(一)——介绍和概览(高质量实时渲染的含义、学习前置、涉及的内容目录、发展史)
  9. simulink仿真实例_推荐几本关于制冷仿真的书籍(制冷仿真必备)
  10. 项目杂识-FOV(视场角)
  11. SD内存卡禁止写入只读怎么办?另类SPI模式修复坏卡
  12. 人工智能初步学习笔记
  13. 自我救赎段子_为什么技术可以成为现代教育和学习的救赎之恩
  14. Docker 与 K8S学习笔记(二十)—— 使用Downward API向容器注入Pod信息
  15. 如何用css写出一个三角形
  16. 小米ES Pro和X Pro对比有什么区别?哪个更值得入手
  17. 三分钟搭建开源的工单系统ferry
  18. Json工具Demo(二)
  19. C语言(二级基础知识2)
  20. Facade与Adapter模式应用

热门文章

  1. 我们唯一的选择其实就是向前
  2. jquery封装的ajax方法获取web服务器时间
  3. PhpStorm破解版及使用教程
  4. IntelliJ IDEA 或者 phpstorm 破解包破解方法
  5. IDEA 编写 SpringBoot 项目自动编译刷新
  6. Http与Https区别,加密,证书
  7. 计算机win7按任意键唤醒,windows7系统下开机必须按任意键才能启动如何解决
  8. 剖析:Python与Java相比,选谁好?
  9. b is not defined报错详解
  10. redis监控软件对比