Qubu Docs

Инференс модели

Подробное описание настройки и запуска инференса модели на платформе Qubu с использованием Python и BentoML.

Инференс модели

Инференс позволяет запустить обученную модель как сервис для получения предсказаний.
На платформе Qubu инференс реализован с использованием Python и фреймворка BentoML ≥ 1.2, который отвечает за развёртывание сервера, маршруты и документацию API.
Разработчик модели настраивает код, интерфейс и ресурсы, после чего получает готовый endpoint и веб‑форму для тестирования.

Что такое BentoML?

BentoML — это фреймворк для развертывания ML-моделей, который автоматически создаёт REST API, документацию и сервер для вашей модели. В версии 1.2+ сервис описывается как Python-класс с декораторами @bentoml.service и @bentoml.api.

BentoML v1.2+ — новый API

Qubu использует BentoML v1.2+ с class-based API. Старый функциональный стиль (svc = bentoml.Service(...), @svc.api(input=JSON(), output=JSON()), from bentoml.io import JSON) не поддерживается и вызовет ошибку AttributeError: 'Service' object has no attribute 'api'.


1. Конфигурация развертывания

Выбор провайдера и машины

Перед началом необходимо выбрать:

  • Провайдер (например, RunPod)
  • Тип машины — GPU или CPU (Tesla V100, A100 и др.)

Настройка параметров

Укажите параметры окружения:

  • Источник сервисаНаписать код (редактор service.py) или Загрузить .bento (готовый архив)
  • Переменные окружения — пути к файлам, ключи API и другие параметры
  • Зависимости — содержимое requirements.txt для pip
  • Настройки доступа — Public, Private или Qubu users

Мониторинг состояния

После развертывания станут доступны:

  • Обновить статус — проверка текущего состояния
  • Пауза / Остановить Endpoint — приостановка или полная остановка контейнера
  • Перезапустить сервис — применение изменений кода без пересоздания контейнера

Источник сервиса: «Написать код» или «Загрузить .bento»

Qubu поддерживает два способа задать BentoML‑сервис:

  • Написать код: вы редактируете service.py прямо в интерфейсе. Платформа установит requirements.txt и запустит bentoml serve service:Service.
  • Загрузить .bento: вы загружаете уже собранный Bento‑архив. Платформа скачает архив, выполнит bentoml import и запустит bentoml serve <bento_tag>.

.bento — что внутри?

.bento — это архив с кодом сервиса и метаданными. Он может содержать модели/веса, но для Qubu обычно правильнее хранить веса отдельно и грузить их в контейнер в /workspace/model (через модельные артефакты), а в сервисе ссылаться на MODEL_PATH=/workspace/model.

Готовность сервиса

Когда сервис успешно запущен, появится строка Endpoint активен с URL. В блоке Состояние контейнера все флаги (health, ready, этап) должны быть зелёными.


2. Код инференса

В блоке Код инференса вы пишете Python‑код, который обрабатывает запросы и вызывает модель.
BentoML 1.2+ использует class-based подход: вы описываете сервис как класс с декоратором @bentoml.service, а каждый endpoint — метод класса с декоратором @bentoml.api.

Структура сервиса

Каждый сервис — это файл service.py с классом Service:

import bentoml

@bentoml.service(name="my_inference")
class Service:
    def __init__(self) -> None:
        # Загрузка модели и подготовка к инференсу
        pass

    @bentoml.api
    def predict(self, inputs: dict) -> dict:
        # Обработка запроса и возврат результата
        return {"result": "..."}

Обязательные правила

  • В режиме «Написать код»:

    • Класс должен называться Service (именно с большой буквы)
    • Файл должен называться service.py
    • Платформа запускает сервис командой bentoml serve service:Service
  • В режиме «Загрузить .bento»:

    • Входная точка определяется вашим Bento‑архивом (Qubu запускает bentoml serve <bento_tag>)

Базовый пример

import os
import bentoml
from typing import Any, Dict, Optional

@bentoml.service(name="salary_predict_inference")
class Service:
    def __init__(self) -> None:
        # Загрузка модели при старте (один раз)
        import pickle
        model_path = os.getenv("MODEL_PATH", "/workspace/model")
        with open(f"{model_path}/model.pkl", "rb") as f:
            self.model = pickle.load(f)

    @bentoml.api
    def predict(self, inputs: dict) -> dict:
        skills = inputs.get("skills", [])
        variable_1 = inputs.get("variable_1")
        variable_2 = inputs.get("variable_2")
        variable_3 = inputs.get("variable_3")

        prediction = self.model.predict(...)
        return {"prediction": str(prediction)}

Примеры с разными моделями

import os
import pickle
import bentoml

@bentoml.service(name="sklearn_inference")
class Service:
    def __init__(self) -> None:
        model_path = os.getenv("MODEL_PATH", "/workspace/model")
        with open(f"{model_path}/model.pkl", "rb") as f:
            self.model = pickle.load(f)

    @bentoml.api
    def predict(self, inputs: dict) -> dict:
        features = inputs.get("features")
        prediction = self.model.predict([features])[0]
        return {"prediction": float(prediction)}
import os
import bentoml
from catboost import CatBoostClassifier

@bentoml.service(name="catboost_inference")
class Service:
    def __init__(self) -> None:
        model_path = os.getenv("MODEL_PATH", "/workspace/model")
        self.model = CatBoostClassifier()
        self.model.load_model(f"{model_path}/catboost_model.cbm")

    @bentoml.api
    def predict(self, inputs: dict) -> dict:
        features = inputs.get("features")
        prediction = self.model.predict([features])[0]
        probability = self.model.predict_proba([features])[0]
        return {
            "prediction": int(prediction),
            "probability": float(probability.max()),
        }
import os
import bentoml
import torch

@bentoml.service(name="pytorch_inference")
class Service:
    def __init__(self) -> None:
        model_path = os.getenv("MODEL_PATH", "/workspace/model")
        self.model = torch.load(f"{model_path}/model.pt", weights_only=False)
        self.model.eval()

    @bentoml.api
    def predict(self, inputs: dict) -> dict:
        features = torch.tensor(inputs.get("features"))
        with torch.no_grad():
            output = self.model(features)
            prediction = output.argmax().item()
        return {"prediction": prediction}

Этот шаблон используется по умолчанию при создании нового инференса на Qubu:

import os
import logging
from typing import Any, Dict, Optional

import bentoml
from transformers import pipeline

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

MODEL_PATH = os.getenv("MODEL_PATH", "/workspace/model")
TASK = os.getenv("TASK", "text-classification")

@bentoml.service(name="inference")
class Service:
    def __init__(self) -> None:
        logger.info(f"Load transformers pipeline: task={TASK}, model_path={MODEL_PATH}")
        self.pipeline = pipeline(TASK, model=MODEL_PATH, tokenizer=MODEL_PATH)

    @bentoml.api
    def predict(self, inputs: Any, parameters: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
        """Универсальный endpoint. Поддерживает строку или список строк."""
        params = parameters or {}
        data = inputs if isinstance(inputs, list) else [inputs]
        outputs = self.pipeline(data, **params)
        return {"results": outputs, "count": len(outputs)}

Несколько endpoints

Вы можете определить несколько методов с @bentoml.api в одном сервисе. Для кастомного маршрута используйте параметр route:

import bentoml

@bentoml.service(name="multi_endpoint")
class Service:
    def __init__(self) -> None:
        self.model = ...

    @bentoml.api
    def predict(self, inputs: dict) -> dict:
        """Основной endpoint: POST /predict"""
        return {"result": self.model.predict(inputs)}

    @bentoml.api(route="/classify")
    def classify(self, text: str) -> dict:
        """Дополнительный endpoint: POST /classify"""
        return {"label": self.model.classify(text)}

    @bentoml.api(route="/health")
    def health(self) -> dict:
        """Кастомный health-check: POST /health"""
        return {"status": "ok"}

Обновление сервиса

После изменения кода нажмите Перезапустить сервис, чтобы обновить версию на сервере. При успешном запуске сервис станет доступен по вашему endpoint, а в браузере появится автосгенерированная документация (Swagger / OAS 3.0).


3. Конструктор UI и маршрутов

После написания кода необходимо настроить интерфейс и маршруты — то, как пользователи будут взаимодействовать с эндпоинтами.

Маршруты

Определите пути и методы для вызова вашей модели

Входные поля

Настройте параметры, которые будут передаваться в модель

Выходные данные

Укажите, как результат должен отображаться пользователю

Настройка маршрута

В блоке Конструктор UI/маршрутов создайте новую функцию:

ПолеЗначение
НазваниеPredict
Путь/predict
МетодPOST
Content‑Typeapplication/json
Authqubu (user)
Корень JSON (bodyRoot)inputs

Важно

Маршрут должен совпадать с именем метода или параметром route декоратора @bentoml.api. Если метод называется predict и route не задан, BentoML создаст endpoint /predict.

Входные поля

Настройте, какие параметры будут передаваться в модель.
Пример конфигурации для задачи прогнозирования зарплаты:

КлючЗаголовокТип поляДополнительно
skillsНавыкиМассив (Array)тип элементов — text
variable_1ГрафикSelectОпции: гибкий, полный день, вахта, удалёнка, посменно
variable_2Опыт работыSelectОпции: 1–3, 3–6, 6+, без опыта
variable_3Тип занятостиSelectпользовательские опции

Каждое поле будет отображаться на странице модели как форма для ввода.

Выходные данные

Затем настройте вывод — какой результат должен отобразиться пользователю.

ПолеЗначение
Типtext
ЗаголовокЗП такого специалиста
JSON Pathprediction

Это означает, что из JSON‑ответа сервиса будет взято значение поля prediction и выведено в интерфейсе.
Если структура отличается, результат не отобразится корректно.


4. Зависимости и окружение

requirements.txt

Укажите Python-пакеты в поле Requirements (вкладка Env). Платформа установит их через pip install -r requirements.txt при запуске контейнера.

transformers>=4.40
torch>=2.0
numpy<2

Автоустановка зависимостей

Если при запуске сервиса Python не может импортировать модуль, платформа автоматически попытается его установить (до 5 попыток). Но лучше указать все зависимости заранее в requirements.txt — это надёжнее и быстрее.

bentofile.yaml (опционально)

Если вам удобнее описывать сборку Bento через bentofile.yaml, вы можете вставить его в поле bentofile.yaml (в секции «Код»).

На деплое Qubu:

  • сохраняет YAML как /workspace/bentofile.yaml
  • запускает bentoml build
  • затем запускает bentoml serve <bento_tag> для собранного Bento

Ограничение: Qubu не парсит список зависимостей из bentofile.yaml для установки. Убедитесь, что нужные пакеты всё равно указаны в requirements.txt.

Переменные окружения

Задайте переменные в формате KEY=VALUE (каждая на новой строке):

MODEL_PATH=/workspace/model
TASK=text-classification
HF_HOME=/workspace/.cache/huggingface

Стандартные переменные, доступные по умолчанию:

ПеременнаяОписание
MODEL_PATHПуть к артефактам модели (задаётся при синхронизации)
WORKDIRРабочая директория (/workspace)
HOSTХост сервиса (0.0.0.0)
PORTПорт сервиса (8888)

5. Развёртывание

Запуск развёртывания

Когда код и UI настроены, нажмите Развернуть Endpoint.
Qubu создаст контейнер с BentoML‑сервисом, установит зависимости и поднимет сервер на выбранной машине.

Получение URL

После успешного развертывания появится активная ссылка:

https://qubu.ai/api/models/<model_slug>/inference/proxy

Проверка документации

Откройте URL в браузере — вы увидите BentoML‑страницу с:

  • Автоматически сгенерированной документацией API (OpenAPI/Swagger)
  • Интерактивной формой для тестовых запросов
  • Списком доступных эндпоинтов

6. Тестирование и вызовы

После запуска можно отправлять запросы к сервису через веб‑форму или напрямую по API.

Примеры вызова API

curl -X POST "https://qubu.ai/api/models/salary-predict/inference/proxy/predict" \
  -H "Authorization: Bearer <API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "inputs": {
      "skills": ["Python", "ML"],
      "variable_1": "remote",
      "variable_2": "between1And3",
      "variable_3": "fullDay"
    }
  }'
import requests

url = "https://qubu.ai/api/models/salary-predict/inference/proxy/predict"
headers = {
    "Authorization": "Bearer <API_KEY>",
    "Content-Type": "application/json"
}
data = {
    "inputs": {
        "skills": ["Python", "ML"],
        "variable_1": "remote",
        "variable_2": "between1And3",
        "variable_3": "fullDay"
    }
}

response = requests.post(url, headers=headers, json=data)
print(response.json())
const response = await fetch(
  'https://qubu.ai/api/models/salary-predict/inference/proxy/predict',
  {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer <API_KEY>',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      inputs: {
        skills: ['Python', 'ML'],
        variable_1: 'remote',
        variable_2: 'between1And3',
        variable_3: 'fullDay'
      }
    })
  }
);

const data = await response.json();
console.log(data);

На странице модели доступна встроенная веб-форма для тестирования:

  1. Откройте страницу вашей модели на Qubu
  2. Найдите блок Тестирование
  3. Заполните поля формы
  4. Нажмите Выполнить
  5. Результат появится в блоке вывода

Веб-форма автоматически подставляет токен авторизации, если вы вошли в систему.

Пример ответа

{ "prediction": "65000 ₽" }

Результат запроса также появится на странице модели в блоке вывода.


7. Взаимосвязь кода и интерфейса

Синхронизация кода и интерфейса

Главный принцип — код и интерфейс должны быть синхронизированы, иначе интерфейс не сможет корректно отобразить результат.


8. Логи и диагностика

Блок Логи (tail) отображает состояние запущенного сервиса в реальном времени и помогает:

  • Отследить ошибки
  • Проверить успешную инициализацию модели
  • Убедиться, что BentoML‑сервис запущен корректно

Доступные источники логов

BentoML

Логи самого сервиса инференса и обработки запросов

Admin API

Логи административного API и управления контейнером

Start Service

Логи запуска и инициализации сервиса

Qubu Agent

Логи агента мониторинга и синхронизации артефактов

Типичные ошибки


9. Доступ к сервису

Режим доступа определяет, кто может выполнять запросы к модели:

Публичный доступ

Модель доступна всем без авторизации. Идеально для:

  • Демонстрационных моделей
  • Открытых API
  • Прототипов и экспериментов
curl -X POST "https://qubu.ai/api/models/model-name/inference/proxy/predict" \
  -H "Content-Type: application/json" \
  -d '{"inputs": {...}}'

Публичные модели могут быть использованы кем угодно. Не размещайте в них чувствительные данные.

Доступ для зарегистрированных пользователей

Модель доступна только авторизованным пользователям Qubu. Требуется API-ключ:

curl -X POST "https://qubu.ai/api/models/model-name/inference/proxy/predict" \
  -H "Authorization: Bearer <API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{"inputs": {...}}'

API-ключ можно получить в настройках профиля на платформе Qubu.

Приватный доступ

Модель доступна только владельцу и приглашённым участникам. Максимальная безопасность:

curl -X POST "https://qubu.ai/api/models/model-name/inference/proxy/predict" \
  -H "Authorization: Bearer <API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{"inputs": {...}}'

Функции приватного доступа:

  • Управление списком участников
  • Индивидуальные разрешения
  • Полный контроль над использованием

10. Продвинутые настройки BentoML (resources / traffic / batching)

Qubu не выносит в UI многие “операторские” параметры BentoML (таймауты, concurrency, batching, ограничения ресурсов) — их проще и надёжнее задавать в коде.

Где это обычно настраивается:

  • resources / device: в @bentoml.service(...) и логике загрузки модели (CPU/GPU, пути, кеши)
  • traffic / timeouts / concurrency: в параметрах @bentoml.api(...) и/или настройках сервера BentoML
  • batching: через встроенные механизмы BentoML (если вам это действительно нужно)

Если вы не уверены, нужно ли это — чаще всего достаточно корректно выставить requirements.txt, загрузку модели в __init__ и явные маршруты/схемы входа/выхода.

Итог

1. Выберите источник сервиса

Либо напишите class-based BentoML‑сервис в service.py, либо загрузите готовый .bento архив

2. Настройте UI

Определите входные поля и выходные данные

3. Разверните

Выберите машину и запустите endpoint

4. Используйте

Получите готовый API и веб-форму для тестирования

Ключевые преимущества

Инференс на Qubu объединяет Python‑код и визуальную настройку интерфейса. Вы пишете class-based сервис на BentoML, описываете структуру данных в конструкторе UI, выбираете машину и разворачиваете сервис. После запуска модель доступна через веб‑форму и REST API, а все изменения можно обновить и перезапустить в один клик.