Góc nhìn công nghệ về FVI – Hệ thống OCR nhận diện Chứng minh thư nhân dân Việt Nam

468

Bài viết chia sẻ những kinh nghiệm trong nghiên cứu, kiến trúc và giải pháp triển khai hệ thống với Tensorflow của nhóm nghiên cứu, với hy vọng làm sáng tỏ việc xây dựng và triển khai một dự án Deep Learning (học sâu) hoàn chỉnh nói chung và OCR nói riêng.

Lời mở đầu

Tác giả hiện đang làm việc trong một dự án OCR (có tên là FVI) cùng với một số nghiên cứu viên và kỹ sư Vision tại Ban Công nghệ FPT. Nhiệm vụ là trích xuất các mẩu thông tin từ thẻ Chứng minh thư Nhân dân (CMND) của Việt Nam.

Nhận thấy các tài liệu tham khảo trên internet (Dropbox, Zocdoc, Facebook) về cách xây dựng một hệ thống OCR chưa giải thích rõ ràng, hoàn chỉnh cách làm thế nào để đưa các mô hình học sâu này vào một môi trường production. Vì vậy, nhóm nghiên cứu đã có một thời gian khó khăn (khoảng 6 tháng) để xây dựng một hệ thống OCR chính xác, sẵn sàng cho môi trường production và có khả năng mở rộng được.

Trong bài viết này, tác giả sẽ chia sẻ với bạn đọc kinh nghiệm của nhóm trong nghiên cứu, kiến ​​trúc và giải pháp triển khai hệ thống với Tensorflow; với hy vọng làm sáng tỏ việc xây dựng và triển khai một dự án Deep Learning (học sâu) hoàn chỉnh nói chung và OCR nói riêng.

Hệ thống

Cấu trúc của FVI bao gồm 3 tác vụ cơ bản: Cropper, Detector, Reader. Mỗi tác vụ có một mô hình riêng và quá trình huấn luyện, đánh giá, kiểm thử cho từng mô hình. Vì vậy, có thể dễ dàng thay từng mô hình nhỏ này để cải thiện hệ thống. Điều này sẽ khiến việc kiểm soát và debug dễ dàng hơn so với một mô hình end-to-end.

structure1. Cropper

Tác vụ này xác định 4 góc của thẻ CMND và sau đó cắt về dạng ảnh chữ nhật. Ý nghĩa chính của tác vụ là phục vụ cho việc Detector liền kề sau đó dễ dàng hơn.

Các mô hình phát hiện đối tượng (object detection) phổ biến hiện nay chỉ trả về 2 góc (trái trên phải dưới, hoặc tâm box kèm giá trị chiều ngang dọc) giúp ta định hình một box hình chữ nhật. Chúng tôi sử dụng một mẹo nhỏ bằng cách coi mỗi góc của CMND là một đối tượng và sau đó phát hiện 4 góc này. Tiếp theo đó bằng cách áp dụng một vài phép biến đổi hình học cơ bản để cắt về dạng ảnh chữ nhật.

cropper

Mô hình phát hiện mà nhóm nghiên cứu đang sử dụng là bộ phát hiện đơn pha: SSD (SSD: Single Shot MultiBox Detector), với bộ trích xuất đặc trưng là MobileNet v2 (MobileNetV2: Inverted Residuals và Linear Bottlenecks).

SSD cung cấp cho nhóm nghiên cứu tốc độ truy xuất nhanh, trong khi MobileNet v2 giảm số lượng tính toán và bộ nhớ sử dụng nhưng vẫn duy trì được độ chính xác tốt.

ssd-mobilenet
Ảnh: machinethink.net.

2. Detector

Tác vụ này phát hiện các từ (gồm chữ cái hoặc số) thuộc mỗi lớp thông tin, ví dụ ở đây là số CMND, họ và tên, ngày tháng năm sinh, Nơi ĐKHK thường trú (địa chỉ). Nhóm sắp xếp các từ phát hiện được phụ thuộc vào tọa độ (x, y) và sau đó đưa vào làm đầu vào cho Reader.

detector

Nhóm cũng sử dụng SSD cho tác vụ này giống như Cropper, nhưng với một bộ trích xuất đặc trưng khác: Resnet FPN (Deep Residual Learning for Image Recognition, Feature Pyramid Networks for Object Detection)

fpn
Ảnh: arxiv.

Resnet FPN đảm bảo tính chính xác cao, đồng thời hỗ trợ nhiều thang độ phân giải của ảnh để mô hình có thể xử lý tốt với các đầu vào khác nhau.

3. Reader

Với lượng từ kèm thứ tự của chúng cho mỗi khu vực lớp thông tin, nhóm thực hiện việc truy xuất theo lô (batch) cho mô hình Reader để nhận được kết quả dạng chuỗi (string), sau đó nối chúng lại với nhau theo format phù hợp.

Mô hình được sử dụng là một mô hình OCR cấp từ, với một số chỉnh sửa nhỏ từ Attention OCR của Google (Attention-based Extraction of Structured Information from Street View Imagery), vốn được dùng cho việc OCR cho các biển tên đường phố.

reader
Ảnh: Attention OCR paper.

Đầu tiên, các nhà nghiên cứu sử dụng 1 góc nhìn thay vì 4 góc nhìn cho mỗi ảnh vì các từ được phát hiện và cắt ra chủ yếu là theo chiều dọc sau tác vụ Detector. Và dùng CNN là Inception Resnet v2 (Inception-v4, Inception-ResNet và Impact of Residual Connections on Learning) được cắt tại lớp Mixed_6a để trích xuất đặc trưng của ảnh, rồi sau đó là một lớp LSTM, cuối cùng là bộ attention giải mã.

Với hàm tối ưu, Adadelta được sử dụng cùng với learning rate ban đầu 1.0 chứ không phải là Stochastic Gradient Descent (SGD) với momentum được trình bày trong paper. Lý do chủ yếu là Adadelta điều chỉnh learning rate theo các tham số, do đó nhóm nghiên cứu không cần quá bận tâm về điều chỉnh learning rate trong quá trình huấn luyện.

Tác vụ Reader này đạt được hơn 99% với cấp ký tự và thường từ 1-2% đọ giảm với cấp từ. Hệ thống end-to-end (Cropper -> Detector -> Reader) đạt được độ chính xác khoảng 90% cho từng vùng/lớp.

Về mặt lý thuyết, nhóm có thể làm tốt hơn với một số phương pháp như dữ liệu nhân tạo, curriculum learning,…. Nhưng phiên bản công khai đầu tiên đã đạt độ chính xác có thể sử dụng và nhóm quyết định đưa vào môi trường production, sau đó cập nhật theo phản hồi của khách hàng.

 

 

Kiến trúc

Đây là một sơ đồ cấu trúc sơ lược của nhóm sử dụng trong môi trường thực tế.

architecture

Vấn đề là làm thế nào để đưa các mô hình nghiên cứu vào môi trường production.

Cách đơn giản nhất là chúng ta giữ nguyên source code, dùng trực tiếp mô hình đã được huấn luyện và viết một số hàm truy vấn bổ sung. Nhưng đây không phải là cách tối ưu. Điều này rất ngốn các nguồn tài nguyên của máy bao gồm bộ nhớ, CPU,… và dễ gây ra các truy vấn với độ trễ cao.

Một cách tốt hơn để giải quyết một phần các vấn đề trên là chúng ta “đóng băng” mô hình (Frozen Graph). Nhưng nhóm nghiên cứu muốn một cách tốt hơn nữa để dùng các mô hình được huấn luyện của mình trong môi trường production. Ví dụ như yêu cầu về các truy xuất có thông lượng cao độ trễ thấp (low-latency high-throughput), cập nhật mô hình với zero-downtime, truy xuất dữ liệu từ theo lô (batch), API nhất quán,… May mắn thay, Google có một giải pháp, đó là: Tensorflow Serving.

Tensorflow Serving

Tensorflow Serving sử dụng SavedModel với tag phiên bản. Ví dụ, ở đây có 1 phiên bản Cropper, 1 phiên bản Detector và 2 phiên bản Reader.

Và chúng ta có thể load tất cả các mô hình này vào Tensorflow Serving cùng một lúc bằng cách thiết lập một file config (ví dụ: serve.config):

Và khởi động Tensorflow Serving với flag phù hợp:

Điều rắc rối duy nhất là trước tiên chúng ta phải xuất mô hình với trọng số được huấn luyện sang định dạng SavedModel.

export

Một code mẫu để xuất ra SavedModel được cung cấp ở đây. Bí quyết thứ nhất là bạn sử dụng Tensorflow Saver. Thứ hai là bạn hiểu được node đầu vào và đầu ra mà mô hình của bạn đang có.

Backend

Đây là giản đồ sơ lược về Backend của nhóm nghiên cứu:

backend

Tất nhiên trong thực tế có nhiều thành phần hơn như Database, Logger,… nhưng ở đây ó 2 service nhỏ tác giả muốn đề cập tới: apiserving.

serving là Tensorflow Serving như đã đượ nêu ở trên; api(cung cấp RESTful API cho client) kết nối với serving thông qua gRPC. May mắn nhóm nghiên cứu không phải quan tâm nhiều đến giao thức Protocol Buffers và chỉ tận dụng thư viện có sẵn tensorflow-serve-api. Một code sử dụng mẫu mà nhóm cung cấp:

Triển khai

Triển khai là một phần quan trọng trong cả dự án, nhưng hiện nay thường ít được chia sẻ trong các bài viết về Deep Learning. Ở đây chia sẻ một cách đơn giản sử dụng Docker Compose để triển khai hai service apiserving..

Có hai loại máy chủ: máy chỉ có CPU và máy có GPU.

Với máy chủ CPU, có file config cho Compose: docker-compose.yml, Dockerfile cho apiDockerfile.serving cho serving.

cpu

Trong khi đó, máy chủ GPU có file config Compose với một số hiệu chỉnh nhỏ: nvidia-docker-compose.yml (yêu cầu cần có nvidia-docker), cùng một Dockerfile cho api (như trên) và Dockerfile.serving.gpu cho serving.

gpu

Một lưu ý chính để chạy Docker Compose với GPU là trong nvidia-docker-compose.yml bạn phải thiết lập runtime: nvidia. Một vấn đề rắc rối khác là Docker Compose mặc định sử dụng tất cả GPU nên bạn phải đặt biến môi trường NVIDIA_VISIBLE_DEVICES cho GPU bạn muốn sử dụng. Một mẹo mà nhóm sử dụng để mang tính nhất quán giữa Tensorflow (CUDA_VISIBLE_DEVICES) và Docker Compose là:

Bằng cách này, bạn thiết lập CUDA_VISIBLE_DEVICES với GPU nào bạn muốn sử dụng. Nếu không được thiết lập, hệ thống sẽ mặc định sử dụng tất cả các GPU.

Tổng kết

Nghiên cứu là một phần quan trọng nhưng đem triển khai mô hình đã được huấn luyện ra môi trường thực tế cũng là một thử thách không hề nhỏ.

Ở đây với việc sử dụng Tensorflow nhóm nghiên cứu có cả một hệ sinh thái được hỗ trợ bởi Google, đặc trưng ví dụ là Tensorflow Serving (thuộc về TFX). Thực tế thì mỗi framework hay hệ sinh thái Deep Learning hiện nay đều có cách đa dạng riêng để đem kết quả được huấn luyện ra môi trường production, việc tìm hiểu song song tác vụ nghiên cứu đòi hỏi sự hợp tác của cả các nghiên cứu viên và các kỹ sư.

Hiệp Phạm

Tin liên quan:
  • 102
    Shares