使用IMDB数据集,包含50000条严重两极分化的评论。
下面的代码会加载IMDB数据集(第一次运行时会下载大约80mb的数据,所以会有一些慢)
from keras.datasets import imdb
# num_wwords = 10000 保留训练数据中前10000个最常出现的单词
(train_data,train_labels),(test_data,test_labels) = imdb.load_data(num_words = 10000)
print("train_data: \n",train_data[0])
print("\ntrain_data.shape: \n",train_data.shape)
print("\ntrain_labels: \n",train_labels)# 1 代表正面 0 代表负面
# train_data和test_data这两个变量是评论组成的列表,每条评论又是单词索引组成的列表
# train_labels是 0 1列表,0代表负面
# 将评论 解码为 英文单词
word_index = imdb.get_word_index()# word_index是一个将单词映射为整数索引的字典
reverse_word_index = dict(
[(value,key) for (key,value) in word_index.items()])# 键为数字,值为单词
decoded_example = ' '.join(
[reverse_word_index.get(i - 3,',') for i in train_data[0]])# 评论解码
# PS:索引 - 3 是因为0,1,2是"padding"(填充) "start of sequence"(序列开始) "unknown"(未知动词)分别保留的索引
print(decoded_example)
print(word_index)
# 将数据转换为张量
# 两种转换方法
# 1、填充列表
# 2、对列表进行one-hot编码,将其转换为0-1组成的向量。比如序列[3,5]将被转换成10000维向量,只有索引为3,5的元素是1,其他都是0
# 为什么是 10000 维? 因为数据限定为前10000个最常见的单词,所以编码一次就会形成10000列
import numpy as np
def vectorize_sequences(sequences,dimension = 10000):
results = np.zeros( (len(sequences),dimension) )# 创建一个形状为 (len(sequences),dimension)的矩阵
for i,sequence in enumerate(sequences):
results[i,sequence] = 1.#
return results
x_train = vectorize_sequences(train_data)
x_test = vectorize_sequences(test_data)
print(x_train[0].shape)
# 标签向量化
y_train = np.asarray(train_labels).astype('float32')
y_test = np.asarray(test_labels).astype('float32')# astype:转换数组的数据类型
# 主要区别在于 np.array (默认情况下)将会copy该对象,而 np.asarray 除非必要,否则不会copy该对象。
# array和asarray都可以将结构数据转化为ndarray,但是主要区别就是当数据源是ndarray时,
# array仍然会copy出一个副本,占用新的内存,但asarray不会
print(train_labels.shape)
print(y_train.shape)
输入数据是向量,标签是标量(1 or 0),有一种网络在这种问题上表现得很好,带有relu激活的全连接层(Dense)的简单堆叠。
# build network
# 输入数据是向量,标签是 标量,这几乎是最简单的情况 ,有一种网络在这种问题上表现的很好,
# 带有relu激活的全连接层(Dense)的简单堆叠
# like Dense(16,activation = 'relu') 16代表改成隐藏单元的个数
from keras import models
from keras import layers
# 两个中间层,每层16个隐藏单元
# 第三层输出一个标量,预测当前评论的情感概率
model = models.Sequential()
model.add(layers.Dense(16,activation = 'relu',input_shape = (10000,)))
model.add(layers.Dense(16,activation = 'relu'))
model.add(layers.Dense(1,activation = 'sigmoid'))
# 还需要选择损失函数和优化器
# 二分类问题,网络输出是一个概率值,最好使用 binary_crossentropy(二元交叉熵)损失
# 使用 rmsprop优化器和binary_crossentropy损失函数来配置模型
# 并且还在训练过程中监视精度
model.compile(optimizer = 'rmsprop',
loss = 'binary_crossentropy',
metrics = ['accuracy'])
# 配置优化器
# 想optimizer参数传入一个优化器类实例实现
from keras import optimizers
model.compile(optimizer = optimizers.RMSprop(lr = 0.001),
loss = 'binary_crossentropy',
metrics = ['accuracy'])
# 向loss 和metrics传入函数对象来实现
from keras import losses
from keras import metrics
model.compile(optimizer = optimizers.RMSprop(lr = 0.001),
loss = losses.binary_crossentropy,
metrics = [metrics.binary_accuracy])
# 为了在训练过程中监控模型在 测试集上的表现,将原始数据留出10000个样本来作为验证集
# x_train.shape -> (25000, 10000)
x_val = x_train[:10000]
partial_x_train = x_train[10000:]
y_val = y_train[:10000]
partial_y_train = y_train[10000:]
# 现在使用512个样本组成的小批量,将模型训练20次,同时还要监控在留出的10000个样本上的损失和精度
# 通过将验证数据传入 validation_data参数完成
model.compile(optimizer = optimizers.RMSprop(lr = 0.001),
loss = 'binary_crossentropy',
metrics = ['acc'])
history = model.fit(partial_x_train,
partial_y_train,
epochs = 20,# 20次迭代
batch_size = 512,
validation_data = (x_val,y_val)
)
# 调用model.fit()返回了一个History对象,这个对象有一个成员history是一个字典,包含训练过程中的所有数据
history_dict = history.history
print(history_dict)
# 绘制训练损失和验证损失
import matplotlib.pyplot as plt
loss_values = history_dict['loss']
val_loss_values = history_dict['val_loss']
epochs = range(1,len(loss_values) + 1)
plt.plot(epochs,loss_values,'bo',label = 'Training loss')
plt.plot(epochs,val_loss_values,'b',label = 'Validation loss')
plt.title('Trianing and validation loss')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend()
plt.show()