看cs231n课程时记录的一些小笔记(汇总, Updating...)

来源:互联网 发布:冠新软件怎么样 知乎 编辑:程序博客网 时间:2024/06/05 01:19

以前听说cs231n课程,稍微看了看,发现讲的很不错,故而记之,只记录本人认为有用的不准备分成多个博客了,全部杂糅放在这里得了。

更新方式

AdaGrad

cache += dx ** 2x += -learning_rate * dx/(np.sqrt(cache)+1e-7)

以前的SGD之类的,都是对每个参数运用同一个学习率,但是我们能不能对每个参数运用不同的学习率呢? AdaGrad就可以做到。可以看到这里x是所有参数的向量,所以cache记录的是历史中参数x的累计梯度。对于x的某一维来说,第二行会使得其学习率独立与其他维度的学习率。
1. 对于梯度大的方向,cache中的该方向会比较大,从而造成该方向的学习率变小。
2. 对于梯度小的方向,cache中的该方向的会比较小,从而相对于梯度大的方向,该方向的学习率相对增大。

这个更新方式的一个问题是cache会不断增大,最终导致无法更新。

RMSprop

这个是修改的AdaGrad

cache = decay_rate * cache +(1-decay_rate) * dx ** 2第二行一样

既然AdaGrad会随着不断的迭代使得最终所有参数的学习率降为0,这都是由于cache不断累加造成的。那么如果我每次将cache进行递减,那么即使训练很久,cache都不会太大。
decay_rate使得cache不会考虑以前所有的梯度,这是因为以前的梯度对此时的更新影响是指数递减的。一般decay_rate取0.99。

Adam

m = beta1*m + (1-beta1)*dx -- first momentv = beta2*v + (1-beta2)*(dx**2) -- second momentx += -learning_rate * m/(np.sqrt(v)+1e-7)

Adam将momentum和AdaGrad结合,可以看到就是最后一行不直接用dx了,而是用“带动量的”dx,即mm利用了前面几个batch的梯度的衰减和(第一行),同时第二行也使得其能在梯度大的方向步长减小,梯度小的方向步长稍微大点,也是利用前面几个batch的梯度的累计效果。、
更加完整的Adam:

m,v = 0for t in xrange(0, big_number):    dx = 0    m = beta1*m + (1-beta1)*dx -- first moment    v = beta2*v + (1-beta2)*(dx**2) -- second moment    m /= 1-beta1**t  -- correct bias    v /= 1-beta2**t  -- correct bias    x += -learning_rate * m/(np.sqrt(v)+1e-7)

在correct bias是对m,v初始值的一种补偿,会使得初始几次的更新时把m和v放大,但接下来就会没什么作用了。

另外有用二阶梯度的,一般用计算Hession矩阵,但是对于大矩阵求逆是不可能的。所以有BFGS,用秩为1的矩阵近似Hession。LBFGS对大量数据的效果不好。如果只是小数据,比如就一张图片Neural style的。那可以用LBFGS。

特殊层

下面两个特殊层在训练和测试时的计算是不一样的。

BN

Dropout

Dropout每次随机失活一些神经元,可以看成是对网络的一种抽样,防止过拟合有用,毕竟减少了很多神经元。Dropout前向传播时要将没有mask的神经元的输出除以p,这样训练时输出会放大,测试时就没必要减少激活值。测试时让所有神经元都激活。

可视化

可视化分为2种,一种是可视化kernel的某一层的。另外一种是可视化feature map的。
可视化其实是重建,就是我们想知道weights学到了什么,描述的是什么特征提取。或是网络中某一层出来的特征是什么样的。我们当然不是直接输出通道值。我们需要将weights或是feature map重建出raw images(比如RGB图像)。

可视化weights

对于某层的某个kernel的某个通道感兴趣,那么先前向传播,到那层停止。将那个通道的梯度置为1.00,其他通道全部为0(比如那层是512*128*3*3,我对第一个2个kernel的第3个通道感兴趣,那么就是[2, 3, :, :] = 1.00,其他为0,重建出来比如是3*128*128)。

三种不同的策略

最naive

就按照上面那样传呗。不过可视化出来的特征会比较乱,看不清每个kernel的每个通道的作用。

Guided BP

这个主要是对于Relu的激活进行更改。
original relu BP:对于前向输入为负值的地方,直接梯度为0;前向出入正值的地方,梯度直接通过。(值为0的地方随便让其梯度为0或是通过,没啥区别)
Guided BP: 反传时不仅那些前向输入为负值的地方梯度置为0(naive BP的基本要求), 而且还让那些梯度为负值的地方,也让其置为0!
这种会得到比较清晰的weights可视化。对于这两种现象的一种解释是,梯度为负值的地方,可以看成是对前一层有negative of influences,梯度为正值,则为positive influences。 如果全部都传,浙西效果会相互影响,故而会混乱。 而Guided BP只保留正值的影响。

Visualizing的那篇

只要是梯度是正值,就往前一层丢。效果也很好。
个人觉得可视化权值采用第二种或是第三种吧。

参考论文:
Deep Inside Convolutional Networks: Visualising Image Classification Models and Saliency Maps
Visualizing and Understanding Convolutional Networks
Striving for Simplicity: The All Convolutional Net

可视化特征

可视化特征是值,将某一层输出的feature maps进行重建,即以三维的RGB图进行其特征再描述,转换为人类可以看的明白的东西。否则你输出的一团 128*16*16的东西怎么看?
Understanding Deep Image Representations by Inverting Them,用这种不断迭代优化的方法。核心思想是,先用一个随机的图像,如果这个图像经过某些层的输出与那个图像在那一层的feature map尽量一样就行。比如我让一座房子的图像经过VGG到conv5层,不说了,太简单了没啥说的。
另外一点是,其实直接用Neural style,让其只匹配content image就行,就是值用content loss重建就行。

卷积的代码实现方式

先想一下到底是怎么卷的。
以卷积核为主体,比如有 M个,比如 M*C*3*3,图像大小为 C*W*H。
M个卷积核在图像上进行滑动。那么我们要将其转换为两个矩阵相乘:
M个卷积核: M*(3*3)
假设能在W*H(加入了pad)上能滑动的位置有N个。
显然

N=imageh+2padhkernelh/strideh+1imagew+2padwkernelw/stridew+1

那么卷积为:
AB=[M(33C)][(33C)N]=MN
最终得到的矩阵是MN,其中M是输出的维度,而N就是每个feature map的向量形式。

为了方便起见,从Caffe的卷积原理 引用一个例子,其中C=1:
[1201][2131]是两个卷积核,输入图像为
312101213那么,如果不加pad。那么我们首先将M个卷积核写成二维矩阵形式:

A=[12032111]
再将每个位置的信息图像写成矩阵形式(有4个位置):

B=3110120110210113
然后(称为 im2col):
AB=[12032111]3110120110210113=[510296557]
最终得到两个feature map(称为 col2im)

[5625][10597]

值得注意的是,这里只列举了C=1的情况,对于跟大的C也是类似展开,展开方式也是一样,从左到右,从第一维到第C维。
这里有两张图,拿去看吧。。
这里写图片描述
这里写图片描述

原创粉丝点击