MLOps Model Development (2) Build End to end prototype
본 게시물은 W&B가 제공한 MLOps의 Model Development에 대한 내용을 기술한다.
1. Introduce
Model development를 위해 W&B의 여러 기능을 사용하여 End to End Prototype을 생성해 봄
1.1 Agenda
📍 Build to End to End Prototype
Prototype을 설계하기 위한 단계는 아래와 같다.
- Understand the Business Context
- Frame the Data Science Problem
- Explore & Understand Your Data
- Establish Baseline Metrics & Models
- Communicate Your Result
1.2 Case Study
📍 Autonomous Vehicles Perception
- 자율주행을 위한 인식, 예측, 동작 중 인식에 초점을 맞춤
- BDD100K라는 기존 데이터세트의 서브세트로 학습
- Semantic Segmentation을 사용
👀 Object Detection Vs Semantic Segmentation
- Object Detection (객체 검출):
- Object detection은 이미지 내에서 물체를 감지하고 해당 물체가 어디에 있는지를 바운딩 박스(bounding box)로 표시한다.
- 이미지에서 여러 물체를 동시에 감지하고, 각 물체의 위치와 클래스를 식별한다.
- Semantic Segmentation (의미적 분할):
- Semantic segmentation은 이미지를 픽셀 수준에서 분할하여 각 픽셀을 특정 클래스(물체 또는 배경)로 할당한다.
- 각 픽셀에 대해 해당 픽셀이 어떤 물체에 속하는지 또는 배경에 속하는지를 식별한다.
2. EDA
2.1 의존성 설치 및 데이터셋 다운로드
# Install dependencies (run once)
!wget https://raw.githubusercontent.com/wandb/edu/main/mlops-001/lesson1/requirements.txt
!wget https://raw.githubusercontent.com/wandb/edu/main/mlops-001/lesson1/params.py
!wget https://raw.githubusercontent.com/wandb/edu/main/mlops-001/lesson1/utils.py
!pip install -r requirements.txt
DEBUG = False # set this flag to True to use a small subset of data for testing
from fastai.vision.all import *
import params
import wandb
URL = 'https://storage.googleapis.com/wandb_course/bdd_simple_1k.zip'
path = Path(untar_data(URL, force_download=True))
path.ls()
(#3) [Path('/root/.fastai/data/bdd_simple_1k/labels'),Path('/root/.fastai/data/bdd_simple_1k/LICENSE.txt'),Path('/root/.fastai/data/bdd_simple_1k/images')]
- 이미지 파일과 라벨링 그리고 라이선스 파일이 있음을 확인
2.2 W&B Table
run = wandb.init(project=params.WANDB_PROJECT, entity=params.ENTITY, job_type="upload")
raw_data_at = wandb.Artifact(params.RAW_DATA_AT, type="raw_data")
- W&B initialize 및 수행 화면
def label_func(fname):
return (fname.parent.parent/"labels")/f"{fname.stem}_mask.png"
def get_classes_per_image(mask_data, class_labels):
unique = list(np.unique(mask_data))
result_dict = {}
for _class in class_labels.keys():
result_dict[class_labels[_class]] = int(_class in unique)
return result_dict
def _create_table(image_files, class_labels):
"Create a table with the dataset"
# W&B Table 생성 코드
labels = [str(class_labels[_lab]) for _lab in list(class_labels)]
table = wandb.Table(columns=["File_Name", "Images", "Split"] + labels)
for i, image_file in progress_bar(enumerate(image_files), total=len(image_files)):
image = Image.open(image_file)
mask_data = np.array(Image.open(label_func(image_file)))
class_in_image = get_classes_per_image(mask_data, class_labels)
table.add_data(
str(image_file.name),
wandb.Image(
image,
masks={
"predictions": {
"mask_data": mask_data,
"class_labels": class_labels,
}
}
),
"None", # we don't have a dataset split yet
*[class_in_image[_lab] for _lab in labels]
)
return table
- Interactive하게 EDA를 수행하기 위해 W&B의 Table 생성
- W&B table 가이드
- W&B artifacts 가이드
raw_data_at.add_file(path/'LICENSE.txt', name='LICENSE.txt')
raw_data_at.add_dir(path/'images', name='images')
raw_data_at.add_dir(path/'labels', name='labels')
image_files = get_image_files(path/"images", recurse=False)
- raw_data_at에 파일 및 폴더 추가
- fastai의 get_image_files을 사용해 이미지 가져옴
# sample a subset if DEBUG
if DEBUG: image_files = image_files[:10]
table = _create_table(image_files, params.BDD_CLASSES)
raw_data_at.add(table, "eda_table")
run.log_artifact(raw_data_at)
run.finish()
- 생성된 테이블(eda_table)에 이미지 데이터를 임포트
📍 Artifacts import 수행화면
- W&B Table을 통해 데이터를 쉽게 EDA 할 수 있게 됨
3. Split Dataset
import os, warnings
import pandas as pd
from sklearn.model_selection import StratifiedGroupKFold
warnings.filterwarnings('ignore')
run = wandb.init(project=params.WANDB_PROJECT, entity=params.ENTITY, job_type="data_split")
raw_data_at = run.use_artifact(f'{params.RAW_DATA_AT}:latest')
fnames = os.listdir(path/'images')
groups = [s.split('-')[0] for s in fnames]
orig_eda_table = raw_data_at.get("eda_table")
y = orig_eda_table.get_column('bicycle')
- 이전 저장한 Table과 데이터들을 불러옴
df = pd.DataFrame()
df['File_Name'] = fnames
df['fold'] = -1
cv = StratifiedGroupKFold(n_splits=10)
for i, (train_idxs, test_idxs) in enumerate(cv.split(fnames, y, groups)):
df.loc[test_idxs, ['fold']] = i
df['Stage'] = 'train'
df.loc[df.fold == 0, ['Stage']] = 'test'
df.loc[df.fold == 1, ['Stage']] = 'valid'
del df['fold']
df.Stage.value_counts()
train 800
valid 100
test 100
Name: Stage, dtype: int64
df.to_csv('data_split.csv', index=False)
processed_data_at = wandb.Artifact(params.PROCESSED_DATA_AT, type="split_data")
processed_data_at.add_file('data_split.csv')
processed_data_at.add_dir(path)
data_split_table = wandb.Table(dataframe=df[['File_Name', 'Stage']])
join_table = wandb.JoinedTable(orig_eda_table, data_split_table, "File_Name")
processed_data_at.add(join_table, "eda_table_data_split")
run.log_artifact(processed_data_at)
run.finish()
- Train, Validation, Test로 분리된 데이터를 다시 Artifacts 및 Table에 저장
4. Baseline Model
from fastai.callback.wandb import WandbCallback
from utils import get_predictions, create_iou_table, MIOU, BackgroundIOU, \
RoadIOU, TrafficLightIOU, TrafficSignIOU, PersonIOU, VehicleIOU, BicycleIOU
train_config = SimpleNamespace(
framework="fastai",
img_size=(180, 320),
batch_size=8,
augment=True, # use data augmentation
epochs=10,
lr=2e-3,
pretrained=True, # whether to use pretrained encoder
seed=42,
)
set_seed(train_config.seed, reproducible=True)
run = wandb.init(project=params.WANDB_PROJECT, entity=params.ENTITY, job_type="training", config=train_config)
- config를 통해 실험의 조건을 설정
processed_data_at = run.use_artifact(f'{params.PROCESSED_DATA_AT}:latest')
processed_dataset_dir = Path(processed_data_at.download())
df = pd.read_csv(processed_dataset_dir / 'data_split.csv')
- 앞서 저장된 artifacts를 사용해 데이터를 불러옴
df = df[df.Stage != 'test'].reset_index(drop=True)
df['is_valid'] = df.Stage == 'valid'
# 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]
- valid와 test를 구분
def get_data(df, bs=4, img_size=(180, 320), 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),
batch_tfms=aug_transforms() if augment else None,
)
return block.dataloaders(df, bs=bs)
- fastai의 datablock을 사용해 dataloaders 생성
config = wandb.config
dls = get_data(df, bs=config.batch_size, img_size=config.img_size, augment=config.augment)
metrics = [MIOU(), BackgroundIOU(), RoadIOU(), TrafficLightIOU(), \
TrafficSignIOU(), PersonIOU(), VehicleIOU(), BicycleIOU()]
learn = unet_learner(dls, arch=resnet18, pretrained=config.pretrained, metrics=metrics)
callbacks = [
SaveModelCallback(monitor='miou'),
WandbCallback(log_preds=False, log_model=True)
]
- fastai의 unet_learner를 통해 학습
- Metric 중 miou를 통해 모델 학습을 모니터링하도록 설정
learn.fit_one_cycle(config.epochs, config.lr, cbs=callbacks)
samples, outputs, predictions = get_predictions(learn)
table = create_iou_table(samples, outputs, predictions, params.BDD_CLASSES)
wandb.log({"pred_table":table})
scores = learn.validate()
metric_names = ['final_loss'] + [f'final_{x.name}' for x in 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
wandb.finish()
- 학습 및 결과 로깅
5. Future Plan
- 이번 포스팅에선 case study를 통해 W&B의 artifacts와 table을 사용하여 효과적인 EDA를 수행하였고, baseline 모델의 학습 결과를 기록하였다.
- 다음 포스팅에서는 현재 만들어진 baseline 모델을 developement 시키도록 하는 과정을 살펴볼 것이다.
댓글남기기