I/O-Bindung

Bei der Arbeit mit Nicht-CPU-Ausführungs-Providern ist es am effizientesten, wenn die Eingaben (und/oder Ausgaben) auf dem Zielgerät (abstrahiert durch den verwendeten Ausführungs-Provider) angeordnet sind, bevor der Graph ausgeführt wird (Aufruf von Run()). Wenn die Eingabe nicht auf das Zielgerät kopiert wird, kopiert ORT sie während des Run()-Aufrufs von der CPU. Ähnlich verhält es sich, wenn die Ausgabe nicht vorab auf dem Gerät zugewiesen wird. ORT geht davon aus, dass die Ausgabe auf der CPU angefordert wird und kopiert sie als letzten Schritt des Run()-Aufrufs vom Gerät. Dies schmälert die Ausführungszeit des Graphen und lässt Benutzer fälschlicherweise denken, ORT sei langsam, wenn die meiste Zeit für diese Kopien aufgewendet wird.

Um dies zu beheben, haben wir das Konzept der IOBindung eingeführt. Die Kernidee ist, die Eingaben vor dem Aufruf von Run() auf das Gerät zu kopieren und die Ausgaben auf dem Gerät vorab zuzuweisen. IOBindung ist in allen unseren Sprachbindungen verfügbar.

Im Folgenden finden Sie Code-Snippets in verschiedenen Sprachen, die die Verwendung dieser Funktion demonstrieren.

  • 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);
    

    Beachten Sie, dass im obigen Codebeispiel der Ausgabe-Tensor nicht vor dem Binden zugewiesen wird, sondern eine Ort::MemoryInfo als Ausgabe gebunden wird. Dies ist eine effektive Möglichkeit, die Sitzung den Tensor basierend auf den benötigten Formen zuweisen zu lassen. Insbesondere bei datenabhängigen oder dynamischen Formen kann dies eine großartige Lösung für die richtige Zuweisung sein. Wenn jedoch die Ausgabeform bekannt ist und der Ausgabe-Tensor wiederverwendet werden soll, ist es vorteilhaft, auch einen Ort::Value an die Ausgabe zu binden. Dieser kann mit dem Sitzungszuweiser oder externem Speicher zugewiesen werden. Weitere Details finden Sie in der Dokumentation zu Gerätetensoren.

     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 (siehe Python API-Dokumentation)

  • C# (siehe OrtIoBindingAllocationTest.cs)