深度學習的廣泛運用之一就是對文本按照其內容進行分類撬腾。例如對新聞報道根據其性質進行劃分是常見的應用領域螟蝙。在本節(jié),我們要把路透社自1986年以來的新聞數(shù)據按照46個不同話題進行劃分民傻。網絡經過訓練后胰默,它能夠分析一篇新聞稿场斑,然后按照其報道內容,將其歸入到設定好的46個話題之一牵署。深度學習在這方面的應用屬于典型的“單標簽漏隐,多類別劃分”的文本分類應用。
我們這里采用的數(shù)據集來自于路透社1986年以來的報道奴迅,數(shù)據中每一篇新聞稿附帶一個話題標簽青责,以用于網絡訓練,每一個話題至少含有10篇文章取具,某些報道它內容很明顯屬于給定話題脖隶,有些報道會模棱兩可,不好確定它到底屬于哪一種類的話題者填,我們先把數(shù)據加載到機器里浩村,代碼如下:
from keras.datasetsimportreuters(train_data, train_label),(test_data, test_labels)= reuters.load_data(num_words=10000)
keras框架直接附帶了相關數(shù)據集,通過執(zhí)行上面代碼就可以將數(shù)據下載下來占哟。上面代碼運行后結果如下:
這里寫圖片描述
從上面運行結果看酿矢,它總共有8982條訓練數(shù)據和2246條測試數(shù)據榨乎。跟我們上節(jié)數(shù)據類型一樣,數(shù)據里面對應的是每個單詞的頻率編號瘫筐,我們可以通過上一節(jié)類似的代碼,將編號對應的單詞從字典中抽取出來結合成一篇文章拙毫,代碼如下:
word_index = reuters.get_word_index()reverse_word_index = dict([value, key]for(key, value)inword_index.items())decoded_newswire =' '.join([reverse_word_index.get(i-3,'?')foriintrain_data[0]])print(decoded_newswire)
上面代碼運行后結果如下:
這里寫圖片描述
如同上一節(jié)膘婶,我們必須要把訓練數(shù)據轉換成數(shù)據向量才能提供給網絡進行訓練逝段,因此我們像上一節(jié)一樣,對每條新聞創(chuàng)建一個長度為一萬的向量朗儒,先把元素都初始為0开呐,然后如果某個對應頻率的詞在文本中出現(xiàn)卵惦,那么我們就在向量中相應下標設置為1,代碼如下:
importnumpyasnpdefvectorize_sequences(sequences, dimension=10000):results = np.zeros((len(sequences), dimension))fori, sequenceinenumerate(sequences):? ? ? ? results[i, sequence] =1.returnresultsx_train = vectorize_sequences(train_data)x_test = vectorize_sequences(test_data)print(x_train[0])
上面代碼運行后揍拆,我們就把訓練數(shù)據變成含有1或0的向量了:
這里寫圖片描述
其實我們可以直接調用keras框架提供的接口一次性方便簡單的完成:
fromkeras.utils.np_utilsimportto_categoricalone_hot_train_labels = to_categorical(train_label)one_hot_test_labels = to_categorical(test_labels)
接下來我們可以著手構建分析網絡筒狠,網絡的結構與上節(jié)很像聘萨,因為要解決的問題性質差不多,都是對文本進行分析叔收。然而有一個重大不同在于,上一節(jié)我們只讓網絡將文本劃分成兩種類別复濒,而這次我們需要將文本劃分為46個類別脖卖!上一節(jié)我們構造網絡時,中間層網絡我們設置了16個神經元巧颈,由于現(xiàn)在我們需要在最外層輸出46個結果畦木,因此中間層如果只設置16個神經元那就不夠用,由于輸出的信息太多砸泛,如果中間層神經元數(shù)量不足十籍,那么他就會成為信息過濾的瓶頸蛆封,因此這次我們搭建網絡時,中間層網絡節(jié)點擴大為6個勾栗,代碼如下:
fromkerasimportmodelsfromkerasimportlayersmodel = models.Sequential()model.add(layers.Dense(64, activation='relu', input_shape=(10000,)))model.add(layers.Dense(64, activation='relu'))#當結果是輸出多個分類的概率時惨篱,用softmax激活函數(shù),它將為46個分類提供不同的可能性概率值model.add(layers.Dense(46, activation='softmax'))#對于輸出多個分類結果,最好的損失函數(shù)是categorical_crossentropymodel.compile(optimizer='rmsprop', loss='categorical_crossentropy', metrics=['accuracy'])
像上一節(jié)一樣围俘,在網絡訓練時我們要設置校驗數(shù)據集砸讳,因為網絡并不是訓練得次數(shù)越多越好,有了校驗數(shù)據集楷拳,我們就知道網絡在訓練幾次的情況下能夠達到最優(yōu)狀態(tài)绣夺,準備校驗數(shù)據集的代碼如下:
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:]
有了數(shù)據,就相當于有米入鍋欢揖,我們可以把數(shù)據輸入網絡進行訓練:
history= model.fit(partial_x_train, partial_y_train, epochs=20, batch_size=512,? ? ? ? ? ? ? ? ? ? validation_data=(x_val, y_val))
代碼進行了20個周期的循環(huán)訓練陶耍,由于數(shù)據量比上一節(jié)小,因此速度快很多她混,與上一節(jié)一樣烈钞,網絡的訓練并不是越多越好,它會有一個拐點坤按,訓練次數(shù)超出后毯欣,效果會越來越差,我們把訓練數(shù)據圖形化臭脓,以便觀察拐點從哪里開始:
importmatplotlib.pyplotaspltloss = 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.xlabel('Epochs')plt.ylabel('Loss')plt.legend()plt.show()
上面代碼運行后結果如下:
這里寫圖片描述
通過上圖觀察我們看到酗钞,以藍點表示的是網絡對訓練數(shù)據的判斷準確率,該準確率一直在不斷下降来累,但是藍線表示的是網絡對校驗數(shù)據判斷的準確率砚作,仔細觀察發(fā)現(xiàn),它一開始是迅速下降的嘹锁,過了某個點葫录,達到最低點后就開始上升,這個點大概是在epochs=9那里领猾,所以我們把前面對網絡訓練的循環(huán)次數(shù)減少到9:
fromkerasimportmodelsfromkerasimportlayersmodel = models.Sequential()model.add(layers.Dense(64, activation='relu', input_shape=(10000,)))model.add(layers.Dense(64, activation='relu'))#當結果是輸出多個分類的概率時米同,用softmax激活函數(shù),它將為46個分類提供不同的可能性概率值model.add(layers.Dense(46, activation='softmax'))#對于輸出多個分類結果,最好的損失函數(shù)是categorical_crossentropymodel.compile(optimizer='rmsprop', loss='categorical_crossentropy', metrics=['accuracy'])history = 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(results)
上面兩句代碼運行結果為:
這里寫圖片描述
右邊0.78表示面粮,我們網絡對新聞進行話題分類的準確率達到78%,差一點到80%拯坟。我們從測試數(shù)據集中拿出一條數(shù)據但金,讓網絡進行分類,得到結果再與其對應的正確結果比較看看是否一致:
predictions = model.predict(x_test)print(predictions[0])print(np.sum(predictions[0]))print(np.argmax(predictions[0]))print(one_hot_test_labels[0])
我們讓網絡對每一條測試數(shù)據一一進行判斷郁季,并把它對第一條數(shù)據的判斷結果顯示出來冷溃,最后我們打印出第一條測試數(shù)據對應的分類钱磅,最后看看網絡給出去的結果與正確結果是否一致,上面代碼運行后結果如下:
這里寫圖片描述
從上面運行結果看到似枕,網絡對第一條數(shù)據給出了屬于46個分類的概率盖淡,其中下標為3的概率值最大,也就是第一條數(shù)據屬于分類4的概率最大凿歼,最后打印出來的測試數(shù)據對應的正確結果來看褪迟,它也是下標為3的元素值為1,也就是說數(shù)據對應的正確分類是4答憔,由此我們網絡得到的結果是正確的味赃。
前面提到過,由于網絡最終輸出結果包含46個元素虐拓,因此中間節(jié)點的神經元數(shù)目不能小于46心俗,因為小于46,那么有關46個元素的信息就會遭到擠壓蓉驹,于是在層層運算后會導致信息丟失城榛,最后致使最終結果的準確率下降,我們試試看是不是這樣:
fromkerasimportmodelsfromkerasimportlayersmodel = models.Sequential()model.add(layers.Dense(64, activation='relu', input_shape=(10000,)))model.add(layers.Dense(4, activation='relu'))#當結果是輸出多個分類的概率時态兴,用softmax激活函數(shù),它將為46個分類提供不同的可能性概率值model.add(layers.Dense(46, activation='softmax'))#對于輸出多個分類結果狠持,最好的損失函數(shù)是categorical_crossentropymodel.compile(optimizer='rmsprop', loss='categorical_crossentropy', metrics=['accuracy'])history = 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(results)
上面代碼運行后,輸出的results結果如下:
[1.4625472680649796, 0.6705253784505788]
從上面結果看到瞻润,我們代碼幾乎沒變喘垂,致使把第二層中間層神經元數(shù)量改成4,最終結果的準確率就下降10個點绍撞,所以中間層神經元的減少導致信息壓縮后王污,最后計算的準確度缺失。反過來你也可以試試用128個神經元的中間層看看準確率有沒有提升楚午。
到這里不知道你發(fā)現(xiàn)沒有,神經網絡在實際項目中的運用有點類似于樂高積木尿招,你根據實際需要矾柜,通過選定參數(shù),用幾行代碼配置好基本的網絡結構就谜,把訓練數(shù)據改造成合適的數(shù)字向量怪蔑,然后就可以輸入到網絡中進行訓練,訓練過程中記得用校驗數(shù)據監(jiān)測最優(yōu)訓練次數(shù)丧荐,防止過度擬合缆瓣。
在網絡的設計過程中,其背后的數(shù)學原理我們幾乎無需了解虹统,只需要憑借經驗弓坞,根據項目的性質隧甚,設定網絡的各項參數(shù),最關鍵的其實在根據項目數(shù)據性質對網絡進行調優(yōu)渡冻,例如網絡設置幾層好戚扳,每層幾個神經元,用什么樣的激活函數(shù)和損失函數(shù)等等族吻,這些操作與技術無關帽借,取決以個人經驗,屬于“藝術”的范疇超歌。
作者:望月從良
鏈接:http://www.reibang.com/p/c81414c30d6b
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯(lián)系作者獲得授權并注明出處巍举。