1 前言
?? 優(yōu)質(zhì)競賽項(xiàng)目系列,今天要分享的是
基于深度學(xué)習(xí)的中文情感分類
該項(xiàng)目較為新穎,適合作為競賽課題方向,學(xué)長非常推薦!
?? 更多資料, 項(xiàng)目分享:文章來源:http://www.zghlxwxcb.cn/news/detail-707099.html
https://gitee.com/dancheng-senior/postgraduate文章來源地址http://www.zghlxwxcb.cn/news/detail-707099.html
2 情感文本分類
2.1 參考論文
Convolutional Neural Networks for Sentence
Classification
模型結(jié)構(gòu)
在短文本分析任務(wù)中,由于句子句長長度有限、結(jié)構(gòu)緊湊、能夠獨(dú)立表達(dá)意思,使得CNN在處理這一類問題上成為可能,主要思想是將ngram模型與卷積操作結(jié)合起來
2.2 輸入層
如圖所示,輸入層是句子中的詞語對應(yīng)的wordvector依次(從上到下)排列的矩陣,假設(shè)句子有 n 個詞,vector的維數(shù)為 k ,那么這個矩陣就是 n
× k 的(在CNN中可以看作一副高度為n、寬度為k的圖像)。
這個矩陣的類型可以是靜態(tài)的(static),也可以是動態(tài)的(non static)。靜態(tài)就是word
vector是固定不變的,而動態(tài)則是在模型訓(xùn)練過程中,word vector也當(dāng)做是可優(yōu)化的參數(shù),通常把反向誤差傳播導(dǎo)致word
vector中值發(fā)生變化的這一過程稱為Fine tune。(這里如果word
vector如果是隨機(jī)初始化的,不僅訓(xùn)練得到了CNN分類模型,還得到了word2vec這個副產(chǎn)品了,如果已經(jīng)有訓(xùn)練的word
vector,那么其實(shí)是一個遷移學(xué)習(xí)的過程)
對于未登錄詞的vector,可以用0或者隨機(jī)小的正數(shù)來填充。
2.3 第一層卷積層:
輸入層通過卷積操作得到若干個Feature Map,卷積窗口的大小為 h ×k ,其中 h 表示縱向詞語的個數(shù),而 k 表示word
vector的維數(shù)。通過這樣一個大型的卷積窗口,將得到若干個列數(shù)為1的Feature Map。(熟悉NLP中N-GRAM模型的讀者應(yīng)該懂得這個意思)。
2.4 池化層:
接下來的池化層,文中用了一種稱為Max-over-timePooling的方法。這種方法就是簡單地從之前一維的Feature
Map中提出最大的值,文中解釋最大值代表著最重要的信號。可以看出,這種Pooling方式可以解決可變長度的句子輸入問題(因?yàn)椴还蹻eature
Map中有多少個值,只需要提取其中的最大值)。最終池化層的輸出為各個Feature Map的最大值們,即一個一維的向量。
2.5 全連接+softmax層:
池化層的一維向量的輸出通過全連接的方式,連接一個Softmax層,Softmax層可根據(jù)任務(wù)的需要設(shè)置(通常反映著最終類別上的概率分布)。
2.6 訓(xùn)練方案
在倒數(shù)第二層的全連接部分上使用Dropout技術(shù),Dropout是指在模型訓(xùn)練時隨機(jī)讓網(wǎng)絡(luò)某些隱含層節(jié)點(diǎn)的權(quán)重不工作,不工作的那些節(jié)點(diǎn)可以暫時認(rèn)為不是網(wǎng)絡(luò)結(jié)構(gòu)的一部分,但是它的權(quán)重得保留下來(只是暫時不更新而已),因?yàn)橄麓螛颖据斎霑r它可能又得工作了,它是防止模型過擬合的一種常用的trikc。同時對全連接層上的權(quán)值參數(shù)給予L2正則化的限制。這樣做的好處是防止隱藏層單元自適應(yīng)(或者對稱),從而減輕過擬合的程度。
在樣本處理上使用minibatch方式來降低一次模型擬合計(jì)算量,使用shuffle_batch的方式來降低各批次輸入樣本之間的相關(guān)性(在機(jī)器學(xué)習(xí)中,如果訓(xùn)練數(shù)據(jù)之間相關(guān)性很大,可能會讓結(jié)果很差、泛化能力得不到訓(xùn)練、這時通常需要將訓(xùn)練數(shù)據(jù)打散,稱之為shuffle_batch)。
3 實(shí)現(xiàn)
我們以上圖為例,圖上用紅色標(biāo)簽標(biāo)注了5部分,結(jié)合這5個標(biāo)簽,具體解釋下整個過程的操作,來看看CNN如何解決文本分類問題的。
3.1 sentence部分
上圖句子為“[I like this movie very much!”
,一共有兩個單詞加上一個感嘆號,關(guān)于這個標(biāo)點(diǎn)符號,不同學(xué)者有不同的操作,比如去除標(biāo)點(diǎn)符號。在這里我們先不去除,那么整個句子有7個詞,詞向量維度為5,那么整個句子矩陣大小為7x5
3.2 filters部分
filters的區(qū)域大小可以使不同的,在這里取(2,3,4)3種大小,每種大小的filter有兩個不同的值的filter,所以一共是有6個filter。
3.3 featuremaps部分
我們在句子矩陣和過濾器矩陣填入一些值,那么我們可以更好理解卷積計(jì)算過程,這和CNN原理那篇文章一樣
比如我們?nèi)〈笮?的filter,最開始與句子矩陣的前兩行做乘積相加,得到0.6 x 0.2 + 0.5 x 0.1 + … + 0.1 x 0.1 =
0.51,然后將filter向下移動1個位置得到0.53.最終生成的feature map大小為(7-2+1x1)=6。
為了獲得feature map,我們添加一個bias項(xiàng)和一個激活函數(shù),比如Relu
3.4 1max部分
因?yàn)椴煌笮〉膄ilter獲取到的feature map大小也不一樣,為了解決這個問題,然后添加一層max-
pooling,選取一個最大值,相同大小的組合在一起
3.5 concat1max部分
經(jīng)過max-pooling操作之后,我們將固定長度的向量給sofamax,來預(yù)測文本的類別。
3.6 關(guān)鍵代碼
下面是利用Keras實(shí)現(xiàn)的CNN文本分類部分代碼:
?
# 創(chuàng)建tensor
print("正在創(chuàng)建模型...")
inputs=Input(shape=(sequence_length,),dtype='int32')
embedding=Embedding(input_dim=vocabulary_size,output_dim=embedding_dim,input_length=sequence_length)(inputs)
reshape=Reshape((sequence_length,embedding_dim,1))(embedding)
# cnn
conv_0=Conv2D(num_filters,kernel_size=(filter_sizes[0],embedding_dim),padding='valid',kernel_initializer='normal',activation='relu')(reshape)
conv_1=Conv2D(num_filters,kernel_size=(filter_sizes[1],embedding_dim),padding='valid',kernel_initializer='normal',activation='relu')(reshape)
conv_2=Conv2D(num_filters,kernel_size=(filter_sizes[2],embedding_dim),padding='valid',kernel_initializer='normal',activation='relu')(reshape)
maxpool_0=MaxPool2D(pool_size=(sequence_length-filter_sizes[0]+1,1),strides=(1,1),padding='valid')(conv_0)
maxpool_1=MaxPool2D(pool_size=(sequence_length-filter_sizes[1]+1,1),strides=(1,1),padding='valid')(conv_1)
maxpool_2=MaxPool2D(pool_size=(sequence_length-filter_sizes[2]+1,1),strides=(1,1),padding='valid')(conv_2)
concatenated_tensor = Concatenate(axis=1)([maxpool_0, maxpool_1, maxpool_2])
flatten = Flatten()(concatenated_tensor)
dropout = Dropout(drop)(flatten)
output = Dense(units=2, activation='softmax')(dropout)
model=Model(inputs=inputs,outputs=output)
**main.py**
import os
os.environ["CUDA_DEVICE_ORDER"] = "PCI_BUS_ID" # see issue #152
os.environ["CUDA_VISIBLE_DEVICES"] = ""
import re
import numpy as np
from flask import Flask, render_template, request
from keras.models import load_model
from data_helpers_english import build_input_english
from data_helpers_chinese import build_input_chinese
app = Flask(__name__)
en_model = load_model('results/weights.007-0.7618.hdf5')
ch_model = load_model('results/chinese.weights.003-0.9083.hdf5')
# load 進(jìn)來模型緊接著就執(zhí)行一次 predict 函數(shù)
print('test train...')
print(en_model.predict(np.zeros((1, 56))))
print(ch_model.predict(np.zeros((1, 50))))
print('test done.')
def en_predict(input_x):
sentence = input_x
input_x = build_input_english(input_x)
y_pred = en_model.predict(input_x)
result = list(y_pred[0])
result = {'sentence': sentence, 'positive': result[1], 'negative': result[0]}
return result
def ch_predict(input_x):
sentence = input_x
input_x = build_input_chinese(input_x)
y_pred = ch_model.predict(input_x)
result = list(y_pred[0])
result = {'sentence': sentence, 'positive': result[1], 'negative': result[0]}
return result
@app.route('/classification', methods=['POST', 'GET'])
def english():
if request.method == 'POST':
review = request.form['review']
# 來判斷是中文句子/還是英文句子
review_flag = re.sub(r"[^A-Za-z0-9(),!?\'\`]", " ", review) # 去除數(shù)字
review_flag = re.sub("[\s+\.\!\/_,$%^*(+\"\')]+|[+——()?【】“”!,。?、~@#¥%……&*()]+", "", review_flag)
if review_flag:
result = en_predict(review)
# result = {'sentence': 'hello', 'positive': '03.87878', 'negative': '03.64465'}
return render_template('index.html', result=result)
else:
result = ch_predict(review)
# result = {'sentence': 'hello', 'positive': '03.87878', 'negative': '03.64465'}
return render_template('index.html', result=result)
return render_template('index.html')
#
# if __name__ == '__main__':
# app.run(host='0.0.0.0', debug=True)
4 實(shí)現(xiàn)效果
4.1 測試英文情感分類效果
準(zhǔn)訓(xùn)練結(jié)果:驗(yàn)證集76%左右
4.2 測試中文情感分類效果
準(zhǔn)訓(xùn)練結(jié)果:驗(yàn)證集91%左右
5 調(diào)參實(shí)驗(yàn)結(jié)論
- 由于模型訓(xùn)練過程中的隨機(jī)性因素,如隨機(jī)初始化的權(quán)重參數(shù),mini-batch,隨機(jī)梯度下降優(yōu)化算法等,造成模型在數(shù)據(jù)集上的結(jié)果有一定的浮動,如準(zhǔn)確率(accuracy)能達(dá)到1.5%的浮動,而AUC則有3.4%的浮動;
- 詞向量是使用word2vec還是GloVe,對實(shí)驗(yàn)結(jié)果有一定的影響,具體哪個更好依賴于任務(wù)本身;
- Filter的大小對模型性能有較大的影響,并且Filter的參數(shù)應(yīng)該是可以更新的;
- Feature Map的數(shù)量也有一定影響,但是需要兼顧模型的訓(xùn)練效率;
- 1-max pooling的方式已經(jīng)足夠好了,相比于其他的pooling方式而言;
- 正則化的作用微乎其微。
6 建議
- 使用non-static版本的word2vec或者GloVe要比單純的one-hot representation取得的效果好得多;
- 為了找到最優(yōu)的過濾器(Filter)大小,可以使用線性搜索的方法。通常過濾器的大小范圍在1-10之間,當(dāng)然對- 于長句,使用更大的過濾器也是有必要的;
- Feature Map的數(shù)量在100-600之間;
- 可以盡量多嘗試激活函數(shù),實(shí)驗(yàn)發(fā)現(xiàn)ReLU和tanh兩種激活函數(shù)表現(xiàn)較佳;
- 使用簡單的1-max pooling就已經(jīng)足夠了,可以沒必要設(shè)置太復(fù)雜的pooling方式;
- 當(dāng)發(fā)現(xiàn)增加Feature Map的數(shù)量使得模型的性能下降時,可以考慮增大正則的力度,如調(diào)高dropout的概率;
- 為了檢驗(yàn)?zāi)P偷男阅芩?,多次反?fù)的交叉驗(yàn)證是必要的,這可以確保模型的高性能并不是偶然。
7 最后
?? 更多資料, 項(xiàng)目分享:
https://gitee.com/dancheng-senior/postgraduate
到了這里,關(guān)于計(jì)算機(jī)競賽 基于深度學(xué)習(xí)的中文情感分類 - 卷積神經(jīng)網(wǎng)絡(luò) 情感分類 情感分析 情感識別 評論情感分類的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!