新闻分类--多分类问题


1.加载路透社数据集

from tensorflow.keras.datasets import reuters
(train_data,train_lables),(test_data,test_lables) = reuters.load_data(num_words=10000)

首次运行会自动下载数据集

2.准备数据

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.0
    return results
x_train = vectorize_sequences(train_data) #训练数据向量化
x_test = vectorize_sequences(test_data)   #测试数据向量化

标签向量化可以采用one-hot编码,标签的 one-hot 编码就是将每个标签表示为全零向量,
只有标签索引对应的元素为 1。其代码实现如下。

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
one_hot_train_labels = to_one_hot(train_lables)
one_hot_test_labels = to_one_hot(test_lables)

 3.构建网络

这个主题分类问题与前面的电影评论分类问题类似,两个例子都是试图对简短的文本片段
进行分类。但这个问题有一个新的约束条件:输出类别的数量从 2 个变为 46 个。输出空间的维
度要大得多。下面将使用维度更大的层,包含 64 个单元。

from tensorflow.keras import models
from tensorflow.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维向量,output[i]代表第i个类别的概率。46个概率总和为1

4.编译模型

和之前二分类不同的是损失函数的选择为分类交叉熵

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

 5.留出验证集

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:]

6.训练模型

history = model.fit(partial_x_train,
                    partial_y_train,
                    epochs=20,
                    batch_size=512,
                    validation_data=(x_val,y_val))  # validation_data验证集

 7.绘制训练损失和验证损失

import matplotlib.pyplot as plt

loss = history.history['loss']
val_loss = history.history['val_loss']

epochs = range(1,len(loss)+1)

plt.plot(epochs,loss,'bo',label = 'Train 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()

8.绘制训练精度和验证精度

plt.clf()

acc = history.history['accuracy']
val_acc = history.history['val_accuracy']

plt.plot(epochs,acc,'bo',label = 'Train acc')
plt.plot(epochs,val_acc,'b',label= 'vallidation acc')
plt.title("Training and validation acc")
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.legend()

plt.show()

 可以看到从第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)
print(result)

 小结:

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