|
논문 내용
19번째 클래스 void =무시하는 클래스들
20번째 클래스 생성==>fish eye 배경 여백
논문 코드
무시=19
배경=20
ignore index=19
num_classes=21
수정 전 내 코드
ignore index=12
bkg_label=12
class_num = 13
num_classes=13
내 코드에서 설정
논문과 같이 배경을 따로 설정해보기.
ignore index=12
bkg_label=13으로 설정할것
borderValue=13
class_num = 14
num_classes=14
다시 설정
ignore index=12
bkg_label=12
borderValue=12
class_num = 13
num_classes=13
1 클래스변경 : 기존 클래스 + void class+ bkg class
논문과 같이 배경을 따로 설정.
ignore index=12
bkg_label=13으로 설정
borderValue=13
class_num = 14
num_classes=14
CKPT_DIR = "model_swift_re_set1"
가중치 변경
#논문그대로 옮겨오기
class_weights = torch.tensor([
2.7114885,6.237076,3.582358,8.316548, 8.129169, 8.6979065
, 8.497886
, 4.312109
, 6.91469
, 8.135018
, 8.741297
, 5.983605 ,0.
, 3.6 ]).cuda()
2. 논문 파라미터 범위 설정
CKPT_DIR = "model_swift_num_classes_14_new_ext_range" class DefaultConfig(object): data_dir = './' train_img_dir = 'D:/jyn/samsung/open/train_source_image/' train_annot_dir = 'D:/jyn/samsung/open/train_source_gt/' valid_img_dir='D:/jyn/samsung/open/val_source_image/' valid_annot_dir='D:/jyn/samsung/open/val_source_gt/' #train_with_ckpt = False train_with_ckpt = False logdir = "checkpoints/"+CKPT_DIR ckpt_name = "checkpoints/"+CKPT_DIR+"/ckpt" model_path = "checkpoints/"+CKPT_DIR+"/Model.pth" ckpt_path = "./checkpoints/model_swift_real/ckpt_84.pth" batch_size = 4 val_batch_size = 4 dataloader_num_worker = 0 #class_num = 13 class_num = 14 learning_rate = 4e-4 max_epoch = 200 crop = True crop_rate = 0.8 rand_ext = True #범위 -a ~ a #ext_range = [0, 0, 0, 0.7, 0, 0] ext_range = [25, 0, 0, 0.5, 0.1, 0.4] #파라미터 직접 값 설정 ext_param = [0, 0, 0, 0, 0, 0] rand_f = True f = 350 f_range = [200, 400] fish_size = [640, 640] #fish_size = [224, 224] mask_radius = 100 |
모델 경로
model_swift_num_classes_14_new_ext_range
3.val image에도 train과 같은 random aug 적용
4. 클래스 재설정 + val aug 적용 +그래프 설정 +ignore index 무시
클래스 다시 설정 총 0~11번의 클래스+12번 배경 클래스
ignore index=12
bkg_label=12
borderValue=12
class_num = 13
num_classes=13
손실함수 가중치 다시 설정해서 훈련시 ignore class 제거
class_weights = torch.tensor([
2.7114885,6.237076,3.582358,8.316548, 8.129169, 8.6979065
, 8.497886
, 4.312109
, 6.91469
, 8.135018
, 8.741297
, 5.983605
, 3.6 ]).cuda()
+ignore index설정 없애기
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | def val(model, dataloader, ignore_index=12, is_print=False): # 현재 시간 기록 (시작 시간) start_time = time.time() # 모델을 사용 가능한 디바이스로 이동 (CPU 또는 GPU) model.to(MyDevice) # 모델을 평가 (evaluation) 모드로 설정 model.eval() # 클래스 수만큼의 0으로 초기화된 배열을 생성 (평균 정밀도, 평균 재현율, 평균 IoU 및 클래스별 정밀도, 재현율, IoU를 저장할 배열들) # 각 클래스에 대한 정밀도를 저장하는 배열 precision_list = np.zeros(Config.class_num, dtype=float) #각 클래스에 대한 재현율을 저장하는 배열 recall_list = np.zeros(Config.class_num, dtype=float) #각 클래스에 대한 IoU(Intersection over Union)를 저장하는 배열 iou_list = np.zeros(Config.class_num, dtype=float) # 클래스별로 픽셀 수 및 TP, FP, FN 수를 저장할 배열들 #TP(Ture Positive), FP(False Positive), FN(False Negative) #클래스별 OR 연산을 수행한 픽셀 수 저장(OR 연산은 예측값과 실제 어노테이션 중 하나라도 픽셀이 존재하는 경우) pix_num_or = np.zeros(Config.class_num, dtype=float) #각 클래스에 대한 레이블 픽셀 중에서 어떤 예측값과 겹치는 픽셀 수를 저장 #AND 연산은 예측값과 실제 어노테이션 양쪽에 모두 픽셀이 존재하는 경우 pix_num_and = np.zeros(Config.class_num, dtype=float) #각 클래스에 대한 True Positives와 False Positives의 합계를 저장 pix_num_TPFP = np.zeros(Config.class_num, dtype=float) # True Positives와 False Negatives의 합계를 저장 pix_num_TPFN = np.zeros(Config.class_num, dtype=float) # 검증 데이터 배치 수 계산 (학습 데이터의 일부만 사용하도록 설정한 경우를 고려) val_iter_num = math.ceil(500 / Config.val_batch_size) # 모델을 평가 모드로 설정하고 역전파 비활성화 (no_grad) with torch.no_grad(): for i, (image, annot) in enumerate(dataloader): # 현재 시간 기록 (배치 처리 시작 시간) tic = time.time() # 이미지와 어노테이션을 지정한 디바이스로 이동 input = image.to(MyDevice) target = annot.to(MyDevice, dtype=torch.long) # 모델에 이미지를 전달하고 예측을 수행 predict = torch.argmax(model(input), 1, keepdim=True) # 예측값을 클래스별 one-hot 형식으로 변환 predict_onehot = torch.zeros(predict.size(0), Config.class_num, predict.size(2), predict.size(3)).cuda() predict_onehot = predict_onehot.scatter(1, predict, 1).float() # 어노테이션을 클래스별 one-hot 형식으로 변환 target.unsqueeze_(1) target_onehot = torch.zeros(target.size(0), Config.class_num, target.size(2), target.size(3)).cuda() target_onehot = target_onehot.scatter(1, target, 1).float() # 검정 레이블을 무시할 경우 해당 레이블의 마스크 생성 #mask = (1 - target_onehot[:, ignore_index, :, :]).view(target.size(0), 1, target.size(2), target.size(3)) mask = torch.ones(target.size(0), 1, target.size(2), target.size(3), device=MyDevice) predict_onehot *= mask target_onehot *= mask # TP, FP, FN에 대한 면적 계산 area_and = predict_onehot * target_onehot area_or = predict_onehot + target_onehot - area_and # 클래스별 TPFP, TPFN, AND, OR의 픽셀 수 누적 pix_num_TPFP += torch.sum(predict_onehot, dim=(0, 2, 3)).cpu().numpy() pix_num_TPFN += torch.sum(target_onehot, dim=(0, 2, 3)).cpu().numpy() pix_num_and += torch.sum(area_and, dim=(0, 2, 3)).cpu().numpy() pix_num_or += torch.sum(area_or, dim=(0, 2, 3)).cpu().numpy() # 현재 배치 처리 시간 출력 toc = time.time() print(f"validation step {i}/{val_iter_num-1}, {toc-tic} sec/step ...") # 정밀도, 재현율, IoU 계산 (0으로 나누는 경우를 방지하기 위해 1e-5를 더함) precision_list = pix_num_and / (pix_num_TPFP + 1e-5) recall_list = pix_num_and / (pix_num_TPFN + 1e-5) iou_list = pix_num_and / (pix_num_or + 1e-5) # 무시할 레이블(클래스)에 대한 값은 0으로 설정 # precision_list[ignore_index] = 0 # recall_list[ignore_index] = 0 # iou_list[ignore_index] = 0 # 평균 정밀도, 평균 재현율, 평균 IoU 계산 (무시할 레이블을 제외) # mean_precision = np.sum(precision_list) / (Config.class_num - 1) # mean_recall = np.sum(recall_list) / (Config.class_num - 1) # mean_iou = np.sum(iou_list) / (Config.class_num - 1) # 전체 클래스에 대한 평균 정밀도, 평균 재현율, 평균 IoU 계산 mean_precision = np.sum(precision_list) / Config.class_num mean_recall = np.sum(recall_list) / Config.class_num mean_iou = np.sum(iou_list) / Config.class_num # 19개 클래스에 대한 평균 정밀도, 평균 재현율, 평균 IoU 계산 (배경 레이블을 제외) m_precision_19 = np.sum(precision_list[0:-1]) / (Config.class_num - 2) m_recall_19 = np.sum(recall_list[0:-1]) / (Config.class_num - 2) m_iou_19 = np.sum(iou_list[0:-1]) / (Config.class_num - 2) if is_print: print("==================RESULT====================") print("Mean precision:", mean_precision, '; Mean precision 19:', m_precision_19) print("Mean recall:", mean_recall, '; Mean recall 19:', m_recall_19) print("Mean IoU:", mean_iou, '; Mean IoU 19:', m_iou_19) print("Class-specific precision:") print(precision_list) print("Class-specific recall:") print(recall_list) print("Class-specific IoU:") print(iou_list) print(time.time()-start_time, "sec/validation") print("===================END======================") return mean_precision, mean_recall, mean_iou, m_precision_19, m_recall_19, m_iou_19 | cs |
+그래프 설정
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 | train_transform = MyTransform(Config.f, Config.fish_size) train_transform.set_ext_params(Config.ext_param) train_transform.set_ext_param_range(Config.ext_range) if Config.rand_f: train_transform.rand_f(f_range=Config.f_range) if Config.rand_ext: train_transform.rand_ext_params() train_transform.set_bkg(bkg_label=12, bkg_color=[0, 0, 0]) train_transform.set_crop(rand=Config.crop, rate=Config.crop_rate) # train_transform = RandOneTransform(Config.f, Config.fish_size) # train_transform.set_ext_params(Config.ext_param) # train_transform.set_ext_param_range(Config.ext_range) # train_transform.set_f_range(Config.f_range) # train_transform.set_bkg(bkg_label=20, bkg_color=[0, 0, 0]) # train_transform.set_crop(rand=Config.crop, rate=Config.crop_rate) train_set = CityScape(Config.train_img_dir, Config.train_annot_dir, transform=train_transform) train_loader = DataLoader(train_set, batch_size=Config.batch_size, shuffle=True) # # 가져온 이미지와 주석 데이터를 출력합니다. # print("Sample Image Shape:", sample_image.shape) # 이미지의 모양을 출력합니다. # print("Sample Annotation Shape:", sample_annotation.shape) # 주석 데이터의 모양을 출력합니다. validation_set = CityScape(Config.valid_img_dir, Config.valid_annot_dir,transform=train_transform) validation_loader = DataLoader( validation_set, batch_size=Config.val_batch_size, shuffle=False) # for epoch in tqdm(range(50)): # 에폭 # train_set = CityScape(Config.train_img_dir, # Config.train_annot_dir, transform=train_transform) # # validation_set = CityScape(Config.valid_img_dir, Config.valid_annot_dir) # # train_set에서 첫 번째 항목을 가져옵니다. # model = ERFPSPNet(shapeHW=[640, 640], num_classes=13) resnet = resnet18(pretrained=True) model = SwiftNet(resnet, num_classes=13) model.to(MyDevice) # class_weights = torch.tensor([8.6979065, 8.497886 , 8.741297 , 5.983605 , 8.662319 , 8.681756 , # 8.683093 , 8.763641 , 8.576978 , 2.7114885, # 6.237076 , 3.582358 , # 8.439253 , 8.316548 , 8.129169 , 4.312109 , 8.170293 , 6.91469 , # 8.135018 , 0. ,3.6]).cuda() #논문그대로 옮겨오기 class_weights = torch.tensor([ 2.7114885,6.237076,3.582358,8.316548, 8.129169, 8.6979065 , 8.497886 , 4.312109 , 6.91469 , 8.135018 , 8.741297 , 5.983605 , 3.6 ]).cuda() # # class_weights = torch.tensor([ # # 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1. ]).cuda() # # criterion = CrossEntropyLoss2d(weight=class_weights) criterion = FocalLoss2d(weight=class_weights) #criterion = smp.losses.FocalLoss(mode='multiclass') # criterion = CrossEntropyLoss2d() # lr = Config.learning_rate # Pretrained SwiftNet optimizer optimizer = torch.optim.Adam([{'params':model.random_init_params()}, {'params':model.fine_tune_params(), 'lr':1e-4, 'weight_decay':2.5e-5}], lr=4e-4, weight_decay=1e-4) # ERFNetPSP optimizer # optimizer = torch.optim.Adam(model.parameters(), # lr=1e-3, # betas=(0.9, 0.999), # eps=1e-08, # weight_decay=2e-4) # scheduler = torch.optim.lr_scheduler.StepLR( # optimizer, step_size=90, gamma=0.1) scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, 200, 1e-6) start_epoch = 0 step_per_epoch = math.ceil(2975 / Config.batch_size) writer = SummaryWriter(Config.logdir) # writer.add_graph(model) if Config.train_with_ckpt: checkpoint = torch.load(Config.ckpt_path) print("Load",Config.ckpt_path) model.load_state_dict(checkpoint['model_state_dict']) optimizer.load_state_dict(checkpoint['optimizer_state_dict']) start_epoch = checkpoint['epoch']+1 val(model, validation_loader, is_print=True) # loss = checkpoint['loss'] model.train() start_time = None # Lists to store training loss and accuracy train_losses = [] train_accuracies = [] # Lists to store validation loss and accuracy val_losses = [] val_accuracies = [] for epoch in tqdm(range(start_epoch, Config.max_epoch)): train_loss = 0.0 correct = 0 total = 0 # Validation loop for i, (image, annot) in enumerate(train_loader): if start_time is None: start_time = time.time() input = image.to(MyDevice) target = annot.to(MyDevice, dtype=torch.long) model.train() # 옵티마이저의 그래디언트 초기화 optimizer.zero_grad() # 모델을 사용하여 입력 이미지에 대한 예측 점수(확률) 계산 score = model(input) # predict = torch.argmax(score, 1) #print(target) # 손실 함수를 사용하여 예측과 실제 레이블 간의 손실 계산 loss = criterion(score, target) # 역전파를 통해 그래디언트 계산 loss.backward() # 옵티마이저를 사용하여 모델 파라미터 업데이트 optimizer.step() # 전체 전역 스텝 계산 global_step = step_per_epoch * epoch + i if i%20 ==0: # 20번째 반복마다 이미지와 예측 결과를 TensorBoard에 추가 predict = torch.argmax(score, 1).to(MyCPU, dtype=torch.uint8) writer.add_image("Images/original_image", image[0], global_step=global_step) writer.add_image("Images/segmentation_output", predict[0].view(1, 640, 640)*10, global_step=global_step) writer.add_image("Images/segmentation_ground_truth", annot[0].view(1, 640, 640)*10, global_step=global_step) if i % 20 == 0 and global_step > 0: # 20번째 반복마다 손실을 TensorBoard에 추가 writer.add_scalar("Monitor/Loss", loss.item(), global_step=global_step) #정확도 계산 train_loss += loss.item() predicted = torch.argmax(score, 1) correct += (predicted == target).sum().item() total += target.size(0) * target.size(1) * target.size(2) # 현재 스텝의 실행 시간 계산 time_elapsed = time.time() - start_time # 현재 스텝의 시작 시간 업데이트 start_time = time.time() #print(f"{epoch}/{Config.max_epoch-1} epoch, {i}/{step_per_epoch} step, loss:{loss.item()}, sec/step:" # f"{time_elapsed} , global step={global_step}") # 에폭마다 훈련 손실 및 정확도 저장 train_losses.append(train_loss / len(train_loader)) train_accuracy = correct / total train_accuracies.append(train_accuracy) # 스케줄러를 사용하여 학습률 스케줄링 scheduler.step() #if epoch >20: # 20번째 에폭 이후에 검증(val) 및 모델 저장 # 검증 데이터로 모델을 평가 mean_precision, mean_recall, mean_iou, m_precision_19, m_racall_19, m_iou_19 ,val_loss,val_accuracy = val( model, validation_loader, is_print=True) # TensorBoard에 평가 결과를 추가 writer.add_scalar("Monitor/precision20", mean_precision, global_step=epoch) writer.add_scalar("Monitor/recall20", mean_recall, global_step=epoch) writer.add_scalar("Monitor/mIOU20", mean_iou, global_step=epoch) writer.add_scalar("Monitor1/precision19", m_precision_19, global_step=epoch) writer.add_scalar("Monitor1/recall19", m_racall_19, global_step=epoch) writer.add_scalar("Monitor1/mIOU19", m_iou_19, global_step=epoch) print(epoch, '/', Config.max_epoch, ' loss:', loss.item()) torch.save({ 'epoch': epoch, 'model_state_dict': model.state_dict(), 'loss': loss.item(), 'optimizer_state_dict': optimizer.state_dict() }, Config.ckpt_name + "_" + str(epoch) + ".pth") print("model saved!") val_losses.append(val_loss) val_accuracies.append(val_accuracy) print(epoch, '/', Config.max_epoch, f"train loss: {train_loss / len(train_loader)}, train accuracy: {train_accuracy}, " f"Validation Loss: {val_loss}, Validation Accuracy: {val_accuracy}") # Plotting loss and accuracy curves in a single graph plt.figure(figsize=(10, 5)) plt.plot(range(0, len(train_losses) ), train_losses, label='Training Loss', color='blue') plt.plot(range(0, len(train_accuracies) ), train_accuracies, label='Training Accuracy', color='darkblue') plt.plot(range(0, len(val_losses) ), val_losses, label='Validation Loss', color='red', linestyle='dashed') plt.plot(range(0, len(val_accuracies) ), val_accuracies, label='Validation Accuracy', color='darkred', linestyle='dashed') plt.xlabel('Epoch') plt.ylabel('Value') plt.legend() plt.tight_layout() plt.show() val(model, validation_loader, is_print=True) torch.save({ 'epoch': epoch, 'model_state_dict': model.state_dict(), 'optimizer_state_dict': optimizer.state_dict(), 'loss': loss }, Config.model_path) print("Save model to disk!") writer.close() | cs |
model_swiftNet
훈련중
==================RESULT==================== Mean precision: 0.7123723000323345 ; Mean precision 19: 0.751138099508566 Mean recall: 0.6688001313288502 ; Mean recall 19: 0.6995850777079257 Mean IoU: 0.5747613244758253 ; Mean IoU 19: 0.5886006446825902 Class-specific precision: [0.95364915 0.44317527 0.82232164 0.71037604 0.52944253 0.66364927 0.79192836 0.89897969 0.97719996 0.24306326 0.30868544 0.92004848 0.99832081] Class-specific recall: [0.95485948 0.68641615 0.89105734 0.33109848 0.39106377 0.52166274 0.66455922 0.89545561 0.9682493 0.10601476 0.37715105 0.90784795 0.99896585] Class-specific IoU: [0.91251018 0.36855683 0.74719908 0.29171915 0.29019937 0.41258085 0.56577174 0.81358881 0.94685862 0.07970157 0.20445711 0.84146378 0.99729013] 90.36281943321228 sec/validation ===================END======================
112 / 200 train loss: 0.021930532898068535, train accuracy: 0.9809926508553156, Validation Loss: 0.0761587324942279, Validation Accuracy: 0.969408729127548
103 / 200 train loss: 0.022871513465904582, train accuracy: 0.9803017662695135, Validation Loss: 0.06834592089120649, Validation Accuracy: 0.9702221155780579
65 / 200 train loss: 0.0277750376995334, train accuracy: 0.977563080418186, Validation Loss: 0.06901520980983718, Validation Accuracy: 0.9685144671657054
27 / 200 train loss: 0.03608692034685438, train accuracy: 0.9735110036872578, Validation Loss: 0.06982199430593058, Validation Accuracy: 0.9668012548618562
25 / 200 train loss: 0.03492078692304523, train accuracy: 0.973886994715702, Validation Loss: 0.06714009183148544, Validation Accuracy: 0.9664275520553917
test data로 예측 결과
ep 103
위의 모델로 훈련데이터, 검증데이터 예측 결과
5. 새로운 데이터셋의 rle ->submission 변환 코드
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 | import os import torch from torch.utils import data from torchvision.transforms import ToTensor, Normalize import numpy as np import cv2 import albumentations as A from albumentations.pytorch import ToTensorV2 #데이터 증강을 위한 transform 파이프라인 정의 class CityScape(data.Dataset): def __init__(self, img_dir, annot_dir=None, transform=None,infer=False): self._transform = transform self._infer = infer self._imgs = sorted([os.path.join(img_dir, img) for img in os.listdir(img_dir) if img.endswith('.png')]) if annot_dir is not None: self._imgs_annot = sorted([os.path.join(annot_dir, img) for img in os.listdir(annot_dir) if img.endswith('.png')]) else: self._imgs_annot=None def __getitem__(self, index): image = cv2.imread(self._imgs[index]) if self._infer: image = image[:,:,(2,1,0)] #ori_img=image[:,:,(2,1,0)] ori_img=image image = (image * 255).astype(np.uint8) if self._transform: image = self._transform(image=image)['image'] image = ToTensor()(image) return image , ori_img annot = cv2.imread(self._imgs_annot[index], 0) annot[annot == 255] = 12 #배경을 픽셀값 12로 간주 image = image[:,:,(2,1,0)] if self._transform is not None: image, annot = self._transform(image, annot) return image, annot else: image = ToTensor()(image) annot = torch.from_numpy(annot) return image, annot def __len__(self): return len(self._imgs) test_img_dir="D:/jyn/samsung/open/test_image/" test_dataset = CityScape(test_img_dir, annot_dir=None, transform=None, infer=True) test_dataloader = DataLoader( test_dataset, batch_size=16, shuffle=False) resnet = resnet18(pretrained=True).to(torch.device('cuda')) model = SwiftNet(resnet, num_classes=13) model = model.to(torch.device('cuda')) checkpoint = torch.load("./checkpoints/model_swiftNet/ckpt_100.pth") model.load_state_dict(checkpoint['model_state_dict']) model.eval() device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') model.to(device) # RLE 인코딩 함수 def rle_encode(mask): pixels = mask.flatten() pixels = np.concatenate([[0], pixels, [0]]) runs = np.where(pixels[1:] != pixels[:-1])[0] + 1 runs[1::2] -= runs[::2] return ' '.join(str(x) for x in runs) with torch.no_grad(): model.eval() result = [] for images,ori_img in tqdm(test_dataloader): #images = images[:,:,(2,1,0)] # images=images.astype(np.uint8) # 8비트 부호 없는 정수형으로 변환 #image = (image * 255).astype(np.uint8) # [0, 1] 범위의 데이터를 [0, 255] 범위로 확장 #images = ToTensor()(images) images = images.float().to(device) ori_img=ori_img.to(device) outputs = model(images) outputs = torch.softmax(outputs, dim=1).cpu() outputs = torch.argmax(outputs, dim=1).numpy() # batch에 존재하는 각 이미지에 대해서 반복 for i, pred in enumerate(outputs): pred = pred.astype(np.uint8) pred = Image.fromarray(pred) # 이미지로 변환 pred = pred.resize((960, 540), Image.NEAREST) # 960 x 540 사이즈로 변환 pred = np.array(pred) # 다시 수치로 변환 # class 0 ~ 11에 해당하는 경우에 마스크 형성 / 12(배경)는 제외하고 진행 for class_id in range(12): class_mask = (pred == class_id).astype(np.uint8) if np.sum(class_mask) > 0: # 마스크가 존재하는 경우 encode mask_rle = rle_encode(class_mask) result.append(mask_rle) else: # 마스크가 존재하지 않는 경우 -1 result.append(-1) # plt.figure(figsize=(10,5)) # plt.subplot(1, 2, 1) # plt.imshow(ori_img[i].cpu()) # plt.title("Input Image") # plt.subplot(1, 2, 2) # plt.imshow(label2color(pred)) # plt.title("Predicted Mask") # plt.show() | cs |
위의 모델 예측 점수
|
첫댓글 1. 검증용 마스크이미지에서 차의 색상이 훈련데이터로 예측했을때 차의 색상과 같아야 하는게 아닌지?
2. 훈련에 사용한 어안변환을 이용하여 검증영상 10개 정도를 변환 후 저장하고 그걸로 예측해볼것, 훈련 및 검증용 정상 이미지처럼 잘되는지 확인 필요
3. 테스트결과에서 분할을 잘하는 클래스와 못하는 클래스를 수치로 보여줄수는 없는지? 도로영역이 잘 안되는거 같은데
4. 최대한 테스트 이미지와 유사하게 변환하려면 논문의 변환수식의 파라미터중에서 어떤걸 조정해야하는지 찾아낼것
5. 테스트이미지를 관찰해보면 도로가 가운데 나오고 차선들이 좌우 대칭적으로 보임, 차선들의 소실점(모이는점)이 항상 가운데 상단에 있음 이것을 고려해서 테스트 이미지와 유사하게 만들도록 파라미터를 조정-> 변환의 일부 파라미터는 고정해도 될것 같음, 결국 7개 파라미터중에 일부는 고정해서 최대한 테스트 이미지에 가깝게 만드는 변환 파라미터를 찾아낼것
6. 훈련영상을 어안변환한 이미지에서 배경의 면적을 줄일수는 없는지? 변환후 확대해서 배경부분을 최소화하도록 하면 좋지 않을까요?
7. 새로운 데이터셋의 rle ->submission 변환 코드 -> 이건 뭐하는건지
테스트영상의 특징(직관적 분석)
1. 카메라의 시점은 항상 도로상에 있어야함, 도로가 항상 가운데에 위치, 시점이 도로 밖에 있는 것 제외
2. 차선이 좌우 대칭적으로 보임
3. 가운데를 기준으로 위쪽 또는 아래쪽으로 갈수록 압축되는 변환임
4. 배경이 없음, 화면전체를 채우고 있음
지난번에 데이터셋을 분석하는 코드를 이용하여 훈련데이터, 어안변환영상, 테스트영상의 특성을 분류해볼것
훈련에 사용한 어안변환영상과 테스트영상의 특성이 얼마나 유사한지 정량적(수치적) 분석 필요