讓你聽見你想要聽見的,讓你看見你想要看見的。Joi能知足你的一切幻想。 --《銀翼殺手2049》python
在這部電影中,用程序設定的虛擬人物,時時刻刻的與主角進行情感溝通,甚至產生了親密的感情,或許這個在將來真的可以實現。如今轉到現實中來,近兩年AI的熱度暴漲,其中天然語言處理也是研究的重點,如今顯然已經有很是顯著的效果。git
情感對於人類的社交、表達、記憶、決策和感知上都有很重要的做用,有研究顯示人類交流中的80%信息都是帶有情感信息的。情感狀態不一樣會影響人的思惟和行動,特別是積極或消極所帶來的影響有很大的不一樣。因爲情感在人類溝通的重大意義,因此在設計人與計算機交流的時候也是必不可少的部分。經過和人的聊天,AI可用情感分析對實體進行高效率的自動化標註,學習到用戶的性格變得更加智能。像微軟的小冰,聊的越多越「懂」本身。github
通常狀況下,咱們探討的情感分析多指文本中的情感分析,也有更多維的情感分析,好比文字+圖片+標籤+語音+面部表情、肢體動做等等,就像前一段時間被授予合法公民身份的AI機器人索菲亞能夠經過攝像聲音和周圍的環境來經過面部表情來傳達情感。人類能表達的情感的信息量的大小和維度。好比面對面交流時,情感性的信息每每是從語音語調、面部表情、肢體等多個維度表達出來的。然而到了人機交互中,情感寬帶的整個範式會發生較大的變化,如經過人機對話系統交流時,少了肢體這個維度,人類的情感帶寬彷佛瞬間驟降了。但實際上也增長了幾個新的輸出維度,如圖片、表情包、回覆時間的長短等。數組
顯然,面對多維更加智能的場景,目前的技術實現起來難度很大,可是針對大多數的文本語意的表達仍是有比較成熟的解決方案,如今就來講一下深度學習在天然語言處理的表現吧。網絡
深度學習在情感分析中的應用已經較爲廣泛了,如利用 LSTM 結合句法分析樹、基於卷積神經網絡和支持向量機等。通常狀況下,對於各類方法的綜合創新應用,能達到取長補短的效果,進而可以提升情感分析的準確率,另外還能從無標註的文本里學習到其中的隱藏特徵,以實現端到端的分類。app
關於更多的深度學習相比於詞典以及傳統的機器學習的方式的優點,你們能夠自行查閱相關文章,這篇文章只將用深度學習來簡單的訓練一個樣本,並預測任意一個句子的情感傾向。機器學習
開始以前,你須要對深度學習原理有比較深入的瞭解,lstm的原理,調參優化細節,keras基本知識的掌握。項目github地址戳這裏。函數
1. 準備語料工具
本次收集的語料不是太多。中文大概2w多條(淘寶評論),英文1w多條(電影評論),之後有時間會繼續補充語料。其中有5%做爲驗證集,10%爲測試集合。文件已經切分好,可是由於須要訓練全部數據集,因此這個提早切分到不一樣文件夾並無什麼做用(後面講到會從新合併再切分)。學習
2.選擇語言版本,分別設置訓練集、測試集、驗證集和維度
由於後面的程序要訓練中文或英文,因此在這裏提早選擇語言版本和不一樣的語言版本訓練相關的參數。
# 選擇語言中文仍是英文
languageType = ''
while (languageType != 'c' and languageType != 'e'):
languageType = input("Please enter a train type(chinese enter lower: c , english enter lower: e): ")
max_length = '' #一句話最大長度
load_path = '' #文件加載路徑
language = '' #語言類型
tr_num = 17000 #訓練集
va_num = 2000 #訓練集
if languageType == 'c':
max_length = 100
load_path = 'data/chinese'
language = 'chinese'
tr_num = 17000
va_num = 2000
elif languageType == 'e':
max_length = 40
load_path = 'data/english'
language = 'english'
tr_num = 8000
va_num = 600
複製代碼
3.加載數據集 這裏把中文和英文放在不一樣的文件夾下,利用 pandas
中的read_csv()
讀取數據集合併到一塊兒,若是這裏原本就是一個整的數據集。則直接讀取就好。
# 獲取csv文件:內容放到數組裏面 分別是訓練集、驗證集、測試集,最後合併到一塊兒
def sst_binary(data_dir='data/chinese'):
tr_data = pd.read_csv(os.path.join(data_dir, 'train_binary_sent.csv'))
va_data = pd.read_csv(os.path.join(data_dir, 'valid_binary_sent.csv'))
te_data = pd.read_csv(os.path.join(data_dir, 'test_binary_sent.csv'))
all_data = tr_data.append(va_data).append(te_data)
return all_data
複製代碼
4.數據預處理
這一步是針對中文和英文的特色來處理掉對分析無用的詞提高精度。好比停用詞、標點符號、特殊字符、轉義字符等等。由於語料比較少,這個程序尚未針對這一塊作處理。
5.將詞語轉化爲向量
這裏是最核心的地方,深度學習在訓練數據的時候要求輸入的數據是一個向量,這樣才能進行矩陣運算,也是多層感知器的輸入。因此若是直接將一組句子是沒法識別的。因此最重要的一步就是將詞語轉化爲詞向量,但是如何才能獲得向量呢?
這裏用到的是詞嵌入的方法,大概步驟是:
jieba
)將一句話按照詞語切分開來而非字。Embedding()
,該層會利用詞嵌入將句子數字數組轉化爲詞向量。須要注意的是,jieba分詞雖然是分中文的,可是也能夠處理英文(英文是按照空格切分的),這樣能夠獲得比較統一的數組shape。
#定義模型
class Model(object):
def __init__(self, sentence_max_length=100):
sentence_max_length = sentence_max_length #截斷詞數 cut texts after this number of words (among top max_features most common words)
sentence_drop_length = 5 #出現次數少於該值的詞扔掉。這是最簡單的降維方法
#將每一個句子裏的詞轉化成詞頻索引值
def transform(data):
#若是是中文調用結巴分詞
xs = data['sentence'].apply(lambda s: list(jieba.cut(s)))
#將全部詞放到一個數組中
word_all = []
for i in xs:
word_all.extend(i)
#統計詞頻並排序建索引
global word_frequency, word_set
word_frequency = pd.Series(word_all).value_counts() #統計詞頻,從大到小排序
word_frequency = word_frequency[word_frequency >=
sentence_drop_length] #出現次數小於5的丟棄
word_frequency[:] = list(range(
1,
len(word_frequency) + 1)) #將詞頻排序的結果加索引
word_frequency[''] = 0 #添加空字符串用來補全,以前丟棄的後面的找不到的會用0代替
word_set = set(
word_frequency.index) #通過處理以後的全部詞的數組集合,而且去掉可能存在的重複元素
#將詞語替換成按照全部訓練集詞頻排序後的索引
xt = xs.apply(lambda s: word2num(s, sentence_max_length))
xt = np.array(list(xt))
yt = np.array(list(data['label'])).reshape(
(-1, 1)) #此處用來調整標籤形狀n行1列 (-1是模糊控制即有不定多少行,1是1列)
#當前訓練集合詞的索引長度
wi = len(word_frequency)
return xt, yt, wi
self.transform = transform
複製代碼
6.keras 訓練數據集
這一部分就交給keras處理了,具體用法能夠參見keras中文文檔,能夠自定義一些參數,好比訓練輪數、激活函數、加入驗證集等等。固然核心的仍是lstm了,相對於RNN,在訓練長文本有更好的效果。訓練完了以後能夠選擇保存模型。方便下次直接調用。
#將詞轉化爲數字向量 即一個句子裏的每一個詞都有用上面生成的索引值代替
def word2num(s, sentence_max_length):
s = [i for i in s if i in word_set]
s = s[:sentence_max_length] + [''] * max(0, sentence_max_length - len(s))
return list(word_frequency[s])
# krea 訓練數據集
def model_train(x, y, wi, language, sentence_max_length=100, tr_num=17000, va_num=2000):
global model
model = Sequential()
model.add(Embedding(wi, 256, input_length=sentence_max_length))
model.add(LSTM(128))
model.add(Dropout(0.5))
model.add(Dense(1))
model.add(Activation('sigmoid'))
model.compile(
loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
model.fit(
x[:tr_num],
y[:tr_num],
batch_size=128,
nb_epoch=30,
validation_data=(x[tr_num:tr_num + va_num], y[tr_num:tr_num + va_num]))
score = model.evaluate(
x[tr_num + va_num:], y[tr_num + va_num:], batch_size=128)
model.save('model_' + language + '.h5')
return score[1]
#加載已經訓練好的模型
def model_load(language):
global model
model = load_model('model_' + language + '.h5')
複製代碼
7.預測單個句子
預測單個句子依然須要將這個句子分詞,而後將詞轉化爲數字,因此仍是用到訓練模型時用到的處理方式。
#單個句子的預測函數
def model_predict(s, sentence_max_length=100):
s = np.array(word2num(list(jieba.cut(s)), sentence_max_length))
s = s.reshape((1, s.shape[0]))
return model.predict_classes(s, verbose=0)[0][0]
複製代碼
好了,大功告成,咱們已經能夠直接測試訓練的結果了。
如今,咱們已經可以利用keras裏的lstm對文本進行預測情感傾向了。可是這裏完美仍是有很大距離,須要不斷的調參來提升準確度。可以提高的地方好比加大訓練集數量、對數據預處理、調整訓練次數等等。固然還有更酷的方案好比雙向lstm這樣的訓練方式,綜合對比,或許都是改良的途徑。
目前一套模型同時解決中文和英文的例子仍是很是少,畢竟語言的差別仍是很是大,接下來會繼續對其中進行一些探索,這個也是我對天然語言處理中的情感分析一點小小的嘗試。
Github地址:github.com/Elliottssu/…
轉載著名出處