관리 메뉴

TEAM EDA

Cassava Leaf Disease Classification Public 13, Private 171 Solution 본문

TEAM EDA /EDA 3기 (2020.04.01 ~ 2021.12.31)

Cassava Leaf Disease Classification Public 13, Private 171 Solution

김현우 2021. 9. 17. 18:10

Cassava Leaf Disease Classification Public 13, Private 171 Solution

이번 포스팅에서는 Pseudo Lab 소속으로 4명의 팀원과 함께 나간 캐글 - Cassava Leaf Disease Classification 대회 솔루션의 후기를 작성하겠습니다. 정리한 내용이 길어서 이번 글에서는 저희 팀의 솔루션을 다음 글에서는 다른 팀의 솔루션과 배운점을 위주로 정리하도록 하겠습니다.

1. 개요

카사바란 아프리카 2위 탄수화물 공급식물입니다. 열악한 환경에서도 견딜 수 있어서 한국인의 쌀과 같이 핵심 공급 수단입니다. 하지만, 바이러스성 질병이 생길경우 수확량이 떨어지는 문제가 발생할 수 있습니다. 이를, 딥러닝의 도움을 통해서 문제를 해결하려고 하는게 이번 대회의 목적입니다. 대부분의 이미지는 농부들이 그들의 정원을 사진 찍는 것을 크라우드소싱을 통해서 얻었으며 캄팔라 마케레 대학의 AI 연구소와 협력하여 국립 작물자원연구소(NaCRRI)의 전문가들이 주석을 달았습니다. 실제로 이러한 과정은 농부들이 실제 생활에서 진단해야 할 것을 가장 현실적으로 나타내는 형식을 따른 것입니다. 이러한 카사바 이미지를 총 네 가지 질병 혹은 정상 잎을 나타내는 다섯 개의 클래스로 분류하는 것이 과제입니다.

2. 데이터 탐색

2.1. 클래스의 불균형

데이터 탐색을 통해서 확인한 첫번째 문제는 "클래스의 불균형" 입니다. 일반적으로 Healthy 라는 정상 클래스가 가장 많을 것으로 예상한 것과 다르게 Mosaic Disease가 가장 많았습니다. 그리고 그 외는 다들 2000 근방으로 비슷한 모습을 보였습니다.

2.2. 이미지의 포커싱이 다른 점

두번째 문제는 "이미지별 포커싱 된 영역이 다른 점" 이었습니다. 보이는 것과 같이 확대를 해서 찍은 이미지도 있고, 멀리서 찍은 모습도 보였습니다. 이럴 경우에 일정한 Receptive Field를 가지는 모델이 서로 다른 부분을 학습하기에 모델자체가 일관성이 없게 학습될 것이라고 판단했습니다.

2.3. 라벨에 노이즈가 발생한 경우

세번째 문제는 "레이블의 노이즈"입니다. 실제 육안으로 확인을 했을때 왼쪽의 경우는 Healthy로 오른쪽은 CMD와 CGM으로 판단된 이미지였습니다. 하지만, 왼쪽의 경우 반점이 나온 것처럼 정상으로 보이지는 않았고 오른쪽의 경우도 실제 레이블과 이미지가 매칭되지 않는 문제를 보였습니다. (하지만, 어려운 점은 도메인의 지식이 없다보니 맞게 판단했는지에 대해서 정확한 판단을 할수가 없었습니다.)

그위의 육안으로 판단하기 어려운 현상때매 CleanLab이라는 패키지의 도움을 받아서 노이즈에 대한 판단을 진행했습니다. 그 결과 위와 같이 나왔는데 왼쪽은 Clean Labl로 오른쪽은 Noise Label로 노이즈한 레이블이 많이 나온 것을 확인할 수 있었습니다.

노이즈와 관련해서 그 외에도 중복된 이미지들이 많이 존재했습니다. 정확히 동일한 이미지도 있었고 줌만 살짝 다르게해서 찍힌 이미지들도 있었고 그 외에도 중복된 이미지이지만 레이블이 다른 경우도 있었습니다.

3. 분석 과정

한번 위의 문제를 어떻게 해결했는지에 대해서 하나씩 살펴보겠습니다.

3.1. 클래스의 불균형

클래스의 불균형을 해결하기위해서 사용한 시도는 외부 데이터를 이용하는 것이었습니다. 실제 2021년도에 열린 Cassava 대회 외에도 비슷한 대회로 19년도와 In Class에 Cassava Leaf Disease 대회가 있었습니다. 그래서, 이러한 데이터 셋을 활용해가지고 여러가지 실험을 진행했습니다.

  • 시도1. 레이블이 적은 이미지만 활용
  • 시도2. 전체 이미지를 활용
  • 시도3. 수도 레이블로 레이블을 만들어서 유의미한 이미지만 활용

하지만 3가지의 시도는 모두 성능이 안좋아졌습니다. 개인적인 이유로 생각하기에는 외부 데이터에도 있었던 노이즈가 큰 영향을 끼친 것으로 생각됩니다. (이를 해결하기 위해서 시도3도 적용했지만 떨어진 이유는 잘 모르겠습니다.) 하지만, 3.3 부분에 다시 설명하겠지만 이러한 외부데이터를 Unlabeled로 보고 Semi-Supervised Classification 기법인 FixMatch를 적용했을때 성능향상이 있었습니다. 이에 대해서는 뒤에서 다시 말씀드리겠습니다.

3.2. 이미지의 포커싱이 다른 점

다음은 이제 이미지의 포커싱에 대한 문제였습니다. 언급한 것처럼 학습 이미지의 포커싱이 달랐고 이를 해결해주기위해서 Augmentation을 처음 생각했습니다. 첫번째 시도는 5 Crop을 만들어서 입력 이미지의 다양한 영역을 확대해서 학습하는 방법입니다. 그림처럼 확대된 이미지를 확대해서 크게 학습하기도 하고, 줌이 잘 안된 이미지도 이런 방식으로 다양하게 확대할 수 있었습니다. 하지만, 성능적인 측면에서는 하락했는데 아무래도 포커싱이 큰 이미지에 대해서도 Crop이 되어서로 생각합니다.

그래서, 이를 해결하기위해 학습단에서 Augmentation 주는 것이 아닌 Inference 시에 주는 TTA를 적용했습니다. 보는 것과 같이 많은 Augmentation이 적용되어있기는 하지만, 핵심적인 부분은 OneOf 내부에 들어가는 3개의 Resize 함수였습니다.

Resize - CenterCrop - RandomResizedCrop

3개 중에 하나가 랜덤하게 추출되어서 추론하도록 TTA를 적용했을때, 같은 이미지에 대해서 Resize 된 경우와 CenterCrop 된 경우 Random ResizedCrop 된게 모두 평균이 내지면서 성능적인 측면에서 많이 좋아졌습니다.

3.3. 라벨에 노이즈가 발생한 경우

마지막으로 레이블에 대한 노이즈를 해결하기 위한 시도들입니다. 첫번째로 가장 많이 사용하는 기법인 Soft Target을 이용한 Label Smoothing 이었습니다. 실제 이를 사용했을때 점수 상승폭이 가장 컸는데, alpha을 0.1로 작게 주었을때는 성능이 떨어졌지만 0.2~0.3으로 크게 주었을때는 0.899에서 0.902로 많은 상승이 있었습니다.

그 외에서 Label Smoothing 말고, 여러가지 레이블 노이즈에 강건한 로스등을 적용해보면서 실험을 진행했습니다. 하지만, 모두 성능 향상에는 도움이 되지 않았습니다.

그리고, CleanLab, OOF 등으로 노이즈를 제거하려고 많은 시도를 적용해봤는데 리더보드 상에서 모두 성능이 좋지 않았습니다. Validation 점수는 조금 상승했는데 Public 측면에서는 하락이 좀 있었습니다.

그래서, 아예 2019년도를 Unlabeled로 활용하고 대회 데이터를 레이블이 있는 데이터로 활용해서 Semi-Supervised 모델인 FixMatch를 적용했습니다. (FixMix는 오타입니다...) 성능을 보시면 알겠지만 Public의 경우 0.896으로 기존 0.902에 비해서 많이 낮게 나왔는데, Private에서 0.900으로 단일 모델 중 가장 높게 나온 모델이었습니다. 이를 보고 참 validation에 따라서 public이 잘 따르는 것을 확인했는데도 private에 이렇게 shake up 있는게 아쉬운 마음이 컸습니다.

그 외에도 중복 이미지를 제거해주기 위해서 DBSCAN을 적용했습니다. 재밌던 점이 GAP를 통해서 2D Embedding을 추출하고 이에 DBSCAN을 적용하는 간단한 방법임에도 불구하고 위의 결과처럼 굉장히 잘 나온 것을 확인할 수 있습니다.

3.4. 그 외의 실험

그 외로 성능을 높이기 위해서 시도한 내용들을 공유드리도록 하겠습니다.

첫번째로 Augmentation에 대한 부분입니다. 실제 대회를 진행하면서 가장 신경을 많이 쓴 부분입니다. 적용하는 기법에 따라서 0.875부터 0.891까지 성능이 다양한 것을 확인할 수 있습니다. 하지만, 하면서 느낀점은 Kaggle의 Notebook Augmentation 부분은 대부분 어느정도 최적화가 된 값인 것 같습니다. 많은 실험을 해도 해당 Augmentation을 이기는 조합을 찾기가 어려웠습니다.

두번쨰로는 Optimizer에 대한 부분입니다. Optimizer도 Adam 이외에도 여러 Optimizer 들을 알게되었는데, AdamP를 적용했을때 성능이 많이 상승했습니다. 하지만, 모델마다 동일하게 효과가 있지는 않았고 ViT와 RegNetY 모델은 상승한 반면에 EfficientNet은 하락했습니다.

그 이후로 Model에 대한 실험을 많이 진행했는데, 기본적으로 EfficientNet과 RegNetY가 성능이 많이 좋았습니다. 둘다 9050 이었습니다. 하지만, 나중에 Private 점수를 같이 보면 Public하고 Private간의 일관성이 없어서 Fixmatch가 가장 성능이 높은 것도 확인할 수 있고 2019을 같이 활용한게 Public은 나빠지지만 Private은 좋아지는 것을 체크할 수 있었습니다.

NFNet, VIT, Fixmatch 등의 최신 기법들도 크게 좋지는 않았습니다.

마지막으로 이렇게 만든 기법들을 전처리와 Optimizer, 외부데이터, 모델 등을 다르게 해서 총 6개의 모델을 앙상블하는 Submission1을 생성했고,

6개에서 성능이 낮게 나왔던 4개까지 합친 10개를 이용한 Submission2를 생성했습니다. 결과를 보면 Public은 904로 하락했지만 Private가 899로 높게 나와서 결론적으로 171등을 달성할 수 있었습니다. Public 908이 공개 리더보드는 13등이었는데 Private에서 많이 떨어져서 순위가 많이 하락했습니다.

4. 결론

Image Classification으로 본격적인 대회를 나가본게 첫번째인 대회였는데, 생각보다 좋은 성능을 거두기도하고 쉐이크업을 당해서 많이 아쉽기도 한 대회였습니다. 그래도 이 대회를 통해서 배운점들이 많아서 내용을 공유드리도록 하겠습니다.

4.1 대회를 통해서 배운 점

팀업을 같이 하다보니 이 부분에서 많은 이슈가 발생했습니다. 먼저, 서로간의 작업환경이 윈도우랑 리눅스로 달라서 num_workers의 문제가 발생하는 부분이 있었고 작업에 대한 히스토리를 정리하지 않아서 나중 팀원들이 따라가기 어려운 점이었습니다. 그래서, 나중 대회를 진행할때는 작업 히스토리 정리를 처음부터 시작하고 서로 코드에 대한 공유를 진행할때 돌아가는지에 대한 확인, 오타에 대한 확인 등을 더 신경쓰고 진행할 수 있게 되었습니다.

두번째로는 학습모델과 기법에 대해서 배운점인데, 대회를 하기 전에는 Knowledge Distilation도 몰랐고 Fixmatch도 무엇인지 몰랐습니다. 하지만, 팀원분이 RegNetY에 Knowledge Distilation을 시도해보고 Fixmatch 를 통해서 Unlabeled도 잘 활용한 부분에서 좋은 것을 배웠습니다.

세번째로는 Augmentation에 대해서 배운 점입니다. 세상에 이렇게 많은 Augmentation이 존재하는 줄 몰랐습니다 ㅋㅋ Mixup은 알고있었는데 여기에 Hestitation을 활용한 Mixup이 소개되었고

SnapMix라고 CutMix를 진행할때, CAM을 활용해서 Cutmix를 적용하는 SnapMix도 소개되었습니다. 둘 다 실험을 했을때는 큰 성능향상은 없었지만, SnapMix는 나중에 다른 테스크에 활용하기에 좋은 방법 같았습니다.

그 외에도 CycleGAN을 이용해서 데이터를 늘린 팀이 있었습니다. 이전 캐글의 손글씨 분류 대회에서 CycleGAN으로 생성이미지를 만들어서 1등을 달성한 팀이 있었는데, 그때의 방법을 이용해서 생성이미지를 만들었고 이미지를 보면 굉장히 잘 만들어진 것을 볼 수 있었습니다.


그 외에도 Loss와 Optimizer를 많이 알게되었는데, Loss만 해도 아래와 같이 6개에 대해서 알 수 있었습니다.

  • Focal Loss
  • Focal Cosine Loss
  • Symmetric Cross Entropy Loss
  • Bi-Tempered Loss
  • Label Smoothing
  • Taylor Cross Entropy Loss

4.2 아쉬웠던 점

이때, GPU 부족 및 생각의 부족으로 코드는 만들었지만 실험은 하지 못했었던 내용들이 있어서 아쉬움이 많았습니다. 아는 분의 GPU를 사용하고 있었는데 이게 끊어지면서 실험을 하지 못했고, 생각만 해보고 시도하지 못한 기법들이 있어서 아쉬움이 많았습니다.

  • 실험1. 초기 몇개의 에폭은 간단한 Augmentation을 진행하고 후반의 에폭은 mixup이나 fmix와 같은 복잡한 Augmentation을 수행하는 방법
  • 실험2. OOF를 이용해서 LGBM과 같은 머신러닝 모델 돌리는 방법 : 2019년도가 같이 사용되는 모델도 있고 그렇지 않은 모델도 있어서 Validation이 다르니 따로 OOF를 저장안했는데, 다른 솔루션 중에 2020년도만 Validation으로만 사용해서 OOF를 모으고 해당 값들로 CV 체크와 머신러닝 모델 적용한 솔루션이 있었음
  • 실험3. 실험2에서 Validation에 대한 생각을 잘못해서 현재 모델에 대한 분석을 제대로 하지 못한 점
  • 실험4. 모델에 대한 이해를 통해서 모델을 직접 수정을 많이 못해본 점

그래도 이번 대회를 시작으로 이미지 컴피티션에 본격적으로 참여할 수 있어서 좋았습니다. 비록 하면서 아쉬운 점도 많았고 Shake Up으로 순위도 많이 내려갔지만 이를 바탕으로 다음 대회에는 더 높은 성능을 달성해보도록 노력해보겠습니다. 관련해서 코드를 보고 싶은 분은 https://github.com/choco9966/Cassava-Leaf-Disease-Classification 의 링크를 참고하시기 바랍니다. 이번 대회에서 나온 다른 팀의 솔루션은 다음 포스팅에서 작성하도록 하겠습니다.