把矩阵乘积称为MatMul节点:
下面这个图表示矩阵乘积y=xW的计算图 。因为考虑了mini-batch 处理,假设x中保存了N个数据。此时x 、W、y 的形状分别是 N×D、D×H 、N×H 。
下面是推反向传播的数学式:
用代码表述MatMul层:params 中保存要学习的参数,梯度保存在 grads 中。
下面这句话是设置梯度的值,使用省略号可以固定 NumPy 数组的内存地址,覆盖 NumPy 数组的元素。a=b 和 a[…]=b 的区别:使用省略号时数据被覆盖,变量a指向的内存地址不变,在 a = b 的情况下,a 指向的内存地址转到和b一样了。
self.grads[0][...] = dW
class MatMul:def __init__(self, W):self.params = [W]#w就是权重矩阵self.grads = [np.zeros_like(W)]#构造一个和W矩阵维度一致,但是全为0的矩阵。self.x = Nonedef forward(self, x):W, = self.paramsout = np.dot(x, W)#矩阵x和矩阵w相乘self.x = xreturn outdef backward(self, dout):W, = self.paramsdx = np.dot(dout, W.T)#dout是上游传来的;W.T是把W转置了dW = np.dot(self.x.T, dout)self.grads[0][...] = dWreturn dx
CBOW 模型一开始有两个 MatMul 层,这两个层的输出被加在一起。然后,对这个相加后得到的值乘以 0.5 求平均,可以得到中间层的神经元。最后,将另一个 MatMul 层应用于中间层的神经元,输出得分。
MatMul 层的正向传播其实也就是求矩阵乘积。
CBOW 模型网络结构:
python实现 CBOW 模型的推理:这里面输入侧的 MatMul 层共享权重 W_in。
import sys
sys.path.append('..')
import numpy as np
from common.layers 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)# 生成层
in_layer0 = MatMul(W_in)
in_layer1 = MatMul(W_in)
out_layer = MatMul(W_out)# 正向传播
h0 = in_layer0.forward(c0)
h1 = in_layer1.forward(c1)
h = 0.5 * (h0 + h1)
s = out_layer.forward(h)
print(s)
输出:
[[-0.78101945 -0.63278993 0.62227128 1.97029862 0.51288306 -0.481098630.6403517 ]]