Reuters数据集下载速度慢,可以在我的repo库中找到下载,下载后放到~/.keras/datasets/目录下,即可正常运行。
构建神经网络将路透社新闻分类,一共有46个类别。因为有多个类别,属于多分类问题,而每条数据只属于一个类别,所以是单标签多分类问题;如果每条数据可以被分到多个类别中,那问题则属于多标签多分类问题。
完整代码 欢迎Fork、Star
Reuters数据集发布在1986年,一系列短新闻及对应话题的数据集;是文本分类问题最常用的小数据集。和IMDB、MNIST数据集类似,Reuters数据集也可以通过Keras直接下载。
加载数据集
from keras.datasets import reuters
(train_data,train_labels), (test_data, test_labels) = reuters.load_data(num_words=10000)
有8982条训练集,2246条测试集。
每个样本表示成整数列表。
>>> train_data[10]
[1, 245, 273, 207, 156, 53, 74, 160, 26, 14, 46, 296, 26, 39, 74, 2979,
3554, 14, 46, 4689, 4329, 86, 61, 3499, 4795, 14, 61, 451, 4329, 17, 12]
也可以将整数列表转换成原始数据[英文句子]
word_index = reuters.get_word_index()# 单词--下标 对应字典
reverse_word_index = dict([(value, key) for (key, value) in word_index.items()])# 下标-单词对应字典
decoded_newswire = ' '.join([reverse_word_index.get(i - 3, '?') for i in
train_data[0]]) #偏移3个:0,1,2保留下标,分别表示:“padding,” “start of sequence,” and “unknown.”
整数数据向量化,与IMDB数据集处理方法相同。
import numpy as np
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)
标签的向量化有两种方法:将标签列表转换成整数张量;使用one-hot编码。One-hot编码方式是类别数据常用的一种数据格式,也称为categorical encoding。
def to_one_hot(labels, dimension=46):# 46个类别
results = np.zeros((len(labels), dimension))
for i, label in enumerate(labels):
results[i, label] = 1.
return results
one_hot_train_labels = to_one_hot(train_labels)
one_hot_test_labels = to_one_hot(test_labels)
Keras中有一个内置的One-hot编码转换函数:
from keras.utils.np_utils import to_categorical
one_hot_train_labels = to_categorical(train_labels)
one_hot_test_labels = to_categorical(test_labels)
使用Dense线性连接堆栈结构,每层网络只能处理上层网络的输出结果。如果网络层丢失了一些关于分类问题的信息,那么下一层网络并不能恢复这些信息:每个网络层潜在地成为一个信息处理瓶颈。
网络定义
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.意味着每个输入样本最终变成46维的向量。输出向量的每个数表示不同的类别;
- 最后一层网络使用softmax激活函数–网络会输出一个46类的概率分布。每个输入最终都会产生一个46维的向量,每个数表示属于该类别的概率,46个数加起来等于1.
最好的损失函数为categorical_crossentropy—衡量两个概率分布之间的距离:网络的输出向量和标签的真实分布向量。通过最小化两个分布之间的距离,训练网络模型,使得输出向量尽可能与真实分布相似。
model.compile(optimizer='rmsprop',loss='categorical_crossentropy', metrics=['accuracy'])
在训练数据中分出1000条样本做为验证集。
x_val = x_train[:1000]
partial_x_train = x_train[1000:]
y_val = one_hot_train_labels[:1000]
partial_y_train = one_hot_train_labels[1000:]
训练20个epochs
history = model.fit(partial_x_train,partial_y_train,epochs=20,batch_size=512,validation_data=(x_val, y_val))
训练集和验证集的损失值变化
训练集和验证集的准确率变化
模型在第9次epochs之后开始过拟合。我们将epochs设置为5重新训练,同时在测试集上测试。
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.fit(partial_x_train,partial_y_train,epochs=9,batch_size=512,
validation_data=(x_val, y_val))
results = model.evaluate(x_test, one_hot_test_labels)
# [0.9565213431445807, 0.79697239536954589] 损失值,准确率
准确率达到80%.比随机猜测好。
使用predict函数,产生一个46维的概率分布。在测试数据上进行预测:
predictions = model.predict(x_test)
在预测结果中概率最大的类别就是预测类:
np.argmax(predictions[0])#第一条新闻的预测类 4
直接将列表转换成numpy数组
y_train = np.array(train_labels)
y_test = np.array(test_labels)
需要改变的是损失函数的选择。categorical_crossentropy损失函数期望标签数据使用categorical encoding编码方式。整数标签,应该使用sparse_categorical_crossentropy损失函数:
model.compile(optimizer='rmsprop',loss='sparse_categorical_crossentropy',metrics=['acc'])
新的损失函数在数学表示上与categorical_crossentropy损失函数相同,只是接口不同。
因为最终分为46类,中间层的神经元数目不应该小于46个。如果中间层数目小于46,有4个,将会产生信息瓶颈。
model = models.Sequential()
model.add(layers.Dense(64, activation='relu', input_shape=(10000,)))
model.add(layers.Dense(4, activation='relu'))
model.add(layers.Dense(46, activation='softmax'))
model.compile(optimizer='rmsprop',loss='categorical_crossentropy',metrics=['accuracy'])
model.fit(partial_x_train,partial_y_train,epochs=20,batch_size=128,validation_data=(x_val, y_val))
最终训练结果最高为71%,降低了8个百分点。主要原始是模型试图将大量的信息压缩到低纬度空间中表示,丢失了大量重要的信息。