Keras深度学习实战(24)——从零开始构建单词向量

Posted 盼小辉丶

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Keras深度学习实战(24)——从零开始构建单词向量相关的知识,希望对你有一定的参考价值。

Keras深度学习实战(24)——从零开始构建单词向量

0. 前言

在解决文本相关问题时,传统方法通常需要对单词进行独热编码。但是,如果数据集中具有数千个不同的单词,则生成的独热编码矢量将具有数千个维度,这会导致计算代价十分高昂。此外,在这种情况下,相似的单词并不具备相似的向量。因此,我们需要研究如何对文本数据进行编码,以使相似的数据具有相似的编码向量。

1. 单词向量

1.1 Word2Vec 原理

Word2Vec 是一种可以将相似单词编码为相似向量的方法。在了解 Word2Vec 原理之前,我们首先考虑以下问题,假设我们有以下输入句子

I love watching movie
I like watching movie

传统方法中,对单词进行独热编码,输出结果如下所示:

单词独热编码
I10000
love01000
watching00100
movie00010
like00001

我们知道,在语义上,lovelike 是相似的词。但是,使用独热编码单词 Ilike 之间的欧式距离与 lovelike 之间的欧式距离相同,不能体现出 lovelike 之间的语义相似性。但是,我们知道 lovelike 之间的距离应小于 Ilike 之间的距离,因为 lovelike 之间的语义更加相似。

1.2 构建单词向量

构建单词向量的核心思想是,在向量空间中,每个单词周围都存在着与之相似的单词。例如:“queen” 和 “princess” 单词的周围会出现类似的词,如“kingdom”。从某种意义上说,这些词的上下文同样是相似的。
依旧使用上一节中的两个句子,当我们一个句子中的某个单词作为输出,而句子中的其余单词作为输入时,可以构造以下数据集:

输入输出
lovewatchingmovieI
Iwatchingmovielove
Ilovemoviewatching
Ilovewatchingmovie
likewatchingmovieI
Iwatchingmovielike
Ilikemoviewatching
Ilikewatchingmovie

当我们将某一个单词用作输出,其余单词用作输入,将输入和输出进行独热编码后得到以下形式的向量:

输入向量输出向量
0111010000
1011001000
1101000100
1110000010
0011110000
1011000001
1001100100
1010100010

可以看到,输入向量的第一行为 0, 1, 1, 1, 0,因为输入单词的索引为 1, 2, 3,输出为 1, 0, 0, 0, 0,因为输出单词的索引为 0

1.3 神经网络架构

如果我们使用的神经网络中隐藏层包含三个神经元,则神经网络架构如下所示:

网络中每层的信息如下:

网络层尺寸描述
输入层5每个输入向量尺寸为 5
输入层权重5x3隐藏层中的 3 个神经元各有 5 个连接到输入层的权重
隐藏层3隐藏层包含 3 个神经元
输出层权重3x5由于有 5 个不同单词,因此 3 个隐藏单元输出映射到输出层的 5 个输出
输出层5输出向量的尺寸为 5,每一单词对应一个预测单词概率

在构建单词向量时,在隐藏层中并不使用激活函数。使用 softmax 函数处理输出层输出值,以便得到单词概率,使用交叉熵损失作为损失函数,使用 Adam 优化器优化网络权重值。当向网络中输入单词(而非输入语句)的独热编码时,给定单词的编码向量可以使用隐藏层的输出值表示。

2. 使用 Keras 从零开始构建单词向量

根据我们在上一小节中介绍的单词向量的生成方式,我们使用 Keras 实现单词编码向量神经网络。

(1) 首先,定义输入句子:

docs = ["I love watching movie", "I like watching movie"]

在以上语句中,我们期望 lovelike 的词向量是相似的,因为 lovelike 的上下文是完全相同的。
(2) 然后,我们为每个句子创建一个独热编码:

from sklearn.feature_extraction.text import CountVectorizer
vectorizer = CountVectorizer(min_df=0, token_pattern=r"\\b\\w+\\b")
vectorizer.fit(docs)

vectorizer 定义了将文档转换为向量格式的参数。此外,通过传递参数 min_df 确保在 CountVectorizer 中不会过滤掉诸如 I 之类的词,使用定义的输入句子拟合 vectorizer 得到合适的单词向量化模型。

(3) 将文档 docs 转换为向量格式:

vector = vectorizer.transform(docs)

(4) 验证执行转换后的语句向量:

print(vectorizer.vocabulary_)
print(vector.shape)
print(vector.toarray())

vocabulary_ 返回各种单词的索引,而 vector.toarray 将返回句子的独热编码,输出结果如下:

'i': 0, 'love': 2, 'watching': 4, 'movie': 3, 'like': 1
(2, 5)
[[1 0 1 1 1]
 [1 1 0 1 1]]

(5) 创建输入和输出数据集:

x = []
y = []
for i in range(len(docs)):
    for j in range(len(docs[i].split())):
        t_x = []
        t_y = []
        for k in range(4):
            if(j==k):
                t_y.append(docs[i].split()[k])
                continue
            else:
                t_x.append(docs[i].split()[k])
        x.append(t_x)
        y.append(t_y)

x2 = []
y2 = []
for i in range(len(x)):
    x2.append(' '.join(x[i]))
    y2.append(' '.join(y[i]))

从前面的代码中,我们创建了输入和输出数据集,我们可以打印数据集,查看其内容:

print(x2)
print(y2)

打印出的输入和输出数据如下:

['love watching movie', 'I watching movie', 'I love movie', 'I love watching', 'like watching movie', 'I watching movie', 'I like movie', 'I like watching']
['I', 'love', 'watching', 'movie', 'I', 'like', 'watching', 'movie']

(6) 将前面的输入和输出单词转换为向量:

vector_x = vectorizer.transform(x2)
vector_y = vectorizer.transform(y2)

vector_x = vector_x.toarray()
vector_y = vector_y.toarray()
# 打印输入与输出数组
print('Input: ', vector_x)
print('Output: ' vector_y)

打印出的输入和输出数组如下:

Input: [[0 0 1 1 1]
 [1 0 0 1 1]
 [1 0 1 1 0]
 [1 0 1 0 1]
 [0 1 0 1 1]
 [1 0 0 1 1]
 [1 1 0 1 0]
 [1 1 0 0 1]]
Output: [[1 0 0 0 0]
 [0 0 1 0 0]
 [0 0 0 0 1]
 [0 0 0 1 0]
 [1 0 0 0 0]
 [0 1 0 0 0]
 [0 0 0 0 1]
 [0 0 0 1 0]]

(7) 根据在上一小节中定义的神经网络,构建神经网络模型:

from keras.layers import Dense
from keras.models import Sequential
model = Sequential()
model.add(Dense(3, input_shape=(5,)))
model.add(Dense(5,activation='sigmoid'))
model.summary()

模型简要架构信息输入如下:

Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense (Dense)                (None, 3)                 18        
_________________________________________________________________
dense_1 (Dense)              (None, 5)                 20        
=================================================================
Total params: 38
Trainable params: 38
Non-trainable params: 0
_________________________________________________________________

(8) 编译并拟合模型:

model.compile(loss='categorical_crossentropy',optimizer='adam')
model.fit(vector_x, vector_y, epochs=1000, batch_size=2,verbose=1)

(9) 通过获取中间层值来提取词向量,其中输入是每个单个词的编码向量:

from keras.models import Model
layer_name = 'dense'
intermediate_layer_model = Model(inputs=model.input,outputs=model.get_layer(layer_name).output)

在以上代码中,我们从目标层中提取输出——通过模型中的名为 dense 的层获取单词编码向量。

(10) 接下来,向网络中传递单词的独热编码向量作为输入,提取中间层的输出:

for i in range(len(vectorizer.vocabulary_)):
     word = list(vectorizer.vocabulary_.keys())[i]
     word_vec = vectorizer.transform([list(vectorizer.vocabulary_.keys())[i]]).toarray()
     print(word, intermediate_layer_model.predict(word_vec))

各个单词的编码向量如下:

i [[-1.41066     0.02432728 -1.0654368 ]]
love [[-1.1692711   1.7719828   0.54331756]]
watching [[ 1.163808   1.908086  -1.5191256]]
movie [[0.01165223 2.0688105  1.532387  ]]
like [[-1.197992   1.662775   0.5817174]]

可以看出,在以上单词编码向量中,“love” 和 “like” 这两个单词之间的相关性更高,因此可以更好地表示单词向量。

3. 测量单词向量之间的相似度

有多种用于度量测量单词向量之间的相似度的方法,以下是两种较常见的度量方法:

  • 余弦相似度
  • 欧氏距离

两个不同向量 AB 之间的余弦相似度计算如下:

s i m i l a r i t y = c o s ( θ ) = A ⋅ B ∥ A ∥ 2 ∥ B ∥ 2 = ∑ i = 1 n A i B i ∑ i = 1 n A i 2 ∑ i = 1 n B i 2 similarity=cos(\\theta)=\\frac A \\cdot B \\Vert A \\Vert_2 \\Vert B \\Vert_2=\\frac \\sum_i=1^nA_iB_i\\sqrt\\sum_i=1^nA_i^2\\sqrt\\sum_i=1^nB_i^2 similarity=cos(θ)=A2B2AB=i=1nAi2 i=1nBi2 i=1nAiBi

例如在上一小节构建的单词向量示例中,“love” 和 “like” 之间的余弦相似度计算方法如下:

(1)love” 和 “like” 的单词向量如下:

enjoy = (-1.17, 1.77, 0.54)
like = (-1.20, 1.66, 0.58)

(2)love” 向量和 “like” 向量之间的余弦相似度:

( ( − 1.17 ) × ( − 1.20 ) + 1.77 × 1.66 + 0.54 × 0.58 ) ( − 1.17 ) 2 + 1.7 7 2 + 0.5 4 2 ( − 1.20 ) 2 + 1.6 6 2 + 0.5 8 2 = 0.998826867 \\frac ((-1.17)\\times(-1.20)+1.77\\times1.66+0.54\\times0.58)\\sqrt(-1.17)^2+1.77^2+0.54^2\\sqrt(-1.20)^2+1.66^2+0.58^2=0.998826867 (1.17)2+1.772+0.542 (1.20)2+1.662+0.582 ((1.17)×(1.20)+1.77×1.66+0.54×0.58)=0.998826867

两个不同向量 AB 之间的欧式距离计算如下:

E u c l e d i a n = ( A − B ) 2 =

以上是关于Keras深度学习实战(24)——从零开始构建单词向量的主要内容,如果未能解决你的问题,请参考以下文章

Keras深度学习实战(26)——文档向量详解

Keras深度学习实战(26)——文档向量详解

Keras深度学习实战(27)——循环神经详解与实现

Keras深度学习实战(27)——循环神经详解与实现

Keras深度学习实战——使用Keras构建神经网络

Keras深度学习实战——使用GloVe模型构建单词向量