fastapi не может найти определение модели при запуске с uvicorn

Я хочу разместить модель pytorch в бэкэнде fastapi. Когда я запускаю код с помощью python, он работает нормально. очищенная модель может использовать определенный класс. Когда тот же файл запускается с помощью uvicorn, он не может найти определение класса.

Исходный код выглядит так:

import uvicorn
import json
from typing import List
from fastapi import Body, FastAPI
from fastapi.encoders import jsonable_encoder
import requests
from pydantic import BaseModel

#from model_ii import Model_II_b

import dill as pickle
import torch as T
import sys

app = FastAPI()
current_model = 'model_v2b_c2_small_ep15.pkl'
verbose_model = False  # for model v2

class Model_II_b(T.nn.Module):
[...]
@app.post('/function')
def API_call(req_json: dict = Body(...)):
    try:
        # load model...
        model = pickle.load(open('models/' + current_model, 'rb'))
        result = model.dosomething_with(req_json)

        return result

    except Exception as e:
        raise e
        return {"error" : str(e)}

if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=8000)

Когда я запускаю это с python main.py, он работает нормально, и я получаю результаты. Когда я запускаю его с помощью uvicorn main:app и отправляю запрос, я получаю следующую ошибку:

AttributeError: Can't get attribute 'Model_II_b' on <module '__mp_main__' from '/opt/webapp/env/bin/uvicorn'>

оба должны использовать тот же Python env, что и я использую uvicorn изнутри env.

Я надеюсь, что кто-то знает, что не так с моей настройкой или кодом.

Обновите Stacktrace:

(model_2) root@machinelearning-01:/opt/apps# uvicorn main:app --env-file /opt/apps/env/pyvenv.cfg --reload
INFO:     Loading environment from '/opt/apps/env/pyvenv.cfg'
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO:     Started reloader process [164777] using statreload
INFO:     Started server process [164779]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     127.0.0.1:33872 - "POST /ml/v2/predict HTTP/1.1" 500 Internal Server Error
ERROR:    Exception in ASGI application
Traceback (most recent call last):
  File "/opt/apps/env/lib/python3.6/site-packages/uvicorn/protocols/http/httptools_impl.py", line 385, in run_asgi
    result = await app(self.scope, self.receive, self.send)
  File "/opt/apps/env/lib/python3.6/site-packages/uvicorn/middleware/proxy_headers.py", line 45, in __call__
    return await self.app(scope, receive, send)
  File "/opt/apps/env/lib/python3.6/site-packages/fastapi/applications.py", line 183, in __call__
    await super().__call__(scope, receive, send)  # pragma: no cover
  File "/opt/apps/env/lib/python3.6/site-packages/starlette/applications.py", line 102, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/opt/apps/env/lib/python3.6/site-packages/starlette/middleware/errors.py", line 181, in __call__
    raise exc from None
  File "/opt/apps/env/lib/python3.6/site-packages/starlette/middleware/errors.py", line 159, in __call__
    await self.app(scope, receive, _send)
  File "/opt/apps/env/lib/python3.6/site-packages/starlette/exceptions.py", line 82, in __call__
    raise exc from None
  File "/opt/apps/env/lib/python3.6/site-packages/starlette/exceptions.py", line 71, in __call__
    await self.app(scope, receive, sender)
  File "/opt/apps/env/lib/python3.6/site-packages/starlette/routing.py", line 550, in __call__
    await route.handle(scope, receive, send)
  File "/opt/apps/env/lib/python3.6/site-packages/starlette/routing.py", line 227, in handle
    await self.app(scope, receive, send)
  File "/opt/apps/env/lib/python3.6/site-packages/starlette/routing.py", line 41, in app
    response = await func(request)
  File "/opt/apps/env/lib/python3.6/site-packages/fastapi/routing.py", line 197, in app
    dependant=dependant, values=values, is_coroutine=is_coroutine
  File "/opt/apps/env/lib/python3.6/site-packages/fastapi/routing.py", line 149, in run_endpoint_function
    return await run_in_threadpool(dependant.call, **values)
  File "/opt/apps/env/lib/python3.6/site-packages/starlette/concurrency.py", line 34, in run_in_threadpool
    return await loop.run_in_executor(None, func, *args)
  File "/usr/lib/python3.6/concurrent/futures/thread.py", line 56, in run
    result = self.fn(*self.args, **self.kwargs)
  File "./main.py", line 155, in API_call
    raise e
  File "./main.py", line 129, in API_call
    model = pickle.load(open('models/' + current_model, 'rb'))
  File "/opt/apps/env/lib/python3.6/site-packages/dill/_dill.py", line 270, in load
    return Unpickler(file, ignore=ignore, **kwds).load()
  File "/opt/apps/env/lib/python3.6/site-packages/dill/_dill.py", line 473, in load
    obj = StockUnpickler.load(self)
  File "/opt/apps/env/lib/python3.6/site-packages/dill/_dill.py", line 463, in find_class
    return StockUnpickler.find_class(self, module, name)
AttributeError: Can't get attribute 'Model_II_b' on <module '__mp_main__' from '/opt/apps/env/bin/uvicorn'>
enter code here

person Sebastian Steinfort    schedule 17.07.2020    source источник
comment
Ты пользуешься докером? Кроме того, код взят из двух отдельных файлов? Не возражаете ли вы поделиться папкой и файловой структурой?   -  person lsabi    schedule 17.07.2020
comment
@lsabi Докер не задействован и находится в том же файле. приведенный выше код - это в точности код из файла. Он работает напрямую с python и выдает прогноз из модели при вызове через веб-сервер fastapi. вот почему я действительно невежественен в данный момент. Что касается структуры, то файлы моделей находятся в подпапке «models /».   -  person Sebastian Steinfort    schedule 20.07.2020
comment
Понятно. Тогда не могли бы вы опубликовать еще немного трассировки стека? Сложно сказать только по модулю mp_main   -  person lsabi    schedule 20.07.2020
comment
@lsabi Я добавил трассировку стека в свой пост. Надеюсь, ты найдешь подсказку!   -  person Sebastian Steinfort    schedule 20.07.2020
comment
Может ли это быть полезно? stackoverflow .com / questions / 27732354 /   -  person lsabi    schedule 20.07.2020
comment
@lsabi спасибо за подсказку. Распаковщик клиентов решил мою проблему!   -  person Sebastian Steinfort    schedule 21.07.2020
comment
У меня такая же проблема, но пользовательский маршрут unpickler не решил мою проблему. Я использую torch.load для загрузки моей модели, и определение модели находится прямо там, над этой линией. Это проблема, вызванная увикорном?   -  person Hamman Samuel    schedule 30.06.2021


Ответы (1)


С помощью @lsabi я нашел решение здесь https://stackoverflow.com/a/51397373/13947506

С помощью кастомного unpickler моя проблема была решена:

class CustomUnpickler(pickle.Unpickler):

    def find_class(self, module, name):
        if name == 'Model_II_b':
            from model_ii_b import Model_II_b
            return Model_II_b
        return super().find_class(module, name)

current_model = 'model_v2b_c2_small_ep24.pkl'

model = CustomUnpickler(open('models/' + current_model, 'rb')).load()
person Sebastian Steinfort    schedule 21.07.2020