【自然語言處理】文本信息提取器-CNN

本文主要內容

  • 簡略介紹卷積神經網絡(CNN, Convolutional Neural Network)處理文本信息的過程
  • 使用CNN進行文本分類任務,並對代碼進行註釋
  • 本文代碼【https://github.com/540117253/Chinese-Text-Classification 】

一、CNN概述

在這裏插入圖片描述

圖1 CNN文本編碼器

  CNN文本編碼器的結構如圖1所示。在第一層,詞映射函數f:MRdf:M \rightarrow R^{d}將評論的每個單詞映射爲dd維向量,然後將給定的評論文本轉化爲長度固定爲TT的詞嵌入矩陣(只截取評論文本中的前TT個單詞,如果長度不足的文本則進行填充處理)。

  詞映射層後的是卷積層,其包含mm個神經元,每個神經元對應的卷積核KRt×dK \in R^{t \times d}用於對詞向量進行卷積運算提取特徵。假設V1:TV_{1:T}是文本長度爲TT的詞嵌入矩陣,第jj個神經元產生的特徵爲:
zj=ReLU(V1:TKj+bj) z_j=ReLU(V_{1:T}*K_j + b_j)
其中bjb_j爲偏倚項,*表示卷積運算,ReLUReLU是非線性激活函數。

  最終在滑動窗口tt的作用下,第jj個神經元產生的特徵爲z1,z2,...,zjTt+1z_1,z_2,...,z_j^{T-t+1}。將該特徵進行max-pooling運算,其主要用於捕獲擁有最大值的最重要的特徵,其定義爲:
oj=max(z1,z2,...,zjTt+1) o_j = max(z_1,z_2,...,z_j^{T-t+1})
  最後卷積層的最終輸出爲mm個神經元輸出的拼接結果,其定義爲:
O=[o1,o2,....om] O=[o_1,o_2,....o_m]
  通常OO會接着送入全連接層,其中包含權重矩陣WRm×nW \in R ^{m \times n}和偏置項gRng \in R^n,具體公式爲:
X=ReLU(WO+g) X=ReLU(WO+g)
  整體上,CNN的卷積核大小一般爲3或者5(即一次卷積運算僅計算3個單詞或5個單詞的信息),其僅採用一個卷積核就能通過滑動窗口的方式來掃描整個文本,因此整個文本可以看作是共享同一個卷積核的一組參數,能很好地節省內存空間。然而一次卷積運算僅能包含卷積窗口內的單詞,當輸入的文本越長,卷積窗口滑動到文本的尾部時所丟失掉的前文信息就越多。因此對於文本數據,一般採用循環神經網絡RNN,其比CNN的文本信息提取能力更優秀。

二、CNN文本分類實例

2.1 數據集介紹

1. 下載地址:

  【https://github.com/skdjfla/toutiao-text-classfication-dataset 】

2. 格式:

6552431613437805063_!_102_!_news_entertainment_!_謝娜爲李浩菲澄清網絡謠言,之後她的兩個行爲給自己加分_!_佟麗婭,網絡謠言,快樂大本營,李浩菲,謝娜,觀衆們

每行爲一條數據,以_!_分割的個字段,從前往後分別是 新聞ID,分類code(見下文),分類名稱(見下文),新聞字符串(僅含標題),新聞關鍵詞

分類code與名稱:

100 民生 故事 news_story
101 文化 文化 news_culture
102 娛樂 娛樂 news_entertainment
103 體育 體育 news_sports
104 財經 財經 news_finance
106 房產 房產 news_house
107 汽車 汽車 news_car
108 教育 教育 news_edu 
109 科技 科技 news_tech
110 軍事 軍事 news_military
112 旅遊 旅遊 news_travel
113 國際 國際 news_world
114 證券 股票 stock
115 農業 三農 news_agriculture
116 電競 遊戲 news_game

2.2 預訓練詞向量

預訓練詞向量使用的是,基於ACL-2018模型在百度百科訓練的詞向量。

下載地址:【 https://github.com/Embedding/Chinese-Word-Vectors 】

2.3 數據預處理

  1. 清除無用字符,並且進行分詞處理
  2. 建立整個數據集的字典,key=word, value=詞語的編號
  3. 對進行截斷或補0處理,確保每條樣本的長度爲maxlen
  4. 序列化樣本的標籤,例如“體育類新聞”的類別編號爲1,“娛樂類新聞”的類別編號爲2
  5. 將處理好的數據轉化爲DataFrame格式,並保存到硬盤

2.4 CNN模型的定義

'''
    Text => CNN => Fully_Connected => Softmax
    
    參數:
    filter_sizes:卷積核的大小
    num_filters:卷積核的個數
    embedded_size:詞向量的維度
    dict_size:數據集的單詞個數
    maxlen:每條樣本的最大單詞數
    label_num:樣本類別的數量
    learning_rate:梯度優化器的初始學習率
'''
class CNN:
    def __init__(self, filter_sizes, num_filters, embedded_size,
                 dict_size, maxlen, label_num, learning_rate): 

        # print('model_Name:', 'CNN')

        self.droput_rate = 0.5
        
        '''
            Convulutional Neural Network
        '''
        def cnn (input_emb, filter_sizes, num_filters):
            pooled_outputs = []
            for i, filter_size in enumerate(filter_sizes):
                filter_shape = [filter_size, embedded_size, 1, num_filters]
                W = tf.Variable(tf.truncated_normal(filter_shape, stddev=0.1), name="W")
                b = tf.Variable(tf.constant(0.1, shape=[num_filters]), name="b")         
                conv = tf.nn.conv2d(
                    input_emb,
                    W,
                    strides=[1, 1, 1, 1],
                    padding="VALID",
                    name="conv") # shape(conv) = [None, sequence_length - filter_size + 1, 1, num_filters]
                h = tf.nn.relu(tf.nn.bias_add(conv, b), name="relu")
                word_num = input_emb.shape.as_list()[1]
                pooled = tf.nn.max_pool(
                    h,
                    ksize=[1, word_num - filter_size + 1, 1, 1],
                    strides=[1, 1, 1, 1],
                    padding='VALID',
                    name="pool") # shape(pooled) = [None, 1, 1, num_filters]
                pooled_outputs.append(pooled)
            num_filters_total = num_filters * len(filter_sizes)

            h_pool = tf.concat(pooled_outputs,3) 

            h_pool_flat = tf.reshape(h_pool, [-1, num_filters_total])  # shape = [None,num_filters_total] 

            cnn_fea = tf.nn.dropout(h_pool_flat, keep_prob =  self.droput_rate)

            return cnn_fea
        
        self.X = tf.placeholder(tf.int32, [None, maxlen], name='input_x')
        self.Y = tf.placeholder(tf.int64, [None])
        
        self.encoder_embeddings = tf.Variable(tf.random_uniform([dict_size, embedded_size], -1, 1), trainable=False)
        encoder_embedded = tf.nn.embedding_lookup(self.encoder_embeddings, self.X)
        
        # 由於conv2d需要一個四維的輸入數據,因此需要手動添加一個維度。
        encoder_embedded = tf.expand_dims(encoder_embedded, -1) # shape(encoder_embedded) = [None, user_review_num*u_n_words, embedding_size, 1]

        outputs = cnn(input_emb = encoder_embedded, filter_sizes = filter_sizes, num_filters = num_filters)
 
        self.logits = keras.layers.Dense(label_num, use_bias=True)(outputs)
        self.probability = tf.nn.softmax(self.logits, name='probability')

        self.cost = tf.nn.sparse_softmax_cross_entropy_with_logits(
                                                                    labels = self.Y, 
                                                                    logits = self.logits)
        self.cost = tf.reduce_mean(self.cost)
        self.optimizer = tf.train.AdamOptimizer(learning_rate = learning_rate).minimize(self.cost)
        self.pre_y = tf.argmax(self.logits, 1, name='pre_y')
        correct_pred = tf.equal(self.pre_y, self.Y)
        self.accuracy = tf.reduce_mean(tf.cast(correct_pred, tf.float32))

2.5 訓練模型

  1. 將預處理好的數據集切分爲80%的訓練集,10%作爲驗證集,10%作爲測試集
  2. 每使用一次訓練集進行訓練後,就使用驗證集進行測試。
  3. 當驗證集的準確率連續下降5次,就停止步驟2,然後使用測試集的結果作爲模型的最終性能。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章