FCN语义分割——训练自己的数据

本文介绍了如何使用FCN进行语义分割,并在自定义数据集上进行训练。详细讨论了数据集处理,包括创建8位图像表示不同类别,以及制作图像列表文件。在训练阶段,重点讲解了修改网络路径、solver.py、score.py和voc_layer.py文件以适应自定义数据。虽然目前分割结果不理想,但提供了继续优化的潜力。

前言

前段时间研究了下FCN的语义分割,并且将其成功运用在了自己的数据集上,现在分割出来的结果不是很满意,期待后期的调试将其提升。这里就将这个过程记录下来,希望对各位看官有所帮助

1. 数据集处理

在VOC2012的那个数据集中包含了做好的分割数据集,但是要自己制作数据集的时候就需要注意下了。首先,VOC2012分割数据集中的分割好的图像数据是8位的,不要看着是彩色的就认为是3通道的RGB图像,如下图例子所示
分类图像
查看该图像的属性,可以看到是8位的图像
图像位深
这里为什么将其弄成为彩色的是为了给人看的,并不是真正的彩色图像。所以,在制作数据集的时候我们需要分析我们的数据集,需要将那些物体进行分割得到一张表格,将每个物体用一个颜色去表示,比如我的
这里写图片描述
这里的特征值代表的是像素值(灰度值),每一个级别的值代表一个类,因而0~255就可以代表256个分类。
这是我制作的数据集(方便观看)
这里写图片描述
而实际用于训练的,全是黑的是因为我每个分类的像素值取得小-_-。。
这里写图片描述
然后其他的比如图像列表文件啦,各位看官按照自己的数据集分析整理就好了,若有不清楚的欢迎留言或是私信交流。好了,这下数据集准备好了,那就开始训练了

2. 数据训练

2.1 修改网络路径

修改solver.prototxt文件中训练和测试网络的地址
这里写图片描述
修改train.prototxt和val.prototxt中的dataset参数地址
这里写图片描述
PS: 这里需要说明一下,在训练自己的数据的时候,定义的类数目跟原始网络的类数目不相同就需要将train.prototxt和val.prototxt中num_output为21的改为num_output加上你的分类数目,因为这里是用别人的模型进行再训练。

2.2 修改solver.py

我这里将solver.py修改了增加了些绘制曲线

# -*- coding=utf-8 -*-
import os
import matplotlib.pyplot as plt
import sys
sys.path.append('/home/sucker/Desktop/caffe-1.0/python')
sys.path.append('/home/sucker/Desktop/caffe-1.0/python/caffe')
sys.path.append('/home/sucker/Desktop/caffe-1.0/build/lib')
import caffe
import surgery, score
import numpy as np

try:
    import setproctitle
    setproctitle.setproctitle(os.path.basename(os.getcwd()))
except:
    pass

weights = 'fcn8s-heavy-pascal.caffemodel'

# init
caffe.set_device(0)
caffe.set_mode_gpu()

solver = caffe.SGDSolver('solver.prototxt')
vgg_net = caffe.Net('deploy_21.prototxt', weights, caffe.TRAIN)
surgery.transplant(solver.net, vgg_net)
del vgg_net

# surgeries
interp_layers = [k for k in solver.net.params.keys() if 'up' in k]
surgery.interp(solver.net, interp_layers)

# init net_show
m_show = net_show.Net_Show(solver.net)
m_show.ShowLayer_Info()

# scoring
val = np.loadtxt('../MRI_Seg/seg11valid.txt', dtype=str)

all_acc = []
mean_acc = []
n_iter = 25
n_step = 500

for _ in range(n_iter):
    solver.step(n_step)
    acc, m_acc = score.seg_tests(solver, False, val, layer='score')
    all_acc.append(acc)
    mean_acc.append(m_acc)

train_loss = np.array(all_acc)
test_loss = np.array(mean_acc)

# 绘制train loss、test loss和accuracy曲线
print '\nplot the train loss and test accuracy\n'
_, ax1 = plt.subplots()
ax2 = ax1.twinx()

# train loss -> 绿色
ax1.plot(n_step * np.arange(len(train_loss)), train_loss, 'g')
# test loss -> 黄色
ax1.plot(n_step * np.arange(len(test_loss)), test_loss, 'y')
# test accuracy -> 红色
# ax2.plot(test_interval * np.arange(len(test_acc)), test_acc, 'r')

plt.show()

2.3 修改score.py文件

这里只是将函数里面运算得到的数据返回回去,你可以根据自己的需求选择修改或是不修改
修改seg_tests函数

def seg_tests(solver, save_format, dataset, layer='score', gt='label'):
    print '>>>', datetime.now(), 'Begin seg tests'
    solver.test_nets[0].share_with(solver.net)
    hist, loss, acc, m_acc, m_iu = do_seg_tests(solver.test_nets[0], solver.iter, save_format, dataset, layer, gt)
    return acc, m_acc

修改do_seg_tests函数

def do_seg_tests(net, iter, save_format, dataset, layer='score', gt='label'):
    n_cl = net.blobs[layer].channels
    if save_format:
        save_format = save_format.format(iter)
    hist, loss = compute_hist(net, save_format, dataset, layer, gt)
    # mean loss
    print '>>>', datetime.now(), 'Iteration', iter, 'loss', loss
    # overall accuracy
    acc = np.diag(hist).sum() / hist.sum()
    print '>>>', datetime.now(), 'Iteration', iter, 'overall accuracy', acc
    # per-class accuracy
    acc = np.diag(hist) / hist.sum(1)
    print '>>>', datetime.now(), 'Iteration', iter, 'mean accuracy', np.nanmean(acc)
    # per-class IU
    iu = np.diag(hist) / (hist.sum(1) + hist.sum(0) - np.diag(hist))
    print '>>>', datetime.now(), 'Iteration', iter, 'mean IU', np.nanmean(iu)
    freq = hist.sum(1) / hist.sum()
    print '>>>', datetime.now(), 'Iteration', iter, 'fwavacc', \
            (freq[freq > 0] * iu[freq > 0]).sum()
    return hist, loss, acc, np.nanmean(acc), np.nanmean(iu)

2.4 修改voc_layer.py文件

修改这个文件主要是为了让它可以直接支持图片加载进来,具体可以参考之前的博文:FCN语义分割——直接加载图像数据

后记

运行起来了,但是结果没有达到需求,后面再改进吧
这里写图片描述

### FCN全卷积网络用于语义分割的实现方法 #### 一、FCN简介 FCN是首个能够执行端对端像素级预测的全卷积网络[^3]。该模型摒弃了传统CNN中的全连接层,转而采用反卷积操作来恢复空间分辨率,从而实现了任意尺寸输入图像的密集预测。 #### 二、架构设计 为了适应不同尺度的目标检测需求,研究者们提出了多种变体版本如FCN-32s、FCN-16s以及FCN-8s等。这些改进主要体现在跳跃结构的设计上——即通过融合来自浅层特征图的信息以提高最终输出的质量和精度[^1]。 ```python import torch from torchvision.models.segmentation import fcn_resnet50 def create_fcn_model(num_classes=21): # 定义并加载预训练权重的ResNet50为基础的FCN模型 model = fcn_resnet50(pretrained=True) # 修改分类头以匹配特定任务所需的类别数 if num_classes != 21: model.classifier[4] = torch.nn.Conv2d( 512, num_classes, kernel_size=(1, 1), stride=(1, 1)) model.aux_classifier[4] = torch.nn.Conv2d( 256, num_classes, kernel_size=(1, 1), stride=(1, 1)) return model ``` 当目标数据集所含有的对象种类不同于PASCAL VOC时(默认为21类),则需调整`classifier`与`aux_classifier`部分的最后一层卷积核数量至对应的新类别数目[^5]。 #### 三、训练流程概述 FCN训练分为两步走策略:首先是利用ImageNet这样的大型通用图片库完成编码器部分参数初始化;接着再基于具体应用场景下的带标签样本集实施精细化调节工作,确保解码环节能更好地服务于当前任务特性[^2]。 对于多模态信息处理场景而言,比如NYUDv2室内场景解析挑战赛里提到过的RGB-D视觉感知案例,还可以考虑引入双流架构来进行跨域特征交互学习,即将色彩空间同深度线索各自送入独立分支处理后再于高层处汇聚整合[^4]。
评论 28
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值