あなたはあなたのデータ変換フローに大規模なLLM呼び出しを持っていますか? これにより、AI ネイティブ ワークフローの Throughput が ~5× (≈80% 速く) 向上しました。そして最も重要なことは、バッチングが自動的に行われ、トラフィックに適応し、GPU を完全に活用するため、コードを変更する必要はありません。 CocoIndex ここでは、Adaptive Batching サポートを Cocoindex に構築する際に学んだことです。 しかし、まず、あなたのミックスにいるかもしれないいくつかの質問に答えましょう。 なぜバッチングは処理を加速させるのか? This consists of all the preparatory and administrative work required before the actual computation can begin. Examples include GPU kernel launch setup, Python-to-C/C++ transitions, scheduling of tasks, memory allocation and management, and bookkeeping performed by the framework. These overhead tasks are largely independent of the input size but must be paid in full for each call. Fixed overhead per call: This portion of the computation scales directly with the size and complexity of the input. It includes floating-point operations (FLOPs) performed by the model, data movement across memory hierarchies, token processing, and other input-specific operations. Unlike the fixed overhead, this cost increases proportionally with the volume of data being processed. Data-dependent work: 個別に処理する場合、個別に固定オーバーヘッドは個別に繰り返し発生し、全体のランタイムを迅速に支配することができ、特に個別に計算が比較的小さい場合に。対照的に、複数のアイテムをバッチで一緒に処理することは、個別オーバーヘッドの個別の影響を大幅に削減します。 バッチングにより、固定コストが多くのアイテムで削減され、また、データ依存の作業の効率を向上させるハードウェアおよびソフトウェアの最適化も可能になります。 これらの最適化には、GPUパイプラインのより効果的な利用、より良いキャッシュ利用、およびより少ないカーネルリリースが含まれます。 バッチングは、計算効率とリソース利用の両方を最適化することでパフォーマンスを大幅に向上させます。 Each function or API call carries a fixed overhead — GPU kernel launches, Python-to-C/C++ transitions, task scheduling, memory management, and framework bookkeeping. By processing items in batches, this overhead is spread across many inputs, dramatically reducing the per-item cost and eliminating repeated setup work. Amortizing one-time overhead: Larger batches allow the GPU to execute operations as dense, highly parallel matrix multiplications, commonly implemented as General Matrix–Matrix Multiplication (GEMM). This mapping ensures the hardware runs at higher utilization, fully leveraging parallel compute units, minimizing idle cycles, and achieving peak throughput. Small, unbatched operations leave much of the GPU underutilized, wasting expensive computational capacity. Maximizing GPU efficiency: Batching minimizes the frequency of memory transfers between CPU (host) and GPU (device). Fewer Host-to-Device (H2D) and Device-to-Host (D2H) operations mean less time spent moving data and more time devoted to actual computation. This is critical for high-throughput systems, where memory bandwidth often becomes the limiting factor rather than raw compute power. Reducing data transfer overhead: バッチングは、多くの小規模で非効率な計算を、現代のハードウェア能力を完全に活用する大規模で高度に最適化された操作に変換します。 普通のPythonコードのバッチングがどう見えるか Non-batching code – simple but less efficient (バッチングコードなし) パイプラインを組織する最も自然な方法は、データの一部ずつ処理することです。 for file in os.listdir(directory): content = file.read() chunks = split_into_chunks(content) for chunk in chunks: vector = model.encode([chunk.text]) # one item at a time index.upsert(file_id=file.name, chunk_offset=chunk.offset, vector=vector) これは読みやすく、論理:各部分は複数のステップを通してまっすぐ流れています。 手動パッチング - より効率的だが複雑 バッチングでスピードアップできますが、最も単純な「一度にすべてをバッチするだけ」のバージョンでさえ、コードを大幅に複雑にします。 # 1) Collect payloads and remember where each came from batch_texts = [] metadata = [] # (file_id, chunk_id) for file in os.listdir(directory): content = file.read() chunks = split_into_chunks(content) for chunk in chunks: batch_texts.append(chunk.text) metadata.append((file.name, chunk.offset)) # 2) One batched call (library will still mini-batch internally) vectors = model.encode(batch_texts) # 3) Zip results back to their sources for (file_name, chunk_offset), vector in zip(metadata, vectors): index.upsert(file_id=file.name, chunk_offset=chunk.offset, vector=vector) さらに、すべてを一度にバッチングすることは通常、次のステップがすべてのデータでこのステップが完了した後にのみ開始できるため、理想的ではありません。 CocoIndexのバッチングサポート CocoIndexはこのギャップを縮小し、両方の世界のベストを得ることを可能にします - CocoIndex ランタイムが提供するバッチングの効率を得ながら、自然なフローに従ってコードのシンプルさを維持します。 すでに、以下の組み込み機能のバッチサポートを有効にしました。 Embedテキスト トランスフォーメーションサイン コラボレーション コラボコラボ 花火を変えることはありません。 Your existing code will just work without any change – still following the natural flow, while enjoying the efficiency of batching. カスタム機能の場合、バッチングを有効にすることは、以下のように簡単です。 Set batching=True in the custom function decorator を設定します。 アルゴリズムを変更し、リストにタイプを返します。 たとえば、API を呼び出すカスタマイズされた関数を作成する場合は、画像のミニ画像を作成します。 @cocoindex.op.function(batching=True) def make_image_thumbnail(self, args: list[bytes]) -> list[bytes]: ... 詳細についてはバッチングドキュメントをご覧ください。 詳細についてはバッチングドキュメントをご覧ください。 ココインデックスのバッチ 共通アプローチ バッチングは、入力リクエストを列に収集し、それらを単一のバッチとして洗浄するのに適切なタイミングを決定することによって機能します。 Two widely used batching policies dominate the landscape: In this approach, the system flushes all requests that arrived within a fixed window of W milliseconds. Time-based batching (flush every W milliseconds): The maximum wait time for any request is predictable, and implementation is straightforward. It ensures that even during low traffic, requests will not remain in the queue indefinitely. Advantages: During periods of sparse traffic, idle requests accumulate slowly, adding latency for early arrivals. Additionally, the optimal window W often varies with workload characteristics, requiring careful tuning to strike the right balance between latency and throughput. Drawbacks: Here, a batch is triggered once the queue reaches a pre-defined number of items, K. Size-based batching (flush when K items are queued): The batch size is predictable, which simplifies memory management and system design. It is easy to reason about the resources each batch will consume. Advantages: When traffic is light, requests may remain in the queue for an extended period, increasing latency for the first-arriving items. Like time-based batching, the optimal K depends on workload patterns, requiring empirical tuning. Drawbacks: 多くの高性能システムがAを採用 : 彼らは、時間ウィンドウWが終了したとき、または列がサイズKに達したときにバッテリーを洗浄します - どちらが先に来るかに関係なく。 hybrid approach それにもかかわらず、バッチングは常に関わる。 トラフィックパターン、ワークロードの特徴、およびシステム制限はすべて理想的な設定に影響を与えます。最適なパフォーマンスを達成するには、しばしばモニタリング、プロファイリング、および動的にこれらのパラメータをリアルタイム条件に調節する必要があります。 tunable parameters and trade-offs CocoIndexのアプローチ フレームワークレベル: Adaptive, knob-free CocoIndex 実装 A 入力リクエストのロードに自動的に適応します。プロセスは次の通りです。 simple and natural batching mechanism 連続列:現在のバッチがデバイス(例えばGPU)で処理されている間、新しい入力リクエストはすぐに処理されません。 自動バッチウィンドウ:現在のバッチが完了すると、CocoIndexはすぐに列に蓄積したすべてのリクエストを取り、次のバッチとして扱います。 適応型バッチング: タイマーがない、固定バッチサイズなし、事前設定の限界なし. 各バッチのサイズは、前バッチのサービス期間中に到着したトラフィックに自然に適応します. 高トラフィック期間は自動的により大きなバッチを生成し、GPUの利用を最大化します. 低トラフィック期間はより小さいバッチを生成し、早期リクエストの遅延を最小化します. CocoIndexのバッチングメカニズムは パッチサイズがリアルタイムの需要を反映する一方で、手動の調節や複雑なエウリスティクスを必要とせずに高速なパフォーマンスを達成するために、パッチサイズの要求を継続的に処理します。 In essence, self-tuning なぜこれが良いのか。 少数のリクエストで、バッチは小さい(しばしばサイズ1)ので、ほぼ単一呼び出しの遅延で効果的に実行できます。 忙しいときに高いパフォーマンス: トラフィックがピークすると、フライト中のバッチ中により多くのリクエストが蓄積されるので、次のバッチはより大きくなります - 利用率は自動的に増加します。 調節なし:WまたはKを調節する必要はありません。システムは、トラフィックパターンに設計に応じて適応します。 Function-level batching: packing the batch intelligently 機能レベルのバッチング: バッチをスマートに包む 関数レベルでは、CocoIndex はそれぞれの関数を、その特定のモデルまたはライブラリのための最も効率的かつ安全な方法で、バッチ ウィンドウ - 前のバッチ 終了時点ですべての列のリクエスト - 処理することを可能にします。 最大限の柔軟性とパフォーマンスを提供します。 how it’s processed is up to the function TAKE THE 基本的な sentence-transformer ライブラリは任意の長さのバッチを受け入れることができますが、内部的にはそれらを分割します。 (デフォルトサイズ:32) それぞれがデバイスのメモリに快適に組み込まれており、GPUカーネルを最適な「甘い場所」に保つために、CocoIndexはこのデフォルトマイクロバッチサイズを自動的に活用します。 SentenceTransformerEmbed micro-batches バッチングは、データをメモリーに組み込むことだけでなく、無駄なコンピューティングを最小限に抑えることでもあります。 , GPU が均一で高出力のカーネルを実行することを可能にする. しかし、これは短いシーケンスがバッチ内の最も長いシーケンスのコストを支払うことを意味します. たとえば、64 トークンと 256 トークンアイテムを混合すると、64 トークンアイテムが必要以上に約 4 倍のコストで処理されます. CocoIndex はこれを解決します。 ほぼ同じ長さのマイクロバッチを形成し、パッディングオーバーヘッドを減らし、GPUの利用率を高く保つ。 pad every sequence in a batch to the length of the longest sequence sorting requests by token count 他の機能は独自の戦略を適用することができます:一部は単にバックエンドに完全なバッチを転送する場合があります。 SIMD テーブルや merge-writes のように CocoIndex はその方法に対して無知であり、その責任は それぞれの機能に、どのようにしてトランスポートを最大化し、オーバーヘッドを最小化するかを完全にコントロールできるようにします。 custom packing schemes deliver the batch window efficiently and without delay このデザインのバランス : フレームワークはバッチングのオーケストラ化を処理し、機能自体はメモリ、コンピューティング、およびカーネル効率を最適化し、さまざまなワークロードにわたって高いスループットを確保し、すべてのソリューションを一つのサイズに適合させる必要がありません。 simplicity, flexibility, and performance Conclusion 結論 バッチングは、コンピュータワークロードを加速するための最も効果的な戦略の1つです。 を可能にする そして、 バッチングは、多くの小規模で非効率な計算を、より少ない、高度に最適化された操作に変換します。 amortizing fixed overhead across multiple items larger, more efficient GPU operations minimizing data transfer CocoIndex バッチング いくつかの組み込みの機能は既にキャップの下でバッチングを活用し、カスタマイズされた機能は簡単な方法でそれを採用することができます。 これにより、列、タイマー、またはバッチサイズを手動で管理する複雑さを取り除き、開発者はモデルやアプリケーションに焦点を当てることができます。 effortless and automatic batching=True バッチングのパフォーマンスの利点が最も顕著なのは、 例えば、より小さいモデルや軽量な操作などで、バッチングは、ベースのAPIまたはライブラリが最も効果的である場合もあります。 部分的なサポートが利益を制限する可能性があるため、例えばOllamaのようないくつかのライブラリでは、バッチングの際にわずかな改善しか示さない。 fixed overhead represents a significant portion of total computation fully supports batched operations 要するに、バッチングはA : トランスポートを最大化し、重要な場所で遅延を減らし、ハードウェアが完全な可能性に近づいて動作することを可能にし、開発者体験をシンプルで予測できるようにします。 high-leverage optimization GitHub で CocoIndex に ⭐ Star を与え、役に立つと思ったらコミュニティと共有することで私たちをサポートしてください! 与えることによって私たちをサポート あなたのコミュニティと共有して、役に立つと思います! CocoIndex a ⭐ Star on GitHub GitHub