听它爹说他孩儿:Keras 学习笔记 4.4

新闻分类:多个类别的分类范例

本节,你将搭建网络把路透社的新闻按主题区分成 46 个不同类,每个数据点只能归入一个类别,因此,这种问题叫做单标签、多类别的分类。如果每个数据点可以属于多个类别(即主题),你所面临的问题就成了多标签、多类别的分类。

路透社数据集

这个数据集是路透社1986年推出的、由短新闻及其分类主题构成的。它是个简单的、广泛用于文本分类的玩具级数据集。它有     46 个不同主题,每个主题至少有 10 个样本在训练集中。与 IMDB 和 MNIST 相同,路透社数据集也打包进了 Keras。我们来看一下。

 载入路透社数据集 

from keras.datasets import reuters
(train_data, train_labels), (test_data, test_labels) = reuters.load_data(num_words=10000)
# words=10000 限制数据集最常用的词汇数目

# 训练样本 8,982 个,测试样本 2,246 个:
>>> len(train_data)
8982
>>> len(test_data)
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]])

# 样本的标签是个整数,值为 0 - 45,表示主题的索引:
>>> train_labels[10]
3
数据预处理

 文本数据编码 

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)

# 二值编码:
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_labels)
one_hot_test_labels = to_one_hot(test_labels)

# 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)
搭建网络

 定义模型 

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 维向量。每一维编码表示不同的输出类别
# 网络最后一层的激活函数是 softmax。这意味着输出是 46 个不同类别的概率分布,并且其和等于 1。

在此最后的损失函数是 categorical_crossentropy。它测算网络输出的概率分布与标签实际分布的差距。将两种分布的差距最小化,你训练的网络输出就最大限度地接近真正的标签。

 编译模型 

model.compile(optimizer='rmsprop',
              loss='categorical_crossentropy',metrics=['accuarcy']
验证你的训练方法

 建立验证数据集 

# 从训练数据中分出 1,000 样本,用于验证。
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 次迭代) 

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

 画出训练和验证的损失 

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='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()
acc = history.history['acc']
val_acc = history.history['val_acc']
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 次的新网络,再用测试数据进行评估。

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
[0.9565213431445807, 0.79697239536954589]
根据新数据进行预测

你可以验证,模型预测的返回结果是对 46 个主题的概率分布。

predictions = model.predict(x_test)

# 每条预测是长度为 46 的向量:
>>> predictions[0].shape
(46,)

# 这个向量各系数之和为 1:
>>> np.sum(predictions[0])
1.0

# 向量系数(概率值)中的最大值是预测出的类别:
>>> np.argmax(predictions[0])
4
处理标签和损失的另一种办法
# 标签编码的另一种办法是将其转成整数张量:
y_train = np.array(train_labels)
y_test = np.array(test_labels)

# 使用数字标签,应当相应地改变损失函数为 sparse_categorical_crossentropy:
model.compile(optimizer='rmsprop',
              loss='sparse_categorical_crossentropy',
              metrics=['acc'])

大空间中间层很重要

本例的中间层不能少于 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%。





  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值