Advertisement

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

阅读量:

文章目录

      • 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
    
    
    AI写代码python
    
    运行

与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]])
    
    
    AI写代码python
    
    运行

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)
    
    
    AI写代码python
    
    运行
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-05-31/JqfNbaBlXkv5uIhLoZF30EW8x9SU.png)

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)
    
    
    AI写代码python
    
    运行

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'))
    
    
    AI写代码python
    
    运行

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

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

5.编译网络

复制代码
    model.compile(optimizer='rmsprop',
              loss='categorical_crossentropy',
              metrics=['accuracy'])
    
    
    AI写代码python
    
    运行

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:]
    
    
    AI写代码python
    
    运行

7.训练模型

复制代码
    history = model.fit(partial_x_train,
                    partial_y_train,
                    epochs=20,
                    batch_size=512,
                    validation_data=(x_val, y_val))
    
    
    AI写代码python
    
    运行

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()
    
    
    AI写代码python
    
    运行
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-05-31/SZ7s5wR1HN9FqUhEBrgIGcpxDtuO.png)
在这里插入图片描述
复制代码
    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()
    
    
    AI写代码python
    
    运行
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-05-31/snaq7i6uXhQ8NHPtYB9omUAMKb5g.png)
在这里插入图片描述

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 
    
    
    AI写代码python
    
    运行
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-05-31/1oZYqFHseCcpJ0y3BkOjPadwVgbz.png)

[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)
    
    
    AI写代码python
    
    运行

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
    
    
    AI写代码python
    
    运行

总结

  • 如果要对 N个类别的数据点进行分类,网络的最后一层应该是大小为N的Dense层。
  • 对于单标签、多分类问题,网络的最后一层应该使用softmax 激活,这样可以输出在N个输出类别上的概率分布。
  • 这种问题的损失函数几乎总是应该使用分类交叉熵。它将网络输出的概率分布与目标的真实分布之间的距离最小化。
  • 处理多分类问题的标签有两种方法。
  • 通过分类编码(也叫 one-hot 编码)对标签进行编码,然后使用 categorical_crossentropy作为损失函数。
  • 将标签编码为整数,然后使用 sparse_categorical_crossentropy损失函数。
  • 如果你需要将数据划分到许多类别中,应该避免使用太小的中间层,以免在网络中造成信息瓶颈。

全部评论 (0)

还没有任何评论哟~