深度学习进阶:自然语言处理入门:第4章 word2vec的高速化

第4章 word2vec的高速化

  • 第4章 word2vec的高速化
    • 4.1 word2vec的改进①
      • 4.1.1  Embedding层
      • 4.1.2  Embedding层的实现
        • 函数
    • 4.2 word2vec的改进②
      • 4.2.1  中间层之后的计算问题
      • 4.2.2  从多分类到二分类
      • 4.2.3  sigmoid函数和交叉熵误差
      • 4.2.4  多分类到二分类的实现
        • 函数
      • 4.2.5  负采样
      • 4.2.6  负采样的采样方法
        • 函数
        • 简单实现
      • 4.2.7  负采样的实现
    • 4.3 改进版 word2vec的学习
      • 4.3.1  CBOW模型的实现
        • 改进版的 CBOW 类
      • 4.3.2  CBOW模型的学习代码
      • 4.3.3  CBOW模型的评价
    • 4.4 wor2vec相关的其他话题
      • 4.4.1  word2vec的应用例
      • 4.4.2  单词向量的评价方法
    • 4.5 小结
      • 本章所学的内容

第4章 word2vec的高速化

上一章我们学习了 word2vec 的机制,并实现了 CBOW 模型。因为 CBOW 模型是一个简单的 2 层神经网络,所以实现起来比较简单。但是, 目前的实现存在几个问题,其中最大的问题是,随着语料库中处理的词汇量 的增加,计算量也随之增加。

对上一章中简单的 word2vec 进行两点改进:引入名为 Embedding 层的新层,以及引入名为 Negative Sampling 的新损失函数。

上一章的 CBOW 模型接收拥有 2 个单词的上下文,并 基于它们预测 1 个单词(目标词)。
深度学习进阶:自然语言处理入门:第4章 word2vec的高速化_第1张图片
深度学习进阶:自然语言处理入门:第4章 word2vec的高速化_第2张图片

三个计算大户

1.H=Win x

2.S=H Wout

3.Y=Softmax with loss(s)

4.1 word2vec的改进①

4.1.1  Embedding层

针对计算大户1:
深度学习进阶:自然语言处理入门:第4章 word2vec的高速化_第3张图片

我们反应过来了,我们要的h,其实就是在Win中取出跟X对应的那一行

即可那用不着dot,直接取就行了

这个我们给他起名叫Embedding层

4.1.2  Embedding层的实现

深度学习进阶:自然语言处理入门:第4章 word2vec的高速化_第4张图片
深度学习进阶:自然语言处理入门:第4章 word2vec的高速化_第5张图片
深度学习进阶:自然语言处理入门:第4章 word2vec的高速化_第6张图片

深度学习进阶:自然语言处理入门:第4章 word2vec的高速化_第7张图片

函数

class Embedding:
    def __init__(self, W):
        self.params = [W]
        self.grads = [np.zeros_like(W)]
        self.idx = None
        
    def forward(self, idx):
        W, = self.params   #加逗号把array外面的方括号去点了
        self.idx = idx
        out = W[idx]
        return out
    
    def backward(self, dout):
        dW, = self.grads
        dW[...] = 0
        for i, word_id in enumerate(self.idx):
            dW[word_id] += dout[i]
         # 或者
         # np.add.at(dW, self.idx, dout)
        return None

深度学习进阶:自然语言处理入门:第4章 word2vec的高速化_第8张图片

这里,取出权重梯度dW,通过dW[…]=0,将dW的元素设为0(并不是将dW设为0,而是保持dW的形状保持不变,将他的元素设为0)

然后,将上一层传来的梯度dout写入idx指定的行

这里我们看到,0的位置的梯度累加了

此外for循环语句的实现也可以通过Numpy的np.add.at()进行。

np.add.at(A,idx,B)将B加到A上,此时可以通过idx指定A中需要进行加法

通常情况下,NumPy 的内置方法比 Python 的 for循环处理更快。 这是因为 NumPy 的内置方法在底层做了高速化和提高处理效率的 优化。因此,上面的代码如果使用 np.add.at()来实现,效率会比 使用 for循环处理高得多。

4.2 word2vec的改进②

下面解决问题2和3

4.2.1  中间层之后的计算问题

深度学习进阶:自然语言处理入门:第4章 word2vec的高速化_第9张图片

  • 中间层的神经元和权重矩阵(Wout)的乘积

    中间层向量的 大小是 100,权重矩阵的大小是 100 × 1 000 000 万,如此巨大的矩阵乘积 计算需要大量时间(也需要大量内存)。此外,因为反向传播时也要进行同 样的计算,所以很有必要将矩阵乘积计算“轻量化”

  • Softmax 层的计算
    深度学习进阶:自然语言处理入门:第4章 word2vec的高速化_第10张图片

4.2.2  从多分类到二分类

考虑用二分类拟合多分类

多分类:给you和goodbye,目标词是谁?

二分类:“当上下文是you和goodbye时,目标词是say吗?

二 分 类 处 理 的 是 答 案 为“Yes/No”的 问 题。诸 如,“这 个 数 字 是 7 吗?”“这是猫吗?”“目标词是 say 吗?”等,这些问题都可以用 “Yes/No”来回答

那么我们的计算就变成下图

​ 输出层的神经元仅有一个。因此,要计算中间层和输出 侧的权重矩阵的乘积,只需要提取 say 对应的列(单词向量),并用它与中间层的神经元计算内积即可。
深度学习进阶:自然语言处理入门:第4章 word2vec的高速化_第11张图片
深度学习进阶:自然语言处理入门:第4章 word2vec的高速化_第12张图片

4.2.3  sigmoid函数和交叉熵误差

​ 要使用神经网络解决二分类问题,需要使用 sigmoid 函数将得分转化为 概率。为了求损失,我们使用交叉熵误差作为损失函数。这些都是二分类神 经网络的老套路。

在多分类的情况下,输出层使用Softmax函数将得分转化为概率,损 失函数使用交叉熵误差。在二分类的情况下,输出层使用sigmoid 函数, 损失函数也使用交叉熵误差。

深度学习进阶:自然语言处理入门:第4章 word2vec的高速化_第13张图片

深度学习进阶:自然语言处理入门:第4章 word2vec的高速化_第14张图片

输出 −log y;当 t 为 0 时,输出 −log (1 − y)。

深度学习进阶:自然语言处理入门:第4章 word2vec的高速化_第15张图片

4.2.4  多分类到二分类的实现

1.回顾一下多分类
深度学习进阶:自然语言处理入门:第4章 word2vec的高速化_第16张图片

2.转化成进行二分类的神经网络
深度学习进阶:自然语言处理入门:第4章 word2vec的高速化_第17张图片

在图 4-12 中,向 Sigmoid with Loss 层输入正确解标签 1,这意 味着现在正在处理的问题的答案是“Yes”。当答案是“No”时, 向 Sigmoid with Loss 层输入 0。

实现这个层

深度学习进阶:自然语言处理入门:第4章 word2vec的高速化_第18张图片

深度学习进阶:自然语言处理入门:第4章 word2vec的高速化_第19张图片
深度学习进阶:自然语言处理入门:第4章 word2vec的高速化_第20张图片
深度学习进阶:自然语言处理入门:第4章 word2vec的高速化_第21张图片

深度学习进阶:自然语言处理入门:第4章 word2vec的高速化_第22张图片

函数

class Embedding:
    def __init__(self, W):
        self.params = [W]
        self.grads = [np.zeros_like(W)]
        self.idx = None
        
    def forward(self, idx):
        W, = self.params   #加逗号把array外面的方括号去点了
        self.idx = idx
        out = W[idx]
        return out
    
    def backward(self, dout):
        dW, = self.grads
        dW[...] = 0
        for i, word_id in enumerate(self.idx):
            dW[word_id] += dout[i]
         # 或者
         # np.add.at(dW, self.idx, dout)
        return None
class EmbeddingDot:
    def __init__(self, W):
        self.embed = Embedding(W)
        self.params = self.embed.params
        self.grads = self.embed.grads
        self.cache = None

    def forward(self, h, idx):
        target_W = self.embed.forward(idx)
        out = np.sum(target_W * h, axis=1)

        self.cache = (h, target_W)
        return out

    def backward(self, dout):
        h, target_W = self.cache
        dout = dout.reshape(dout.shape[0], 1)

        dtarget_W = dout * h
        self.embed.backward(dtarget_W)
        dh = dout * target_W
        return dh

4.2.5  负采样

仅学习了正例(正确答案),
深度学习进阶:自然语言处理入门:第4章 word2vec的高速化_第23张图片
深度学习进阶:自然语言处理入门:第4章 word2vec的高速化_第24张图片

我们需要对所有的负例进行学习吗?
Non non non, pas du tout~
我们只需要选几个个负例即可

比如下面这张图
深度学习进阶:自然语言处理入门:第4章 word2vec的高速化_第25张图片

4.2.6  负采样的采样方法

采样有很多方法,比如

  • 随机抽样
  • 基于语料库的统计抽样这里我们选择第二种

高频词汇抽到的概率大,低领词汇抽到的概率小
深度学习进阶:自然语言处理入门:第4章 word2vec的高速化_第26张图片

​ 基于语料库中各个单词的出现次数求出概率分布后,只需根据这个概率 分布进行采样就可以了。通过根据概率分布进行采样,语料库中经常出现的 单词将容易被抽到,而“稀有单词”将难以被抽到

负采样应当尽可能多地覆盖负例单词,但是考虑到计算的复杂度, 有必要将负例限定在较小范围内(5 个或者 10 个)。

这里,如果只选 择稀有单词作为负例会怎样呢?结果会很糟糕。因为在现实问题中, 稀有单词基本上不会出现。也就是说,处理稀有单词的重要性较低。 相反,处理好高频单词才能获得更好的结果

看一下python是怎么实现的

深度学习进阶:自然语言处理入门:第4章 word2vec的高速化_第27张图片

word2vec 中提出的负采样对刚才的概率分布增加了一个步骤。

另外对概率做一个平滑处理 分softmax有点类似
深度学习进阶:自然语言处理入门:第4章 word2vec的高速化_第28张图片

这是为了防止低频单词被忽略。更准确地说,通过取 0.75 次方,低频单词的概率将稍微变高。我们来看一个具体例子,如下所示

(0.75没有理论依据,随便选)
深度学习进阶:自然语言处理入门:第4章 word2vec的高速化_第29张图片

函数

import sys
sys.path.append('..')
from common.np import *  # import numpy as np
from common.layers import Embedding, SigmoidWithLoss
import collections


class UnigramSampler:
    def __init__(self, corpus, power, sample_size):
        self.sample_size = sample_size
        self.vocab_size = None
        self.word_p = None

        counts = collections.Counter()
        for word_id in corpus:		#统计每个单词出现的次数
            counts[word_id] += 1

        vocab_size = len(counts)		#代表一共有多少个单词,
        self.vocab_size = vocab_size

        self.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), dtype=np.int32)

            for i in range(batch_size):
                p = self.word_p.copy()
                target_idx = target[i]
                p[target_idx] = 0
                p /= p.sum()
                negative_sample[i, :] = np.random.choice(self.vocab_size, size=self.sample_size, replace=False, p=p)
        else:
            # 在用GPU(cupy)计算时,优先速度
            # 有时目标词存在于负例中
            negative_sample = np.random.choice(self.vocab_size, size=(batch_size, self.sample_size),
                                               replace=True, p=self.word_p)

        return negative_sample

在进行初始化时,UnigramSampler 类取 3 个参数,分别是单词 ID 列表 格式的 corpus、对概率分布取的次方值 power(默认值是 0.75)和负例的采 样个数 sample_size。

UnigramSampler 类有 get_negative_sample(target) 方法, 该方法以参数 target 指定的单词 ID 为正例,对其他的单词 ID 进行采样。
深度学习进阶:自然语言处理入门:第4章 word2vec的高速化_第30张图片
深度学习进阶:自然语言处理入门:第4章 word2vec的高速化_第31张图片

简单实现

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])

#GPU=False
negative_sample = sampler.get_negative_sample(target)
print(negative_sample)
[[0 3]
[1 2]
[2 3]]

这里,考虑将 [1, 3, 0] 这 3 个数据的 mini-batch 作为正例。此时,对 各个数据采样 2 个负例。在上面的例子中,可知第 1 个数据的负例是 [0, 3], 第 2 个是 [1, 2],第 3 个是 [2, 3]。这样一来,我们就完成了负采样。

4.2.7  负采样的实现

最后,我们来实现负采样。我们把它实现为 NegativeSamplingLoss 类, 首先从初始化开始

class NegativeSamplingLoss:
    def __init__(self, W, corpus, power=0.75, sample_size=5):
        #输出侧权重的 W、语料库(单词 ID 列表)corpus、概率分布的次方值 power 和负例的采样数 sample_size。
        self.sample_size = sample_size
        #生成上一节所说的 UnigramSampler 类,并使用成员变量 sampler 保存
        self.sampler = UnigramSampler(corpus, power, sample_size)
        #成员变量 loss_layers 和 embed_dot_layers 中以列表格式保存了必要的层。
        #在这两个列表中生成 sample_size + 1 个层,这是因为需要生成一个正例用的层和 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 = [], []			#params存储的是w的值
        for layer in self.embed_dot_layers:
            self.params += layer.params
            self.grads += layer.grads

   #接收的参数是中间层的神经元 h 和正例目标词 target。         
    def 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, dtype=np.int32)	#正确解标签都是1
        loss = self.loss_layers[0].forward(score, correct_label)

        # 负例的正向传播
        negative_label = np.zeros(batch_size, dtype=np.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 loss

    def backward(self, dout=1):
        dh = 0
        for l0, l1 in zip(self.loss_layers, self.embed_dot_layers):
            dscore = l0.backward(dout)
            dh += l1.backward(dscore)

        return dh

​ 成员变量 loss_layers 和 embed_dot_layers 中以列表格式保存了必要的 层。在这两个列表中生成 sample_size + 1 个层,这是因为需要生成一个正 例用的层和 sample_size 个负例用的层。这里,我们假设列表的第一个层处 理正例。也就是说,loss_layers[0] 和 embed_dot_layers[0] 是处理正例的层。 然后,将 embed_dot_layers 层使用的权重和梯度分别保存在数组中。

​ forward(h, target) 方法接收的参数是中间层的神经元 h 和正例目标 词 target。这里进行的处理是,首先使用 self.sampler 采样负例,并设为 negative_sample。然后,分别对正例和负例的数据进行正向传播,求损失的 和。具体而言,通过 Embedding Dot 层的 forward 输出得分,再将这个得 分和标签一起输入 Sigmoid with Loss 层来计算损失。这里需要注意的是, 正例的正确解标签为 1,负例的正确解标签为 0。

​ 反向传播的实现非常简单,只需要以与正向传播相反的顺序调用各层的 backward() 函数即可。在正向传播时,中间层的神经元被复制了多份,这相 当于 1.3.4.3 节中介绍的 Repeat 节点。因此,在反向传播时,需要将多份梯 度累加起来。以上就是负采样的实现的说明。

深度学习进阶:自然语言处理入门:第4章 word2vec的高速化_第32张图片
深度学习进阶:自然语言处理入门:第4章 word2vec的高速化_第33张图片
深度学习进阶:自然语言处理入门:第4章 word2vec的高速化_第34张图片
这的负样例改为了4个
深度学习进阶:自然语言处理入门:第4章 word2vec的高速化_第35张图片
深度学习进阶:自然语言处理入门:第4章 word2vec的高速化_第36张图片
深度学习进阶:自然语言处理入门:第4章 word2vec的高速化_第37张图片

4.3 改进版 word2vec的学习

到目前为止,我们进行了 word2vec 的改进。首先说明了 Embedding 层,又介绍了负采样的方法,然后对这两者进行了实现。现在我们进一步来 实现进行了这些改进的神经网络,并在 PTB 数据集上进行学习,以获得更 加实用的单词的分布式表示。

4.3.1  CBOW模型的实现

改进版的 CBOW 类

import sys
sys.path.append('..')
from common.np import *  # import numpy as np
from common.layers import Embedding
from ch04.negative_sampling_layer import NegativeSamplingLoss


class CBOW:
    def __init__(self, vocab_size, hidden_size, window_size, corpus):
        #vocab_size 是词汇量,hidden_size 是中间层的神经元个数,corpus 是单词 ID 列表。
        #window_size 指定上下文的大小,即上下文包含多少个周围单词。如果 window_size 是 2,则目标词的左右 2 个单词(共 4 个单词)将成为上下文。
     
        V, H = vocab_size, hidden_size

        # 初始化权重
        W_in = 0.01 * np.random.randn(V, H).astype('f')
        W_out = 0.01 * np.random.randn(V, H).astype('f')

        # 生成层
        #创建 2 * window_size 个Embedding 层,并将其保存在成员变量 in_layers 中。然后,创建 Negative Sampling Loss 层。
        
        self.in_layers = []
        for i in range(2 * window_size):
            layer = Embedding(W_in)  # 使用Embedding层
            self.in_layers.append(layer)
        self.ns_loss = NegativeSamplingLoss(W_out, corpus, power=0.75, sample_size=5)

        # 将所有的权重和梯度整理到列表中
        layers = self.in_layers + [self.ns_loss]
        self.params, self.grads = [], []
        for layer in layers:
            self.params += layer.params
            self.grads += layer.grads

        # 将单词的分布式表示设置为成员变量
        self.word_vecs = W_in

    def forward(self, contexts, target):
        h = 0
        for i, layer in enumerate(self.in_layers):
            h += layer.forward(contexts[:, i])
        h *= 1 / len(self.in_layers)
        loss = self.ns_loss.forward(h, target)
        return loss

    def backward(self, dout=1):
        dout = self.ns_loss.backward(dout)
        dout *= 1 / len(self.in_layers)
        for layer in self.in_layers:
            layer.backward(dout)
        return None

​ 在 SimpleCBOW类(改进前的实现)中,输入侧的权重和输出侧的 权重的形状不同,输出侧的权重在列方向上排列单词向量。而 CBOW类的输出侧的权重和输入侧的权重形状相同,都在行方向 上排列单词向量。这是因为 NegativeSamplingLoss类中使用了 Embedding 层

1.这个初始化方法有 4 个参数。vocab_size 是词汇量,hidden_size 是中间 层的神经元个数,corpus 是单词 ID 列表。另外,通过 window_size 指定上下 文的大小,即上下文包含多少个周围单词。如果 window_size 是 2,则目标 词的左右 2 个单词(共 4 个单词)将成为上下文

2.在权重的初始化结束后,继续创建层。这里,创建 2 * window_size 个 Embedding 层,并将其保存在成员变量 in_layers 中。然后,创建 Negative Sampling Loss 层

3.在创建好层之后,将神经网络中使用的参数和梯度放入成员变量 params 和 grads 中。另外,为了之后可以访问单词的分布式表示,将权重 W_in 设置 为成员变量 word_vecs。

4.这里的实现只是按适当的顺序调用各个层的正向传播(或反向传播), 这是对上一章的 SimpleCBOW 类的自然扩展。不过,虽然 forward (contexts, target) 方法取的参数仍是上下文和目标词,但是它们是单词 ID 形式的(上 一章中使用的是 one-hot 向量,不是单词 ID),具体示例如图 4-19 所示。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-y3kXhN2s-1639141023224)(4/31.png)]

4.3.2  CBOW模型的学习代码

最后,我们来实现 CBOW 模型的学习部分。其实只是复用一下神经网络的学习,

import sys
sys.path.append('..')
from common import config
# 在用GPU运行时,请打开下面的注释(需要cupy)
# ===============================================
# config.GPU = True
# ===============================================
from common.np import *
import pickle
from common.trainer import Trainer
from common.optimizer import Adam
from cbow import CBOW
from skip_gram import SkipGram
from common.util import create_contexts_target, to_cpu, to_gpu
from dataset import ptb


# 设定超参数
window_size = 5
hidden_size = 100
batch_size = 100
max_epoch = 10

# 读入数据
corpus, word_to_id, id_to_word = ptb.load_data('train')
vocab_size = len(word_to_id)

contexts, target = create_contexts_target(corpus, window_size)
if config.GPU:
    contexts, target = to_gpu(contexts), to_gpu(target)

# 生成模型等
model = CBOW(vocab_size, hidden_size, window_size, corpus)
# model = SkipGram(vocab_size, hidden_size, window_size, corpus)
optimizer = Adam()
trainer = Trainer(model, optimizer)

# 开始学习
trainer.fit(contexts, target, max_epoch, batch_size)
trainer.plot()

# 保存必要数据,以便后续使用
word_vecs = model.word_vecs
if config.GPU:
    word_vecs = to_cpu(word_vecs)
params = {}
params['word_vecs'] = word_vecs.astype(np.float16)
params['word_to_id'] = word_to_id
params['id_to_word'] = id_to_word
pkl_file = 'cbow_params.pkl'  # or 'skipgram_params.pkl'
with open(pkl_file, 'wb') as f:
    pickle.dump(params, f, -1)

​ 本次的 CBOW 模型的窗口大小为 5,隐藏层的神经元个数为 100。虽 然具体取决于语料库的情况,但是一般而言,当窗口大小为 2 ~ 10、中间 层的神经元个数(单词的分布式表示的维数)为50~500时,结果会比较好。

​ 这次我们利用的 PTB 语料库比之前要大得多,因此学习需要很长时间 (半天左右)。作为一种选择,我们提供了使用 GPU 运行的模式。如果要使 用 GPU 运行,需要打开顶部的“# config.GPU = True”。不过,使用 GPU 运行需要有一台安装了 NVIDIA GPU 和 CuPy 的机器。

​ 在学习结束后,取出权重(输入侧的权重),并保存在文件中以备后用 (用于单词和单词 ID 之间的转化的字典也一起保存)。这里,使用 Python 的 pickle 功能进行文件保存。pickle 可以将 Python 代码中的对象保存到文 件中(或者从文件中读取对象)。

4.3.3  CBOW模型的评价

现在,我们来评价一下上一节学习到的单词的分布式表示。这里我们 使用第 2 章中实现的 most_similar() 函数,显示几个单词的最接近的单词

import sys
sys.path.append('..')
from common.util import most_similar, analogy
import pickle	


pkl_file = 'cbow_params.pkl'			#cbow_params.pkl
# pkl_file = 'skipgram_params.pkl'

with open(pkl_file, 'rb') as f:
    params = pickle.load(f)
    word_vecs = params['word_vecs']
    word_to_id = params['word_to_id']
    id_to_word = params['id_to_word']

# most similar task
querys = ['you', 'year', 'car', 'toyota']
for query in querys:
    most_similar(query, word_to_id, id_to_word, word_vecs, top=5)

# analogy task
print('-'*50)
analogy('king', 'man', 'queen',  word_to_id, id_to_word, word_vecs)
analogy('take', 'took', 'go',  word_to_id, id_to_word, word_vecs)
analogy('car', 'cars', 'child',  word_to_id, id_to_word, word_vecs)
analogy('good', 'better', 'bad',  word_to_id, id_to_word, word_vecs)

4.4 wor2vec相关的其他话题

4.4.1  word2vec的应用例

深度学习进阶:自然语言处理入门:第4章 word2vec的高速化_第38张图片

在这里插入图片描述
深度学习进阶:自然语言处理入门:第4章 word2vec的高速化_第39张图片

4.4.2  单词向量的评价方法

深度学习进阶:自然语言处理入门:第4章 word2vec的高速化_第40张图片
深度学习进阶:自然语言处理入门:第4章 word2vec的高速化_第41张图片

基于类推问题可以在一定程度上衡量“是否正确理解了单词含义或语法 问题”。

因此,在自然语言处理的应用中,能够高精度地解决类推问题的单 词的分布式表示应该可以获得好的结果。

但是,单词的分布式表示的优劣对 目标应用贡献多少(或者有无贡献),取决于待处理问题的具体情况,

比如 应用的类型或语料库的内容等。

也就是说,不能保证类推问题的评价高,目 标应用的结果就一定好。这一点请一定注意

4.5 小结

本章所学的内容

  • Embedding 层保存单词的分布式表示,在正向传播时,提取单词 ID 对应的向量
  • 因为 word2vec 的计算量会随着词汇量的增加而成比例地增加,所以 最好使用近似计算来加速
  • 负采样技术采样若干负例,使用这一方法可以将多分类问题转化为 二分类问题进行处理
  • 基于 word2vec 获得的单词的分布式表示内嵌了单词含义,在相似的 上下文中使用的单词在单词向量空间上处于相近的位置
  • word2vec 的单词的分布式表示的一个特性是可以基于向量的加减法 运算来求解类推问题
  • word2vec 的迁移学习能力非常重要,它的单词的分布式表示可以应 用于各种各样的自然语言处理任务

你可能感兴趣的:(深度学习进阶:自然,自然语言处理,深度学习,word2vec)