本文中我希望用IMDB数据集和神经网络对数据集中的影评内容进行“正面影评”和“负面影评”的二分类。
IMDB
IMDB数据集是Tensorflow中带有的数据集,其中包含来自互联网电影库的50000条影评文本,首先来下载该数据集并且查看一下:
加载数据(如果缓存中没有回自动下载该数据):
import tensorflow as tf from tensorflow import keras import numpy as np imdb = keras.datasets.imdb (train_data, train_labels), (test_data, test_labels) = imdb.load_data(num_words=10000)
查看数据:
print("Trraining entries:{},labels:{}".format(len(train_data),len(train_labels)))
输出中可以看到我们训练集的样本量为25000
查看数据中的其中一个样本是什么:
print(train_data[0])
可以看书虽然是影评,在我们的数据集中译英转换为了数值类型而不是字符型,其中每一个数字都代表一个词语,后续会用其他的方法将数值型转换为字符型。
我们知道在神经网络的输入中必须要有相同的长度,所以我们先查看几条数据的长度是不是相同的:
print(len(train_data[0]),len(train_data[10]),len(train_data[100]))
由这个输出结果可以看出,每条影评的长度是不相同的所以我们要想办法处理这个问题,在这里我的办法设置一个最长值得限制,并将短的数据用零来填充:
train_data = keras.preprocessing.sequence.pad_sequences(train_data, value=0, padding='post', maxlen=256) test_data = keras.preprocessing.sequence.pad_sequences(test_data, value=0, padding='post', maxlen=256) print(len(train_data[0]),len(train_data[10]),len(train_data[100]))
输出结果如下,此时我们可以看出每一条数据的长度都是相同的:
keras.preprocessing.sequence.pad_sequences(sequences, maxlen=None, dtype=’int32’, padding=’pre’, truncating=’pre’, value=0.)
函数说明:
将长为nb_samples的序列(标量序列)转化为形如(nb_samples,nb_timesteps)2D numpy array。如果提供了参数maxlen,nb_timesteps=maxlen,否则其值为最长序列的长度。其他短于该长度的序列都会在后部填充0以达到该长度。长于nb_timesteps的序列将会被截断,以使其匹配目标长度。padding和截断发生的位置分别取决于padding和truncating.
参数:
sequences:浮点数或整数构成的两层嵌套列表
maxlen:None或整数,为序列的最大长度。大于此长度的序列将被截短,小于此长度的序列将在后部填0.
dtype:返回的numpy array的数据类型
padding:‘pre’或‘post’,确定当需要补0时,在序列的起始还是结尾补
truncating:‘pre’或‘post’,确定当需要截断序列时,从起始还是结尾截断
value:浮点数,此值将在填充时代替默认的填充值0
构建模型
神经网络通过层数的堆叠创建成,下面先说一下每一层的作用。
示例中,输入数据由字词-索引数组构成,要预测的标签是0或1(正面影评和负面影评)
第一层:Embedding层,该层会在整数编码的词汇表中查找每个字词-索引的嵌入向量,模型在接受训练时会学习这些向量,这些向量会向输出数组中添加一个维度,添加后的维度是(batch,sequence,embedding);
第二层:一个 GlobalAveragePooling1D 层通过对序列维度求平均值,针对每个样本返回一个长度固定的输出向量。这样,模型便能够以尽可能简单的方式处理各种长度的输入。
第三层:该长度固定的输出向量会传入一个全连接 (Dense) 层(包含 16 个隐藏单元)。
第四层:最后一层与单个输出节点密集连接。应用 sigmoid 激活函数后,结果是介于 0 到 1 之间的浮点值,表示概率或置信水平。
vocab_size = 10000 model = keras.Sequential() model.add(keras.layers.Embedding(vocab_size, 16)) model.add(keras.layers.GlobalAveragePooling1D()) model.add(keras.layers.Dense(16, activation=tf.nn.relu)) model.add(keras.layers.Dense(1, activation=tf.nn.sigmoid)) model.summary()
输出如下:
损失函数和优化器
构建完了神经网络下面我们来定义一个损失函数和优化器
model.compile(optimizer=tf.train.AdamOptimizer(), loss='binary_crossentropy', metrics=['accuracy'])
创建验证集
创建数据集的目的是为了检测模型处理未见过的数据时的准确率,我们取总数据的20%也就是10000条数据来创建验证集。
x_val = train_data[:10000] partial_x_train = train_data[10000:] y_val = train_labels[:10000] partial_y_train = train_labels[10000:]
训练模型并且评估模型
用有 512 个样本的小批次训练模型 40 个周期。这将对 x_train 和 y_train 张量中的所有样本进行 40 次迭代。在训练期间,监控模型在验证集的 10000 个样本上的损失和准确率,最后我们使用evaluate来查看模型的误差和准确率:
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) print(results)
最后的输出结果如下:
由此可见我们的模型准确率为0.87,并不是很完美,如果采用更好的方法可能会对准确率有更大的提高。