목표
1. 거만하게 공부하지 않기 : 교수님이 시키는 거 해보자
2. 베이스 코드를 짠 후, 교수님께 배운 기법들을 적용해보고 성능이 좋아졌는지 확인해보자
3. augmentation 이것 저것 가정하고 시도해보기
강의 정리
- Dataset
주어진 vanilla data를 모델이 좋아하는 형태의 Dataset으로 만들어주는 법
- Pre-processing
현업에서는 null, noise 등 제대로 되지 않은 데이터가 과반수 -> 전처리 시간 오래 걸리고 중요함
이미지 데이터의 경우 , 시계열이나 정형 데이터에 비해서 전처리에 손이 많이 가는 편은 아니다.
하지만 이미지의 크기 때문에 메모리 문제가 발생
competition data는 품질이 매우 양호한 편 속지마라!
1. bounding box
: 이미지 내 내가 필요한 정보에 대해서만 bbox를 쳐서 그 부분만 사용하기
2. Resize
: 계산의 효율(Memory)을 위해 적당한 크기로 사이즈 변경
3. 도메인, 데이터 형식에 따라 정말 다양한 전처리 방법이 존재
-> medical data의 경우 밝기조절 등
전처리는 마스터키가 아니다! 이것저것 가정하고 실험해보자
- Data augmentation
: 주어진 데이터가 가질 수 있는 Case , State 의 다양성
문제가 만들어진 배경과 모델의 쓰임새를 살펴보면 힌트를 얻을 수 있다.
좋다고 막 쓰면 안됨 -> 이게 실제로 가능한지? 고려해보기
'무조건'이 아니다! 주제를 깊이 관찰해 어떤 기법을 적용해 효과를 얻을 수 있는 지 실험으로 증명해야 된다.!
- Data feedinng
대상의 상태를 고려해 적정한 양을 준다
generator의 속도 측정 추천! 벤치마킹하면서 적당한 batch)size , num_worker 등 찾기
compose안의 순서도 중요하다. 이거에 따라 속도가 달라진다.
이 부분은 생각도 안해봤는데 엄청난 거 같다. 메모리를 줄일 수 있는 Resize를 먼저 하는 게 맞는 거 같다.
이것도 순서를 실험해보면서 튜닝하기
- Dataset , Dataloader
Dataset : torch.utils.data.Data 상속받으므로 init, getitem, len 필수
Dataloader : Dataset을 batch size만큼 불러온다.
-> shuffle & sampler ,& collate_fn 조합해서 직접 해보기 추천
Dataset과 Dataloader는 엄연히 다르다 !
데이터를 원하는 형태로 출력하는 클래스 / Dataset을 더 효율적으로 사용하기 위함
이 중에서 교수님이 dataloader에서 언급하신 sampler와 catalyst에서 제공하는 sampler기능에 대해서 좀 공부해봤다.
[Sampler]
Sampler는 Dataset을 인자로 받아 호출 시 data의 index를 반환해준다.
즉 dataloader 내 에서 index를 컨트롤 하는 역할을 한다.
shuffle = True를 실행했을 때, RandomSampler가 실행되는 거라고 한다.
catalyst-team.github.io/catalyst/api/data.html#balanceclasssampler 적용이 힘들다;; ㅜㅜ
목표를 위한 행동
1 . Baseline 짜보기
baseline 완성! 올리고 싶지만 그러면 안되니까 꾹 참기,,,
2. 겸손히 공부하기 : 교수님이 하라는 대로 해보기
-1번 실험 : transform vs albumentation 누가 더 빠를까?
# torchvision tramsforms 사용
class CustomDataset(torch.utils.data.Dataset):
def __init__(self, path , df ,transform = None):
self.path = path
self.df = df
self.transform = transform
def __getitem__(self,idx):
image = Image.open(self.df['path'].iloc[idx]).convert("RGB")
if self.transform:
image = self.transform(image)
label = self.df['label'].iloc[idx]
return image, label
def __len__(self):
return len(self.df)
# torchvision tramsforms 사용
train_transforms = transforms.Compose([
transforms.Resize((img_size, img_size)),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406],
[0.229, 0.224, 0.225])])
val_transforms = transforms.Compose([
transforms.Resize((img_size, img_size)),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406],
[0.229, 0.224, 0.225])])
albumentation을 사용할 때, torch vision 과 거의 똑같지만 다른 점이 있다.
transform을 함수처럼 받아와서 그 중 'image'에 해당하는 이미지를 가져온다.
# albumentation 사용
class CustomDataset(torch.utils.data.Dataset):
def __init__(self, path , df ,transform = None):
self.path = path
self.df = df
self.transform = transform
def __getitem__(self,idx):
image = cv2.imread(self.df['path'].iloc[idx])
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
if self.transform:
augmented = self.transform(image=image)
image = augmented['image']
label = self.df['label'].iloc[idx]
return image, label
def __len__(self):
return len(self.df)
# albumentation 사용
train_transforms = A.Compose([
A.Resize(256,256),
A.Normalize([0.485, 0.456, 0.406],[0.229, 0.224, 0.225]),
A.pytorch.transforms.ToTensor()
])
val_transforms = A.Compose([
A.Resize(256,256),
A.Normalize([0.485, 0.456, 0.406],[0.229, 0.224, 0.225]),
A.pytorch.transforms.ToTensor()
])
시간을 재보자!
# torch transform 사용
start = time.time()
for i , (img , tgt) in enumerate(train_dataset):
if i == 100 :
end = time.time()
print(f'소요시간 : {end - start}')
break
iteration 100번에 대해서 albumentation을 사용했을 떄가 0.25초 정도 더 빨랐다.
그러면 학습을 시켜보면 어떨까?
예상 외로 똑같이 1분 38초가 나온다.
내 예상으로는 에폭1번당 iter100번 정도인데 그럼 둘이 0.25초 차이로 tqdm은 초까지만 표시해주므로 아마 차이는 나지만 반올림 돼서 둘이 똑같아 보이는 게 아닌가 싶다.
💚하지만 제 사랑은 albumentation입니다💚
- 2번 실험 : 어떤 augmentation이 좋을까?
실험은 아래와 같은 조건으로 모두 동일하게 진행했다.
Epoch 10번이 너무 적을 수도 있지만 빠르게 비교해보기 위해서 10번만 했다.
❗❗ 저작권의 이유로 다른 사진으로 대체 ❗❗
batch_size = 128
num_workers = 2
learning_rate = 0.001
epochs = 10
img_size = 256
criterion = CEloss
optimizer = Adam
lr_scheduler = None
Model = EfficientNet B0
1. Base
# albumentation 사용
train_transforms = A.Compose([
A.Resize(256,256),
A.Normalize([0.485, 0.456, 0.406],[0.229, 0.224, 0.225]),
A.pytorch.transforms.ToTensor()
])
결과 : 10epoch 기준 73.84% 0.67%
➕ 번외로 사람들이 lr_scheduler는 잘 안 쓰는 거 같던데,,, 이거만 잘 써도 4% 이상 향상된다.
2. Rotate
왜? train / test 이미지가 모두 정면을 바라보고 있어서 Rotate는 필요가 없나 싶지만 갸웃거리는 수준의 이미지도 있을 수 있으니 10도 정도 rotate 시켜보자.
# rotate_albumentation 사용
rotate_train_transforms = A.Compose([
A.Resize(256,256),
A.Rotate(limit = 10 , border_mode = 1), # 'cv2.BORDER_REPLICATE' = 1
A.Normalize([0.485, 0.456, 0.406],[0.229, 0.224, 0.225]),
A.pytorch.transforms.ToTensor()
])
그려보자 : 정말 티도 안나게 조금씩 돌아간 걸 볼 수 있다.
결과 : 10 epoch 기준 : 72.35% 0.62%
3. RandomCrop
왜? 개요를 보면 공공장소에서 사람들의 착용 상태를 검사한다고 한다. 그렇다면 항상 정직하게 찍히진 않을 것이다.
그런 점을 고려해 RandomCrop을 사용했다.
scale과 ratio가 디폴트값인 ver1 과 scale 과 ratio를 내가 조절해준 ver2 두 가지 버전으로 시도해보았다.
# randomcrop_albumentation 사용 ver1
randomcrop_train_transforms = A.Compose([
A.Resize(256,256),
A.RandomResizedCrop(256,256) ,
A.Normalize([0.485, 0.456, 0.406],[0.229, 0.224, 0.225]),
A.pytorch.transforms.ToTensor()
])
# randomcrop_albumentation 사용 ver2
randomcrop_train_transforms = A.Compose([
A.Resize(256,256),
A.RandomResizedCrop(256,256, scale=(0.4, 1.0) , ratio = (0.75 , 1)) ,
A.Normalize([0.485, 0.456, 0.406],[0.229, 0.224, 0.225]),
A.pytorch.transforms.ToTensor()
])
그려보자 ver1 scale = (0.08 , 1.0) & ratio = (0.75 , 1.3333)
그려보자 ver2 scale = (0.4 , 1.0) & ratio = (0.75 , 1.0)
scale과 ratio를 이렇게 준 이유는 원본 이미지의 ratio를 따라했고, scale은 이미지를 그려가면서 확인했을 때 마스크를 가리지 않는 선에서 가장 적당하다고 생각했기 때문이다.
ver1 결과 : 78.83% 0.74%
ver2 결과 : 75.57% 0.70%
4. Horizontal Flip
왜? 성능의 큰 향상이 목적보다는 단순히 데이터의 다양성을 위해 추가함
vertical flip의 경우 실제에서 그럴 일이 없기때문에 사용하지 않았고, 마스크를 눈에 낀 경우와 혼동할 수 있어 추가하지 않았다.
그려보자
결과 : 70.63% 0.62%
5. JpegCompression
왜? 보현님의 의견! 완전 압축돼서 굵직한 이미지가 남으면 그게 마스크를 의미하지 않을까? 라는 아이디어
# JpegCompression_albumentation 사용
Jpeg_train_transforms = A.Compose([
A.Resize(256,256),
A.JpegCompression(quality_lower=0, quality_upper=50),
A.Normalize([0.485, 0.456, 0.406],[0.229, 0.224, 0.225]),
A.pytorch.transforms.ToTensor()
])
그려보자
결과 : 67.71% 0.57%
-> 노이즈를 추가하는 방식은,,, epoch을 좀 더 늘려봐야하나?
오늘의 달성 및 깨달음
- Random Crop을 사용했더니 성능이 갑자기 훅! 올라서 순간 2등을 했다 하하.
역시 이것저것 해보라는 마스터님의 말씀을 곧이곧대로 해서 그런건가,,,! 싶었다. - 다른 조원들은 안된다고 로터리티켓 아니냐고 ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ 그럴 수도 있을 거 같다.
- augmentation을 추가했을 때가 오히려 base에 비해 성능이 안나오는 것이,,,,,좀 놀라웠다. 이게 진짜로 base보다 안좋은 건지, 아니면 epoch 수가 너무 적어서 그런 건지 또 실험을 좀 해봐야 할 거 같다.
- Sampler를 이용해보려고했는데,, 너무 어렵다. 내 코드에 적용이 안 된다. ㅠㅠ
- Further Reading 중 흥미롭게 읽은 것
목표 & 내일의 시도
시간 상의 문제로 오늘의 실험은 여기까지 ㅠㅠ
- 내일은 augmentation 조합을 좀 도전 해보자!
- RandomResizedCrop
- One of [ gaussian noise , MotionBlur , jpegcompression]
- horizontal flip
- rotate
- Fc layer를 한 단 더 추가해보기
- Model 바꿔보기 B3 , B4 등
남들이 쓰니까 augmentation을 하는 것도 좋지만 ,직접 어떤 게 필요할까? 생각하면서 시도해보니 데이터나 문제에 대해 더 잘 이해할 수 있던 거 같다. 당장 리더보드에서 점수 내는 거에 급급하지 말고 내일도 교수님 말에 좀 충실해보자. 그럼 내일을 위해 빨리 자러 가보자 💨
'Naver Ai Boostcamp' 카테고리의 다른 글
[04/02] More... (0) | 2021.04.03 |
---|---|
[03/31] Model (0) | 2021.03.31 |
[03/29] P Stage Start ! (0) | 2021.03.30 |
[Day 38] 빠르게 & 가지치기 (0) | 2021.03.28 |
[Day 37] 모델의 시공간 & 알뜰히 (0) | 2021.03.27 |