[Семантическая сегментация] 3. Используйте ммсегментацию для обучения собственного набора данных сегментации.


В этом блоге также есть множество очень подробных обзоров. Друзья, которым интересно, могут перейти по адресу:

Сверточная нейронная сеть: очень подробное введение в сверточную нейронную сеть

Обнаружение целей: очень подробное введение в обнаружение целей.

Семантическая сегментация: очень подробное введение в семантическую сегментацию.

NMS: позволит вам понять и увидеть все NMS и его варианты в одной статье.

Увеличение данных: понимание увеличения данных в компьютерном зрении в одной статье.

Функция потерь: функция потерь и индекс оценки при классификации, обнаружении и сегментации.

Трансформер: обзор визуальных трансформеров

Практическая серия по машинному обучению: Дерево решений

Серия YOLO: v1v2v3v4Scaled-v4v5v6v7йолофйолоксйолйолоп


1. Введение в ммсегментацию

ссылка на github: https://github.com/open-mmlab/mmsegmentation

2. Введение в набор данных городского пейзажа

2.1 Структура данных

1. Структура набора данных:

  • Images_base: leftImg8bit (5030 элементов, общий объем 11,6 ГБ, фактически 5000 элементов)
  • Annotations_base: gtFine (30030 элементов общим объемом 1,1 ГБ)

2. Количество фотографий

  • 5000 прекрасных аннотаций

    • 2975 обучающих изображений, 500 обучающих изображений, 1525 тестовых изображений
  • 20 000 черновых аннотаций (с использованием полигонов для покрытия отдельных объектов)

3. Размер изображения:

  • 1024x2048

4. Сценарий данных:

  • Уличные сцены в 50 разных городах
  • Города поезд/вал/тест все разные

5. Определение категории:
вставьте сюда описание изображения

  • *: Отмечен для одного экземпляра. Если несколько объектов одной и той же категории распределены между собой, то есть границы экземпляров неочевидны, эти объекты образуют одну группу экземпляров, например группу автомобилей/велосипедов.
  • +: Представленный ярлык в настоящее время не включен ни в один элемент оценки и считается недействительным, поэтому эти ярлыки удаляются. Обычно мы говорим, что CityScapes содержит 19 категорий.
    вставьте сюда описание изображения

6. Метод маркировки

У Cityscape есть собственный метод аннотаций: Urbanscripts
https://github.com/mcordts/cityscapesScripts/tree/master/cityscapesscripts.

Примечание: перед тренировкой обязательно проверьте, есть ли в trainlabelid.png категорий 19. Лучше использовать citysscripts/helpers/labels.py, чтобы перегенерировать его и сделать безопаснее.

вставьте сюда описание изображения

Файл UrbansScripts/helpers/labels.py определяет соответствующие методы, цвета и т. д. различных категорий и значений идентификаторов, как показано ниже:

  • Всего категорий: 34 категории
  • Доступные категории: 19 категорий.
    вставьте сюда описание изображениявставьте сюда описание изображения
  • Тип файла метки: метки CityScapes не сосредоточены в одном json, но каждое изображение соответствует 4 файлам меток.
    • color.png: Каждый цвет соответствует категории.
      вставьте сюда описание изображения

    • instanceIds.png: используется для разделения экземпляров.
      вставьте сюда описание изображения

    • labelIds.png: метка, всего 34 категории (0–33), фон — 0
      вставьте сюда описание изображения

    • TrainLabelId.png: метка для обучения, (19 категорий обучения + 1 игнор), значение пикселя, не участвующего в обучении, устанавливаем 255, а значения пикселей остальных категорий, участвующих в обучении, 0-18.
      вставьте сюда описание изображения

    • полигоны.json

  • _gtFine_polygons.json хранит каждый класс и соответствующую область (положение вершины многоугольника используется для представления границы области);

2.2 Пример аннотации

вставьте сюда описание изображения
вставьте сюда описание изображения
вставьте сюда описание изображения
вставьте сюда описание изображения
вставьте сюда описание изображения
вставьте сюда описание изображения

3. Преобразуйте набор данных в формат Cityscape.

3.1 Преобразование данных, отмеченных меткой labelme, в данные, пригодные для обучения.

from pathlib import Path
import os
import glob
import cv2
import png
import numpy as np
import shutil
from PIL import Image


# set add_4 and add_15 folder
seg_folder = Path('./20210311_ground_mask_part1/')

seg_folder_TrainID = Path(os.path.join(seg_folder,"TrainID"))
seg_folder_img = Path(os.path.join(seg_folder,"img"))
seg_folder_LabelID = Path(os.path.join(seg_folder,"LabelID"))
seg_folder_color = Path(os.path.join(seg_folder,"color"))

if not seg_folder_img.exists():
    os.mkdir(seg_folder_img)
if not seg_folder_LabelID.exists():
    os.mkdir(seg_folder_LabelID)
if not seg_folder_TrainID.exists():
    os.mkdir(seg_folder_TrainID)
if not seg_folder_color.exists():
    os.mkdir(seg_folder_color)

LabelID_glob = glob.glob('./20210311_ground_mask_part1/20210222_TJP_freespace_ss/20210222_TJP_freespace_ss_label/*.png')
TrainID_glob = glob.glob('./20210311_ground_mask_part1/20210222_TJP_freespace_ss/20210222_TJP_freespace_ss_label/*.png')
Img_glob = glob.glob('./20210311_ground_mask_part1/20210222_TJP_freespace_ss/20210222_TJP_freespace_ss_extract/*.jpg')
Color_glob = glob.glob('./20210311_ground_mask_part1/20210222_TJP_freespace_ss/20210222_TJP_freespace_ss_label/*.png')
# assert(len(LabelID_glob)==len(Img_glob))

print("len for lable glob",len(LabelID_glob))

# ******************* TrainID process ****************************
print("begin to process TrainID")
for k in range(len(LabelID_glob)):
    transfer_ori = Image.open(TrainID_glob[k])
    transfer_ground = np.array(transfer_ori)
    transfer_ground[transfer_ground == 0] = 255  # ignore
    transfer_ground[transfer_ground == 1] = 0   # freespace
    transfer_ground[transfer_ground == 2] = 1  # white solid lane line
    transfer_ground[transfer_ground == 3] = 2  # white dotted lane line
    # transfer_ground[transfer_ground == 4] = 3  # yellow solid lane line
    # transfer_ground[transfer_ground == 5] = 4  # yellow dotted lane line
    transfer_ground[transfer_ground == 6] = 3  # arrow
    transfer_ground[transfer_ground == 7] = 4  # diamond_sign
    transfer_ground[transfer_ground == 8] = 5  # zebra crossing
    transfer_ground[transfer_ground == 9] = 6  # stop line
    transfer_ground_img = Image.fromarray(transfer_ground)
    transfer_ground_img = transfer_ground_img.resize((2048, 1024))
    transfer_ori_path = os.path.join(seg_folder_TrainID,TrainID_glob[k].split('/')[-1].split('\\')[1])
    transfer_ground_img.save(transfer_ori_path)
    print("the {0} th TrainID img has been processed and save in folder".format(k))
#
# # ******************* LableID process ****************************
print("begin to process LableID")
for k in range(len(LabelID_glob)):
    transfer_ori = Image.open(TrainID_glob[k])
    transfer_ground = np.array(transfer_ori)
    transfer_ground[transfer_ground == 0] = 0  # ignore
    transfer_ground[transfer_ground == 1] = 1  # freespace
    transfer_ground[transfer_ground == 2] = 2  # white solid lane line
    transfer_ground[transfer_ground == 3] = 3  # white dotted lane line
    # transfer_ground[transfer_ground == 4] = 4  # yellow solid lane line
    # transfer_ground[transfer_ground == 5] = 5  # yellow dotted lane line
    transfer_ground[transfer_ground == 6] = 4  # arrow
    transfer_ground[transfer_ground == 7] = 5  # diamond_sign
    transfer_ground[transfer_ground == 8] = 6  # zebra crossing
    transfer_ground[transfer_ground == 9] = 7  # stop line

    transfer_ground_img = Image.fromarray(transfer_ground)
    transfer_ground_img = transfer_ground_img.resize((2048, 1024))
    transfer_ori_path = os.path.join(seg_folder_TrainID, TrainID_glob[k].split('/')[-1].split('\\')[1])
    transfer_ground_img.save(transfer_ori_path)
    print("the {0} th LabelID img has been processed and save in folder".format(k))


# # ******************** resize img ***********************************
for k in range(len(Img_glob)):
    print("copy the {0}th img to add img folder".format(k))
    src_img = Image.open(Img_glob[k])
    src_img = src_img.resize((2048, 1024))
    src_img_save_path = os.path.join(seg_folder_img,Img_glob[k].split('/')[-1].split('\\')[1].split('.')[0])
    src_img.save(src_img_save_path+'.png')
#
# ## ********************* resize color png *****************************
for k in range(len(Color_glob)):
    print("copy the {0}th img to color folder".format(k))
    src_img = Image.open(Color_glob[k])
    src_img = src_img.resize((2048,1024))
    color_img_save_path = os.path.join(seg_folder_color,Color_glob[k].split('/')[-1].split('\\')[1].split('.')[0])
    src_img.save(color_img_save_path+'.png')

3.2 Двойное именование

import os
import glob
import shutil
from pathlib import Path


img_path = './img/'
TrainID_path = './TrainID/'
LabelID_path = './LabelID/'
color_path = './color/'
gtFine_path = './gtFine/'
leftImg8bit_path = './leftImg8bit/'

if not Path(gtFine_path).exists():
    os.mkdir(gtFine_path)
if not Path(leftImg8bit_path).exists():
    os.mkdir(leftImg8bit_path)

img_files = os.listdir(img_path)
TrainID_files = os.listdir(TrainID_path)
LabelID_files = os.listdir(LabelID_path)
color_files = os.listdir(color_path)

m = 0
for file in color_files:
    #import pdb;pdb.set_trace()

    old = color_path + os.sep + color_files[m]
    filename = os.path.splitext(file)[0]

    new = gtFine_path + 'part1_' + filename + '_gtFine_color.png'
    shutil.move(old, new)
    print('rename {}th color files'.format(m))
    m+=1

i = 0
for file in img_files:
    #import pdb;pdb.set_trace()

    old = img_path + os.sep + img_files[i]
    filename = os.path.splitext(file)[0]

    new = leftImg8bit_path+ 'part1_' + filename + '_leftImg8bit.png'
    shutil.move(old, new)
    print('rename {}th img files'.format(i))
    i+=1
j = 0
for file in TrainID_files:
    # import pdb;pdb.set_trace()

    old = TrainID_path + os.sep + TrainID_files[j]
    filename = os.path.splitext(file)[0]

    new = gtFine_path + 'part1_' + filename + '_gtFine_labelTrainIds.png'
    shutil.move(old, new)
    print('rename {}th trainid files'.format(j))
    j += 1
k = 0
for file in LabelID_files:
    # import pdb;pdb.set_trace()

    old = LabelID_path + os.sep + LabelID_files[k]
    filename = os.path.splitext(file)[0]

    new = gtFine_path + 'part1_' + filename + '_gtFine_labelIds.png'
    shutil.move(old, new)
    print('rename {}th labelid files'.format(k))
    k += 1
  • цвет
    вставьте сюда описание изображения

  • меткаtrainid
    вставьте сюда описание изображения

  • метка
    вставьте сюда описание изображения

3.3 Преобразование XML в JSON

import json
import xmltodict
import glob
import os

xml_list = glob.glob('./20210222_TJP_freespace_ss_xml/*.xml') #xml文件的路径

 
'''json to xml'''
def json_to_xml(json_str):
    # xmltodict库的unparse()json转xml
    # 参数pretty 是格式化xml
    xml_str = xmltodict.unparse(json_str, pretty=1, root='shapes')
    return xml_str
 
'''xml to json'''
def xml_to_json(xml_str):
    # parse是的xml解析器
    xml_parse = xmltodict.parse(xml_str)
    # json库dumps()是将dict转化成json格式,loads()是将json转化成dict格式。
    # dumps()方法的ident=1,格式化json
    json_str = json.dumps(xml_parse, indent=1)
    return json_str
 

for xml_path in xml_list:

    if os.path.exists(xml_path):
        with open(xml_path, 'r') as f1:
            xmlfile = f1.read()
            print('---------xml文件-----------')
            print(xmlfile)
            print('---------json文件----------')
            print(xml_to_json(xmlfile))
        with open(xml_path[:-3]+'json','w') as newfile:
            newfile.write(xml_to_json(xmlfile))
            print('--------写入json文件--------')
            print('写入xml.json文件成功')

4. Обучение и тестирование

вставьте сюда описание изображения

4.1. Измените имя пути к набору данных и т. д.

Примечание. Сначала скомпилируйте путь. python setup.py develop

1. Измените путь к набору данных.

mmseg/datasets/cityscapes.py

вставьте сюда описание изображения

2. Измените количество категорий.

config/_base_/ocrnet_hr18.py  

вставьте сюда описание изображения

mmseg/datasets/cityscapes.py

вставьте сюда описание изображения

mmseg/core/class_names.py

вставьте сюда описание изображения
3. Используйте labelid.png в качестве метки для обучения, то есть тренируйте две категории: свободное пространство и фон:

Если вы обучаете только категорию свободного пространства и используете обычный метод, чтобы игнорировать фон как игнорируемый и не участвовать в обучении, вы обнаружите, что весь фон был изучен как категория свободного пространства во время визуализации, поскольку игнорируемые пиксели в сегментации на самом деле являются пикселями, на которые не сфокусировано внимание., то есть никого не волнует, к какой категории им предсказывают, но если на изображении есть большая область игнорирования, то есть есть большая область Неправильные категории, такую ​​модель использовать нельзя, поэтому здесь в качестве обучения используется labelid.png label, то есть обучение двух категорий: свободного пространства и фона, поэтому эффект обучения будет очень хорошим.

mmseg/datasets/cityscapes.py

вставьте сюда описание изображения

4. Измените данные обучения, тестирования и проверки.

mmseg/datasets/cityscapes.py

вставьте сюда описание изображения

5. Измените количество выборок (пакетов) для каждого графического процессора.

configs/_base_/datasets/cityscapes.py

вставьте сюда описание изображения

6. Модификация БН распределенного обучения/нераспределенного обучения.

config/_base_/models/ocrnet_hr18.py

вставьте сюда описание изображения
7. Измените количество итераций и интервал сохранения модели.

config/_base_/schedules/schedule_160k.py

вставьте сюда описание изображения

8. Где посмотреть данные каждой тренировки:

mmseg/datasets/builder.py

вставьте сюда описание изображения
вставьте сюда описание изображения

datasets[0].keys()
>>>
dict_keys(['img_metas', 'img', 'gt_semantic_seg'])

4.2 Обучение

1. Обучение одной карте

python tools/train.py ${
    
    CONFIG_FILE} [optional arguments]

2. Обучение с использованием нескольких карт

./tools/dist_train.sh ${
    
    CONFIG_FILE} ${
    
    GPU_NUM} [optional arguments]
python -m torch.distributed.launch --nproc_per_node=2 --master_port=29003  tools/train.py --config configs/ocrnet/ocrnet_hr18s_512x1024_40k_cityscapes.py --launcher pytorch --work_dir work_dir

Если сообщается о следующей ошибке, решение состоит в том, master_port чтобы изменить значение

subprocess.CalledProcessError: Command '[xxx]' returned non-zero exit status 1.
Optional arguments are:
--no-validate (not suggested): By default, the codebase will perform evaluation at every k iterations during the training. To disable this behavior, use --no-validate.
--work-dir ${
    
    WORK_DIR}: Override the working directory specified in the config file.
--resume-from ${
    
    CHECKPOINT_FILE}: Resume from a previous checkpoint file (to continue the training process).
--load-from ${
    
    CHECKPOINT_FILE}: Load weights from a checkpoint file (to start finetuning for another task).
Difference between resume-from and load-from:
resume-from loads both the model weights and optimizer state including the iteration number.
load-from loads only the model weights, starts the training from iteration 0.

4.3 Тестирование

# single-gpu testing
python tools/test.py ${
    
    CONFIG_FILE} ${
    
    CHECKPOINT_FILE} [--out ${
    
    RESULT_FILE}] [--eval ${
    
    EVAL_METRICS}] [--show]

# save test result at dir
python tools/test.py ${
    
    CONFIG_FILE} ${
    
    CHECKPOINT_FILE} [--out ${
    
    RESULT_FILE}] [--show-dir result]

# multi-gpu testing
./tools/dist_test.sh ${
    
    CONFIG_FILE} ${
    
    CHECKPOINT_FILE} ${
    
    GPU_NUM} [--out ${
    
    RESULT_FILE}] [--eval ${
    
    EVAL_METRICS}]
Optional arguments:

RESULT_FILE: Filename of the output results in pickle format. If not specified, the results will not be saved to a file.
EVAL_METRICS: Items to be evaluated on the results. Allowed values depend on the dataset, e.g., mIoU is available for all dataset. Cityscapes could be evaluated by cityscapes as well as standard mIoU metrics.
--show: If specified, segmentation results will be plotted on the images and shown in a new window. It is only applicable to single GPU testing and used for debugging and visualization. Please make sure that GUI is available in your environment, otherwise you may encounter the error like cannot connect to X server.
--show-dir: If specified, segmentation results will be plotted on the images and saved to the specified directory. It is only applicable to single GPU testing and used for debugging and visualization. You do NOT need a GUI available in your environment for using this option.

Примеры:

Предположим, что вы уже загрузили контрольные точки в каталог checkpoints/.

  • Протестируйте PSPNet и визуализируйте результаты. Нажмите любую клавишу для перехода к следующему изображению.
python tools/test.py configs/pspnet/pspnet_r50-d8_512x1024_40k_cityscapes.py \
    checkpoints/pspnet_r50-d8_512x1024_40k_cityscapes_20200605_003338-2966598c.pth \
    --show
  • Протестируйте PSPNet и сохраните нарисованные изображения для последующей визуализации.
python tools/test.py configs/pspnet/pspnet_r50-d8_512x1024_40k_cityscapes.py \
    checkpoints/pspnet_r50-d8_512x1024_40k_cityscapes_20200605_003338-2966598c.pth \
    --show-dir psp_r50_512x1024_40ki_cityscapes_results
  • Протестируйте PSPNet на PASCAL VOC (не сохраняя результаты теста) и оцените mIoU.
python tools/test.py configs/pspnet/pspnet_r50-d8_512x1024_20k_voc12aug.py \
    checkpoints/pspnet_r50-d8_512x1024_20k_voc12aug_20200605_003338-c57ef100.pth \
    --eval mAP
  • Протестируйте PSPNet с 4 графическими процессорами и оцените стандартные показатели mIoU и городских пейзажей.
./tools/dist_test.sh configs/pspnet/pspnet_r50-d8_512x1024_40k_cityscapes.py \
    checkpoints/pspnet_r50-d8_512x1024_40k_cityscapes_20200605_003338-2966598c.pth \
    4 --out results.pkl --eval mIoU cityscapes

Примечание: существует некоторый разрыв (~0,1%) между городскими пейзажами и нашим mIoU. Причина в том, что городские пейзажи усредняют каждый класс по размеру класса по умолчанию. Мы используем простую версию без среднего значения для всех наборов данных.

  • Протестируйте PSPNet на городских пейзажах, протестируйте разделение на 4 графических процессора и сгенерируйте файлы PNG для отправки на официальный оценочный сервер.

Сначала добавьте следующее в файл конфигурации configs/pspnet/pspnet_r50-d8_512x1024_40k_cityscapes.py:

data = dict(
    test=dict(
        img_dir='leftImg8bit/test',
        ann_dir='gtFine/test'))

Затем запустите тест.

./tools/dist_test.sh configs/pspnet/pspnet_r50-d8_512x1024_40k_cityscapes.py \
    checkpoints/pspnet_r50-d8_512x1024_40k_cityscapes_20200605_003338-2966598c.pth \
    4 --format-only --eval-options "imgfile_prefix=./pspnet_test_results"

Вы получите файлы PNG в каталоге ./pspnet_test_results. Вы можете запустить zip -r results.zip pspnet_test_results/ и отправить zip-файл на оценочный сервер.

4.4 демо

python demo/image_demo.py ${
    
    IMAGE_FILE} ${
    
    CONFIG_FILE} ${
    
    CHECKPOINT_FILE} [--device ${
    
    DEVICE_NAME}] [--palette-thr ${
    
    PALETTE}]
# example
python demo/image_demo.py demo/demo.jpg configs/pspnet/pspnet_r50-d8_512x1024_40k_cityscapes.py \
    checkpoints/pspnet_r50-d8_512x1024_40k_cityscapes_20200605_003338-2966598c.pth --device cuda:0 --palette cityscapes

Примечание. Если вы используете одну и ту же конфигурацию для обучения несколько раз, вы можете поместить результаты в другой рабочий каталог, изменив имя config/hr.py.

5. Тренировочные навыки

5.1 Настройки похудения для разных категорий

/configs/_base_/models/ocrnet_hr18.py

вставьте сюда описание изображения

Guess you like

Origin blog.csdn.net/jiaoyangwm/article/details/114373269#comments_28426349