https://www.facebook.com/groups/KaggleKoreaOpenGroup/permalink/652171618848274/

AWS, Facebook, Microsoft가 캐글 역사상 총상금 규모 세 번째인 100만 달러(약 12억원)를 걸고 개최한 DFDC(Deepfake Detection Challenge)에서 상위 1.3% (30/2265)를 달성했습니다. Public leaderboard에서는 2위로 마무리했던만큼 기대했던 금메달권에는 들지 못했지만 제 경험을 공유해드리고자 글을 작성하게 되었습니다.
들어가기에 앞서 캐글 discussion에도 대회에 참여한 여정과 솔루션을 올려 놓았으니, 궁금하신 분들은 한번 구경해보세요. (감사하게도 전체 캐글 discussion 중 upvote 20위권에 들었네요!) https://www.kaggle.com/c/deepfake-detection-challenge/discussion/140236

저는 2019년 1년동안 다양한 캐글 대회에 참여하고 간단한 토이 프로젝트들을 하면서 정형/이미지/텍스트/음성 데이터를 다루는 법과 모델의 성능과 generalizability를 향상시키는 방법을 배웠고, 다양한 종류의 tree 기반 모델, cnn, segmentation model, rnn, transformer, bert 등을 사용해보았습니다.
그러던 차에 이번 대회가 개최된다는 소식을 듣고 캐글을 통해 익힌 테크닉들을 본격적으로 활용해보고자 참여하게 되었습니다. 작년 12월~올해 3월까지 무려 4개월 동안 진행된 대회였는데 마침 시간도 나서 3개월 간은 이 대회에 메달렸던 것 같습니다.

팀을 처음으로 구성해보았는데 각자 사정 때문에 결국은 제가 대부분의 작업을 하게 되었네요 ㅎㅎ.. 캐글에서 모르는 사람들과 팀을 맺을 땐 캐글티어와 관계 없이 각별히 조심해야한다는 점을 깨달았습니다.

이제 제가 느낀 이 대회의 주요 과제들과 이에 대한 제 솔루션들을 말씀드리겠습니다.

1. 대규모 데이터: 10만개가 넘는 동영상들로 이루어진 데이터로, 500gb가량 됩니다. 한정된 컴퓨팅 자원 하에서 빠르고 효율적으로 여러 실험들을 진행하기 위한 파이프라인 구축이 필수적이었습니다.
-> 동영상에서 프레임을 n개 읽어 얼굴부분만 자르고 추출된 다른 메타데이터와 함께 compressed joblib file로 저장한 뒤, 훈련 시 multiprocessing이 적용된 dataloader에서 읽어들여 cpu-gpu bottleneck을 없앴습니다. 또한 Apex fp16을 활용하여 batch size를 두 배 가량 늘려 한 epoch의 소요 시간을 50% 가량 단축했습니다.

2. 동영상 데이터: 단순히 이미지 여러개로 보고 접근할 것인지, 프레임 간의 관계와 오디오를 활용할 것인지, 활용한다면 어떻게 활용할지에 대한 고민이 필요했습니다.
-> 프레임 간의 관계를 모델링 하기 위해 cnn-lstm을 활용해봤지만, 결과가 좋지 않았고, 3d cnn 등은 pretrained weight가 부족하고, 무거워서 시도하지 않았습니다. 오디오는 전체에서 8%밖에 조작되지 않았고, 파이프라인을 복잡하게 만들어 사용하지 않았습니다. 결국 프레임 예측값의 평균을 사용했습니다.

3. 얼굴: 결국 deepfake는 사람의 얼굴에 적용되는 것이기 때문에 얼굴과 관련된 vision 연구들을 활용해야 했습니다. Face detection은 필수로 사용해야 했고, validation split을 위한 face recognition + clustering, encoder로서 vggface2 pretrained 모델도 고려했습니다.
-> WiderFace dataset에서 좋은 성능을 보여준 Retinaface를 face detection model로 사용했습니다. 같은 사람이 train set과 validation set에 함께 등장하지 않도록 하기 위해 face recognition으로 얼굴을 encoding하고, kmeans 또는 pca+tsne+dbscan 으로 동영상들을 clustering 해봤으나, folder 기반 split보다 못했습니다. FaceNet Pytorch에서 제공한 vggface 2 pretrained inceptionresnetv1을 사용해보았으나, efficientnet보다 성능이 좋지 않았습니다.

4. train-test 차이: validation 점수와 test 점수의 상관관계가 적거나, 그 격차가 큰 경우는 캐글에서 종종 볼 수 있습니다. 이번 대회는 이러한 train-test 차이가 두드러졌습니다. private leaderboard와 public leaderboard의 격차가 상당히 큰 것도 같은 맥락으로 볼 수 있을 것 같습니다. 이 문제를 어떻게 해결할지가 사실상 이 대회의 중심에 있었습니다.
-> 랜덤, 원본 기반, 사람 기반, 폴더 기반 등으로 validation split을 시도해보고, 그나마 public leaderboard와의 격차가 적었던 폴더 기반 split을 선택했습니다. 그러나 여전히 잘 맞지 않아서 결국에는 public leaderboard, 3 종류의 외부 dataset, local validation dataset 순서로 가중을 두어 모델의 성능을 검증했습니다. 또한 아래에서 설명하겠지만, 모델의 일반화에 신경을 썼습니다.

5. 일반화: Deepfake를 만드는 사람들은 detection model의 취약점을 활용하려 할 것입니다. 따라서 특정 데이터에 overfitting되는 것을 특히 조심하고 모델을 일반화시키는 것이 중요했습니다. 나아가 adversarial attack에 대한 고려도 할 수 있습니다.
-> albumentations을 이용해 사용 가능한 거의 모든 augmentation을 비교적 강도 높게 적용하였습니다.(public leaderboard 기준으로 fine tuning) 총 10개의 모델 예측값의 평균을 취해(앙상블) 최종 예측값을 안정적으로 만들었고, 이렇게 나온 최종 예측값을 보수적으로 하기 위해 logit에 1보다 작은 상수를 곱하고 sigmoid를 취해 예측의 일반화를 도모했습니다.

6. Postprocessing: 동영상 데이터이기 때문에 프레임 예측값 외에도 오디오, face confidence score 등 다양한 feature들을 활용하여 최종 예측값을 도출할 수 있는 가능성이 많았습니다.
-> lightgbm으로 메인 모델의 예측값과 다른 feature들을 stacking해 보았으나, public score이 좋아지지 않아, 결국은 train set에 overfitting되지 않도록 postprocessing은 최소화 했고, 프레임 예측값들의 평균을 최종 예측값으로 이용했습니다.

Public leaderboard 점수를 향상시킨 주요 테크닉들을 소개해드리겠습니다. 이번 대회의 특성상 이 테크닉들이 private set에 대해서는 어떻게 작용했는지 알 수는 없네요.

1. 조작된 픽셀을 1로 둔 mask를 segmentation part target으로 두고, encoder 끝에 classification branch를둔 UNet 모델 구조 (multi-task learning) (이미지 참고) -> 어느 부분이 조작됐는지의 정보를 모델에게 줌

2. 얼굴을 추출해낼 때 얼굴 주변부도 상당 부분 포함시킴 -> cnn이 조작된 부분과 그렇지 않은 부분의 차이를 학습하는 것을 도움

3. logit에 sigmoid를 취하기 전에 1보다 작은 상수를 곱하여 예측값이 극단으로 가지 않도록 조정 -> metric이 logloss였기 때문에 train-test 차이가 컸던 이번 대회에서 test logloss를 개선시킴

4. augmentation을 강하게 적용 -> 모델의 generalizability 향상

5. 앙상블 -> 최종 예측값의 성능과 generalizability 모두 향상

6. 적절한 하이퍼파라미터와 모델 사이즈, 충분한 프레임 개수

긴 글 읽어주셔서 감사합니다!

Posted by uniqueone
,