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.
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.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:
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:
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