【实验记录】PSPNet(PyTorch)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/qq_31347869/article/details/102476128

代码地址:https://github.com/hszhao/semseg

环境配置

# 创建虚拟环境
conda create -n pytorch-pspnet python==3.7
pip install torch==1.0.0
pip install tensorboardX
conda install opencv
conda install pillow
conda install pyaml

# clone源文件
git clone https://github.com/hszhao/semseg.git

环境配置过程中的问题记录:

1)pip install apex 后 import 报错

TypeError: Class advice impossible in Python3.  Use the @implementer class decorator instead

参考: issues/214#issuecomment-476399539

解决: 卸载 pip 安装的 apex,确保当前 CUDA 版本和 PyTorch 版本一致的前提下,执行:

git clone https://github.com/NVIDIA/apex.git
cd apex
pip install -v --no-cache-dir --global-option="--cpp_ext" --global-option="--cuda_ext" .

注意: 不要忘记第三条命令最后的点

# 安装 apex 时报错
FileNotFoundError: [Errno 2] No such file or directory: '/home/usr/local/cuda-9.0:/bin/nvcc': '/home/usr/local/cuda-9.0:/bin/nvcc'

发现很奇怪的在路径里多了 “:”,输入 vi ~/.bashrc 检查环境变量,看来应该是 :$PATH 前面冒号的问题。

# 将后面的:$CUDA_HOME删掉
export CUDA_HOME=/data/zyy/usr/local/cuda-9.0:$CUDA_HOME
source ~/.bashrc

2)opencv 报错

image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)  # convert cv2 read image from BGR order to RGB order
cv2.error: OpenCV(3.4.2) /tmp/build/80754af9/opencv-suite_1535558553474/work/modules/imgproc/src/color.hpp:253: error: (-215:Assertion failed) VScn::contains(scn) && VDcn::contains(dcn) && VDepth::contains(depth) in function 'CvtHelper'

参考:
issues/6#issuecomment-428078042
issues/12163#issuecomment-411200484

解决: 看到是在 BGR 转 RGB 时出了错,在尝试过上面两种方法之后,均排除了这些问题,后来通过加入 image = image.astype('uint8') 发现数据异常,为 ‘NoneType’,说明数据没有被正确加载,通过检查 util/dataset.py 的 37 行左右:

image_name = os.path.join(data_root, line_split[0])
label_name = os.path.join(data_root, line_split[1])

打印输出 image_name,发现果然是路径不对,要确保数据的索引文件格式为这样:

JPEGImages/2007_000032.jpg SegmentationClassAug/2007_000032.png

修改好之后问题解决。


在VOC数据集上训练

1. 数据集

这里用的是 VOC 增强数据集,文章【PASCAL VOC 2012 Augmented Dataset】内有说明如何组织数据。

将数据 SegmentationClassAug 放在 semseg/dataset/voc2012 下,数据集索引文件放在 semseg/dataset/voc2012/ImageSets/Segmentation 下,修改 config/voc2012/ 目录下的配置文件目录设置。

这里需要的文件只有原图(JPEGImages),标签文件(SegmentatinClass),数据划分文件(ImageSets)和 colors.txt 以及 names.txt

# 配置文件,主要留意一下路径要正确
DATA:
  data_root: /data/zyy/code/semseg/dataset/voc2012
  train_list: /data/zyy/code/semseg/dataset/voc2012/ImageSets/Segmentation/train_aug.txt
  val_list: /data/zyy/code/semseg/dataset/voc2012/ImageSets/Segmentation/val.txt
  classes: 21

另外,由于显存大小不够,训练 batch 适当减小,这里设置为了 5。

2. 执行训练

sh tool/train.sh voc2012 pspnet101
  • 第一个参数是数据集名称,第二个参数是网络名称

这个网站 可以下载预训练模型,将模型放在 initmodel 文件夹下即可。

如果要取消预训练:

# 修改 model/pspnet.py 第 30 行
pretrained=False

在训练时进行验证:

# config.yaml
TRAIN:
	...
	evaluate: True # evaluate on validation set, extra gpu memory needed and small batch_size_val is recommend

训练正常跑起来输出:
在这里插入图片描述
3. 执行测试

将训练好的 model 放在 config 文件中指定的路径下,或者修改 config 文件的路径指向 model 所在位置,都可以很随意~

这里我先用验证集做测试(因为 VOC 数据的测试集没有 ground-truth)

# config.yaml

TEST:
  test_list: /data/zyy/code/semseg/dataset/voc2012/ImageSets/Segmentation/val.txt
  split: val  # split in [train, val and test]
  base_size: 512  # based size for scaling
  test_h: 473
  test_w: 473
  scales: [1.0]  # evaluation scales, ms as [0.5, 0.75, 1.0, 1.25, 1.5, 1.75]
  has_prediction: False  # has prediction already or not
  index_start: 0  # evaluation start index in list
  index_step: 0  # evaluation step index in list, 0 means to end
  test_gpu: [0,1]
  model_path: exp/voc2012/pspnet101/model/train_epoch_80.pth  # evaluation model path
  save_folder: exp/voc2012/pspnet101/result/epoch_80/val  # results save folder
  colors_path: dataset/voc2012/voc2012_colors.txt  # path of dataset colors
  names_path: dataset/voc2012/voc2012_names.txt  # path of dataset category names
  • test_list:要做测试的图片索引txt文件

运行测试程序执行命令:

sh tool/test.sh voc2012 pspnet101
  • 第一个参数是模型名称,第二个参数是网络名称

测试问题记录:

# 错误信息
RuntimeError: cuda runtime error (11) : invalid argument at /pytorch/aten/src/THC/THCGeneral.cpp:405

参考: https://discuss.pytorch.org/t/a-error-when-using-gpu/32761

解决: 原因可能是 1)多GPU测试,或者 2)PyTorch版本与显卡不兼容

在这里我的报错是由于后者,我的显卡是 RTX2080(Ti),PyTorch 1.0,如果换成 RTX1080(Ti)就没有问题,比较简单的解决方案是,将 python 文件中的 torch.backends.cudnn.benchmark = True 设置成 False,即可得到一个静态 CUDA error,此时虽然报错但并不影响后面的运行。

4. 可视化

# 使用 tensorboard 可视化训练过程
tensorboard --logdir=run1:$EXP1,run2:$EXP2 --port=6789

quick demo:

PYTHONPATH=./ python tool/demo.py --config=config/ade20k/ade20k_pspnet50.yaml --image=figure/demo/ADE_val_00001515.jpg TEST.scales '[1.0]'
  • --config:配置文件的路径
  • --image:要测试的图片路径

在自己的数据集上训练

为了避免改名称的麻烦,自己的数据也套用 VOC 数据的组织格式和名称。将自己的数据放在 semseg/dataset/voc2012 下,分别用 JPEGImagesSegmentationClass 存放训练图像和标签文件。

voc2012/ImageSets/Segmentation 下,生成自己数据集的 train.txtval.txt 索引文件,注意格式为:

# train.txt
JPEGImages/图片名.后缀 SegmentationClass/标签名.后缀
JPEGImages/图片名.后缀 SegmentationClass/标签名.后缀
...

提供一个转换自己数据的脚本,前提时你的索引文件同原 VOC 数据索引文件格式相同,每行只有图片数据的名称,运行以下脚本生成新的 txt 文件:

import os

def create_txt(file, out_file):
    if os.path.exists(out_file):
        os.remove(out_file)
    old_file = open(file)
    new_file = open(out_file, 'w')
    lines = old_file.readlines()
    for line in lines:
        line = line.strip('\n')
        new_line = 'JPEGImages/'+line+'.png' +' '+'SegmentationClass/'+line+'.png'+'\n'
        new_file.write(new_line)
    old_file.close()
    new_file.close()

if __name__=='__main__':
    root = 'path\\to\\Segmentation'
    ori_file = os.path.join(root, 'trainval.txt')
    out_file = os.path.join(root, 'trainval_mod.txt')
    create_txt(ori_file, out_file)

config/voc2012/ 目录下对配置文件 .yaml,根据自己数据特点修改训练参数:

# 配置文件,主要留意一下路径要正确
DATA:
  data_root: /data/zyy/code/semseg/dataset/voc2012
  train_list: /data/zyy/code/semseg/dataset/voc2012/ImageSets/Segmentation/train.txt
  val_list: /data/zyy/code/semseg/dataset/voc2012/ImageSets/Segmentation/val.txt
  classes: 2
  ...
  train_h: 512
  train_w: 512
  batch_size: 5
  

建立文件 voc2012_names.txtvoc2012_colors.txt,根据自己数据集的类别进行修改:其中 names 文件是数据集的类别名称,colors 文件是最后测试时为不同类别覆盖的颜色,比如第一行 0 0 0 就对应背景黑色,128 0 0 对应第一个飞机类别的红色,自己根据情况设置就好了。

依然执行训练命令:

sh tool/train.sh voc2012 pspnet101

注意1: 数据集的 label 要确保是 uint8 的(位深度=8),根据类别个数设定每一类在 label 上的像素值,比如我的二分类就是背景像素值为 0,前景像素值为 1。

注意2: 在做测试时,可以选择用 val 或 test 数据,其中 split 等于 val 时需要提供标签,而 test 不需要提供标签。

猜你喜欢

转载自blog.csdn.net/qq_31347869/article/details/102476128
今日推荐