Inquir Compute · ML-инференс

Serverless-инференс ONNX-моделей на Python 3.12

Запускайте обученную модель за HTTP-маршрутом без отдельного model server. Рантайм — Python 3.12 на glibc (Debian slim), поэтому manylinux-колёса ставятся чисто, а onnxruntime, onnx и scikit-learn доступны как подключаемые слои. Положите файл модели внутрь функции — он лежит рядом с обработчиком в /var/task, — загрузите его один раз на холодном старте и переиспользуйте в тёплых вызовах. Это инференс на CPU: GPU нет.

Обновлено: 2026-06-28

  • Python 3.12 на glibc (Debian slim): manylinux-колёса работают, без ограничений edge-изолятов
  • Подключаемые слои: py-onnxruntime, py-onnx, py-scikit-learn
  • Модель в /var/task рядом с обработчиком — загрузка один раз на холодном старте, переиспользование в тёплых
  • Память 256 МБ по умолчанию (до 2 ГБ); таймаут 5 с по умолчанию, настраивается до 24 ч

Суть ответа

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, работающий круглосуточно, рассчитанный на пик и оплачивающий простой между запросами. Для инференса по запросу, в основном всплескового, это слишком много постоянной инфраструктуры ради функции, которая грузит файл и вызывает session.run().

Сама модель небольшая, а код инференса короткий. Не хватает места, где запускать её по требованию: поставить рантайм, держать модель в памяти между вызовами, выставить за HTTP-маршрутом с авторизацией и не платить, когда вызовов нет.

Почему edge и минимальные рантаймы мешают инференсу

Edge и V8-изоляты вообще не запускают нативные ML-колёса — onnxruntime поставляет скомпилированный бинарник, и изоляты не могут его загрузить. Так что инференс, которому нужен настоящий процесс CPython, на таких рантаймах недоступен, какой бы маленькой ни была модель.

Даже там, где Python есть, образ на musl (Alpine) ломает готовые manylinux-колёса, которые публикуют onnxruntime и scikit-learn: приходится собирать из исходников или фиксировать старые версии. База на glibc — то, что позволяет колёсам ставиться как опубликовано.

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 на уровне модуля. Первый вызов в свежем контейнере оплачивает загрузку; тёплые контейнеры в пуле переиспользуют сессию, так что большинство запросов вообще пропускают загрузку модели.

Инференс за маршрутом с авторизацией

Привяжите обработчик к маршруту шлюза с авторизацией по API-ключу или bearer-токену. Вызывающие шлют признаки JSON-ом по POST; обработчик возвращает предсказания. Память по умолчанию 256 МБ и поднимается до 2 ГБ под крупные модели или батчи.

Батч- или async-инференс

Для одного предсказания отвечайте синхронно в пределах таймаута 5 с по умолчанию. Для объёмного скоринга, который идёт дольше, примите запрос, верните 202 и запускайте инференс в шаге пайплайна (таймаут шага настраивается до 24 часов).

Как обслужить ONNX-модель как функцию

Экспортируйте модель в ONNX, отправьте её с обработчиком, подключите слой рантайма и выставьте за маршрутом.

1

Экспортируйте и отправьте модель

Экспортируйте обученную модель в ONNX (например, через skl2onnx для оценщика scikit-learn). Положите файл .onnx в бандл функции, чтобы он попал в /var/task рядом с обработчиком.

2

Подключите рантайм и загрузите один раз

Подключите слой py-onnxruntime. Создайте InferenceSession на уровне модуля, указав путь к модели в /var/task, чтобы она грузилась на холодном старте и оставалась в тёплых контейнерах.

3

Выставьте и наблюдайте

Привяжите обработчик к маршруту шлюза с авторизацией по API-ключу. Каждый вызов даёт запись прогона — длительность, статус, логи, — чтобы видеть задержку холодного и тёплого пути в истории выполнения.

Обработчик инференса ONNX: загрузка один раз, запуск на каждый запрос

Модель грузится во время импорта (холодный старт) и переиспользуется каждым тёплым вызовом. Обработчик читает признаки из тела запроса и возвращает предсказания. Файл модели лежит рядом с этим обработчиком в /var/task.

requirements.txt (или подключите слой py-onnxruntime)
# 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
infer.py (обработчик на Python 3.12)
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 при сборке слоя; чисто-Python зависимости могут жить в бандле функции.

Где лежит файл модели и когда он грузится?

Отправьте файл .onnx внутри бандла функции — он попадает рядом с обработчиком в /var/task — или смонтируйте как слой. Создавайте InferenceSession на уровне модуля, чтобы он грузился один раз на холодном старте; тёплые контейнеры в пуле переиспользуют загруженную сессию между вызовами.

Есть ли GPU?

Нет. Инференс идёт на CPU (CPUExecutionProvider). Это подходит для небольших и средних моделей и оценщиков уровня scikit-learn. Крупные сети под GPU и обучение для этой платформы не подходят.

Какие лимиты памяти и таймаута?

Память по умолчанию 256 МБ и поднимается до 2 ГБ под крупные модели или батчи. Таймаут функции по умолчанию 5 с и настраивается до 24 часов. Для объёмного скоринга дольше этого верните 202 и запускайте инференс в шаге пайплайна.