|
|
1) 훈련예제에서 사용한 deeplabv3 모델의 구조를 조사하고 설명하시오.
★ Atrous convloultion이란?
- Atrous에서 trous는 구멍(hole)을 의미함으로써, Atrous Convolution은 기존 Convolution과 다르게 필터 내부에 빈 공간을 둔 채 작동하게 된다.
- 위 그림에서 얼마나 빈 공간을 둘지 결정하는 파라미터값 r(rate의 약자)이 1인 경우, 기존 Convolution과 동일하고 r이 커질수록 빈 공간이 넓어지게 되는 것이다.
---> 이를 통해 convolution과 동일한 양의 파라미터와 계산량을 유지하면서도, field of view(한 픽셀이 볼 수 있는 영역)를 크게 넓힐 수 있다. 즉, 수용영역을 넓힐 수 있다. (receptive field를 넓힐 수 있다는 의미)
- 보통 Semantic Segmentation에서 높은 성능을 내기 위해서는 CNN의 마지막에 존재하는 한 픽셀이 입력값에서 어느 크기의 영역에서 커버할 수 있는지를 결정하는 receptive field 크기가 중요하게 작용한다.
---> 즉, 여러 convolution과 pooling 과정에서 디테일한 정보가 줄어들고 특성이 점점 추상화되는 것을 어느정도 방지할 수 있다.
4. 업샘플링(upsampling)
- 4x 업샘플링을 통해 입력 이미지 크기로 복원한다.
- 최종 출력은 입력 이미지와 동일한 크기 픽셀 단위 예측(segmentation mask)이다.
5. 예측
- 기본 구조 사진에서 주황색 블록은 최종 예측 결과로, 각 픽셀마다 클래스가 지정된 세그멘테이션 맵이다.
2) 다음 2가지 방식으로 훈련결과를 실시간으로 시각화하시오.
- 원본은 건드리지 말고 새로운 소스파일 my_train.py 생성하여 원본을 복사하여 작업하고 시각화 코드를 적당한 위치에 추가할것
- 예제의 소스코드에서 훈련로스, 정확도, 검증로스 정확도를 추출하는 방법을 설명하라. -> 훈련과정에서 저장되는 로그 데이터가 어디에 저장되는지 어떻게 출력할수 있는지 소스코드 분석할 것
- 훈련로스, 정확도, 검증로스, 검증정확도 그래프 출력기능을 다음 2가지 방식으로 구현
- 교재 626페이지 코드를 이용하는 방법(matplotlib), 텐서보드를 사용하여 시각화하는 방법
- 매 에퍽마다 실시간으로 그래프를 업데이트하도록 할것 -> 훈련하는 동안 시간에 따라 로스의 변화를 확인가능하도록 할것(동영상으로 저장) -> 손실이 더이상 감소하지 않거나 감소하다가 다시 증가한다면 훈련중단해야함
그래프 예제 -> https://youtu.be/m2gqcl06UeM
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 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 | def evaluate(model, data_loader, criterion,device, num_classes, epoch, cut_train, metric_logger, args): model.eval() confmat = utils.ConfusionMatrix(num_classes) header = "Test:" header = f"Test: [{epoch}] cut : " + cut_train num_processed_samples = 0 with torch.inference_mode(): for image, target in metric_logger.log_every(data_loader, 30, header): image, target = image.to(device), target.to(device) with torch.cuda.amp.autocast(enabled=args.amp): output = model(image) loss = criterion(output, target) #metric_logger.add_meter('valid_loss', loss.item()) metric_logger.update(valid_loss=loss.item()) output = output["out"] confmat.update(target.flatten(), output.argmax(1).flatten()) # FIXME need to take into account that the datasets # could have been padded in distributed setup num_processed_samples += image.shape[0] # confamt에 정확도 값 저장 confmat.reduce_from_all_processes() num_processed_samples = utils.reduce_across_processes(num_processed_samples) if ( hasattr(data_loader.dataset, "__len__") and len(data_loader.dataset) != num_processed_samples and torch.distributed.get_rank() == 0 ): # See FIXME above warnings.warn( f"It looks like the dataset has {len(data_loader.dataset)} samples, but {num_processed_samples} " "samples were used for the validation, which might bias the results. " "Try adjusting the batch size and / or the world size. " "Setting the world size to 1 is always a safe bet." ) return confmat def train_one_epoch(model, criterion, optimizer, data_loader, lr_scheduler, device, epoch, print_freq, metric_logger, num_classes,scaler=None): model.train() metric_logger.add_meter("lr", utils.SmoothedValue(window_size=1, fmt="{value}")) header = f"Epoch: [{epoch}]" confmat = utils.ConfusionMatrix(num_classes) for image, target in metric_logger.log_every(data_loader, print_freq, header): image, target = image.to(device), target.to(device) with torch.cuda.amp.autocast(enabled=scaler is not None): #with torch.cpu.amp.autocast(enabled=scaler is not None): output = model(image) loss = criterion(output, target) optimizer.zero_grad() if scaler is not None: scaler.scale(loss).backward() scaler.step(optimizer) scaler.update() else: loss.backward() optimizer.step() lr_scheduler.step() pred = output["out"].argmax(1) # confmat에 정확도값 저장장 confmat.update(target.flatten(), pred.flatten()) # 이후 메트릭에 로스 값값 업데이트 metric_logger.update(train_loss=loss.item(), lr=optimizer.param_groups[0]["lr"]) return confmat def main(args): if args.backend.lower() != "pil" and not args.use_v2: # TODO: Support tensor backend in V1? raise ValueError("Use --use-v2 if you want to use the tv_tensor or tensor backend.") if args.use_v2 and args.dataset != "coco": raise ValueError("v2 is only support supported for coco dataset for now.") if args.output_dir: utils.mkdir(args.output_dir) utils.init_distributed_mode(args) print(args) device = torch.device(args.device) if args.use_deterministic_algorithms: torch.backends.cudnn.benchmark = False torch.use_deterministic_algorithms(True) else: torch.backends.cudnn.benchmark = True dataset, num_classes = get_dataset(args, is_train=True) dataset_test, _ = get_dataset(args, is_train=False) if args.distributed: train_sampler = torch.utils.data.distributed.DistributedSampler(dataset) test_sampler = torch.utils.data.distributed.DistributedSampler(dataset_test, shuffle=False) else: train_sampler = torch.utils.data.RandomSampler(dataset) test_sampler = torch.utils.data.SequentialSampler(dataset_test) data_loader = torch.utils.data.DataLoader( dataset, batch_size=args.batch_size, sampler=train_sampler, num_workers=args.workers, collate_fn=utils.collate_fn, drop_last=True, ) data_loader_test = torch.utils.data.DataLoader( dataset_test, batch_size=1, sampler=test_sampler, num_workers=args.workers, collate_fn=utils.collate_fn ) model = torchvision.models.get_model( args.model, weights=args.weights, weights_backbone=args.weights_backbone, num_classes=num_classes, aux_loss=args.aux_loss, ) # freeze backbone weights for param in model.backbone.parameters(): param.requires_grad = False for name, param in model.named_parameters(): print(name, param.requires_grad) model.to(device) if args.distributed: model = torch.nn.SyncBatchNorm.convert_sync_batchnorm(model) model_without_ddp = model if args.distributed: model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[args.gpu]) model_without_ddp = model.module params_to_optimize = [ {"params": [p for p in model_without_ddp.backbone.parameters() if p.requires_grad]}, {"params": [p for p in model_without_ddp.classifier.parameters() if p.requires_grad]}, ] if args.aux_loss: params = [p for p in model_without_ddp.aux_classifier.parameters() if p.requires_grad] params_to_optimize.append({"params": params, "lr": args.lr * 10}) optimizer = torch.optim.SGD(params_to_optimize, lr=args.lr, momentum=args.momentum, weight_decay=args.weight_decay) scaler = torch.cuda.amp.GradScaler() if args.amp else None iters_per_epoch = len(data_loader) main_lr_scheduler = PolynomialLR( optimizer, total_iters=iters_per_epoch * (args.epochs - args.lr_warmup_epochs), power=0.9 ) if args.lr_warmup_epochs > 0: warmup_iters = iters_per_epoch * args.lr_warmup_epochs args.lr_warmup_method = args.lr_warmup_method.lower() if args.lr_warmup_method == "linear": warmup_lr_scheduler = torch.optim.lr_scheduler.LinearLR( optimizer, start_factor=args.lr_warmup_decay, total_iters=warmup_iters ) elif args.lr_warmup_method == "constant": warmup_lr_scheduler = torch.optim.lr_scheduler.ConstantLR( optimizer, factor=args.lr_warmup_decay, total_iters=warmup_iters ) else: raise RuntimeError( f"Invalid warmup lr method '{args.lr_warmup_method}'. Only linear and constant are supported." ) lr_scheduler = torch.optim.lr_scheduler.SequentialLR( optimizer, schedulers=[warmup_lr_scheduler, main_lr_scheduler], milestones=[warmup_iters] ) else: lr_scheduler = main_lr_scheduler if args.resume: checkpoint = torch.load(args.resume, map_location="cpu", weights_only=True) model_without_ddp.load_state_dict(checkpoint["model"], strict=not args.test_only) if not args.test_only: optimizer.load_state_dict(checkpoint["optimizer"]) lr_scheduler.load_state_dict(checkpoint["lr_scheduler"]) args.start_epoch = checkpoint["epoch"] + 1 if args.amp: scaler.load_state_dict(checkpoint["scaler"]) if args.test_only: # We disable the cudnn benchmarking because it can noticeably affect the accuracy torch.backends.cudnn.benchmark = False torch.backends.cudnn.deterministic = True confmat = evaluate(model, data_loader_test, device=device, num_classes=num_classes) print(confmat) return plt.ion() # 인터랙브 모드 -> 실시간 그래프 업데이트 가능 print("Start training") start_time = time.time() metric_logger = utils.MetricLogger(" ") x_arr=[] rec_train=[[],[]] rec_valid=[[],[]] fig, (ax1, ax2) = plt.subplots(1,2, figsize=(16, 4)) for epoch in range(args.start_epoch, args.epochs): if args.distributed: train_sampler.set_epoch(epoch) train_comfmat=train_one_epoch(model, criterion, optimizer, data_loader, lr_scheduler, device, epoch, args.print_freq, metric_logger, num_classes=num_classes,scaler=None) confmat = evaluate(model, data_loader_test,criterion, device=device, num_classes=num_classes, epoch=epoch, cut_train='V',metric_logger=metric_logger, args=args) print(confmat) checkpoint = { "model": model_without_ddp.state_dict(), "optimizer": optimizer.state_dict(), "lr_scheduler": lr_scheduler.state_dict(), "epoch": epoch, "args": args, } if args.amp: checkpoint["scaler"] = scaler.state_dict() # 훈련정확도 t_acc,_,_=train_comfmat.compute() # 검증 정확도 v_acc, __, __ = confmat.compute() rec_train[0].append(metric_logger.meters['train_loss'].avg) rec_train[1].append(t_acc.item()) rec_valid[0].append(metric_logger.meters['valid_loss'].avg) rec_valid[1].append(v_acc.item()) print("train_loss : ", rec_train[0]) print("train_acc : ", rec_train[1]) print("valid_loss : ", rec_valid[0]) print("valid_acc : ", rec_valid[1]) utils.save_on_master(checkpoint, os.path.join(args.output_dir, f"model_{epoch}.pth")) utils.save_on_master(checkpoint, os.path.join(args.output_dir, "checkpoint.pth")) torch.save(model_without_ddp, os.path.join(args.output_dir, "model.pth")) # 현재 에폭까지 저장된 훈련, 검증 (손실, 정확도) 값 출력 print('epoch 학습 데이터 : ', str(epoch)) print(rec_train) print('epoch 검증 데이터 : ', str(epoch)) print(rec_valid) to_numpy_train = np.array(rec_train) to_numpy_valid = np.array(rec_valid) x_arr = np.arange(epoch + 1) # 실시간 그래프 업데이트 ax1.clear() # 손실 그래프 ax1.plot(x_arr, to_numpy_train[0], '-', label='Train loss', marker='o') ax1.plot(x_arr, to_numpy_valid[0], '--', label='Valid loss', marker='o') ax1.legend(fontsize=15) ax1.set_title('Loss') ax1.set_xlabel('Epoch', size=15) ax1.set_ylabel('Loss', size=15) ax2.clear() # 정확도 그래프 ax2.plot(x_arr, to_numpy_train[1], '-', label='Train acc', marker='o') ax2.plot(x_arr, to_numpy_valid[1], '--', label='Valid acc', marker='o') ax2.legend(fontsize=15) ax2.set_title('Accuracy') ax2.set_xlabel('Epoch', size=15) ax2.set_ylabel('Loss', size=15) # 그래프 갱신 plt.draw() # 그래프 업데이트 plt.pause(0.1) # 0.5초 대기 (실제 학습 환경 시뮬레이션) plt.savefig(f"graph{epoch}.png") plt.ioff() # 인터랙티브 모드 종료 # 그래프를 파일로 저장 (PNG 형식) plt.savefig("result_graph.png") plt.show() total_time = time.time() - start_time total_time_str = str(datetime.timedelta(seconds=int(total_time))) print(f"Training time {total_time_str}") | cs |
3) 최종 모델파일을 이용하여 모델의 성능을 테스트하는 파이토치 코드 my_test.py를 작성하시오.
테스트영상은 교내 건물실내영상 30장을 새로 찍어서 사용하라
파일을 개별적으로 오픈하지 말고 파이썬 os 패키지는 이용하여 폴더명을 알려주면 폴더에 저장된 영상파일을 모두 검색하여 불러와서 테스트하도록 작성할것
영상 1장의 추론(예측)시간을 측정하여 출력하시오.
https://learnopencv.com/pytorch-for-beginners-semantic-segmentation-using-torchvision/
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 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 | def evaluate(model, data_loader, criterion,device, num_classes, epoch, cut_train, metric_logger, args): model.eval() confmat = utils.ConfusionMatrix(num_classes) header = "Test:" header = f"Test: [{epoch}] cut : " + cut_train num_processed_samples = 0 with torch.inference_mode(): for image, target in metric_logger.log_every(data_loader, 30, header): image, target = image.to(device), target.to(device) with torch.cuda.amp.autocast(enabled=args.amp): output = model(image) loss = criterion(output, target) #metric_logger.add_meter('valid_loss', loss.item()) metric_logger.update(valid_loss=loss.item()) output = output["out"] confmat.update(target.flatten(), output.argmax(1).flatten()) # FIXME need to take into account that the datasets # could have been padded in distributed setup num_processed_samples += image.shape[0] # confamt에 정확도 값 저장 confmat.reduce_from_all_processes() num_processed_samples = utils.reduce_across_processes(num_processed_samples) if ( hasattr(data_loader.dataset, "__len__") and len(data_loader.dataset) != num_processed_samples and torch.distributed.get_rank() == 0 ): # See FIXME above warnings.warn( f"It looks like the dataset has {len(data_loader.dataset)} samples, but {num_processed_samples} " "samples were used for the validation, which might bias the results. " "Try adjusting the batch size and / or the world size. " "Setting the world size to 1 is always a safe bet." ) return confmat def train_one_epoch(model, criterion, optimizer, data_loader, lr_scheduler, device, epoch, print_freq, metric_logger, num_classes,scaler=None): model.train() metric_logger.add_meter("lr", utils.SmoothedValue(window_size=1, fmt="{value}")) header = f"Epoch: [{epoch}]" confmat = utils.ConfusionMatrix(num_classes) for image, target in metric_logger.log_every(data_loader, print_freq, header): image, target = image.to(device), target.to(device) with torch.cuda.amp.autocast(enabled=scaler is not None): #with torch.cpu.amp.autocast(enabled=scaler is not None): output = model(image) loss = criterion(output, target) optimizer.zero_grad() if scaler is not None: scaler.scale(loss).backward() scaler.step(optimizer) scaler.update() else: loss.backward() optimizer.step() lr_scheduler.step() pred = output["out"].argmax(1) # confmat에 정확도값 저장장 confmat.update(target.flatten(), pred.flatten()) # 이후 메트릭에 로스 값값 업데이트 metric_logger.update(train_loss=loss.item(), lr=optimizer.param_groups[0]["lr"]) return confmat def main(args): if args.backend.lower() != "pil" and not args.use_v2: # TODO: Support tensor backend in V1? raise ValueError("Use --use-v2 if you want to use the tv_tensor or tensor backend.") if args.use_v2 and args.dataset != "coco": raise ValueError("v2 is only support supported for coco dataset for now.") if args.output_dir: utils.mkdir(args.output_dir) utils.init_distributed_mode(args) print(args) device = torch.device(args.device) if args.use_deterministic_algorithms: torch.backends.cudnn.benchmark = False torch.use_deterministic_algorithms(True) else: torch.backends.cudnn.benchmark = True dataset, num_classes = get_dataset(args, is_train=True) dataset_test, _ = get_dataset(args, is_train=False) if args.distributed: train_sampler = torch.utils.data.distributed.DistributedSampler(dataset) test_sampler = torch.utils.data.distributed.DistributedSampler(dataset_test, shuffle=False) else: train_sampler = torch.utils.data.RandomSampler(dataset) test_sampler = torch.utils.data.SequentialSampler(dataset_test) data_loader = torch.utils.data.DataLoader( dataset, batch_size=args.batch_size, sampler=train_sampler, num_workers=args.workers, collate_fn=utils.collate_fn, drop_last=True, ) data_loader_test = torch.utils.data.DataLoader( dataset_test, batch_size=1, sampler=test_sampler, num_workers=args.workers, collate_fn=utils.collate_fn ) model = torchvision.models.get_model( args.model, weights=args.weights, weights_backbone=args.weights_backbone, num_classes=num_classes, aux_loss=args.aux_loss, ) # freeze backbone weights for param in model.backbone.parameters(): param.requires_grad = False for name, param in model.named_parameters(): print(name, param.requires_grad) model.to(device) if args.distributed: model = torch.nn.SyncBatchNorm.convert_sync_batchnorm(model) model_without_ddp = model if args.distributed: model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[args.gpu]) model_without_ddp = model.module params_to_optimize = [ {"params": [p for p in model_without_ddp.backbone.parameters() if p.requires_grad]}, {"params": [p for p in model_without_ddp.classifier.parameters() if p.requires_grad]}, ] if args.aux_loss: params = [p for p in model_without_ddp.aux_classifier.parameters() if p.requires_grad] params_to_optimize.append({"params": params, "lr": args.lr * 10}) optimizer = torch.optim.SGD(params_to_optimize, lr=args.lr, momentum=args.momentum, weight_decay=args.weight_decay) scaler = torch.cuda.amp.GradScaler() if args.amp else None iters_per_epoch = len(data_loader) main_lr_scheduler = PolynomialLR( optimizer, total_iters=iters_per_epoch * (args.epochs - args.lr_warmup_epochs), power=0.9 ) if args.lr_warmup_epochs > 0: warmup_iters = iters_per_epoch * args.lr_warmup_epochs args.lr_warmup_method = args.lr_warmup_method.lower() if args.lr_warmup_method == "linear": warmup_lr_scheduler = torch.optim.lr_scheduler.LinearLR( optimizer, start_factor=args.lr_warmup_decay, total_iters=warmup_iters ) elif args.lr_warmup_method == "constant": warmup_lr_scheduler = torch.optim.lr_scheduler.ConstantLR( optimizer, factor=args.lr_warmup_decay, total_iters=warmup_iters ) else: raise RuntimeError( f"Invalid warmup lr method '{args.lr_warmup_method}'. Only linear and constant are supported." ) lr_scheduler = torch.optim.lr_scheduler.SequentialLR( optimizer, schedulers=[warmup_lr_scheduler, main_lr_scheduler], milestones=[warmup_iters] ) else: lr_scheduler = main_lr_scheduler if args.resume: checkpoint = torch.load(args.resume, map_location="cpu", weights_only=True) model_without_ddp.load_state_dict(checkpoint["model"], strict=not args.test_only) if not args.test_only: optimizer.load_state_dict(checkpoint["optimizer"]) lr_scheduler.load_state_dict(checkpoint["lr_scheduler"]) args.start_epoch = checkpoint["epoch"] + 1 if args.amp: scaler.load_state_dict(checkpoint["scaler"]) if args.test_only: # We disable the cudnn benchmarking because it can noticeably affect the accuracy torch.backends.cudnn.benchmark = False torch.backends.cudnn.deterministic = True confmat = evaluate(model, data_loader_test, device=device, num_classes=num_classes) print(confmat) return plt.ion() # 인터랙브 모드 -> 실시간 그래프 업데이트 가능 print("Start training") start_time = time.time() metric_logger = utils.MetricLogger(" ") x_arr=[] rec_train=[[],[]] rec_valid=[[],[]] fig, (ax1, ax2) = plt.subplots(1,2, figsize=(16, 4)) for epoch in range(args.start_epoch, args.epochs): if args.distributed: train_sampler.set_epoch(epoch) train_comfmat=train_one_epoch(model, criterion, optimizer, data_loader, lr_scheduler, device, epoch, args.print_freq, metric_logger, num_classes=num_classes,scaler=None) confmat = evaluate(model, data_loader_test,criterion, device=device, num_classes=num_classes, epoch=epoch, cut_train='V',metric_logger=metric_logger, args=args) print(confmat) checkpoint = { "model": model_without_ddp.state_dict(), "optimizer": optimizer.state_dict(), "lr_scheduler": lr_scheduler.state_dict(), "epoch": epoch, "args": args, } if args.amp: checkpoint["scaler"] = scaler.state_dict() # 훈련정확도 t_acc,_,_=train_comfmat.compute() # 검증 정확도 v_acc, __, __ = confmat.compute() rec_train[0].append(metric_logger.meters['train_loss'].avg) rec_train[1].append(t_acc.item()) rec_valid[0].append(metric_logger.meters['valid_loss'].avg) rec_valid[1].append(v_acc.item()) print("train_loss : ", rec_train[0]) print("train_acc : ", rec_train[1]) print("valid_loss : ", rec_valid[0]) print("valid_acc : ", rec_valid[1]) utils.save_on_master(checkpoint, os.path.join(args.output_dir, f"model_{epoch}.pth")) utils.save_on_master(checkpoint, os.path.join(args.output_dir, "checkpoint.pth")) torch.save(model_without_ddp, os.path.join(args.output_dir, "model.pth")) # 현재 에폭까지 저장된 훈련, 검증 (손실, 정확도) 값 출력 print('epoch 학습 데이터 : ', str(epoch)) print(rec_train) print('epoch 검증 데이터 : ', str(epoch)) print(rec_valid) to_numpy_train = np.array(rec_train) to_numpy_valid = np.array(rec_valid) x_arr = np.arange(epoch + 1) # 실시간 그래프 업데이트 ax1.clear() # 손실 그래프 ax1.plot(x_arr, to_numpy_train[0], '-', label='Train loss', marker='o') ax1.plot(x_arr, to_numpy_valid[0], '--', label='Valid loss', marker='o') ax1.legend(fontsize=15) ax1.set_title('Loss') ax1.set_xlabel('Epoch', size=15) ax1.set_ylabel('Loss', size=15) ax2.clear() # 정확도 그래프 ax2.plot(x_arr, to_numpy_train[1], '-', label='Train acc', marker='o') ax2.plot(x_arr, to_numpy_valid[1], '--', label='Valid acc', marker='o') ax2.legend(fontsize=15) ax2.set_title('Accuracy') ax2.set_xlabel('Epoch', size=15) ax2.set_ylabel('Loss', size=15) # 그래프 갱신 plt.draw() # 그래프 업데이트 plt.pause(0.1) # 0.5초 대기 (실제 학습 환경 시뮬레이션) plt.savefig(f"graph{epoch}.png") plt.ioff() # 인터랙티브 모드 종료 # 그래프를 파일로 저장 (PNG 형식) plt.savefig("result_graph.png") plt.show() total_time = time.time() - start_time total_time_str = str(datetime.timedelta(seconds=int(total_time))) print(f"Training time {total_time_str}") | cs |
6) 훈련 코드에서 백본레이어의 가중치를 freeze하는 이유를 설명하라.
- 백본은 일반적으로 대규모 데이터셋에서 사전학습된 CNN(ResNet, VGG 등)을 의미한다. 훈련 코드에서 백본레이어의 가중치를 freeze하는 이유는 이미 백본이 좋은 특성을 학습했기 때문에 학습된 내용 그대로 활용하고자 할 때 가중치를 업데이트 하지 않고 freeze한다. 잘 학습되어 있어 굳이 학습시킬 필요가 없으므로 freeze 하는것이다. 만약 freeze 안하게 되면 너무 소량의 데이터로 fine-tuning을 할 경우 백본까지 같이 학습시키면 모델이 너무 쉽게 학습하여 과적합이 될 수 있다.
---> 백본은 그대로 두고, 마지막 분류기 또는 디코더 같은 고수준 레이어만 학습하는 것이 안정적임.
7) 백본모델을 resnet101 모델로 변경하여 훈련 및 테스트 해보고 resnet50과 성능을 비교하시오.
<훈련>
<추론>
<이번주까지 끝낼예정..>
9) 파이토치 예제 train.py를 분석하여 사용한 증식방법을 설명하고 dataloader객체에 저장된 증식결과영상를 출력하여 잘 동작하는지를 확인하라. 원본소스는 건드리지 말고 새로운 파일 my_train.py를 만들어서 적당한 테스트코드를 추가하여 실행할것
참고 : https://cafe.daum.net/SmartRobot/W2or/159
10) 건물 실내를 촬영한 동영상을 이용하여 테스트해보고 추론시간을 측정하고 초당 처리가능한 프레임수를 구하라.
모델은 resnet50, resnet101을 이용하여 비교해보라. 실시간 처리가 가능하려면 어떻게 해야하나?
11) Yolo 분할모델을 이용하여 객체검출을 수행하라.
- 최신 Yolo 분할모델을 이용하여 Cityscapes 데이터셋을 이용하여 영상 분할 과제를 수행하라.
https://www.cityscapes-dataset.com/
마스크영상(png, json) -> Yolo label형식에 맞게 변환할것
입력영상(png)
- Yolo 분할모델 훈련시 사용하는 레이블 파일의 형식을 조사하시오.
- Cityscapes 의 레이블파일을 Yolo 레이블 파일의 형식으로 변환하시오.
- 울트라리틱스에서 제공하는 소스를 설치하여 사용할것 https://www.ultralytics.com/ko
- 2번에서 사용한 그래프 기능을 Yolo 코드에 추가하여 그래프를 그려보시오.
- Yolo 백본의 가중치는 고정하고 전이학습을 수행하라.
- 도로주행 동영상을 이용하여 테스트를 수행하라.
https://www.youtube.com/watch?v=tkG57zXrr3w
- 참고자료 -> https://youtu.be/9e2x4dDRB-k?list=PLjWnfPvWhv9Isn-erhtk7LXUFrB2cZQsq
- cityscapes json to coco json -> https://github.com/TillBeemelmanns/cityscapes-to-coco-conversion
