Cityscapse 数据集使用 + 训练 STDC踩坑
官網地址:Cityscapes Dataset – Semantic Understanding of Urban Street Scenes (cityscapes-dataset.com)
getFine 文件下存儲標注文件
leftImg8bit 文件夾下存儲真實圖片
兩個文件下文件目錄級別是一樣的:
????????getFine/liftImg8bit? ->? test / train / val? ->? 城市目錄? ->? labels / imgs
cityscapse 數據集內的圖片均為 2048 x 1024,?總共5000張精細釋,2975張訓練圖,500張驗證圖和1525張測試圖, 共有19個類別。
下面著重說一下getFine下的標注文件:
xxx_gtFine_color.png,? :?標注的可視化圖片
xxx_gtFine_instanceIds.png :是用來做實例分割訓練用的
xxx_gtFine_labelsIds.png :是語義分割訓練需要的,它們的像素值就是class值
xxx_gtFine_polygons.json :用labelme工具標注后所生成的文件,里面主要記錄了每個多邊形標注框上的點集坐標。
對于 cityscapse_info.json 文件如下:
Label = namedtuple('Label', ['name', 'id', 'trainId', 'category', 'categoryId', 'hasInstances', 'ignoreInEval', 'color'])labels = [# name id trainId category catId hasInstances ignoreInEval colorLabel( 'unlabeled' , 0 , 255 , 'void' , 0 , False , True , ( 0, 0, 0) ),Label( 'ego vehicle' , 1 , 255 , 'void' , 0 , False , True , ( 0, 0, 0) ),Label( 'rectification border' , 2 , 255 , 'void' , 0 , False , True , ( 0, 0, 0) ),Label( 'out of roi' , 3 , 255 , 'void' , 0 , False , True , ( 0, 0, 0) ),Label( 'static' , 4 , 255 , 'void' , 0 , False , True , ( 0, 0, 0) ),Label( 'dynamic' , 5 , 255 , 'void' , 0 , False , True , (111, 74, 0) ),Label( 'ground' , 6 , 255 , 'void' , 0 , False , True , ( 81, 0, 81) ),Label( 'road' , 7 , 1 , 'flat' , 1 , False , False , (128, 64,128) ),Label( 'sidewalk' , 8 , 2 , 'flat' , 1 , False , False , (244, 35,232) ),Label( 'parking' , 9 , 255 , 'flat' , 1 , False , True , (250,170,160) ),Label( 'rail track' , 10 , 255 , 'flat' , 1 , False , True , (230,150,140) ),Label( 'building' , 11 , 3 , 'construction' , 2 , False , False , ( 70, 70, 70) ),Label( 'wall' , 12 , 4 , 'construction' , 2 , False , False , (102,102,156) ),Label( 'fence' , 13 , 5 , 'construction' , 2 , False , False , (190,153,153) ),Label( 'guard rail' , 14 , 255 , 'construction' , 2 , False , True , (180,165,180) ),Label( 'bridge' , 15 , 255 , 'construction' , 2 , False , True , (150,100,100) ),Label( 'tunnel' , 16 , 255 , 'construction' , 2 , False , True , (150,120, 90) ),Label( 'pole' , 17 , 6 , 'object' , 3 , False , False , (153,153,153) ),Label( 'polegroup' , 18 , 255 , 'object' , 3 , False , True , (153,153,153) ),Label( 'traffic light' , 19 , 7 , 'object' , 3 , False , False , (250,170, 30) ),Label( 'traffic sign' , 20 , 8 , 'object' , 3 , False , False , (220,220, 0) ),Label( 'vegetation' , 21 , 9 , 'nature' , 4 , False , False , (107,142, 35) ),Label( 'terrain' , 22 , 10 , 'nature' , 4 , False , False , (152,251,152) ),Label( 'sky' , 23 , 11 , 'sky' , 5 , False , False , ( 70,130,180) ),Label( 'person' , 24 , 12 , 'human' , 6 , True , False , (220, 20, 60) ),Label( 'rider' , 25 , 13 , 'human' , 6 , True , False , (255, 0, 0) ),Label( 'car' , 26 , 14 , 'vehicle' , 7 , True , False , ( 0, 0,142) ),Label( 'truck' , 27 , 15 , 'vehicle' , 7 , True , False , ( 0, 0, 70) ),Label( 'bus' , 28 , 16 , 'vehicle' , 7 , True , False , ( 0, 60,100) ),Label( 'caravan' , 29 , 255 , 'vehicle' , 7 , True , True , ( 0, 0, 90) ),Label( 'trailer' , 30 , 255 , 'vehicle' , 7 , True , True , ( 0, 0,110) ),Label( 'train' , 31 , 17 , 'vehicle' , 7 , True , False , ( 0, 80,100) ),Label( 'motorcycle' , 32 , 18 , 'vehicle' , 7 , True , False , ( 0, 0,230) ),Label( 'bicycle' , 33 , 19 , 'vehicle' , 7 , True , False , (119, 11, 32) ),Label( 'license plate' , -1 , -1 , 'vehicle' , 7 , False , True , ( 0, 0,142) ), ]'name' , # The identifier of this label, e.g. 'car', 'person', ... .# We use them to uniquely name a class'id' , # An integer ID that is associated with this label.# The IDs are used to represent the label in ground truth images# An ID of -1 means that this label does not have an ID and thus# is ignored when creating ground truth images (e.g. license plate).# Do not modify these IDs, since exactly these IDs are expected by the# evaluation server.'trainId' , # Feel free to modify these IDs as suitable for your method. Then create# ground truth images with train IDs, using the tools provided in the# 'preparation' folder. However, make sure to validate or submit results# to our evaluation server using the regular IDs above!# For trainIds, multiple labels might have the same ID. Then, these labels# are mapped to the same class in the ground truth images. For the inverse# mapping, we use the label that is defined first in the list below.# For example, mapping all void-type classes to the same ID in training,# might make sense for some approaches.# Max value is 255!'category' , # The name of the category that this label belongs to'categoryId' , # The ID of this category. Used to create ground truth images# on category level.'hasInstances', # Whether this label distinguishes between single instances or not'ignoreInEval', # Whether pixels having this class as ground truth label are ignored# during evaluations or not'color' , # The color of this label如果將自己的數據集改成cityscapse格式:
1、先確定好自己的類別 n_classes,另外背景也要算一類!比如分割人的二值圖像,那就是兩類,未標注的黑色背景算一類,標注的白色人形算一類。
2、更改cityscapse_info.json文件,文件總共包含34個字典,每個字典代表一個label,格式如下:
{"hasInstances": false,"category": "void","catid": 0,"name": "unlabeled","ignoreInEval": false,"id": 0,"color": [0,0,0],"trainId": 1}更改時,整體框架不要動!! 只需要將用不到的類別做兩個操作:
? ? ? ? 1)、將“ignoreInEval”設置為true
? ? ? ? 2)、將“trainId”設置為255
對于需要保留的類別:
? ? ? ? 1)、"catid" 從0開始計數,依次遞增,總共有3個類別,那就是:0、1、2
? ? ? ? 2)、“id”從0開始計數,依次遞增,總共有3個類別,那就是:0、1、2。該值為標注圖片中對? ????????????????應類別對象區域的像素值。
? ? ? ? 3)、“ignoreInEval” 設置為 false
? ? ? ? 4)、“trainId”從0開始計數,依次遞增,總共有3個類別,那就是:0、1、2
3、更改自己的標注圖片:
? ? ? ? 1、自己數據集的原始圖片 和 標注后的mask灰度圖片 名稱中,應該按照官方cityscapse數據集的格式命名,即:
? ? ? ? ? ? ? ? 原始圖片名稱:? ***_leftImg8bit.png
? ? ? ? ? ? ? ? 標注圖片名稱: ***_gtFine_labelIds.png
????????重命名代碼:
import os import tqdm from PIL import Imagegt_path = './gtFine_trainvaltest/gtFine/train/qdu/' img_path = './leftImg8bit_trainvaltest/leftImg8bit/train/qdu/'gt_suffix = '_gtFine_labelIds.png' img_suffix = '_leftImg8bit.png'gtlist = os.listdir(gt_path) for gt in tqdm.tqdm(gtlist):newname = gt[:-4] + gt_suffixsrc = os.path.join(gt_path, gt)dst = os.path.join(gt_path, newname)os.rename(src, dst)newname = gt[:-4] + img_suffixsrc = os.path.join(img_path, gt)dst = os.path.join(img_path, newname)os.rename(src, dst)? ? ? ?
???????? 2、標注圖片應該為單通道圖片,多通道轉單通道圖片代碼:
import os import cv2 import tqdm import numpy as np from PIL import Imagegt_path = './gtFine_trainvaltest/gtFine/train/qdu/'gtlist = os.listdir(gt_path) for gt in tqdm.tqdm(gtlist):read_path = os.path.join(gt_path, gt)mask = Image.open(read_path)img = np.array(mask)print(img.shape, mask.size)#導入 opencvimport cv2 #讀入原始圖像,使用 cv2.IMREAD_UNCHANGEDimg = cv2.imread(read_path, cv2.IMREAD_UNCHANGED) #查看原始圖像shape = img.shapeif len(shape) == 2:continue# print(shape)if shape[2] == 3 or shape[2] == 4: img_gray = cv2.cvtColor(img,cv2.COLOR_RGB2GRAY) #將彩色圖轉化為單通道圖# print(img_gray.shape) #查看轉換后圖像通道# cv2.imshow("gray_img", img_gray)# cv2.imshow("image", img)# cv2.waitKey(0)# cv2.destroyAllWindows()cv2.imwrite(read_path, img_gray)# break? ? ? ? 3、標注圖片及原圖尺寸應該為 2048 x 1024, 更改圖片尺寸代碼:
import os import tqdm from PIL import Imagegt_path = './gtFine_trainvaltest/gtFine/train/qdu/' img_path = './leftImg8bit_trainvaltest/leftImg8bit/train/qdu/'gtlist = os.listdir(gt_path) for gt in tqdm.tqdm(gtlist):rdpath = os.path.join(gt_path, gt)mask = Image.open(rdpath)mask = mask.resize((2048, 1024), Image.ANTIALIAS)mask.save(rdpath)gt = gt.replace('_gtFine_labelIds.png', '_leftImg8bit.png')rdpath = os.path.join(img_path, gt)image = Image.open(rdpath)image = image.resize((1024, 2048), Image.ANTIALIAS)image.save(rdpath)? ? ? ? 4、?對于語義分割,標注mask圖片中的像素值即為類別值,某個類別對象區域的像素值應該為該類別的“id”的值。其他未標注的區域設置為0即可。和cityscapse_info.json文件中的“id”值對應。更改像素值代碼參考:
import os import cv2 import tqdm import glob import numpy as np from PIL import Imagenp.set_printoptions(threshold=np.inf) gt_path = './gtFine_trainvaltest/gtFine/train/qdu/' gtlist = os.listdir(gt_path)for gt in tqdm.tqdm(gtlist):read_path = os.path.join(gt_path, gt)mask = Image.open(read_path)img = np.array(mask)img[img < 100] = 0img[img > 100] = 1image = Image.fromarray(img)image.save(read_path)# img = np.array(mask) # print(img.shape, img)breakSTDC 踩坑:
RuntimeError: transform: failed to synchronize: cudaErrorIllegalAddress: an illegal memory access?報上述錯誤:
? ? ? ? 1)、標注文件 / 標簽 等沒有設置正確
? ? ? ? 2)、網絡模型、訓練數據(圖片和標簽)沒有放置到GPU上
? ? ? ? 3)、縮小batch size
? ? ? ? 4)、python版本不匹配(可能性不大,我的python3.7 + torhc1.7正常跑)
RuntimeError: 1only batches of spatial targets supported (non-empty 3D tensors) but got targets of size報上述錯誤,標注文件通道不對! 語義分割,cityscape格式數據集,標注mask圖片應該為單通道圖片! 如果是多通道圖片就會出現上述出錯。 其他問題可以參考:???????RuntimeError: 1only batches of spatial targets supported (non-empty 3D tensors) but got targets of size - DuanYongchun - 博客園 (cnblogs.com)
RuntimeError: Some elements marked as dirty during the forward method were not returned as output. The inputs that are modified inplace must all be outputs of the Function.?報上述錯誤,BatchNorm2d函數不對,建議使用torch官方正則化函數,即nn.BatchNorm2d。 其他問題參考:RuntimeError: Some elements marked as dirty during the forward method were not returned as output. The inputs that are modified inplace must all be outputs of the Function. · Issue #267 · zhanghang1989/PyTorch-Encoding (github.com)
RuntimeError: stack expects each tensor to be equal size, but got [3, 256, 341] at entry 0報上述類似錯誤,標注mask圖片和真實圖片以及網絡輸出的維度不對應,網絡輸出一般為(batch, class, width ,height)
RuntimeError: shape '[2, 2]' is invalid for input of size 202報上述類似錯誤,cityscape_info.json 文件有誤 或者 mask圖片像素值有誤
測試:
保存預測mask
#!/usr/bin/python # -*- encoding: utf-8 -*-import logging import math import os import os.path as osp import time from PIL import Image import matplotlib.pyplot as plot from pathlib import Path import torchvision.transforms as transformsimport numpy as np import torch import torch.distributed as dist import torch.nn as nn import torch.nn.functional as F from cityscapes import CityScapes from logger import setup_logger from models.model_stages import BiSeNet from torch.utils.data import DataLoader from tqdm import tqdm from transform import *np.set_printoptions(threshold = 1e9999)to_tensor = transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.485, 0.456, 0.406), (0.229, 0.224, 0.225)),])class MscEvalV0(object):def __init__(self, readpath, save_path, scale=0.5, ignore_label=255):self.ignore_label = ignore_labelself.scale = scaleself.readpath = readpathself.save_path = save_pathdef __call__(self, net, n_classes):# evaluatehist = torch.zeros(n_classes, n_classes).cuda().detach()for i, imagepath in enumerate(self.readpath.iterdir()):imgs = Image.open(imagepath).convert('RGB') imgs = to_tensor(imgs)imgs = imgs[None,:]imgnames = imagepath.nameimgs = imgs.cuda()N, C, H, W = imgs.size()new_hw = [int(H * self.scale), int(W * self.scale)]imgs = F.interpolate(imgs, new_hw, mode='bilinear', align_corners=True)logits = net(imgs)[0]logits = F.interpolate(logits, size=(H, W), mode='bilinear', align_corners=True)probs = torch.softmax(logits, dim=1)preds = torch.argmax(probs, dim=1)preds = preds.cpu().numpy()preds[preds>0] = 255img = np.array(preds[0])predgt = Image.fromarray(np.uint8(img)).convert('L')predgt.save(f'{self.save_path}/{imgnames}')print('\r', i, end='', flush=True)def evaluatev0(respth='./pretrained', backbone='CatNetSmall', test_path=None, save_path=None, scale=0.75, use_boundary_2=False, use_boundary_4=False, use_boundary_8=False, use_boundary_16=False, use_conv_last=False):print('scale', scale)print('use_boundary_2', use_boundary_2)print('use_boundary_4', use_boundary_4)print('use_boundary_8', use_boundary_8)print('use_boundary_16', use_boundary_16)print("backbone:", backbone)# datasetbatchsize = 5n_workers = 2n_classes = 2# modelnet = BiSeNet(backbone=backbone, n_classes=n_classes,use_boundary_2=use_boundary_2, use_boundary_4=use_boundary_4,use_boundary_8=use_boundary_8, use_boundary_16=use_boundary_16,use_conv_last=use_conv_last)net.load_state_dict(torch.load(respth))net.cuda()net.eval()with torch.no_grad():single_scale = MscEvalV0(readpath=test_path, save_path=save_path, scale=scale)single_scale(net, n_classes)if __name__ == "__main__":log_dir = 'evaluation_logs/origin/'if not os.path.exists(log_dir):os.makedirs(log_dir)setup_logger(log_dir)test_path = Path('data/leftImg8bit/test/qdu')model_path = './checkpoints/train_STDC2-Seg/pths/model_maxmIOU75.pth'# STDC1-Seg50 mIoU 0.7222evaluatev0(model_path, test_path=test_path, save_path=log_dir, backbone='STDCNet1446', scale=0.75, use_boundary_8=True)從mask黑白圖生成外圍輪廓json
import cv2 import json import tqdm import random import numpy as np from pathlib import PathPAD = 10 mask_root = Path('evaluation_logs/origin') pad_mask = Path('evaluation_logs/padding') image_root = Path('data/leftImg8bit/test/qdu') json_root = Path('evaluation_logs/jsons')# 填充mask,使其有黑邊,方便查找輪廓 def padMask():for mask_path in mask_root.iterdir():mask = cv2.imread(str(mask_path), cv2.IMREAD_GRAYSCALE)maskpad = np.pad(mask, PAD, 'constant')print(f'{mask.shape} --> {maskpad.shape}')pad_mask.mkdir(parents=True, exist_ok=True)save_path = pad_mask / mask_path.namecv2.imwrite(str(save_path), maskpad)# 獲取輪廓,生成json def generateJson():for mask_path in tqdm.tqdm(pad_mask.iterdir()):name = mask_path.namelabel = "person"item = dict(name = label, points = None)mask = cv2.imread(str(mask_path), cv2.IMREAD_GRAYSCALE)contours, hierarchy = cv2.findContours(mask,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)# print(type(contours), len(contours))maxlen, outline = 0, []H, W = mask.shapefor contour in contours:# print(type(contour), len(contour), contour.shape)if len(contour) <= maxlen:continuemaxlen = len(contour)# 獲取相對原圖坐標點# print("process...")contour = contour[:, 0, :]contour -= PAD # 減去填充導致的位置便宜contour[contour < 0] = 0 # 小于0的位置設置為0contour[contour[:, 0] > W, 0] = W # 坐標超過右邊界的,設置為寬度contour[contour[:, 1] > H, 1] = H # 坐標超過下邊界的,設置為高度# 加入列表contour = contour.astype(np.float)outline = contour.tolist()# print(maxlen)item['points'] = outlineitem = [item]json_root.mkdir(parents=True, exist_ok=True)with open(json_root / name.replace('jpg', 'json'), 'w') as handle:json.dump(item, handle)# break# 獲取輪廓,生成json def vasualization():for mask_path in mask_root.iterdir():name = mask_path.namemask = cv2.imread(str(mask_path), cv2.IMREAD_GRAYSCALE)contours, hierarchy = cv2.findContours(mask,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)print(type(contours), len(contours))outlines = []H, W = mask.shapefor contour in contours:print(type(contour), len(contour), contour.shape)# 輪廓點少于20個,直接跳過舍棄if len(contour) < 20:continue# 獲取相對原圖坐標點print("process...")contour = contour[:, 0, :]contour -= PAD # 減去填充導致的位置便宜contour[contour < 0] = 0 # 小于0的位置設置為0contour[contour[:, 0] > W, 0] = W # 坐標超過右邊界的,設置為寬度contour[contour[:, 1] > H, 1] = H # 坐標超過下邊界的,設置為高度# 加入列表contour = contour.tolist()outlines.append(contour)print("outlines : ", len(outlines))imagepath = image_root / nameimage = cv2.imread(str(imagepath), cv2.IMREAD_COLOR)for otl in outlines:c1 = random.randint(0,255)c2 = random.randint(0,255)c3 = random.randint(0,255)for point in otl:cv2.circle(image, point, 2, (c1,c2,c3))cv2.namedWindow('show', 0)cv2.imshow('show', image)cv2.waitKey(0)breakif __name__ == '__main__':padMask()generateJson()可視化分割mask,即:mask+原圖
import cv2 import numpy as np from tqdm import tqdm from PIL import Image from pathlib import Pathimage_root = Path('data/leftImg8bit/test/02/images') mask_root = Path('evaluation_logs/origin') save_root = Path('evaluation_logs/visual')for mask in tqdm(mask_root.iterdir()):name = mask.nameimagepath = image_root / name# mask = Image.open(mask)# image = Image.open(imagepath)# print(mask.mode) # L# print(image.mode) # RGBmask = cv2.imread(str(mask), cv2.IMREAD_GRAYSCALE)image = cv2.imread(str(imagepath), cv2.IMREAD_COLOR)# print(mask.shape) # 1080 1920# print(image.shape) # 1080 1920 3image = image.astype(np.float64)image[mask > 100] = (image[mask > 100] * 0.6).astype(np.int64)image[mask > 100] += np.array([100,0,0], dtype=np.int64)save_root.mkdir(parents=True, exist_ok=True)sp = save_root / namecv2.imwrite(str(sp), image)可視化全景分割結果:
#!/usr/bin/python # -*- encoding: utf-8 -*-import logging import math import os import os.path as osp import time from PIL import Image import matplotlib.pyplot as plotimport numpy as np import torch import torch.distributed as dist import torch.nn as nn import torch.nn.functional as F from cityscapes import CityScapes from logger import setup_logger from models.model_stages import BiSeNet from torch.utils.data import DataLoader from tqdm import tqdm#ignore_label=255, #label_mapping = {-1: ignore_label, 0: ignore_label, # 1: ignore_label, 2: ignore_label, # 3: ignore_label, 4: ignore_label, # 5: ignore_label, 6: ignore_label, # 7: 0, 8: 1, 9: ignore_label, # 10: ignore_label, 11: 2, 12: 3, # 13: 4, 14: ignore_label, 15: ignore_label, # 16: ignore_label, 17: 5, 18: ignore_label, # 19: 6, 20: 7, 21: 8, 22: 9, 23: 10, 24: 11, # 25: 12, 26: 13, 27: 14, 28: 15, # 29: ignore_label, 30: ignore_label, # 31: 16, 32: 17, 33: 18} ignore_label=255, label_mapping = {-1: ignore_label, 0: 0,1: ignore_label, 2: ignore_label,3: ignore_label, 4: ignore_label,5: ignore_label, 6: ignore_label,7: ignore_label, 8: ignore_label, 9: ignore_label,10: ignore_label, 11: ignore_label, 12: ignore_label,13: ignore_label, 14: ignore_label, 15: ignore_label,16: ignore_label, 17: ignore_label, 18: ignore_label,19: ignore_label, 20: ignore_label, 21: ignore_label, 22: ignore_label, 23: ignore_label, 24: 1,25: ignore_label, 26: ignore_label, 27: ignore_label, 28: ignore_label, 29: ignore_label, 30: ignore_label,31: ignore_label, 32: ignore_label, 33: ignore_label}def convert_label(label, inverse=False):temp = label.copy()if inverse:for v, k in label_mapping.items():label[temp == k] = velse:for k, v in label_mapping.items():label[temp == k] = vreturn labeldef get_palette(n):palette = [0] * (n * 3)for j in range(0, n):lab = jpalette[j * 3 + 0] = 0palette[j * 3 + 1] = 0palette[j * 3 + 2] = 0i = 0while lab:palette[j * 3 + 0] |= (((lab >> 0) & 1) << (7 - i))palette[j * 3 + 1] |= (((lab >> 1) & 1) << (7 - i))palette[j * 3 + 2] |= (((lab >> 2) & 1) << (7 - i))i += 1lab >>= 3return palettedef save_pred(preds, sv_path, name):palette = get_palette(256)preds = np.asarray(np.argmax(preds.cpu(), axis=1), dtype=np.uint8)for i in range(preds.shape[0]):pred = convert_label(preds[i], inverse=True)save_img = Image.fromarray(pred)save_img.putpalette(palette)save_img.save(os.path.join(sv_path, f'{name[i]}.png'))class MscEvalV0(object):def __init__(self, scale=0.5, ignore_label=255):self.ignore_label = ignore_labelself.scale = scaledef __call__(self, net, dl, n_classes):# evaluatehist = torch.zeros(n_classes, n_classes).cuda().detach()if dist.is_initialized() and dist.get_rank() != 0:diter = enumerate(dl)else:diter = enumerate(tqdm(dl))for i, (imgs, label, imgnames) in diter:# 跑 1500 張圖片if i == 1500:breakN, _, H, W = label.shapelabel = label.squeeze(1).cuda()size = label.size()[-2:]imgs = imgs.cuda()N, C, H, W = imgs.size()new_hw = [int(H * self.scale), int(W * self.scale)]imgs = F.interpolate(imgs, new_hw, mode='bilinear', align_corners=True)logits = net(imgs)[0]logits = F.interpolate(logits, size=size, mode='bilinear', align_corners=True)# print(imgnames)save_pred(logits, './evaluation_logs/origin/', imgnames)probs = torch.softmax(logits, dim=1)preds = torch.argmax(probs, dim=1)keep = label != self.ignore_labelhist += torch.bincount(label[keep] * n_classes + preds[keep],minlength=n_classes ** 2).view(n_classes, n_classes).float()if dist.is_initialized():dist.all_reduce(hist, dist.ReduceOp.SUM)ious = hist.diag() / (hist.sum(dim=0) + hist.sum(dim=1) - hist.diag())miou = ious.mean()return miou.item()def evaluatev0(respth='./pretrained', dspth='./data', backbone='CatNetSmall', scale=0.75, use_boundary_2=False, use_boundary_4=False, use_boundary_8=False, use_boundary_16=False, use_conv_last=False):print('scale', scale)print('use_boundary_2', use_boundary_2)print('use_boundary_4', use_boundary_4)print('use_boundary_8', use_boundary_8)print('use_boundary_16', use_boundary_16)# datasetbatchsize = 5n_workers = 2dsval = CityScapes(dspth, mode='val')dl = DataLoader(dsval,batch_size=batchsize,shuffle=False,num_workers=n_workers,drop_last=False)n_classes = 2print("backbone:", backbone)net = BiSeNet(backbone=backbone, n_classes=n_classes,use_boundary_2=use_boundary_2, use_boundary_4=use_boundary_4,use_boundary_8=use_boundary_8, use_boundary_16=use_boundary_16,use_conv_last=use_conv_last)net.load_state_dict(torch.load(respth))net.cuda()net.eval()with torch.no_grad():single_scale = MscEvalV0(scale=scale)mIOU = single_scale(net, dl, n_classes)logger = logging.getLogger()logger.info('mIOU is: %s\n', mIOU)if __name__ == "__main__":log_dir = 'evaluation_logs/origin/'if not os.path.exists(log_dir):os.makedirs(log_dir)setup_logger(log_dir)# STDC1-Seg50 mIoU 0.7222evaluatev0('./checkpoints/train_STDC2-Seg/pths/model_maxmIOU75.pth', dspth='./data', backbone='STDCNet1446', scale=0.75, use_boundary_2=False, use_boundary_4=False, use_boundary_8=True, use_boundary_16=False)# STDC1-Seg75 mIoU 0.7450# evaluatev0('./checkpoints/STDC1-Seg/model_maxmIOU75.pth', dspth='./data', backbone='STDCNet813', scale=0.75,# use_boundary_2=False, use_boundary_4=False, use_boundary_8=True, use_boundary_16=False)# STDC2-Seg50 mIoU 0.7424# evaluatev0('./checkpoints/STDC2-Seg/model_maxmIOU50.pth', dspth='./data', backbone='STDCNet1446', scale=0.5,# use_boundary_2=False, use_boundary_4=False, use_boundary_8=True, use_boundary_16=False)# # STDC2-Seg75 mIoU 0.7704 # imagepath = './data' # checkpoints_path = './checkpoints/train_STDC2-Seg/pths/model_maxmIOU75.pth' # #checkpoints_path = './checkpoints/STDC2-Seg/model_maxmIOU50.pth' # evaluatev0(respth=checkpoints_path, dspth=imagepath, backbone='STDCNet1446', # scale=0.75, use_boundary_2=False, use_boundary_4=False, use_boundary_8=True, use_boundary_16=False)reference:
1、cityscapes數據集 - learningcaiji - 博客園 (cnblogs.com)
2、圖像語意分割Cityscapes訓練數據集使用方法分享 - 知乎 (zhihu.com)
3、?Cityscapes數據集的深度完整解析_MVandCV的博客-CSDN博客
總結
以上是生活随笔為你收集整理的Cityscapse 数据集使用 + 训练 STDC踩坑的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ubuntu 更换系统软件源 和 pip
- 下一篇: 使用PIL库将一张小图贴到大图的指定位置