在学习了FCN之后特别地兴奋, 也许这就是网络结构的创意带来的思路上的刺激感吧, 于是开始跑一个FCN试试, 还是觉得 Siftflow-fcn8s 比较靠谱, 一个是数据量适当, 另一个是训练任务比较适合现在正在做的事情, 于是训练了一下官方demo, 之后又训练了Pascal-context的任务
理论部分参考我的另一篇文章: Fully Convolutional Networks
原论文 : Fully Convolutional Networks for Semantic Segmentation
siftflow-fcn8s
网络结构
- 在 sift-flow数据集上有两个任务,一个是语义分割(33类+背景类);另一个是几何分割(3类+背景类), 用caffe自带的工具将siftflow-fcn8s的网路结构画出来, 由下图可知, 该网络完成了两个任务的训练
训练步骤
在Github上clone代码: FCN代码
数据准备:将下载的数据集解压到
fcn.berkeleyvision.org/data/sift-flow
将
siftflow_layers.py
和surgery.py
还有score.py
文件复制到fcn.berkeleyvision.org/siftflow-fcn8s
文件夹运行
python net.py
生成训练的trainval.prototxt
和测试的test.prototxt
运行
solve.py
训练网络, 大约需要十八个小时左右(NVIDIA K40m)
运行结果:
1 | >>> 2016-12-02 04:36:48.858090 Iteration 100000 loss 31759.9664818 |
- 和论文结果相差零点几个百分点, demo训练成功, 下面我们要基于该网络做
Python Layer
数据制作问题:
caffe的label必须是从自然数N连续的开始的。0,1,2,…,N,这就表示了具有N+1个类别的标签label。
Caffe通过Boost中的Boost.Python
模块来支持使用Python定义Layer
使用C++增加新的Layer繁琐耗时
开发速度与执行速度之间的权衡
在网络的输入层可以使用python自己加载数据, 但是在编译caffe的时候要将Makefile.config文件中的WITH_PYTHON_LAYER := 1
注释掉, 在用net.py
生成的trainval.prototxt中定义如下:
1 | layer { |
module
的名字,通常是定义Layer的.py文件的文件名,需要在$PYTHONPATH下layer
是定义的类的名字
SIFTFlowSegDataLayer在siftflow_layers.py的文件中被定义为一个类:
1 | import caffe |
- 在定义layer的python文件中, 类的名称就是在prototxt中
参数layer
的名称 - 类直接继承的是
caffe.Layer
,然后必须重写setup()
,reshape()
,forward()
,backward()
函数,在该类中也可以定义其他函数 setup()
是类启动时该层所需数据的初始化等操作reshape()
是读取数据然后规范化为四维的矩阵forward()
是网络的前向运算,这里就是把取到的数据往前传递,因为data层没有其他运算backward()
就是网络的后向求导,data层是没有反馈的就直接pass
了解如何在C++中创建新的layer : Making a Caffe Layer
构建网络
构建网络网络本质上就是生成训练和测试的.prototxt文件
, 在这里直接用net.py
定义网络结构, 运行该python文件就可以生成相应的prototxt文件
, 网络所有参数在net中定义
1 | import caffe |
- 注意在
Fine-tuning
(微调)一个网络的时候, 由于output_num
已经改变, 要将所有含有output_num
发生改变的层重命名, 原因是在我们下载的caffemodel中已经包含原有的层名称, 而在.prototxt
中我们更改了输出参数, 在加载caffemodel时, 如果层名称一样但是数据结构不同, 就会报错, 重命名之后模型中原有的层会被忽略继而使用我们自己定义的新的层
solver.prototxt
1 | train_net: "trainval.prototxt" |
如何更改FCN的batch size?
- 最简单的方式是更改
iter_size
参数, 在文中iter_size: 1
$, 也就是说每次迭代输入一个样本, 即batch_size=1
test_iter: 1000
: 由于我们的batchsize=1, 测试样本数为1000, 需要迭代1000次才能完成
Pascal-Context
数据的准备和设置就不多说了在Github的README上都有, 主要有三个方面:
- JPEG原始图片
- mat文件的label
- 下载caffemodel
然后在相应的python文件中设置路径就可以了
网络结构
通过更改net.py生成了111类(包括背景类)的分类模型, 运行net.py
可以生成train.prototxt
和val.prototxt
, 网络结构如下:
Python Layer
Pascal-Context的Python Layer定义如下:
1 | import caffe |
值得注意的是在Python Layer中对于label的处理方式, 我们将源代码中的对于label的处理程序抽取出来:
1 | import numpy as np |
- 通过打印输出可以得出结论: 将459类映射为59类的标签数据, 所以在制作自己的数据集的label的时候直接返回自己的标签就可以了, 不用这些处理, 更改后的net.py文件如下: 仅供参考
1 | import caffe |
训练模型
运行
net.py
生成train.prototxt
和val.prototxt
可以更改
solver.prototxt
更改训练策略, 运行solve.py
训练模型