MLOps Model Development (3) Hyper Parameter Tuning by Sweep
본 게시물은 W&B가 제공한 MLOps의 Model Development에 대한 내용을 기술한다.
1. Model Development
1.1 Target
- 모델 개선 시, 개선이 될 타겟을 선정해야함
- 앞선 prototype은 사물을 구분기 위한
Semantic Segmentation
를 수행
-
수행 결과 모델이 사람을 구분해내지 못함을 알 수 있음
☞ person IoU를 개선하는 목표 설정
2. Hyper Parameter
2.1 Hyper parameter optimization
-
모델의 목적에 맞게
Hyper Parameter
를 tuning하여 최적의 결과를 이끌어 내야함☞ 이번 포스팅에서는 사람을 구분해내기 위한 person iou의 성능 개선의 목적을 가짐
-
Hyper parameter의 공간 탐색하는 것은 너무 많은 경우의 수가 존재하기에 수동으로 할 수 없음
☞ 최적화를 오케스트레이션 하는 방법을 정의해야함
2.2 Sweep
- W&B의
sweep
은 하이퍼파라미터 최적화 도구 - 학습 스크립트와 탐색할 hyper parameter의 범위에 대한 정의가 있으면 대규모 튜닝을 실행할 수 있음
2.3 Train script
## This script comes from 04_refactor_baseline.ipynb
import argparse, os
import wandb
from pathlib import Path
import torchvision.models as tvmodels
import pandas as pd
from fastai.vision.all import *
from fastai.callback.wandb import WandbCallback
import params
from utils import get_predictions, create_iou_table, MIOU, BackgroundIOU, \
RoadIOU, TrafficLightIOU, TrafficSignIOU, PersonIOU, VehicleIOU, BicycleIOU, t_or_f
# defaults
default_config = SimpleNamespace(
framework="fastai",
img_size=180, #(180, 320) in 16:9 proportions,
batch_size=8, #8 keep small in Colab to be manageable
augment=True, # use data augmentation
epochs=10, # for brevity, increase for better results :)
lr=2e-3,
pretrained=True, # whether to use pretrained encoder,
mixed_precision=True, # use automatic mixed precision
arch="resnet18",
seed=42,
log_preds=False,
)
def parse_args():
"Overriding default argments"
argparser = argparse.ArgumentParser(description='Process hyper-parameters')
argparser.add_argument('--img_size', type=int, default=default_config.img_size, help='image size')
argparser.add_argument('--batch_size', type=int, default=default_config.batch_size, help='batch size')
argparser.add_argument('--epochs', type=int, default=default_config.epochs, help='number of training epochs')
argparser.add_argument('--lr', type=float, default=default_config.lr, help='learning rate')
argparser.add_argument('--arch', type=str, default=default_config.arch, help='timm backbone architecture')
argparser.add_argument('--augment', type=t_or_f, default=default_config.augment, help='Use image augmentation')
argparser.add_argument('--seed', type=int, default=default_config.seed, help='random seed')
argparser.add_argument('--log_preds', type=t_or_f, default=default_config.log_preds, help='log model predictions')
argparser.add_argument('--pretrained', type=t_or_f, default=default_config.pretrained, help='Use pretrained model')
argparser.add_argument('--mixed_precision', type=t_or_f, default=default_config.mixed_precision, help='use fp16')
args = argparser.parse_args()
vars(default_config).update(vars(args))
return
def download_data():
"Grab dataset from artifact"
processed_data_at = wandb.use_artifact(f'{params.PROCESSED_DATA_AT}:latest')
processed_dataset_dir = Path(processed_data_at.download())
return processed_dataset_dir
def label_func(fname):
return (fname.parent.parent/"labels")/f"{fname.stem}_mask.png"
def get_df(processed_dataset_dir, is_test=False):
df = pd.read_csv(processed_dataset_dir / 'data_split.csv')
if not is_test:
df = df[df.Stage != 'test'].reset_index(drop=True)
df['is_valid'] = df.Stage == 'valid'
else:
df = df[df.Stage == 'test'].reset_index(drop=True)
# assign paths
df["image_fname"] = [processed_dataset_dir/f'images/{f}' for f in df.File_Name.values]
df["label_fname"] = [label_func(f) for f in df.image_fname.values]
return df
def get_data(df, bs=4, img_size=180, augment=True):
block = DataBlock(blocks=(ImageBlock, MaskBlock(codes=params.BDD_CLASSES)),
get_x=ColReader("image_fname"),
get_y=ColReader("label_fname"),
splitter=ColSplitter(),
item_tfms=Resize((img_size, int(img_size * 16 / 9))),
batch_tfms=aug_transforms() if augment else None,
)
return block.dataloaders(df, bs=bs)
def log_predictions(learn):
"Log a Table with model predictions and metrics"
samples, outputs, predictions = get_predictions(learn)
table = create_iou_table(samples, outputs, predictions, params.BDD_CLASSES)
wandb.log({"pred_table":table})
def final_metrics(learn):
"Log latest metrics values"
scores = learn.validate()
metric_names = ['final_loss'] + [f'final_{x.name}' for x in learn.metrics]
final_results = {metric_names[i] : scores[i] for i in range(len(scores))}
for k,v in final_results.items():
wandb.summary[k] = v
def train(config):
set_seed(config.seed)
run = wandb.init(project=params.WANDB_PROJECT, entity=params.ENTITY, job_type="training", config=config)
# good practice to inject params using sweeps
config = wandb.config
# prepare data
processed_dataset_dir = download_data()
proc_df = get_df(processed_dataset_dir)
dls = get_data(proc_df, bs=config.batch_size, img_size=config.img_size, augment=config.augment)
metrics = [MIOU(), BackgroundIOU(), RoadIOU(), TrafficLightIOU(),
TrafficSignIOU(), PersonIOU(), VehicleIOU(), BicycleIOU()]
cbs = [WandbCallback(log_preds=False, log_model=True),
SaveModelCallback(fname=f'run-{wandb.run.id}-model', monitor='miou')]
cbs += ([MixedPrecision()] if config.mixed_precision else [])
learn = unet_learner(dls, arch=getattr(tvmodels, config.arch), pretrained=config.pretrained,
metrics=metrics)
learn.fit_one_cycle(config.epochs, config.lr, cbs=cbs)
if config.log_preds:
log_predictions(learn)
final_metrics(learn)
wandb.finish()
if __name__ == '__main__':
parse_args()
train(default_config)
- Jupyter로 수행한 baseline 코드를 py file 형태로 script 변환
- 파일 수행 시
parse_args
부분에 정의된 argument를 통해 다양한 파라미터로 학습 가능
2.4 Sweep file
# The program to run
program: train.py
# Method can be grid, random or bayes
method: random
# Project this sweep is part of
project: mlops-course-001
entity: av-team
# Metric to optimize
metric:
name: miou
goal: maximize
# Parameters space to search
parameters:
log_preds:
value: False
lr:
distribution: log_uniform_values
min: 1e-5
max: 1e-2
batch_size:
values: [4, 8]
img_size:
value: 240
arch:
values:
- 'resnet18'
- 'convnext_tiny'
- 'regnet_x_400mf'
- 'mobilenet_v3_small'
- Method can be grid, random or bayes: hyper parameter 공간의 탐색 방식 정의
- grid search, random, bayesian optimization
- Metric to optimize: 모니터링할 metric 설정
- Parameters space to search: hyper parameter의 공간 정의
- lr: distribution을 사용하여 연속적인 파라미터 샘플링 가능
- batch_size: 불연속 파라미터에 대한 값 지정
- arch: backbone 정의
3. W&B Example
3.1 Sweep space
- sweep.yaml 파일을 사용하여 wandb의 sweep 기능을 사용
- wandb 내 sweep space 생성
- overview에 sweep에 대한 config 내용 확인 가능
3.2 Agent
- agent 기능을 통해 각 hyper parameter 별로 학습 수행
- count를 주지 않으면 영원히 실행되기에 수동으로 종료해야함
- 각 수행 별로 학습의 결과를 확인할 수 있음
3.3 Interpretation
- 하나의 점은 각 실행을 나타냄
- parameter가 metric에 미치는 영향을 알 수 있음
- 평행 좌표 플롯으로 각 parameter 및 metric에 대한 결과를 확인할 수 있음
- 이번 포스팅의 목표인 person iou가 없기에 pannel에서 해당 metric 추가
- person iou가 높다고 miou가 높지 않은 것을 확인 할 수 있음
- 테이블에서 아키텍쳐별 성능을 확인할 수 있음
- 해당 지표는 각 arch별 sweep의 실행결과에 대한 평균
- 각 행을 클릭하면 arch의 sweep 수행결과를 확인
- 가장 성능이 좋았던 모델에 대해 명령어로 다시 수행할 수 있음
- 사물에 대한 분류 성능이 좋아지도록
image_size
의 크기를 더 키움
- sweep을 통해 진행한 결과보다 더 좋은 성능을 얻음
4. Lesson & Learned
- MLOps Model Development(1)은 모델의 성능 개선을 위한 이론적 바탕에 대해 학습하였음
- MLOps Model Development(2)는 모델의 초기 프로토타입인 baseline을 작성하였음
- MLOps Model Development(3)은 baseline에서 부족한 부분을 tuning을 통해 개선하였음
- 3가지 과정을 통해 모델 개선을 하는 방법에 대해 이론 뿐 아니라 W&B의 기능을 사용해 수행하는 방법에 대해 배울 수 있었음
- 향후 프로젝트 시에 모델 성능 이슈 혹은 재학습에 대한 mlops 방안을 이를 통해 개선할 수 있을 듯 함
댓글남기기