[Deep-Learning-with-Python]基于Kears的Reuters新聞分類

Reuters數(shù)據(jù)集下載速度慢,可以在我的repo庫中找到下載,下載后放到~/.keras/datasets/目錄下,即可正常運行。

完整代碼 歡迎Fork、Star

構建神經(jīng)網(wǎng)絡將路透社新聞分類,一共有46個類別。因為有多個類別,屬于多分類問題,而每條數(shù)據(jù)只屬于一個類別,所以是單標簽多分類問題;如果每條數(shù)據(jù)可以被分到多個類別中,那問題則屬于多標簽多分類問題。

路透社數(shù)據(jù)集

Reuters數(shù)據(jù)集發(fā)布在1986年,一系列短新聞及對應話題的數(shù)據(jù)集;是文本分類問題最常用的小數(shù)據(jù)集。和IMDB、MNIST數(shù)據(jù)集類似,Reuters數(shù)據(jù)集也可以通過Keras直接下載。

加載數(shù)據(jù)集

from keras.datasets import reuters

(train_data,train_labels), (test_data, test_labels) = reuters.load_data(num_words=10000)

有8982條訓練集,2246條測試集。
每個樣本表示成整數(shù)列表。

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

也可以將整數(shù)列表轉(zhuǎn)換成原始數(shù)據(jù)[英文句子]

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]]) #偏移3個:0,1,2保留下標,分別表示:“padding,” “start of sequence,” and “unknown.”

準備數(shù)據(jù)

整數(shù)數(shù)據(jù)向量化,與IMDB數(shù)據(jù)集處理方法相同。

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)

標簽的向量化有兩種方法:將標簽列表轉(zhuǎn)換成整數(shù)張量;使用one-hot編碼。One-hot編碼方式是類別數(shù)據(jù)常用的一種數(shù)據(jù)格式,也稱為categorical encoding。

def to_one_hot(labels, dimension=46):# 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中有一個內(nèi)置的One-hot編碼轉(zhuǎn)換函數(shù):

from keras.utils.np_utils import to_categorical

one_hot_train_labels = to_categorical(train_labels)
one_hot_test_labels = to_categorical(test_labels)

模型搭建

使用Dense線性連接堆棧結構,每層網(wǎng)絡只能處理上層網(wǎng)絡的輸出結果。如果網(wǎng)絡層丟失了一些關于分類問題的信息,那么下一層網(wǎng)絡并不能恢復這些信息:每個網(wǎng)絡層潛在地成為一個信息處理瓶頸。

網(wǎng)絡定義

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

關于這個網(wǎng)絡架構有兩點需要注意:

  • 最后一層網(wǎng)絡神經(jīng)元數(shù)目為46.意味著每個輸入樣本最終變成46維的向量。輸出向量的每個數(shù)表示不同的類別;
  • 最后一層網(wǎng)絡使用softmax激活函數(shù)--網(wǎng)絡會輸出一個46類的概率分布。每個輸入最終都會產(chǎn)生一個46維的向量,每個數(shù)表示屬于該類別的概率,46個數(shù)加起來等于1.

最好的損失函數(shù)為categorical_crossentropy---衡量兩個概率分布之間的距離:網(wǎng)絡的輸出向量和標簽的真實分布向量。通過最小化兩個分布之間的距離,訓練網(wǎng)絡模型,使得輸出向量盡可能與真實分布相似。

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

模型驗證

在訓練數(shù)據(jù)中分出1000條樣本做為驗證集。

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個epochs

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

訓練集和驗證集的損失值變化


image

訓練集和驗證集的準確率變化


image

模型在第9次epochs之后開始過擬合。我們將epochs設置為5重新訓練,同時在測試集上測試。
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)
# [0.9565213431445807, 0.79697239536954589] 損失值,準確率

準確率達到80%.比隨機猜測好。

預測新數(shù)據(jù)

使用predict函數(shù),產(chǎn)生一個46維的概率分布。在測試數(shù)據(jù)上進行預測:

predictions = model.predict(x_test)

在預測結果中概率最大的類別就是預測類:

np.argmax(predictions[0])#第一條新聞的預測類 4

另一種標簽、損失函數(shù)處理方式

直接將列表轉(zhuǎn)換成numpy數(shù)組

y_train = np.array(train_labels)
y_test = np.array(test_labels)

需要改變的是損失函數(shù)的選擇。categorical_crossentropy損失函數(shù)期望標簽數(shù)據(jù)使用categorical encoding編碼方式。整數(shù)標簽,應該使用sparse_categorical_crossentropy損失函數(shù):

model.compile(optimizer='rmsprop',loss='sparse_categorical_crossentropy',metrics=['acc'])

新的損失函數(shù)在數(shù)學表示上與categorical_crossentropy損失函數(shù)相同,只是接口不同。

有充分大規(guī)模中間層的重要性

因為最終分為46類,中間層的神經(jīng)元數(shù)目不應該小于46個。如果中間層數(shù)目小于46,有4個,將會產(chǎn)生信息瓶頸。

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個百分點。主要原始是模型試圖將大量的信息壓縮到低緯度空間中表示,丟失了大量重要的信息。

小結

  • N分類問題,網(wǎng)絡最后Dense層神經(jīng)元數(shù)目為N;
  • 單標簽多分類問題中,最后一層的激活函數(shù)為softmax,產(chǎn)生一個包含N類的概率分布;
  • categorical crossentropy是處理單標簽多分類問題最常用的損失函數(shù);
  • 在多分類問題中有兩種標簽處理方式:
    1. 使用categorical encoding(one-hot)編碼,將標簽one-hot化,同時使用categorical_crossentropy作為損失函數(shù);
    2. 編碼成整數(shù)向量,使用sparse_categorical_crossentropy作為損失函數(shù);
  • 如果分類數(shù)目過大,應該避免網(wǎng)絡中間層數(shù)目過小(比分類數(shù)目小--信息壓縮),產(chǎn)生信息瓶頸。
最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容