# BentoML

**BentoML** ist ein modernes Open-Source-Framework für **den Aufbau, die Bereitstellung und das Skalieren von KI-Anwendungen**. Es überbrückt die Lücke zwischen ML-Experimenten und Produktionsbereitstellung, sodass Sie jedes Modell aus jedem Framework in wenigen Minuten in einen produktionsbereiten API-Dienst verpacken können. Führen Sie BentoML in Clore.ais GPU-Cloud aus, um KI-Anwendungen kosteneffizient zu hosten.

***

## Was ist BentoML?

BentoML macht es einfach, ein trainiertes Modell zu nehmen und in einen skalierbaren API-Dienst zu verwandeln:

* **Framework-agnostisch:** PyTorch, TensorFlow, JAX, scikit-learn, HuggingFace, XGBoost, LightGBM und mehr
* **Bento:** Ein eigenständiges, reproduzierbares Artefakt (Modell + Code + Abhängigkeiten)
* **Runner:** Skalierbare Inferenz-Einheit für Modelle mit automatischem Batching
* **Service:** FastAPI-ähnliche HTTP/gRPC-Service-Definition
* **BentoCloud:** Optionale verwaltete Bereitstellungsplattform
* **Docker-first:** Jedes Bento kann mit einem Befehl containerisiert werden

**Wichtige Funktionen:**

* Adaptive Micro-Batching zur Durchsatzoptimierung
* Eingangs-/Ausgangsvalidierung integriert mit Pydantic
* OpenAPI-Spezifikation automatisch generiert
* Prometheus-Metriken integriert
* Unterstützung für Streaming-Antworten (LLMs)

***

## Voraussetzungen

| Anforderung | Minimum     | Empfohlen       |
| ----------- | ----------- | --------------- |
| GPU-VRAM    | 8 GB        | 16–24 GB        |
| GPU         | Jede NVIDIA | RTX 4090 / A100 |
| RAM         | 8 GB        | 16 GB           |
| Speicher    | 20 GB       | 40 GB           |
| Python      | 3.9+        | 3.11+           |

***

## Schritt 1 — Mieten Sie eine GPU auf Clore.ai

1. Melden Sie sich an bei [clore.ai](https://clore.ai).
2. Klicken Sie **Marktplatz** und wählen Sie eine GPU-Instanz mit ≥ 16 GB VRAM.
3. Docker-Image festlegen: Wir verwenden einen benutzerdefinierten Build (siehe Schritt 2).
4. Offene Ports festlegen: `22` (SSH) und `3000` (BentoML-Service).
5. Klicken Sie **Mieten**.

***

## Schritt 2 — Dockerfile

BentoML hat kein offizielles GPU-Docker-Image, daher bauen wir eines:

```dockerfile
FROM pytorch/pytorch:2.1.2-cuda12.1-cudnn8-runtime

ENV DEBIAN_FRONTEND=noninteractive

RUN apt-get update && apt-get install -y \
    git wget curl \
    openssh-server \
    libgl1 libglib2.0-0 \
    && rm -rf /var/lib/apt/lists/*

# Konfiguriere SSH
RUN mkdir /var/run/sshd && \
    echo 'root:clore123' | chpasswd && \
    sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config

# Installiere BentoML und gängige ML-Bibliotheken
RUN pip install --upgrade pip && \
    pip install \
        bentoml \
        transformers \
        accelerate \
        diffusers \
        Pillow \
        numpy \
        scipy \
        tritonclient[all]

WORKDIR /workspace

EXPOSE 22 3000

CMD service ssh start && tail -f /dev/null
```

### Build und Push

Baue das Image und pushe es in dein eigenes Docker Hub-Konto (ersetze `YOUR_DOCKERHUB_USERNAME` durch deinen tatsächlichen Benutzernamen):

```bash
docker build -t YOUR_DOCKERHUB_USERNAME/bentoml-gpu:latest .
docker push YOUR_DOCKERHUB_USERNAME/bentoml-gpu:latest
```

{% hint style="info" %}
BentoML stellt kein offizielles GPU-Docker-Image auf Docker Hub bereit. Die `bentoml/bento-server` Images auf Docker Hub dienen dem Bereitstellen vorverpackter Bentos und enthalten keine CUDA-Unterstützung. Baue das Image aus dem obigen Dockerfile für GPU-fähige Bereitstellungen auf Clore.ai.
{% endhint %}

***

## Schritt 3 — Verbindung per SSH

```bash
ssh root@<clore-host> -p <assigned-ssh-port>
```

BentoML verifizieren:

```bash
bentoml --version
# Erwartet: bentoml, version 1.x.x
```

***

## Schritt 4 — Ihr erster BentoML-Service

### Einfacher Textklassifizierer

Erstellen Sie eine Service-Datei:

```bash
mkdir -p /workspace/my-service
cat > /workspace/my-service/service.py << 'EOF'
import bentoml
from bentoml.io import JSON, Text
import numpy as np

# Definiere einen Runner (die Modelleinheit)
class TextClassifierRunnable(bentoml.Runnable):
    SUPPORTED_RESOURCES = ("gpu", "cpu")
    SUPPORTS_CPU_MULTI_THREADING = True
    
    def __init__(self):
        import torch
        from transformers import pipeline
        
        self.classifier = pipeline(
            "text-classification",
            model="distilbert-base-uncased-finetuned-sst-2-english",
            device=0 if torch.cuda.is_available() else -1,
        )
    
    @bentoml.Runnable.method(batchable=True, batch_dim=0)
    def classify(self, texts: list[str]) -> list[dict]:
        results = self.classifier(texts)
        return results

# Erstelle Runner
classifier_runner = bentoml.Runner(
    TextClassifierRunnable,
    name="text_classifier",
    max_batch_size=32,
    max_latency_ms=100,
)

# Definiere Service
svc = bentoml.Service(
    name="text_classifier_service",
    runners=[classifier_runner],
)

@svc.api(input=Text(), output=JSON())
async def classify(text: str) -> dict:
    """Klassifiziere die Stimmung des Eingabetextes."""
    results = await classifier_runner.classify.async_run([text])
    return results[0]
EOF
```

### Starte den Service

```bash
cd /workspace/my-service

bentoml serve service:svc \
    --host 0.0.0.0 \
    --port 3000 \
    --reload
```

{% hint style="info" %}
Der `--reload` Flag aktiviert Hot-Reload während der Entwicklung. Entfernen Sie es in der Produktion für Stabilität.
{% endhint %}

***

## Schritt 5 — Zugriff auf den Service

Öffnen Sie die automatisch generierte Swagger-UI:

```
http://<clore-host>:<public-port-3000>
```

Oder teste über `curl`:

```bash
curl -X POST http://<clore-host>:<public-port-3000>/classify \
    -H "Content-Type: text/plain" \
    -d "This GPU cloud service is amazing!"
```

Erwartete Antwort:

```json
{"label": "POSITIVE", "score": 0.9986}
```

***

## Schritt 6 — Bildklassifizierungsdienst

### Vision-Modell-Service

```python
# /workspace/vision-service/service.py
import bentoml
from bentoml.io import Image, JSON
from PIL import Image as PILImage
import numpy as np

class ImageClassifierRunnable(bentoml.Runnable):
    SUPPORTED_RESOURCES = ("gpu",)
    SUPPORTS_CPU_MULTI_THREADING = False
    
    def __init__(self):
        import torch
        import torchvision.transforms as transforms
        from torchvision.models import resnet50, ResNet50_Weights
        
        self.device = "cuda" if torch.cuda.is_available() else "cpu"
        weights = ResNet50_Weights.DEFAULT
        self.model = resnet50(weights=weights).to(self.device)
        self.model.eval()
        self.preprocess = weights.transforms()
        self.categories = weights.meta["categories"]
    
    @bentoml.Runnable.method(batchable=True, batch_dim=0)
    def predict(self, images: list) -> list[dict]:
        import torch
        
        batch = torch.stack([self.preprocess(img) for img in images]).to(self.device)
        
        with torch.no_grad():
            predictions = self.model(batch).softmax(dim=1)
        
        results = []
        for pred in predictions:
            top5 = pred.topk(5)
            results.append({
                "predictions": [
                    {"label": self.categories[idx], "score": round(score.item(), 4)}
                    for score, idx in zip(top5.values, top5.indices)
                ]
            })
        return results


image_runner = bentoml.Runner(
    ImageClassifierRunnable,
    name="image_classifier",
    max_batch_size=16,
)

svc = bentoml.Service(
    name="image_classifier_service",
    runners=[image_runner],
)

@svc.api(input=Image(), output=JSON())
async def classify(image: PILImage.Image) -> dict:
    """Klassifiziere ein Bild mit ResNet50."""
    results = await image_runner.predict.async_run([image])
    return results[0]
```

```bash
bentoml serve service:svc --host 0.0.0.0 --port 3000
```

Teste mit einem Bild:

```bash
curl -X POST http://<clore-host>:<public-port-3000>/classify \
    -H "Content-Type: image/jpeg" \
    --data-binary @/path/to/image.jpg
```

***

## Schritt 7 — LLM-Streaming-Service

Für Sprachmodelle mit Streaming-Antworten:

```python
# /workspace/llm-service/service.py
import bentoml
from bentoml.io import JSON, Text
from typing import AsyncGenerator

class LLMRunnable(bentoml.Runnable):
    SUPPORTED_RESOURCES = ("gpu",)
    SUPPORTS_CPU_MULTI_THREADING = False
    
    def __init__(self):
        from transformers import AutoModelForCausalLM, AutoTokenizer
        import torch
        
        model_name = "microsoft/phi-2"
        self.tokenizer = AutoTokenizer.from_pretrained(model_name)
        self.model = AutoModelForCausalLM.from_pretrained(
            model_name,
            torch_dtype=torch.float16,
            device_map="auto"
        )
    
    @bentoml.Runnable.method(batchable=False)
    def generate(self, prompt: str, max_tokens: int = 200) -> str:
        import torch
        
        inputs = self.tokenizer(prompt, return_tensors="pt").to("cuda")
        
        with torch.no_grad():
            outputs = self.model.generate(
                **inputs,
                max_new_tokens=max_tokens,
                do_sample=True,
                temperature=0.7,
                pad_token_id=self.tokenizer.eos_token_id,
            )
        
        return self.tokenizer.decode(outputs[0], skip_special_tokens=True)


llm_runner = bentoml.Runner(LLMRunnable, name="llm")

svc = bentoml.Service("llm_service", runners=[llm_runner])

@svc.api(input=JSON(), output=Text())
async def generate(body: dict) -> str:
    prompt = body.get("prompt", "")
    max_tokens = body.get("max_tokens", 200)
    return await llm_runner.generate.async_run(prompt, max_tokens)
```

***

## Schritt 8 — Speichern und Baue ein Bento

Eine **Bento** ist ein verpacktes, reproduzierbares Artefakt:

```python
# /workspace/build_bento.py
import bentoml

# Speichere Modell im BentoML-Modellspeicher
import torch
from torchvision.models import resnet50, ResNet50_Weights

model = resnet50(weights=ResNet50_Weights.DEFAULT)
model.eval()

saved_model = bentoml.pytorch.save_model(
    name="resnet50",
    model=model,
    labels={"framework": "pytorch", "task": "image-classification"},
    metadata={"accuracy": 0.80, "dataset": "ImageNet"}
)
print(f"Model saved: {saved_model.tag}")
```

```bash
python /workspace/build_bento.py

# Liste gespeicherter Modelle
bentoml models list

# Baue ein Bento (erfordert bentofile.yaml)
bentoml build
```

### bentofile.yaml

```yaml
service: "service:svc"
labels:
  owner: "ml-team"
  stage: "production"
include:
  - "*.py"
python:
  packages:
    - torch
    - torchvision
    - transformers
    - Pillow
    - numpy
docker:
  python_version: "3.11"
  cuda_version: "12.1"
  system_packages:
    - libgl1
```

```bash
bentoml build

# Liste gebaute Bentos
bentoml list

# Containerize
bentoml containerize image_classifier_service:latest \
    --image-tag YOUR_DOCKERHUB_USERNAME/my-bento:latest
```

***

## Überwachung und Metriken

BentoML stellt Prometheus-Metriken unter `/metrics`:

```bash
curl http://<clore-host>:<public-port-3000>/metrics
```

Wichtige Metriken:

```
# Anfrage-Rate
bentoml_service_request_total{endpoint="classify", http_status_code="200"}
# Latenz
bentoml_service_request_duration_seconds{endpoint="classify"}
# Runner-Durchsatz  
bentoml_runner_request_total{runner_name="image_classifier"}
```

***

## Adaptive Batching-Konfiguration

```python
# Feineinstellung des Batching-Verhaltens
image_runner = bentoml.Runner(
    ImageClassifierRunnable,
    name="image_classifier",
    max_batch_size=64,          # Max. Anfragen pro Batch
    max_latency_ms=50,          # Maximale Wartezeit vor dem Dispatch
)
```

***

## Fehlerbehebung

### Service startet nicht

```
ERROR - Fehler beim Initialisieren des Runners
```

**Lösungen:**

* Überprüfe CUDA-Verfügbarkeit: `python -c "import torch; print(torch.cuda.is_available())"`
* Überprüfe GPU-VRAM: `nvidia-smi`
* Prüfe, ob der Modell-Download abgeschlossen ist (suche nach Download-Fortschritt in den Logs)

### Port 3000 nicht erreichbar

```bash
# Stelle sicher, dass der Service an 0.0.0.0 gebunden ist (nicht localhost)
bentoml serve service:svc --host 0.0.0.0 --port 3000
```

### Hohe Latenz bei der ersten Anfrage

Das ist normal — die erste Anfrage löst das Laden des Modells (Warm-up) aus. Alle nachfolgenden Anfragen werden schnell sein. Füge nach dem Start einen Warm-up-Endpunkt-Aufruf hinzu:

```bash
# Warm-up nach dem Start
sleep 10 && curl -s -o /dev/null http://localhost:3000/healthz
```

### Importfehler

```
ModuleNotFoundError: No module named 'transformers'
```

**Lösung:**

```bash
pip install transformers accelerate
```

***

## Clore.ai GPU-Empfehlungen

BentoML ist ein Serving-Framework — GPU-Anforderungen hängen vollständig vom Modell ab, das Sie bereitstellen. Das ist bei gängigen Workloads zu erwarten:

| GPU       | VRAM  | Clore.ai-Preis | LLM (7B Q4) Durchsatz | Diffusion (SDXL) | Vision (ResNet50) |
| --------- | ----- | -------------- | --------------------- | ---------------- | ----------------- |
| RTX 3090  | 24 GB | \~$0.12/Stunde | \~80 tok/s            | \~4 img/min      | \~400 req/s       |
| RTX 4090  | 24 GB | \~$0.70/Stunde | \~140 tok/s           | \~8 img/min      | \~700 req/s       |
| A100 40GB | 40 GB | \~$1.20/Stunde | \~110 tok/s           | \~6 img/min      | \~1200 req/s      |
| A100 80GB | 80 GB | \~$2.00/Stunde | \~130 tok/s           | \~7 img/min      | \~1400 req/s      |

**Anwendungsleitfaden:**

* **LLM-API-Serving (7B–13B):** RTX 3090 (\~0,12 $/Std.) — optimales Preis-Leistungs-Verhältnis
* **Image-Generierungs-APIs:** RTX 3090 oder RTX 4090 je nach Durchsatzanforderungen
* **Große Modelle (34B–70B Q4):** A100 40GB (\~1,20 $/Std.) — passt bequem
* **Produktions-Multi-Model-Serving:** A100 80GB für mehr Speicher-Headroom

{% hint style="info" %}
BentoMLs **adaptive Micro-Batching** ist besonders effektiv auf A100 — der Hardware-Scheduler verarbeitet Batches effizient und erzielt mehr Durchsatz pro Dollar als naives Einzelanfragen-Serving. Für stark frequentierte APIs liefert die A100 40GB oft ein besseres ROI als zwei RTX 4090.
{% endhint %}

***

## Nützliche Ressourcen

* [Offizielle BentoML-Dokumentation](https://docs.bentoml.com)
* [BentoML GitHub](https://github.com/bentoml/BentoML)
* [BentoML Beispiele](https://github.com/bentoml/BentoML/tree/main/examples)
* [BentoML Discord-Community](https://l.bentoml.com/join-slack-space)
* [BentoML Galerie](https://www.bentoml.com/gallery)
* [Quickstart: Serving von LLMs](https://docs.bentoml.com/en/latest/get-started/quickstart.html)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.clore.ai/guides/guides_v2-de/mlops-and-bereitstellung/bentoml.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
