Решения

Gradio и FastAPI на GPU: API и UI для моделей

Задача страницы. Практический гид по развёртыванию UI и API для моделей на GPU‑инстансах с помощью Gradio (быстрый фронт/демо) и FastAPI (прод‑API: REST/SSE/WebSocket). Разберём типовые архитектуры (single‑/multi‑GPU, MIG), стриминг токенов/аудио, очереди и backpressure, конфиги контейнеров и K8s, метрики/алерты, экономику и траблшутинг. Используем NVMe‑кэш, профили On‑Demand (низкая латентность) и Interruptible (оффлайн/батч). Соседние разделы: https://cloudcompute.ru/solutions/triton-inference-server/, https://cloudcompute.ru/solutions/realtime-streaming/, https://cloudcompute.ru/solutions/mig/, https://cloudcompute.ru/solutions/llm-inference/observability/.

TL;DR

  • Паттерны:
    • Gradio — быстрый UI/демо, очереди запросов (queue()), прогрев модели, стриминг генерации.
    • FastAPI — прод‑API: REST + SSE (стрим токенов) + WebSocket (потоки аудио/видео).
    • Роутер поверх нескольких бэкендов: локальный Torch/ONNX, Triton или внешние сервисы. См. https://cloudcompute.ru/solutions/triton-inference-server/
  • GPU‑эффективность: микробатч ≤ 4, U≈0.6–0.75, FP16/BF16, pinned/zero‑copy, NVMe‑кэш моделей. Для мелких сервисов — MIG. См. https://cloudcompute.ru/solutions/mig/
  • Стриминг: SSE для LLM/ASR‑токенов, WS для двунаправленного аудио. Гарантируйте keep-alive и «принудительный» flush.
  • Наблюдаемость: E2E p95, queue_depth, token_rate, gpu_util/HBM, ошибки/таймауты; экспорт в Prometheus. См. https://cloudcompute.ru/solutions/llm-inference/observability/
  • Экономика: GPU_count ≈ ceil(QPS × t_infer / U), Cost_per_1000 ≈ (c_gpu × 1000 × t_infer) / (3600 × U). См. https://cloudcompute.ru/solutions/cost-planner/
  • Продакшн: readiness/liveness, rate‑limit, CORS/ACL, лимиты на токены/размеры файлов, канарейки и автоскейл.

Сценарии (когда это нужно)

  • LLM‑чат/ассистенты: Gradio для UX + FastAPI для интеграций (SSE для токенов).
  • ASR/TTS/VC: WebSocket‑потоки и SSE‑уведомления; буфер 200–500 мс, политику дропа.
  • CV/детект/OCR: REST‑эндпойнты + Gradio‑демо для контрольных картинок/видео.
  • Генерация изображений (DIFF): Gradio для итераций, FastAPI для батч‑запросов; каторая — в Interruptible.
  • Аналитика/рексис: лёгкие ранкеры/эмбеддинги на MIG, UI для отладки запросов. См. https://cloudcompute.ru/solutions/recsys/

Архитектуры и пайплайны

A) Single‑GPU: Gradio UI + локальная модель

				
					Browser ──HTTP──> Gradio (queue, stream)
                   └─> Model Runner (Torch/ONNX, FP16)
                        └─> NVMe cache (weights/tokenizers)


				
			

Особенности: минимальная латентность, прогрев модели при старте, ограничение очереди и микробатча.

B) FastAPI Gateway: REST/SSE/WS + несколько бэкендов

				
					Client ──HTTP/WS──> FastAPI Gateway
                      ├─ Local Torch/ONNX
                      ├─ Triton Inference Server (gRPC/HTTP)
                      └─ Доп. сервисы (CV/ASR/TTS)
                             ↓ Prometheus/Logs
				
			

Особенности: маршрутизация по модели/SLA, таймауты/ретраи, деградации (урезать токены/шаги).

C) Мультимодельный узел с MIG

				
					Ingress (LB)
  └─ K8s Node (A100/H100 MIG)
       ├─ Pod: LLM-small  (MIG 2g)
       ├─ Pod: ASR        (MIG 1g)
       ├─ Pod: Embeddings (MIG 1g)
       └─ Pod: TTS        (MIG 1g)


				
			

Особенности: изоляция SM/HBM/копировщиков; следить за packing_efficiency. См. https://cloudcompute.ru/solutions/mig/

Профили GPU и ориентиры (онлайн‑нагрузка)

Диапазоны для интерактивных сценариев при U≈0.7, FP16, микробатч ≤ 4. Реальные значения зависят от модели/разрешения/IO.

Профиль GPU

Память

LLM (ток/с)

ASR/TTS (RPS)

CV инференс (RPS)

Комментарии

24 ГБ (Compact)

24 ГБ

100–300

10–30

100–300

Демки/малые модели/OCR/эмбеддинги.

48 ГБ (Balanced)

48 ГБ

300–700

30–70

300–700

Баланс latency/качества.

80 ГБ (HQ)

80 ГБ

700–1500

70–150

700–1500

Крупные модели/двойной стриминг.

Тонкая настройка производительности: https://cloudcompute.ru/solutions/performance-tuning/ и https://cloudcompute.ru/solutions/throughput-vs-latency/

Конфиги (Docker/K8s) и скелеты кода

Docker Compose: Gradio + FastAPI + Triton (опционально)

				
					version: "3.9"

x-env: &env
  PRECISION: "fp16"
  MAX_TOKENS: "256"
  MAX_MICROBATCH: "4"
  CACHE_DIR: "/nvme/cache"
  MODELS_DIR: "/nvme/models"

services:
  gradio-ui:
    image: cloudcompute/gradio-ui:latest
    environment: *env
    deploy:
      resources:
        reservations:
          devices: [{ capabilities: ["gpu"] }]
    ports: ["7860:7860"]
    volumes:
      - /nvme/models:/nvme/models
      - /nvme/cache:/nvme/cache
    command: ["python","app_gradio.py","--port","7860","--host","0.0.0.0"]

  api:
    image: cloudcompute/fastapi-gpu:latest
    environment:
      <<: *env
      ENABLE_SSE: "true"
    deploy:
      resources:
        reservations:
          devices: [{ capabilities: ["gpu"] }]
    ports: ["9090:9090"]
    volumes:
      - /nvme/models:/nvme/models
      - /nvme/cache:/nvme/cache
    command: ["gunicorn","-k","uvicorn.workers.UvicornWorker","-w","1","--threads","4","--timeout","0","--keep-alive","75","-b","0.0.0.0:9090","app_api:app"]

  triton:  # опционально
    image: cloudcompute/triton:latest
    deploy:
      resources:
        reservations:
          devices: [{ capabilities: ["gpu"] }]
    ports: ["8000:8000","8001:8001"]
    volumes:
      - /nvme/models:/models


				
			

Kubernetes: FastAPI (readiness/liveness + ресурсы)

				
					apiVersion: apps/v1
kind: Deployment
metadata: { name: fastapi-gpu }
spec:
  replicas: 3
  selector: { matchLabels: { app: fastapi-gpu } }
  template:
    metadata: { labels: { app: fastapi-gpu } }
    spec:
      containers:
        - name: api
          image: cloudcompute/fastapi-gpu:latest
          ports: [{ containerPort: 9090 }]
          env:
            - { name: PRECISION, value: "fp16" }
            - { name: MAX_TOKENS, value: "256" }
            - { name: MAX_MICROBATCH, value: "4" }
          readinessProbe: { httpGet: { path: /healthz, port: 9090 }, periodSeconds: 5 }
          livenessProbe:  { httpGet: { path: /livez,  port: 9090 }, periodSeconds: 10, failureThreshold: 5 }
          resources:
            limits: { nvidia.com/gpu: 1, cpu: "4", memory: "32Gi" }
      nodeSelector: { pool: on-demand }


				
			

Конфиг приложения (YAML)

				
					app:
  cors_origins: ["https://your.domain"]
  rate_limit_qps: 50
  timeout_ms:
    llm: 90000
    asr: 30000
    cv: 20000
  stream:
    sse: true
    ws_audio: true
  batching:
    max_microbatch: 4
    max_queue: 128
  models:
    llm:  { path: "/nvme/models/llm-small", max_tokens: 256 }
    asr:  { path: "/nvme/models/asr", chunk_ms: 500 }
    cv:   { path: "/nvme/models/detector", max_side: 1280 }
  nvme:
    cache_dir: "/nvme/cache"


				
			

Gradio: стриминг LLM + очередь

				
					import gradio as gr, torch
from transformers import AutoTokenizer, AutoModelForCausalLM, TextIteratorStreamer
from threading import Thread

tok = AutoTokenizer.from_pretrained("/nvme/models/llm-small", local_files_only=True)
model = AutoModelForCausalLM.from_pretrained("/nvme/models/llm-small", torch_dtype=torch.float16, local_files_only=True).to("cuda").eval()

def generate_stream(prompt, max_new_tokens=256, temperature=0.7):
    inputs = tok(prompt, return_tensors="pt").to("cuda")
    streamer = TextIteratorStreamer(tok, skip_special_tokens=True)
    gen_kwargs = dict(**inputs, max_new_tokens=max_new_tokens, temperature=temperature, do_sample=temperature>0)
    th = Thread(target=model.generate, kwargs={**gen_kwargs, "streamer": streamer}); th.start()
    text = ""
    for new_text in streamer:
        text += new_text
        yield text

with gr.Blocks() as demo:
    gr.Markdown("### LLM демо (стриминг)")
    with gr.Row():
        inp = gr.Textbox(label="Промпт")
    out = gr.Textbox(label="Ответ", lines=8)
    btn = gr.Button("Сгенерировать")
    btn.click(generate_stream, inputs=[inp], outputs=[out])
    demo.queue(concurrency_count=2, max_size=128)
demo.launch(server_name="0.0.0.0", server_port=7860)


				
			

FastAPI: REST + SSE (стрим токенов) + WebSocket (аудио)

				
					from fastapi import FastAPI, Body, WebSocket
from sse_starlette.sse import EventSourceResponse
import asyncio, time, json

app = FastAPI()

@app.get("/healthz")
def health(): return {"ok": True}
@app.get("/livez")
def live():   return {"ok": True}

# REST: синхронный инференс (условный вызов локальной модели)
@app.post("/v1/complete")
def complete(payload: dict = Body(...)):
    prompt = payload["prompt"]; t0 = time.time()
    text = run_llm_sync(prompt, max_tokens=payload.get("max_tokens", 256))
    return {"ok": True, "latency_ms": int((time.time()-t0)*1000), "text": text}

# SSE: поток частичных токенов
@app.post("/v1/stream")
def stream(payload: dict = Body(...)):
    prompt = payload["prompt"]
    async def gen():
        async for token in run_llm_stream(prompt):
            yield {"event": "token", "data": token}
        yield {"event": "done", "data": "{}"}
    return EventSourceResponse(gen())

# WebSocket: поток аудио (ASR chunking 200–500 мс) → частичные гипотезы
@app.websocket("/ws/asr")
async def ws_asr(ws: WebSocket):
    await ws.accept()
    buffer = b""
    try:
        while True:
            chunk = await ws.receive_bytes()
            buffer += chunk
            if len(buffer) > 16000*2*0.3:  # ~300ms @16kHz, 16-bit
                text_partial = asr_score(buffer); buffer = b""
                await ws.send_json({"partial": text_partial})
    except Exception:
        await ws.close()


				
			

Для бэкенда используйте локальную модель (Torch/ONNX) или прокиньте запрос в Triton. Подробно: https://cloudcompute.ru/solutions/triton-inference-server/

Наблюдаемость/метрики/ алерты

Метрики сервиса:

  • http_requests_total, latency_seconds{route=…} (p50/p95/p99), queue_depth, timeouts_total, errors_total.
  • LLM/ASR: tokens_per_second, rtf (real‑time factor), stream_gaps_ms.
  • GPU: gpu_utilization, gpu_memory_bytes, gpu_copy_util, nvme_{read,write}_mb_s.

Алерты (примеры):

  • latency_p95 > SLA — урезать max_tokens/steps, уменьшить батч/микробатч, расширить профиль/MIG, прогрев кэша.
  • queue_depth↑ + timeouts↑ — узкое место стадии; добавить реплик/увеличить GPU/перестроить роутинг.
  • gpu_copy_util≈100% при низком SM — упор в PCIe/копировщики → pinned/zero‑copy, фьюзинг препроцесса, меньше промежуточных копий.
  • gpu_mem_peak/HBM > 0.9 — FP16/BF16, меньшие токены/резолюции, выгрузка неиспользуемых тензоров.

Сбор и панели: https://cloudcompute.ru/solutions/monitoring-logging/ • наблюдаемость LLM/инференса — https://cloudcompute.ru/solutions/llm-inference/observability/

Экономика и формулы

Обозначения: c_gpu — цена/час, U — целевая загрузка, t_infer — среднее время запроса, QPS — входной поток.

  • Сколько GPU нужно: GPU_count ≈ ceil( (QPS × t_infer) / U ).
  • Стоимость 1 000 запросов: Cost_per_1000 ≈ (c_gpu × 1000 × t_infer) / (3600 × U).
  • Стриминг (SSE): держите keep-alive; при QPS_stream учитывайте open‑коннекты: Conn ≈ QPS_stream × avg_stream_secs.
  • MIG vs целый GPU: для мелких сервисов снижает стоимость при достаточной packing_efficiency. См. https://cloudcompute.ru/solutions/mig/
  • On‑Demand vs Interruptible: интерактив (Gradio/FastAPI) — On‑Demand; генерация/ETL — Interruptible. См. https://cloudcompute.ru/solutions/interruptible-patterns/, https://cloudcompute.ru/solutions/throughput-vs-latency/

Безопасность и политики

  • PII/контент: маскирование идентификаторов, фильтрация загрузок, лимиты размера/типа файла. См. https://cloudcompute.ru/solutions/security/
  • Секреты/ключи: только Secret‑хранилища/ENV; ротация; запрет ключей в образах.
  • CORS/ACL/Rate‑limit: белые списки Origin/Token, лимиты по IP/тенанту, анти‑бот.
  • Guardrails для LLM: нормализация промптов/ответов, лимиты на токены и цепочки, блок‑листы. См. https://cloudcompute.ru/solutions/llm-inference/observability/
  • Ретеншн: TTL на артефакты/загрузки/логи; хэш‑имена файлов; приватные бакеты.

Траблшутинг

Симптом

Возможная причина

Решение

Высокая p95‑латентность

Узкое место в LLM/DIFF/ASR; нет стриминга

Включить SSE/WS, уменьшить max_tokens/steps, повысить параллельность/реплики

Затыки очереди Gradio

queue() без лимитов/микробатч слишком большой

concurrency_count≤2–4, max_size, уменьшить микробатч

GPU простаивает

Препроцесс/I/O на CPU

NVJPEG/NVDEC, pinned/zero‑copy, фьюзинг препроцесса, выделить CPU лимиты

CUDA OOM

Пики VRAM (большие токены/резолюции)

FP16/BF16, лимит токенов/изображений, выгрузка кэшей, MIG профиль побольше

SSE рвётся

Прокси/таймауты/keep‑alive

Увеличить таймауты, посылать heartbeat, отключить буферизацию на прокси

WS‑аудио «дребезжит»

Мало буферов/неправильный чанк

200–500 мс чанки, ring‑buffer, backpressure и drop‑политика

Прогрев долгий

Кэш моделей пуст/холодный NVMe

Прогрев при старте, закреплённые пути /nvme/models, ленивые загрузки

Разные версии API

Канарейки/несогласованные схемы

Семантические версии, контракт схем, поэтапный rollout/rollback

Как запустить в cloudcompute.ru

  1. Перейдите в Шаблоны запусков: https://cloudcompute.ru/solutions/templates/ — выберите Gradio UI, FastAPI GPU API и/или Triton Inference Server.
  2. Выберите профиль GPU (24/48/80 ГБ) или раскладку MIG под SLA. См. https://cloudcompute.ru/solutions/mig/
  3. Смонтируйте NVMe: /nvme/models (веса/токенайзеры), /nvme/cache (артефакты).
  4. Задайте переменные (PRECISION, MAX_TOKENS, MAX_MICROBATCH, пути моделей), включите стриминг.
  5. В продакшне — readiness/liveness, автоскейл по U/queue/latency, дашборды и алерты, канареечные релизы.

Чек‑лист перед продом

  • Заданы SLA: E2E и по стадиям; включён стриминг (SSE/WS) и деградации.
  • Прогреты модели/кэши на NVMe; gpu_mem_peak/HBM < 0.9, стабильный token_rate.
  • Настроены очереди (max_queue, max_microbatch), лимиты на токены/файлы, CORS/ACL.
  • Мониторинг: p95 latency, queue_depth, timeouts, gpu_util, HBM, copy_util; экспорт в Prometheus.
  • Политики безопасности/ретеншна и guardrails внедрены.
  • Пулы On‑Demand/Interruptible и/или MIG согласованы; канареечный деплой готов.
  • Нагрузочный прогон ≥ 30 мин с целевым трафиком.