一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

如何用 Python 和循環(huán)神經(jīng)網(wǎng)絡(RNN)做中文文本分類?

 LibraryPKU 2018-11-24

本文為你展示,如何使用 fasttext 詞嵌入預訓練模型和循環(huán)神經(jīng)網(wǎng)絡(RNN), 在 Keras 深度學習框架上對中文評論信息進行情感分類。

疑問

回顧一下,之前咱們講了很多關于中文文本分類的內(nèi)容。

你現(xiàn)在應該已經(jīng)知道如何對中文文本進行分詞了。

你也已經(jīng)學習過,如何利用經(jīng)典的機器學習方法,對分詞后的中文文本,做分類。

你還學習過,如何用詞嵌入預訓練模型,以向量,而不是一個簡單的索引數(shù)值,來代表詞語,從而讓中文詞語的表征包含語義級別的信息。

但是,好像還差了點兒什么。

對,基于深度學習的中文文本分類方法,老師是不是忘了講?

其實沒有。

我一直惦記著,把這個重要的知識點,給你詳細講解一下。但是之前這里面一直有一條鴻溝,那就是循環(huán)神經(jīng)網(wǎng)絡(Recurrent Neural Network, RNN)。

如果你不知道 RNN 是怎么回事兒,你就很難理解文本作為序列,是如何被深度學習模型來處理的。

好在,我已經(jīng)為你做了視頻教程,用手繪的方式,給你講了這一部分。

既然現(xiàn)在這道鴻溝,已被跨越了。本文咱們就來嘗試,把之前學過的知識點整合在一起,用 Python 和 Keras 深度學習框架,對中文文本嘗試分類。

數(shù)據(jù)

為了對比的便捷,咱們這次用的,還是《如何用Python和機器學習訓練中文文本情感分類模型?》一文中采用過的某商戶的點評數(shù)據(jù)。

我把它放在了一個 github repo 中,供你使用。

請點擊這個鏈接,訪問咱們的代碼和數(shù)據(jù)。

我們的數(shù)據(jù)就是其中的 dianping.csv 。你可以點擊它,看看內(nèi)容。

每一行是一條評論。評論內(nèi)容和情感間,用逗號分隔。

1 代表正向情感,0 代表負面情感。

環(huán)境

要運行深度學習,你需要有 GPU 或者 TPU 的支持。

我知道,它們不便宜。

好在,Google 為咱們提供了免費的云端運行環(huán)境,叫做 Google Colab 。我曾經(jīng)在《如何免費云端運行Python深度學習框架?》一文中,為你介紹過它?,F(xiàn)在,它不止支持 GPU 了,還包含了 TPU 的選項。

注意,請使用 Google Chrome 瀏覽器來完成以下操作。

因為你需要安裝一個瀏覽器插件插件,叫做 Colaboratory ,它是 Google 自家的插件,只能在 Chrome 瀏覽器中,才能運行。

點擊這個鏈接,安裝插件。

把它添加到 Google Chrome 之后,你會在瀏覽器的擴展工具欄里面,看見下圖中間的圖標:

安裝它做什么用?

它的好處,是讓你可以直接把看到的 Github 源代碼,一鍵挪到 Google Colab 深度學習環(huán)境中來使用。

回到本范例的github repo 主頁面,打開其中的 demo.ipynb 文件。

然后,點擊剛剛安裝的  Colaboratory 擴展圖標。Google Chrome 會自動幫你開啟 Google Colab,并且裝載這個 ipynb 文件。

點擊菜單欄里面的“代碼執(zhí)行程序”,選擇“更改運行時類型”。

在出現(xiàn)的對話框中,確認選項如下圖所示。

點擊“保存”即可。

下面,你就可以依次執(zhí)行每一個代碼段落了。

注意第一次執(zhí)行的時候,可能會有警告提示。

出現(xiàn)上面這個警告的時候,點擊“仍然運行”就可以繼續(xù)了。

如果再次出現(xiàn)警告提示,反勾選“在運行前充值所有代碼執(zhí)行程序”選項,再次點擊“仍然運行”即可。

環(huán)境準備好了,下面我們來一步步運行代碼。

預處理

首先,我們準備好 Pandas ,用來讀取數(shù)據(jù)。

import pandas as pd

我們從前文介紹的github repo里面,下載代碼和數(shù)據(jù)。

!git clone https://github.com/wshuyi/demo-chinese-text-classification-lstm-keras.git

下面,我們調(diào)用 pathlib 模塊,以便使用路徑信息。

from pathlib import Path

我們定義自己要使用的代碼和數(shù)據(jù)文件夾。

mypath = Path('demo-chinese-text-classification-lstm-keras')

下面,從這個文件夾里,把數(shù)據(jù)文件打開。

df = pd.read_csv(mypath/'dianping.csv')

看看頭幾行數(shù)據(jù):

df.head()

讀取正確,下面我們來進行分詞。

我們先把結巴分詞安裝上。

!pip install jieba

安裝好之后,導入分詞模塊。

import jieba

對每一條評論,都進行切分:

df['text'] = df.comment.apply(lambda x: ' '.join(jieba.cut(x)))

因為一共只有2000條數(shù)據(jù),所以應該很快完成。

Building prefix dict from the default dictionary ...
Dumping model to file cache /tmp/jieba.cache
Loading model cost 1.089 seconds.
Prefix dict has been built succesfully.

再看看此時的前幾行數(shù)據(jù)。

df.head()

如圖所示,text 一欄下面,就是對應的分詞之后的評論。

我們舍棄掉原始評論文本,只保留目前的分詞結果,以及對應的情感標記。

df = df[['text''sentiment']]

看看前幾行:

df.head()

好了,下面我們讀入一些 Keras 和 Numpy 模塊,為后面的預處理做準備:

from keras.preprocessing.text import Tokenizer
from keras.preprocessing.sequence import pad_sequences
import numpy as np

系統(tǒng)提示我們,使用的后端框架,是 Tensorflow 。

Using TensorFlow backend.

下面我們要設置一下,每一條評論,保留多少個單詞。當然,這里實際上是指包括標點符號在內(nèi)的“記號”(token)數(shù)量。我們決定保留 100 個。

然后我們指定,全局字典里面,一共保留多少個單詞。我們設置為 10000 個。

maxlen = 100
max_words = 10000

下面的幾條語句,會自動幫助我們,把分詞之后的評論信息,轉換成為一系列的數(shù)字組成的序列。

tokenizer = Tokenizer(num_words=max_words)
tokenizer.fit_on_texts(df.text)
sequences = tokenizer.texts_to_sequences(df.text)

看看轉換后的數(shù)據(jù)類型。

type(sequences)

顯示為:

list

可見, sequences 是列表類型。

我們看看第一條數(shù)據(jù)是什么。

sequences[:1]

評論語句中的每一個記號,都被轉換成為了一個大字典中對應的序號。字典的長度我們前面已經(jīng)規(guī)定了,最多10000條。

但是這里有個問題——評論句子有長有短,其中包含的記號個數(shù)不同啊。

我們探索一下,只看最前面5句話,包含多少個記號(token)。

for sequence in sequences[:5]:
  print(len(sequence))
150
12
16
57
253

果然,不僅長短不一,而且有的還超出我們想要的句子長度。

沒關系,用 pad_sequences 方法裁長補短,我們讓它統(tǒng)一化:

data = pad_sequences(sequences, maxlen=maxlen)

再看看這次的數(shù)據(jù):

data
array([[   2,    1,   74...4471,  864,    4],
       [   0,    0,    0...,    9,   52,    6],
       [   0,    0,    0...,    13154,    6],
       ...,
       [   0,    0,    0...2840,    12240],
       [   0,    0,    0...,   19,   44,  196],
       [   0,    0,    0...,  533,   42,    6]], dtype=int32)

那些長句子,被剪裁了;短句子,被從頭補充了若干個 0 。整齊規(guī)范。

我們還希望知道,這些序號分別代表什么單詞,所以我們把這個字典保存下來。

word_index = tokenizer.word_index

看看索引的類型。

type(word_index)
dict

類型驗證通過。看看內(nèi)容:

print(word_index)

沒問題了。

中文評論數(shù)據(jù),已經(jīng)被我們處理成一系列長度為 100 ,其中都是序號的序列了。下面我們要把對應的情感標記,存儲到標記序列 labels 中。

labels = np.array(df.sentiment)

看一下其內(nèi)容:

labels
array([010, ..., 011])

全部數(shù)據(jù)都已經(jīng)備妥了。下面我們來劃分一下訓練集和驗證集。

我們采用的,是把序號隨機化,但保持數(shù)據(jù)和標記之間的一致性。

indices = np.arange(data.shape[0])
np.random.shuffle(indices)
data = data[indices]
labels = labels[indices]

看看此時的標記:

labels
array([011, ..., 011])

注意順序已經(jīng)發(fā)生了改變。

我們希望,訓練集占 80% ,驗證集占 20%。根據(jù)總數(shù),計算一下兩者的實際個數(shù):

training_samples = int(len(indices) * .8)
validation_samples = len(indices) - training_samples

其中訓練集包含多少數(shù)據(jù)?

training_samples
1600

驗證集呢?

validation_samples
400

下面,我們正式劃分數(shù)據(jù)。

X_train = data[:training_samples]
y_train = labels[:training_samples]
X_valid = data[training_samples: training_samples + validation_samples]
y_valid = labels[training_samples: training_samples + validation_samples]

看看訓練集的輸入數(shù)據(jù):

X_train
array([[   0,    0,    0...,  963,    4,  322],
       [   0,    0,    0...1485,   79,   22],
       [   1,   26,  305...,  289,    3,   71],
       ...,
       [   0,    0,    0...,  365,  810,    3],
       [   0,    0,    0...,    1,  1621727],
       [ 141,    5,  237...,  450,  254,    4]], dtype=int32)

至此,預處理部分就算完成了。

詞嵌入

下面,我們安裝 gensim 軟件包,以便使用 Facebook 提供的 fasttext 詞嵌入預訓練模型。

!pip install gensim

安裝后,我們讀入加載工具:

from gensim.models import KeyedVectors

然后我們需要把 github repo 中下載來的詞嵌入預訓練模型壓縮數(shù)據(jù)解壓。

myzip = mypath / 'zh.zip'

! 開頭的語句,代表 bash 命令。其中如果需要使用 Python 變量,前面需要加 $ 。

!unzip $myzip
Archive:  demo-chinese-text-classification-lstm-keras/zh.zip
  inflating: zh.vec

解壓完畢。

下面我們讀入詞嵌入預訓練模型數(shù)據(jù)。

zh_model = KeyedVectors.load_word2vec_format('zh.vec')

看看其中的第一個向量是什么:

zh_model.vectors[0]

這么長的向量,對應的記號是什么呢?

看看前五個詞匯:

list(iter(zh_model.vocab))[:5]
['的', '', '在', '是', '年']

原來,剛才這個向量,對應的是標記“的”。

向量的維度是多少?也就是,一個向量中,包含多少個數(shù)字?

len(zh_model[next(iter(zh_model.vocab))])
300

看來, fasttext 用 300 個數(shù)字組成一個向量,代表一個記號(token)。

我們把這個向量長度,進行保存。

embedding_dim = len(zh_model[next(iter(zh_model.vocab))])

然后,以我們規(guī)定的字典最大長度,以及每個標記對應向量長度,建立一個隨機矩陣。

embedding_matrix = np.random.rand(max_words, embedding_dim)

看看它的內(nèi)容:

embedding_matrix

這個隨機矩陣建立的時候,因為使用了 Numpy 的 random.rand 函數(shù),默認都是從0到1的實數(shù)。

然而,我們剛才已經(jīng)看過了“的”的向量表示,

請注意,其中的數(shù)字,在 -1 到 1 的范圍中間。為了讓我們隨機產(chǎn)生的向量,跟它類似,我們把矩陣進行一下數(shù)學轉換:

embedding_matrix = (embedding_matrix - 0.5) * 2
embedding_matrix

這樣看起來,隨機產(chǎn)生的數(shù)據(jù),就和真正的預訓練結果更相似了。

為什么做這一步呢?一會兒你就知道了。

我們嘗試,對某個特定標記,讀取預訓練的向量結果:

zh_model.get_vector('的')

但是注意,如果你指定的標記,出現(xiàn)在自己任務文本里,卻在預訓練過程中沒有出現(xiàn),會如何呢?

試試輸入我的名字:

zh_model.get_vector('王樹義')

不好意思,因為我的名字,在 fasttext 做預訓練的時候沒有,所以獲取詞嵌入向量,會報錯。

因此,在我們構建適合自己任務的詞嵌入層的時候,也需要注意那些沒有被訓練過的詞匯。

這里我們判斷一下,如果無法獲得對應的詞向量,我們就干脆跳過,使用默認的隨機向量。

for word, i in word_index.items():
    if i <>
        try:
          embedding_vector = zh_model.get_vector(word)
          embedding_matrix[i] = embedding_vector
        except:
          pass

這也是為什么,我們前面盡量把二者的分布調(diào)整成一致。這樣咱們對于沒見過的詞匯,也可以做成個以假亂真的分布,一起參加后面的模型訓練過程。

看看我們產(chǎn)生的“混合”詞嵌入矩陣:

embedding_matrix

模型

詞嵌入矩陣準備好了,下面我們就要搭建模型了。

from keras.models import Sequential
from keras.layers import Embedding, Flatten, Dense, LSTM

units = 32

model = Sequential()
model.add(Embedding(max_words, embedding_dim))
model.add(LSTM(units))
model.add(Dense(1, activation='sigmoid'))
model.summary()

注意這里的模型,是最簡單的順序模型,對應的模型圖如下:

如圖所示,我們輸入數(shù)據(jù)通過詞嵌入層,從序號轉化成為向量,然后經(jīng)過 LSTM (RNN 的一個變種)層,依次處理,最后產(chǎn)生一個32位的輸出,代表這句評論的特征。

這個特征,通過一個普通神經(jīng)網(wǎng)絡層,然后采用 Sigmoid 函數(shù),輸出為一個0到1中間的數(shù)值。

Sigmoid 函數(shù),大概長成這個樣子:

這樣,我們就可以通過數(shù)值與 0 和 1 中哪個更加接近,進行分類判斷。

但是這里注意,此處搭建的神經(jīng)網(wǎng)絡里,Embedding 只是一個隨機初始化的層次。我們需要把剛剛構建的詞嵌入矩陣導入。

model.layers[0].set_weights([embedding_matrix])
model.layers[0].trainable = False

我們希望保留好不容易獲得的單詞預訓練結果,所以在后面的訓練中,我們不希望對這一層進行訓練,因而,trainable 參數(shù)設定為 False

因為是二元分類,因此我們設定了損失函數(shù)為 binary_crossentropy

我們訓練模型,保存輸出為 history ,并且把最終的模型結構和參數(shù)存儲為 mymodel.h5

好了,開始訓練吧:

model.compile(optimizer='rmsprop',
              loss='binary_crossentropy',
              metrics=['acc'])
history = model.fit(X_train, y_train,
                    epochs=10,
                    batch_size=32,
                    validation_data=(X_valid, y_valid))
model.save('mymodel.h5')

機器認認真真,替我們跑了10個來回。

因為有 TPU 的幫助,所以這個過程,應該很快就能完成。

討論

對于這個模型的分類效果,你滿意嗎?

如果單看最終的結果,訓練集準確率超過 90%, 驗證集準確率也超過 80%,好像還不錯嘛。

但是,我看到這樣的數(shù)據(jù)時,會有些擔心。

我們把這些訓練中獲得的結果數(shù)值,用可視化的方法,顯示一下:

import matplotlib.pyplot as plt

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

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

plt.plot(epochs, acc, 'bo', label='Training acc')
plt.plot(epochs, val_acc, 'b', label='Validation acc')
plt.title('Training and validation accuracy')
plt.legend()

plt.figure()

plt.plot(epochs, loss, 'bo', label='Training loss')
plt.plot(epochs, val_loss, 'b', label='Validation loss')
plt.title('Training and validation loss')
plt.legend()

plt.show()

上圖是準確率曲線。虛線是訓練集,實線是驗證集。我們看到,訓練集準確率一路走高,但是驗證集準確率在波動——即便最后一步剛好是最高點。

看下面的圖,會更加清晰。

上圖是損失數(shù)值對比。我們可以看到,訓練集上,損失數(shù)值一路向下,但是,從第2個 epoch 開始,驗證集的損失數(shù)值,就沒有保持連貫的顯著下降趨勢。二者發(fā)生背離。

這意味著什么?

這就是深度學習中,最常見,也是最惱人的問題——過擬合(overfitting)。

如何用機器學習處理二元分類任務?》一文中,我曾經(jīng)就這個問題,為你做過詳細的介紹。這里不贅述了。

但是,我希望你能夠理解它出現(xiàn)的原因——相對于你目前使用的循環(huán)神經(jīng)網(wǎng)絡結構,你的數(shù)據(jù)量太小了。

深度學習,可以讓你端到端操作,不需要手動繁復去做特征工程。但是,它對于數(shù)據(jù)數(shù)量和質(zhì)量的需求,都很高。

有沒有辦法,可以讓你不需要這么多的數(shù)據(jù),也能避免過擬合,取得更好的訓練結果呢?

這個問題的答案,我在《如何用 Python 和深度遷移學習做文本分類?》一文中已經(jīng)為你介紹過,如果你忘記了,請復習一下吧。

小結

本文,我們探討了如何用 Python 和循環(huán)神經(jīng)網(wǎng)絡處理中文文本分類問題。讀過本文并且實踐之后,你應該已經(jīng)能夠把下列內(nèi)容融會貫通了:

  • 文本預處理

  • 詞嵌入矩陣構建

  • 循環(huán)神經(jīng)網(wǎng)絡模型搭建

  • 訓練效果評估

希望這份教程,可以在你的科研和工作中,幫上一些忙。

祝(深度)學習愉快!

    本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內(nèi)容,請點擊一鍵舉報。
    轉藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    好吊色免费在线观看视频| 性欧美唯美尤物另类视频 | 九七人妻一区二区三区| 欧美黄色成人真人视频| 国产午夜福利在线观看精品| 欧美日韩精品视频在线| 国产又长又粗又爽免费视频| 亚洲一区二区三区日韩91| 久久精品伊人一区二区| 国产欧美韩日一区二区三区| 欧美日韩国产另类一区二区| 日韩国产亚洲一区二区三区| 国产在线不卡中文字幕| 国产高清精品福利私拍| 丝袜美女诱惑在线观看| 日韩一区中文免费视频| 在线视频免费看你懂的| 在线日本不卡一区二区| 日韩人妻欧美一区二区久久| 久久夜色精品国产高清不卡| 国产女性精品一区二区三区| 日本亚洲精品在线观看| 欧美三级大黄片免费看| 日韩成人中文字幕在线一区| 好吊日成人免费视频公开| 国产免费成人激情视频| 国产又色又爽又黄又免费| 国产亚洲系列91精品| 暴力三级a特黄在线观看| 日韩精品视频免费观看| 欧美不卡一区二区在线视频| 亚洲国产成人爱av在线播放下载| 国产乱淫av一区二区三区| 国产美女精品午夜福利视频| 黑鬼糟蹋少妇资源在线观看| 亚洲精品国男人在线视频| 日韩一区二区三区在线日| 我要看日本黄色小视频| 亚洲视频一区自拍偷拍另类| 欧美精品一区二区水蜜桃| 大香伊蕉欧美一区二区三区|