一、电影评论的二分类问题
IMDB数据集有5万条来自网络电影数据库的评论:其中2万5千条用来训练,2万5千条用来测试,每个部分正负评论各占50%。与MNIST数据集类似,IMDB数据集也集成在Keras中,同时经过了预处理:电影评论转换成了一系列数字,每个数字代表字典中的一个单词。
可以在下载的数据中找到一个imdb.vocab文件,那就是字典。

有了词典给定一个词就可以找到它的位置。
比如:
"I like the film"
I--index即 9
like--index即 37
the--index即 1
film--index即 18
所以这个评论对应的词向量就为 [9, 37, 1, 18] 。
二、张量(Tensor)
张量是矢量概念的推广,矢量是一阶张量。
张量是一个可用来表示在一些矢量、标量和其他张量之间的线性关系的多线性函数。
三、填充数据方法 pad_sequences()
这个函数功能是将 sequences(序列列表--每个列表都是整数列表) 转为二维numpy数组。
maxlen是所有序列的最大长度,可选int,若未提供,则将序列填充为最长的单个序列的长度。
padding是填充发生的位置、truncating是截断发生的位置(默认情况下,从序列的开头 'pre' 预填充或移除值.。若想从后面填充值,则应为 ‘post’)。
value是填充值,默认是填充0。
dtype是输出序列的类型,默认是int32。
tf.keras.preprocessing.sequence.pad_sequences(
sequences, maxlen=None, dtype='int32', padding='pre',
truncating='pre', value=0.0
)
返回numpy数组 。
四、隐层单元(隐藏层)
隐层单元就是在输入和输出之间的中间层,输出(单元,结点或神经元)的数量即为层表示空间的维度。
隐层单元的作用,简单来说是构造一个复杂的模型,复杂的程度由隐层单元的层数和各隐层单元神经元的个数决定,,当层数=0时,相当一一个最简单的模型--线性或非线性回归模型。
五、激活函数
激活函数是用来加入非线性因素的,提高神经网络对模型的表达能力,解决线性模型所不能解决的问题。
sigmoid函数输出范围是(0,1),所以二分类的概率常常用这个函数。
六、训练模型 model.fit()函数
x:输入数据,如果模型只有一个输入,那么x的类型是numpy数组。
y:标签,类型也为numpy数组。
batch_size:指定进行梯度下降时每个batch包含的样本数。训练时一个batch的样本会被计算一次梯度下降,使目标函数优化一步。
epochs:训练终止时的epoch值,训练将在达到该epoch值时停止,当没有设置initial_epoch时,它就是训练的总轮数,否则训练的总轮数为epochs - inital_epoch
verbose:日志显示,0为不在标准输出流输出日志信息,1为输出进度条记录,2为每个epoch输出一行记录
shuffle:布尔值或字符串,一般为布尔值,表示是否在训练过程中随机打乱输入样本的顺序。若为字符串“batch”,则是用来处理HDF5数据的特殊情况,它将在batch内部将数据打乱。
validation_split:0~1之间的浮点数,用来指定训练集的一定比例数据作为验证集。验证集将不参与训练,并在每个epoch结束后测试的模型的指标,如损失函数、精确度等。(注意:validation_split的划分在shuffle之前,因此如果你的数据本身是有序的,需要先手工打乱再指定validation_split,否则可能会出现验证集样本不均匀)
validation_data:形式为(X,y)的元组,是指定的验证集。此参数将覆盖validation_spilt。
fit( x, y, batch_size=32, epochs=10, verbose=1, callbacks=None,
validation_split=0.0, validation_data=None, shuffle=True,
class_weight=None, sample_weight=None, initial_epoch=0)
返回一个 History的对象,其中History.history属性记录了损失函数和其他指标的数值随epoch变化的情况,如果有验证集的话,也包含了验证集的这些指标变化情况
七、代码
import tensorflow as tf
from tensorflow import keras
import matplotlib.pyplot as plt
import numpy as np
# 下载IMDB数据集(已经打包在Tensorflow中)该数据集已经经过预处理,评论已经被转换为整数序列,其中每个整数表示字典中的特定单词
imdb = keras.datasets.imdb
(train_data,train_labels),(test_data,test_labels) = imdb.load_data(num_words=10000)
# 探索数据
# 首先了解数据格式(处理过的),每个样本都是一个表示影评中词汇的整数数组,标签值为0,1:0表示消极评论,1表示积极评论
# 打印首条评论,即评论被转换为整数值,每个整数代表词典中的一个单词
# 打印第一条和第二条评论中的单词数,即影评长度不一,但神经网络的输入必须是同意的长度
print('training entries:{}, labels:{}'.format(len(train_data),len(train_labels)))
print('首条评论',train_data[0])
print('第一、二条评论的长度:',len(train_data[0]),len(train_data[1]))
# 将整数转换回单词,创建辅助函数
# 一个映射单词到整数索引的词典,即获取索引字典
word_index = imdb.get_word_index()
# 保留第一个索引,因为前3个索引是预先保留的索引,所以跳过 v+3
word_index = {k:(v+3) for k ,v in word_index.items()}
word_index['<PAD>']=0
word_index['<START>']=1
word_index['<UNK>']=2
word_index['<UNUSED>']=3
# 将键值颠倒
reverse_word_index = dict([(value, key) for (key,value) in word_index.items()])
# 解码的函数
def decode_review(text):
return ' '.join([reverse_word_index.get(i,'?') for i in text])
# 显示首条评论的文本
print(decode_review(train_data[0]))
# 准备数据:整数数组必须在输入神经网络之前转换为张量,有两种方式来完成
# 1.将数组转换为表示单词出现与否的由0,1组成的向量,类似于one-hot编码(不过此方法需要大量内存-一个大小为num_words*num_reviews的矩阵)
# 2.可以填充数据来保证输入数据具有相同的长度(创建一个大小为max_length*num_reviews的整型张量),可以使用能够处理此形状数据的嵌入层作为网络中的第一层
# 使用第二种方法,用pad_sequences函数来使长度标准化,再打印输出看看是否长度相同,也可再检查一下首条评论(原来比第二条评论短一些)
train_data = keras.preprocessing.sequence.pad_sequences(train_data,
value=word_index['<PAD>'],
padding='post',
maxlen=256)
test_data = keras.preprocessing.sequence.pad_sequences(test_data,
value=word_index['<PAD>'],
padding='post',
maxlen=256)
print('标准化后第一、二条评论的长度:',len(train_data[0]),len(train_data[1]))
print('标准化后的第一条评论',train_data[0])
# 构建模型(输入数据包含一个单词索引的数组,要预测标签为0或1)
# 输入形状是用于电影评论的词汇数目
vocab_size = 10000
# 层按顺序堆叠以构建分类器
# 1.第一层是嵌入层-该层采用整数编码的词汇表,并查找每个词索引的嵌入向量(通过模型训练学习到的),向量向输出数组增加了一个维度(batch,sequence,embedding)
# 2.GlobalAveragePooling1D通过对序列维度求平均值来为每个样本返回一个定长输出向量,这允许模型以尽可能最简单的方式处理变长输入
# 3.该定长输出向量通过一个有16个隐层单元的全连接(Dense)层传输
# 4.最后一层与单个输出结点密集连接。使用sigmoid激活函数,其函数值为介于0与1之间的浮点数,表示概率或置信度
model = keras.Sequential()
model.add(keras.layers.Embedding(vocab_size,16))
model.add(keras.layers.GlobalAveragePooling1D())
model.add(keras.layers.Dense(16,activation='relu'))
model.add(keras.layers.Dense(1,activation='sigmoid'))
model.summary()
# 编译模型
# 损失函数用binary_crossentropy,更适合处理概率-它能够度量概率分布之间的距离
model.compile(optimizer='adam',
loss='binary_crossentropy',
metrics=['accuracy'])
# 创建一个验证集
# 从原始训练数据中分离10000个样本来创建一个验证集(不使用测试集,因为我们的目标只使用训练数据来开发和调整模型,然后只使用一次测试数据来评估准确率)
x_val = train_data[:10000]
partial_x_train = train_data[10000:]
y_val = train_labels[:10000]
partial_y_train = train_labels[10000:]
# 训练模型
# 以512个样本的mini-batch大小迭代40个epoch来训练模型-指对x_train和y_train张量中所有样本的40次迭代。训练时检测损失值和准确率
history = model.fit(partial_x_train,
partial_y_train,
epochs=40,
batch_size=512,
validation_data=(x_val,y_val),
verbose=1)
# 评估模型-返回损失值(越低越好)和准确率(越高越好)
results = model.evaluate(test_data,test_labels,verbose=2)
print(results)
# 创建一个准确率和损失值随时间变化的图标-model.fit返回一个history对象,该对象包含一个字典,其中包含训练阶段所发生的一切事件
# dic_keys有四个条目:'loss', 'accuracy', 'val_loss', 'val_accuracy'
history_dict = history.history
history_dict.keys()
acc = history_dict['accuracy']
val_acc = history_dict['val_accuracy']
loss = history_dict['loss']
val_loss = history_dict['val_loss']
epochs = range(1, len(acc)+1)
# 'bo'代表蓝点
# 'b'代表蓝色实线
# 先画损失值的图,再画准确率的图
plt.plot(epochs,loss,'bo',label='Training loss')
plt.plot(epochs,val_loss,'b',label='Validation loss')
plt.title('Training and validation loss')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend()
plt.savefig(r"D:\test\validation_loss.jpg")
plt.show()
# 清除数字
plt.clf()
plt.plot(epochs, acc, 'bo', label='Training acc')
plt.plot(epochs, val_acc, 'b', label='Validation acc')
plt.title('Training and validation accuracy')
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.legend()
plt.savefig(r"D:\test\validation_accuracy.jpg")
plt.show()
八、运行结果



生成 accuracy.jpg和loss.jpg


tensorflow官方文档 链接:https://tensorflow.google.cn/tutorials/keras/text_classification
本文介绍使用TensorFlow和Keras实现IMDB影评数据集的情感分析任务,包括数据预处理、模型构建、训练及评估过程。

2302

被折叠的 条评论
为什么被折叠?



