1 卷積運算
在泛函分析中,卷積是通過兩個函數 f 和 g 生成第三個函數的數學運算,表徵函數 f 和經過翻轉,平移的 g 的乘積函數圍成的曲邊梯形的面積。
連續函數卷積: 設 f(x),g(x) 是 R 上兩個可積函數,作積分:
離散序列卷積: 設 f(m),g(n) 是長度爲 N 的兩個離散信號,它們的積分是
卷積運算的應用相當廣泛,比如多項式的乘法(包括整數的乘法), 其實就是在進行對兩個離散序列進行卷 積運算。在圖像處理中,用作圖像的邊緣檢測,圖像模糊,銳化等等。在統計學中,加權的平滑是一種卷積。 在概率論中,兩個統計獨立的變量 X,Y 的概率密度函數是 XY 概率密度函數的卷積。在信號處理的過程中, 任何一個系統的輸出都可以看成是輸入信號和系統衝擊響應的卷積。
2 卷積運算動機
卷積運算的三個重要思想:
- 稀疏權重:卷積網絡通過使核的大小遠小於輸入的大小來達到稀疏連接的目的。
- 參數共享:在一個模型的多個函數中使用相同的參數。
- 等變表示:輸入改變,輸出也以同樣的方式改變。
3 池化運算
池化運算也叫亞採樣或者下采樣。池化運算用一個矩陣區域內部的某個總體統計量來作爲神經網絡在該矩陣區域的輸出,它綜合了該矩陣區域的信息。
- 最大池化:定義一個窗口,並從窗口內取出最大值作爲總體統計量。
- 均值池化:定義一個窗口,並從窗口內取出平均值作爲總體統計量。
- 其他常見的還有: 範數以及基於中心像素距離的加權平均函數作爲總體統計量。
4 池化動機
- 平移近似不變性:
- 當輸入做出了少量的平移時,最大池化能夠獲得輸出的近似不變性。
- 局部平移不變性是個很重要的性質。該性質表明:網絡只關心某個特徵是否出現,而不關心它出現的具體位置。
- 模擬其它不變性
- 最大池化只能對空間的平移具有不變性,而無法對空間的旋轉具有不變性
- 最大池化的空間平移不變性是原生的,其他變換的不變性則必須採用這種多通道的方法來實現。
5 Text-CNN原理
Text-CNN模型結構
TextCNN詳細過程:
- Embedding:第一層是圖中最左邊的7乘5的句子矩陣,每行是詞向量,維度=5,這個可以類比爲圖像中的原始像素點。
- Convolution:然後經過 kernel_sizes=(2,3,4) 的一維卷積層,每個kernel_size 有兩個輸出 channel。
- MaxPolling:第三層是一個1-max pooling層,這樣不同長度句子經過pooling層之後都能變成定長的表示。
- Full connection and Softmax:最後接一層全連接的 softmax 層,輸出每個類別的概率。
通道(Channels):
- 圖像中可以利用 (R, G, B) 作爲不同channel;
- 文本的輸入的channel通常是不同方式的embedding方式(比如 word2vec或Glove),實踐中也有利用靜態詞向量和fine-tunning詞向量作爲不同channel的做法。
一維卷積(conv-1d):
- 圖像是二維數據;
- 文本是一維數據,因此在TextCNN卷積用的是一維卷積(在word-level上是一維卷積;雖然文本經過詞向量表達後是二維數據,但是在embedding-level上的二維卷積沒有意義)。一維卷積帶來的問題是需要通過設計不同 kernel_size 的 filter 獲取不同寬度的視野。
6 Text-CNN模型來進行文本分類
import jieba
from gensim.models.word2vec import Word2Vec
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn import metrics
import jieba
import keras
from keras import optimizers
from keras.preprocessing.text import Tokenizer
from keras.preprocessing.sequence import pad_sequences
from keras.layers import *
from keras.models import Model
text = ['我喜歡吃蘋果',
'我愛吃香蕉',
'他不想吃桃子',
'我想去上海玩',
'她遊玩的地點在重慶',
'他正在北京玩']
category = [1,1,1,2,2,2]
corpus = []
for t in text:
corpus.append(list(jieba.cut(t)))
print(corpus)
tokenizer=Tokenizer()
tokenizer.fit_on_texts(corpus)
vocab = tokenizer.word_index
x_train, x_test, y_train, y_test = train_test_split(corpus, category, test_size=0.25)
# 將每個樣本中的每個詞轉換爲數字列表,使用每個詞的編號進行編號
x_train_word_ids=tokenizer.texts_to_sequences(x_train)
x_test_word_ids = tokenizer.texts_to_sequences(x_test)
#序列模式
# 每條樣本長度不唯一,將每條樣本的長度設置一個固定值
x_train_padded_seqs=pad_sequences(x_train_word_ids,maxlen=10) #將超過固定值的部分截掉,不足的在最前面用0填充
x_test_padded_seqs=pad_sequences(x_test_word_ids, maxlen=10)
#訓練詞向量
word2vec_model = Word2Vec(sentences=corpus,min_count=1,iter=5)
embedding_matrix = np.zeros((len(vocab) + 1, 100))
for word, i in vocab.items():
try:
embedding_vector = word2vec_model[str(word)]
embedding_matrix[i] = embedding_vector
except KeyError:
continue
#構建TextCNN模型
def TextCNN(x_train_padded_seqs,y_train,x_test_padded_seqs,y_test,embedding_matrix):
# 模型結構:詞嵌入-卷積池化*3-拼接-全連接-dropout-全連接
main_input = Input(shape=(10,), dtype='float64')
# 詞嵌入(使用預訓練的詞向量)
embedder = Embedding(len(vocab) + 1, 100, input_length=10, weights=[embedding_matrix], trainable=False)
#embedder = Embedding(len(vocab) + 1, 300, input_length=50, trainable=False)
embed = embedder(main_input)
# 詞窗大小分別爲3,4,5
cnn1 = Conv1D(128, 1, padding='same', strides=1, activation='relu')(embed)
cnn1 = MaxPooling1D(pool_size=5)(cnn1)
cnn2 = Conv1D(128, 2, padding='same', strides=1, activation='relu')(embed)
cnn2 = MaxPooling1D(pool_size=4)(cnn2)
# 合併模型的輸出向量
cnn = concatenate([cnn1, cnn2], axis=-1)
flat = Flatten()(cnn)
drop = Dropout(0.5)(flat)
main_output = Dense(3, activation='softmax')(drop)
model = Model(inputs=main_input, outputs=main_output)
model.compile(loss='categorical_crossentropy', optimizer='sgd', metrics=['accuracy'])
one_hot_labels = keras.utils.to_categorical(y_train, num_classes=3) # 將標籤轉換爲one-hot編碼
model.fit(x_train_padded_seqs, one_hot_labels, batch_size=10, epochs=10)
#y_test_onehot = keras.utils.to_categorical(y_test, num_classes=3) # 將標籤轉換爲one-hot編碼
result = model.predict(x_test_padded_seqs) # 預測樣本屬於每個類別的概率
result_labels = np.argmax(result, axis=1) # 獲得最大概率對應的標籤
y_predict = list(map(int, result_labels))
print('準確率', metrics.accuracy_score(y_test, y_predict))
print('平均f1-score:', metrics.f1_score(y_test, y_predict, average='weighted'))
推薦文章: