Boostcamp AI Tech

[Wrap-up report] Image Classification

ju_young 2021. 9. 3. 14:52
728x90

Problem Definition

  • 카메라로 촬영한 사람 얼굴 이미지의 마스크 착용 여부를 판단
  • 입력되는 이미지는 모두 정면을 바라보고 있으며 아시아인 남녀로 구성되고 20대부터 70대까지 연령층이 다양함
  • 마스크 착용, 이상하게 착용, 미착용의 분류와 나이(젊은층, 중년층, 노년층), 성별까지 종합한 총 18개의 label를 분류하여 출력
  • 이미지 데이터의 특성상 해당 분류 문제는 카메라를 정면을 바라봐야하고 촬영되는 사람도 카메라 화면상 중앙에 위치해야 성립
  • 얼굴이 일부 보이는 마스크(투명한 마스크)일 경우와 사람이 얼굴이 프린트된 마스크일 경우와 같은 이미지일 경우 제대로 인식하는가에 대한 문제가 발생

EDA

  • 데이터의 불균형 확인을 위해 feature, label별 분포확인
  • Normalize의 mean과 std값을 지정해주기위해 이미지의 RGB 통계량을 계산
  • opencv의 haar cascasde를 사용하여 이미지상 사람의 얼굴을 인식하는 방법을 적용하였지만 몇몇 이미지들은 인식을 잘 못하는 경우가 발생
  • 이미지를 시각화하여 잘못된 label이 있는지 확인

Image Data

  • 상황
    1. 대부분의 이미지에서 얼굴 부분을 제외한 나머지 불필요한 정보가 존재
    2. opencv의 haar cascasde를 사용하여도 얼굴을 제대로 인식하지 못하는 경우가 발생
  • 해결방안
  • facenet_pytorch의 MTCNN을 사용하여 face를 detection하였지만 여전히 인식을 못하는 이미지가 생겨 retinaface도 활용하여 face만 crop함

Dataset

  • 상황 : train set과 validation set 둘 다 같은 id(사람)를 가지는 이미지가 들어감으로서 overfitting의 위험이 발생
  • 가설 : 사람을 기준으로 구분하여 train set과 validation set에 같은 사람이 들어가지 않게함으로서 overfitting의 위험을 줄일 수 있을 것임
  • 결과 : 사람을 기준으로 구분한 dataset을사용했을 때 validation score가 이미지를 기준으로 구분한 dataset의 validation score보다 작게 나오고 리더보드 점수는 비슷하게 나오는 결과로 overfitting의 위험이 줄어들었다고 판단
  • 정리 : 그저 train set과 validation set을 구분한다는 생각보다 구분되는 데이터들이 어떻게 모델 학습에 영향이 갈지에 대해 조금 더 구체적으로 생각하게 되었음

Data Imbalance

  • 상황
    1. 중년층(30, 40, 50대)이 젊은층(20대 이하)와 노년층(60대)보다 상대적으로 많음
    2. male보다 female 데이터가 좀 더 많이 분포되어있음
    3. label에 대한 분포를 확인했을 때 0, 1, 3, 4(마스크를 쓴 젊은층과 중년층)에 집중적으로 분포되어있음
    4. 마스크 착용 : 이상하게 착용 : 미착용 = 5 : 1 : 1
  • 가설 : 상대적으로 많이 분포되어있는 중년층 중에서 55세 이상 60세 미만의 데이터를 가장 적게 분포되어있는 60세로 label을 바꿔줌으로서 데이터 불균형의 문제를 조금 해결할 수 있을 것임
  • 결과 : 10% 단위로 50%까지 실험한 결과 비중이 높을수록 validation score가 더 낮아지는 그래프가 그려졌고 50%를 바꾸었을 때의 inference 제출시 리더보드 점수가 상승함
  • 정리
    1. 중년층 중 일부를 노년층으로 바꿔주면서 overfitting의 위험을 줄일 수 있었지만 해당 프로젝트의 목적(다양한 기법들을 사용한 모델 성능 향상 등)과 벗어난다고 판단
    2. 이처럼 데이터의 일부를 다른 label로 옮기거나 외부 데이터로 데이터 불균형을 보완할 수 있을 것이라는 생각보다 generalization을 통해 성능 향상을 꾀하는 것이 효율적이라고 생각함

Data Augmentation

​ [#1]

  • 상황 : 이미지를 육안으로 확인했을 때 밝기, 인물의 위치, 원근감, 머리카락의 유무, 안경 착용의 유무 등 다양함
  • 가설 : RandomBrightness, RandomPerspective, GaussianBlur, Grayscale와 같은 기법들을 사용하여 밝기, 원근감, 마스크 색깔 등을 보완할 수 있을 것임
  • 결과 : augmentation을 하지않았을 때와 미미한 차이를 보여줌
  • 정리 : 랜덤하게 선택된 이미지들에게 augmentation을 적용했을 때 수가 상대적으로 많은 마스크 착용 이미지들에게도 적용됨 → 데이터 수가 적은 부분에 augmentation을 적용하여 부족한 부분을 채워야하지만 데이터 수가 많은 부분과 데이터 수가 적은 부분 모두에 augmentation을 적용이되어 점수 차이에 영향이 없었던 것이라 생각함

[#2]

  • 상황 : 여러 모델을 사용하여 학습을 하였을때 데이터 불균형에 따른 overfitting 문제가 발생
  • 가설
    1. 데이터가 비교적 많이 분포한 중년층 중에서 마스크를 착용한 이미지에 cutmix를 사용하여 generalization이 적용됨으로서 overfitting의 위험을 낮추어줄 것임
    2. 이미지의 왼쪽 반과 오른쪽 반을 섞는 방식의 cutmix를 사용함으로서 학습시 generalization 적용이 가능해질 것임
  • 결과
    1. resnet50을 사용하고 cutmix를 마스크 쓴 중년층에 30% 적용했을 때 f1 score가 약 0.1이 상승
    2. efficientnet_b7과 resnet152와 같이 좀 더 레이어가 깊은 모델의 경우 마스크 쓴 중년층과 젊은층 모두에게 적용하여 좀 더 높은 점수를 보여줌
  • 정리
    1. resnet50과 같이 레이어가 깊지않은 모델의 경우에도 generalization을 적용하여 충분히 좋은 결과를 얻을 수 있다고 생각함
    2. efficientnet_b7과 resnet152는 resnet50보다 레이어가 깊기 때문에 overfitting의 위험 또한 높아지기 때문에 generalization을 적용하는 비중을 높여서 성능 향상에 도움을 주었다고 판단

[#3]

  • 상황 : 하나의 모델을 사용하여 augmentation을 적용했을 때 성능 차이를 확인
  • 가설 : 고정된 hyperparameter(batch size, lr, epoch, loss, optimizer, weight decay, lr_scheduler, earlystopping-patience)과 고정된 random seed, requires_grad=False를 적용하고 augmentation만을 추가 & 수정한다면 얼마나 성능 차이가 있을지 확인할 수 있을 것임
  • 결과 : 성능 차이가 거의 나지 않았음
  • 정리
    1. pre-train된 모델에 backpropagation이 안될때 augmentation을 적용한 데이터에 맞게 학습이 되지않아 실질적으로 성능 차이를 확인할 수 없다고 생각함
    2. trainsfer learning을 수행할 때 backpropagation의 수행 여부에 따라 성능 차이 확인에 어떠한 영향을 주는가에 대한 판단이 힘들었음

Optimizer & Loss

  • 상황 : 학습시 overfitting이 일어나고 제출 점수 기준이 f1 loss임
  • 가설
    1. 기존의 adam보다 generalization 능력이 더 좋은 adamw를 사용하여 overfitting의 위험을 낮출 것임
    2. 기존의 crossentropy loss를 사용하는 것보다 f1 loss를 사용하여 조금 더 정확한 성능 판단을 할 수 있을 것임
  • 결과 & 정리
    1. adamw의 경우 weight decay를 조절하며 generalization 성능을 끌어올릴 수 있었다고 판단
    2. f1 loss을 사용하게되면서 리더보드 점수와의 차이를 알 수 있었고 모델의 성능 차이를 확인할 수 있는 지표가 되었다고 판단

Early Stopping

[#1]

  • 상황 : 성능 향상이 없음에도 지정한 epoch 만큼 학습이 수행됨
  • 해결방안 : Early Stopping 기법을 적용하여 학습시 patience 만큼 성능 향상이 없으면 중단

[#2]

  • 상황
    1. 주어진 patience 이후에도 성능 향상의 여지가 있었음에도 학습이 중단되는 문제 발생
    2. 1 epoch 차이임에도 제출시 점수 차이가 많이나는 문제 발생
  • 해결방안 : 20 epoch를 지정하고 5 epoch 이후부터 각 epoch마다 checkpoint를 저장하고 WandB를 사용하여 그려진 그래프를 통해 최종 inference할 checkpoint를 선택

TTA(Test Time Augmentation)

  • Test를 할 때에도 augmentation을 적용시켜 더 다양한 시야와 각도로 본 이미지를 inference함으로서 score 향상에 기여하는 기법
  • 여러 개의 augmentation을 적용하여 각 확률 값을 합하거나 평균을 구하는 등의 방법을 통해 최종 예측 값을 도출하는 기법을 사용해보았으며 score 향상에 조금 도움됨
  • augmentation을 지나치게 많이 주게되면 오히려 score가 하락하는 문제가 있기때문에 많은 실험과 검증을 통해 최적의 augmentation을 찾는 것이 좋겠지만 성능 차이에 영향이 크지 않아 후반에 사용하는 것이 좋을 것이라 생각함

아쉬웠던 점

  • 이번 프로젝트를 진행하면서 코드에 실수가 많았다. 급한 마음에 코드를 꼼꼼히 보지 못하고 진행했던 탓이 컸던 것 같다.
  • 대부분의 시간을 augmentation과 cutmix 적용에 사용하여 앙상블과 같은 다양한 기법들을 사용하지 못했던 것이 아쉽다.
  • 모델을 실행하는데 시간이 오래걸리는 문제가 발생하여 시간복잡도에 대한 생각과 gpu 사용에 대한 지식이 필요하다고 느꼈다.
  • 토론게시판을 이용하려 생각은 하지만 어떤 부분을 공유해야할지에 대한 고민과 불확실성때문에 참여도가 부족했었다. 다름 프로젝트에서는 토론게시판에 참여하려는 노력에 힘써야겠다.
  • shell script를 사용하여 계획적으로 모델을 실행하는 시도를 못해본 것이 아쉬웠다. 모델이 실행되고 에러가 발생했을 때 눈치채기 전까지는 그 시간을 버리는 것이기 때문에 shell script를 사용을 꺼렸던 것 같다. 하지만 익숙해지면 좀 더 효율적으로 진행할 수 있을 것이라 생각하기에 사용해봐야겠다.
  • 해당 모델이 어떠한 부분을 예측하고 못하는지에 대한 시각화 또는 지표에대한 공부가 더 필요하다는 것을 느꼈다. 모델을 어떠한 방향으로 개선해야할 지에 대한 방향성을 찾는 것이 중요한 것 같다.

새롭게 시도했거나 어려웠던 점

  • 데이터 불균형으로 인한 overfitting을 해결하는 것이 가장 어렵다고 느꼈다. overfitting을 판단하는 기준이나 지표조차 정확하게 정할 수 없다는 것이 문제였던 것 같다.
  • jupyter notebook에서 수행하던 것을 OOP를 통해 python file 로 대부분의 기능을 클래스와 함수로 구현하였다. 이렇게 여러 python file으로 나누어 구현함으로서 코드의 가용성을 늘리고 유지보수를 줄일 수 있는 효과를 얻게 되었다.
  • overfitting의 위험을 낮추기위해 가장 대표적인 cutmix 기법을 사용해보았지만 처음에는 제대로된 적용법을 모르고 실수를 여러번 거치게되었다. 예를 들어 validation set에는 적용하지 않아야하는데 적용했거나 loss 계산을 수정하지 않았던 점 등이 발생하게 되었다. 이 경험을 통해 다음부터는 제대로된 적용법을 숙지하여 불필요한 작업을 최소화할 수 있는 방향으로 진행할 수 있게 노력해야겠다.
  • 레이어의 깊이가 적은 모델을 사용했을 때 성능 향상에 도움이 되었던 augmentation이 레이어의 깊이가 깊은 모델에 적용했을 때 성능이 오히려 떨어지는 문제가 있었다. 레이어가 깊을수록 overfitting의 위험이 커지기 때문에 적용되는 augmentation의 비중 또한 높여가며 다시 맞춰가야한다는 것이 어렵다고 느꼈고 이렇게 진행하는 것이 맞는지에 대한 의문도 들었다.

최종 결과

  • 모델 : Resnet50
  • hyperparameter : learing_rate : 1e-5, train_batch_size : 32, validation_batch_size : 16, epochs : 14, weight_decay : 20
  • augmentation : Resize(224, 224), Normalize, ToTensor, Cutmix(마스크 쓴 중년층 30%)
  • optimizer & loss : AdamW, F1_loss
  • 결과
    1. public 데이터셋 리더보드 점수 = 0.721, private 데이터셋 리더보드 점수 = 0.728
    2. 0.721 → 0.728로 소폭 상승
    3. 최종 점수로는 팀 제출에서 가장 높은 점수를 달성
  • 정리 : 레이어가 깊고 parameter의 수가 많은 모델이 아니더라도 충분히 overfitting의 위험을 낮추고 성능을 향상시킬 수 있었다. 이렇게 하나의 모델로 성능 향상에대해 고민하고 적용해보았던 것이 다음 프로젝트에서도 도움이 될 수 있을 것이라 생각한다.
728x90