当前位置:   article > 正文

路透社数据集——新闻主题多分类_多分类数据集

多分类数据集

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

与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]])
  • 1
  • 2
  • 3
  • 4
  • 5

3.准备输入的数据

import numpy as np

def 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)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

Keras 内置方法也可以实现这个操作。

from keras.utils.np_utils import to_categorical

one_hot_train_labels = to_categorical(train_labels)
one_hot_test_labels = to_categorical(test_labels)
  • 1
  • 2
  • 3
  • 4

4.构建网络

这个主题分类问题与前面的电影评论分类问题类似,两个例子都是试图对简短的文本片段进行分类。但这个问题有一个新的约束条件:输出类别的数量从2 个变为46 个。输出空间的维度要大得多。对于前面用过的Dense 层的堆叠,每层只能访问上一层输出的信息。如果某一层丢失了与分类问题相关的一些信息,那么这些信息无法被后面的层找回,也就是说,每一层都可能成为信息瓶颈。上一个例子使用了16 维的中间层,但对这个例子来说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'))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

关于这个架构还应该注意:

  • 网络的最后一层是大小为 46 的 Dense 层。这意味着,对于每个输入样本,网络都会输出一个46 维向量。这个向量的每个元素(即每个维度)代表不同的输出类别。
  • 最后一层使用了 softmax 激活,网络将输出在 46个不同输出类别上的概率分布——对于每一个输入样本,网络都会输出一个46 维向量,其中output[i] 是样本属于第i 个类别的概率。46 个概率的总和为1。对于这个例子,最好的损失函数是categorical_crossentropy(分类交叉熵)。它用于衡量两个概率分布之间的距离,这里两个概率分布分别是网络输出的概率分布和标签的真实分布。通过将这两个分布的距离最小化,训练网络可使输出结果尽可能接近真实标签。

5.编译网络

model.compile(optimizer='rmsprop',
              loss='categorical_crossentropy',
              metrics=['accuracy'])
  • 1
  • 2
  • 3

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:]
  • 1
  • 2
  • 3
  • 4
  • 5

7.训练模型

history = model.fit(partial_x_train,
                    partial_y_train,
                    epochs=20,
                    batch_size=512,
                    validation_data=(x_val, y_val))
  • 1
  • 2
  • 3
  • 4
  • 5

8.画出训练数据

import matplotlib.pyplot as plt
%matplotlib inline

loss = 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()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

在这里插入图片描述

plt.clf()   # clear figure

acc = 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()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

在这里插入图片描述

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'))
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)

results 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

[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)
  • 1
  • 2
  • 3
  • 4
  • 5

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
  • 1
  • 2
  • 3
  • 4

总结

  • 如果要对 N个类别的数据点进行分类,网络的最后一层应该是大小为N的Dense层。
  • 对于单标签、多分类问题,网络的最后一层应该使用softmax 激活,这样可以输出在N个输出类别上的概率分布。
  • 这种问题的损失函数几乎总是应该使用分类交叉熵。它将网络输出的概率分布与目标的真实分布之间的距离最小化。
  • 处理多分类问题的标签有两种方法。
  • 通过分类编码(也叫 one-hot 编码)对标签进行编码,然后使用 categorical_crossentropy作为损失函数。
  • 将标签编码为整数,然后使用 sparse_categorical_crossentropy损失函数。
  • 如果你需要将数据划分到许多类别中,应该避免使用太小的中间层,以免在网络中造成信息瓶颈。
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/344605?site
推荐阅读
相关标签
  

闽ICP备14008679号