文本分类
注意:本教程需要TensorFlow版本>= 2.1
本教程根据影评文本将影评分为正面或负面。这是一个二元或两类分类的例子,这是一个重要的和广泛应用的机器学习问题。
我们将使用IMDB数据集里面有5万篇电影评论的文本互联网电影数据库.它们被分成25000个用于培训的评审和25000个用于测试的评审。训练和测试集是平衡的,这意味着它们包含相同数量的正面和负面评价。
让我们启动并加载Keras以及其他一些必需的库。
下载电影评论数据集
我们将使用由Bo Pang和Lillian Lee创建的电影评论数据集。该数据集是在获得作者许可的情况下使用NLTK重新分发的。
可以找到该数据集在这里,可从Kaggle UI下载或使用针包中。
如果你要用针遵循这个教程注册Kaggle董事会。然后你可以运行:
路径< -针::pin_get(“nltkdata /电影评论”,“kaggle”)我们只需要movie_review.csv文件路径< -路径(1]
现在我们把它读给Rread_csv
funcntion从readr
包中。
使用列规范解析:## cols(## fold_id = col_double(), ## cv_tag = col_character(), ## html_id = col_double(), ## sent_id = col_double(), ## text = col_character(), ## tag = col_character() ##)
头(df)
# # #一个宠物猫:6 x 6 # # fold_id cv_tag html_id sent_id文本标签# # <双> <空空的> <双> <双> <空空的> < >从而向# # 1 0 cv000 29590 0电影改编自漫画…pos # # 2 0 cv000 29590 1对初学者来说,它是由阿尔…pos # # 3 0 cv000 29590 2说摩尔和坎贝尔thoroughl…pos # # 4 0 cv000 29590 3”这本书(或\”漫画小说,\…pos # # 5 0 cv000 29590 4换句话说,不要小看这…pos # # 6 0 cv000 29590 5如果你能穿过整个漫画…pos
探索数据
让我们花点时间来理解数据的格式。该数据集有60k行,每一行代表一个电影评论。的文本
专栏有实际的回顾和标签
代表向我们展示了分类的情绪。
## # A tibble: 2 x 2 ## tag n ## ## 1 neg 31783 ## 2 pos 32937
大约一半的评论是负面的,另一半是正面的。下面是一个回顾的例子:
“根据漫画改编的电影已经取得了很大的成功,无论是关于超级英雄(蝙蝠侠、超人、spawn),还是面向儿童(casper)或艺术电影人群(幽灵世界),但之前从未有过一部来自地狱的漫画书。”
让我们将数据集分为训练和测试:
找出每篇文章的字数分布也很有用。
df$文本% > %strsplit(”“)% > %酸式焦磷酸钠(长度)% > %总结()
##最小1曲,中值平均3曲,最大值。## 1.00 14.00 21.00 23.06 30.00 179.00
准备数据
在输入神经网络之前,评论(文本)必须转换为张量。首先,我们创建一个字典,用一个整数表示10,000个最常见的单词中的每一个。在这种情况下,每次评审都将由一个整数序列表示。
然后我们可以用几种方式表示评论:
对数组进行1 -热编码,将它们转换为0和1的向量。例如,序列[3,5]将变成一个10,000维的向量,除了指标3和5是1之外,它都是0。然后,把这个作为网络的第一层- a
密集的
层——可以处理浮点向量数据。但是,这种方法是内存密集型的,需要一个num_words * num_reviews
大小的矩阵。或者,我们可以填充数组,使它们都具有相同的长度,然后创建一个形状的整数张量
num_examples * max_length
.我们可以使用一个能够处理这种形状的嵌入层作为网络中的第一层。
在本教程中,我们将使用第二种方法。现在,让我们定义我们的文本矢量化层,它将负责获取字符串输入并将其转换为一个张量。
num_words < -10000max_length < -50text_vectorization < -layer_text_vectorization(max_tokens =num_words,output_sequence_length =max_length)
现在,我们需要适应
文本矢量化层。这是我们打电话的时候适应
该层将学习数据集中唯一的单词,并为每个单词分配一个整数值。
text_vectorization% > %适应(df$文本)
我们现在可以看到词汇表在文本向量化层中。
#待办事项参见https://github.com/tensorflow/tensorflow/pull/34529get_vocabulary(text_vectorization)
你可以看到文本向量化层如何转换它的输入:
text_vectorization(矩阵(df$文本(1),ncol =1))
# #特遣部队。张量(## [[68 2835 30 359 1662 33 91 1056 5 632 631 321 41 7803 ## 709 4865 1767 48 7600 1337 398 5161 48 21 1808 1800 148 ## 17 140 109 90 69 3 359 408 40 30 503 142 00 ## 00 00 0]],shape=(1,50), dtype=int64)
构建模型
神经网络是通过堆叠层创建的——这需要两个主要的架构决策:
- 在模型中使用多少层?
- 每个图层使用多少隐藏单位?
在本例中,输入数据由一个单词索引数组组成。要预测的标签是0或1。让我们为这个问题建立一个模型:
输入< -layer_input(形状=c(1),dtype =“字符串”)输出< -输入% > %text_vectorization()% > %layer_embedding(input_dim =num_words+1,output_dim =16)% > %layer_global_average_pooling_1d()% > %layer_dense(单位=16,激活=“relu”)% > %layer_dropout(0.5)% > %layer_dense(单位=1,激活=“乙状结肠”)模型< -keras_model(输入、输出)
这些层按顺序堆叠以构建分类器:
- 第一层是
嵌入
层。这一层采用整数编码的词汇表,并为每个单词索引查找嵌入向量。这些向量被学习为模型列车。这些向量向输出数组添加了一个维度。得到的维度是:(批处理、序列嵌入
). - 接下来,一个
global_average_pooling_1d
Layer通过在序列维度上取平均值,为每个示例返回一个固定长度的输出向量。这允许模型以最简单的方式处理可变长度的输入。 - 这个固定长度的输出向量通过一个完全连接的(
密集的
)层有16个隐藏单位。 - 最后一层与单个输出节点紧密连接。使用
乙状结肠
激活函数,这个值是一个介于0和1之间的浮点数,表示一个概率,或置信水平。
损失函数和优化器
一个模型需要一个损失函数和一个训练优化器。由于这是一个二元分类问题,并且模型输出一个概率(具有sigmoid激活的单个单元层),因此我们将使用binary_crossentropy
损失函数。
这不是损失函数的唯一选择,举个例子,你可以选择mean_squared_error
.但是,一般来说,binary_crossenropy更适合于处理概率——它度量概率分布之间的“距离”,或者在我们的例子中,度量基本真理分布和预测之间的“距离”。
稍后,当我们探索回归问题(比如,预测房子的价格)时,我们将看到如何使用另一个损失函数,称为均方误差。
现在,配置模型使用优化器和损失函数:
火车模型
在512个样本的小批次中训练模型的20个epoch。这是对x_train和y_train张量中所有样本的20次迭代。在训练时,监控模型在验证集中的10,000个样本上的损失和准确性:
< -历史模型% > %适合(培训$文本,as.numeric(培训$标签= =“pos”),时代=10,batch_size =512,validation_split =0.2,verbose =2)
# #火车在41420个样本,验证10356个样本# #时代1/10 # # 41420/41420 - 1 s -损失:0.6921 -准确性:0.5185 - val_loss: 0.6898 - val_accuracy: 0.5410 # #时代# # 41420/41420——2/10 0 -损失:0.6862 -准确性:0.5600 - val_loss: 0.6805 - val_accuracy: 0.5965 # #时代# # 41420/41420——3/10 0 -损失:0.6716 -准确性:0.6050 - val_loss: 0.6633 - val_accuracy: 0.6400 # #时代# # 41420/41420——4/10 0 -损失:0.6468 -准确性:0.6515 - val_loss: 0.6399 - val_accuracy:0.6619 # #时代# # 41420/41420——5/10 0 -损失:0.6161 -准确性:0.6796 - val_loss: 0.6184 - val_accuracy: 0.6747 # #时代# # 41420/41420——6/10 0 -损失:0.5875 -准确性:0.7029 - val_loss: 0.6039 - val_accuracy: 0.6808 # #时代7/10 # # 41420/41420 - 1 s -损失:0.5632 -准确性:0.7212 - val_loss: 0.5963 - val_accuracy: 0.6831 # #时代# # 41420/41420——8/10 0 -损失:0.5448 -准确性:0.7336 - val_loss: 0.5917 - val_accuracy: 0.6863 # #时代# # 41420/41420——9/10 0 -损失:0.5297 -精度:0.7442 - val_loss: 0.5937 - val_accuracy: 0.6842 ##纪元10/10 ## 41420/41420 - 0s -损耗:0.5165 -精度:0.7539 - val_loss: 0.5953 - val_accuracy: 0.6868
评估模型
让我们看看模型的表现。将返回两个值。损失(一个代表我们错误的数字,数值越低越好)和准确性。
结果< -模型% > %评估(测试$文本,as.numeric(测试$标签= =“pos”),verbose =0)结果
# # # #[1]美元损失精度0.5940198 # # # # # # 0.6830192 [1]
这种相当简单的方法获得了约68%的准确性。使用更先进的方法,模型应该接近85%。
创建一个准确性和损失随时间变化的图表
适合
返回一个keras_training_history
的对象指标
槽包含训练过程中记录的损耗和度量值。你可以像这样绘制损失和指标曲线:
情节(历史)
在RStudio Viewer窗格的训练过程中,也可以看到损失和度量的演变。英格兰vs伊朗让球
注意训练损耗随时间的增加而减小,训练精度随时间的增加而增加。当使用梯度下降优化时,这是预期的——它应该在每次迭代中最小化所需的数量。