M l ops

Triển khai AI model sử dụng Flask

Triển khai AI model sử dụng Flask

Bạn đã xây dựng thành công một DL model với độ chính xác rất cao, 99%. Xin chúc mừng bạn!

Vấn đề tiếp theo bạn cần nghĩ đến là làm sao đưa model đó vào trong sản phẩm thực tế, để mọi người có thể sử dụng model của bạn một cách đơn giản và dễ dàng. Xây dựng và triển khai model luôn là 2 công đoạn bắt buộc trong một bài toán về AI. Trong các bài tiếp theo, mình sẽ chia sẻ các cách thức mà chúng ta có thể sử dụng để triển khai một DL model vào trong ứng dụng để sử dụng trong thưc tế.

Có 2 kiểu Inference mà một AI model có thể được sử dụng:

  • Online Inference: Model phải liên tục xử lý và trả về kết quả dự đoán gần như real-time khi nó nhận được yêu cầu. Số lượng yêu cầu đến thường rất lớn, thậm chí là nhiều yêu cầu đến tại cùng 1 thời điểm. Chính vì vậy mà việc triển khai model theo kiểu này thường phức tạp hơn rất nhiều so với kiểu thứ 2.

  • Batch Inference: Model chỉ chạy Inference tại một số thời điểm cố định trong ngày, và mỗi lần Inference sẽ xử lý một tập hợp (batch) các input data nhất định.

Mỗi kiểu Inference phù hợp với các bài toán khác nhau, có lẽ mình sẽ viết một bài so sánh chi tiết hơn về 2 kiểu Inference này.

Trong bài đầu tiên này chúng ta sẽ sử dụng Flask, một web server framework nhỏ nhẹ, dễ dàng trong việc cài đạt và sử dụng, để triển khai model phân loại Cat&Dog&Panda trong bài trước theo kiểu Online Inference.

1. Giới thiệu về kiến trúc Client-Server và Flask

Client-server là kiểu kiến trúc xử lý phân tán, gồm 2 thành phần chính là client và server:

  • Client gửi các yêu cầu (requests) đến server.
  • Server xử lý các yêu cầu đó và trả lại kết quả cho client. Yêu cầu có thể là truy vấn database, tính toán, so sánh, dự đoán, …

Dữ liệu trao đổi giữa client và server gọi là các messages.

Giao thức trao đổi giữa client-server thường là HTTP/HTTPS trong trường hợp client là website, và server khi đó gọi là webserver. Nếu client không phải là website thì giao thức có thể là TCP/UDP hoặc uwsgi. Giao thức sẽ định nghĩa định dạng dữ liệu, cơ chế truyền, truyền lại, cơ chế xác thực dữ liệu, …. của các bản tin trao đổi giữa 2 bên. Ví dụ, một HTTP request/Response bao gồm 4 thành phần cơ bản:

  • URL đích: đường dẫn (path) đến một dịch vụ cụa thể của server mà client cần giao tiếp.
  • Phương pháp giao tiếp (method): có 4 phương pháp là GET, POST, UPDATE, DELETE. Tùy từng yêu cầu cụ thể của bài toán mà ta sử dụng phương pháp phù hợp.
  • Header: là các metadata kiểu như ngày tháng năm (date), tình trạng(status), kiểu dữ liệu (content-type), … giúp server xử lý và đồng bộ dữ liệu với client.
  • Body: chứa dữ liệu thực tế mà ta cần gửi từ client đến server hoặc ngược lại.

Flask là một framework để tạo ra thành phần server, bao gồm cả web server. Một số ưu điểm của Flask có thể kể đến như sau:

  • Nó giúp triển khai DL model dưới dạng web application nếu bạn muốn cung cấp giao diện web cho người dùng.
  • Đơn giản, dễ dàng cài đặt và sử dụng.
  • Hỗ trợ nhiều chức năng thông qua các end-point URL khác nhau.

Tuy nhiên, Flask không hỗ trợ đầy đủ các chức năng cần thiết của 1 server để có thể sử dụng trong môi trường sản phẩm thực tế giống như là tính bảo mật và sự hỗ trợ cùng lúc nhiều client truy cập. Nó chỉ phù hợp cho các ứng dụng mang tính demo, kiểm thử tính năng model. Nếu cần triển khai thực tế, uWSGI là một sự lựa chọn phù hợp (sẽ được đề cập chi tiết trong bài sau).

2. Xây dựng Server với Flask

Ta sẽ sử dụng Flask để xây dựng một server phục vụ cả 2 loại client: dạng web và dạng code python (dạng thông thường).

Đầu tiên, tạo file server.py và import Flask và các thư viện cần thiết:

import cv2
import os
import numpy as np
import tensorflow as tf
from flask_cors import CORS
from tensorflow.keras.models import load_model
from flask import Flask, request, render_template, make_response, jsonify

Tạo một instance của Flask:

app = Flask(__name__)

Định nghĩa 1 vài hằng số sử dụng:

image_width = 300
image_height = 300
classes = ['cat', 'dog', 'pandas']
APP_ROOT_1 = os.getenv('APP_ROOT', '/infer1')
APP_ROOT_1 = os.getenv('APP_ROOT', '/infer2')

Hàm render UI mặc định khi truy cập vào địa chỉ server:

# render default webpage
@app.route('/')
def home():
    return render_template('home.html')

Hàm này chỉ phục vụ client dạng web. File home.html chính là phần front-end mà chúng ta sẽ viết code để tạo giao diện tương tác với người dùng trên web.

Hàm nhận và xử lý request từ client dạng web:

@app.route(APP_ROOT_1, methods = ['POST', 'GET'])
def classify_image():
    if request.method == 'POST':
    # geting data from html form
        img_path = request.form["img_path"]
        # call funtion to classify image and receive result
        result = classify_animal(img_path)
        # return result to client
        response = {'result': result, 'image': img_path}        
        return make_response(jsonify(response), 200)

Hàm nhận và xử lý request từ client dạng thông thường:

@app.route(APP_ROOT_2, methods=["POST"]) 
def infer(): 
	data = request.json 
	image = data['image_path'] 
	return classify_animal(img_path)

Hãy nhớ lại ở bài trước, sau khi huấn luyện xong model, ta đã lưu nó thành file animal_model_classification.h5 vào ổ cứng. File này có kích thước khá nặng, khoảng 1.7GB. Bây giờ, ta sẽ sử dụng model đó đã nhận diện.

Load DL model:

model = load_model('animal_model_classification.h5')

Hàm dưới đây nhận vào tham số là đường dẫn đến ảnh cần nhận diện và trả về kết quả:

def classify_animal(img_path):
    # read image
    image = cv2.imread(img_path)
    image = image/255
    image = cv2.resize(image, (image_width,image_height)
    image = np.reshape(image, [1,image_width,image_height,3])

    # pass the image through the network to obtain our predictions
    preds = model.predict(image)
    label = classes[np.argmax(preds)]

    return label

Cuối cùng, sử dụng hàm run() để khởi tạo server:

if __name__ == '__main__':
    app.run()

Để chạy server, mở cửa sổ terminal và gõ lệnh:

$ python server.py

Nếu mọi thứ Ok thì cửa sổ terminal sẽ xuất hiện như sau:

Như vậy là đã xong phần backend, tiếp theo ta sẽ viết code cho front-end.

3. Web client

Web client có giao diện đơn giản gồm 1 button cho phép user chọn ảnh cần nhận diện và 1 khu vực để hiển thị ảnh kèm kết quả.

Vì web không phải là lĩnh vực chuyên sâu của mình nên mình sẽ không đi chi tiết code ở đây. Các bạn có thể tham khảo code web trên github của mình.

Để kiểm tra hoạt động, truy cập vào địa chỉ http://localhost:5000, upload một bức ảnh, click Detect button. Kết quả phân loại sẽ được hiển thị.

4. Python client

Tạo file client.py và code như sau:

import requests
import numpy as np
ENDPOINT_URL = 'http://0.0.0.0:5000/infer2'

def infer(): 
   img_path = 'dog1.jpg'
   data = { 'image': image_path } 
   response = requests.post(ENDPOINT_URL, json = data) 
   response.raise_for_status() 
   print(response.content) 
 
if __name__ =="__main__": 
   infer() 

Khởi chạy client:

$ python client.py

Kết quả trả về từ server:

b'dog'

Thử lại với một ảnh ảnh con mèo, cat.1.jpg. Kết qủa trả về:

b'cat'

5. Kết luận

Như vậy là chúng ta đã cùng nhau triển khai xong DL model sử dụng Flask. Mặc dù tồn tại nhiều nhược điểm nhưng khi cần nhanh chóng đạt được kết quả để thử nghiệm thì Flask vẫn được tin dùng.

Bài viết tiếp theo, mình sẽ giới thiệu một cách nâng cao hơn để triển khai DL model, thường được áp dụng trong các bài toán thực tế. Mời các bạn đón đọc!

Toàn bộ source code của backend và front-end trong bài này, các bạn có thể tham khảo trên github cá nhân của mình tại đây. Vì model animal_model_classification.h5 có dung lượng khá lớn (> 1.5GB) nên mình không upload lên github được. Các bạn hãy sử dụng model của chính mình để thực hành nhé!

6. Tham khảo