天天看点

Keras 模型中使用预训练的词向量(用word2vec替换keras自带的Embedding层)

由于Keras中自带的Embedding层的表现效果不佳,想用word2vec做为预训练模型替换Keras中自带的Embedding层,在此记录下来。

本文假设大家已经有了训练好的Word2vec模型,并且简单理解的keras的embeddings层。可以查看中文官方文档了解一下。

1.首先要导入预训练的词向量。

## 1 导入 预训练的词向量
myPath = './CarComment_vord2vec_100' # 本地词向量的地址
model = gensim.models.Word2Vec.load(myPath) # 读取词向量
           

2.构造“词语-词向量”字典

(1) word2idx 保存词语和 token 的对应关系,语料库 tokenize 时候需要。(这个东西我也没弄明白有什么作用,我把它删掉之后也是可以正常运行的,大神求告知。)

(2) vocab_list 保存[(词语1,词向量1),(词语2,词向量3),········]的列表

(3) embeddings_matrix 存储所有 word2vec 中所有向量的矩阵,用于初始化模型 Embedding 层

word2idx = {"_PAD": 0} # 初始化 `[word : token]` 字典,后期 tokenize 语料库就是用该词典。

vocab_list = [(k, model.wv[k]) for k, v in model.wv.vocab.items()]

# 存储所有 word2vec 中所有向量的数组,留意其中多一位,词向量全为 0, 用于 padding
embeddings_matrix = np.zeros((len(model.wv.vocab.items()) + 1, model.vector_size))
           

3.填充字典和矩阵

for i in range(len(vocab_list)):
    word = vocab_list[i][0]
    word2idx[word] = i + 1
    embeddings_matrix[i + 1] = vocab_list[i][1]
           

4.在keras的Embedding层中使用 预训练词向量

#使用方法
from keras.layers import Embedding

EMBEDDING_DIM = 100 #词向量维度

embedding_layer = Embedding(len(embeddings_matrix),          #词向量矩阵的高(高是词向量矩阵的特征数,长是词向量的维度)
                            EMBEDDING_DIM,                   #词向量的维度
                            weights = [embeddings_matrix],   #Word2vec的预训练的参数
                            trainable = False                #是否在训练的过程中更新词向量
                            )
           

5.构建模型的完整代码

from gensim.models import Word2Vec
import numpy as np
from keras.models import Sequential,Input
from keras.layers.core import Dense, Dropout, Activation,Flatten
from keras.layers.embeddings import Embedding
import numpy as np
from gensim.models import word2vec, Word2Vec
from keras import Model
from keras.layers import Conv1D, MaxPooling1D, concatenate

def word2vec2keras_cnn(maxlen = 150,max_features = 2000,embed_size = 32):
    #Input
    comment_seq = Input(shape=[maxlen],name='x_seq')

    model_path = ("./Keras_study/300features_40minwords_10context")#我自己本地的训练好的word2vec模型
    model = Word2Vec.load(model_path)#加载训练好的wordvec模型

    word2idx = {"_PAD":0}#初始化'[word : token]'字典,后期tokenize语料库就是用该字典。
    vocab_list = [(k,model.wv[k]) for k,v in model.wv.vocab.items()]

    #储存所有 word2vec 中所有向量的数组,留意其中多一位,词向量全为0,用于padding
    embeddings_matrix = np.zeros((len(model.wv.vocab.items()) + 1,model.vector_size))#创建一个空的矩阵(储存多个数组)
    for i in range(len(vocab_list)):
        word = vocab_list[i][0]
        word2idx[word] = i + 1
        embeddings_matrix[i+1] = vocab_list[i][1]

    #使用方法
    from keras.layers import Embedding

    EMBEDDING_DIM = 300 #词向量维度

    embed_comment = Embedding(len(embeddings_matrix),  #词向量矩阵的高(高是词向量矩阵的特征数,长是词向量的维度)
                                EMBEDDING_DIM,          #词向量的维度
                                weights = [embeddings_matrix],
                                trainable = False
                                )(comment_seq)

    convs = []
    filter_sizes = [2, 3, 4, 5]
    for fsz in filter_sizes:
        l_conv = Conv1D(filters=100, kernel_size=fsz, activation='tanh')(embed_comment)
        l_pool = MaxPooling1D(maxlen - fsz + 1)(l_conv)
        l_pool = Flatten()(l_pool)
        convs.append(l_pool)
    merge = concatenate(convs, axis=1)

    out = Dropout(0.5)(merge)
    output = Dense(32, activation='relu')(out)

    output = Dense(units=1, activation='sigmoid')(output)

    model = Model([comment_seq], output)
    model.compile(loss="binary_crossentropy", optimizer="adam", metrics=['accuracy'])
    return model

model = word2vec2keras_cnn()
print(model.summary())
           

6.模型结构(图太大,只显示出来一部分)

Keras 模型中使用预训练的词向量(用word2vec替换keras自带的Embedding层)

7.实验结果

用Keras中自带的Embedding层的精确度为:0.86

Keras 模型中使用预训练的词向量(用word2vec替换keras自带的Embedding层)

用Word2vec替换Keras中自带的Embedding层精确度为:0.87

Keras 模型中使用预训练的词向量(用word2vec替换keras自带的Embedding层)

精确度有少量的提升,证明了word2vec的有效性。提升幅度小很有可能是因为我训练word2vec模型的语料库与我的测试集的语料库有一定差距,如果用相似的语料库训练word2vec模型作为预训练的初始参数,效果应该会更好。

继续阅读