Keras深度学习——使用神经网络进行新闻分类

687 阅读5分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第20天,点击查看活动详情

新闻分类

在先前的应用实战中,我们分析了结构化的数据集,即数据集中包含变量及其对应实际输出值。在本项目实战中,我们将处理一个以文本作为输入的数据集,并且预期的输出是文本相关的主题。

任务与模型分析

为了进行文本分析,本章使用Reuters数据集,其中每则新闻文章都被分类为46种可能的主题之一。我们将采用以下策略构建神经网络模型:

  • 假设一个数据集可以包含数千个不同的单词,我们需要给定要考虑的单词。
  • 对于此实战,我们使用最常用的10,000个单词。
  • 一种替代方法是考虑累积构成数据集中80%内容的单词。这样可以确保排除数据集中的稀有词。
  • 获取候选单词后,将根据这些单词对输入文章进行独热编码。
  • 同样,对输出标签进行独热编码。
  • 经过独热编码后,每个输入都是10,000维向量,而输出是46维向量:
  • 将数据集分为训练和测试数据集。本项目使用Keras中内置的Reuters数据集,该数据集一些内置方法,包括识别前n个常用词以及将该数据集分为训练和测试数据集。
  • 由于模型数据量较大,因此神经网络中包括多个隐藏层。
  • 在输出层使用softmax函数,以获得输入数据的类别概率。
  • 由于有多个可能的类别输出,因此使用分类交叉熵损失函数。
  • 最后,编译并拟合该模型以在测试数据集上测量其准确性。

模型构建与训练

接下来,我们将实现上述定义的神经网络模型。 导入数据集:

from keras.datasets import reuters
(train_data, train_labels), (test_data, test_labels) = reuters.load_data(num_words=10000)

在前面的代码片段中,我们从Keras中可用的reuters数据集中加载了数据。此外,我们仅考虑数据集中的10000个最常见单词。 检查数据集:

print(train_data[0])

加载的训练数据集的示例如下:

[1, 2, 2, 8, ... , 17, 12]

先前输出中的数字表示输入文章中的单词索引。也可以获取单词对应的索引:

word_index = reuters.get_word_index()
print(word_index)

输出结果如下:

{'mdbl': 10996,
 'fawc': 16260,
 'degussa': 12089,
 'woods': 8803,
 'hanging': 13796,
 'localized': 20672,
 'sation': 20673,
...}

可以看到每个单词在数据集中对应的索引。我们可以调转键值对得到{索引:单词}对,然后使用此字典可以打印句子中包含的单词:

reverse_word_index = dict([(value, key) for (key, value) in word_index.items()])
print(reverse_word_index)
#{30933: 'enahnce', 752: 'agreements', 20649: 'monoclonal', 9379: 'grieveson', 10063: 'emirate',... }
decoded_newswire = ' '.join([reverse_word_index.get(i - 3, '?') for i in train_data[0]])
print(decoded_newswire)

输出结果如下:

#? ? ? said as a result of its december acquisition of space co it expects earnings per share in 1987 of 1 15 to 1 30 dlrs per share up from 70 cts in 1986 the company said pretax net should rise to nine to 10 mln dlrs from six mln dlrs in 1986 and rental operation revenues to 19 to 22 mln dlrs from 12 5 mln dlrs it said cash flow per share this year should be 2 50 to three dlrs reuter 3

接下来构建向量化输入,通过以下方式将文本转换为向量:

  • 对输入的单词进行独热编码——在输入数据集中总共包含 10000 列,每个文章是一个长度为 10000 的数据。
  • 如果给定文本中的一个单词,则将对应于单词 index 的列的值设为1,而其他列的值为 0
  • 对文本中的所有单词重复上述步骤。如果一个文本有两个不重复的单词,那么该文本对应的向量总共有两列的值为 1,而其余列的值为 0
def vectorize_sequences(sequences, dimension=10000):
    results = np.zeros((len(sequences), dimension))
    for i, sequence in enumerate(sequences):
        results[i, sequence] = 1.
    return results

在前面的函数中,我们基于输入序列中存在的索引值初始化了一个零矩阵变量,并将单词相应索引处的值设为 1。 接下来,使用上述函数将文本向量化。

x_train = vectorize_sequences(train_data)
x_test = vectorize_sequences(test_data)

将输出值进行独热编码:

from keras.utils.np_utils import to_categorical
one_hot_train_labels = to_categorical(train_labels)
one_hot_test_labels = to_categorical(test_labels)

以上代码将每个输出标签转换为长度为46的独热向量,其中46个值中只有一个为1,其余为零,具体取决于标签的索引值。 定义模型并进行编译:

from keras.models import Sequential
from keras.layers import Dense

model = Sequential()
model.add(Dense(128, activation='relu', input_shape=(10000, )))
model.add(Dense(64, activation='relu'))
model.add(Dense(46, activation='softmax'))
model.summary()
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['acc'])

模型简要信息如下:

Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense (Dense)                (None, 128)               1280128   
_________________________________________________________________
dense_1 (Dense)              (None, 64)                8256      
_________________________________________________________________
dense_2 (Dense)              (None, 46)                2990      
=================================================================
Total params: 1,291,374
Trainable params: 1,291,374
Non-trainable params: 0
_________________________________________________________________

在编译时,将损失定义为 categorical_crossentropy,因为本例的输出是多分类结果(输出中有多个类)。 拟合模型:

history = model.fit(x_train, one_hot_train_labels,
                    epochs=20,
                    batch_size=512,
                    validation_data=(x_test, one_hot_test_labels),
                    verbose=1)

训练后的模型,能够以近80%的准确率将输入文本分类为正确的主题。