【工程测试与训练】使用 DDRNet 测试、训练cityscapes数据集、训练自己的数据集

本文分享了作者在2022年使用DDRNet进行实时语义分割工程的实践经验,包括工程下载、数据集处理、城市scapes与自定义数据集的训练与测试,以及遇到的问题和解决方案。最终在cityscapes上达到0.77 mIOU,并提供了详细步骤和代码调整建议。
摘要由CSDN通过智能技术生成

前言

2023.11.27记录
没想到大家还都挺关注这篇工程的使用。我是在2022年初测试该工程,当时我测的时候,要训练自己的数据集还是做了些改动的,如本篇博客记载,最后成功训练并推理。当时CPU、GPU都跑通,在cityscapes数据集上训练,验证集上得到mIOU为 0.77。
同时也测试了分割排名的绝大部分易部署的工程,综合原因评定,没有使用该方案。
后面就搞其它的了。中间评论区也有同学问问题,去年断断续续重新测过两次(改代码的时候一定要细心),都是可以跑通的。今年年中服务器清理,现在我这边工程环境已经被清除,所以太过于详细的内容我这也没办法给到解释。

论文解读路径:【论文阅读–实时语义分割】DDRNet:Deep Dual-resolution Networks for Real-time and Accurate Semantic Segmentation

先上本篇博客的结果展示:

  • demo测试效果
    在这里插入图片描述
  • cityscapes 数据集训练结果
    在这里插入图片描述
  • 自己数据集训练结果
    在这里插入图片描述

1 工程和数据集的下载

使用电脑环境 :Ubuntu18+anconde
环境配置:略


1.1 工程下载

作者提供的测试工程:https://github.com/ydhongHIT/DDRNet,(仅使用其预训练模型)
其他开发者复现的完整工程:https://github.com/chenjun2hao/DDRNet.pytorch(下载下来当时我直接重命名为 DDRNet_record)


下载第二个工程重命名了DDRNet_record,并下载第一个工程中的预训练模型,将其放置路径【DDRNet_record/pretrained_models】
在这里插入图片描述


1.2 下载数据集并解压

官网链接:https://www.cityscapes-dataset.com/,下载数据需要注册,且账号有一定的要求。登录后进行数据下载:
请添加图片描述
在这里插入图片描述


1.3 文件重布局

为了工程好管理,所以文件布局如下。(本人习惯工程和数据集分开放置,多个工程获取数据更规范)
└──DataSet_2D
  ├── cityscapes
  ├── 其他数据集
  └── list (工程中的【./data/list】)
└──Code_2D
  ├── DDRNet_record
  └── 其他工程

2 使用开源模型测试cityscapes数据

这里说下,作者把该工程完成了并开源出来很优秀了,美中不足的是使用起来或多或少有些地方略微不便,比如GPUS的设置,容易引起报错。
预测时需要改部分代码和设置(2022.04.01记录,没准后面作者就优化了)。


2.1 工程的修改

修改1:

【ddrnet_23_slim.yaml】中,设置DATASET的TEST_SET、 TEST的 MODEL_FILE。
在这里插入图片描述
在这里插入图片描述
注意这里的TEST_SET必须设置为 test.lst,该文件可以重命名为 test1.lst/test_***.lst,总之lst 的文件名中必须出现test,因为代码中会凭这个标志返回相应的数据。否则会报错:
在这里插入图片描述

修改2:

在【./tools/demo.py】中,修改如下内容。放弃使用提供的多gpu的使用,直接避免掉gpu的设置带来的报错。
在这里插入图片描述

修改3:

在【lib/core/function.py】中的 def test(),在预测时会被调用。但运行时会报错。本人看了看这个函数,调用了一些其他函数,想着希望改动全局代码最小的情况下 工程能够正常预测,只需将该函数用下面的函数替换
(由于发布博客格式的问题,复制到自己代码中,4个空格可能变成3个… 自己修改下咯)

def test(config, test_dataset, testloader, model,
        sv_dir='', sv_pred=True):
   ## 作者数据读取时,使用的opencv,所以我这里保存时也用opencv了
   import cv2

   ## 我这里设置自己的颜色,当然代码生成颜色都可以。
   COLOR = [
               (0, 0, 0),
               (174, 199, 232), 
               (152, 223, 138), 
               (31, 119, 180), 
               (255, 187, 120),  
               (188, 189, 34), 
               (140, 86, 75),  
               (255, 152, 150), 
               (214, 39, 40),  
               (197, 176, 213), 
               (148, 103, 189), 
               (196, 156, 148),  
               (23, 190, 207),  
               (178, 76, 76),
               (247, 182, 210),  
               (66, 188, 102),
               (219, 219, 141), 
               (140, 57, 197),
               (202, 185, 52),
               (51, 176, 203),
               (200, 54, 131),]
   ## 保存图片,用于结果对比时,了解哪个颜色代表第几类别。当然图片的名字保存为自己的类别名是最ok了。
   ## 这里简单起见使用数字表示        
   color_path = "label_color/"
   os.makedirs(color_path) if not os.path.exists(color_path) else None
   for i in range(len(COLOR)):
       img = np.zeros((500,500,3),dtype=np.uint8)
       img =img+list(COLOR[i] )
       # print(img)
       cv2.imwrite(os.path.join(color_path, str(i)+".png"), img)

   model.eval()
   with torch.no_grad():
       for _, batch in enumerate(tqdm(testloader)):
           image, size, name = batch
           size = size[0]
           pred = test_dataset.multi_scale_inference(
               config,
               model,
               image,
               scales=config.TEST.SCALE_LIST,
               flip=config.TEST.FLIP_TEST)

           if pred.size()[-2] != size[0] or pred.size()[-1] != size[1]:
               pred = F.interpolate(
                   pred, size[-2:],
                   mode='bilinear', align_corners=config.MODEL.ALIGN_CORNERS
               )

           if sv_pred:

               image = image.squeeze(0)
               image = image.numpy().transpose((1,2,0))
               image *= test_dataset.std
               image += test_dataset.mean
               image *= 255.0
               image = image.astype(np.uint8)

               _, pred = torch.max(pred, dim=1)
               pred = pred.squeeze(0).cpu().numpy()

               ## ================================================
               ## 将神经网络的输出pred,转换成color图片显示,便于观察
               img_lbl = np.zeros((pred.shape[0],pred.shape[1],3),dtype=np.uint8)
               pred_uni = np.unique(pred)
               for s in range(len(pred_uni)):
                   mask = pred==s
                   img_lbl[mask] = list(COLOR[s])
               
               ## ================================================
               ## 将掩码添加到原图上,便于观察。
               # image = image[:,:,[2,1,0]]
               # image1 = Image.fromarray(image).convert('RGBA')
               # image2 = Image.fromarray(img_lbl).convert('RGBA')
               # img_merge = Image.blend(image1, image2, 0.5)
               # img_merge = np.array(img_merge)[:,:,:3]
                
               ## 将掩码添加到原图上,便于观察。
               image = image[:,:,[2,1,0]]
               img_merge =   image*0.5 + img_lbl*0.5
               
               ## ================================================
               ## 原图,标签图,叠加图 拼接保存。
               image = np.concatenate([image, img_lbl, img_merge], axis=1)

               sv_path = os.path.join(sv_dir, 'test_results')
               if not os.path.exists(sv_path):
                   os.mkdir(sv_path)
               cv2.imwrite(os.path.join(sv_path, name[0]+".png"), image)



2.2 进行推理:

修改结束后,打开终端激活环境,运行命令:
export CUDA_VISIBLE_DEVICES=2   # 设置为自己使用的gpu的id
python tools/demo.py --cfg experiments/cityscapes/ddrnet23_slim.yaml

然后在路径【./output/cityscapes/ddrnet23_slim/test_result/test_results】下得到了预测结果:

在这里插入图片描述在这里插入图片描述在这里插入图片描述

3 训练 cityscape dataset


3.1 文件的修改

【./experiments/cityscapes/ddrnet23_slim.py】中,修改DATASET.ROOT为自己具体的路径。注意,前面测试时,将 TEST_SET 设置成了 test.lst,训练时要修改回 val.txt。否侧会报错
在这里插入图片描述


3.2 工程的训练

需要注意的是,在使用 DDP式的分布式训练时,该文件内的 GPUS: ( ) 并不能很好的设定网络具体使用的GPU的id,但使用使用GPU的个数,和这里括号内的个数要一致。具体使用哪几个训练,比如想用id为2,3 的显卡训练,命令如下。
export CUDA_VISIBLE_DEVICES=2,3
python -m torch.distributed.launch --nproc_per_node=2 tools/train.py --cfg experiments/cityscapes/ddrnet23_slim.yaml
训练过程如下图:
在这里插入图片描述

3.3 工程的结果在这里插入图片描述

4 训练自己的数据集


4.1 准备好自己的数据集

语义分割的标注参考 2D图片语义分割标注
当数据标签都准备好了,仿照cityscapes数据集进行布局:
我这里将自己的数据集命名为【Seg_ChenZCH】。
在路径【DataSet_2D/Seg_ChenZCH】下存放这文件夹【data、label】,里面存放这神经网络所需的数据和标签。
在路径【DataSet_2D/list/Seg_ChenZCH】下存放着文件【train.lst、val.lst、test.lst】,里面存放着所需数据的相对路径。比如 train.lst,内容保存如下。注意相对路径是相对于【ddrnet23_slim.yaml】中的DATASET下的ROOT路径的。
我所有的博客都将不重要但又可能有点敏感的信息全部涂掉了,小心驶得好久船么
在这里插入图片描述


4.2 工程的修改

修改1

复制文件【./lib/datasets/cityscapes.py】并重命名为【Seg_ChenZCH.py】
需要修改一下内容:

  • 处理数据类的名字:class Seg_ChenZCH()修改为class Seg_ChenZCH()
  • mean、std、self.label_mapping、self.class_weights的内容根据自己实际情况修改
  • 由于我这边保存的train.lst中的相对路径,这里也需要调整下图片的读取路径

需要修改内容 修改如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

这里的self.label_mapping的设置,不小心容易设置错误。使用如下代码,更直观不易出错的设置,且要进行不同的类别训练,要修改label_mapping设置会很方便。
假设类别有11类,原始的标签如下,此时我们想进行转换,部分类别不想进行训练。

{'bg': 0, 'sofa:': 1, 'bed': 2, 'desk': 3, 'chair': 4, 
'cupboard': 5, 'cabinet': 6, 'refrigerator': 7, 'toilet': 8,
'washing_machine': 9, 'TV': 10, 'curtain': 11}

解决方法:需要创建一个字典,key是自己原本标签类别的name(按照原本的顺序),value是我们想要转换后的label的值:

class_dict_11 = {"bg":0,
           "sofa:":1, 
           "bed":2, 
           "desk":3, 
           "chair":4,  
           "cupboard":0,
           "cabinet":0, 
           "refrigerator":5, 
           "toilet":6, 
           "washing_machine":7, 
           "TV":8,
           "curtain":0,
           }
class_list = list(class_dict_11.keys())


label_ori = {class_list[i]:i for i in range(len(class_list))}  
print(" =======这里得到的是 name:原始的idx")
print(label_ori)
print()

label_mapping = {i:class_dict_11[class_list[i]] for i in range(len(class_list))}  
print(" =======这里得到的是 原始的idx:转换后的idx")
print(label_mapping)

在这里插入图片描述

修改2

在文件【./lib/datasets/init.py】导入刚才编写的数据读取脚本
在这里插入图片描述

修改3

在文件【./lib/models/ddrnet_23_slim.py】中,作者对网络的分类设置了固定的19类。需要将这个19 调整成 cfg.DATASET.NUM_CLASSES,自动的从yaml文件中获取类别信息
在这里插入图片描述

修改4

复制文件【./experiments/cityscapes/ddrnet23_slim_Seg_CHenZCH.yaml】并重命名为【ddrnet23_slim_Seg_CHenZCH.yaml】,其中必须修改的参数如下图。其他的参数根据自己训练情况进行调整。
在这里插入图片描述


4.3 工程的训练

修改完以上内容,运行命令:
export CUDA_VISIBLE_DEVICES=2,3
python -m torch.distributed.launch --nproc_per_node=2 tools/train.py --cfg experiments/cityscapes/ddrnet23_slim_Seg_CHenZCH.yaml


4.4自己数据集训练结果

在这里插入图片描述

  • 16
    点赞
  • 65
    收藏
    觉得还不错? 一键收藏
  • 42
    评论
评论 42
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值