微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

反向传播实现 - 如何在矩阵上应用链式法则 对于dL/dX对于dL/dWdL/dXdL/dW.T

如何解决反向传播实现 - 如何在矩阵上应用链式法则 对于dL/dX对于dL/dWdL/dXdL/dW.T

dL/dX 的梯度使用链式法则

提供L是神经网络的损失,X是输入,Y是点积Y = X•W = np.dot(X,W)输出

根据链式法则,dL/dX → dY/dX • dL/dY → W.T • dL/dY 因为产品 dY/dX = WY = X•W

问题 1

如何将链式法则公式 dL/dX → W.T • dL/dY 应用于矩阵?由于 W.T(4,3)dL/dY(4,) 的形状不匹配,因此简单地将其应用如下不起作用。

我可以应用什么想法、原理或转变来克服这个问题?我认为矩阵需要不同的思维。

        # gradient dy (dL/dY) back-propagated from the posterior layer
        dy = self.posterior.backward()    

        # Apply chain-rule dL/dX = dY/dX @ dL/dY where dY/dX = W.T
        dx = np.dot(self.w.T,dy)

enter image description here


注意:图中有错别字。 (,4)(4,) 等等。在我的 大脑,4 个元素的一维数组是 (,4) 但在 NumPy 中,它是 (4,)

问题 2

必须转置 W.TX.T 才能使链式法则起作用的基本原理是什么?如果我转置 W,我想我可以在不转置的情况下使用 dL/dY,但请帮助理解。


对于dL/dX

我看到一个答案是交换位置,但不知道它来自哪里以及为什么。为什么可以改变链式法则中元素的顺序?

        # dL/dX = dL/dY • W.T instead of W.T • dL/dY 
        dx = np.dot(dy,self.w.T)   # dy(4,) @ w.T(4,3) -> (3,)

对于dL/dW

在下图中的答案中,X.T (,3)dL/dY (,4) 的形状被转换为 (3,1)(1,4) 以匹配形状(实际上是 (2,1) and (1,3)但与上面的快照保持一致),但不确定它来自哪里以及背后的基本原理是什么。

回答

enter image description here

    def backward(self,dout):
        dx = np.dot(dout,self.W.T)
        self.dW = np.dot(self.x.T,dout)
        self.db = np.sum(dout,axis=0)
        
        dx = dx.reshape(*self.original_x_shape)  # 入力データの形状に戻す(テンソル対応)
        return dx

代码

正在编码中,未测试,无法工作。

class Affine(object):
    """Affine (MatMul) Layer"""
    def __init__(self,units,weights,optimizer,posteriors: List[object]):
        """Initialize the affine layer.
        
        [X] shape(size,n)
        Aka Batch. An array of input data x with n features (n: 0,1,...,n). n=0 is a bias.
        j-th input X[j] is [x(j)(0),x(j)(1),... x(j)(n)] where bias 'x(j)(0)' is 1.
        Use capital X for batch and x for its individual input.
        
        NOTE: "input" is not limited to the first input data layer e.g. image pixels,but "input" at any layer.

        [weights] shape(n,units)
        k-th neuron (k:0,.. size-1) has its weight vector W(k):[w(k)(0),w(k)(1),... w(k)(n)].
        w(k)(0) is its bias weight. Each w(k)(i) amplifies i-th feature in the input x.  
                
        Args:
            units: number of neurons in the layer
            weights: array of weight-vectors of each neuron. shape(n,size)
            optimizer: gradient descent implementation e.g SGD,Adam.
            posteriors: next layers
        """
        # neuron weight vectors
        self.w: numpy.ndarray = weights  # weight vector per neuron
        self.n: int = weights.shape[0]   # number of features expected
        self.dw: numpy.ndarray = None    # gradient of W
        
        self.X: numpy.ndarray = np.empty(0,self.n)     # Batch input
        self.m: int  = -1                # batch size: X.shape[0]

        self.posterior = posteriors[0]
        
        
    def forward(self,X):
        """Forward propagation of the affine layer X@W"""
        # X@W from X(m,n) @ W(n,units) to generate output Y(m,units)
        self.m = self.X.shape[0] if self.X is not None else -1
        Y = np.dot(self.X,self.w)
        self.posterior.forward(Y)


    def backward(self):
        # --------------------------------------------------------------------------------
        # Back propagation dy from the posterior layer. dy shape must match that of Y(m,units)
        # --------------------------------------------------------------------------------
        dy = self.posterior.backward()    # gradient back-propagated from the posterior 
        assert(dy.shape[0] == self.m),\
        "gradient dy shape {} must match output Y shape ({},{})".format(
            dy.shape,self.m,self.n
        )

        # --------------------------------------------------------------------------------
        # Gradient descent on W
        # --------------------------------------------------------------------------------
        dw = np.dot(self.X.T,dy)
        self.w = self.optimizer.(self.w,dw)

        dx = np.dot(dy,self.w)
        return dx

相关

建议查看以下问题,如How to apply chain rule on matrix

enter image description here

几何

据我所知,X•W 是通过几何截断 W 的其他维度来提取 XX 维度部分。如果是这样,dL/dXdL/dW 正在恢复截断的维度?不确定这是否正确,但如果是这样,是否可以像图中的 X•W 投影一样将其可视化?

enter image description here

解决方法

感谢 @Reti43 指出参考文献。详细数学由 cs231 Justin Jonson(现在在密歇根大学)作为 http://cs231n.stanford.edu/handouts/linear-backprop.pdf 提供,也可作为 Backpropagation for a Linear Layer 使用。

cs231n lecture 4 解释了这个想法。

enter image description here

从步骤(5)到(6)的数学计算似乎是一个飞跃,因为点积不会由两个二维矩阵产生,而numpy.dot会产生矩阵乘法np.matmul,因此它不会是点积。

numpy function to use for mathematical dot product to produce scalar 中的答案解决了一个问题。

enter image description here


通过阅读贾斯汀约翰逊的论文,我的理解如下。

权重向量W的格式

需要注意 Justin Johnson 对 W 的权重表示。

在 Coursera ML 课程中,Andrew Ng 使用行向量来捕获节点的权重。当输入到层的特征数为n时,行向量大小为n

Justin Johnson 使用行向量来表示层大小,即层中的节点数。因此,如果层中有 m 个节点,则行向量大小为 m

因此 Andrew Ng 的权重矩阵是 m x n 表示 m 行权重向量,每行权重向量是特定节点的 n 特征的权重。 Justin Johnson 的权重矩阵是 n x m 表示 n 行权重向量,每行权重向量是层中每个特征的 m 节点的权重。

enter image description here

我想贾斯汀·约翰逊认为 layer is a function 而 Andrew Ng 认为 node is a function

当我首先学习 Andrew Ng 的 ML 课程时,我使用了 weight vector per node 方法,结果为 W as m x n matrix。我的困惑来自于将 W = m x n 应用于 Justin Jhonson 的论文。

维度分析

首先框定渐变的尺寸/形状。

enter image description here

推导梯度

使用简单的单输入记录 X shape(d,),导出 dL/dX 并将其扩展到二维输入 X shape(n,d),从而得到 W.T @ dL/dY

dL/dX

对X和W使用行序矩阵。结果与cs321不同,因为如何组织权重W不同。

enter image description here

dL/dW.T

对X和W使用行序矩阵。结果与cs321不同,因为如何组织权重W不同。

enter image description here 如果有什么不正确,非常感谢任何反馈。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。