反向传播的矩阵形式与批量归一化


12

批归一化已被认为可在深度神经网络中显着提高性能。互联网上的大量资料显示了如何在逐个激活的基础上实施它。我已经使用矩阵代数实现了backprop,并且考虑到我正在使用高级语言(同时依赖Rcpp(最终是GPU的)密集矩阵乘法),将所有内容剔除并采用for-loops可能会使我的代码变慢除了遭受巨大的痛苦之外

批处理归一化函数为 其中

b(xp)=γ(xpμxp)σxp1+β
  • pxp是激活之前的个节点p
  • βγ和是标量参数β
  • σ X p X pμxp和是均值和SD的。(请注意,通常使用方差的平方根加上一个模糊系数-假设非零元素为紧凑起见)σxpxp

以矩阵形式,整个层的批量归一化将为 其中

b(X)=(γ1p)(XμX)σX1+(β1p)
  • XN×p
  • 1N是1的列向量
  • β pγ和现在是每层归一化参数的行向量βp
  • σ X Ñ × p ÑμX和是矩阵,其中每一列都是列均值和标准差的向量σXN×pN
  • 是Kronecker产品,是elementwise(Hadamard)产品

,这是一个非常简单的没有批次归一化且连续结果的单层神经网络

y=a(XΓ1)Γ2+ϵ

哪里

  • p 1 × p 2Γ1p1×p2
  • p 2 × 1Γ2p2×1
  • a(.)是激活函数

如果损失为,则渐变为 řR=N1(yy^)2

RΓ1=2VTϵ^RΓ2=XT(a(XΓ1)2ϵ^Γ2T)

哪里

  • V=a(XΓ1)
  • ϵ^=yy^

在批量归一化下,网络变为 或 我不知道如何计算Hadamard和Kronecker产品的导数。关于克罗内克产品,文献变得相当神秘。 Ý = 一个 γ ⊗ 1 Ñ X Γ 1 - μ X Γ 1σ - 1 X Γ 1 + β ⊗ 1 Ñ Γ 2

y=a(b(XΓ1))Γ2
y=a((γ1N)(XΓ1μXΓ1)σXΓ11+(β1N))Γ2

是否存在在矩阵框架内计算,和的?一个简单的表达式,无需借助逐节点计算?- [R /β - [R /Γ 1R/γR/βR/Γ1

更新1:

我已经弄清楚了类的。它是: 一些R代码演示了这等效于执行此操作的循环方法。首先设置假数据:1 Ť Ñ一个'X Γ 1- 2 ε Γ Ť 2R/β

1NT(a(XΓ1)2ϵ^Γ2T)
set.seed(1)
library(dplyr)
library(foreach)

#numbers of obs, variables, and hidden layers
N <- 10
p1 <- 7
p2 <- 4
a <- function (v) {
  v[v < 0] <- 0
  v
}
ap <- function (v) {
  v[v < 0] <- 0
  v[v >= 0] <- 1
  v
}

# parameters
G1 <- matrix(rnorm(p1*p2), nrow = p1)
G2 <- rnorm(p2)
gamma <- 1:p2+1
beta <- (1:p2+1)*-1
# error
u <- rnorm(10)

# matrix batch norm function
b <- function(x, bet = beta, gam = gamma){
  xs <- scale(x)
  gk <- t(matrix(gam)) %x% matrix(rep(1, N))
  bk <- t(matrix(bet)) %x% matrix(rep(1, N))
  gk*xs+bk
}
# activation-wise batch norm function
bi <- function(x, i){
  xs <- scale(x)
  gk <- t(matrix(gamma[i]))
  bk <- t(matrix(beta[i]))
  suppressWarnings(gk*xs[,i]+bk)
}

X <- round(runif(N*p1, -5, 5)) %>% matrix(nrow = N)
# the neural net
y <- a(b(X %*% G1)) %*% G2 + u

然后计算导数:

# drdbeta -- the matrix way
drdb <- matrix(rep(1, N*1), nrow = 1) %*% (-2*u %*% t(G2) * ap(b(X%*%G1)))
drdb
           [,1]      [,2]    [,3]        [,4]
[1,] -0.4460901 0.3899186 1.26758 -0.09589582
# the looping way
foreach(i = 1:4, .combine = c) %do%{
  sum(-2*u*matrix(ap(bi(X[,i, drop = FALSE]%*%G1[i,], i)))*G2[i])
}
[1] -0.44609015  0.38991862  1.26758024 -0.09589582

他们匹配。但是我仍然很困惑,因为我真的不知道为什么会这样。@Mark L. Stone引用的MatCalc注释说的派生应为β1N

ÑpqŤ

ABA=(InqTmp)(Invec(B)Im)
其中下标,和,是和的尺寸。 是换向矩阵,在这里仅为1,因为两个输入都是向量。我尝试这样做,但得到的结果似乎没有帮助:mnpqABT
# playing with the kroneker derivative rule
A <- t(matrix(beta)) 
B <- matrix(rep(1, N))
diag(rep(1, ncol(A) *ncol(B))) %*% diag(rep(1, ncol(A))) %x% (B) %x% diag(nrow(A))
     [,1] [,2] [,3] [,4]
 [1,]    1    0    0    0
 [2,]    1    0    0    0
 snip
[13,]    0    1    0    0
[14,]    0    1    0    0
snip
[28,]    0    0    1    0
[29,]    0    0    1    0
[snip
[39,]    0    0    0    1
[40,]    0    0    0    1

这是不符合要求的。显然,我不了解那些Kronecker导数规则。那些方面的帮助会很棒。对于和,我仍然完全停留在其他派生类上,因为它们不会像那样累加地输入,所以它们更难。γΓ1β1

更新2

在阅读教科书时,我相当确定和将需要使用运算符。但是,我显然无法充分遵循派生方法,无法将其转换为代码。例如,将要涉及利用该衍生物的相对于,其中(目前我们可以将其视为恒定矩阵)。 R/Γ1R/γvec()R/Γ1wXΓ1Γ1w(γ1)σXΓ11

我的直觉是简单地说“答案是 ”,但这显然行不通,因为与不符。wXwX

我知道

(AB)=AB+AB

这个,那个

vec(wXΓ1)vec(Γ1)T=vec(XΓ1)Ivec(w)vec(Γ1)T+vec(w)Ivec(XΓ1)vec(Γ1)T
但我不确定如何评估它,更不用说对其进行编码了。

更新3

在这里取得进展。我昨晚凌晨2点醒来时就想到了这个主意。数学对睡眠不利。

这是,在一些符号糖之后:R/Γ1

  • w(γ1)σXΓ11
  • "stub"a(b(XΓ1))2ϵ^Γ2T

这是链规则的结尾,内容如下: 以这种循环方式开始和将对列进行下标,而是一致的身份矩阵:

RΓ1=wXΓ1Γ1("stub")
ijI
RΓij=(wiXi)T("stub"j)
RΓij=(IwiXi)T("stub"j)
RΓij=XiTIwi("stub"j)
tl; dr基本上是将存根乘以batchnorm比例因子。这应该等效于:
RΓ=XT("stub"w)

而且,实际上是:

stub <- (-2*u %*% t(G2) * ap(b(X%*%G1)))
w <- t(matrix(gamma)) %x% matrix(rep(1, N)) * (apply(X%*%G1, 2, sd) %>% t %x% matrix(rep(1, N)))
drdG1 <- t(X) %*% (stub*w)

loop_drdG1 <- drdG1*NA
for (i in 1:7){
  for (j in 1:4){
    loop_drdG1[i,j] <- t(X[,i]) %*% diag(w[,j]) %*% (stub[,j])
  }
}

> loop_drdG1
           [,1]       [,2]       [,3]       [,4]
[1,] -61.531877  122.66157  360.08132 -51.666215
[2,]   7.047767  -14.04947  -41.24316   5.917769
[3,] 124.157678 -247.50384 -726.56422 104.250961
[4,]  44.151682  -88.01478 -258.37333  37.072659
[5,]  22.478082  -44.80924 -131.54056  18.874078
[6,]  22.098857  -44.05327 -129.32135  18.555655
[7,]  79.617345 -158.71430 -465.91653  66.851965
> drdG1
           [,1]       [,2]       [,3]       [,4]
[1,] -61.531877  122.66157  360.08132 -51.666215
[2,]   7.047767  -14.04947  -41.24316   5.917769
[3,] 124.157678 -247.50384 -726.56422 104.250961
[4,]  44.151682  -88.01478 -258.37333  37.072659
[5,]  22.478082  -44.80924 -131.54056  18.874078
[6,]  22.098857  -44.05327 -129.32135  18.555655
[7,]  79.617345 -158.71430 -465.91653  66.851965

更新4

我认为这里是。第一R/γ

  • XΓ~(XΓμXΓ)σXΓ1
  • γ~γ1N

与之前类似,链式规则将您带到 循环为您提供 与以前一样,它基本上是预乘存根。因此,它应等效于:

Rγ~=γ~XΓ~γ~("stub")
Rγ~i=(XΓ~)iTIγ~i("stub"i)
Rγ~=(XΓ~)T("stub"γ~)

有点匹配:

drdg <- t(scale(X %*% G1)) %*% (stub * t(matrix(gamma)) %x% matrix(rep(1, N)))

loop_drdg <- foreach(i = 1:4, .combine = c) %do% {
  t(scale(X %*% G1)[,i]) %*% (stub[,i, drop = F] * gamma[i])  
}

> drdg
           [,1]      [,2]       [,3]       [,4]
[1,]  0.8580574 -1.125017  -4.876398  0.4611406
[2,] -4.5463304  5.960787  25.837103 -2.4433071
[3,]  2.0706860 -2.714919 -11.767849  1.1128364
[4,] -8.5641868 11.228681  48.670853 -4.6025996
> loop_drdg
[1]   0.8580574   5.9607870 -11.7678486  -4.6025996

第一个的对角线与第二个的对角线相同。但是实际上,由于导数是关于矩阵的-尽管矩阵具有某种结构,所以输出应该是具有相同结构的相似矩阵。我是否应该采用矩阵方法的对角线并将其简单地设为?我不确定。γ

看来我已经回答了自己的问题, 但不确定自己是否正确。在这一点上,我将接受一个可以严格证明(或反对)我被黑的东西的答案。

while(not_answered){
  print("Bueller?")
  Sys.sleep(1)
}

2
Magnus和Neudecker的第三版janmagnus.nl/misc/mdc2007-3rdedition的“矩阵微分微积分及其在统计和计量经济学中的应用”的第9章第14节 介绍了Kronecker产品的微分,并以Hadamard产品微分的练习作为结束。保罗·法克勒(Paul L. Fackler)的“关于矩阵微积分的笔记” www4.ncsu.edu/~pfackler/MatCalc.pdf 关于区分Kronceker产品有很多材料
Mark L. Stone

感谢您的参考。我之前已经找到了MatCalc笔记,但是它并不涵盖Hadamard,无论如何我都不确定来自非矩阵演算的规则是否适用于矩阵情况。产品规则,连锁规则等。我将研究这本书。我接受了,他说点我的所有成分的,我需要铅笔它自己...
generic_user

你为什么做这个?为什么不使用Keras / TensorFlow之类的framewroks?实施这些低级算法很浪费生产时间,您可以用它们来解决实际问题
Aksakal

1
更准确地说,我正在使用利用已知参数结构的网络-无论是输入数据的线性参数表示形式还是纵向/面板结构。已建立的框架已进行了高度优化,以至于超出我的能力进行修改/修改。再加上数学通常会有所帮助。很多代码猴子都不知道他们在做什么。同样,学习足够的知识Rcpp以有效地实施它也是有用的。
–generic_user

1
@ MarkL.Stone不仅在理论上听起来不错,而且实际上很简单!或多或少的机械过程!&%#$!
–generic_user

Answers:


1

不是一个完整的答案,而是要证明我在,其中,而是1的向量,则按照链式规则 注意到和,我们看到

b(X)=(XeNμXT)ΓΣX1/2+eNβT
Σ - 1 / 2 X = ð σ - 1 X 1σ - 1 X 2... Ê ñ &dtri; β - [R = [ - 2Γ=diag(γ)ΣX1/2=diag(σX11,σX21,)eN
βR=[2ϵ^(Γ2TI)JX(a)(IeN)]T
2ϵ^(Γ2TI)=vec(2ϵ^Γ2T)TJX(a)=diag(vec(a(b(XΓ1))))
βR=(IeNT)vec(a(b(XΓ1))2ϵ^Γ2T)=eNT(a(b(XΓ1))2ϵ^Γ2T)
通过身份。同样,,其中(“存根”),为vec(AXB)=(BTA)vec(X)
γR=[2ϵ^(Γ2TI)JX(a)(ΣXΓ11/2(XΓ1eNμXΓ1T))K]T=KTvec((XΓ1eNμXΓ1T)TWΣXΓ11/2)=diag((XΓ1eNμXΓ1T)TWΣXΓ11/2)
W=a(b(XΓ1))2ϵ^Γ2TKNp×p选择与方形矩阵的对角元素相对应的Kronecker乘积列的二进制矩阵。这是基于的事实。与第一个渐变不同,此表达式不等于您导出的表达式。考虑到是线性函数WRT,不应该有一个因素在梯度。我将的梯度了OP,但是对于固定推导,我会说,本文的作者试图避免这种“爆炸”。实际上,您还需要找到和 wrt的雅可比行列式dΓij=0bγiγiΓ1wΣXμXX 并使用产品规则。
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.