Viết engine phân loại hình ảnh bằng neural network một cách dễ dàng (Python + Tensorflow)

image-classification
deep-learning
transfer-learning

#1

Nhu cầu của dự án bọn mình sắp làm như sau: user upload một tấm ảnh, phải phân loại được ngay ảnh đó là ảnh chụp món đồ nào. User vẫn có thể chọn lại trên giao diện, nhưng vì muốn user cảm thấy thật dễ dàng nên càng bớt các bước thao tác cho họ càng tốt.

Một chút lý thuyết

Để giải quyết nhu cầu này, mình thử Google thì ra được cách dùng Convolution Neural Network (CNN). Nhưng vấn đề là với một thằng data engineer như mình thì chuyện viết từ đầu một cái CNN khá là phê, ngoài ra mình thì rành về dataflow các kiểu chứ cũng không rành thuật toán nên tiếp tục Google để xem có cái nào đơn giản hơn mà mình có thể hiểu được hay không.

Hóa ra chính Google có hướng dẫn cho chúng ta rồi, và đó là giải pháp cực kì hữu dụng trong rất nhiều trường hợp: Transfer Learning.

Bình thường khi bạn train từ đầu các model (mô hình, mà mình thích dùng chữ model hơn) nhận diện hình ảnh, bạn sẽ cần rất nhiều sức mạnh từ máy tính. Nếu không có GPU khủng, nói chung là cấu hình mạnh thì sẽ mất rất nhiều thời gian. Chưa kể việc bạn phải viết từ đầu cũng là một thứ không chắc là hay trừ khi bạn cần phải tối ưu nó một cách cụ thể.

Thế nên người ta mới nghĩ tới Transfer Learning, nó là kĩ thuật giúp rút ngắn thời gian (và sức mạnh máy tính) cần thiết để train model bằng cách sử dụng một model nền có sẵn, tạm gọi là model được train gần hoàn chỉnh, sau đó train thêm chút xíu nữa bằng data của riêng bạn để có thể phân loại theo ý bạn muốn. Việc này giống như có ai đó đào móng, dựng cốt thép bê tông sẵn cho bạn rồi, bạn chỉ việc lên xây cái nhà theo ý thích của mình là được.

Bài hướng dẫn mình xem trên Google sử dụng ImageNet làm nền. Đây là một database cực lớn về phân loại hình ảnh đã được Google phát triển một thời gian. Nó đã được train sẵn với 20 nghìn loại (category) hình ảnh khác nhau, chúng ta chỉ cần tận dụng nó thêm một bước nữa để áp category mà bạn muốn vào là được (thay vì chỉ dùng category do Google cung cấp).

Tất nhiên, việc bạn xài một giải pháp có sẵn sẽ không bao giờ có thể tốt như việc bạn từ làm từ đầu, model cũng thế. Nhưng không phải lúc nào bạn cũng cần tới mức phức tạp như vậy, đôi khi chỉ cần việc nó chạy là ngon lắm rồi, và tình huống của mình là như thế đấy. Độ chính xác tầm 70-80% là đã cực kì hiệu quả và giúp cho user của mình nhiều lắm rồi.

Kiểu transfer learning này cũng cho phép bạn train vài nghìn tấm ảnh bằng chính laptop của mình, ngay cả khi nó không có GPU rời. Cho nhu cầu cơ bản và để học, tìm hiểu thì quá tuyệt vời.

Bắt tay vào chiến

Hơi tiếc chút là bộ data mình dùng để train thực tế không share được, nên để cho bài viết này thì mình dùng một tập train do chính Google cung cấp: http://download.tensorflow.org/example_images/flower_photos.tgz. Tập này bao gồm ảnh của các loài hoa, và nhiệm vụ của bạn là phân biệt ảnh nào là hoa gì.

Những thứ khác cần chuẩn bị:

Tensorflow, cài bằng: pip3 install --upgrade "tensorflow==1.7.*"

Clone repo chứa code về:

git clone https://github.com/googlecodelabs/tensorflow-for-poets-2
cd tensorflow-for-poets-2

Chép các file ảnh lúc nãy bạn đã download vào thư mục tensorflow-for-poets-2/tf_files/flower_photos

Chạy train:

python3 scripts/retrain.py --output_graph=tf_files/retrained_graph.pb --output_labels=tf_files/retrained_labels.txt --image_dir=tf_files/flower_photos

Chúc mừng, vậy là bạn đã chạy được một neural network training ngay trên máy của mình rồi :smiley: sướng nha.

Cách test lại với ảnh mới:

Bạn kiếm trên mạng một tấm ảnh về hoa bồ công anh mới hoàn toàn, sau đó chép xuống cùng thư mục tensorflow-for-poets-2 là chạy lệnh để engine nhận diện ảnh bạn mới download thuộc loại nào:

python3 scripts/label_image.py --image image.png

Nếu lỗi The name import / input refers to an Operation not in the Graph thì làm như sau: mở file label_image.py, sửa dòng

input_height = 224
input_width = 224
input_mean = 128
input_std = 128
input_layer = "input"

thành

input_height = 299
input_width = 299
input_mean = 0
input_std = 255
input_layer = "Mul"

Lưu file, chạy lại lệnh ở trên là xong. Bạn sẽ thấy kết quả dạng dạng như sau (mình dùng ảnh của mình nên category hơi khác với các bạn chút):

Evaluation time (1-image): 0.944s

phone (score=0.82035)
watch (score=0.10135)
cloth (score=0.04695)
furniture (score=0.02881)
motobike (score=0.00183)

Giải thích các khái niệm mà script sử dụng

Trong khi chờ neural network nó chạy train thì mình sẽ giúp bạn hiểu hơn về những thứ mà script đang làm nhé.

Bottleneck

Bước 1 khi bạn chạy script, bạn sẽ thấy script sinh ra nhiều file gọi là bottleneck. Bottleneck là từ được sử dụng để chỉ lớp train cuối cùng trước khi xuất ra kết quả phân tích thật sự. Bạn có thể xem các file này giống như các phiên bản thu gọn của mỗi tầm hình bạn chuẩn bị đưa vài train, và thay vì phải chạy đi chạy lại mỗi lần thì giờ script xuất sẵn thành một đống file nằm đó để truy xuất cho nhanh. Nếu đang chạy mà bạn bị đứt giữa chừng, ví dụ khi bị cúp điện, thì lúc khởi động lại script nó sẽ chạy tiếp chứ không chạy lại từ đầu.

Đoạn này trên Google thấy hay, trích lại cho các bạn xem:

Lớp gần cuối này đã được train để xuất ra một tập các giá trị đủ tốt để engine phân loại có thể phân biệt được giữa các lớp mà bạn đang yêu cầu nó nhận diện. Các file bottleneck chứa những thông tin tổng hợp đủ tốt, có thể xài được của hình ảnh.

Này là video mình quay lại 1 đoạn script đang chạy

Giai đoạn training

Khi các file bottleneck được tạo xong, script sẽ bắt đầu quá trình training. Trên cửa sổ dòng lệnh của bạn sẽ là hàng loạt các dòng chữ thể hiện từng bước train, có cả độ chính xác nữa. Các thông số này mình chỉ hiểu mỗi accuracy, còn những thứ như validation accuracycross entropy thì không hiểu nên thôi để dành lại cho các bạn khác giải thích :smiley: sẵn mình học ké luôn.

Mặc định script sẽ chạy 4000 step để train. Mỗi step nó lựa ra 10 ảnh bất kì từ tập training data, lấy file bottleneck từ cache lên và đưa vào dự đoán. Mỗi ảnh được dự đoán sẽ đem đi so với label (chính là tên folder chứa các file ảnh) để xem độ chính xác bao nhiêu.

Next step

Sau khi train xong model, bạn sẽ có một file *.pb, cỡ 80MB. File này chính là model của bạn, và nó sẽ được reuse dễ dàng trong code khi bạn deploy lên production. Ví dụ, user upload tấm ảnh mới thì bạn sẽ gọi model này từ disk hoặc RAM để tiến hành nhận diện. Cái này dính tới back-end system nhiều hơn nên thôi mình sẽ không nói sâu hơn nữa.

Hai nguồn mình tham khảo cho việc học transfer learning: https://towardsdatascience.com/training-inception-with-tensorflow-on-custom-images-using-cpu-8ecd91595f26https://www.tensorflow.org/hub/tutorials/image_retraining. Bạn nào cần thì đọc kĩ hơn nhé, nhất là bài viết của trang Tensorflow. Trong đó có đầy đủ khái niệm bạn cần biết.


#2

Vừa hay bài viết xong thì model cũng train xong :smiley: thôi đi integrate nó vô production cái đã


#3

Khổ nỗi là các bác ở đây chỉ hứng thú với thuật toán. T.T


#4

Đâu, có nhiều người cũng thích thực tế, áp dụng mà :smiley: như mình chẳng hạn


#5

Hehe ngon quá, mình rất thích những bài viết áp dụng vào thực tế luôn như của bác :smiley:


#6

#relax Đọc bài viết của anh cũng là một hình thức transfer learning. Mọi người đang “train” não mình bằng cách dùng bộ “weight” của anh Luân :)). Dĩ nhiên đối với e thì bộ weight này tốt hơn rất nhiều cái mà “model” của e tự luyện


#7

Ý thím là mình mập :(((((


#8

Không phải ý đó anh ạ, anh hiểu xa quá. :)))


#9

chào bạn, Trong bài viết bạn có đề cập tới cách dùng Convolution Neural Network (CNN), vậy bạn có thể cho mình xin tài liệu về CNN không, hiện tại mình đang muốn tìm hiểu về CNN. cảm ơn :slight_smile:


#11

Cảm ơn bạn. Mình đã ứng dụng chia sẻ của bạn để làm công cụ phân loại danh mục dựa vào hình ảnh, hiện tại test acc mới đạt 40%, có lẽ tập data mình còn hơi ít (~500 hình/label).

Mọi người có thể test chơi tại: https://console.thitruongsi.com/category-predict

Mình đang dùng model mobilenet để train cho lẹ & predict cũng lẹ hơn. Tuy nhiên thì acc cũng sẽ bị tệ hơn so với inception.


#12

Cảm ơn bác vì bài viết:D Em cũng đang làm phần này nhưng có vướng mắc 1 vấn đề nhỏ, mong bác cho em lời khuyên:

Khi muốn thêm 1 hoặc nhiều class vào nữa. thì có cách nào để không phải train lại toàn bộ dữ liệu k ạ:D


#13

Này mình thua :smiley: chắc phải train lại hết quá vì thêm label là chuyện nghiêm trọng


#14

Cảm ơn anh vì bài chia sẻ này. Em có thắc mắc, mong được anh giải đáp. Có cách nào để nó kiểm tra nếu input đưa vào không thuộc bất kì dataset nào thì nó sẽ báo, ví dụ như báo “unknown” không anh? Em thử test 1 ảnh về điện thoại trên dataset hoa thì nó cho kết quả là hoa hồng… hơi sai sai :frowning:


#15

Mình nghĩ là bạn phải set threshold, % thấp quá thì loại :smiley: chứ output nó ra thì trong dataset bạn đã dạy thôi


#16

Có thể áp dụng bài này cho nhận dạng các vật thể trong ảnh theo thời gian thực được không DuyLuan?