[Kaggle][Solution for Inclusive Images Challenge]

kaggle

#1

Mình và team vừa giành được vị trí thứ 6 / 109 team tại cuộc thi Inclusive Images stage 2, vị trí thứ 3 / 468 team tại stage 1, chỉ tiếc là top5 stage 2 sẽ được 5000$ và đi nips 2018 rồi. Mình chia sẻ solution của mình tại cuộc thi này, hi vọng có ích cho những bạn đang và sẽ tham gia trên kaggle.

Bài toán của cuộc thi này thuộc dạng multi-labeling, có nghĩa trong cùng một ảnh sẽ phải phân biệt nhiều class khác nhau. Số lượng nhãn phải phân biệt lên tới 7178.

Dataset của cuộc thi này là tập training của imagenet, tổng cộng có 1,743,042 training images. Cuộc thi này có 2 stage, stage 1 có 32580 images cho tập test và 1000 images cho tập tuning, stage 2 có 99650 images. Rule của cuộc thi này không được sử dụng các model đã được pretrain và không sử dụng bất kì data nào khác ngoài tập training để train model. Và distribution của tập training, test stage1 và test stage 2 khác nhau khá nhiều. Score của bài toán này sử dụng là F2-score

3 bước chính mình sử dụng là build strong model, stacking và optimize threshhold

Bước 1: build strong model

  • Mình chia tập training ra làm 10 phần: 9 phần cho train và 1 phần cho valid, mình không sử dụng cross validation vì lúc mình tham gia chỉ còn chưa đầy 1 tháng, để train 1tr7 ảnh sử dụng kfold là không kịp thời gian.
  • Mình sử dụng kiến trúc của 3 networks: Inception resnet v2, resnet 152 và xception. Mình modify các kiến trúc này để phù hợp với bài toán:
    • Xóa lớp dense cuối (1000 class), xóa lớp average pooling cuối
    • Thêm 1 lớp CNN layer (kernel_size = 1, filters = 7178), thêm lớp cnn này bởi lớp average pool cuối thường có kích thước 1000 - 2000, mà số lượng class của bài toán này là 7178 nên 1000-2000 features không đủ để cho model phân biệt, gọi là bottle-nect
    • Thêm 1 lớp GlobalMaxPooling2D
    • Lớp cuối là 1 dense với size 7178, activation function là sigmoid
  • Mình train 3 model này trên tập training và valid trên tập valid, loss là binary_crossentropy, optimize là adam, learning rate ban đầu là 1e-3, cứ 2 epoch valid f2 không tăng thì mình giảm learning rate xuống 5 lần.
  • Model hội tụ sau 12 - 15 epoch, để tiết kiệm tối đa thời gian mình tính f2 score với ngưỡng mặc định 0.2 cho tất cả vì để tối ưu thresh hold cho 7000 class trên 170000 ảnh, chạy multiprocessing trên 16 cpu cũng phải mất hơn 2 ngày :(( . F2 score trên tập train lúc hội tụ là 0.58, của valid là 0.61, của tập tuning (chỉ có 484 class) là 0.36. Mình submit thì f2 score trên tập test stage 1 cũng là 0.36. Có nghĩa tập tuning 1000 ảnh này cùng distribution với test stage1

Bước 2: stacking

  • Sau đó mình stack 3 model: lấy output của 3 model được 7178x3, add vài lớp cnn đơn giản ở phía sau, output là dense 7178. Mình chia tập valid làm 10 fold. Train trên 9 phần và valid trên phần còn lại. Valid f2 score sau khi stack chỉ là 0.63 trên tập sub valid, trên tập tuning vần giữ nguyên 0.36. Mình submit thì score LB cũng chỉ là 0.36

Bước 3: optimize thresh hold

  • Kĩ thuật quan trọng duy nhất với các bài toán multilabel kiểu này là optimize thresh hold. Có nghĩa với mỗi class khác nhau mình sẽ sử dụng một ngưỡng khác nhau để predict. Mình chia 0-1 thành 50 khoảng, mỗi class mình sẽ cho thresh chạy từ 0-1, chọn thresh mà f2 score maximum. Sau khi optimize thresh trên tập subvalid (7178 class) thì f2 score cho tập sub valid tăng từ 0.63 lên 0.71, tiếp tục optimize thresh hold trên tập tuning (484 class trong tập tuning sẽ sử dụng thresh này, những class còn lại sử dụng thresh đã được optimize trên tập sub valid), thì f2 score trên tập tuning của mình tăng từ 0.36 lên 0.42. Mình submit lên LB thì được score 0.41

Mình bị stuck ở giai đoạn này 1 tuần rưỡi vì không thể improve f2 score thêm nữa. Nên mình quyết định thử focus trên 484 class của tập tuning (vì thằng này cùng distribution của test stage 1), đổi lớp dense 7178 thay bằng dense 484, train lại trên tập train. Sau đó stack 3 model chỉ với 484 class này, lại tiếp tục optimize trên tập tuning thì f2 score của tập tuning là 0.50. Mình submit thì score LB là 0.486 (10th place trên ranking, top1 là 0.56)

Sau đó còn đúng 1 ngày, mình thử stacking trên tập tuning (just for fun :v vì không nghĩ nó work). Chia tập tuning làm 10 fold, train trên 9 phần và valid trên 1 phần, optimize trên phần valid này luôn, chạy đúng 10 lần với 10 fold sau cộng trung bình. Sau khi submit thì LB là 0.539 (3rd place trên stage 1 :v )

Stage 2 chỉ có đúng 1 lần chọn file submission, và không được train thêm hay tuning thresh hold. Nên chỉ có generate file submission và đợi. Cuối cùng mình và team đạt được vị trí thứ 6, tiếc là top5 sẽ được 5000$ và đi nips 2018. Thế này cũng được vì mình còn tranh thủ buổi tối thi kaggle lâu dài nên sẽ còn cơ hội


#2

Cảm ơn bạn đã chia sẻ. Chúc mừng bạn đã đạt được vị trí cao. Bạn có thể chia sẻ rõ hơn về cấu hình bạn dùng để train ko?


#3

mình dùng 2 con 1080Ti, ram 32GB, core i7 20 CPU


#4

Mình muốn chơi kaggle nhưng thấy những solution của bạn như này (về cơ bản là mình không hiểu được mấy) mà cũng chưa đạt top có thể nhận giải thấy nản quá :joy:


#5

Cảm ơn anh đã chia sẻ:slight_smile:


#6

Em là người mới bắt đầu về lĩnh vực này.Em rất thắc mắc về việc căn cứ vào đâu mọi người có thể tự build các model như vậy. Anh có thể cho em xin một số key word về vấn đề này không ạ


#7

Chúc mừng team đã lên master kaggle. Cám ơn vì bài chia sẽ. Hy vọng team tiếp tục đạt giải và chia sẽ anh em nhiều bài như thế này nữa.


#8

Em cũng muốn được giải đáp về phương pháp chọn lựa model để giải quyết bài toán ạ. Hi vọng có thể được anh giải thích hoặc cho keyword để tìm hiểu :smiley:


#9

cùng câu hỏi, mình cũng chưa hiểu sao người ta có thể tự xây dựng được các model :frowning:


#10

Tuyệt vời Dũng à! Cố lên nhé.


#11

Hi Dũng, cho mình hỏi ở bước 1 (build strong model), thì với 7178 class, tại sao activation cho lớp cuối lại là sigmoid mà không phải softmax, và trong bước train thì hàm loss lại là binary_crossentropy thay vì categorical_crossentropy?


#12

Hi Tamlt188, vì đây là bài toán multilabel có nghĩa một ảnh có thể có nhiều nhãn (ví dụ một ảnh người sẽ xuất hiện nhãn người, tóc, quần áo) nên phải dùng sigmoid để khả năng xuất hiện của các class là độc lập với nhau. Khác với bài toán classification là một ảnh chỉ đại diện cho 1 nhãn nên mới dùng hàm softmax. Dùng binary_crossentropy vì phân biệt 7178 classes trong 1 ảnh sẽ giống như chia nhỏ thành 7178 bài toán phân biệt 1 class dùng binary_crossentropy