Deep learning và bài toán Face Recognition

deep-learning
face-indentification
one-shot-learning
triplet-loss

#1

Nhận dạng khuôn mặt là gì???

Trong phim ta hay thấy những tình huống hết sức magical ví dụ như 1 nắc cơ zoom hình lên 1 triệu x, ấn ấn vài phát rồi hình nét như chụp bằng Leica ! Hay magical hơn như là ấn ấn mấy cái là load toàn bộ camera an ninh của một thành phố và tìm ra ai đó bằng vài cái nhấp chuột:

Phương pháp thực hiện Face Recognition với Facenet

Để hiểu cho đơn giản CNN hay Mạng neuron tích chập gồm các lớp tích chập sẽ thực hiện các thao tác tách feature của một hình ảnh ra và sau đó sử dụng một mô hình máy học khác như kNN hoặc SVM để phân biệt người này với người khác. Cách thực hiện này là one-shot learning, CNN chỉ đóng vai trò extract feature, việc huấn luyện CNN ở đây là khiến nó tách đặc trưng tốt hơn. Ta cũng có thể thực hiện huấn luyện một CNN với số đầu ra là số người, nhưng điều đó rất khó khăn, đòi hỏi thay đổi cấu trúc mạng và việc thu thập dataset cũng mất thời gian hơn, còn có thể mất cân bằng bộ dataset. Facenet, thực chất là một CNN có nhiệm vụ tách các đặc trưng của một ảnh mặt. Điểm đặc biệt tạo nên sự khác biệt của Facenet là nó sử dụng hàm lỗi Triplet để tối thiểu hóa khoảng cách giữa các gương mặt tương đồng và tối đa hóa khoảng cách đến những gương mặt không tương đồng, vì vậy facenet có thể phân biệt rất chính xác người với người. Quá trình train CNN được thực hiện trên các bộ dataset lớn (ví dụ như vggface hoặc MS 1 million), kết quả ta muốn là tập embedding vector ra phải tách nhau ra thành từng cụm để thực hiện phân loại bằng kNN hoặc SVM. Quá trình training dựa trên triplet loss như sau: Tiền xử lý data: Chú ý là các bộ dataset kể trên thường có dạng là các folder với tên là tên của một người, trong folder là hình của người đó, mỗi người tầm 100-1000 hình, một bộ data thì khoảng vài nghìn người

  1. Sử dung một bộ face detector để tách phần ảnh có gương mặt người ra. Các phương pháp hiện đại sử dụng MTCNN (Multi-task Cascaded Convolutional Networks), ưu điểm là mô hình này detect được gương mặt ở nhiều góc độ, và có thể nhận diện cả face landmark với thời gian xử lý khá tốt. Vì mục tiêu của bài viết không đi sau vào MTCNN nên đây là link paper: https://kpzhang93.github.io/MTCNN_face_detection_alignment/index.html. Sau đó ta resize hình lại một kích cỡ xác định (tùy chọn), facenet thì là 160x160, gần đây thì arcface dùng cỡ 112x112, việc chọn cỡ này là tùy theo yêu cầu về phần cứng hoặc độ chính xác.

  2. Thực hiện các bước “lọc” bộ dataset. Thực tế là các bộ dataset lớn như vggface hay ms 1m đều có nhiều “nhiễu”, tức các hình không chứa gương mặt hoặc gương mặt khác với người cần xét. Vì vậy có thể dùng một mô hình nhận diện gương mặt khác để tìm và loại bỏ những hình “nhiễu” ấy. Hoặc đơn giản là ta có thể lấy clean list (danh sách các hình chuẩn) đã được lọc sẵn.

  3. Thực hiện bước normalize cho tập dataset đã chuẩn bị. Cách normalize cũng giống như cách normalize cho CNN bình thường. Các bước train: Đầu vào là tập dataset đã chuẩn bị, CNN có thể là các CNN như inception, mobilenet,… với đầu ra là embbeding vector như đã nói, embedding vector này có thể có 128 chiều hoặc 512 chiều,… tùy ý. Tóm lại ta chỉ cần lấy cấu trúc inception hoặc mobilenet, bỏ lớp cuối và thêm vào lớp embedding vector (không có activation)

  4. Forward pass trên tập data, lưu các embedding vector đã tính trên minibatch lại.

  5. Chia minibatch thành 3 phần là positive, negative và anchor, trong đó anchor là phần “neo” giống như “tâm” của cụm embedding vector, sau đó chọn phần positive là những embedding vector là cùng người với anchor, negative là khác người

  6. Tính Triplet loss là khoảng cách giữa các embbeding vector anchor và positive trừ cho khoảng cách giữa các embbeding vector anchor và negative (tức ta tìm cách làm giảm khoẳng cách từ các vector positive tới anchor và ngược lại đẩy các vector negative đi xa khỏi anchor) 35687079_2095079327439281_5082034505556951040_n Ngoài Triplet Loss còn có các biến thể của Softmax Loss như Center Loss, ArcLoss, Cosine Loss,… trong đó hàm lỗi được biến đổi cho mục đích phân cụm càng nhiều càng tốt.

    Một số hàm loss softmax và tác dụng phân cụm của chúng (paper SphereFace) Để nói kĩ về các hàm này và triplet loss, có lẽ sẽ cần một bài viết khác.

    Sau khi đã train trên các tập data lớn thì kết quả đạt được là một CNN có thể tách được các đặc trưng hữu ích để phân loại gương mặt. Lúc này để nhận diện người với người ta cần các bước: Huấn luyện:

    1. Tạo một bộ dataset khác cho đối tượng mình muốn nhận diện.
    2. Lưu bộ dataset đó theo cấu trúc như bộ dataset lớn đã train (để dễ tính lại các embedding vector), cấu trúc là thư mục chứ ảnh của cùng một người - một người tầm 10-20 ảnh, chú ý là đủ các góc độ sẽ cho hiệu quả hơn.
    3. Tính embedding vector cho tập đã thu thập, lưu các embedding này vào file nào đó (tùy chọn)
    4. Huấn luyện kNN hoặc SVM trên tập vector để phân loại người với người.

Thực hiện trong thực tế:

  1. Sử dụng một model face detector nào đó để tìm bounding box của gương mặt (các mô hình hiện đại sử dụng MTCNN, còn OpenFace dùng Dlib detector) chú ý là face detector phải giống với face detector được dùng cho quá trình train mới cho kết quả chính xác
  2. Cắt phần gương mặt đã tìm được ra, resize lại và thực hiện prewhiten (bước normalize data)
  3. Đưa vào CNN đã train để tính ra được embbeding vector.
  4. Dùng kNN, SVM, hoặc so sánh khoảng cách để tìm “cụm” mà embedding vector đó thuộc về, từ đó suy ra danh tính người được chọn image Bước tiền xử lý Bước thực hiện nhận dạng Tóm lại đó là cách facenet hay FaceID hoạt động, trích đặc trưng và so sánh. Tất nhiên nói luôn dễ hơn làm, để thực hiên một hệ thống an ninh bằng gương mặt cần đầu tư thời gian và công sức rất nhiều.

Reference

[1]https://github.com/davidsandberg/facenet github của facenet, bạn có thể tham khảo cách train triplet loss và center loss, huấn luyện SVM trong wiki của github

[2]https://arxiv.org/abs/1503.03832 Paper của facenet

[3] SphereFace: https://arxiv.org/pdf/1704.08063.pdf

[4] CosFace: https://arxiv.org/abs/1801.09414

[5] ArcFace: https://arxiv.org/abs/1801.07698

[6] https://github.com/deepinsight/insightface github chứa bản implement của các paper face recognition mới trên Mxnet, cũng có một số bộ dataset trong dataset zoo

[7]https://arxiv.org/abs/1703.07737 In Defense of the Triplet Loss for Person Re-Identification đây là một paper nói rất rõ về triplet loss


#3

Mình cũng đã từng làm qua Face Recognition với FaceNet, một điều khó khăn khi sử dụng các embeddings đưa vào một classifier SVM đó là việc set ngưỡng để nhận diện khuôn mặt không thuộc trong dataset (“unknow”). Mình có tạo 1 class tên là unknow chưa ảnh những người không thuộc trong dataset, nhưng mình không chắc chắn là lấy bao nhiêu người với số lượng ảnh bao nhiêu là tốt. Nếu bạn có kinh nghiệm trong việc này thì chia sẻ để mình học hỏi. Cám ơn.


#4

Với kinh nghiệm của mình thì lấy 1 class khoảng 10-20 ảnh, trong đó có thật nhiều góc độ, chú ý là phải nhiều góc độ khác nhau, và đưa vào SVM, mình chọn một ngưỡng Threshold co SVM, nếu accuracy của SVM không qua ngưỡng threshold đó thì cho là Unknown, cách này có thể hạn chế tỉ lệ true negative.


#5

Mình có dùng openface để nhận diện mặt của từng người. Nhưng bị một vấn đề là model rất dễ bị confusion giữa những người với nhau khi đặt trong một môi trường thực tế( ví dụ camera giám sát). Làm thế nào để cải thiện vấn đề này.?. Mặc dù đã set ngưỡng khá cao.


#6

Thêm nhiều pose khó vào đi bạn, openface dùng dlib thì hơi khó khăn khi nhận mấy pose khó, bạn có thể thử mtcnn hoặc dùng facenet


#7

Nếu đặt trong thực tế thì vị trí đặt của camera khá cao với xa so với khuôn mặt. Nên việc classification trong trường hợp này khá dễ bị nhầm lẫn. Mà thôi cứ thử cái đã. Thank bạn.!


#8

Ảnh đầu tiên bị lỗi không xem được bạn ơi.


#9

Cảm ơn bài viết của bạn, tuy nhiên mình thắc mắc là cách chia 3 phần positive, negative và anchor như thế nào nhỉ? Tại sao lại gọi là positive, negative và anchor. Mình đang hình dung nó mỗi cái là 1 tấm ảnh hay 1 vector gì đó.

“negative là khác người”: khác ở đây là khác mặt người A với mặt người B hay không phải ảnh mặt người (nhiễu mục 2?)

Với lại có một chỗ trình bày bị lỗi tí, chỗ này phải xuống dòng thì phải và đánh index lại vì mục 5-8 khá giống 1-4 (mình có highlight màu đỏ)


#10

Cảm ơn bạn đã trả lời, về vấn đề positive, negative,anchor được chọn sau khi forward pass thì đầu tiên ta tính ra được embedding vector, ta mới thực hiện bước chọn triplet:

  1. Chọn ra một người trong batch, chọn một embedding vector làm anchor
  2. Chọn ra các gương mặt khác của người này, chọn embedding vector của người đó làm tập positive, số lượng thì tùy vào batch
  3. Chọn ngẫu nhiên hoặc có chọn lựa các cặp negative (chính xác là tùy vào loại của triplet loss). Có thể chọn các cặp vector có khoảng cách lớn nhất đến anchor hoặc là chọn tất cả các căp negative có thể, cái này tùy vào loại loss, và nó có ảnh hưởng đến độ chính xác Nhiễu là các hình không phải mặt và cũng không đóng góp vào quá trình train. Thực chất khi mình tìm hiểu cái repo của facenet thì thực chất là ông tác giả không xài triplet loss nữa :smile: chủ yếu do nó khó train (cách chọn triplet có ảnh hưởng nhiều đến độ chính xác), việc train triplet loss mất 30 tiếng trên titanX, nên tác giả đã xài softmax và center loss :wink: do bài này cũng dài nên mình định sẽ có bài sau để nói rõ hơn về triplet và softmax :smile:

#11
  • Thứ nhất, nếu dùng embs cho recognition thì mình nghĩ bài toán chọn ngưỡng này không phải là dễ dàng, bợi vì khi bạn dùng 1 classifier SVM -> bạn phải train lại mỗi khi dataset của bạn thêm người -> điều này làm cho ngưỡng của SVM cũng thay đổi nên mình nghĩ phải có một bước train ngưỡng này. Mình có tham khảo các vấn đề trên github về mảng này mình cũng thấy chưa có một phương pháp nào thuyết phục cho ngưỡng.
  • Thứ hai, mình nghĩ triplet loss này được thiết kế nhằm mục đích cho bài toán face verification chứ không phải recognition, có nghĩa là khi dataset mặt người trong một hệ thống ngày càng tăng thì cũng không cần train lại.
  • Cái này là theo mình hiểu, các bạn có ý kiến gì cho mình biết để mình học hỏi?

#12

*Hiện tại thì mình cũng chưa thấy cách nào chọn threshold cho khả dĩ được ngoài kinh nghiệm, hoặc la fkeets hợp các phương pháp cả, cũng mong có ai đó giúp mình trả lời câu hỏi này. *Còn về triplet loss thì như paper In Defense of the Triplet Loss for Person Re-Identification đã nói rất rõ rồi, nhiệm vụ của nó là cluster các vector lại thành các cụm, và nó khá khó train, tính đến nay có khá là ít paper xài thành công triplet loss, các phương thức state of art hiện nay dùng biến thể của softmax, và nếu cần thì train thêm một chút bằng triplet để “khóa” các cụm lại chặt hơn.


#13

Bài toán nhận diện người unkown là bài toán openset. Bạn có thể tìm hiểu giải thuật EVM hoặc openmax


#14

Chào bạn @Tung_Trinh mình là Cao Thanh Hà (admin của forum), do quá trình setup có sự cố nên bị mất ảnh đính trong bài này của bạn. Xin được bạn giúp đỡ bằng cách upload lại các ảnh bị mất trong bài viết này. Xin cảm ơn bạn rất nhiều!


#15

Cám ơn bạn @vanhoa đây là cái mình đang tìm ^^


#16

Nếu dùng phương pháp này thì có cách nào để phân biệt ảnh và mặt người thật không ạ


#17

mình nghĩ là không phân biệt được, cần thêm mô hình chống giả mạo


#18

Anh @Tung_Trinh cho em hỏi chút là:

  1. Sau khi qua CNN và embedding layer thì là sao để chọn positive, negative và archor nếu bài toán mỗi người chỉ có 1 ảnh vậy?
  2. Em có đọc về facenet và có phần chọn hard negative và hard positive thì việc chọn này có giúp nhiều cho bài toán của mình khi train ở batch rất nhỏ k ạ?

#19

@Dung_Doan_Viet theo mình nghĩ thì việc chọn hard negative và hard positive nhằm tăng cường việc học nhằm phân biệt được các khuôn mặt mà khá giống nhau và việc này sẽ làm giảm size của batch bạn lại tùy theo ngưỡng. Nên khi batch của bạn rất nhỏ thì việc train sẽ lâu hơn.


#20

thế tức là việc tìm hard negative và hard positive sẽ được thực hiện trên toàn bộ dữ liệu chứ không phải từng batch ạ?


#21

@Dung_Doan_Viet Tùy vào triplet bạn dùng là offline hay online nữa bạn. Nếu là offline thì tính trên toàn bộ dataset, ngược lại online thì bạn chỉ tính trên 1 batch. Mình nghĩ nên chọn online triplet vì khống tốn nhiều bộ nhớ như offline.