I/O バインディング
I/O バインディング
Section titled “I/O バインディング”非CPU実行プロバイダーを使用する場合、グラフを実行する(Run()を呼び出す)前に、入力(および/または出力)をターゲットデバイス(使用される実行プロバイダーによって抽象化される)上に配置することが最も効率的です。入力がターゲットデバイスにコピーされていない場合、ORTはRun()呼び出しの一部としてCPUからコピーします。同様に、出力がデバイス上に事前に割り当てられていない場合、ORTは出力がCPU上で要求されていると仮定し、Run()呼び出しの最後のステップとしてデバイスからコピーします。これによりグラフの実行時間が削られ、実際にはこれらのコピーに大部分の時間が費やされているにも関わらず、ユーザーはORTが遅いと誤解してしまいます。
この問題に対処するため、IOBindingの概念を導入しました。主要なアイデアは、Run()を呼び出す前に、入力をデバイスにコピーし、出力をデバイス上に事前に割り当てることです。IOBindingは、すべての言語バインディングで利用できます。
以下は、この機能の使用方法を示すさまざまな言語でのコードスニペットです。
-
C++
Ort::Env env;Ort::Session session(env, model_path, session_options);Ort::IoBinding io_binding{session};auto input_tensor = Ort::Value::CreateTensor<float>(memory_info, input_tensor_values.data(), input_tensor_size, input_node_dims.data(), 4);io_binding.BindInput("input1", input_tensor);Ort::MemoryInfo output_mem_info{"Cuda", OrtDeviceAllocator, 0,OrtMemTypeDefault};// 形状が事前に分からない場合にデバイスに出力をバインドするために使用します。形状が分かっている場合は、Ort::Valueを入力として受け取るこの関数の他のオーバーロードを使用できます(IoBinding::BindOutput(const char* name, const Value& value))。// これは内部的にBindOutputToDevice C APIを呼び出します。io_binding.BindOutput("output1", output_mem_info);session.Run(run_options, io_binding);上記のコードサンプルでは、出力テンソルはバインドする前に割り当てられておらず、代わりに
Ort::MemoryInfoが出力としてバインドされていることに注意してください。 これは、必要な形状に応じてセッションにテンソルを割り当てさせる効果的な方法です。 特にデータ依存の形状や動的形状の場合、これは適切な割り当てを得るための優れたソリューションになります。 ただし、出力形状が分かっていて出力テンソルを再利用する場合は、出力にOrt::Valueをバインドすることも有益です。これは、セッションアロケーターまたは外部メモリを使用して割り当てることができます。詳細については、デバイステンソルドキュメントを参照してください:Ort::Allocator gpu_allocator(session, output_mem_info);auto output_value = Ort::Value::CreateTensor(gpu_allocator, output_shape.data(), output_shape.size(),ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT16);io_binding.BindOutput("output1", output_mem_info); -
Python(Python API ドキュメントを参照)