[AIVIVN-Face Recognition] 3nd solution


#1

3st solution - face recognition challenge https://www.aivivn.com/contests/2

Xin chào mọi người,mình là Nguyễn Văn Tài , mình xin chia sẻ source code và solution cho cuộc thi nhận dạng người nổi tiếng.

  • source code : https://github.com/vipcualo/AIVIVN2 Tổng hợp các pretrained model mình đã sử dụng ở đây : https://drive.google.com/file/d/1NC1-clFQjSV98QkzFBm7nlAQHC8SBuOv/view?usp=sharing ( Các bạn có thể tự tải ở repo tác giả ở từng model ) Các bạn tải về và cho vào source code để run file với các option mặc định

    *Environments:

    • ubuntu 16.04

    • python 3.6 hoặc 2.7 ( mình lưu embedding file bằng python 3 nên nếu bạn nào dùng python 2 thì phải tự chạy lại nhé )

    • opencv

    • mxnet

    • faiss

    • Có thể dùng google colab để chạy code

  • Quá trình làm : Toàn bộ model của mình bao gồm:

      + tập train . detect face -> align face -> face embedding -> select threshold and get train embedding file
    
      + tập test  detect face -> align face -> face embedding -> get test embedding file. Rồi dựa vào train embedding file, cùng threshold đã chọn và dùng voting cho ra kết quả.
    

*** Dữ liệu :** + Tất cả các ảnh đều có kích thước 127 x 127 hoặc 181 x 181, nhiều ảnh trong dataset rất mờ , không có face trong ảnh. ( ảnh vẽ , …) + Train : 4720 ảnh, 84 class chỉ có 1 ảnh + Test : 17091 ảnh

  • Face detection : Thuật toán face detection mà vẫn hầu hết các source face recognition đều dùng là mtcnn vì độ chính xác tương đối và rất nhanh. Tuy nhiên vì trong dataset có rất nhiều mặt trong ảnh rất mờ, cúi xuống nên mình đã chọn thuật toán có độ chính xác cao hơn là Single Stage Headless Face Detector . Link https://github.com/deepinsight/mxnet-SSH . Pretrain model : https://github.com/deepinsight/insightface/wiki/Model-Zoo 61 Vì tất cả các bức ảnh đều có kích thước hoặc 127 x 127 hoặc 181 x 181 , khá nhỏ nên để ssh detector detect face tốt với dataset này thì mình phải chỉnh scales=[500, 800, 1200, 1600] ( detect tốt trong nhiều kích thước face ) thành [100, 200, 300, 400] ( detect face tốt trong dataset này ) và giảm threshold xuống 0.2. Kết quả là so với mtcnn ( giữ nguyên threshold các mạng mtcnn ) ( hơn 600 ảnh ko detect đươc face trong test và 200 trong face ) thì model của mình 59 ảnh ko detect được trong test và 7 ảnh trong tập train

  • Face alignment : Để align face mình đã dùng thuật toán mtcnn nhưng ko phải cả mạng mà là 1 phần , mtcnn bao gồm 4 mạng con liên tiếp : Pnet, Rnet, Onet, Lnet . Mình sẽ không nói kĩ model mtcnn ở đây vì không phải mục đích của bài này ,mình sử dụng 2 mạng con phía sau Onet và Lnet, mục đích của 2 mạng này là detect ra 5 landmark và refine lại . Tuy nhiên vì tính chất dataset nên ở mạng Onet mình cũng giảm threshold từ 0.8 ( origin) xuống 0.5. Mtcnn : https://github.com/deepinx/mtcnn-face-detection Ngoài ra các bạn có thể tham khảo hơn một số model align face rất tốt như wingloss, …

  • Face embedding : Mình chọn thuật toán arcface làm model face embedding ( LResNet100E-IR,ArcFace@ms1m-refine-v2) . Đây là pretrained model đã được training với vài triệu ảnh nên model đã học được khả năng đặc trưng ( general ) là rất tốt. Việc training lại model với dataset này mình nghĩ sẽ cho kết quả không tốt.

    Link : https://github.com/deepinsight/insightface Pretrained model : https://github.com/deepinsight/insightface/wiki/Model-Zoo Các bạn có thể khảo sát về các model face recognition hiện tại ở đây : https://arxiv.org/pdf/1804.06655.pdf Vì mình không có thời gian và cơ sở gpu mạnh nên mình chỉ dùng 1 model face embedding arcface Lresnet100 ở đây và ko ensemble model

    • Tạo file embedding :
    • Với những bức ảnh trong tập training mà ko detect được face thì mình sẽ loại bỏ và ko dùng những embedding này để phân loại cho tập test ( 1 embedding sai ở tập train có thể dẫn đến nhiều bức ảnh tập test bị phân loại sai và giảm kết quả đi nhiều ) . Ngoài ra khi tạo file train embedding để dự đoán cho tập test, với mỗi bức ảnh trong tập train mình augment lên bằng cách lấy ảnh đối xứng qua gương( để chọn threshold thì ko dùng augment này )

    • Còn với những ảnh trong tập test mà ko detect được face, mình vẫn tạo embedding cho những bức ảnh này bình thường bằng cách xử lý ảnh về đúng yêu cầu đầu vào của model face embedding, thêm được điểm nào hay điểm đấy. .

             python get_train_embedding.py --file-output train_sort_v100_ssh_flip.pkl  --image-folder vn_celeb_face_recognition/train/ --gpu-index 0 --flip 0 
      
             python get_train_embedding.py --file-output train_sort_v100_ssh_flip.pkl  --image-folder  vn_celeb_face_recognition/train/ --gpu-index 0 --flip 1  ( flip image )
      
             python get_test_embedding.py --image-folder vn_celeb_face_recognition/test/  --gpu-index 0 --file-output test.pkl --sample-submission-file  vn_celeb_face_recognition/sample_submission.csv --gpu-index 0
      

      nếu không có gpu : --gpu-index -1

  • Chọn ngưỡng và cách voting: Ở đây có thể chọn threshold theo cách của a Khôi Tuấn Nguyễn : https://www.kaggle.com/suicaokhoailang/aivivn-celebs-re-identification-baseline/?fbclid=IwAR0L7uDaqEK7PDoaRYQX01vRJSDAJ_dv3YAI5lqxPcavAwWaiVh8rOmKeA8. Nhưng mình đã chọn threshold bằng tính điểm mỗi threshold với tập training dataset và chọn threshold có kết quả cao nhất.

    • Thresholds mình chọn nằm từ np.arange(0.8, 1.4, 0.02)
    • Với mỗi threshold, mình dùng tập training data để tính điểm. Trong tâp training data, mình lọc ra random 20 class và dùng thêm 84 class ( chỉ có duy nhất 1 ảnh trong mỗi class ) làm class unknown . Với mỗi bức ảnh trong tập training, mình chọn ra 15 bức ảnh khác trong tập training mà khoảng cách euclidean distance giữa embedding là gần nhất, rồi từ 15 ảnh này mình chọn ra 15 predictions ( tuy nhiên sẽ chèn class 1000 vào trước vị trị nào mà euclidean distance bé nhất nhưng lớn hơn threshold ). Về công thức voting 15 predictions để chọn ra 5 class cuối cùng : Mình dùng bằng cách voting theo cộng nghịch đảo của chỉ số trong 15 predictions này, rồi chọn 5 class điểm cao nhất. Từ đó tình điểm tập training trên từng threshold . Ngoài ra mình đã thử thay bằng voting bằng cộng nghịch đảo chỉ số euclidean distance, tuy nhiên kết quả không tốt.
    • Sau 5 lần test như vậy thì mình thấy với threshold =1.16 1.18 1.20 1.22 sẽ cho ra kết quả tốt nhất( chênh lệch trên public test là ko đáng kể ) và mình đã chọn threshold=1.22
    • Việc dùng voting ở trên giúp mình tăng kết quả trên public test từ 93.785 lên 94.303

    python find_threshold.py --train-embedding-file train_sort_v100_ssh_v2.pkl

  • Verify dữ liệu : Trong quá trình xem lại những ảnh training mà model của mình dự đoán sai, thì mình thấy rất nhiều ảnh mà model của mình dự đoán đúng, và label sai. Nên ở đây mình đã nghĩ ra một số trick để lọc lại dữ liệu training : Nếu 2 bức ảnh khác class mà euclidean distance < 0.7 thì mính sẽ lọc lại ( euclidean distance mà bé hơn 0.7 thì gần như mặt trong 2 bức ảnh rất giống nhau ) , việc gán nhãn label cho 1 trong 2 ảnh sai là kết quả rất cao. . Các bạn có thể xem kết quả ở file ipynb ở đây : https://github.com/vipcualo/AIVIVN2/blob/master/solution/clean_data.ipynb x1 x2 x3

    • Nhưng vì thời gian dành cho cuộc thi không nhiều và mình đang làm đồ án nên mình chỉ viết file scripts nhưng không dành thời gian ngồi lọc được, khá tiếc vì nếu ngồi lọc thì kết quả khả năng sẽ tăng lên :)) . Trong các bài toán thực tế thì nghĩ ra trick để lọc lại dữ liệu với những gì đang có là khá quan trọng vì mình không thể ngồi xem lại toàn bộ data ( không khác gì làm lại nhãn ) .
  • Lấy kết quả . python get_result.py --train-embedding-file train_sort_v100_ssh_v2_flip.pkl --test-embedding-file v100_ssh_test_embedding.pkl --output-file final-submit.csv --threshold 1.22

Xin cảm ơn BTC và nhà tài trợ rubikAi đã tạo ra cuộc thi này để mọi người có thể học hỏi lẫn nhau và trau dồi thêm kiến thức .


#2

Cảm ơn bác. Rất xứng đáng. (3rd*)


#3

bạn chia train/test/dev như nào thế ạ ?


#4

Model mình không training gì nên mình không chia bạn nhé.


#5

Bạn ơi cho mình hỏi face_embedding bạn trích ra vetor 128D phải k ạ


#6

ko phải bạn . 512 bạn nhé


#8

Như luật ban đầu không được public nên bạn liên hệ ban tổ chức nhé .


#9

mở mang tầm mắt, cách làm rất hay ạ


#10

Ok ạ, mình cũng không theo dõi cuộc thi nên cũng không biết ạ, cảm ơn bạn nhé!


#11

mình k hiểu lắm: " Verify dữ liệu : Trong quá trình xem lại những ảnh training mà model của mình dự đoán sai" . bạn bảo cách bạn ko chia train/test vì ko training, nhưng làm sao bạn đánh giá đc kq ? bạn đánh giá bằng chính tập ban đầu nhỉ ?


#12

Vỡi mỗi bức ảnh trong tập training nhé, bạn coi bức ảnh đó chính là tập test, và n-1 bức ảnh còn lại trong tập train là tập train, rồi bạn phân loại bức ảnh này bằng thuật toán của mình .


Tổng kết cuộc thi 'Nhận diện người nổi tiếng' trên AIviVN
#13

Trong bước face alignment thì mấy cái đoạn code như dưới đây nó làm cái gì hả bạn. Mình thử tìm face alignment implement trên mạng nhưng không thấy có giải thích cũng như code kiểu này nên không hiểu nó làm cái gì chỗ này.

src = np.array([ [30.2946, 51.6963], [65.5318, 51.5014], [48.0252, 71.7366], [33.5493, 92.3655], [62.7299, 92.2041] ], dtype=np.float32)