路透社数据集——新闻主题多分类"/>
路透社数据集——新闻主题多分类
文章目录
- 1.数据集及问题简介
- 2.加载数据集并探索数据
- 3.准备输入的数据
- 4.构建网络
- 5.编译网络
- 6.从训练集中留出验证集
- 7.训练模型
- 8.画出训练数据
- 9.根据训练数据,重新训练模型并测试
- 10.使用训练好的网络在新数据上生成预测结果
- 总结
1.数据集及问题简介
路透社数据集(Reuter),它包含许多短新闻及其对应的主题,由路透社在1986 年发布。它是一个简单的、广泛使用的文本分类数据集。它包括46 个不同的主题:某些主题的样本更多,但训练集中每个主题都有至少10 个样本。与IMDB 和MNIST 类似,路透社数据集也内置为Keras 的一部分。
我们需要将路透社新闻划分为46 个互斥的主题。因为有多个类别,所以这是多分类(multiclass classification)问题的一个例子。因为每个数据点只能划分到一个类别,所以更具体地说,这是单标签、多分类(single-label, multiclass classification)问题的一个例子。如果每个数据点可以划分到多个类别(主题),那它就是一个多标签、多分类(multilabel,multiclass classification)问题。
2.加载数据集并探索数据
from keras.datasets import reuters(train_data, train_labels), (test_data, test_labels) = reuters.load_data(num_words=10000)print(len(train_data)) #8982
print(len(test_data)) #2246
print(train_data[10])
print(train_labels[10]) # 3
与IMDB 数据集一样,参数num_words=10000 将数据限定为前10 000 个最常出现的单词。我们有8982 个训练样本和2246 个测试样本。与IMDB 评论一样,每个样本都是一个整数列表(表示单词索引)。样本对应的标签是一个0~45 范围内的整数,即话题索引编号。
我们可以用下列代码将索引解码为单词。
word_index = reuters.get_word_index()
reverse_word_index = dict([(value, key) for (key, value) in word_index.items()])
# Note that our indices were offset by 3
# because 0, 1 and 2 are reserved indices for "padding", "start of sequence", and "unknown".
decoded_newswire = ' '.join([reverse_word_index.get(i - 3, '?') for i in train_data[0]])
3.准备输入的数据
import numpy as npdef to_one_hot(labels, dimension=46):results = np.zeros((len(labels), dimension))for i, label in enumerate(labels):results[i, label] = 1.return results# Our vectorized training labels
one_hot_train_labels = to_one_hot(train_labels)
# Our vectorized test labels
one_hot_test_labels = to_one_hot(test_labels)
Keras 内置方法也可以实现这个操作。
from keras.utils.np_utils import to_categoricalone_hot_train_labels = to_categorical(train_labels)
one_hot_test_labels = to_categorical(test_labels)
4.构建网络
这个主题分类问题与前面的电影评论分类问题类似,两个例子都是试图对简短的文本片段进行分类。但这个问题有一个新的约束条件:输出类别的数量从2 个变为46 个。输出空间的维度要大得多。对于前面用过的Dense 层的堆叠,每层只能访问上一层输出的信息。如果某一层丢失了与分类问题相关的一些信息,那么这些信息无法被后面的层找回,也就是说,每一层都可能成为信息瓶颈。上一个例子使用了16 维的中间层,但对这个例子来说16 维空间可能太小了,无法学会区分46 个不同的类别。这种维度较小的层可能成为信息瓶颈,永久地丢失相关信息。出于这个原因,下面将使用维度更大的层,包含64 个单元。
from keras import models
from keras import layersmodel = 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 的 Dense 层。这意味着,对于每个输入样本,网络都会输出一个46 维向量。这个向量的每个元素(即每个维度)代表不同的输出类别。
- 最后一层使用了 softmax 激活,网络将输出在 46个不同输出类别上的概率分布——对于每一个输入样本,网络都会输出一个46 维向量,其中output[i] 是样本属于第i 个类别的概率。46 个概率的总和为1。对于这个例子,最好的损失函数是categorical_crossentropy(分类交叉熵)。它用于衡量两个概率分布之间的距离,这里两个概率分布分别是网络输出的概率分布和标签的真实分布。通过将这两个分布的距离最小化,训练网络可使输出结果尽可能接近真实标签。
5.编译网络
modelpile(optimizer='rmsprop',loss='categorical_crossentropy',metrics=['accuracy'])
6.从训练集中留出验证集
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:]
7.训练模型
history = model.fit(partial_x_train,partial_y_train,epochs=20,batch_size=512,validation_data=(x_val, y_val))
8.画出训练数据
import matplotlib.pyplot as plt
%matplotlib inlineloss = history.history['loss']
val_loss = history.history['val_loss']epochs = range(1, len(loss) + 1)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.show()
plt.clf() # clear figureacc = history.history['accuracy']
val_acc = history.history['val_accuracy']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('Loss')
plt.legend()plt.show()
9.根据训练数据,重新训练模型并测试
网络在训练9 轮后开始过拟合。我们从头开始训练一个新网络,共9 个轮次,然后在测试集上评估模型。
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'))
modelpile(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)results
[1.006295904344676, 0.7849510312080383]
这种方法可以得到约80% 的精度。对于平衡的二分类问题,完全随机的分类器能够得到50% 的精度。但在这个例子中,完全随机的精度约为19%,所以上述结果相当不错,至少和随机的基准比起来还不错。
import copy
#【完全随机】
test_labels_copy = copy.copy(test_labels)
np.random.shuffle(test_labels_copy)
float(np.sum(np.array(test_labels) == np.array(test_labels_copy))) / len(test_labels)
0.18432769367764915
10.使用训练好的网络在新数据上生成预测结果
predictions = model.predict(x_test)
print(predictions[0].shape) #(46,)
print(np.sum(predictions[0])) #0.99999994
print(np.argmax(predictions[0])) #3
总结
- 如果要对 N个类别的数据点进行分类,网络的最后一层应该是大小为N的Dense层。
- 对于单标签、多分类问题,网络的最后一层应该使用softmax 激活,这样可以输出在N个输出类别上的概率分布。
- 这种问题的损失函数几乎总是应该使用分类交叉熵。它将网络输出的概率分布与目标的真实分布之间的距离最小化。
- 处理多分类问题的标签有两种方法。
- 通过分类编码(也叫 one-hot 编码)对标签进行编码,然后使用
categorical_crossentropy
作为损失函数。 - 将标签编码为整数,然后使用
sparse_categorical_crossentropy
损失函数。 - 如果你需要将数据划分到许多类别中,应该避免使用太小的中间层,以免在网络中造成信息瓶颈。
更多推荐
路透社数据集——新闻主题多分类
发布评论