怎样做网站教程,网站平台建设规划,免费自助小型网站,wordpress官方中文主题多分类问题处理为二分类问题#xff0c;需要能够正确地对正例和负例进行分类。
如果以所有的负例为对象#xff0c;词汇量将增加许多#xff0c;无法处理。作为一种近似方法#xff0c;将只使用少数负例。
负采样方法#xff1a;求正例作为目标词时的损失#xff0c;同…多分类问题处理为二分类问题需要能够正确地对正例和负例进行分类。
如果以所有的负例为对象词汇量将增加许多无法处理。作为一种近似方法将只使用少数负例。
负采样方法求正例作为目标词时的损失同时采样(选出)若干个负例对这些负例求损失。然后将正例和采样出来的负例的损失加起来作为最终的损失。例子如下图所示。 负采样的采样方法
抽取负例让语料库中常出现的单词易被抽到不常出现的单词难被抽到。
基于频率的采样方法计算语料库中各个单词的出现次数并将其表示为概率分布然后使用这个概率分布对单词进行采样。
通过给np.random.choice函数参数p指定表示概率分布的列表将进行基于概率分布的采样。
import numpy as np
words [you, say, goodbye, I, hello, .]
a np.random.choice(words)
b np.random.choice(words, size5)
c np.random.choice(words, size5, replaceFalse)
p [0.5, 0.1, 0.05, 0.2, 0.05, 0.1]
d np.random.choice(words, pp)
print(a)
print(b)
print(c)
print(d)输出
hello
[. hello hello goodbye goodbye]
[hello . goodbye you I]
youword2vec中的负采样对原来的概率分布取0.75次方。分子表示第i个单词的概率。分母是变换后的概率分布的总和。(使变换后的概率总和仍为1)通过取0.75次方低频单词的概率将稍微变高。作为一种补救措施使得变换后低频单词比变换前抽到的几率增加。 以1个连续单词(unigram)为对象创建概率分布进行负例抽取的函数如下。corpus是是单词ID列表power是概率分布取的次方值sample_size是负例的采样个数。
如果是bigram则以(you,say)、(you,goodbye)这样的2个单词的组合为对象创建概率分布。
class UnigramSampler:def __init__(self, corpus, power, sample_size):self.sample_size sample_sizeself.vocab_size Noneself.word_p Nonecounts collections.Counter()for word_id in corpus:counts[word_id] 1vocab_size len(counts)self.vocab_size vocab_sizeself.word_p np.zeros(vocab_size)for i in range(vocab_size):self.word_p[i] counts[i]self.word_p np.power(self.word_p, power)self.word_p / np.sum(self.word_p)def get_negative_sample(self, target):batch_size target.shape[0]if not GPU:negative_sample np.zeros((batch_size, self.sample_size), dtypenp.int32)for i in range(batch_size):p self.word_p.copy()target_idx target[i]p[target_idx] 0p / p.sum()negative_sample[i, :] np.random.choice(self.vocab_size, sizeself.sample_size, replaceFalse, pp)else:# 在用GPU(cupy计算时优先速度# 有时目标词存在于负例中negative_sample np.random.choice(self.vocab_size, size(batch_size, self.sample_size),replaceTrue, pself.word_p)return negative_sample使用这个类[1, 3, 0]这3个数据的mini-batch作为正例对各个数据采样2个负例。
import numpy as np
from negative_sampling_layer import UnigramSampler
corpus np.array([0, 1, 2, 3, 4, 1, 2, 3])
power 0.75
sample_size 2
sampler UnigramSampler(corpus, power, sample_size)
target np.array([1, 3, 0])
negative_sample sampler.get_negative_sample(target)
print(negative_sample)输出可以看到每个数据的负例。
[[2 4][2 0][2 1]]实现负采样层
参数输出侧权重W单词ID列表corpus概率分布的次方值power负例的采样数sample_size sampler保存UnigramSampler生成的采样负例。
loss_layers 和 embed_dot_layers 中以列表格式保存了必要的层生成sample_size 1 个层意味着生成一个正例用的层和 sample_size 个负例用的层。loss_layers[0] 和 embed_dot_layers[0] 是处理正例的层。
正向传播通过 Embedding Dot 层的 forward 输出得分再将得分和标签一起输入 Sigmoid with Loss 层来计算损失和。
反向传播以与正向传播相反的顺序调用各层的 backward() 函数将多份梯度累加起来。
class NegativeSamplingLoss:def __init__(self, W, corpus, power0.75, sample_size5):self.sample_size sample_sizeself.sampler UnigramSampler(corpus, power, sample_size)self.loss_layers [SigmoidWithLoss() for _ in range(sample_size 1)]self.embed_dot_layers [EmbeddingDot(W) for _ in range(sample_size 1)]self.params, self.grads [], []for layer in self.embed_dot_layers:self.params layer.paramsself.grads layer.gradsdef forward(self, h, target):batch_size target.shape[0]negative_sample self.sampler.get_negative_sample(target)# 正例的正向传播score self.embed_dot_layers[0].forward(h, target)correct_label np.ones(batch_size, dtypenp.int32)loss self.loss_layers[0].forward(score, correct_label)# 负例的正向传播negative_label np.zeros(batch_size, dtypenp.int32)for i in range(self.sample_size):negative_target negative_sample[:, i]score self.embed_dot_layers[1 i].forward(h, negative_target)loss self.loss_layers[1 i].forward(score, negative_label)return lossdef backward(self, dout1):dh 0for l0, l1 in zip(self.loss_layers, self.embed_dot_layers):dscore l0.backward(dout)dh l1.backward(dscore)return dh