Serverless-инференс ONNX-моделей на Python 3.12
Запускайте обученную модель за HTTP-маршрутом без отдельного model server. Рантайм — Python 3.12 на glibc (Debian slim), поэтому manylinux-колёса ставятся чисто, а <code>onnxruntime</code>, <code>onnx</code> и <code>scikit-learn</code> доступны как подключаемые слои. Поместите файл модели внутрь функции — он лежит рядом с хендлером в <code>/var/task</code> — загрузите его один раз на холодном старте и переиспользуйте в тёплых вызовах. Это инференс на CPU: GPU нет.
Обновлено: 2026-06-25
- Python 3.12 на glibc (Debian slim): manylinux-колёса работают, без ограничений edge-изолятов
- Подключаемые слои: py-onnxruntime, py-onnx, py-scikit-learn
- Модель в /var/task рядом с хендлером — загрузка один раз на холодном старте, переиспользование в тёплых
- Память 256MB по умолчанию (до 2GB); таймаут 5с по умолчанию, максимум 15 минут
Кратко
Суть ответа
Serverless-инференс ONNX-моделей на Python 3.12. Inquir запускает Python 3.12 в контейнерах на glibc (Debian slim), поэтому manylinux-колёса ставятся так же, как на обычной Linux-машине. onnxruntime, onnx и scikit-learn доступны как подключаемые слои (py-onnxruntime, py-onnx, py-scikit-learn): подключайте слой к функции вместо упаковки колеса в каждый деплой.
Когда подходит и когда нет
- Запросный инференс для небольшой или средней модели, экспортированной в ONNX (классификатор, ранкер, голова эмбеддингов)
- Модели scikit-learn или другие CPU-модели, которые нужно выставить за аутентифицированным HTTP-маршрутом без model server
- Всплесковый или малообъёмный скоринг, где платить за всегда включённый GPU или контейнер расточительно
На что обратить внимание
- Edge и V8-изоляты вообще не запускают нативные ML-колёса —
onnxruntimeпоставляет скомпилированный бинарник, и изоляты не могут его загрузить. Так что инференс, которому нужен настоящий процесс CPython, на таких рантаймах недоступен, какой бы маленькой ни была модель. - Даже там, где Python есть, образ на musl (Alpine) ломает заранее собранные manylinux-колёса, которые публикуют
onnxruntimeиscikit-learn, заставляя собирать из исходников или фиксировать старые версии. База glibc — это то, что позволяет колёсам ставиться как опубликовано.
Ситуация: нагрузка и где обычно ломается
Чего стоит держать одну обученную модель в проде
У вас есть обученная модель — классификатор scikit-learn, экспортированный в ONNX, небольшой градиентный ранкер, голова эмбеддингов. Обычно её обслуживание — это контейнер или model server, работающий 24/7, рассчитанный на пик и оплачивающий простой между запросами. Для запросного, в основном всплескового инференса это слишком много постоянной инфраструктуры под функцию, которая грузит файл и вызывает session.run().
Сама модель небольшая, а код инференса короткий. Не хватает места, где запускать её по требованию: поставить рантайм, держать модель в памяти между вызовами, выставить за аутентифицированным HTTP-маршрутом и не платить, когда вызовов нет.
Компромиссы
Почему edge и минимальные рантаймы мешают инференсу
Edge и V8-изоляты вообще не запускают нативные ML-колёса — onnxruntime поставляет скомпилированный бинарник, и изоляты не могут его загрузить. Так что инференс, которому нужен настоящий процесс CPython, на таких рантаймах недоступен, какой бы маленькой ни была модель.
Даже там, где Python есть, образ на musl (Alpine) ломает заранее собранные manylinux-колёса, которые публикуют onnxruntime и scikit-learn, заставляя собирать из исходников или фиксировать старые версии. База glibc — это то, что позволяет колёсам ставиться как опубликовано.
Как Inquir помогает в этом сценарии
Python-рантайм на glibc с подключаемыми ML-слоями
Inquir запускает Python 3.12 в контейнерах на glibc (Debian slim), поэтому manylinux-колёса ставятся так же, как на обычной Linux-машине. onnxruntime, onnx и scikit-learn доступны как подключаемые слои (py-onnxruntime, py-onnx, py-scikit-learn): подключайте слой к функции вместо упаковки колеса в каждый деплой.
Файл модели едет внутри бандла функции и лежит рядом с хендлером в /var/task, либо его можно смонтировать как слой. Загрузите его один раз на уровне модуля — на холодном старте — и тёплый пул контейнеров (от 1 до 8 на функцию) переиспользует загруженную сессию между вызовами, так что при стабильном трафике модель не перечитывается каждый раз. Инференс идёт на CPU: GPU на платформе нет, поэтому это подходит для небольших и средних моделей, а не для крупных сетей под GPU.
Что вы получаете на платформе
Что покрывает serverless-инференс ONNX
Подключите рантайм как слой
Добавьте py-onnxruntime (и py-onnx или py-scikit-learn при необходимости) к функции вместо упаковки колеса в каждый деплой. База glibc означает, что опубликованное manylinux-колесо грузится как есть.
Модель грузится один раз на холодном старте
Создавайте InferenceSession на уровне модуля. Первый вызов в свежем контейнере оплачивает загрузку; тёплые контейнеры в пуле переиспользуют сессию, так что большинство запросов вообще пропускают загрузку модели.
Инференс за аутентифицированным маршрутом
Привяжите хендлер к маршруту шлюза с auth по api-key или bearer. Вызывающие шлют признаки JSON-ом по POST; хендлер возвращает предсказания. Память по умолчанию 256MB и поднимается до 2GB под крупные модели или батчи.
Батч- или async-инференс
Для одного предсказания отвечайте синхронно в пределах таймаута 5с по умолчанию. Для объёмного скоринга, который идёт дольше, примите запрос, верните 202 и запускайте инференс в шаге пайплайна (до 15 минут на шаг).
Что сделать дальше, по шагам
Как обслужить ONNX-модель как функцию
Экспортируйте модель в ONNX, отправьте её с хендлером, подключите слой рантайма и выставьте за маршрутом.
Экспортируйте и отправьте модель
Экспортируйте обученную модель в ONNX (например, через skl2onnx для оценщика scikit-learn). Положите файл .onnx в бандл функции, чтобы он попал в /var/task рядом с хендлером.
Подключите рантайм и загрузите один раз
Подключите слой py-onnxruntime. Создайте InferenceSession на уровне модуля, указав путь к модели в /var/task, чтобы она грузилась на холодном старте и оставалась в тёплых контейнерах.
Выставьте и наблюдайте
Привяжите хендлер к маршруту шлюза с auth по api-key. Каждый вызов даёт запись прогона — длительность, статус, логи — чтобы видеть задержку холодного и тёплого пути в истории выполнения.
Пример кода
Хендлер инференса ONNX: загрузка один раз, запуск на каждый запрос
Модель грузится во время импорта (холодный старт) и переиспользуется каждым тёплым вызовом. Хендлер читает признаки из тела запроса и возвращает предсказания. Файл модели лежит рядом с этим хендлером в /var/task.
# Python 3.12 on glibc (Debian slim) — manylinux wheels install as published. # Prefer attaching the shared layers (py-onnxruntime, py-numpy) over bundling. onnxruntime numpy
import os import json import numpy as np import onnxruntime as ort # Loaded ONCE on cold start, at module scope. # The model ships inside the function and lives next to this handler in /var/task. MODEL_PATH = os.path.join(os.path.dirname(__file__), "model.onnx") _session = ort.InferenceSession(MODEL_PATH, providers=["CPUExecutionProvider"]) # CPU only — no GPU _input_name = _session.get_inputs()[0].name def handler(event, context): body = json.loads(event.get("body") or "{}") features = body.get("features") if not features: return {"statusCode": 400, "body": json.dumps({"error": "features required"})} x = np.asarray(features, dtype=np.float32) if x.ndim == 1: x = x.reshape(1, -1) # single row -> batch of 1 # Warm containers reuse _session — no per-request model load. outputs = _session.run(None, {_input_name: x}) predictions = outputs[0].tolist() return {"statusCode": 200, "body": json.dumps({"predictions": predictions})}
Когда подходит и когда нет
Когда уместен serverless-инференс ONNX
Когда это уместно
- Запросный инференс для небольшой или средней модели, экспортированной в ONNX (классификатор, ранкер, голова эмбеддингов)
- Модели scikit-learn или другие CPU-модели, которые нужно выставить за аутентифицированным HTTP-маршрутом без model server
- Всплесковый или малообъёмный скоринг, где платить за всегда включённый GPU или контейнер расточительно
Когда лучше не трогать
- Крупные модели под GPU или низколатентное высоконагруженное обслуживание — GPU нет, а холодные старты на CPU реальны
Вопросы и ответы
Вопросы и ответы
Какая версия Python и базовый образ запускают модель?
Python 3.12 на glibc (Debian slim). Поскольку база — glibc, manylinux-колёса, которые публикуют onnxruntime, onnx и scikit-learn, ставятся и грузятся как есть — без сборки из исходников и без поломок колёс на Alpine/musl.
Как затащить onnxruntime в функцию?
Подключите слой py-onnxruntime (с py-onnx или py-scikit-learn, если нужны) к функции вместо упаковки колеса в каждый деплой. Можно и pip-install через сборку слоя; чисто-Python зависимости могут жить в бандле функции.
Где лежит файл модели и когда он грузится?
Отправьте файл .onnx внутри бандла функции — он попадает рядом с хендлером в /var/task — или смонтируйте как слой. Создавайте InferenceSession на уровне модуля, чтобы он грузился один раз на холодном старте; тёплые контейнеры в пуле переиспользуют загруженную сессию между вызовами.
Есть ли GPU?
Нет. Инференс идёт на CPU (CPUExecutionProvider). Это подходит для небольших и средних моделей и оценщиков уровня scikit-learn. Крупные сети под GPU и обучение для этой платформы не подходят.
Какие лимиты памяти и таймаута?
Память по умолчанию 256MB и поднимается до 2GB под крупные модели или батчи. Таймаут функции по умолчанию 5с и доходит до 15 минут. Для объёмного скоринга дольше этого верните 202 и запускайте инференс в шаге пайплайна.