使用FCN做图像语义分割(实践篇)

FCN原理

原理我已经在上篇博客说过,大家可以参考FCN原理篇

代码

FCN有官方的代码,具体地址是FCN官方代码 不过我用的不是这个代码,我用的是别人修改官方的版本的代码,使用Chainer框架实现的,Chainer的源码链接: Chainer框架源码,如果大家使用过Keras的话,应该对它不会感到特别的陌生,Chainer: a neural network framework

好了,我使用的代码是FCN的Chainer implementation, 具体地址是FCN Chainer implementation

安装

安装很简单,直接pip或者源码安装都可以,但是我在我的机器上装过几次,发现使用pip的方式最后fcn.data_dir这个变量的值会指向到你系统的python下的dist-packages这个目录,但是这个目录需要root权限,所以不推荐使用pip直接安装的方式; 关于此问题的说明见: fcn.data_dir的问题

所以我最后使用的是源码安装的方式,这里推荐使用virtualenv工具建立虚拟环境,实践中发现这是最不会出错的方式,推荐使用!

clone代码

git clone https://github.com/wkentaro/fcn.git –recursive

使用virtualenv安装

sudo pip install virtualenv #安装virtualenv 创建虚拟目录 virtualenv test-fcn cd test-fcn 激活虚拟环境 source ./bin/activate 克隆fcn代码 git clone https://github.com/wkentaro/fcn.git –recursive cd fcn 安装fcn python setup.py develop

demo

下载VOC2012数据集,放入fcn-data-pascal-VOC2012路径下 1. 转换caffe model为Chainer model ./scripts/caffe_to_chainermodel.py 2. load model,进行分割 ./scripts/fcn_forward.py –img-files data/pascal/VOC2012/JPEGImages/2007_000129.jpg

训练自己的数据

这个前后搞了快一个月,才把最终的训练搞定,其中艰辛很多,在这里写出来供大家参考

准备自己的数据集

数据集做成VOC2012segementClass的样子,下图是示例,上面一张是原图,下面一张是分割图

但是每一种label指定的物体都有对应的具体的颜色,这个我们犯了很多错,最后跟踪代码找出来的,具体的每一类的RGB值如下:

Index

RGB值

0

(0,0,0)

1

(0,128,0)

2

(128,128,0)

3

(0,0,128)

4

(128,0,128)

5

(0,128,128)

6

(128,128,128)

7

(64,0,0)

8

(192,0,0)

9

(62,128,0)

10

(192,128,0

这里只列出10类的值,更多类的可以看下面这段代码:

def bitget(byteval, idx):
    return ((byteval & (1 << idx)) != 0)


def labelcolormap(N=256):
    cmap = np.zeros((N, 3))  #N是类别数目
    for i in xrange(0, N):
        id = i
        r, g, b = 0, 0, 0
        for j in xrange(0, 8):
            r = np.bitwise_or(r, (bitget(id, 0) << 7-j))
            g = np.bitwise_or(g, (bitget(id, 1) << 7-j))
            b = np.bitwise_or(b, (bitget(id, 2) << 7-j))
            id = (id >> 3)
        cmap[i, 0] = r
        cmap[i, 1] = g
        cmap[i, 2] = b
    cmap = cmap.astype(np.float32) / 255 #获得Cmap的RGB值
    return cmap

def _label_rgb_to_32sc1(self, label_rgb):
        assert label_rgb.dtype == np.uint8
        label = np.zeros(label_rgb.shape[:2], dtype=np.int32)
        label.fill(-1)
        cmap = fcn.util.labelcolormap(len(self.target_names)) 
        cmap = (cmap * 255).astype(np.uint8)  #转换为整数值
        for l, rgb in enumerate(cmap):
            mask = np.all(label_rgb == rgb, axis=-1)
            label[mask] = l
        return label

按照此颜色表做图就没有问题,代码可以正确的读取分割的ground-truth结果 原始的图像放在fcn/data/pascal/VOC2012/JPEGImages 分割的图像放在fcn/data/pascal/VOC2012/SegmentationClass 之后在fcn/data/pascal/VOC2012/ImageSets/Segmentationtrain.txt,trainval.txt,val.txt,写入需要进行相应任务的图片的编号

修改代码

  1. fcn/scripts/fcn_train.py
# setup optimizer
    optimizer = O.MomentumSGD(lr=1e-10, momentum=0.99) #这里的lr一定要小,大的话程序会报错,我使用的是1e-9
    optimizer.setup(model)

    # train
    trainer = fcn.Trainer(
        dataset=dataset,
        model=model,
        optimizer=optimizer,
        weight_decay=0.0005,
        test_interval=1000,
        max_iter=100000,
        snapshot=4000,
        gpu=gpu,
    )
  1. fcn/fcn/pascal.py
target_names = np.array([
        'background',
        'aeroplane',
        'bicycle',
        'bird',
        'boat',
        'bottle',
        'bus',
        'car',
        'cat',
        'chair',
        'cow',
        'diningtable',
        'dog',
        'horse',
        'motorbike',
        'person',
        'potted plant',
        'sheep',
        'sofa',
        'train',
        'tv/monitor',
    ]) #修改成自己的,记得按照颜色表写
  1. fcn/fcn/util.py
def resize_img_with_max_size(img, max_size=500*500):  #修改max_size,按照实际写
    """Resize image with max size (height x width)"""
    from skimage.transform import rescale
    height, width = img.shape[:2]
    scale = max_size / (height * width)
    resizing_scale = 1
    if scale < 1:
        resizing_scale = np.sqrt(scale)
        img = rescale(img, resizing_scale, preserve_range=True)
        img = img.astype(np.uint8)
    return img, resizing_scale
  1. fcn/fcn/models/fcn32s.py
def __init__(self, n_class=21):  #修改类别n_class
        self.n_class = n_class
        super(self.__class__, self).__init__(
            conv1_1=L.Convolution2D(3, 64, 3, stride=1, pad=100),
            conv1_2=L.Convolution2D(64, 64, 3, stride=1, pad=1),

            conv2_1=L.Convolution2D(64, 128, 3, stride=1, pad=1),
            conv2_2=L.Convolution2D(128, 128, 3, stride=1, pad=1),

            conv3_1=L.Convolution2D(128, 256, 3, stride=1, pad=1),
            conv3_2=L.Convolution2D(256, 256, 3, stride=1, pad=1),
            conv3_3=L.Convolution2D(256, 256, 3, stride=1, pad=1),

            conv4_1=L.Convolution2D(256, 512, 3, stride=1, pad=1),
            conv4_2=L.Convolution2D(512, 512, 3, stride=1, pad=1),
            conv4_3=L.Convolution2D(512, 512, 3, stride=1, pad=1),

            conv5_1=L.Convolution2D(512, 512, 3, stride=1, pad=1),
            conv5_2=L.Convolution2D(512, 512, 3, stride=1, pad=1),
            conv5_3=L.Convolution2D(512, 512, 3, stride=1, pad=1),

            fc6=L.Convolution2D(512, 4096, 7, stride=1, pad=0),
            fc7=L.Convolution2D(4096, 4096, 1, stride=1, pad=0),

            score_fr=L.Convolution2D(4096, self.n_class, 1, stride=1, pad=0),

            upscore=L.Deconvolution2D(self.n_class, self.n_class, 64,
                                      stride=32, pad=0),
        )
        self.train = False

训练

./scripts/fcn_train.py

  1. 其会在fcn/data/ 下创建一个目录叫做SegmentationClassDataset_db,里面存放训练的图片的pickle数据,如果需要修改原始的训练图片则需要将此目录删除,否则默认读取此目录内的pickle数据作为图像的原始数据
  2. 会在fcn下创建snapshot这个目录,里面有训练保存的model,日志文件等,重新训练的话,建议删除此目录

使用自己训练的model

./scripts/fcn_forward.py -c path/to/your/model -i path/to/your/image 结果存放在fcn/data/forward_out

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏人工智能LeadAI

pytorch入门教程 | 第四章:准备图片数据集

在训练神经网络之前,我们必须有数据,作为资深伸手党,必须知道以下几个数据提供源: 1 CIFAR-10 ? CIFAR-10图片样本截图 CIFAR-10是多...

1K80
来自专栏ATYUN订阅号

保存并加载您的Keras深度学习模型

Keras是一个用于深度学习的简单而强大的Python库。 鉴于深度学习模式可能需要数小时、数天甚至数周的时间来培训,了解如何保存并将其从磁盘中加载是很重要的...

65260
来自专栏付越的专栏

深度学习入门篇--手把手教你用 TensorFlow 训练模型

最近笔者终于跑通 TensorFlow Object Detection API的ssd_mobilenet_v1 模型,这里记录下如何完整跑通数据准备到模型使...

6.4K20
来自专栏一英里广度一英寸深度的学习

Tensorflow 迁移学习 识别中国军网、中国军视网Logo水印

作者bourdakos1整合了tensorflow中的object-detection和slim两个子项目。 设置环境,把当前目录、slim、object_d...

41150
来自专栏PaddlePaddle

【FAQ】模型配置相关问题汇总

导语 我们用13篇推文向您介绍了如何安装、编译和使用PaddlePaddle,您可以点击公众号右下角的历史消息获取相应的使用指南。 ? 在使用指南的最后一部分,...

392100
来自专栏10km的专栏

SSD(Single Shot MultiBox Detector):ubuntu16安装及训练自己的数据集(VOC2007格式)过程记录

安装SSD # SSD代码clone到 caffe-ssd文件夹下 git clone --recursive https://github.com/weili...

52260
来自专栏简书专栏

基于xgboost的风力发电机叶片结冰分类预测

xgboost中文叫做极致梯度提升模型,官方文档链接:https://xgboost.readthedocs.io/en/latest/tutorials/mo...

19010
来自专栏ATYUN订阅号

使用Tensorflow对象检测在安卓手机上“寻找”皮卡丘

在TensorFlow的许多功能和工具中,隐藏着一个名为TensorFlow对象探测API(TensorFlow Object Detection API)的组...

52150
来自专栏Small Code

【TensorFlow | TensorBoard】理解 TensorBoard

TensorBoard 是用于可视化 TensorFlow 模型的训练过程的工具(the flow of tensors),在你安装 TensorFlow 的时...

1.9K120
来自专栏小鹏的专栏

tf API 研读1:tf.nn,tf.layers, tf.contrib概述

        我们在使用tensorflow时,会发现tf.nn,tf.layers, tf.contrib模块有很多功能是重复的,尤其是卷积操作,在使用的时...

43790

扫码关注云+社区

领取腾讯云代金券