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

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 — это то, что позволяет колёсам ставиться как опубликовано.

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

1

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

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

2

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

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

3

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

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

Хендлер инференса ONNX: загрузка один раз, запуск на каждый запрос

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

requirements.txt (or attach the py-onnxruntime layer)
# 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 handler)
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 и запускайте инференс в шаге пайплайна.