BLUF — vergrößern Sie einen Embedding-Batch erst, wenn Sie Padding-Anteil, Wartezeiten und die korrekte Zuordnung der Ergebnisse zu Request-IDs messen. Ein voller Batch ist nicht automatisch produktive Arbeit. Längenklassen können Padding reduzieren, führen aber eine zusätzliche Scheduling-Policy ein und garantieren keine bessere Tail-Latenz.
Für diesen Beitrag wurde ein fest versionierter MiniLM-Encoder auf einer CPU mit derselben synthetischen Ankunftsfolge unter drei Policies ausgeführt. Der Batch mit fester Breite belegte alle Request-Slots, verwendete jedoch 74,32 % seiner Eingabepositionen für Padding. Längenklassen reduzierten diesen Anteil auf 1,87 %; die p95-Latenz war in diesem Lauf trotzdem schlechter als bei Einzelverarbeitung. Das sind lokale Messwerte, keine Aussage zur GPU-Wirtschaftlichkeit oder Empfehlung zur Produktionsdimensionierung.
Legen Sie den semantischen Vertrag vor der Batch-Policy fest
Ein Encoder bildet Text auf einen Vektor ab. Eine Änderung der Batch-Bildung darf diesen Text nicht unbemerkt verändern. Fixieren Sie Modell- und Tokenizer-Revision, Eingabeformatierung, Maximallänge, Trunkierungsseite, Datentyp, Attention-Maske, Pooling und Normalisierung. Verknüpfen Sie Eingaben bei Sortierung, Ausführung und Ergebniszusammenführung durchgängig mit unveränderlichen Request-IDs. Gleiche Vektordimensionen allein belegen keine Gleichwertigkeit.
Die Padding-Dokumentation von Hugging Face trennt Padding, das Positionen ergänzt, von Trunkierung, die Inhalt entfernt. Eine kleinere Maximallänge ist keine reine Batch-Optimierung, wenn dabei Evidenz verloren geht. Die Diagnose zu Tokenbudgets für Reranker behandelt diese Verlustgrenze. Hier geht es dagegen um die Gruppierung unveränderter Encoder-Eingaben.
Definieren Sie genutzte Eingabepositionen als Summe der Einsen in der Attention-Maske, einschließlich berücksichtigter Spezialtokens. Die belegten Tensorpositionen ergeben sich aus Batchgröße mal gepaddeter Sequenzbreite, summiert über alle Ausführungen. Der Padding-Anteil beträgt eins minus genutzte Positionen geteilt durch belegte Positionen. Das beschreibt die Tensorbelegung, nicht verschwendete FLOPs: Kernel, Attention-Pfade und Hardware bestimmen die tatsächlichen Ausführungskosten.
Trennen Sie davon die Belegung der Request-Slots. Acht Requests in einem Batch mit acht Slots können vollständig belegt sein, obwohl die meisten Tokenpositionen Padding sind. Umgekehrt kann eine teilweise gefüllte Längenklasse weniger Arbeit verursachen und dennoch später fertig werden, weil sie auf passende Ankünfte wartet.
Der ausgeführte CPU-Versuch
Verwendet wurde all-MiniLM-L6-v2 von Sentence Transformers mit dieser festgelegten Revision, konkret onnx/model.onnx und tokenizer.json. Die Modellkarte beschreibt 384-dimensionale Ausgaben, maskenbewusstes Mean-Pooling mit Normalisierung und eine standardmäßige Trunkierungsgrenze von 256 Wordpieces. Dieser englische Encoder dient als reproduzierbarer Testfall, nicht als Empfehlung für deutsche Retrieval-Qualität.
Die Ausführung nutzte float32, ONNX Runtime 1.31.0, tokenizers 0.23.3, NumPy 2.5.4 und Python 3.12.13. Der Linux-Gast stellte die Affinitäts-CPUs 0–3 bereit. Die ORT-Session verwendete jeweils einen Intra-op- und Inter-op-Thread, sequenzielle Graphausführung und deaktiviertes Intra-op-Spinning. Vier Aufwärmaufrufe gingen den Messläufen voraus. Der Beitrag zu CPU-Thread-Budgets erläutert, warum Sie diese Einstellungen konstant halten sollten, statt gleichzeitig Batchgröße und Threadzahl zu erhöhen.
Der synthetische Satz „Inspect the bearing temperature.“ wurde je Burst 1-, 32-, 2-, 16-, 1-, 32-, 2- und 16-mal wiederholt. Einschließlich Spezialtokens ergaben sich die Längen 7, 162, 12, 82, 7, 162, 12 und 82. Acht identische Bursts trafen mit 400 Millisekunden Abstand ein; innerhalb eines Bursts lagen die Requests eine Millisekunde auseinander. Das ergibt 64 Requests und 4.208 berücksichtigte Positionen pro Policy. Keine gemessene Eingabe wurde gekürzt. Ein separater Überlängentest mit 302 Tokens erfüllte das Ablehnungskriterium über 256 Tokens. Er wurde nicht an das Modell gesendet und prüft keinen HTTP-Fehlerpfad.
Einzelrequests wurden ausgeführt, sobald der Worker frei war, und nur auf ihre eigene Länge gebracht. Die feste Batch-Policy gruppierte bis zu acht Requests und paddete jeden Batch auf 256 Positionen. Die Längenklassen verwendeten Obergrenzen von 32, 128 und 256, paddeten bei der Ausführung aber auf das tatsächlich längste Mitglied, nicht auf die Klassengrenze. Beide Batch-Policies erlaubten höchstens 15 Millisekunden bewusste Sammelwartezeit; acht passende bereitstehende Requests lösten eine frühere Ausführung aus.
Der Scheduler wählte stets zuerst den ältesten bereitstehenden Request. Dessen Längenklasse bestimmte die nächste Ausführung. So kann eine volle kurze Klasse einen älteren langen Request nicht immer wieder überholen; dafür kann Durchsatz verloren gehen. Die eingestellten 15 Millisekunden begrenzen nicht die gesamte Wartezeit: Der einzelne Worker kann noch beschäftigt sein. In Produktion benötigen Sie separate Regeln für Zulassung, Queue-Größe und Deadlines.
Gemessene Latenz, Padding und Speicher
| Policy | Padding | p50 ms | p95 ms | RSS MiB | Ausführungen |
|---|---|---|---|---|---|
| Einzeln | 0.00% | 84.10 | 163.08 | 259.88 | 64 |
| Fest 256 | 74.32% | 1701.92 | 2737.83 | 329.28 | 8 |
| Längenklassen | 1.87% | 78.86 | 180.00 | 330.70 | 24 |
Alle drei Policies schlossen 64 von 64 Requests ab. Pro Ausführung wurden im Mittel 1,00, 8,00 beziehungsweise 2,67 Requests verarbeitet. Die feste Policy belegte 16.384 Positionen, die Längenklassen 4.288 und die Einzelverarbeitung genau 4.208. Die maximal beobachteten Queue-Wartezeiten betrugen 141,16, 2.047,20 und 144,19 Millisekunden. Eine Sammelwartezeit darf deshalb nicht als durchgängige Queue-Garantie ausgewiesen werden.
Die Latenz beginnt bei der vorgesehenen Ankunft und endet nach Inferenz und Pooling. Sie enthält lokale Dispatch-Verzögerungen und Worker-Wartezeit, jedoch weder Tokenisierung noch Netzwerktransport oder HTTP-Verarbeitung: Alle Tokens wurden vor dem Replay vorbereitet. Jede Policy lief einmal, nacheinander, auf einem gemeinsam genutzten Host. Das Ergebnis der festen Policy kombiniert Gruppierung mit erheblichem Padding und isoliert nicht den kausalen Einfluss der Batchgröße. Ergänzen Sie vor einer Produktionsentscheidung einen Versuch mit Padding auf das längste Batch-Mitglied ohne Längenklassen.
Der Speicherwert ist ungefähr jede Millisekunde abgetasteter Prozess-RSS, weder maximale Tensorallokation noch GPU-Speicher. Derselbe Prozess behielt Modell- und Allokatorzustand zwischen den Läufen. Aus den ähnlichen RSS-Werten der festen und der gruppierten Policy lassen sich daher keine unabhängigen Speicherbedarfe ableiten. Nutzen Sie für eine Kapazitätsentscheidung frische Prozesse und gerätespezifische Messungen.
Entscheidend ist: Die Längenklassen schlugen hier die p95-Latenz der Einzelverarbeitung nicht. Weniger Padding allein ist kein Freigabekriterium. Wiederholen Sie Versuche in zufälliger Reihenfolge, behalten Sie Stichprobenzahlen pro Klasse bei und prüfen Sie die SLOs von Ankunft bis Abschluss, statt eine attraktive Belegungsquote zu optimieren.
Lesen Sie die Belegungsskizze richtig
| Request | Ein Batch mit Breite 8 | Zwei Längenklassen |
|---|---|---|
| A | ■■······ | ■■ |
| B | ■■■■■■■■ | ■■■■■■■■ |
| C | ■■······ | ■■ |
| D | ■■■■■■■■ | ■■■■■■■■ |
Diese kompakte Darstellung verwendet vier hypothetische Längen, nicht das gemessene Korpus. Ein ausgefüllter Block steht für eine berücksichtigte Position, ein Punkt für Padding. Dieselben vier Requests behalten in beiden Anordnungen ihre Länge. Ähnliche Längen zusammenzufassen entfernt leeren Raum im rechteckigen Tensor, verändert aber auch Ausführungsreihenfolge und gegebenenfalls Wartezeit. Die Skizze prognostiziert weder Kernel-Laufzeit noch GPU-Beschleunigung.
Stellen Sie die Zuordnung wieder her und testen Sie dünn besetzte Klassen
Im ausgeführten Versuch mit Längenklassen änderte sich die Abschlussreihenfolge. Ergebnisse wurden anhand ihrer Request-ID gesammelt und vor dem Vergleich mit den Einzel-Embeddings in die ursprüngliche Reihenfolge gebracht. Die maximale absolute Komponentendifferenz betrug für beide Batch-Policies in diesem Testfall 0,0. Das ist beobachtete Gleichheit in dieser Laufzeitumgebung, kein allgemeines Versprechen bitgleicher Ergebnisse über Geräte und Kernel hinweg. Behalten Sie explizite Toleranzen und Retrieval-Qualitätsprüfungen für die Produktion bei.
Der Scheduler-Regressionstest platzierte einen älteren langen Request vor acht kurzen und prüfte, dass der lange zuerst ausgewählt wurde. Das testet die Auswahlregel, nicht Fairness unter dauerhafter Last. Ergänzen Sie kontinuierliche kurze Ankünfte, Abbrüche, überschrittene Deadlines, Worker-Ausfälle und einen begrenzten Drain-Test vor der Einführung. Entfernen Sie niemals unvollendete lange Requests aus Latenzberichten: Das ist zensierte Arbeit, kein schneller Erfolg.
Der reproduzierbare Implementierungskern lautet: ohne Trunkierung tokenisieren; nicht unterstützte Längen ablehnen; Request-ID und Ankunft erhalten; ältesten zugelassenen Request wählen; passende bereitstehende Mitglieder auswählen; bei vollem Batch oder abgelaufener Sammelfrist ausführen; Padding und Attention-Maske erzeugen; inferieren; maskenbewusst poolen; Ergebnis nach Request-ID speichern; gewünschte Aufruferreihenfolge wiederherstellen. Messen Sie das Queue-Alter vor der Inferenz und erfassen Sie abgeschlossene, abgelehnte, abgebrochene und unvollendete Vorgänge getrennt.
Tritons Formkompatibilität ist eine eigene Prüfschranke
NVIDIAs Anleitung zu Dynamic Batching beschreibt Batching für zustandslose Modelle, maximale Sammelverzögerung und Queue-Policies. Sie rät bei den meisten Modellen von bevorzugten Batchgrößen ohne belegten Leistungsvorteil ab. Übernehmen Sie keine attraktive bevorzugte Größe aus einer anderen Installation.
Die Dokumentation zu Ragged Batching nennt übereinstimmende Eingabeformen zwischen Requests als Voraussetzung für gewöhnliches Dynamic Batching. Clientseitiges Padding oder ein geeigneter Wrapper muss diese Formen herstellen. Die Zuordnung zur gleichen Längenklasse macht die Tensorformen noch nicht identisch.
Ragged Input ist kein universeller Beschleunigungsschalter für Transformer. Die dokumentierten Backends verketten solche Eingaben zu eindimensionalen Tensoren. Das Modell benötigt passende Eingaben und Grenzinformationen, um Requests korrekt zu interpretieren. Eine gewöhnliche dichte Attention-Implementierung erhält diesen Vertrag nicht allein durch allow_ragged_batch. Für diesen Beitrag wurden weder Triton noch ein Ragged-Backend ausgeführt. Prüfen Sie exportiertes Modell, Masken, Grenzen und Ausgaben im tatsächlichen Serving-Pfad, bevor Sie Unterstützung behaupten.
Entscheidungstabelle: jeweils einen Fehlermechanismus ändern
| Beobachteter Fehler | Nächster kontrollierter Test | Abbruchkriterium |
|---|---|---|
| Viel Padding; Latenz akzeptabel | Zuerst auf längstes Mitglied padden | Veränderte Trunkierung oder Embeddings |
| Kurze Requests verfehlen Deadlines | Sammelwartezeit und Zulassung begrenzen | Ältester wartender Request fehlt in Telemetrie |
| Dünn besetzte lange Klasse wartet | Ältesten zuerst wählen oder Kapazität reservieren | Nur abgeschlossene Requests im Latenzbericht |
| Längenklassen ändern Reihenfolge | Nach Request-ID zuordnen und Reihenfolge herstellen | Ausgabe wird falschem Dokument zugeordnet |
| Ragged-Option scheitert an Formen | Modell-/Backend-Grenzvertrag prüfen | Konfiguration allein gilt als Kompatibilitätsnachweis |
Freigabe-Checkliste und nächster Versuch
Prüfschranke 1 — bewahren Sie Digests für Modell, Tokenizer, Eingaben und Ankunftsfolge sowie Abhängigkeiten, Thread-Einstellungen, Padding-/Trunkierungsregeln und Rollback-Konfiguration auf. Halten Sie Kundentext aus regulären Metriken heraus. Erfassen Sie Längen und begrenzte Aggregate statt Token-IDs oder Dokumenten.
Prüfschranke 2 — vergleichen Sie unveränderte Basis, Padding auf das längste Batch-Mitglied, feste Breite und begrenzte Längenklassen mit derselben vorgesehenen Ankunftsfolge. Trennen Sie geringe Last, Bursts und kapazitätsnahe Versuche. Erfassen Sie Timeouts und unvollendete Arbeit mit allen angebotenen Requests als Bezugsgröße, nicht nur Perzentile erfolgreicher Antworten.
Prüfschranke 3 — prüfen Sie Ergebniszuordnung, numerische Toleranz, Überlängenbehandlung und Aufgabenqualität. Testen Sie eine dünn besetzte lange Klasse gegen fortlaufend eintreffende kurze Requests. Das Alter des ältesten wartenden Requests muss auch ohne Abschlüsse beobachtbar bleiben.
Prüfschranke 4 — verlangen Sie eingehaltene Klassenlatenzen und Fehlerbudgets, bevor Sie Durchsatz- oder Speichervorteile bewerten. Behalten Sie die einfachere Policy, wenn zusätzliche Scheduling-Komplexität keinen wiederholbaren betrieblichen Nutzen liefert. CPU-Evidenz ersetzt keine Messungen auf vorgesehener GPU, Backend und Präzision.
Bringen Sie für eine Batch-Prüfung Encoder-Manifest, bereinigte Längenverteilung, freigegebene Ankunftsfolge und Latenzgrenzen pro Klasse mit. Eine Implementierungsprüfung kann daraus einen reproduzierbaren Versuch mit Rollback-Kriterium machen — kein Versprechen, dass größere Batches schneller sind.


