深度网络模型裁剪和发布正规化

1.导读

关于Matconvnet中模型发布与共享的思考:https://blog.csdn.net/shenziheng1/article/details/81316760

前面讨论了,如何利用vl_simplenn应用训练好的模型。有一些朋友问我,明明可以直接通过net.val评估函数进行处理,为什么还要单独发布模型,是不是多此一举?

其实,采用模型直接进行评估,或者采用网络裁剪后应用,完全看个人所需。就我自己而言,训练多分支结构用于跟踪领域,如果采用网络直接进行评估是非常消耗时间的。但是,在跟踪领域,跟踪的速度是一个非常重要的的指标!但是,既然有朋友指出来了,我直接对两种测试网络方式都放在这里,需要那种可以直接用。

  • 利用DagNN的评估函数,评估原始网络,用于测试模式;
  • 利用我共享的代码进行网络裁剪,提取网络核心成分用于测试;
  • 此外,这篇博文也增加了对BatchNorm的讨论

2. DagNN的评估函数 eval

netStruct = load('net_name.mat');
net = dagnn.DagNN.loadobj(netStruct.net);
net.mode = 'test'; % 非常重要
net.move('gpu');
net.conserveMemory = false;
im = rand(32,32,1,'single'); % 测试数据
net.eval({'data_rand',gpuArray(im)}); % 测试数据索引
result = gather(net.vars(net.getVarIndex(('G3x'))).value);

3. 采用我编写的裁剪网络提取主干

function simple_net = deployNet(net)
% keep single branch network, then called L2 norm to calculate similarity
input = 'target';
output = 'block3x';
simple_net = [];
simple_net.layers = [];
simple_net.meta = net.meta;

while ~strcmp(input,output)
    for i = 1:numel(net.layers)
        if numel(net.layers(i).inputs) == 1 && strcmp(net.layers(i).inputs{1},input)
            input = net.layers(i).outputs{1};
            if isa(net.layers(i).block,'dagnn.Conv')
                simple_net.layers{end+1} = struct(...
                    'name', net.layers(i).name, ...
                    'type', 'conv', ...
                    'weights', {{net.params(net.getParamIndex(net.layers(i).params{1,1})).value,...
                    net.params(net.getParamIndex(net.layers(i).params{1,2})).value}}, ...
                    'pad', net.layers(i).block.pad, ...
                    'stride', net.layers(i).block.stride,...
                    'dilate',net.layers(i).block.dilate) ;
            elseif isa(net.layers(i).block,'dagnn.BatchNorm')
                simple_net.layers{end+1} = struct(...
                    'name', deal(net.layers(i).name), ...
                    'type', 'bnorm',...
                    'weights',{{net.params(net.getParamIndex(net.layers(i).params{1,1})).value,...
                    net.params(net.getParamIndex(net.layers(i).params{1,2})).value,...
                    net.params(net.getParamIndex(net.layers(i).params{1,3})).value}} ) ;
            elseif isa(net.layers(i).block,'dagnn.ReLU')
                simple_net.layers{end+1} = struct(...
                    'name', deal(net.layers(i).name), ...
                    'type', 'relu') ;
            elseif isa(net.layers(i).block,'dagnn.Pooling')
                simple_net.layers{end+1} = struct(...
                    'name',  deal(net.layers(i).name), ...
                    'method',deal(net.layers(i).block.method),...
                    'pool',  deal(net.layers(i).block.poolSize),...
                    'stride',deal(net.layers(i).block.stride),...
                    'pad',   deal(net.layers(i).block.pad),...
                    'type',  'pool');
            elseif isa(net.layers(i).block,'dagnn.LRN')
                simple_net.layers{end+1} = struct(...
                    'name', deal(net.layers(i).name), ...
                    'type', 'lrn',...
                    'param',net.layers(i).block.param) ;
            else
                error('No such layer!');
            end
            continue;
        end
    end
end

这段代码可以直接调用。之前发布的那个版本由于没有添加BatchNorm层,这个版本涵盖了所有成分。

我亲自用孪生网络测试过,利用裁剪后的网络要比利用完整网络跟踪速度提升477%。

3. 关于BatchNorm的补充

Double_V_博主维护的https://blog.csdn.net/qq_25737169/article/details/79048516 (基础 | batchnorm原理及代码详解)质量非常高。这里,引用一下他的工作作为参考。

1. BatchNorm到底涉及到哪些参数?

Batchnorm(x, gamma, beta, bn_param):
"""
param:x    : 输入数据,设shape(B,L)
param:gama : 缩放因子  γ
param:beta : 平移因子  β
param:bn_param   : batchnorm所需要的一些参数
    eps      : 接近0的数,防止分母出现0
    momentum : 动量参数,一般为0.9, 0.99, 0.999
    running_mean :滑动平均的方式计算新的均值,训练时计算,为测试数据做准备
    running_var  : 滑动平均的方式计算新的方差,训练时计算,为测试数据做准备
"""

这里需要额外说明的是bn的学习参数,使用MatConvNet的都知道,我们学习好BatchNorm层之后会返回三个参数值,bn_f / bn_b / bn_c。 如果前面两个用来表征Batch的均值和标准差,那第三个参数是什么?

其实,BatchNorm的原理就是用一系列Batch去评估整个数据集整体的均值和方差。这其实是有有偏估计,最简单的方法就是引入时间平滑。

2. BatchNorm到底有对多大用?是不是有了BatchNorm就一定能够避免过拟合?

不是这样的,小心做好自己的训练集。争取使得训练集可以做到独立同分布。否则极其容易过拟合(现象:训练集的误差非常小,然而验证集的误差很大)。

猜你喜欢

转载自blog.csdn.net/shenziheng1/article/details/81350061