Как увеличить скорость передачи при отправке изображения в Rest API

#python #rest #machine-learning #deployment #fastapi

#python #rest #машинное обучение #развертывание #fastapi

Вопрос:

Я новичок в разработке Rest API и пытаюсь развернуть модель машинного обучения для сегментации изображений с использованием Python и Rest API.
На стороне сервера я использую FastAPI, а на стороне клиента я использую библиотеку запросов Python. Клиент уже изменяет размер изображения до необходимого входного размера модели и, следовательно, не отправляет излишне большие изображения. Сервер передает полученное изображение в модель и возвращает двоичную маску сегментации. Изображение и маска преобразуются из массивов numpy в списки, которые затем отправляются в виде данных json.
Ниже приведен некоторый код, представляющий то, что я только что описал. Поскольку я не могу предоставить здесь модель, сервер в этом минимально воспроизводимом примере просто вернет то же изображение, которое он получил.

server.py

 import uvicorn
from fastapi import FastAPI
import numpy as np
from datetime import datetime

app = FastAPI()

@app.get('/test')
def predict_and_process(data: dict = None):
    start = datetime.now()
    if data:
        image = np.asarray(data['image'])
        print("Time to run: ", datetime.now() - start)
        return {'prediction': np.squeeze(image).tolist()}
    else:
        return {'msg': "Model or data not available"}

def run():
    PORT = 27010
    uvicorn.run(
        app,
        host="127.0.0.1", 
        port=PORT,
    )


if __name__=='__main__':
    run()
 

client.py

 import requests
import numpy as np
import json
from matplotlib.pyplot import imread 
from skimage.transform import resize
from datetime import datetime

def test_speed():
    path_to_img = r"path_to_some_image"
    
    image = imread(path_to_img)
    image = resize(image, (1024, 1024))
    img_list = image.tolist()

    data = {'image': img_list}
    start = datetime.now()
    respond = requests.get('http://127.0.0.1:27010/test', json=data)

    prediction = respond.json()['prediction']
    print("time for prediction: {}".format(datetime.now()-start))

if __name__=='__main__':
    test_speed()
 

Вывод с сервера выглядит следующим образом:

 (cera) PS C:Usersuser_nameDesktopMRMREST> python .server.py
[32mINFO[0m:     Started server process [[36m20448[0m]
[32mINFO[0m:     Waiting for application startup.
[32mINFO[0m:     Application startup complete.
[32mINFO[0m:     Uvicorn running on [1mhttp://127.0.0.1:27010[0m (Press CTRL C to quit)
Time to run:  0:00:00.337099
[32mINFO[0m:     127.0.0.1:61631 - "[1mGET /test HTTP/1.1[0m" [32m200 OK[0m
 

и вывод от клиента:

 (cera) PS C:Usersuser_nameDesktopMRMREST> python .client.py
time for prediction: 0:00:16.845123
 

Поскольку код, выполняемый на сервере, занимает меньше секунды, время, необходимое для передачи изображения с клиента на сервер (или обратно), составляет где-то около 8 секунд, что определенно слишком долго.
Я не могу отправлять изображения меньшего размера, так как входной размер модели должен оставаться неизменным.

Итак, для новичка в развертывании / REST: каким был бы профессиональный / передовой способ быстрее получать мои прогнозы из REST API? Я предполагаю, что есть ограничения, так как я использую python, но 16 секунд все еще кажутся мне слишком долгими.
Заранее благодарю вас!

Комментарии:

1. вы могли бы base64 кодировать ваше изображение при передаче его через REST

2. Это на самом деле решение! Я опубликую это в качестве ответа, если вы не возражаете, чтобы другие могли это увидеть 🙂

Ответ №1:

Как указал @slizb, кодирование изображения в base64 делает все намного быстрее. Вместо img_list = img.to_list() того, чтобы использовать

 data = {'shape': image.shape, 'img': base64.b64encode(image.tobytes())}
 

и на сервере

 image = np.frombuffer(base64.b64decode(data.img)).reshape(data.shape)
 

Не забудьте также отправить форму, потому что numpy не собирается «запоминать» форму из буфера, поэтому мне нужно было вручную .reshape() обработать изображение.
Общее время сократилось примерно до 1 секунды, что в основном составляет время вывода моей модели.

Ответ №2:

Я бы посоветовал ознакомиться с этой документацией и попробовать примеры, предоставленные для вашего маршрута загрузки изображений.

https://fastapi.tiangolo.com/tutorial/request-files/

Комментарии:

1. Если я правильно понимаю, это может сработать для mrm, но на самом деле я не загружаю файлы с жесткого диска. Начальной точкой всегда будет numpy.ndarray …