【Python】mmSegmentation语义分割框架教程(0

文章目录

0.mmSegmentation介绍

\qquad

mmSegmentation是openmmlab项目下开源的图像语义分割框架,目前支持pytorch,由于其拥有pipeline加速,完善的数据增强体系,完善的模型库,作为大数据语义分割训练及测试的代码框架是再好不过了。本教程支持的是mmsegmentation 0.x版本,包含自定义数据集、训练设定、数据增强等部分。mmsegmentation现已出1.x版本,并将停止维护0.x版本。使用1.x版本的朋友请关注新版本博客

\qquad

在开始本教程之前,你需要解决openmmlab的环境配置问题,好在这个repo上已经有很人性化的步骤讲解了,在此附上链接,就不赘述了:

使用教程的相关链接如下(github的项目还自带了中文版):

\qquad

对着mmSegmentation官方教程一步步做固然是能做出来,但是由于其框架结构过于复杂,加之官方教程对如何规范自定义数据集缺乏一些tips,因而本文提供了一个相对简单的教程供大家参考。本文所有讲解目录均为mmSegmentation的项目目录。
MMSegmentation

1.mmSegmentation基本框架

\qquad

要说mmSegmentation(以下简称mmSeg)当中最重要的东西,固然是Config文件了,Config文件可以分为4大类:

  1. model config
  2. dataset config
  3. runtime config
  4. schedule config

\qquad

如果你想知道为什么分成这四大类,请参考本文X.1.节,对这个不感兴趣就继续往下看。其实3和4大多数人都用不到的,重点还是在1和2,下面就从这两个角度给大家来一个不算精细的讲解。

1.1.mmSegmentation的model设置

\qquad

如果采用的是mmSegmentation里面支持的模型,那么固然是不需要自己写class了,自己挑一个模型就可以了。这些model的目录保存在了configs/models里面了。
models
第一个下划线前面的都好理解,就是模型的名字呗,那r50-d8可能就是resnet的类型了,有人会问,那resnet101和resnet152哪去了,别急,其实这些只是baseline,它的backbone是可以改的,比如说我们要使用的是danet_r50-d8.py,我们先打开它(这里我已经将SyncBN改成了BN,因为需要单GPU训练):
danet

\qquad

只需要把model.backbone.depth设为101或者152就可以使用resnet101或者resnet152啦,如果你的本地没有模型,mmSeg就会从model_zoo里面下载一个,如果本地有(应该是保存在了checkpoint里面),则自动加载本地的,不会重复下载。其他的操作后面会讲,另外如果你是多GPU操作就选择使用SyncBN,否则就使用BN就可以了。如果使用了SyncBN却只有一块可用的GPU,那可能会报类似AssertionError:Default process group is not initialized的错误。有人可能问那我直接改了这个文件不就吧原来的默认参数给覆盖了嘛,不要紧,看到后面大家就会明白这个问题很容易解决,这里只是给大家做一个demo。

1.2.mmSegmentation的dataset设置

\qquad

数据集设置比model的稍微复杂一点,这里会直接定义一个自己的数据集(Custom Dataset)来说明其原理。数据集需要准备的文件有三个

  1. Dataset Class文件
  2. Dataset Config文件
  3. Total Config文件

\qquad

在X.1.节提到的config文件就是Total config(顶层设置文件),也是train.py文件直接调用的config文件,而Dataset Class文件是用来定义数据集的类别数和标签名称的,Dataset Config文件则是用来定义数据集目录、数据集信息(例如图片大小)、数据增强操作以及pipeline的。

1.2.1.Dataset Class文件配置

\qquad

首先来说Dataset Class文件,这个文件存放在 mmseg/datasets/ 目录下,
mmseg

\qquad

在这个目录下自己建一个数据集文件,并命个名。配置文件实际上是继承该目录下custom.py当中的CustomDataset父类的,这样写起了就简单多了,大多数情况下(当你的数据集是以一张张图片出现并且可用PIL模块读入时),你只需要设置两个参数即可——类别标签名称(CLASSES)和类别标签上色的RGB颜色(PALETTE)。以我的配置文件为例,代码如下:

from mmseg.datasets.builder import DATASETS
from mmseg.datasets.custom import CustomDataset
import os.path as osp

@DATASETS.register\_module()
class MRDDataset(CustomDataset):
  CLASSES = ("background","road")
  PALETTE = [[0,0,0],[255,255,255]]
  def \_\_init\_\_(self, split, \*\*kwargs):
    super().__init__(img_suffix='.png', seg_map_suffix='.png', 
                     split=split, \*\*kwargs)
                     
    assert osp.exists(self.img_dir) and self.split is not None

\qquad

img_suffixseg_map_suffix分别是你的数据集图片的后缀和标签图片的后缀,因个人差异而定,tif格式的图片我还没有试过,但是jpg和png的肯定是可以的。

\qquad

设置好之后记得保存在mmseg/datasets/目录下(我的文件名叫my_road_detect.py)。另外还需要设置一下该目录下的__init__文件:

from .ade import ADE20KDataset
from .builder import DATASETS, PIPELINES, build_dataloader, build_dataset
from .chase_db1 import ChaseDB1Dataset
from .cityscapes import CityscapesDataset
from .custom import CustomDataset
from .dataset_wrappers import ConcatDataset, RepeatDataset
from .drive import DRIVEDataset
from .hrf import HRFDataset
from .pascal_context import PascalContextDataset, PascalContextDataset59
from .stare import STAREDataset
from .voc import PascalVOCDataset
from .my_road_detect import MRDDataset
__all__ = [
    'CustomDataset', 'build\_dataloader', 'ConcatDataset', 'RepeatDataset',
    'DATASETS', 'build\_dataset', 'PIPELINES', 'CityscapesDataset',
    'PascalVOCDataset', 'ADE20KDataset', 'PascalContextDataset',
    'PascalContextDataset59', 'ChaseDB1Dataset', 'DRIVEDataset', 'HRFDataset',
    'STAREDataset',"MRDDataset"
]

\qquad

需要改两个地方,①import的时候要把自己的Dataset加载进来,②__all__数组里面需要加入自己的Dataset类名称,修改完成之后保存。这两部操作完成之后还不行,由于训练的时候需要txt文件指示训练集、验证集和测试集的txt文件,一开始我以为这只是一个optional option,但无奈Custom Dataset的__init___下面给我来了一句assert osp.exists(self.img_dir) and self.split is not None,那好吧,不知道删了and后面的条件会有什么后果,还是自己创一个吧,写来一个简单的划分数据集并保存到txt的demo,大家可以把这个py文件放到你的数据集上一级目录上并对着稍微改改:

import mmcv
import os.path as osp
data_root = "/data3/datasets/Custom/Lab/Segmentation/"
ann_dir = "ann\_png1"
split_dir = 'splits'
mmcv.mkdir_or_exist(osp.join(data_root, split_dir))
filename_list = [osp.splitext(filename)[0] for filename in mmcv.scandir(
    osp.join(data_root, ann_dir), suffix='.png')]
with open(osp.join(data_root, split_dir, 'train.txt'), 'w') as f:
  # select first 4/5 as train set
  train_length = int(len(filename_list)\*4/5)
  f.writelines(line + '\n' for line in filename_list[:train_length])
with open(osp.join(data_root, split_dir, 'val.txt'), 'w') as f:
  # select last 1/5 as train set
  f.writelines(line + '\n' for line in filename_list[train_length:])

data_root写自己的工作目录名称,ann_dir写标签图片所在的目录,split_dir则是在data_root下生成split txt文件保存的文件夹目录,其他的就不需要怎么改了。如果你在data_root/split_dir/下成功找到了train.txt和val.txt文件,就没有问题了。

1.2.2.Dataset Config文件配置

\qquad

Dataset Config文件在 configs/__base__/ 目录下,需要自己新建一个xxx.py文件。
set
还是以我自己的Custom Dataset为例,它的书写格式如下:

# dataset settings
dataset_type = 'MRDDataset'
data_root = '/data3/datasets/Custom/Lab/Segmentation/'
img_norm_cfg = dict(
    mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_rgb=True)
crop_size = (640, 480)
train_pipeline = [
    dict(type='LoadImageFromFile'),
    dict(type='LoadAnnotations'),
    dict(type='Resize', img_scale=(640, 480), keep_ratio=True),
    dict(type='RandomCrop', crop_size=crop_size, cat_max_ratio=0.75),
    dict(type='RandomFlip', prob=0.5),
    dict(type='PhotoMetricDistortion'),
    dict(type='Normalize', \*\*img_norm_cfg),
    dict(type='Pad', size=crop_size, pad_val=0, seg_pad_val=255),
    dict(type='DefaultFormatBundle'),
    dict(type='Collect', keys=['img', 'gt\_semantic\_seg']),
]
test_pipeline = [
    dict(type='LoadImageFromFile'),
    dict(
        type='MultiScaleFlipAug',
        img_scale=(640, 480),
        # img\_ratios=[0.5, 0.75, 1.0, 1.25, 1.5, 1.75],
        flip=False,
        transforms=[
            dict(type='Resize', keep_ratio=True),
            dict(type='RandomFlip'),
            dict(type='Normalize', \*\*img_norm_cfg),
            dict(type='ImageToTensor', keys=['img']),
            dict(type='Collect', keys=['img']),
        ])
]
data = dict(
    samples_per_gpu=2,
    workers_per_gpu=2,
    train=dict(
        type=dataset_type,
        data_root=data_root,
        img_dir='data1\_for\_ann',
        ann_dir='ann\_png1/',
        pipeline=train_pipeline,
        split="splits/train.txt"),
    val=dict(
        type=dataset_type,
        data_root=data_root,
        img_dir='data1\_for\_ann',
        ann_dir='ann\_png1',
        split="splits/val.txt",
        pipeline=test_pipeline),
    test=dict(
        type=dataset_type,
        data_root=data_root,
        img_dir='data1\_for\_ann',
        ann_dir='ann\_png1',
        split="splits/val.txt",
        pipeline=test_pipeline))


需要改的地方有以下几个:

  1. img_norm_cfg:数据集的方差和均值
  2. crop_size:数据增强时裁剪的大小. img_dir:
  3. img_scale:原图像尺寸
  4. data_root:工作目录
  5. img_dir:工作目录下存图片的目录
  6. ann_dir:工作目录下存标签的目录
  7. split:之前操作做txt文件的目录
  8. sample_per_gpu:batch size
  9. workers_per_gpu:dataloader的线程数目,一般设2,4,8,根据CPU核数确定,或使用os.cpu_count()函数代替
  10. PhotoMetricDistortion是数据增强操作,有四个参数(参考博客)分别是亮度、对比度、饱和度和色调,它们的默认设定如下:
brightness_delta=32; # 32 
contrast_range=(0.5, 1.5); # (0.5, 1.5),下限-上限
saturation_range=(0.5, 1.5); # (0.5, 1.5),下限-上限
hue_delta=18; # 18

如果不想使用默认设定,仿照其他选项将自定义参数写在后面即可,例如

dict(type='PhotoMetricDistortion',contrast_range=(0.5, 1.0))

改好之后保存 configs/__base__/ 目录下。

\qquad

这里也给大家提供了计算数据集方差和均值的一个样例程序(多数据集计算整体均值和标准差):

# -\*- coding: utf-8 -\*-
"""
Created on Fri Jun 25 10:38:17 2021

@author: 17478
"""
import os
import cv2
import numpy as np
from tqdm import tqdm  # pip install tqdm
import argparse

def input\_args():
    parser = argparse.ArgumentParser(description="calculating mean and std")
    parser.add_argument("--data\_fmt",type=str,default='samples\_{name}')
    parser.add_argument("--data-name",type=str,nargs="+",default=['morning','noon','afternoon','dusk','snowy'])
    return parser.parse_args()


if __name__ == "\_\_main\_\_":
    opt = input_args()
    img_files =[]
    for name in opt.data_name:
        img_dir = opt.data_fmt.format(name=name)
        files = os.listdir(img_dir)
        img_files.extend([os.path.join(img_dir,file) for file in files])

    meanRGB = np.asarray([0,0,0],dtype=np.float64)
    varRGB = np.asarray([0,0,0],dtype=np.float64)
    for img_file in tqdm(img_files,desc="calculating mean",mininterval=0.1):
        img = cv2.imread(img_file,-1)
        meanRGB[0] += np.mean(img[:,:,0])/255.0
学好 Python 不论是就业还是做副业赚钱都不错,但要学会 Python 还是要有一个学习规划。最后大家分享一份全套的 Python 学习资料,给那些想学习 Python 的小伙伴们一点帮助!



### 一、Python所有方向的学习路线



Python所有方向路线就是把Python常用的技术点做整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。



![](https://img-blog.csdnimg.cn/img_convert/9f49b566129f47b8a67243c1008edf79.png)



### 二、学习软件

工欲善其事必先利其器。学习Python常用的开发软件都在这里了,给大家节省了很多时间。



![](https://img-blog.csdnimg.cn/img_convert/8c4513c1a906b72cbf93031e6781512b.png)



### 三、全套PDF电子书



书籍的好处就在于权威和体系健全,刚开始学习的时候你可以只看视频或者听某个人讲课,但等你学完之后,你觉得你掌握了,这时候建议还是得去看一下书籍,看权威技术书籍也是每个程序员必经之路。

![](https://img-blog.csdnimg.cn/img_convert/46506ae54be168b93cf63939786134ca.png)



### 四、入门学习视频

我们在看视频学习的时候,不能光动眼动脑不动手,比较科学的学习方法是在理解之后运用它们,这时候练手项目就很适合了。



![](https://img-blog.csdnimg.cn/afc935d834c5452090670f48eda180e0.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA56iL5bqP5aqb56eD56eD,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center)



### 五、实战案例



光学理论是没用的,要学会跟着一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。



![](https://img-blog.csdnimg.cn/img_convert/252731a671c1fb70aad5355a2c5eeff0.png)



### 六、面试资料

我们学习Python必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有阿里大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。



![](https://img-blog.csdnimg.cn/img_convert/6c361282296f86381401c05e862fe4e9.png)  

![](https://img-blog.csdnimg.cn/img_convert/d2d978bb523c810abca3abe69e09bc1a.png)


  • 20
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值