Embedding和Word2Vec实战

在之前的文章中谈到了文本向量化的一些基本原理和概念,本文将介绍Word2Vec的代码实现

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

Word2Vec论文地址

https://arxiv.org/abs/1301.3781

Embedding

与one-hot编码相比,词嵌入可以将更多的信息塞入更低的维度中

 

下面我们用 Keras 完成一个词嵌入的学习,Keras 的 Embedding 层的输入是一个二维整数张量, 形状为(samples,sequence_length),即(样本数,序列长度)

较短的序列应该用 0 填充,较长的序列应该被截断,保证输入的序列长度是相同的

Embedding 层输出是(samples,sequence_length,embedding_dimensionality) 的三维浮点数张量

  • 首先,我们需要对文本进行分词处理,然后对原始文本进行序列化
  • 再统一输入的序列长度,最后把序列化的结果输入到 Embedding 层中

整个过程可以用下面的图描述

Embedding和Word2Vec实战

从样本的角度看,我们可以用下面的图描述这个过程

Embedding和Word2Vec实战

示意代码如下

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)单词的效果

Embedding和Word2Vec实战

如果增加到50个单词,验证集就达到了80%的正确率

Embedding和Word2Vec实战

 

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)
# total_examples句子数,epochs迭代次数
model.train(sentences, total_examples=2, epochs=1)
print(model.wv['cat'])

训练得到Word2Vec模型后,我们在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上别人的实验

Embedding和Word2Vec实战

 

 

 

 

 

 

 

上一篇:软件工程 in MSRA Code Search-第二次结对编程


下一篇:【Graph Neural Network】GraphSAGE: 算法原理,实现和应用