本帖最后由 matlab的旋律 于 2020-9-1 19:14 编辑
1.前言从上世纪90年代以 LeNet为开始代表的卷积神经网络,2012年又以AlexNet为起始点爆发,在深度学习领域中成为炙手可热的网络框架,特别是在机器视觉领域更是超群绝伦。此后的ZF-Net到VGG-Nets,GoogleNet再到ResNet以及DenseNet,以追求提升识别精确率为主要目的,采用手段的主要方向包括加深网络结构和增强卷积模块功能,同时这也导致了整个用于识别的网络越来越复杂,需要的内存和算力也大大增加。SqueezeNet开辟了另外一个方向:在保证模型精度不降低的前提下,最大程度的提高运算速度。它能够在ImageNet数据集上达到近似AlexNet的效果,但是参数量相比AlexNet少了50倍,同时结合模型压缩技术 Deep Compression,SqueezeNet模型文件相比AlexNet小约510倍。 SqueezeNet与几乎同一时期提出的MobileNet、ShuffleNet和Xception被称为当前的四大轻量级模型,但SqueezeNet是最早在arXiv上公开的。 2.网络结构SqueezeNet创新点在于提出了fire module,包括两个部分,squeeze和expand,如下图所示。 其中的squeeze 在 SqueezeNet的结构中表示一个 squeeze 层,该层采用 1*1 卷积核对上一层 feature map进行卷积,其主要目的是降低feature map 的维数。expand使用的Inception结构,包括1*1和3*3卷积,然后拼接,Matlab实现的代码如下: - lgraph = layerGraph();
- tempLayers = [
- convolution2dLayer([1 1],16,"Name","fire2-squeeze1x1")
- reluLayer("Name","fire2-relu_squeeze1x1")];
- lgraph = addLayers(lgraph,tempLayers);
- tempLayers = [
- convolution2dLayer([3 3],64,"Name","fire2-expand3x3","Padding",[1 1 1 1])
- reluLayer("Name","fire2-relu_expand3x3")];
- lgraph = addLayers(lgraph,tempLayers);
- tempLayers = [
- convolution2dLayer([1 1],64,"Name","fire2-expand1x1")
- reluLayer("Name","fire2-relu_expand1x1")];
- lgraph = addLayers(lgraph,tempLayers);
- tempLayers = [
- depthConcatenationLayer(2,"Name","fire2-concat")];
- lgraph = addLayers(lgraph,tempLayers);
- lgraph = connectLayers(lgraph,"fire2-relu_squeeze1x1","fire2-expand3x3");
- lgraph = connectLayers(lgraph,"fire2-relu_squeeze1x1","fire2-expand1x1");
- lgraph = connectLayers(lgraph,"fire2-relu_expand1x1","fire2-concat/in1");
- lgraph = connectLayers(lgraph,"fire2-relu_expand3x3","fire2-concat/in2");
- plot(lgraph)%绘图
复制代码得到的流程图如下图图所示: 由于两个卷积过程使用的stride都是1,因此输出的数据结构仅仅在于通道数上的差异,拼接后的数据是1*1和3*3卷积后的数据在通道上之和。其中所有的1*1和3*3卷积使用的padding方式分别为[0,0,0,0]和[1,1,1,1]。
整个SqueezeNet的结构使用Matlab中plot函数对深度学习网络结构的表示如下图所示: 从图中可以看出SqueezeNet中一共包含了8个fire module,其中在第3和第5个fire module使用了3*3的最大池化,对应池化层的stride都为2*2,将进行下采样的池化层下移动的原因是作者认为较大的Feature Map含有更多的信息。当然这样的操作虽然会提升网络的精度,但同时也带来一个问题,也就是会导致网络的计算量增加。 3.模型迁移在深度学习行业内一个普遍存在的问题就是在面对某一领域的某一特定问题时,找到足够充分的训练数据非常困难。因此,如果能够使用其他数据集训练得到的成熟模型,经过一定的修改和完善,然后可以复用在与之类似的领域,这样就可以大大的缓解数据源不足导致的问题。当前,能够解决这个问题的一个关键技术就是迁移学习。 迁移学习主要过程包括: 1) 使用现成的数据集训练好模型,保存为预训练模型; 2) 在预训练模型中定位输出为可复用特征(feature)的层次(layer); 3) 将可复用特征的层次的输出作为新模型的输入,进行重新训练。 其中,这里进行预训练的数据集和迁移学习的数据集可以对应完全不同的待解问题,例如样本的尺寸相同,样本标签数目却不一样等。由于此前的预训练模型已经学习得到了数据的组织模式,因此进行迁移学习的网络只需要学习数据集中针对某一特定问题的相关性问题就可以了。简而言之,迁移学习具有的优势可以总结为: 1) 适应小样本,迁移学习能够将大样本数据进行训练的模型迁移到只有小样本的数据领域,实现小样本数据的落地。 2) 提高鲁棒性,通过迁移学习所得到的模型具有普适性,可以迁移到多个不同的领域而不至于产生显著的性能下降。 3) 个性化定制,对应每个问题的个性化样本规模可能不大,但是在通过大数据训练的模型基础上进行迁移学习,就能很好的解决个性化的问题,也可以形象的比如为站在巨人的肩膀上。
下面使用小迈步视频课程上的一个例子,对SqueezeNet进行迁移学习用于Cap、Cube、MWBottle、NFSQ、PlayingCards、Screwdriver和Torch七大类物品的识别。对应的迁移学习步骤和代码如下: - %加载Squeezenet模型并修改
- net = squeezenet();
- lgraph = layerGraph(net);
- inputSize = net.Layers(1).InputSize;
- numClasses = numel(categories(imdsTrain.Labels));
- % 删除squeezenet的最后5层
- lgraph = removeLayers(lgraph, {'conv10', 'relu_conv10', ...
- 'pool10', 'prob', 'ClassificationLayer_predictions'});
- %定义一个卷积核大小为2的卷积层
- conv10 = convolution2dLayer( ...
- 1, numClasses, ...
- 'Stride', 1, ...
- 'Padding', 0, ...
- 'Name', 'conv10');
- relu_conv10 = reluLayer('Name', 'relu_conv10');
- pool10 = averagePooling2dLayer( 14, 'Stride', 1, 'Padding', 0, 'Name', 'pool10');
- %其中新网络的最后5层如下:
- newLayers = [
- conv10
- relu_conv10
- pool10
- softmaxLayer('Name', 'softmax')
- classificationLayer('Name', 'classoutput')];
- % 添加并连接到网络的最后一层 'drop9'层
- lgraph = addLayers(lgraph, newLayers);
- lgraph = connectLayers(lgraph, 'drop9', 'conv10');
复制代码 4.实验结果
对上述迁移学习的模型进行训练,其中具体训练的参数设置可以点击阅读原文参看对应的Matlab源码。其中训练过程详细图示如下图。可以看出经过20轮训练集和验证集都达到了100%的准确率,损失函数值也收敛到了近0值,另外使用的时间仅为42秒。 如下图所示,通过对测试集4张图片的识别其结果也完全正确,这些也说明轻量级网络SqueezeNet在迁移学习上高效性,以及部署到性能较低的单片机上的可行性。 参考文献: 论文:SQUEEZENET: ALEXNET-LEVEL ACCURACYWITH 50X FEWER PARAMETERS AND <0.5MB MODEL SIZE 欢迎加入深度学习算法交流群学习交流。
|