路透社数据,分为46个主题,每个主题有相应的短新闻。
预处理流程基本和IMDB一样。
加载数据
第一次执行会下载数据,打印了训练样本数和测试样本数。
(train_data,train_labels),(test_data,test_labels) = reuters.load_data(num_words=10000)
print(len(train_data))
print(len(test_data))
转换数据为向量
每个样本同样是单词的索引值。因此同样每条评论转化为10000维度的向量,用1表示有该单词。
标签向量化采用分类编码(categorcial encoding),中的one-hot格式,与数据向量化的思路是一样的,对应种类维度的全0向量。只有标签索引对应的元素为1。代码中使用keras提供的内置方法。
import numpy as np
from keras.utils.np_utils import to_categorical
#转换为10000维的向量,索引的位置是1,其他位置是0
def vectorize_sequences(sequences,dimension=10000):
results = np.zeros((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)
#标签向量化 使用 分类编码 ont-hot
ont_hot_train_labrls = to_categorical(train_labels)
one_hot_test_labels = to_categorical(test_labels)
构建网络
之前电影点评最后输出类别只有两个,现在变成了46个。输出空间的维度大了很多。
因此上一个网络里面用的16个单元在这里不够用了。没办法区分46种不同类别。维度小的层可能成为信息瓶颈。
因此这里使用64个单元。不过同样还是两层隐藏,一个输出。
from keras import models
from keras import layers
#模型定义
model = models.Sequential()
model.add(layers.Dense(64,activation='relu',input_shape=(10000,)))
model.add(layers.Dense(64,activation='relu'))
model.add(layers.Dense(46,activation='softmax'))
最后一层46维向量输出,用softmax激活函数,网络输出在46个类别上的概率分布。46个概率总和为1.
然后使用损失函数 categorical_crossentropy(分类交叉熵)。它用于衡量两个概率分布之间的距离。对比的两个分别是网络输出的概率分布和标签的真实分布。通过让这两个分布之间的距离最小化,来训练网络。
#定义优化器,损失函数,指标
model.compile(optimizer='rmsprop',
loss='categorical_crossentropy',
metrics=['accuracy'])
验证集
从数据中去出1000个样本用来做验证集。
#取1000用于验证集
x_val = x_train[:1000] #验证集
partial_x_train = x_train[1000:]
y_val = ont_hot_train_labels[:1000] #验证集
partial_y_train = ont_hot_train_labels[1000:]
训练模型
history = model.fit(partial_x_train,
partial_y_train,
epochs=20,
batch_size=512,
validation_data=(x_val,y_val))
我们输入训练数据集partial_x_train,训练标签集partial_y_trail。
全部数据训练次数*20。
一次取512的个数据。
history 中包含了训练过程中的所有数据。
validation_data是前一步取出来的验证集。
用matplot绘制出这几个指标的走势:
损失变化图:
import matplotlib.pyplot as plt
loss_values = history.history['loss']
val_loss_values = history.history['val_loss']
epochs = range(1,len(loss_values)+1)
plt.plot(epochs,loss_values,'bo',label='Training loss') #bo是蓝色圆点
plt.plot(epochs,val_loss_values,'b',label='Validation loss') #b是蓝色实线
plt.title('Training and validation loss')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend()
plt.show()
精度变化图:
plt.clf() #清空图表
acc_values = history.history['accuracy']
val_acc_values = history.history['val_accuracy']
plt.plot(epochs,acc_values,'bo',label='Training acc') #bo是蓝色圆点
plt.plot(epochs,val_acc_values,'b',label='Validation acc') #b是蓝色实线
plt.title('Training and validation accuracy')
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.legend()
plt.show()
可以看出训练第8轮后来事出现过拟合。
修改epochs为9个轮次训练
然后在测试集上测试模型。
#训练
history = model.fit(partial_x_train,
partial_y_trail,
epochs=9,
batch_size=512,
validation_data=(x_val,y_val))
results = model.evaluate(x_test,one_hot_test_labels)
print(results)
可以达到80%的精度。
在新数据上预测结果
prediction = model.predict(x_test)
print(prediction[0].shape) #其中每个向量的维度
print(np.sum(prediction[0])) #第一个向量中,所有元素的和
print(np.argmax(prediction[0])) #输出第一个向量中最大概率的类别
可见结果中没一个向量是46维,代表这个新闻所属于46个类别的概率,和为1。其中第一条新闻在第三类别的的概率最大。
更换标签的编码方式
将标签的编码方式换成整数张量。
对于之前的标签采用的分类编码,我们用的损失函数是categorical_crossentropy。
现在改为整数标签之后,应该选择使用sparse_categorical_crossentropy
并修改其他相关代码。
#整数张量 编码标签
y_train = np.array(train_labels)
y_test = np.array(test_labels)
#采用整数标签后,对应的损失函数
model.compile(optimizer='rmsprop',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
y_val = y_train[:1000] #验证集
partial_y_train = y_train[1000:]
results = model.evaluate(x_test,y_test)
完整代码
from keras.datasets import reuters
import numpy as np
from keras.utils.np_utils import to_categorical
from keras import models
from keras import layers
import matplotlib.pyplot as plt
(train_data,train_labels),(test_data,test_labels) = reuters.load_data(num_words=10000)
print(len(train_data))
print(len(test_data))
#转换为10000维的向量,索引的位置是1,其他位置是0
def vectorize_sequences(sequences,dimension=10000):
results = np.zeros((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)
#标签向量化 使用 分类编码 ont-hot
# ont_hot_train_labels = to_categorical(train_labels)
# one_hot_test_labels = to_categorical(test_labels)
#整数张量 编码标签
y_train = np.array(train_labels)
y_test = np.array(test_labels)
#模型定义
model = models.Sequential()
model.add(layers.Dense(64,activation='relu',input_shape=(10000,)))
model.add(layers.Dense(64,activation='relu'))
model.add(layers.Dense(46,activation='softmax'))
#定义优化器,损失函数,指标
#采用分类编码后,对应的损失函数
# model.compile(optimizer='rmsprop',
# loss='categorical_crossentropy',
# metrics=['accuracy'])
#采用整数标签后,对应的损失函数
model.compile(optimizer='rmsprop',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
#取1000用于验证集
x_val = x_train[:1000] #验证集
partial_x_train = x_train[1000:]
# y_val = ont_hot_train_labels[:1000] #验证集
# partial_y_train = ont_hot_train_labels[1000:]
y_val = y_train[:1000] #验证集
partial_y_train = y_train[1000:]
#训练
history = model.fit(partial_x_train,
partial_y_train,
epochs=9,
batch_size=512,
validation_data=(x_val,y_val))
# loss_values = history.history['loss']
# val_loss_values = history.history['val_loss']
#
# epochs = range(1,len(loss_values)+1)
#
# plt.plot(epochs,loss_values,'bo',label='Training loss') #bo是蓝色圆点
# plt.plot(epochs,val_loss_values,'b',label='Validation loss') #b是蓝色实线
# plt.title('Training and validation loss')
# plt.xlabel('Epochs')
# plt.ylabel('Loss')
# plt.legend()
# plt.show()
#
# plt.clf() #清空图表
#
# acc_values = history.history['accuracy']
# val_acc_values = history.history['val_accuracy']
#
# plt.plot(epochs,acc_values,'bo',label='Training acc') #bo是蓝色圆点
# plt.plot(epochs,val_acc_values,'b',label='Validation acc') #b是蓝色实线
# plt.title('Training and validation accuracy')
# plt.xlabel('Epochs')
# plt.ylabel('Accuracy')
# plt.legend()
# plt.show()
# results = model.evaluate(x_test,one_hot_test_labels)
results = model.evaluate(x_test,y_test)
print(results)
prediction = model.predict(x_test)
print(prediction[0].shape) #其中每个向量的维度
print(np.sum(prediction[0])) #第一个向量中,所有元素的和
print(np.argmax(prediction[0])) #输出第一个向量中最大概率的类别