训练网络的一些trick(1):pre_train与逐层拷贝网络


最近做detection方面的工作,在实际训练方面做了一些尝试,这一篇主要记录对于网络pre_train的理解。


首先说pre_train,目前几乎所有做detection的网络都会用到这个技巧,相比于ImageNet数据集里张百万甚至千万的图片量,detection数据集几万张的图片量实在有些少(Pascal VOC、COCO),单纯用这些图片去训练一个比较深的随机初始化的cnn然后得到一个比较好的结果几乎是不可能的事情,基本一开始就是loss=NaN。这时候就用到pre_train的技巧,先构建一个分类网络(比如VGG16)并且用ImageNet来训练,这样得到一个能提取较好特征的卷积网络,然后把后面几层用来分类的fc层去掉,换成做detection的rpn、roi或者其他的层,相当于detection训练的一开始就能得到一个比较好的卷积特征(虽然是用来分类的),这样就解决了网络难训练的问题(或者数据量不够的问题?)。


在做的项目里,比如我要检测非自然图像里的一个特定形状(比如在七龙珠动画片里检测龙珠。。或者其他什么奇怪的东西),那么有两个问题,1)我做检测的domain和正常检测的domain是不一样的,是在非自然图像中的(而不是一张照片),这样分类任务训练好的特征提取器(pre_train model)可能不会很好的适用,或许应该在相同domain下训练一个提取器会比较好,这样就引出另一个问题,2)数据量不够。没有一个大型的动画片的分类数据库,而且用作detection的训练数据也并不很多(大概3000张)。然后我自己做了一些探索和猜想。


首先domain的问题几乎没办法解决,除非有一个大的数据集;而数据量的问题(或者说优化detection的问题更合适),可以参考pre_train的过程。博主认为pre_train的过程从梯度下降的角度来考虑,相当于随机初始化等于把参数坐标随机设置到一个位置,这样距离高维空间中的最优解坐标相差非常远,而分类任务的最优解和detection最优解是有一些共通之处的,比如前面conv层提取的特征对于两个任务都有效,两个任务最优解在高维空间的位置可能相对比较接近(当然这两的维度都不一样,这是一个不是很恰当的比喻),而pretrain相当于把最开始随机初始化的参数坐标向着最优位置移动了一大步,这样利用有限的detection训练数据就有可能达到比较好的结果(比随机初始化要好)。


那么,对于要做的detection任务,在voc07或其他数据集上训好的model是不是比分类的pretrain model更接近最优解呢?要知道分类的model最后不会保留fc层,那pvanet来说,最后两层fc6、fc7共有2*4096*4096几千万的参数量,很大的数量级,更不用提还有rpn的一些层。基于这个猜想做了一些实验。


SSD的实验:用在Pascal voc上训练好的ssd300去初始化新任务的网络,base网络是VGG16,除了输出类别数目不同的层其它层全部复制(主要多了fc层),分类网络初始化map在17%左右,新的方法map提升到30%左右。数值整体比较差我认为是数据量和标注质量的问题。

pvanet的实验:几乎同样的做法,map从31%提高到35%,base网络是论文作者release出代码中的默认网络。


以上的实验和猜想都并不严格,还存在很多改进空间甚至是错误之处,欢迎指正。


附逐层拷贝网络的方法:

1.利用pycaffe的接口,初始化net之后会有一些给出的接口来操作net的param,这个在net_surgery里面有很好地例子。这里贴一些其他接口的代码。

if (net.layers[i].type == 'Convolution') or (net.layers[i].type == 'Scale'):
            net.layers[i].blobs[0].data.flat = net_.layers[i].blobs[0].data.flat
            #net.layers[i].blobs[1].data.flat = net_.layers[i].blobs[1].data.flat

主要给出了layer、blobs、data的接口,conv层blob有两个,bn层一般有3个。

2.拆分caffemodel成prototxt。拆分后的结果如下:

layer {
  name: "conv1"
  type: "Convolution"
  bottom: "data"
  top: "conv1"
  param {
    lr_mult: 1.0
  }
  param {
    lr_mult: 2.0
  }
  blobs {
    data: 0.264199763536
    data: -0.220321893692
    data: -0.251213937998
    data: 0.150178313255
    ...
    data: -0.05886515975
    data: 0.0170712769032
    data: -0.185302212834
    shape {
      dim: 70
      dim: 3
      dim: 3
      dim: 3
    }
  }

  blobs {
    data: 0.0
    data: 0.0
    data: 0.0
      ...
    data: 0.0
    data: 0.0
    shape {
      dim: 70
    }
  }
  phase: TEST
  convolution_param {
    num_output: 70
    kernel_size: 3
    stride: 1
    weight_filler {
      type: "xavier"
    }
    bias_filler {
      type: "constant"
    }
  }
}
这是一个conv层的形式。这种方法解析出来的prototxt文件太大,非常难操作,虽然比较直观,但还是不建议这样做。

附拆分代码:

import caffe.proto.caffe_pb2 as caffe_pb2

caffemodel_filename = 'deploy.caffemodel'

model = caffe_pb2.NetParameter()

f = open(caffemodel_filename, 'rb')
model.ParseFromString(f.read())
f.close()

proto_file = open('deploy.prototxt', 'w')
proto_file.write(str(model.__str__))
proto_file.close()
print 'all done'



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值