M l ops

Triển khai AI model sử dụng uWSGI và Nginx

Triển khai AI model sử dụng uWSGI và Nginx

Như đã giới thiệu trong bài trước, mặc dù Flask rất dễ để sử dụng nhưng nó không có đầy đủ chức năng để có thể áp dụng vào các sản phẩm trong thực tế. Đó là tính bảo mật, khả năng xử lý đồng thời nhiều kết nối, khả năng mở rộng và nâng cấp model, … Sử dụng kết hợp bộ ba Flask, uWSGI và Nginx chính là giải pháp hữu hiệu khắc phục những thiếu sót này. Trong bài viết này, chúng ta sẽ cùng tìm hiểu cách cài đặt, cấu hình và sử dụng bộ 3 kể trên để triển khai Animal Classification model dưới dạng server phục vụ các yêu cầu nhận dạng từ các clients.

1. WSGI, uWSGI, và uwsgi là gì?

Trước tiên cần hiểu rõ một số thuật ngữ mà ta sử dụng trong bài này.

  • WSGI: Viết tắt của Web Server Gateway Interface, là một Interface giữa server và client, được viết bằng python. Hiểu một cách đơn giản, nó quy định các thức để client có thể kết nối và gửi nhận dữ liệu với server.
  • uWSGI: Là một server, sử dụng WSGI để giao tiếp với client (hoặc sử dụng giao thức HTTP trong trường hợp client là web application).
  • uwsgi: Là một giao thức ở tầng thấp hơn, cho phép các servers giao tiếp với nhau.

Bạn có thể xem sơ đồ kiến trúc triển khai sử dụng uWSGI như hình bên dưới đây:

Phần xử lý nhận diện của ta vẫn được gọi thông qua Flask. Phía trước Flask ta đặt uWSGI rồi đến web application (client).

Việc đặt uWSGI như vậy mang lại cho ta các lợi ích như sau:

  • Quản lý tiến trình: Quản lý việc tạo và duy trì các tiến trình trong quá trình làm việc. Các tiến trình được đồng bộ với nhau trong cùng 1 môi trường và có khả năng scale-up để phục vụ cho nhiều users.
  • Cân bằng tải: Phân phối tải (các requests) đến các tiến trình khác nhau.
  • Giám sát: Giám sát hiệu năng và tài nguyên sử dụng.
  • Hạn chế tài nguyên: Cho phép chỉ định mức tối đa tài nguyên có thể sử dụng.

2. Nginx là gì và tại sao phải sử dụng nó?

Nginx là một webserver với các đặc tính:

  • High performance: Hiệu năng cao
  • Highly scalable: Khả năng mở rộng cao
  • Highly available: Tính sẵn sàng cao

Nó hoạt động giống như một bộ cân bằng tải, một reverse proxy cùng với cơ chế caching, cơ chế mã hóa và bảo mật trên các bản tin giao tiếp giữa client và server. Nginx được cho là có thể phục vụ hơn 10,000 kết nối đồng thời.

Nginx được sử dụng khá phổ biến trong các công ty công nghệ lớn, trong nhiều sản phẩm, ứng dụng cần phục vụ số lượng lớn người dùng đồng thời.

Xét về kiến trúc tổng thể, nó thường được sử dụng cùng với uWSGI, đứng trước uWSGI như trong hình sau:

Mục đích của việc sử dụng đồng thời cả uWSGI và Nginx là để tận dụng những ưu điểm của cả 2. Tất nhiên điều này là không bắt buộc nếu ứng dụng của chúng ta ở mức đơn giản, không cần phải phục vụ số lượng users đồng thời quá lớn. Nhưng dù sao vẫn nên sử dụng kiến trúc này để có thể dễ dàng mở rộng ứng dụng về sau.

3. Chuẩn bị Flask server

Ta vẫn cần có Flask làm server trực tiếp xử lý request từ client. Có thể hiểu Flask server ở đây là endpoint cũng được. Mình sẽ sử dụng lại file server.py ở bài trước, nhưng đã bỏ đi phần phục vụ web client.

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

config = tf.compat.v1.ConfigProto()
config.gpu_options.allow_growth = True
session = tf.compat.v1.InteractiveSession(config=config)

app = Flask(__name__)
CORS(app)

image_width = 300
image_height = 300
classes = ['cat', 'dog', 'pandas']
APP_ROOT_2 = os.getenv('APP_ROOT', '/infer')
model = load_model('animal_model_classification.h5')

        
@app.route(APP_ROOT_2, methods=["POST"]) 
def infer(): 
	data = request.json 
	img_path = data['img_path'] 
	return classify_animal(img_path)
        
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
  
if __name__ == '__main__':
    app.run()

4. Cài đặt và cấu hình uWSGI

Để cài đặt uWSGI, sử dụng lệnh sau:

$ pip install uwsgi

Kiểm tra cài đặt bằng cách chạy câu lệnh sau:

$ uwsgi --http 0.0.0.0:8080  --wsgi-file server.py --callable app

Nếu output như sau thì tức là viêc cài đặt thành công:

Câu lệnh trên có ý nghĩa là chạy một server tại địa chỉ 0.0.0.0, port 8080, sử dụng ứng dụng đặt trong file server.py.

uWSGI có rất nhiều tùy chọn cấu hình. Do đó, để thuận tiện, ta thường tạo một file cấu hình, tên là app.ini như sau:

[uwsgi] 
  
http = 0.0.0.0:8080 # địa chỉ server
socket = service.sock # socket giao tiếp với Nginx
chmod-socket = 660 # cấp quyền truy câp  socket
wsgi-file = server.py # file chứa code xử lý yêu cầu từ client
callable = app # function được gọi khi tạo uWSGI
die-on-term = true # cho phép kill server từ terminal
processes = 4 # số lượng process
threads = 2 # số lượng thread
chdir = /media/sunt/DATA/GITHUB/Model_Deployment/uWSGI/ # thư mục dự án
virtualenv = /home/sunt/anaconda3/envs/tf2/ # môi trường ảo (nếu có)
master = false 
vacuum = truemodule # định kỳ xóa những file ko cần thiết được sinh ra

Để chạy uWSGI, dùng lệnh:

$ uwsgi app.ini

Nếu thành công, output trên terminal sẽ như sau:

5. Cài đặt và cấu hình Nginx

Để cài đặt Nginx, sử dụng lệnh sau:

$ sudo apt-get install nginx

Tiếp theo, tạo một file cấu hình đặt trong thư mục /etc/nginx/sites-available, tên là service.conf, với nội dụng như sau:

server {
        listen 80;
        server_name 0.0.0.0;

        location / {
            include uwsgi_params;
            uwsgi_pass unix:/media/sunt/DATA/GITHUB/Model_Deployment/uWSGI/service.sock;
        }
}

Theo cấu hình này, Nginx sẽ lắng nghe trên cổng 80 (mặc định) cho tất cả các yêu cầu đến server đặt tại địa chỉ 0.0.0.0. Các yêu cầu sau đó được chuyển đến uWSGI server thông qua socket service.sock (sử dụng giao thức uwsgi).

Tiếp theo, để áp dụng các cấu hình trên cho Nginx, ta cần trỏ liên kết của chúng tới thư mục sites-enabled:

$ sudo ln -s /etc/nginx/sites-available/service.config /etc/nginx/sites-enabled

Kiểm tra lại xem các cấu hình đã đúng hay chưa?:

$ sudo nginx -t 

Nếu mọi thứ OK, sẽ có output như sau:

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Cuối cùng, restart lại Nginx server:

$ sudo systemctl status nginx

6. Tạo client và kiểm tra kết quả

Sử dụng lại client viết bằng python như ở bài trước:

import requests 
from PIL import Image 
import numpy as np 
ENDPOINT_URL = 'http://0.0.0.0:8080/infer2'
 
def infer():
    data = { 'img_path': 'dog.1.jpg' }
    response = requests.post(ENDPOINT_URL, json = data)
    response.raise_for_status()
    print(response.content) 
  
if __name__ =="__main__": 
    infer() 

Để kiểm tra hoạt động của client và server, đầu tiên khởi chạy uWSGI (như phần 4.), sau đó chạy client:

$ python client.py

Nếu nhận được kết quả trả vê từ server tức là hệ thống đã hoạt động chính xác:

b`dog`

7. Kết luận

Như vậy là chúng ta đã cùng nhau triển khai thành công DL model sử dụng Nginx, uWSGI và Flask. Nginx thì mặc định được chạy dưới dạng service sau khi cài đặt xong, còn uWSGI thì không. Ta nên cấu hình uWSGI để nó cũng chạy dưới dạng service cho thuận tiện sử dụng. Hi vọng qua bài này, các bạn đã hiểu rõ hơn về cách thức triển khai một AI model trong các sản phẩm thực tế, đáp ứng số lượng lớn user sử dụng đồng thời.

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é!

Bài viết tiếp theo, chúng ta sẽ đi nâng cao hơn 1 chút nữa, đó là đóng gói tất cả những phần đã làm hôm nay vào một cái gọi là docker. Docker là gì, và tại sao lại nên dùng nó? Tất cả sẽ được giải đáp trong bài viết đó. Mời các bạn đón đọc!

8. Tham khảo