TextCNN 是利用卷積神經網絡對文本進行分類的算法,由 Yoon Kim 在 “Convolutional Neural Networks for Sentence Classification” 一文 (見參考[1]) 中提出. 是 2014 年的算法.
圖 1-1 參考[1] 中的論文配圖
在這裡插入圖片描述
以下是閱讀 TextCNN 後的理解
步驟:
1.先對句子進行分詞,一般使用“jieba”庫進行分詞。
2.在原文中,用了 6 個卷積核對原詞向量矩陣進行卷積。
卷積具有局部特征提取的功能, 所以可用 CNN 來提取句子中類似 n-gram 的關鍵信息.
個卷積核大小:2 個 46、2 個 36 和 2 個 2*6,如上圖所示;然後進行池化,對相同卷積核產生的特征圖進行連接;再進行 softmax 輸出 2 個類別。
1).這裡對 no-static 進行闡述,采用不固定的詞向量,這樣更加貼近自然生活中,不同長度的句子代表的意思不同,所以在我看來采用 no-static 比 static 更加的貼近語義。
2).對一個詞向量進行卷積和池化後,產生的特征只有一個 1*1 的向量,所以說不管采用 static 和 no-static 得到的特征都只有一個,對本生網絡沒什麼影響。
為什麼采用不同大小的卷積核,不同的感受視野,卷積核的寬取詞匯表的緯度,有利於語義的提取。
體現在代碼中
tf.flags.DEFINE_string("filter_sizes", "3,4,5", "Comma-separated filter sizes (default: '3,4,5')")
filter_sizes=list(map(int, FLAGS.filter_sizes.split(","))),
是一個 list
5.研究證明為什麼要采用字,而不采用字,原因是詞粒度准確率 > 字粒度准確率。存在兩種模型,一種是詞袋模型,第二種是詞向量模型。下面對詞向量模型來進行講述。
詞向量模型:
一般開始為高緯度,高稀疏向量,利用嵌入層對其進行降維,增加稠密性。
使用詞向量進行文本分類的步驟為:
①.先使用分詞工具提取詞匯表。
②.將要分類的內容轉換為詞向量。
a.分詞
b.將每個詞轉換為 word2vec 向量。
c.按順序組合 word2vec,那麼久組合成了一個詞向量。
d.降維,由原來的高緯度降維為我們設定的低緯度。
e.卷積、池化和連接,然後進行分類。
6.嵌入層
通過一個隱藏層將 word2vec 高緯度的詞向量轉換到低緯度空間的詞向量,這個層的本質是特征提取,提取高緯度詞向量的特征到低緯度,這樣可以使語義相近的詞映射到低維空間以後,歐式距離更近。
參數與超參數
sequence_length
Q: 對於 CNN, 輸入與輸出都是固定的,可每個句子長短不一, 怎麼處理?
A: 需要做定長處理, 比如定為 n, 超過的截斷, 不足的補 0. 注意補充的 0 對後面的結果沒有影響,因為後面的 max-pooling 只會輸出最大值,補零的項會被過濾掉.
num_classes
多分類, 分為幾類.
vocabulary_size
語料庫的詞典大小, 記為 |D|.
embedding_size
將詞向量的維度, 由原始的 |D| 降維到 embedding_size.
filter_size_arr
多個不同 size 的 filter.
Embedding Layer
首先用 VocabularyProcessor 將 每一句話 轉為 詞 id 向量
然後定義了詞嵌入矩陣,將輸入的詞 id 轉化成詞向量,這裡的詞嵌入矩陣是可以訓練的,我們希望得到的是訓練完以後,輸入經過 W 矩陣轉換得到的固定維度的隱藏層,及詞向量矩陣通過一個詞嵌入矩陣, 將 編碼的詞投影到一個低維空間中.
本質上是特征提取器,在指定維度中編碼語義特征. 這樣, 語義相近的詞, 它們的歐氏距離或余弦距離也比較近.
self.embedded_chars=tf.nn.embedding_lookup(W,self.input_x)
如果先用 word2vec_helpers 處理完,然後代用 textCNN 的情況下,這裡的 embeding 層是不是就不要了?
原始的在沒有預先使用 word2vec 的情況下:在網絡層有 embeding 層
而預先使用了 word2vec_helpers 處理完之後,
Convolution Layer
為不同尺寸的 filter 都建立一個卷積層. 所以會有多個 feature map.
圖像是像素點組成的二維數據, 有時還會有 RGB 三個通道, 所以它們的卷積核至少是二維的.
從某種程度上講, word is to text as pixel is to image, 所以這個卷積核的 size 與 stride 會有些不一樣.
xixi
xi∈Rkxi∈Rk, 一個長度為 n 的句子中, 第 i 個詞語的詞向量, 維度為 k.
xi:jxi:j
xi:j=xi⊕xi+1⊕…⊕xjxi:j=xi⊕xi+1⊕…⊕xj
表示在長度為 n 的句子中, 第 [i,j] 個詞語的詞向量的拼接.
hh
卷積核所圍窗口中單詞的個數, 卷積核的尺寸其實就是 hkhk.
ww
w∈Rhkw∈Rhk, 卷積核的權重矩陣.
cici
ci=f(wxi:i+h1+b)ci=f(wxi:i+h1+b), 卷積核在單詞 i 位置上的輸出.b∈RKb∈RK, 是 bias.ff 是雙曲正切之類的激活函數.
c=[c1,c2,…,cnh+1]c=[c1,c2,…,cnh+1]
filter 在句中單詞上進行所有可能的滑動, 得到的 featuremapfeaturemap.
Max-Pooling Layer
max-pooling 只會輸出最大值, 對輸入中的補 0 做過濾.
SoftMax 分類 Layer
最後接一層全連接的 softmax 層,輸出每個類別的概率。
小的變種
在 word representation 處理上會有一些變種.
CNN-rand
設計好 embedding_size 這個 Hyperparameter 後, 對不同單詞的向量作隨機初始化, 後續 BP 的時候作調整.
static
拿 pre-trained vectors from word2vec, FastText or GloVe 直接用, 訓練過程中不再調整詞向量. 這也算是遷移學習的一種思想.
non-static
pre-trained vectors + fine tuning , 即拿 word2vec 訓練好的詞向量初始化, 訓練過程中再對它們微調.
multiple channel
類比於圖像中的 RGB 通道, 這裡也可以用 static 與 non-static 搭兩個通道來搞.
一些結果表明,max-pooling 總是優於 average-pooling ,理想的 filter sizes 是重要的,但具體任務具體考量,而用不用正則化似乎在 NLP 任務中並沒有很大的不同。
Text CNN 的 tf 實現
圖 8-1 Text CNN 網絡中的卷積與池化 結構
需要注意的細節有。
tf.nn.embedding_lookup()
與 LeNet 作比較
figure LeNet-5 網絡結構
# LeNet5
conv1_weights = tf.get_variable(
"weight",
[CONV1_SIZE, CONV1_SIZE, NUM_CHANNELS, CONV1_DEEP],
initializer=tf.truncated_normal_initializer(stddev=0.1))
tf.nn.conv2d(
input_tensor,
conv1_weights,
strides=[1, 1, 1, 1],
padding='SAME')
tf.nn.max_pool(
relu1,
ksize = [1,POOL1_SIZE,POOL1_SIZE,1],
strides=[1,POOL1_SIZE,POOL1_SIZE,1],
padding="SAME")
# TextCNN
conv1_weights = tf.get_variable(
"weight",
[FILTER_SIZE, EMBEDDING_SIZE, 1, NUM_FILTERS],
initializer=tf.truncated_normal_initializer(stddev=0.1))
tf.nn.conv2d(
self.embedded_chars_expanded,
conv1_weights,
strides=[1, 1, 1, 1],
padding="VALID")
tf.nn.max_pool(
h,
ksize=[1, SEQUENCE_LENGTH - FILTER_SIZE + 1, 1, 1],
strides=[1, 1, 1, 1],
padding='VALID')
LeNet 的 filter 是正方形的, 且每一層都只用了同一種尺寸的卷積核. Text-CNN 中, filter 是矩形, 矩形的長度有好幾種, 一般取 (2,3,4), 而矩形的寬度是定長的, 同 word 的 embedding_size 相同. 每種尺寸都配有 NUM_FILTERS 個數目, 類比於 LeNet 中的 output_depth,所以得到的 feature_map 是長條狀, 寬度為 1.
因為是卷積, 所以 stride 每個維度都是 1.
池化處理, 也叫下采樣. 這裡依舊可以對比 LeNet 網絡.
LeNet 的 kernel 是正方形, 一般也是 2*2 等, 所以會把卷積後的 feature_map 尺寸縮小一半.
Text-CNN 的 kernel 依舊是長方形, 將整個 feature_map 映射到一個點上. 一步到位, 只有一個池化層.
都是多分類, 這一步的處理比較類似. 將池化後的矩陣 reshape 為二維, 用 tf.nn.sparse_softmax_cross_entropy_with_logits() 計算損失.
TextCNN 論文中的網絡結構
windows size 分別取 (3,4,5), 每個尺寸都會有 100 個 filter.
Hyperparameters and Training
For all datasets we use:
rectified linear units, filter
windows (h) of 3, 4, 5 with 100 feature maps each,
dropout rate (p) of 0.5, l2 constraint (s) of 3, and
mini-batch size of 50. These values were chosen
via a grid search on the SST-2 dev set.
1