写在前面,由于 FCN 是基于 Caffe 的,所以准备工作是先配置好 Caffe ~
配置 Caffe 参考 :Ubuntu 16.04下Caffe的配置过程
这是 Caffe 的主程序,里面包含了各种网络层以及函数的实现。下载好之后,编译运行,跑通 mnist,证明你已经装好caffe。
下面主要介绍的是:
- 用训练好的 model 进行测试,看看 FCN 的效果;
- 重新训练 model 后进行测试,与论文中的实验指标进行比较;
这里是官方已经训练好的 model,可以直接进行测试看看效果:http://dl.caffe.berkeleyvision.org/
FCN 项目文件说明
下载 FCN:fcn.berkeleyvision.org,并将 fcn-master 放在 caffe 的主目录下。
fcn-master 整个项目文件如下:
FCN 包括以下几种模型:
- PASCAL VOC models
- NYUDv2 models
- SIFT Flow models
- PASCAL-Context models
1. 用训练好的模型进行语义分割
下载 voc-fcn32s、voc-fcn16s、voc-fcn8s 的 caffemodel(在对应文件夹下的 caffemodel-url
里下载)
添加python接口
由于 fcn-master 和 caffe 是两个独立的文件夹,所以要将 caffe 的 python 接口添加到 path 中。
第一种方法:在所有代码中出现import caffe 之前,加入
import sys
sys.path.append('caffe 根目录/python')
第二种方法:在 bashrc 中将接口加入到 PYTHONPATH
中
export PYTHONPATH=caffe根目录/python:$PYTHONPATH
明显第二种方法更简单哈。
修改测试文件
根据自己的实际情况修改 infer.py
,这里就不改了,因为 demo 里就包含了测试图片,可以直接运行。
im = Image.open('demo/image.jpg')
是将要测试的图片的路径及名称net = caffe.Net('voc-fcn8s/deploy.prototxt', 'voc-fcn8s/fcn8s-heavy-pascal.caffemodel', caffe.TEST)
是 voc-fcn8s 文件夹下的部署文件和训练好的模型out_im.save('demo/output.png')
将分割结果 output.png 保存在 demo 文件夹中masked_im.save('demo/visualization.jpg')
将可视化结果 visualization.jpg 保存在 demo 文件夹中
执行测试
cd fcn-master/
python infer.py
********************** 第一次报错 ***********************
参考: https://blog.csdn.net/weixin_41803041/article/details/79495617
解决: 原来是重新 make all 之后忘记 make pycaffe
,太傻了。
********************** 第二次报错 ***********************
但是在 make pycaffe 时,又报了一个新的错误:
参考: http://blog.sina.com.cn/s/blog_1852c2ba601030woa.html
解决: 在环境变量里添加 anaconda python2.7 的路径
vi ~/.bashrc
export PYTHONPATH="$PYTHONPATH:/data/zyy/usr/local/anaconda/envs/caffe27/include/python2.7"
source ~/.bashrc
注意: 添加环境变量时,第二个要加上 $PYTHONPATH
,否则会覆盖前一个 PYTHONPATH。
添加完环境变量可以来看看是否成功了:
echo $PYTHONPATH
输出如下:
这里修改好以后,再次执行测试命令就成功了~
测试结果
通过运行 python infer.py
,测试结果输出如下:output 和 visualization
下面是 demo 里本来就有的原图和标签:
说明: 这里测试使用的网络是 voc-fcn8s
,如果想要使用其他网络进行测试,只需要在 infer.py
里的 net
处进行修改即可。
2. 训练模型(一)
选择一个想要测试的模型,比如这里用 voc-fcn8s
,打开文件夹:
caffemodel-url
:是该网络预训练好的模型参数,打开这个文件可以看到一个下载地址,复制到浏览器就可以下载对应的模型deploy.prototxt
:是训练好模型以后,进行预测的网络模型net.py
是生成网络模型的文件,暂时用不到solve.py
和solver.prototxt
是训练网络的一些数据路径和参数设置train.prototxt
和val.prototxt
就是训练模型和验证模型
数据集下载
benchmark 数据集:
将 benchmark 解压到 fcn-master/data/sbdd
目录下,如果没有 sbdd
文件夹就自己新建一个。
voc2012 数据集:https://pjreddie.com/projects/pascal-voc-dataset-mirror/
将 voc2012 解压到 fcn-master/data/pascal
目录下。
说明: 在 FCN 中 VOC 数据集的训练需要 benchmark 和 voc,benchmark 中的 dataset 用来存放训练时的数据,voc2012 存放测试时的数据。
配置相关文件
修改 voc-fcn8s
文件夹下的配置文件:
1. 修改配置文件 solve.py
根据自己的实际路径做出如下修改:
(1)序号 1 处加载 python 与 caffe 的接口路径,填写 caffe 工程目录下的 python 文件夹所在目录。
(2)序号 2 处是下载的训练前的网络模型,我的就直接放在了 fcn8s
的文件夹下。
(3)序号 3 处是模型对应的 solver.prototxt
的路径。
(4)序号 4 处是训练数据 data 里的 segvalid11.txt
文件
另外,如果不想用已有的 model 进行 fine-tuning,注释掉 solver.net.copy_from(weights)
2. 修改配置文件 solver.prototxt
solver.prototxt 是 caffe 的配置文件,里面定义了网络训练时候的各种参数,比如学习率、权重衰减、迭代次数等等。
根据自己的实际路径做出如下修改:
(1)序号 1 和 2 分别是训练和验证所用到的 prototxt 文件的路径
(2)序号 3 是训练时保存的模型地址
我修改后的文件如下:
prototxt 中各参数的具体含义参考:caffe中网络结构参数详解
3. 修改配置文件 train.prototxt
将画线部分修改为训练集 dataset 的路径,就是刚才下载的 benchmark
param_str
有 4 个参数:sbdd_dir
,seed
,split
,mean
- sbdd_dir:数据集的存放路径
4. 修改配置文件 val.prototxt
将画线部分修改为 voc2012 的路径
开始训练
修改好了各配置文件以后,进入到 caffe 根目录下,运行
sudo python fcn-master/voc-fcn8s/solve.py
即可开始训练。
测试
训练完的模型要进行测试,测试代码在 fcn-master/infer.py
3. 训练模型(二)
训练数据集: SIFT-Flow
预训练模型: VGG-16
准备数据
下载 SIFT-Flow 数据集:SiftFlowDataset.zip
将 zip 解压到 ~/fcn-master/data/
目录下,由于该目录下已经有了一个文件叫 sift-flow
,可以直接把下载的 SiftFlowDataset 中的四个文件放在 sift-flow 里。
这里是下载的四个文件:
放进 sift-flow 文件夹中:
下载预训练模型
下载 VGG-16 预训练模型:https://pan.baidu.com/s/1qYJeFfQ
将模型放在 fcn-master 工程目录中的 ilsvrc-nets
文件夹下
修改配置文件
将 fcn-master 工程根目录下的相关 .py
文件复制到 siftflow-fcn32s
文件夹中,包括:infer.py
,score.py
,siftflow_layer.py
,surgery.py
,vis.py
。
(1)修改 solver.prototxt 文件:
snapshot:10000
表示训练 10000 次就保存一次模型;snapshot_prefix:XXX
为训练得到的模型的存放路径;display
表示每 200 次迭代就打印一下当前的结果;max_iter
表示最大迭代次数,这里是 300,000 次;
(2)修改 solve.py 文件:
由于这里训练的是 fcn32s 的网络模型,必须修改 solve.py 文件,利用 transplant 的方式获取 vgg-16 的网络权重。
如果仅仅是 copy vgg-16 模型参数,并没有改变网络,训练会无法收敛。
solve.py 文件需要修改以下三个地方:
修改后如下:
其中 VGG_ILSVRC_16_layers_deploy.prototxt
可能没有,需要另外下载(可以自己搜,或者私信我发给你)。
开始训练模型
cd siftflow-fcn32s
# 注意,如果想要绘制loss曲线,先别急着用这句指令训练,后面会介绍怎么生成log文件
python solve.py
将 siftflow-fcn32s 训练好以后,就可以 copy 训练好的 fcn32s 的模型权重用来训练 siftflow-fcn16s:solver.net.copy_from(weights)
,也就是不再需要修改 solve.py。
同理,直接 copy 训练好的 fcn16s 的模型权重来训练 siftflow-fcn8s,不需要修改 solve.py。
第一波训练4、5个小时就 ok 了~
绘制训练过程中的 loss 曲线
修改训练命令为:
python solve.py 2>&1 | tee out.log
2>&1
是 Linux 的信息流输出控制语句,可以将输出信息保存在out.log
文件中,同时不再在命令窗口中实时显示训练信息;tee out.log
将在窗口中显示训练信息,如果不需要显示,可以不用加| tee out.log
;
用 Caffe 自带的脚本绘制 loss 曲线:
将 ~/caffe/tools/extra
目录下的 plot_training_log.py.example
,extract_seconds.py
,parse_log.sh
,parse_log.py
复制到保存 log 文件的目录下,再将 plot_training_log.py.example
复制一份并命名为 plot_training_log.py
cp plot_training_log.py.example plot_training_log.py
注意:这些脚本用的是 python2.7,如果用 python3 环境执行会报错
执行绘制曲线命令:
python plot_training_log.py 6 loss.png out.log
第一个参数 6
是指要绘制哪个指标的曲线图,第二个参数 loss.png
是输出曲线图的保存路径,第三个参数 out.log
是日志文件的路径。
第一个参数具体代表什么可以通过执行 python plot_training_log.py print_help
来查看,这里也告诉我们如何传入参数。
!!但是执行上面的命令时报了这个错:
参考:https://blog.csdn.net/u014520797/article/details/80382792
解决:权限不够,给复制过来的三个文件都添加权限
chmod 777 parse_log.sh
chmod 777 parse_log.py
chmod 777 extract_seconds.py
chmod 777 plot_training_log.py
!!再次执行,又报新的错误:
由于在网上根本没找到能够解决的方案,所以我直接看了 extract_seconds.py
和 parse_log.sh
源代码。
报错信息显示 assert start_datetime, 'Start time not found'
,那 start_datetime
肯定是为 False 或 None 了,说明在 for 循环内所有的 if 判断语句都不成立,即 line.find('Solving')
全都是 -1
,说明在 line
里压根没找到 Solving
,而 lines
又是针对日志文件 out.log
的,那就应该去 out.log
里看看这个 Solving
是什么?我觉得问题就在这里了。
回到训练产生的日志 out.log
里,发现并没有 Solving
这个词,可能是我的日志文件有问题?碰巧看到这篇博客:绘制loss曲线,里面也提到了同样的问题,于是按照他的方法,在第一次迭代开始之前人为加上了 I0507 10:55:51.039144 17590 solver.cpp:239] Solving FCN
,问题解决~
因为这样在 extract_seconds.py
中执行下面这个 if 判断时,就不会出现找不到 Solving 的情况而将 start_datetime 置为 None 啦~
assert 会判断 start_datetime 是否为 False,根据这两个函数的调用关系可知,只要解决了 Solving 缺失的问题,后面也就不会有问题了。
而且在 parse_log.sh
里,也有用到 Solving
,如果不手动添加那句话的话,生成的 aux3.txt
就为空。而 aux4.txt
又是 aux3.txt
生成的,所以一个 Solving
可以同时解决这三个错误。 Linux指令:grep
最后就是 out.log
文件本身的问题,因为它把训练过程中的所有信息都保存下来了,所以会有一些训练信息之外的提示信息,这些信息会影响到提取 out.log.train
文件,比如下面在迭代第 8000 次的时候进行了验证,所以在 8000 次开始,提取的信息就少了一列,导致 learning rate 那一列跑到了 loss 列下,所以做出的 loss 曲线图后面全为 0 了。
另外看看这个 out.log.test
,内容是空的,肯定也是不对的。
【所以要怎样直接从 out.log
解析出 out.log.train
和 out.log.test
??还没有研究要怎么搞】
把 out.log
重命名为 out_org.log
(表示最初的log文件),复制一份命名为 out.log
,将开始迭代后的无关信息删掉,这样就成功了。
# 迭代次数-训练loss
python plot_training_log.py 6 loss_vs_iters.png out.log
# 时间-训练loss
python plot_training_log.py 7 loss_vs_seconds.png out.log
顺便把看代码过程中不了解的东西记录以下,都很简单~
Python中 sys.argv[] 的用法简明解释
os._exit() 和 sys.exit()
断言 ( assert ) 的用法
Python find()方法
Python split()方法
Python rfind()方法
datetime是Python处理日期和时间的标准库
Python File readlines() 方法
if __name__ == ‘__main__’ 如何正确理解
Linux grep命令
测试
修改 fcn-master
根目录下的 infer.py
:
net = caffe.Net('deploy.prototxt', 'siftflow-fcn32s/train_iter_100000.caffemodel', caffe.TEST)
train_iter_100000.caffemodel
就是训练得到的模型
附:caffe 参数介绍
iteration
数据进行一次前向 + 后向的训练
batchsize
每次迭代时训练图像的数量
epoch
所有的训练图像都通过网络训练一次是一个epoch
举例:
训练集中共 1280000 张图像,若设置 batchsize = 256,那么就需要 1280000 / 256 = 5000 个 iteration 才能将所有图片训练一遍,即一个 epoch 是 5000 个 iteration。
若设置 max_iteration = 450000,那么就是最多训练 450000 / 5000 = 90 个 epoch。
learning_rate 衰减与 stepsize 和 gamma 有关,stepsize 决定了 lr 什么时候衰减(衰减步长),gamma 决定了 lr 一次衰减多少(衰减系数)。若设置 stepsize = 500,base_lr = 0.01,gamma = 0.1,那么迭代到第一个 500 次时,lr 进行第一次衰减 lr = lr * gamma = 0.01 * 0.1 = 0.001,下一个 500 次再重复该过程。
训练过程中,每到一定的迭代次数都会进行 test(其实是校验而不是测试),至于迭代次数则是由 test_interval 决定的,若设 test_interval = 1000,则每迭代 1000 次就会测试一遍当前的网络。test_size 决定了在 test 时每次迭代输入图片的数量(类似于训练过程中的 batchsize),test_iter 是 test 所有测试图像的迭代次数。
FCN 项目官方说明文档:
Fully Convolutional Networks for Semantic Segmentation
This is the reference implementation of the models and code for the fully convolutional networks (FCNs) in the PAMI FCN and CVPR FCN papers:
Fully Convolutional Models for Semantic Segmentation
Evan Shelhamer*, Jonathan Long*, Trevor Darrell
PAMI 2016
arXiv:1605.06211
Fully Convolutional Models for Semantic Segmentation
Jonathan Long*, Evan Shelhamer*, Trevor Darrell
CVPR 2015
arXiv:1411.4038
Note that this is a work in progress and the final, reference version is coming soon.
Please ask Caffe and FCN usage questions on the caffe-users mailing list.
Refer to these slides for a summary of the approach.
These models are compatible with BVLC/caffe:master
.
Compatibility has held since master@8c66fa5
with the merge of PRs #3613 and #3570.
The code and models here are available under the same license as Caffe (BSD-2) and the Caffe-bundled models (that is, unrestricted use; see the BVLC model license).
PASCAL VOC models: trained online with high momentum for a ~5 point boost in mean intersection-over-union over the original models.
These models are trained using extra data from Hariharan et al., but excluding SBD val.
FCN-32s is fine-tuned from the ILSVRC-trained VGG-16 model, and the finer strides are then fine-tuned in turn.
The “at-once” FCN-8s is fine-tuned from VGG-16 all-at-once by scaling the skip connections to better condition optimization.
- FCN-32s PASCAL: single stream, 32 pixel prediction stride net, scoring 63.6 mIU on seg11valid
- FCN-16s PASCAL: two stream, 16 pixel prediction stride net, scoring 65.0 mIU on seg11valid
- FCN-8s PASCAL: three stream, 8 pixel prediction stride net, scoring 65.5 mIU on seg11valid and 67.2 mIU on seg12test
- FCN-8s PASCAL at-once: all-at-once, three stream, 8 pixel prediction stride net, scoring 65.4 mIU on seg11valid
FCN-AlexNet PASCAL: AlexNet (CaffeNet) architecture, single stream, 32 pixel prediction stride net, scoring 48.0 mIU on seg11valid.
Unlike the FCN-32/16/8s models, this network is trained with gradient accumulation, normalized loss, and standard momentum.
(Note: when both FCN-32s/FCN-VGG16 and FCN-AlexNet are trained in this same way FCN-VGG16 is far better; see Table 1 of the paper.)
To reproduce the validation scores, use the seg11valid split defined by the paper in footnote 7. Since SBD train and PASCAL VOC 2011 segval intersect, we only evaluate on the non-intersecting set for validation purposes.
NYUDv2 models: trained online with high momentum on color, depth, and HHA features (from Gupta et al. https://github.com/s-gupta/rcnn-depth).
These models demonstrate FCNs for multi-modal input.
- FCN-32s NYUDv2 Color: single stream, 32 pixel prediction stride net on color/BGR input
- FCN-32s NYUDv2 HHA: single stream, 32 pixel prediction stride net on HHA input
- FCN-32s NYUDv2 Early Color-Depth: single stream, 32 pixel prediction stride net on early fusion of color and (log) depth for 4-channel input
- FCN-32s NYUDv2 Late Color-HHA: single stream, 32 pixel prediction stride net by late fusion of FCN-32s NYUDv2 Color and FCN-32s NYUDv2 HHA
SIFT Flow models: trained online with high momentum for joint semantic class and geometric class segmentation.
These models demonstrate FCNs for multi-task output.
- FCN-32s SIFT Flow: single stream stream, 32 pixel prediction stride net
- FCN-16s SIFT Flow: two stream, 16 pixel prediction stride net
- FCN-8s SIFT Flow: three stream, 8 pixel prediction stride net
Note: in this release, the evaluation of the semantic classes is not quite right at the moment due to an issue with missing classes.
This will be corrected soon.
The evaluation of the geometric classes is fine.
PASCAL-Context models: trained online with high momentum on an object and scene labeling of PASCAL VOC.
- FCN-32s PASCAL-Context: single stream, 32 pixel prediction stride net
- FCN-16s PASCAL-Context: two stream, 16 pixel prediction stride net
- FCN-8s PASCAL-Context: three stream, 8 pixel prediction stride net
Frequently Asked Questions
Is learning the interpolation necessary? In our original experiments the interpolation layers were initialized to bilinear kernels and then learned.
In follow-up experiments, and this reference implementation, the bilinear kernels are fixed.
There is no significant difference in accuracy in our experiments, and fixing these parameters gives a slight speed-up.
Note that in our networks there is only one interpolation kernel per output class, and results may differ for higher-dimensional and non-linear interpolation, for which learning may help further.
Why pad the input?: The 100 pixel input padding guarantees that the network output can be aligned to the input for any input size in the given datasets, for instance PASCAL VOC.
The alignment is handled automatically by net specification and the crop layer.
It is possible, though less convenient, to calculate the exact offsets necessary and do away with this amount of padding.
Why are all the outputs/gradients/parameters zero?: This is almost universally due to not initializing the weights as needed.
To reproduce our FCN training, or train your own FCNs, it is crucial to transplant the weights from the corresponding ILSVRC net such as VGG16.
The included surgery.transplant()
method can help with this.
What about FCN-GoogLeNet?: a reference FCN-GoogLeNet for PASCAL VOC is coming soon.
参考文章
https://www.cnblogs.com/xuanxufeng/p/6243342.html
https://blog.csdn.net/wangkun1340378/article/details/70238290
https://blog.csdn.net/weixin_42795611/article/details/85945649
https://www.cnblogs.com/deeeplearnxl/p/6228457.html
https://blog.csdn.net/raby_gyl/article/details/65633400
https://blog.csdn.net/auto1993/article/details/71297151
https://blog.csdn.net/weixin_42795611/article/details/85945649
https://blog.csdn.net/a8039974/article/details/78603017
另外,发现一个Caffe 网络可视化工具:http://ethereon.github.io/netscope/quickstart.html