[ DLPytorch ] word2vec&词嵌入
word2vec
WordEmbedding
对词汇进行多维度的描述,形成一个密集的矩阵。这样每两个词之间的相似性可以通过进行内积的大小体现出来。越大说明距离越远,则越不相似。
Analogies(类比):将男-女和国王-女王做类比,比如将表示‘男’的词向量与‘女’的词向量相减,同理国王和女王也相减,得出来的矩阵近乎相等,则说明这两个对比在某种维度上是相似的。
Cosine similarities: 求解相似度。给出男、女、国王,找到女王的索引。
初始化E,与one-hot矩阵相称,得到对应的embedding。将各个词(一个batch)的embedding做线性变换,且经过softmax后得到某个词的embedding,做交叉熵。再反向传播更新E。
##两种模型
word2vec包含跳字Skip-Gram模型和连续词袋CBOW模型。
**跳字模型**:基于中心词来生成背景词。
**连续词袋模型假设**:基于背景词来生成中心词。
数据处理
二次采样
文本数据中一般会出现一些高频词,如英文中的“the”“a”和“in”。通常来说,在一个背景窗口中,一个词(如“chip”)和较低频词(如“microprocessor”)同时出现比和较高频词(如“the”)同时出现对训练词嵌入模型更有益。因此,训练词嵌入模型时可以对词进行二次采样 [2]。
具体来说,数据集中每个被索引词\(w_i\)将有一定概率被丢弃,该丢弃概率为
\]
其中 \(f(w_i)\) 是数据集中,词\(w_i\)的个数与总词数之比,常数\(t\)是一个超参数(实验中设为\(10^{-4}\))。可见,只有当\(f(w_i) > t\)时,我们才有可能在二次采样中丢弃词\(w_i\),并且越高频的词被丢弃的概率越大,低频词会被完整的保留下来。
提取中心词和背景词
将与中心词距离不超过背景窗口大小的词作为它的背景词。下面定义函数提取出所有中心词和它们的背景词。它每次在整数1和max_window_size
(最大背景窗口)之间随机均匀采样一个整数作为背景窗口大小。
def get_centers_and_contexts(dataset, max_window_size):
centers, contexts = [], []
for st in dataset:
if len(st) < 2: # 每个句子至少要有2个词才可能组成一对“中心词-背景词”
continue
centers += st
for center_i in range(len(st)):
window_size = random.randint(1, max_window_size)
indices = list(range(max(0, center_i - window_size),
min(len(st), center_i + 1 + window_size)))
indices.remove(center_i) # 将中心词排除在背景词之外
contexts.append([st[idx] for idx in indices])
return centers, contexts
下面我们创建一个人工数据集,其中含有词数分别为7和3的两个句子。设最大背景窗口为2,打印所有中心词和它们的背景词。
tiny_dataset = [list(range(7)), list(range(7, 10))]
print('dataset', tiny_dataset)
for center, context in zip(*get_centers_and_contexts(tiny_dataset, 2)):
print('center', center, 'has contexts', context)
输出:
dataset [[0, 1, 2, 3, 4, 5, 6], [7, 8, 9]]
center 0 has contexts [1, 2]
center 1 has contexts [0, 2, 3]
center 2 has contexts [1, 3]
#...
负采样
我们使用负采样来进行近似训练。对于一对中心词和背景词,我们随机采样\(K\)个噪声词(实验中设\(K=5\))。根据word2vec论文的建议,噪声词采样概率\(P(w)\)设为\(w\)词频与总词频之比的0.75次方 [2]。
choices(population, weights=None, *, cum_weights=None, k=1):从population中进行K次随机选取,每次选取一个元素(注意会出现同一个元素多次被选中的情况),weights是相对权重值,population中有几个元素就要有相对应的weights值,cum_weights是累加权重值,例如,相对权重〔10, 5, 30,5〕相当于累积权重〔10, 15, 45,50〕。在内部,在进行选择之前,相对权重被转换为累积权重,因此提供累积权重节省了工作。返回一个列表。
这部分的populiation我一直有点疑问。不过要是想解释得通的话,大概就是:在该数据集中,没有重复的word序列长度为9000多,同时我们已经把它key-value相对应好了,并且sub下存储的是二次采样后的数据集的所对应word的序列。
所以population取值味sampling_weights的长度,而sampling_weights也代表了每个词出现的相对频率。
choices函数,根据相对概率,从population中抽取一个值,总共抽取100,000次,肯定会有重复的数字。
假设矩阵第一行,长度为5,所以本行的噪声词为25个。i = 25
然后来到下一行,长度还是为5,就再接着读取25个。结束时 i = 50。
之后以此类推。。
如果候选词全都被选择完了了,那么重新再生成1e5个。
def get_negatives(all_contexts, sampling_weights, K):
all_negatives, neg_candidates, i = [], [], 0
population = list(range(len(sampling_weights)))
# 1 ~ 9000多
for contexts in all_contexts:
negatives = []
#噪声词是本层长度的5倍!!这不是废话吗!
#一个中心词会有多个配对的背景词,每个中心词选择5个背景词,那肯定就是5倍咯!
while len(negatives) < len(contexts) * K:
#候选词不够了就补充
if i == len(neg_candidates):
# 根据每个词的权重(sampling_weights)随机生成k个词的索引作为噪声词。
# 为了高效计算,可以将k设得稍大一点
# candidate:选择100,000个词作为其候选的上下文。 干扰因素 相当于分类问题 0
i, neg_candidates = 0, random.choices(
population, sampling_weights, k=int(1e5))
#然后在nevigate个数不满足的情况下,从candidate中挑选前T个。最后再加入
neg, i = neg_candidates[i], i + 1
# 噪声词不能是背景词
if neg not in set(contexts):
negatives.append(neg)
#最后再加入所有噪声词中,此时len(all_contexts) 对应了 len(all_contexts) * 5
#即每个中心词对应5个噪声词。
all_negatives.append(negatives)
return all_negatives
#该词词频 ** 0.75
sampling_weights = [counter[w]**0.75 for w in idx_to_token]
all_negatives = get_negatives(all_contexts, sampling_weights, 5)
跳字模型
嵌入层
获取词嵌入的层称为嵌入层,在PyTorch中可以通过创建nn.Embedding
实例得到。嵌入层的权重是一个矩阵,其行数为词典大小(num_embeddings
),列数为每个词向量的维度(embedding_dim
)。我们设词典大小为20,词向量的维度为4。
如果每次取一个batch进行处理的话,那么词典大小也就相当于batchsize了
embed = nn.Embedding(num_embeddings=20, embedding_dim=4)
嵌入层的输入为词的索引。输入一个词的索引\(i\),嵌入层返回权重矩阵的第\(i\)行作为它的词向量。下面我们将形状为(2, 3)的索引输入进嵌入层,由于词向量的维度为4,我们得到形状为(2, 3, 4)的词向量。
x = torch.tensor([[1, 2, 3], [4, 5, 6]], dtype=torch.long)
embed(x)
跳字模型的前向计算
在前向计算中,跳字模型的输入包含中心词索引center
以及连结的背景词与噪声词索。引contexts_and_negatives
。其中center
变量的形状为(批量大小, 1, 1),而contexts_and_negatives
变量的形状为(批量大小, max_len
, 1)。这两个变量先通过词嵌入层分别由词索引变换为词向量,再通过小批量乘法得到形状为(批量大小, 1, max_len
)的输出。输出中的每个元素是中心词向量与背景词向量或噪声词向量的内积。
想了我好久一直没明白它们是干嘛使的。好像有点懂了。
先把center转化为词向量,它在转化过程中的参数是随机的,所以尽管它是个300维的向量,结果可能和我们期望的vector表示有很大的区别,所以需要在backpropagation中优化W参数。
与此同时,也要把背景词和噪声词的组合转化为词向量,同样也是300维的。求得两者的内积。
def skip_gram(center, contexts_and_negatives, embed_v, embed_u):
v = embed_v(center)
u = embed_u(contexts_and_negatives)
#permute交换维度
pred = torch.bmm(v, u.permute(0, 2, 1))
return pred
损失函数的定义
我们可以通过掩码变量指定小批量中参与损失函数计算的部分预测值和标签:当掩码为1时,相应位置的预测值和标签将参与损失函数的计算;当掩码为0时,相应位置的预测值和标签则不参与损失函数的计算。掩码变量可用于避免填充项对损失函数计算的影响。
class SigmoidBinaryCrossEntropyLoss(nn.Module):
def __init__(self): # none mean sum
super(SigmoidBinaryCrossEntropyLoss, self).__init__()
def forward(self, inputs, targets, mask=None):
"""
input – Tensor shape: (batch_size, len)
target – Tensor of the same shape as input
"""
inputs, targets, mask = inputs.float(), targets.float(), mask.float()
res = nn.functional.binary_cross_entropy_with_logits(inputs, targets, reduction="none", weight=mask)
return res.mean(dim=1)
loss = SigmoidBinaryCrossEntropyLoss()
应用词嵌入模型
torch.topk()
torch.topk(input, k, dim=None, largest=True, sorted=True, out=None) -> (Tensor, LongTensor)
沿给定dim维度返回输入张量input中 k 个最大值。
如果不指定dim,则默认为input的最后一维。
如果为largest为 False ,则返回最小的 k 个值。
返回一个元组 (values,indices),其中indices是原始输入张量input中测元素下标。
如果设定布尔值sorted 为_True_,将会确保返回的 k 个值被排序。
参数:
input (Tensor) – 输入张量
k (int) – “top-k”中的k
dim (int, optional) – 排序的维
largest (bool, optional) – 布尔值,控制返回最大或最小值
sorted (bool, optional) – 布尔值,控制返回值是否排序
out (tuple, optional) – 可选输出张量 (Tensor, LongTensor) output buffer
[ DLPytorch ] word2vec&词嵌入的更多相关文章
- L25词嵌入进阶GloVe模型
词嵌入进阶 在"Word2Vec的实现"一节中,我们在小规模数据集上训练了一个 Word2Vec 词嵌入模型,并通过词向量的余弦相似度搜索近义词.虽然 Word2Vec 已经能够成 ...
- 词向量表示:word2vec与词嵌入
在NLP任务中,训练数据一般是一句话(中文或英文),输入序列数据的每一步是一个字母.我们需要对数据进行的预处理是:先对这些字母使用独热编码再把它输入到RNN中,如字母a表示为(1, 0, 0, 0, ...
- 词嵌入之Word2Vec
词嵌入要解决什么问题 在自然语言系统中,词被看作最为基本的单元,如何将词进行向量化表示是一个很基本的问题,词嵌入(word embedding)就是把词映射为低维实数域向量的技术. 下面先介绍几种词的 ...
- DeepLearning.ai学习笔记(五)序列模型 -- week2 自然语言处理与词嵌入
一.词汇表征 首先回顾一下之前介绍的单词表示方法,即one hot表示法. 如下图示,"Man"这个单词可以用 \(O_{5391}\) 表示,其中O表示One_hot.其他单词同 ...
- DLNg序列模型第二周NLP与词嵌入
1.使用词嵌入 给了一个命名实体识别的例子,如果两句分别是“orange farmer”和“apple farmer”,由于两种都是比较常见的,那么可以判断主语为人名. 但是如果是榴莲种植员可能就无法 ...
- NLP领域的ImageNet时代到来:词嵌入「已死」,语言模型当立
http://3g.163.com/all/article/DM995J240511AQHO.html 选自the Gradient 作者:Sebastian Ruder 机器之心编译 计算机视觉领域 ...
- ng-深度学习-课程笔记-16: 自然语言处理与词嵌入(Week2)
1 词汇表征(Word representation) 用one-hot表示单词的一个缺点就是它把每个词孤立起来,这使得算法对词语的相关性泛化不强. 可以使用词嵌入(word embedding)来解 ...
- 词嵌入向量WordEmbedding
词嵌入向量WordEmbedding的原理和生成方法 WordEmbedding 词嵌入向量(WordEmbedding)是NLP里面一个重要的概念,我们可以利用WordEmbedding将一个单 ...
- 词向量 词嵌入 word embedding
词嵌入 word embedding embedding 嵌入 embedding: 嵌入, 在数学上表示一个映射f:x->y, 是将x所在的空间映射到y所在空间上去,并且在x空间中每一个x有y ...
随机推荐
- liunx详解-1
一 文件系统 根目录结构 root root用户家目录 home 其他用户家目录 etc 系统配置目录 bin sbin 可执行二进制文件目录,sbin只有root可访问 opt 软件安装目录 usr ...
- 【红黑树】的详细实现(C++)
红黑树的介绍 红黑树(Red-Black Tree,简称R-B Tree),它一种特殊的二叉查找树.红黑树是特殊的二叉查找树,意味着它满足二叉查找树的特征:任意一个节点所包含的键值,大于等于左孩子的键 ...
- 后台怎么区分接口要写在哪个service类中呢(根据service服务区分)
1,明确页面要实现什么功能,则页面对应的controller要写对应的controller方法 2,这个功能最终要由谁实现完成,在对应的service中药实现这个功能 3,这个接口的实现就写在最终完成 ...
- java获取配置文件中变量值
在resources 目录下新建config.properties文件 #文件保存路径 filePath=E:\\images\\file 工具类 public class ConfigUtil { ...
- java 并交集运算
在面试的过程中,忘记了List中还可以进行交并集运算,这也是常见的数据问题啊,这也是常见的数据结构问题---集合,面试的过程中一直没有想到这种数据结构 java中API中已经集成了并交集的运算. 代码 ...
- 题解 SP19148【INS14G - Kill them All】
SP19148[INS14G - Kill them All] 前置知识:组合数 乘法逆元 感觉其他博客讲的不是很清楚,也没有说组合数公式是怎么来的,我这样数论极菜的萌新看了好久才想明白qwq.. 还 ...
- js判断是横屏还是竖屏
1通过在html中分别引用横屏和竖屏的样式: <link rel="stylesheet" media="all and (orientation:portrait ...
- Node.js Learning Notes
简介 简单的说 Node.js 就是运行在服务端的 JavaScript. Node.js 是一个基于Chrome JavaScript 运行时建立的一个平台. Node.js是一个事件驱动I/O服务 ...
- java篇 之 多态
2018-9-28 多态: 重载也称为静态多态(静态在编译阶段就能确定)(动态是跟运行时挂钩) 尽量去选择关系轻的,降低耦合度(紧密度) 内聚: 减少与外界的联系,降低与其他对象和类的联系 对象与对象 ...
- IIS-反向代理配置&&插件安装
参考:https://www.cnblogs.com/pengcc/p/4329207.html 网络上好多开场的文章就说了好多的原理之类的这里我们直接开始配置.不过也要简单说下win下配置反向代理只 ...