一、前言
參考:https://zhuanlan.zhihu.com/p/73176084
代碼:https://link.zhihu.com/?target=https%3A//github.com/649453932/Chinese-Text-Classification-Pytorch
代碼:https://link.zhihu.com/?target=https%3A//github.com/649453932/Bert-Chinese-Text-Classification-Pytorch
使用pytorch實現了TextCNN,TextRNN,FastText,TextRCNN,BiLSTM_Attention,DPCNN,Transformer。github:Chinese-Text-Classification-Pytorch,開箱即用。
二、中文數據集:
我從THUCNews中抽取了20萬條新聞標題,文本長度在20到30之間。一共10個類別,每類2萬條。
以字為單位輸入模型,使用了預訓練詞向量:搜狗新聞 Word+Character 300d。
類別:財經、房產、股票、教育、科技、社會、時政、體育、游戲、娛樂。
數據集、詞表及對應的預訓練詞向量已上傳至github,開箱即用。
模型效果:
bert,ERNIE代碼:Bert-Chinese-Text-Classification-Pytorch
1.TextCNN
TextCNN整體結構
數據處理:所有句子padding成一個長度:seq_len
1.模型輸入:
[batch_size, seq_len]
2.經過embedding層:加載預訓練詞向量或者隨機初始化, 詞向量維度為embed_size:
[batch_size, seq_len, embed_size]
3.卷積層:NLP中卷積核寬度與embed-size相同,相當於一維卷積。
3個尺寸的卷積核:(2, 3, 4),每個尺寸的卷積核有100個。卷積后得到三個特征圖:[batch_size, 100, seq_len-1]
[batch_size, 100, seq_len-2]
[batch_size, 100, seq_len-3]
4.池化層:對三個特征圖做最大池化
[batch_size, 100]
[batch_size, 100]
[batch_size, 100]
5.拼接:
[batch_size, 300]
6.全連接:num_class是預測的類別數
[batch_size, num_class]
7.預測:softmax歸一化,將num_class個數中最大的數對應的類作為最終預測
[batch_size, 1]
分析:
卷積操作相當於提取了句中的2-gram,3-gram,4-gram信息,多個卷積是為了提取多種特征,最大池化將提取到最重要的信息保留。
2.TextRNN
圖片是單向RNN,看個意思就行
1.模型輸入: [batch_size, seq_len]
2.經過embedding層:加載預訓練詞向量或者隨機初始化, 詞向量維度為embed_size: [batch_size, seq_len, embed_size]
3.雙向LSTM:隱層大小為hidden_size,得到所有時刻的隱層狀態(前向隱層和后向隱層拼接)
[batch_size, seq_len, hidden_size * 2]
4.拿出最后時刻的隱層值:
[batch_size, hidden_size * 2]
5.全連接:num_class是預測的類別數
[batch_size, num_class]
6.預測:softmax歸一化,將num_class個數中最大的數對應的類作為最終預測
[batch_size, 1]
分析:
LSTM能更好的捕捉長距離語義關系,但是由於其遞歸結構,不能並行計算,速度慢。
3.TextRNN+Attention
BiLSTM+Attention
1.模型輸入: [batch_size, seq_len]
2.經過embedding層:加載預訓練詞向量或者隨機初始化, 詞向量維度為embed_size: [batch_size, seq_len, embed_size]
3.雙向LSTM:隱層大小為hidden_size,得到所有時刻的隱層狀態(前向隱層和后向隱層拼接) [batch_size, seq_len, hidden_size * 2]
4.初始化一個可學習的權重矩陣w
w=[hidden_size * 2, 1]
5.對LSTM的輸出進行非線性激活后與w進行矩陣相乘,並經行softmax歸一化,得到每時刻的分值:
[batch_size, seq_len, 1]
6.將LSTM的每一時刻的隱層狀態乘對應的分值后求和,得到加權平均后的終極隱層值
[batch_size, hidden_size * 2]
7.對終極隱層值進行非線性激活后送入兩個連續的全連接層
[batch_size, num_class]
8.預測:softmax歸一化,將num_class個數中最大的數對應的類作為最終預測
[batch_size, 1]
分析:
其中4~6步是attention機制計算過程,其實就是對lstm每刻的隱層進行加權平均。比如句長為4,首先算出4個時刻的歸一化分值:[0.1, 0.3, 0.4, 0.2],然后
4.TextRCNN
left context是前向RNN的隱層值,right context是后向RNN的隱層值。
1.模型輸入: [batch_size, seq_len]
2.經過embedding層:加載預訓練詞向量或者隨機初始化, 詞向量維度為embed_size: [batch_size, seq_len, embed_size]
3.雙向LSTM:隱層大小為hidden_size,得到所有時刻的隱層狀態(前向隱層和后向隱層拼接) [batch_size, seq_len, hidden_size * 2]
4.將embedding層與LSTM輸出拼接,並進行非線性激活:
[batch_size, seq_len, hidden_size * 2 + embed_size]
5.池化層:seq_len個特征中取最大的
[batch_size, hidden_size * 2 + embed_size]
6.全連接后softmax
[batch_size, num_class] ==> [batch_size, 1]
分析:
雙向LSTM每一時刻的隱層值(前向+后向)都可以表示當前詞的前向和后向語義信息,將隱藏值與embedding值拼接來表示一個詞;然后用最大池化層來篩選出有用的特征信息。emm...就做了一個池化,就能稱之為RCNN...
需要注意的是,我的實現和論文中略有不同,論文中其實用的不是我們平時見的RNN,其實從圖中能看出來,看公式的區別:
傳統RNN:
論文中:
符號看不懂不要緊,我給轉換一下:
5.FastText
簡單粗暴的FastText
0.用哈希算法將2-gram、3-gram信息分別映射到兩張表內。
1.模型輸入: [batch_size, seq_len]
2.embedding層:隨機初始化, 詞向量維度為embed_size,2-gram和3-gram同理:
word: [batch_size, seq_len, embed_size]
2-gram:[batch_size, seq_len, embed_size]
3-gram:[batch_size, seq_len, embed_size]
3.拼接embedding層:
[batch_size, seq_len, embed_size * 3]
4.求所有seq_len個詞的均值
[batch_size, embed_size * 3]
5.全連接+非線性激活:隱層大小hidden_size
[batch_size, hidden_size]
6.全連接+softmax歸一化:
[batch_size, num_class]==>[batch_size, 1]
分析:
不加N-Gram信息,就是詞袋模型,准確率89.59%,加上2-gram和3-gram后准確率92.23%。N-Gram的哈希映射算法見utils_fasttext.py中注釋------gram-------處。
N-Gram的詞表我設的25W,相對於前面幾個模型,這個模型稍慢一點,FastText被我搞成SlowText了。。?但是效果不錯呀。。哈哈
有人私信問我這個N-Gram,我大體講一下。對於N-Gram,我們設定一個詞表,詞表大小自己定,當然越大效果越好,但是你得結合實際情況,對於2-Gram,5000個字(字表大小)的兩兩組合有多少種你算算,3-Gram的組合有多少種,組合太多了,詞表設大效果是好了,但是機器它受不了啊。
所以N-Gram詞表大小的設定是要適中的,那么適中的詞表就放不下所有N-Gram了,不同的N-Gram用哈希算法可能會映射到詞表同一位置,這確實是個弊端,但是問題不大:5000個字不可能每兩個字都兩兩組合出現,很多兩個字是永遠不會組成2-Gram的,所以真正出現的N-Gram不會特別多,映射到同一詞表位置的N-Gram也就不多了。
N-Gram詞表大小我定的25w,比較大了,比小詞表訓練慢了很多,效果也提升了。這么形容N-Gram詞表大小對效果的影響吧:一分價錢1分貨,十分價錢1.1分貨。
6.DPCNN
1.模型輸入: [batch_size, seq_len]
2.經過embedding層:加載預訓練詞向量或者隨機初始化, 詞向量維度為embed_size: [batch_size, seq_len, embed_size]
3.進行卷積,250個尺寸為3的卷積核,論文中稱這層為region embedding。
[batch_size, 250, seq_len - 3 + 1]
4.接兩層卷積(+relu),每層都是250個尺寸為3的卷積核,(等長卷積,先padding再卷積,保證卷積前后的序列長度不變)
[batch_size, 250, seq_len - 3 + 1]
5.接下來進行上圖中小框中的操作。
I. 進行 大小為3,步長為2的最大池化,將序列長度壓縮為原來的二分之一。(進行采樣)
II. 接兩層等長卷積(+relu),每層都是250個尺寸為3的卷積核。
III. I的結果加上II的結果。(殘差連接)
重復以上操作,直至序列長度等於1。
[batch_size, 250, 1]
6.全連接+softmax歸一化:
[batch_size, num_class]==>[batch_size, 1]
分析:
TextCNN的過程類似於提取N-Gram信息,而且只有一層,難以捕捉長距離特征。
反觀DPCNN,可以看出來它的region embedding就是一個去掉池化層的TextCNN,再將卷積層疊加。
每層序列長度都減半(如上圖所示),可以這么理解:相當於在N-Gram上再做N-Gram。越往后的層,每個位置融合的信息越多,最后一層提取的就是整個序列的語義信息。
7.Transformer
代碼已上傳
# TODO:圖文
總結
再貼一遍github地址:Chinese-Text-Classification-Pytorch,覺得有用別忘了回來點贊。如果代碼中有問題或者有什么建議,歡迎提出。之后會更新中文的長文本數據集和英文數據集,敬請期待,這個倉庫我會一直更新維護,歡迎關注!
Reference:
[1] Convolutional Neural Networks for Sentence Classification
[2] A Sensitivity Analysis of Convolutional Neural Networks for Sentence Classification
[3] Recurrent Neural Network for Text Classification with Multi-Task Learning
[4] Attention-Based Bidirectional Long Short-Term Memory Networks for Relation Classification
[5] Recurrent Convolutional Neural Networks for Text Classification
[6] Bag of Tricks for Efficient Text Classification
[7] Deep Pyramid Convolutional Neural Networks for Text Categorization
[8] Attention Is All You Need