0.简介
文字2vec是生成单词分布式表示的工具,由Mikolov等人[1]提出。当工具指定实值向量时对于每个单词,单词的意思越接近,相似性就越大矢量将指示。
分布式表示意味着为每个变量分配一个实值向量单词并用向量表示单词。用表示单词时分布式表示,我们称之为单词嵌入.在本教程中,我们旨在解释如何从Penn Tree Bank数据集。
让我们想想单词的意思。既然我们是人,我们就可以要明白,“动物”和“狗”这两个词是密切相关的。但是Word2vec将使用什么信息来学习单词的向量呢?单词“动物”和“狗”应该有相似的载体,但“食物”和“狗”这两个词应该彼此远离。如何自动知道这些单词的特征?
1.基本思路
Word2vec从简单的信息中学习词义的相似性。它学习句子中单词的表示。核心思想基于假设单词的意思受其周围单词的影响分布假说[2].
我们重点学习它的表示法的单词叫做中心词,它周围的单词叫做上下文词.窗户大小\(C)确定要考虑的上下文词的数量。
这里,让我们用一个示例句子来看看算法:“那只可爱的猫跳过了那只懒狗。”.
- 以下所有数字都将“cat”作为中心词。
- 根据窗户尺寸\(C\),您可以看到上下文单词的数量发生了变化。
2.主要算法
创建单词嵌入的工具Word2vec实际上是由两个模型构建,这两个模型称为Skip-gram(跳过粒度)和CBoW公司.
为了用下图解释模型,我们将使用以下内容符号。
符号 |
定义 |
\(|\mathcal{V}|\) |
词汇的大小 |
\(D\) |
嵌入向量的大小 |
\({\bf v}_t\) |
一个单热点单词向量 |
\(V_{t\pm C}\) |
一套\(2C\)周围的上下文向量\({\bf v}_t\)即,\(\{\bf v}_{t+c}\}_{c=-c}^c\反斜杠{\bf v}_t\) |
\({\bf l}_H\) |
输入词向量的嵌入向量 |
\({\bf l}_O\) |
网络的输出向量 |
\({\bf W}_H\) |
输入的嵌入矩阵 |
\({\bf W}_O\) |
输出的嵌入矩阵 |
注释
使用负采样或分层softmax弥补损失函数非常常见,但是在本教程中,我们将使用softmax覆盖所有单词并跳过其他变体简单。
2.1 Skip-gram
这个模型学习预测上下文单词\(V_{t\pm C}\)当一个中心词\({\bf v}_t\)给出了。在模型中,嵌入的每一行输入矩阵\({\bf W}_H\)成为每个单词的单词嵌入。
当你输入中心词时\({\bf v}_t\)接入网络,你可以预测上下文中的一个单词\(在v{t\pmC}中是{bfv}{t+c})如下:
- 计算输入中心词向量的嵌入向量:\({\bf l}_H={\bf-W}_H{\bv-v}_t\)
- 计算嵌入向量的输出向量:\({\bf l}_O={\bv W}_O{\bf-l}_H\)
- 计算上下文词的概率向量:\({bfv}_{t+c}=\text{softmax}({bfl}_O))
每个元素\(|\mathcal{V}|\)-量纲向量\({bfv}{t+c}\)是一个概率词汇表中的一个单词在位置上是上下文单词\(c).所以,概率\(p({\bfv}{t+c}|{\bf v}_t)\)可以通过一个热向量的点积来估计\({\bfv}{t+c}\)表示该位置的实际单词\(c)和输出矢量\({bfv}{t+c}\).
\[p({\bfv}_{t+c}|{\bf v}_t)={\bf-v}_{t+c}^t
预测所有上下文单词的损失函数\(V_{t\pm C}\)给出中心词\({\bf v}_t\)定义如下:
\[\开始{拆分}L(V_{t\pmC}|{\bfv}_t;{\bf W}_H,{\bf-W}_O)&=\sum_{V_{t\pmC}}-\log\left(p({\bv}_{t+C}\mid{\bv}_t)\right)\\&=\sum_{V_{t\pm C}}-\log({\bfv}_{t+C}^t\hat{\bf V}{t+C})\end{split}\]
2.2连续单词包(CBoW)
这个模型学习预测中心词\({\bf v}_t\)当上下文单词\(V_{t\pm C}\)给出了。当你给出一组上下文词时\(V_{t\pm C}\)对于网络,您可以估计中心词\({\bf v}_t\)如下:
- 计算所有上下文单词的平均嵌入向量:\({\bf-l}_H=\frac{1}{2C}\sum_{V{t\pmC}}{\bf W}_H{\bfv}_{t+C})
- 计算嵌入向量的输出向量:\({\bf l}_O={\bv W}_O{\bf-l}_H\)
- 计算中心词的概率向量:\(hat{\bf v}_t=\text{softmax}({\bf l}_O)\)
每个元素\(|\mathcal{V}|\)-量纲向量\({\bf v}_t\)是一个概率词汇表中的一个单词是中心词。所以,概率\(p({\bf v}_t|v_{t\pm C})\)可以通过一个热向量的点积来估计\({\bf v}_t\)表示实际中心词和输出向量\(hat{\bf v}_t).
\[p({\bfv}_t|v_{t\pm C})={\bf v}_t^t\hat{\bf-v}_t\]
预测中心词的损失函数\({\bf v}_t\)给定上下文词\(V_{t\pm C}\)定义如下:
\[\开始{拆分}L({\bf-v}_t|v_{t\pm C};{\bf W}_H,{\bv W}_O)&=-\log\left(p({\bf v}_t\mid v_{t\pm C{)\right)\\&=-\log({\bf v}_t^t\hat{\bv v}_t)\end{split}\]
3.Skip-gram的详细信息
在本教程中,我们主要解释Skip-gram模型,因为
- 该算法比CBoW更容易理解。
- 即使单词数量增加,准确度也基本保持不变。因此,它的可扩展性更强。
因此,让我们考虑一个在此设置下计算Skip-gram的具体示例:
- 词汇的大小\(|\mathcal{V}|\)为10。
- 嵌入向量的大小\(D\)为2。
- 中心词是“狗”。
- 上下文词是“动物”。
因为应该有多个上下文单词,所以对每个上下文单词重复以下过程。
- “dog”的一个热点向量是
[0 0 1 0 0 0 0 0 0 0]
然后将其输入为中心词。
- 嵌入矩阵的第三行\({\bf W}_H\)用于单词“dog”的嵌入\({\bf l}_H\).
- 然后,乘法\({\bf W}_O\)具有\({\bf l}_H\)以获得输出矢量\({\bf l}_O\).
- 给予\({\bf l}_O\)到softmax函数,使其成为预测概率矢量\({bfv}{t+c}\)位置处的上下文词\(c).
- 计算两者之间的误差\({bfv}{t+c}\)和单热向量“动物”;
[1 0 0 0 0 0 0 0 0 0 0]
.
- 将错误传播回网络以更新参数。
4.在Chainer中实现Skip-gram
Chainer的官方存储库中有一个Word2vec示例,因此,我们将在此基础上解释如何实现Skip-gram:示例/word2vec
4.1准备
首先,让我们导入必要的包:
火车字2vec.py
进口 参数解析
进口 收藏
进口 努皮 作为 净现值
进口 六
进口 链子
从 链器后端 进口 库达
进口 链接器.函数 作为 F类
进口 链器初始化器 作为 我
进口 链接器链接 作为 L(左)
进口 链接器.优化器 作为 O(运行)
从 链子 进口 记者
从 链子 进口 训练
从 链子训练 进口 扩展
4.2定义Skip-gram模型
接下来,让我们为Skip-gram定义一个网络。
火车字2vec.py
班 SkipGram公司(链子.链条):
“”“Skip gram模型的定义”“”
定义 __初始化__(自己, n_声控, n个单位, 损失(_func)):
超级的(SkipGram公司, 自己).__初始化__()
具有 自己.初始化作用域():
自己.嵌入 = L(左).嵌入ID(
n_声控, n个单位, 缩写W=我.制服(1 / n个单位))
自己.损失(_func) = 损失(_func)
定义 向前地(自己, x个, 上下文):
e(电子) = 自己.嵌入(上下文)
批处理大小, n_上下文, n个单位 = e(电子).形状
x个 = F类.广播到(x个[:, 无], (批处理大小, n_上下文))
e(电子) = F类.重塑(e(电子), (批处理大小 * 上下文(_C), n个单位))
x个 = F类.重塑(x个, (批处理大小 * n_上下文,))
损失 = 自己.损失(_func)(e(电子), x个)
记者.报告({“损失”: 损失}, 自己)
返回 损失
火车字2vec.py
班 Softmax交叉熵损失(链子.链条):
“”“Softmax交叉熵损失函数前面是线性变换。
"""
定义 __初始化__(自己, n英寸, n出):
超级的(Softmax交叉熵损失, 自己).__初始化__()
具有 自己.初始化作用域():
自己.外面的 = L(左).线性的(n英寸, n出, 缩写W=0)
定义 向前地(自己, x个, t吨):
返回 F类.软最大交叉熵(自己.外面的(x个), t吨)
注释
- 权重矩阵
自我嵌入。W公司
是输入向量的嵌入矩阵x个
.
- 函数调用
向前地
获取中心单词的单词IDx个
和上下文单词上下文的单词ID作为输入,并输出计算的错误通过损失函数损失(_func)
科学技术。Softmax交叉熵损失
.
- 请注意,的初始形状
x个
和上下文是(批大小,)
和(批大小, n_上下文)
分别为。
- 这个
批量_大小
指迷你背带的尺寸,以及n_上下文
是指上下文单词的数量。
首先,我们通过以下方法获得上下文的嵌入向量e(电子) = self.embed(上下文)
.然后F.broadcast_to(x[:, 无], (批大小, n_上下文)
执行的广播x个
(它的形状是(批大小,)
)至(批大小, n_上下文)
通过复制相同的值n_上下文
填充第二个轴的时间,然后广播x个
被重塑为一维向量(批量 * n_上下文,)
虽然e(电子)
被重塑为(批大小 * n_上下文, n个单位)
.在Skip-gram模型中,从中心词预测上下文词与根据上下文词预测中心词,因为中心词总是将上下文词视为中心词时的上下文词。因此,我们创建批处理大小 * n_上下文
应用中心词预测自行退出
线性的层到上下文词的嵌入向量。然后,计算softmax交叉广播中心词ID x和预测之间的熵。
4.3准备数据集和迭代器
让我们使用Chainer的数据集实用程序检索Penn Tree Bank(PTB)数据集获取文本()
方法。
火车, val值, _ = 链子.数据集.获取ptb_words()
计数 = 收藏.计数器(火车)
然后定义一个迭代器,以生成包含一组中心词及其上下文词的迷你标签。火车
和val值
指培训数据和验证数据。每个数据都包含文档ID列表:
>>>列车数组([0,1,2,…,39,26,24],数据类型=int32)
>>>val值数组([22113961129,…,108,27,24],数据类型=int32)
火车字2vec.py
班 WindowIterator(窗口迭代器)(链子.数据集.迭代器):
“”“数据集迭代器,用于在不同位置创建一批序列。
这个迭代器返回一对当前单词和上下文单词。
"""
定义 __初始化__(自己, 数据集, 窗口, 批处理大小, 重复=真的):
自己.数据集 = 净现值.阵列(数据集, 净现值.整数32)
自己.窗口 = 窗口 #上下文窗口的大小
自己.批处理大小 = 批处理大小
自己._重复 = 重复
#order是被洗牌的数组``[window,window+1。。。,
#len(数据集)-窗口-1]``
自己.秩序 = 净现值.随机的,随机的.置换(
伦恩(数据集) - 窗口 * 2).astype类型(净现值.整数32)
自己.秩序 += 窗口
自己.当前位置(_P) = 0
#数据集上已完成的扫描数。在这种情况下,它是
#如果每个单词在最后一个单词之后至少访问一次,则递增
#增量。
自己.纪元 = 0
#如果历元在最后一次迭代时递增,则为True。
自己.是_新_波什 = False(错误)
定义 __下一个__(自己):
“”“此迭代器返回一个表示迷你背带的列表。
每个项目指示原始序列中的不同位置。
"""
如果 不 自己._重复 和 自己.纪元 > 0:
提升 停止迭代
我 = 自己.当前位置(_P)
结束(_E) = 我 + 自己.批处理大小
位置 = 自己.秩序[我:结束(_E)]
w个 = 净现值.随机的,随机的.兰丁(自己.窗口 - 1) + 1
抵消 = 净现值.连接([净现值.阿兰奇(-w个, 0), 净现值.阿兰奇(1, w个 + 1)])
销售时点情报系统 = 位置[:, 无] + 抵消[无, :]
上下文 = 自己.数据集.拿(销售时点情报系统)
中心 = 自己.数据集.拿(位置)
如果 结束(_E) >= 伦恩(自己.秩序):
净现值.随机的,随机的.洗牌(自己.秩序)
自己.纪元 += 1
自己.是_新_波什 = 真的
自己.当前位置(_P) = 0
其他的:
自己.是_新_波什 = False(错误)
自己.当前位置(_P) = 结束(_E)
返回 中心, 上下文
@财产
定义 epoch_detail(epoch_detail)(自己):
返回 自己.纪元 + 浮动(自己.当前位置(_P)) / 伦恩(自己.秩序)
定义 序列化(自己, 序列化程序):
自己.当前位置(_P) = 序列化程序('当前位置',
自己.当前位置(_P))
自己.纪元 = 序列化程序(“epoch”, 自己.纪元)
自己.是_新_波什 = 序列化程序(“is_new_epoch”, 自己.是_新_波什)
如果 自己._订单 是 不 无:
序列化程序('顺序(_O)', 自己._订单)
- 在构造函数中,我们创建了一个数组
自我订购
表示混洗的索引[窗口, 窗口 + 1, ..., len(数据集) - 窗口 - 1]
为了从迷你背包中的数据集中随机选择一个中心词。
- 迭代器定义
__下一个__
退货批处理大小
中心词集和上下文词。
- 代码
自我排序[i:i_end]
返回一组中心词的索引从随机有序数组自我订购
。中心单词ID位于随机索引检索方法自我数据库获取
.
np.连接([np.arange(-w, 0), np.arange(1, w个 + 1)])
创建一组从数据集中检索上下文单词的偏移量。
- 代码
位置[:, 无] + 偏移量[无, :]
生成上下文索引每个中心单词索引的单词。上下文单词ID上下文是检索者自我数据库获取
.
4.4准备模型、优化器和更新程序
火车字2vec.py
模型 = SkipGram公司(n_声控, 参数.单元, 损失(_func))
列车_列车2矢量.py
优化器 = O(运行).亚当()
优化器.设置(模型)
火车字2vec.py
列车_仪表 = WindowIterator(窗口迭代器)(火车, 参数.窗口, 参数.批量)
值(_I) = WindowIterator(窗口迭代器)(val值, 参数.窗口, 参数.批量, 重复=False(错误))
#设置更新程序
更新程序 = 训练.更新程序.标准更新程序(
列车_仪表, 优化器, 转换器=转换, 装置=参数.通用程序单元)
火车字2vec.py
教练 = 训练.教练(更新程序, (参数.纪元, “epoch”), 外面的=参数.外面的)
教练.延伸(扩展.评价人(
值(_I), 模型, 转换器=转换, 装置=参数.通用程序单元))
教练.延伸(扩展.日志报告())
教练.延伸(扩展.打印报告(
[“epoch”, '主要/损失', '验证/主/损失']))
教练.延伸(扩展.进度栏())
教练.运行()
4.5开始培训
$ 密码
/root2chainer/chainer/examples/word2vec
$python train_word2vec.py--测试#按测试模式运行。如果要使用所有数据,请删除“--test”。
GPU:-1
#单位:100
窗口:5
小批量:1000
#历元:20
培训模式:skipgram
输出类型:hsm
n_vocab:10000个
数据长度:100
epoch主/损失验证/主/损失
1 4233.75 2495.33
2 1411.14 4990.66
3 4233.11 1247.66
4 2821.66 4990.65
5 4231.94 1247.66
6 5642.04 2495.3
7 5640.82 4990.64
8 5639.31 2495.28
9 2817.89 4990.62
10 1408.03 3742.94
11 5633.11 1247.62
12 4221.71 2495.21
13 4219.3 4990.56
14 4216.57 2495.16
15 4213.52 2495.12
16 5616.03 1247.55
17 5611.34 3742.78
18 2800.31 3742.74
19 1397.79 2494.95
20 2794.1 3742.66
4.5搜索相似的单词
$ 密码
/root2chainer/chainer/examples/word2vec
$python搜索.py>>苹果查询:苹果
公司:0.6169619560241699
芯片:0.49579331278800964
零售商:0.4904134273529053
制造商:0.4684058427810669
计算机:0.4652436673641205
>>动物查询:动物
美女:0.5680124759674072
人类:0.5404794216156006
胰岛素:0.536515653133923
手机:0.5186758041381836
照片:0.5077002048492432