Embedding和Word2Vec實戰

在以前的文章中談到了文本向量化的一些基本原理和概念,本文將介紹Word2Vec的代碼實現html

https://www.cnblogs.com/dogecheng/p/11470196.html#Word2Vecpython

Word2Vec論文地址服務器

https://arxiv.org/abs/1301.3781網絡

1.Embedding

與one-hot編碼相比,詞嵌入能夠將更多的信息塞入更低的維度中app

 

下面咱們用 Keras 完成一個詞嵌入的學習,Keras 的 Embedding 層的輸入是一個二維整數張量, 形狀爲(samples,sequence_length),即(樣本數,序列長度)dom

較短的序列應該用 0 填充,較長的序列應該被截斷,保證輸入的序列長度是相同的學習

Embedding 層輸出是(samples,sequence_length,embedding_dimensionality) 的三維浮點數張量測試

  • 首先,咱們須要對文本進行分詞處理,而後對分詞結果進行序列化
  • 再統一輸入的序列長度,最後把統一長度的序列化結果輸入到 Embedding 層中

整個過程能夠用下面的圖描述
編碼

從樣本的角度看,咱們能夠用下面的圖描述這個過程spa

示意代碼以下

from keras.preprocessing.text import Tokenizer from keras.preprocessing.sequence import pad_sequences from keras.models import Sequential from keras.layers import Embedding, Flatten, Dense docs = ["The cat sat on the mat.", "I love green eggs and ham."] # 只考慮最多見的8個單詞
max_words = 8
# 統一的序列化長度 # 大於這個長度截斷,小於這個長度用0補全
maxlen = 5
# 嵌入的維度
embedding_dim = 3

# 分詞
tokenizer = Tokenizer(num_words=max_words) tokenizer.fit_on_texts(docs) # 字典
word_index = tokenizer.word_index # 序列化
sequences = tokenizer.texts_to_sequences(docs) # 統一序列長度
data = pad_sequences(sequences, maxlen=maxlen) # Embedding模型
model = Sequential() # Embedding至少須要max_wrods和embedding_dim兩個參數
model.add(Embedding(max_words, embedding_dim, input_length=maxlen, name='embedding')) model.compile('rmsprop', 'mse') out = model.predict(data) print(out) print(out.shape) # 查看權重
layer = model.get_layer('embedding') print(layer.get_weights())

剛剛對Keras中的一些文本處理模塊和Embedding作了簡單的說明和演示

在Embedding層後面能夠跟上神經網絡,完成各類文本任務

下面使用IMDB電影評論作一個情感預測任務

from keras.datasets import imdb from keras import preprocessing from keras.models import Sequential from keras.layers import Flatten, Dense, Embedding # 特徵單詞數
max_words = 10000
# 在20單詞後截斷文本 # 這些單詞都屬於max_words中的單詞
maxlen = 20
# 嵌入維度
embedding_dim = 8

# 加載數據集 # 加載的數據已經序列化過了,每一個樣本都是一個sequence列表
(x_train, y_train), (x_test, y_test) = imdb.load_data(num_words=max_words) # 統計序列長度,將數據集轉換成形狀爲(samples,maxlen)的二維整數張量
x_train = preprocessing.sequence.pad_sequences(x_train, maxlen=maxlen) x_test = preprocessing.sequence.pad_sequences(x_test, maxlen=maxlen) # 構建模型
model = Sequential() model.add(Embedding(max_words, embedding_dim, input_length=maxlen)) # 將3維的嵌入張量展平成形狀爲(samples,maxlen * embedding_dim)的二維張量
model.add(Flatten()) model.add(Dense(1, activation='sigmoid')) model.compile(optimizer='rmsprop', loss='binary_crossentropy', metrics=['acc']) model.summary() history = model.fit(x_train, y_train, epochs=10, batch_size=32, validation_split=0.2)

咱們只是簡單測試一下,咱們最後獲得的效果以下圖所示,這是隻看前20個(maxlen爲20)單詞的效果

若是增長到50個單詞,驗證集就達到了80%的正確率

 

2.Word2Vec

2.1.gensim實現Word2Vec

gensim庫提供了一個word2vec的實現,咱們使用幾個API就能夠方便地完成word2vec

from gensim.models import Word2Vec import re documents = ["The cat sat on the mat.", "I love green eggs and ham."] sentences = [] # 去標點符號
stop = '[’!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~]+'
for doc in documents: doc = re.sub(stop, '', doc) sentences.append(doc.split())
#sentences = [["The", "cat", "sat", "on", "the", "mat"], # ["I", "love", "green", "eggs", "and", "ham"]] # size嵌入的維度,window窗口大小,workers訓練線程數 # 忽略單詞出現頻率小於min_count的單詞 # sg=1使用Skip-Gram,不然使用CBOW model = Word2Vec(sentences, size=5, window=1, min_count=1, workers=4, sg=1)
print(model.wv['cat'])

訓練獲得Word2Vec模型後,咱們在Keras的Embedding層中使用這個Word2Vec獲得的權重

再利用神經網絡或其餘方法去完成各類文本任務

2.2.Keras的Embedding和Word2Vec

咱們去kaggle上下IMDB的電影評論數據集,用這個數據集來學習

由於在本身電腦上跑程序,沒有用服務器,本文只取了前100條用來學習

https://www.kaggle.com/c/word2vec-nlp-tutorial/data

 下面是kaggle上別人用這個數據集作的實驗

https://www.kaggle.com/alexcherniuk/imdb-review-word2vec-bilstm-99-acc/data

import pandas as pd import re from gensim.models import Word2Vec from keras.preprocessing.sequence import pad_sequences from sklearn.model_selection import train_test_split from keras.models import Sequential from keras.layers import Embedding, Flatten, Dense """ 讀取訓練集並構造訓練樣本 """
def split_sentence(sentence): stop = '[’!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~]+' sentence = re.sub(stop, '', sentence) return sentence.split() data = pd.read_csv(r"F:\pythonWP\keras\blog\labeledTrainData.tsv", sep='\t') data = data[:100] sentences = data.review.apply(split_sentence) """ 訓練Word2Vec """
# 嵌入的維度
embedding_vector_size = 10 w2v_model = Word2Vec( sentences=sentences, size=embedding_vector_size, min_count=1, window=3, workers=4) # 取得全部單詞
vocab_list = list(w2v_model.wv.vocab.keys()) # 每一個詞語對應的索引
word_index = {word: index for index, word in enumerate(vocab_list)} # 序列化
def get_index(sentence): global word_index sequence = [] for word in sentence: try: sequence.append(word_index[word]) except KeyError: pass
    return sequence X_data = list(map(get_index, sentences)) # 截長補短
maxlen = 150 X_pad = pad_sequences(X_data, maxlen=maxlen) # 取得標籤
Y = data.sentiment.values # 劃分數據集
X_train, X_test, Y_train, Y_test = train_test_split( X_pad, Y, test_size=0.2, random_state=42) """ 構建分類模型 """
# 讓 Keras 的 Embedding 層使用訓練好的Word2Vec權重
embedding_matrix = w2v_model.wv.vectors model = Sequential() model.add(Embedding( input_dim=embedding_matrix.shape[0], output_dim=embedding_matrix.shape[1], input_length=maxlen, weights=[embedding_matrix], trainable=False)) model.add(Flatten()) model.add(Dense(5)) model.add(Dense(1, activation='sigmoid')) model.compile( loss="binary_crossentropy", optimizer='adam', metrics=['accuracy']) history = model.fit( x=X_train, y=Y_train, validation_data=(X_test, Y_test), batch_size=4, epochs=10) 

因爲訓練樣本少,獲得的模型沒有太大意義,波動也大,僅用來學習。整個訓練集的使用能夠去上面分享的連接去看kaggle上別人的實驗

2.3.LSTM和Word2Vec實現電影評論情感分析

數據集仍是使用的跟上面是同樣的,kaggle 上 IMDB 的電影評論數據集。下面的代碼是在服務器上測試的。

https://www.kaggle.com/c/word2vec-nlp-tutorial/data

在建模以前,須要進行簡單的數據處理,這是其中一條評論。能夠看到,裏面還有存在 html 的標籤 <br />還有許多標點符號 \\ 、 " 和 () 等等

'<br /><br />This movie is full of references. Like \\Mad Max II\\", \\"The wild one\\" and many others. The ladybug´s face it´s a clear reference (or tribute) to Peter Lorre. This movie is a masterpiece. We´ll talk much more about in the future."'

咱們預處理首先就要去掉 html 標籤和這些標點符號標點符號保留 「-」 和 「´」 下進行測試

  • 一些縮寫會用到上引號,如 We´ll
  • 一些短語會用到小橫杆,好比 heavy-handed

另外,爲了簡化訓練詞向量和模型訓練的過程,還進行了其餘處理,好比轉換爲小寫詞性還原。而後使用停用詞庫去除一些對 情感分析 用處不大的詞。

好比a, an, the 等

停用詞庫簡單使用了 sklearn 中自帶的停用詞。預處理代碼以下

import pandas as pd import re from sklearn.feature_extraction import text from nltk.stem import WordNetLemmatizer # 讀取數據
data = pd.read_csv(r"./data/labeledTrainData.tsv", sep='\t') def clean_review(raw_review: str) -> str: # 1. 評論是爬蟲抓取的,存在一些 html 標籤,須要去掉
    review_text = raw_review.replace("<br />", '') # 2. 標點符號只保留 「-」 和 上單引號
    review_text = rex.sub(' ', review_text) # 3. 所有變成小寫
    review_text = review_text.lower() # 4. 分詞
    word_list = review_text.split() # 5. 詞性還原
    tokens = list(map(lemmatizer.lemmatize, word_list)) lemmatized_tokens = list(map(lambda x: lemmatizer.lemmatize(x, "v"), tokens)) # 6. 去停用詞
    meaningful_words = list(filter(lambda x: not x in stop_words, lemmatized_tokens)) return meaningful_words stop_words = set(text.ENGLISH_STOP_WORDS) rex = re.compile(r'[!"#$%&\()*+,./:;<=>?@\\^_{|}~]+') lemmatizer = WordNetLemmatizer() sentences = data.review.apply(clean_review)

訓練 Word2Vec 獲取詞向量

from gensim.models import Word2Vec embedding_vector_size = 256 w2v_model = Word2Vec( sentences=sentences, size=embedding_vector_size, min_count=3, window=5, workers=4)

查看預處理完每句話大概有多少個單詞

cal_len = pd.DataFrame() cal_len['review_lenght'] = list(map(len, sentences)) print("中位數:", cal_len['review_lenght'].median()) print("均值數:", cal_len['review_lenght'].mean()) del cal_len
中位數: 82.0
均值數: 110.52928

用 數字索引 表示原來的句子

from keras.preprocessing.sequence import pad_sequences from sklearn.model_selection import train_test_split # 取得全部單詞
vocab_list = list(w2v_model.wv.vocab.keys()) # 每一個詞語對應的索引
word_index = {word: index for index, word in enumerate(vocab_list)} # 序列化
def get_index(sentence): global word_index sequence = [] for word in sentence: try: sequence.append(word_index[word]) except KeyError: pass
    return sequence X_data = list(map(get_index, sentences)) # 截長補短 # max_len 根據中位數和平均值得來的
maxlen = 100 X_pad = pad_sequences(X_data, maxlen=maxlen) # 取得標籤
Y = data.sentiment.values # 劃分數據集
X_train, X_test, Y_train, Y_test = train_test_split( X_pad, Y, test_size=0.2, random_state=42)

構建和訓練模型

from keras.models import Sequential from keras.layers import Embedding, Bidirectional, LSTM, Dropout, Dense # 讓 Keras 的 Embedding 層使用訓練好的Word2Vec權重
embedding_matrix = w2v_model.wv.vectors model = Sequential() model.add(Embedding( input_dim=embedding_matrix.shape[0], output_dim=embedding_matrix.shape[1], input_length=maxlen, weights=[embedding_matrix], trainable=False)) model.add(Bidirectional(LSTM(128, recurrent_dropout=0.1))) model.add(Dropout(0.25)) model.add(Dense(128, activation='sigmoid')) model.add(Dropout(0.3)) model.add(Dense(1, activation='sigmoid')) model.compile( loss="binary_crossentropy", optimizer='adam', metrics=['accuracy'] ) history = model.fit( x=X_train, y=Y_train, validation_data=(X_test, Y_test), batch_size=50, epochs=8 ) 

實驗結果,準確率81左右

相關文章
相關標籤/搜索