关于Matconvnet中模型发布与共享的思考

1. 前言

现阶段还坚持使用Matconvnet工具箱的一定是MATLAB的死粉。与TensorFlow、Keras相比,matconvnet的便捷性不够。但是,matlab与matconvnet提供了良好的交互调试功能,使得算法开发可以非常迅速得到验证。对于一个训练好的模型,如何迅速的进行测试,这篇博客会开放我对这类问题的处理方法和代码。

2. SimpleNN和 DagNN

参考:http://www.vlfeat.org/matconvnet/mfiles/+dagnn/@DagNN/DagNN/

接触过SimpleNN的童鞋应该记得,SimpleNN是通过struct结构体进行构建的。所以在发布模型或者共享模型的时候可以直接将结构体进行发布,再利用vl_simpnn进行评估就好了。

后来由于Simplenn定义太随性,使得代码非常容易出错。我讲的随性不是灵活,而是结构极其松散。牛津团队为了应付这个事,开始采用DagNN,也就是有向无环图进行网络的定义、训练,但是没有封装一个更好的用于DagNN评估函数。因此,我们只能通过vl_simplenn进行模型评估。也就是说,我们需要将DagNN转成SimpleNN,并去除掉损失函数层。下面开始详细说明我探索出来的一种方法:

首先将网络确定成DagNN类型:

net = dagnn.DagNN.loadobj(net) ; % 'struct' To 'dagnn' 

采用遍历的方式进行信息提取:

function simple_net = deployNet(net)
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.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

很多同学问我,为什么要将训练好的模型转成DagNN之后,在进行网络层和网络参数提取。这是因为我需要用DagNN封转好的一些函数,如getParamIndex()简化流程。

一旦训练好的网络得到了如上处理就可以直接用于测试。测试函数为:

res = vl_simplenn(net, instance)

这里需要注意两点: instance要求为single类型;我们需要用gpuArray(instance)将待测试数据放入到GPU中。

3. vl_simplenn解析

在使用vl_simplenn进行模型性能评估之前,我们都会进行如下操作:

net = vl_simplenn_tidy(net)  % matconvnet的版本适应性
res = vl_simplenn(net, inputdata)

http://www.vlfeat.org/matconvnet/mfiles/simplenn/vl_simplenn/

猜你喜欢

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