在CIFAR-10实例中加入dropout
假如我们要在cifar-10实例中的ip1和ip2层之间加入dropout,那么我们可以定义一个drop1的层,其类型为Dropout,设置底层blob为ip1,顶层blob也为ip1(为了与原来的层匹配,也可以用其它名字,但是要保证各层之间必须能够衔接上)。然后设置dropout_ratio。至此,就为CIFAR-10实例加入了dropout。加入dropout后,重新运行程序进行训练即可。具体代码如下:
layer {
name:"drop1"
type:"Dropout"
bottom:"ip1"
top:"ip1"
dropout_param {
dropout_ratio: 0.5
}
}
保存退出,开始训练。
训练后结果:
I1109 11:34:22.086735 8475 solver.cpp:310] Iteration 2000, loss = 1.08831
I1109 11:34:22.086763 8475 solver.cpp:330] Iteration 2000, Testing net (#0)
I1109 11:34:43.837874 8478 data_layer.cpp:73] Restarting data prefetching from start.
I1109 11:34:44.743183 8475 solver.cpp:397] Test net output #0: accuracy = 0.6436
I1109 11:34:44.743232 8475 solver.cpp:397] Test net output #1: loss = 0.991287 (* 1 = 0.991287 loss)
I1109 11:34:44.743238 8475 solver.cpp:315] Optimization Done.
I1109 11:34:44.743252 8475 caffe.cpp:259] Optimization Done.
从实验结果可以知道,加了Dropout层之后,虽然没有提高识别效果,但是降低了过拟合。
调整batch_size参数
首先batch_size指每次迭代训练图片的数量。
资料上说增大batch_size的好处有三点:
1)内存的利用率提高了,大矩阵乘法的并行化效率提高。
2)跑完一次epoch(全数据集)所需迭代次数减少,对于相同的数据量的处理速度进一步加快。
3)一定范围内,batchsize越大,其确定的下降方向就越准,引起训练震荡越小。
同样,盲目增大的弊端也有三点:
1)当数据集太大时,内存撑不住。
2)跑完一次epocffe-master/tools/extra/parse_log.sh caffe-master/tools/extra/extract_seconds.py和h(全数据集)所需迭代次数减少了,但要想达到相同的 精度,时间开销太大,参数的修正更加缓慢。
3)batchsize增大到一定的程度,其确定的下降方向已经基本不再变化。
实验
batch_size大小默认值是100,我增大到了200。
data_param {
source: "examples/cifar10/cifar10_train_lmdb"
batch_size: 200
backend: LMDB
}
再跑一下数据:
I1109 13:59:48.339932 9762 solver.cpp:310] Iteration 2000, loss = 0.88682
I1109 13:59:48.339977 9762 solver.cpp:330] Iteration 2000, Testing net (#0)
I1109 14:00:09.803097 9765 data_layer.cpp:73] Restarting data prefetching from start.
I1109 14:00:10.693827 9762 solver.cpp:397] Test net output #0: accuracy = 0.7025
I1109 14:00:10.693874 9762 solver.cpp:397] Test net output #1: loss = 0.873489 (* 1 = 0.873489 loss)
I1109 14:00:10.693881 9762 solver.cpp:315] Optimization Done.
I1109 14:00:10.693895 9762 caffe.cpp:259] Optimization Done.
比较和前面测试结果中的loss值,发现降低了0.1左右.
batch_normalization
简要的解释
在训练深层神经网络的过程中, 由于输入层的参数在不停的变化, 因此, 导致了当前层的分布在不停的变化, 这就导致了在训练的过程中, 要求 learning rate 要设置的非常小, 另外, 对参数的初始化的要求也很高.
Batch Normalization 的提出就是为了解决这个问题的. BN 在每一个 training mini-batch 中对每一个 feature 进行 normalize. 通过这种方法, 使得网络可以使用较大的 learning rate, 而且, BN 具有一定的 regularization 作用.
batch normalization直译过来就是批规范化。
在caffe中,可选参数定义在caffe根目录下的/src/caffe/proto/caffe.proto.
message BatchNormParameter {
// 如果为真,则使用保存的均值和方差,否则采用滑动平均计算新的均值和方差。
// 该参数缺省的时候,如果是测试阶段则等价为真,如果是训练阶段则等价为假。
optional bool use_global_stats = 1;
// 滑动平均的衰减系数,默认为0.999
optional float moving_average_fraction = 2 [default = .999];
// 分母附加值,防止除以方差时出现除0操作,默认为1e-5
optional float eps = 3 [default = 1e-5];
}
实验
继续修改cifar10_quick_train_test.prototxt,添加batchnormal层。
layer {
name: "BatchNorm1"
type: "BatchNorm"
bottom: "conv1"
top: "conv1"
param {
lr_mult: 0
decay_mult: 0
}
param {
lr_mult: 0
decay_mult: 0
}
param {
lr_mult: 0
decay_mult: 0
}
}
保存退出,进行迭代测试。
结果如下:
I1110 10:42:33.898412 7974 solver.cpp:310] Iteration 2000, loss = 1.08552
I1110 10:42:33.898449 7974 solver.cpp:330] Iteration 2000, Testing net (#0)
I1110 10:43:05.795646 7977 data_layer.cpp:73] Restarting data prefetching from start.
I1110 10:43:07.118332 7974 solver.cpp:397] Test net output #0: accuracy = 0.6058
I1110 10:43:07.118378 7974 solver.cpp:397] Test net output #1: loss = 1.11712 (* 1 = 1.11712 loss)
I1110 10:43:07.118384 7974 solver.cpp:315] Optimization Done.
I1110 10:43:07.118391 7974 caffe.cpp:259] Optimization Done.
loss下降了0.3。其实batchnormal做了两件事
1) 输入归一化 x_norm = (x-u)/std, 其中u和std是个累计计算的均值和方差。
2)y=alpha×x_norm + beta,对归一化后的x进行比例缩放和位移。其中alpha和beta是通过迭代学习的。
caffe 神经网络中的激活函数
6种激活函数的定义
1.1 ReLU / Rectified-Linear and Leaky-ReLU
ReLU是目前使用最多的激活函数,主要因为其收敛更快,并且能保持同样效果。
标准的ReLU函数为max(x, 0),当x>0时,输出x; 当x<=0时,输出0
f(x)=max(x,0)
1.2 Sigmoid
1.3 TanH / Hyperbolic Tangent
1.4 Absolute Value
f(x)=Abs(x)
1.5 Power
f(x)= (shift + scale * x) ^ power
1.6 BNLL binomial normal log likelihood的简称
f(x)=log(1 + exp(x))
如何使用这几种函数
比如我添加了sigmoid函数
layer {
name: "encode1neuron"
bottom: "encode1"
top: "encode1neuron"
type: "Sigmoid"
}
测试结果如下:
I1110 16:36:08.785380 3022 solver.cpp:310] Iteration 2000, loss = 1.44096
I1110 16:36:08.785424 3022 solver.cpp:330] Iteration 2000, Testing net (#0)
I1110 16:36:34.700467 3025 data_layer.cpp:73] Restarting data prefetching from start.
I1110 16:36:35.746063 3022 solver.cpp:397] Test net output #0: accuracy = 0.4705
I1110 16:36:35.746104 3022 solver.cpp:397] Test net output #1: loss = 1.4736 (* 1 = 1.4736 loss)
I1110 16:36:35.746124 3022 solver.cpp:315] Optimization Done.
I1110 16:36:35.746129 3022 caffe.cpp:259] Optimization Done.
在激活层中,对输入数据进行激活操作(实际上就是一种函数变换),是逐元素进行运算的。从bottom得到一个blob数据输入,运算后,从top输入一个blob数据。在运算过程中,没有改变数据的大小,即输入和输出的数据大小是相等的。
输入:n*c*h*w
输出:n*c*h*w