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}; // Use this to bind output to a device when the shape is not known in advance. If the shape is known you can use the other overload of this function that takes an Ort::Value as input (IoBinding::BindOutput(const char* name, const Value& value)). // This internally calls the 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 文件)
- C#(請參閱OrtIoBindingAllocationTest.cs)