-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2 from bcaitech1/Hyeonjin
Hyeonjin
- Loading branch information
Showing
8 changed files
with
512 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
## 제출 목록 | ||
|모델|배치|시드|time/step|epoch|loss|val_loss|val_mIoU|LB score| | ||
|------|---|---|---|---|---|---|---|---| | ||
|DeepLabV3+, resnext50|16|77|4.8s|10|0.108|0.283|0.463|0.5754| | ||
|DeepLabV3+, seresnext50|16|77|6.8s|16|0.057|0.280|0.476|0.5670| | ||
|DeepLabV3+, resnext50|8|77|2.4s|9|0.098|0.294|0.451|0.5795| | ||
|
||
나머지는 너무 오래 걸려서 1~2에폭에서 관둠 | ||
<br> | ||
<br> | ||
|
||
### 비고 | ||
- scheduler: CosineAnnealingWarmup(LR_start=2e-6, LR_max=1e-4, T_0=20, T_up=2) | ||
- batch_size를 8로 주면 마지막(327번째) 배치에서 size관련 에러 발생<br> | ||
ㄴ train_loader에서 drop_last=True로 해결했으나 원인파악을 못함<br> | ||
- V3에 비해 V3+가 파라미터 수도 작고, 러닝타임도 빠름 | ||
- smp 모델에서 인코더 부분만 timm 모델로 교체하려 했으나, 동일 모델이라도 weight값이 아예 달랐음 (일단 시도 예정) | ||
|
||
<br> | ||
|
||
### 배치16 기준 러닝타임(per step) | ||
- PSPNet : eff-b0(3.2s), eff-b3(3.5s), resnet34(6.0s) | ||
- DeepLabV3+ : resnext50(4.8s), eff-b0(6.7s), seresnext50(6.8s), eff-b3(9.5s), effi-b5(15.5s) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
## Overfitting? | ||
|모델|배치|시드|time/step|epoch|loss|val_loss|val_mIoU|LB score| | ||
|------|---|---|---|---|---|---|---|---| | ||
|DeepLabV3+, resnext50|8|77|2.4s|9|0.098|0.294|0.451|0.5795| | ||
|"|"|"|"|12|0.065|0.305|0.451|0.5696| | ||
|
||
CrossEntropyLoss 기준 대체적으로 train_loss < 0.1 부터 오버피팅되는 듯함<br> | ||
위 결과는 증명을 위해 제출해본 내역 | ||
|
||
## Resize(256) | ||
|모델|input_size|배치|시드|time/step|epoch|loss|val_loss|val_mIoU|LB score| | ||
|------|---|---|---|---|---|---|---|---|---| | ||
|DLV3+, resnext50|512|16|77|4.8s|10|0.108|0.283|0.463|0.5754| | ||
|"|256|16|77|0.8s|14|0.097|0.339|0.416|0.5609| | ||
|"|512|8|77|2.4s|14|0.098|0.294|0.451|0.5795| | ||
|"|256|8|77|0.45s|12|0.103|0.343|0.434|0.5640| | ||
|
||
다른 전처리 없이 train,test 모두 resize(256)<br> | ||
러닝타임 대폭 감소(1epoch 13분->2분), 다양한 실험 진행하기에 좋을듯 | ||
|
||
## (1-mIoU)+CE | ||
|모델|loss|배치|시드|time|epoch|loss|val_loss|val_mIoU|LB score| | ||
|------|---|---|---|---|---|---|---|---|---| | ||
|DLV3+, resnext50|CE|8|77|0.45s|12|0.103|0.343|0.434|0.5640| | ||
|"|(1-mIoU)*0.4|"|"|"|11|0.204|0.428|0.431|0.5653| | ||
|"|(1-mIoU)*0.7|"|"|"|14||0.510|0.417|-| | ||
|"|(1-mIoU)*0.2|"|"|"|13||0.394|0.431|-| | ||
|
||
|
||
## 기타 loss Function | ||
Focal, (1-mIoU)+Focal, weighted(CE) 모두 학습 안됨 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,18 @@ | ||
# Team.분리수거잘하조 | ||
# 안현진 | ||
|
||
*** | ||
|
||
*made by* [김동우]([email protected]), [김익재]([email protected]), [송민기]([email protected]), [안현진]([email protected]), [최재하]([email protected]), [황정훈](https://github.com/wjdgns7712) | ||
### train_wandb.py | ||
wandb autoML 실행 코드 | ||
|
||
blah blah~ | ||
### dataloader.py | ||
CustomDataset 클래스만 있음 | ||
|
||
### scheduler.py | ||
custom scheduler : CosineAnnealingWarmUpRestarts() <br> | ||
출처: https://gaussian37.github.io/dl-pytorch-lr_scheduler/ | ||
|
||
### evaluate.py | ||
metric 및 validation 함수 | ||
|
||
### utils.py | ||
save, load, submit, calculate_parameter |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
import os | ||
import torch | ||
import torch.nn as nn | ||
from torch.utils.data import Dataset, DataLoader | ||
import numpy as np | ||
import pandas as pd | ||
|
||
# 전처리를 위한 라이브러리 | ||
import cv2 | ||
from pycocotools.coco import COCO | ||
import torchvision | ||
import torchvision.transforms as transforms | ||
import albumentations as A | ||
from albumentations.pytorch import ToTensorV2 | ||
|
||
|
||
def get_classname(classID, cats): | ||
for i in range(len(cats)): | ||
if cats[i]['id']==classID: | ||
return cats[i]['name'] | ||
return "None" | ||
|
||
class CustomDataLoader(Dataset): | ||
"""COCO format""" | ||
def __init__(self, data_dir, mode = 'train', transform = None): | ||
super().__init__() | ||
self.mode = mode | ||
self.transform = transform | ||
self.coco = COCO(data_dir) | ||
self.dataset_path = 'input/data/' | ||
self.category_names = ['Backgroud', 'UNKNOWN', 'General trash', 'Paper', 'Paper pack', 'Metal', 'Glass', 'Plastic', 'Styrofoam', 'Plastic bag', 'Battery', 'Clothing'] | ||
|
||
def __getitem__(self, index: int): | ||
image_id = self.coco.getImgIds(imgIds=index) | ||
image_infos = self.coco.loadImgs(image_id)[0] | ||
|
||
images = cv2.imread(self.dataset_path+image_infos['file_name']) | ||
images = cv2.cvtColor(images, cv2.COLOR_BGR2RGB).astype(np.float32) | ||
images /= 255.0 | ||
|
||
if (self.mode in ('train', 'val')): | ||
ann_ids = self.coco.getAnnIds(imgIds=image_infos['id']) | ||
anns = self.coco.loadAnns(ann_ids) | ||
cat_ids = self.coco.getCatIds() | ||
cats = self.coco.loadCats(cat_ids) | ||
|
||
masks = np.zeros((image_infos["height"], image_infos["width"])) | ||
for i in range(len(anns)): | ||
className = get_classname(anns[i]['category_id'], cats) | ||
pixel_value = self.category_names.index(className) | ||
masks = np.maximum(self.coco.annToMask(anns[i])*pixel_value, masks) | ||
masks = masks.astype(np.float32) | ||
|
||
if self.transform is not None: | ||
transformed = self.transform(image=images, mask=masks) | ||
images = transformed["image"] | ||
masks = transformed["mask"] | ||
|
||
return images, masks #, image_infos | ||
|
||
if self.mode == 'test': | ||
if self.transform is not None: | ||
transformed = self.transform(image=images) | ||
images = transformed["image"] | ||
|
||
return images #, image_infos | ||
|
||
|
||
def __len__(self): | ||
return len(self.coco.getImgIds()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
import torch | ||
import numpy as np | ||
from utils import * | ||
|
||
|
||
def validation(model, data_loader, criterion, device): | ||
model.eval() | ||
with torch.no_grad(): | ||
total_loss = 0 | ||
cnt = 0 | ||
mIoU_list = [] | ||
for step, (images, masks) in enumerate(data_loader): | ||
images, masks = images.to(device), masks.long().to(device) | ||
|
||
outputs = model(images) | ||
loss = criterion(outputs, masks) | ||
total_loss += loss | ||
cnt += 1 | ||
|
||
outputs = torch.argmax(outputs.squeeze(), dim=1).detach().cpu().numpy() | ||
|
||
mIoU = label_accuracy_score(masks.detach().cpu().numpy(), outputs, n_class=12) | ||
mIoU_list.append(mIoU) | ||
|
||
avrg_loss = total_loss / cnt | ||
model.train() | ||
return avrg_loss, np.mean(mIoU_list) | ||
|
||
|
||
def validation2(model, data_loader, criterion, device, n_class=12): | ||
model.eval() | ||
with torch.no_grad(): | ||
total_loss = 0 | ||
cnt = 0 | ||
hist = np.zeros((n_class, n_class)) | ||
for step, (images, masks) in enumerate(data_loader): | ||
images, masks = images.to(device), masks.long().to(device) | ||
|
||
outputs = model(images) | ||
loss = criterion(outputs, masks) | ||
total_loss += loss | ||
cnt += 1 | ||
|
||
outputs = torch.argmax(outputs.squeeze(), dim=1).detach().cpu().numpy() | ||
|
||
hist = add_hist(hist, masks.detach().cpu().numpy(), outputs, n_class=n_class) | ||
|
||
avrg_loss = total_loss / cnt | ||
mIoU = mIoU_score(hist) | ||
model.train() | ||
return avrg_loss, mIoU | ||
|
||
|
||
def mIoU_score(hist): | ||
with np.errstate(divide='ignore', invalid='ignore'): | ||
iu = np.diag(hist) / (hist.sum(axis=1) + hist.sum(axis=0) - np.diag(hist)) | ||
mean_iu = np.nanmean(iu) | ||
return mean_iu | ||
|
||
|
||
def add_hist(hist, label_trues, label_preds, n_class): | ||
for lt, lp in zip(label_trues, label_preds): | ||
hist += _fast_hist(lt.flatten(), lp.flatten(), n_class) | ||
return hist | ||
|
||
def _fast_hist(label_true, label_pred, n_class): | ||
mask = (label_true >= 0) & (label_true < n_class) | ||
hist = np.bincount( | ||
n_class * label_true[mask].astype(int) + | ||
label_pred[mask], minlength=n_class ** 2).reshape(n_class, n_class) | ||
return hist | ||
|
||
|
||
def label_accuracy_score(label_trues, label_preds, n_class=12): | ||
hist = np.zeros((n_class, n_class)) | ||
for lt, lp in zip(label_trues, label_preds): | ||
hist += _fast_hist(lt.flatten(), lp.flatten(), n_class) | ||
with np.errstate(divide='ignore', invalid='ignore'): | ||
iu = np.diag(hist) / ( | ||
hist.sum(axis=1) + hist.sum(axis=0) - np.diag(hist) | ||
) | ||
mean_iu = np.nanmean(iu) | ||
return mean_iu |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import math | ||
from torch.optim.lr_scheduler import _LRScheduler | ||
|
||
class CosineAnnealingWarmUpRestarts(_LRScheduler): | ||
def __init__(self, optimizer, T_0, T_mult=1, eta_max=0.1, T_up=0, gamma=1., last_epoch=-1): | ||
if T_0 <= 0 or not isinstance(T_0, int): | ||
raise ValueError("Expected positive integer T_0, but got {}".format(T_0)) | ||
if T_mult < 1 or not isinstance(T_mult, int): | ||
raise ValueError("Expected integer T_mult >= 1, but got {}".format(T_mult)) | ||
if T_up < 0 or not isinstance(T_up, int): | ||
raise ValueError("Expected positive integer T_up, but got {}".format(T_up)) | ||
self.T_0 = T_0 | ||
self.T_mult = T_mult | ||
self.base_eta_max = eta_max | ||
self.eta_max = eta_max | ||
self.T_up = T_up | ||
self.T_i = T_0 | ||
self.gamma = gamma | ||
self.cycle = 0 | ||
self.T_cur = last_epoch | ||
super(CosineAnnealingWarmUpRestarts, self).__init__(optimizer, last_epoch) | ||
|
||
|
||
def get_lr(self): | ||
if self.T_cur == -1: | ||
return self.base_lrs | ||
elif self.T_cur < self.T_up: | ||
return [(self.eta_max - base_lr)*self.T_cur / self.T_up + base_lr for base_lr in self.base_lrs] | ||
else: | ||
return [base_lr + (self.eta_max - base_lr) * (1 + math.cos(math.pi * (self.T_cur-self.T_up) / (self.T_i - self.T_up))) / 2 | ||
for base_lr in self.base_lrs] | ||
|
||
def step(self, epoch=None): | ||
if epoch is None: | ||
epoch = self.last_epoch + 1 | ||
self.T_cur = self.T_cur + 1 | ||
if self.T_cur >= self.T_i: | ||
self.cycle += 1 | ||
self.T_cur = self.T_cur - self.T_i | ||
self.T_i = (self.T_i - self.T_up) * self.T_mult + self.T_up | ||
else: | ||
if epoch >= self.T_0: | ||
if self.T_mult == 1: | ||
self.T_cur = epoch % self.T_0 | ||
self.cycle = epoch // self.T_0 | ||
else: | ||
n = int(math.log((epoch / self.T_0 * (self.T_mult - 1) + 1), self.T_mult)) | ||
self.cycle = n | ||
self.T_cur = epoch - self.T_0 * (self.T_mult ** n - 1) / (self.T_mult - 1) | ||
self.T_i = self.T_0 * self.T_mult ** (n) | ||
else: | ||
self.T_i = self.T_0 | ||
self.T_cur = epoch | ||
|
||
self.eta_max = self.base_eta_max * (self.gamma**self.cycle) | ||
self.last_epoch = math.floor(epoch) | ||
for param_group, lr in zip(self.optimizer.param_groups, self.get_lr()): | ||
param_group['lr'] = lr |
Oops, something went wrong.