赞
踩
使用神经网络,构建神经网络模型;将数据输入到模型中,模型进行预测,并反复更新网络的权重
以下图为例,所谓的推理就是给定了单词的上下文,让模型去预测中间这个单词是什么;
要用神经网络处理单词,需要先将单词转化 为固定长度的向量
一种方式为one-hot独热编码,只有一个元素是 1,其他元素都是 0
用“You say goodbye and I say hello.”这个一句话的语料库来说明的话,这个语料库中, 一共有 7 个单词,因此独热编码向量的长度就可以固定为7,每个单词都是长度为7的向量,并将单词 ID 对应的元素设为 1,其他元素设为 0;
向量固定下来之后,神经网络的输入层的神经元个数就固定下来了
对于 one-hot 表示的某个单词,使用全连接层对其进行变换,如下图所示:
每个箭头上都有权重
权重和输入层神经元的加权和成为中间层的神经元
这里省略了偏置,因此没有偏置的全连接层相当于在计算矩阵乘积
对于某个单词的向量,其维度为[1,7],经过全连接层(即每个输入层神经元都会参与到所有箭头的计算中)得到结果的维度为[1,3],那么这里的箭头上的权重所构成的矩阵维度就是[7,3]
如何理解计算过程:输入层的七个神经元与一组七个箭头上的权重对应相乘再相加,得到中间层第一个神经元的结果;以此类推;如下图所示:
代码示例如下:
import numpy as np
c = np.array([[1, 0, 0, 0, 0, 0, 0]]) # [1,7]
W = np.random.randn(7, 3) # [7,3]
# If both a and b are 2-D arrays, it is matrix multiplication
h = np.dot(c, W) # [1,3]
print(h)
pass
本书中还提供了一个MatMul
层,我们详细看一下其中的内容(因为后面也会用到)
主要实现一个矩阵相乘的计算,同时提供了反向传播的计算函数
关于矩阵求梯度的理解可以看:【深度学习】7-矩阵乘法运算的反向传播求梯度_矩阵梯度公式-CSDN博客;
初始化:
w
保存为参数params
;grads
是一个与权重w
维度相同的矩阵;def __init__(self, W):
self.params = [W]
self.grads = [np.zeros_like(W)] # 放到列表中
self.x = None
前向计算:
x
的维度为[4,2]
,w
的维度为[2,3]
;得到计算结果维度为[4,3]
;def forward(self, x):
W, = self.params
out = np.dot(x, W)
self.x = x
return out
反向传播
def backward(self, dout):
W, = self.params
dx = np.dot(dout, W.T) # 求关于输入x的梯度
dW = np.dot(self.x.T, dout) # 求关于权重矩阵的梯度
self.grads[0][...] = dW # 权重的梯度保存下来
return dx
模型输入的构建
模型的网络结构
通过神经网络的不断训练,两个权重得到优化;输入层与中间层的这个权重矩阵其实就是单词的分布式表示,我的理解是:
注意点:
将之前讲述过的矩阵乘法层应用到这里:由于输入是两个单词,因此输入层使用两个MatMul 层(仍是共享权重),即两个矩阵乘法,两个结果相加再平均,得到中间层的结果;然后再使用一个MatMul 层得到输出
CBOW模型正向计算的代码实现:
import numpy as np from utils.Matmul import MatMul # 样本的上下文单词向量 c0 = np.array([[1, 0, 0, 0, 0, 0, 0]]) c1 = np.array([[0, 0, 1, 0, 0, 0, 0]]) # 权重初始化 w_in = np.random.randn(7, 3) w_out = np.random.randn(3, 7) # 构建层 # 权重是待优化的项;这里两个输入层都使用w_in;因此是共享权重的方式 # 但是由于两个输入层都是单独构建了类的实例,因此共享权重会影响参数的更新 in_layer_0 = MatMul(w_in) # 输入层 in_layer_1 = MatMul(w_in) # 输入层 out_layer = MatMul(w_out) # 输出层 # 正向传播(前向计算) h_0 = in_layer_0.forward(c0) h_1 = in_layer_1.forward(c1) h = 0.5 * (h_0 + h_1) s = out_layer.forward(h) print('前向计算结果:\n', s)
上述神经网络的输出结果称之为得分;对这个得分施加softmax函数,可以转换为概率分布,选取概率最大的作为对当前位置单词的预测;如果网络具有“良好的权重”,那么在最终得到的概率分布中,正确解将具有最高的概率值
当两个层共享权重时,每个层的梯度更新都会影响另一个层。这可能会导致一些问题,特别是当使用像 Adam 这样的优化器时,因为 Adam 依赖于每个参数的梯度的历史信息来调整学习率。
pytorch中如何解决这种问题:
backward()
方法时,PyTorch 会自动累积这些层的梯度,这样你就可以正确地更新共享的权重了。以下是一个简单的例子:
class SharedLayerNet(nn.Module):
def __init__(self):
super(SharedLayerNet, self).__init__()
self.shared_layer = nn.Linear(10, 20)
def forward(self, x1, x2):
out1 = self.shared_layer(x1)
out2 = self.shared_layer(x2)
return out1, out2
即训练上述神经网络,以优化权重,以便能够更准确的进行预测。
学习的结果是,权重
w_in
(确切地说是w_in
和w_out
两者)学习到蕴含单词出现模式的向量;CBOW 模型只是学习语料库中单词的出现模式。如果语料库不一样, 学习到的单词的分布式表示也不一样。比如,只使用“体育”相关 的文章得到的单词的分布式表示,和只使用“音乐”相关的文章得 到的单词的分布式表示将有很大不同
- 但是与先前基于计数的方法相比,他的成本更低
如何学习?目标是什么?
下图为整个过程的维度变化:
w_in
:每一行对应于各个单词的分布式表示;维度为[7,3]
;w_out
:在列方向上保存了各个单词的分布式表示;维度为[3,7]
;w_in
作为最终的单词的分布式表示w_in
的每一列相乘,每一列又刚好是7(与单词个数对应);每一列都蕴含了一些信息;这里有3列;w_in
的有 效性。另外,在与 word2vec 相似的 GloVe[27] 方法中,通过将两个 权重相加,也获得了良好的结果;因此可以看看论文中是如何描述的;Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。