CANN Execution Provider
Huawei Compute Architecture for Neural Networks (CANN) ist eine heterogene Computerarchitektur für KI-Szenarien und bietet mehrschichtige Programmierschnittstellen, um Benutzern zu helfen, KI-Anwendungen und -Dienste schnell auf Basis der Ascend-Plattform zu erstellen.
Die Verwendung des CANN Execution Provider für ONNX Runtime kann Ihnen helfen, ONNX-Modelle auf Huawei Ascend-Hardware zu beschleunigen.
Der CANN Execution Provider (EP) für ONNX Runtime wird von Huawei entwickelt.
Inhalt
- Installieren
- Voraussetzungen
- Erstellen
- Konfigurationsoptionen
- Leistungsoptimierung
- Beispiele
- Unterstützte Ops
- Zusätzliche Ressourcen
Installieren
Vorkompilierte Binärdateien von ONNX Runtime mit CANN EP werden veröffentlicht, aber derzeit nur für Python. Bitte beachten Sie onnxruntime-cann.
Voraussetzungen
Bitte beachten Sie die folgende Tabelle für die offiziellen CANN-Paketabhängigkeiten für das ONNX Runtime-Inferenzpaket.
| ONNX Runtime | CANN |
|---|---|
| v1.18.0 | 8.0.0 |
| v1.19.0 | 8.0.0 |
| v1.20.0 | 8.0.0 |
Build
Anweisungen zum Erstellen finden Sie auf der BUILD-Seite.
Konfigurationsoptionen
Der CANN Execution Provider unterstützt die folgenden Konfigurationsoptionen.
device_id
Die Geräte-ID.
Standardwert: 0
npu_mem_limit
Die Grössenbeschränkung des Gerätespeicher-Arenas in Bytes. Diese Grössenbeschränkung gilt nur für den Arena des Execution Providers. Die gesamte Gerätespeichernutzung kann höher sein.
arena_extend_strategy
Die Strategie zur Erweiterung des Gerätespeicher-Arenas.
| Wert | Beschreibung |
|---|---|
| kNextPowerOfTwo | nachfolgende Erweiterungen erfolgen in grösseren Schritten (multipliziert mit Zweierpotenzen) |
| kSameAsRequested | Erweiterung um den angeforderten Betrag |
Standardwert: kNextPowerOfTwo
enable_cann_graph
Ob die Graph-Inferenzmaschine zur Beschleunigung der Leistung verwendet werden soll. Die empfohlene Einstellung ist true. Wenn false, wird auf die Single-Operator-Inferenzmaschine zurückgegriffen.
Standardwert: true
dump_graphs
Ob der Subgraph im ONNX-Format für die Analyse der Subgraph-Segmentierung ausgegeben werden soll.
Standardwert: false
dump_om_model
Ob das Offline-Modell für den Ascend AI Processor in eine .om-Datei ausgegeben werden soll.
Standardwert: true
precision_mode
Der Präzisionsmodus des Operators.
| Wert | Beschreibung |
|---|---|
| force_fp32/cube_fp16in_fp32out | Konvertierung in float32 gemäss Operator-Implementierung |
| force_fp16 | Konvertierung in float16, wenn float16 und float32 beide unterstützt werden |
| allow_fp32_to_fp16 | Konvertierung in float16, wenn float32 nicht unterstützt wird |
| must_keep_origin_dtype | beibehalten wie es ist |
| allow_mix_precision/allow_mix_precision_fp16 | Mix-Präzisionsmodus |
Standardwert: force_fp16
op_select_impl_mode
Einige integrierte Operatoren in CANN verfügen über hochpräzise und hochleistungsfähige Implementierungen.
| Wert | Beschreibung |
|---|---|
| high_precision | Ziel: hohe Präzision |
| high_performance | Ziel: hohe Leistung |
Standardwert: high_performance
optypelist_for_implmode
Enumerieren Sie die Liste der Operatoren, die den Modus verwenden, der durch den Parameter op_select_impl_mode angegeben ist.
Die unterstützten Operatoren sind wie folgt:
- Pooling
- SoftmaxV2
- LRN
- ROIAlign
Standardwert: None
Leistungsoptimierung
IO Binding
Die I/O Binding-Funktion sollte verwendet werden, um Overhead durch Kopien von Ein- und Ausgaben zu vermeiden.
- Python
import numpy as np
import onnxruntime as ort
providers = [
(
"CANNExecutionProvider",
{
"device_id": 0,
"arena_extend_strategy": "kNextPowerOfTwo",
"npu_mem_limit": 2 * 1024 * 1024 * 1024,
"enable_cann_graph": True,
},
),
"CPUExecutionProvider",
]
model_path = '<path to model>'
options = ort.SessionOptions()
options.graph_optimization_level = ort.GraphOptimizationLevel.ORT_DISABLE_ALL
options.execution_mode = ort.ExecutionMode.ORT_PARALLEL
session = ort.InferenceSession(model_path, sess_options=options, providers=providers)
x = np.array([[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]], dtype=np.int64)
x_ortvalue = ort.OrtValue.ortvalue_from_numpy(x, "cann", 0)
io_binding = sess.io_binding()
io_binding.bind_ortvalue_input(name="input", ortvalue=x_ortvalue)
io_binding.bind_output("output", "cann")
sess.run_with_iobinding(io_binding)
return io_binding.get_outputs()[0].numpy()
- C/C++ (zukünftig)
Beispiele
Derzeit können Benutzer die C/C++ und Python API auf CANN EP nutzen.
Python
import onnxruntime as ort
model_path = '<path to model>'
options = ort.SessionOptions()
providers = [
(
"CANNExecutionProvider",
{
"device_id": 0,
"arena_extend_strategy": "kNextPowerOfTwo",
"npu_mem_limit": 2 * 1024 * 1024 * 1024,
"op_select_impl_mode": "high_performance",
"optypelist_for_implmode": "Gelu",
"enable_cann_graph": True
},
),
"CPUExecutionProvider",
]
session = ort.InferenceSession(model_path, sess_options=options, providers=providers)
C/C++
Hinweis: Dieses Beispiel zeigt die Modellinferenz unter Verwendung von resnet50_Opset16.onnx als Beispiel. Sie müssen den model_path sowie die Funktionen input_prepare() und output_postprocess() nach Ihren Bedürfnissen anpassen.
#include <iostream>
#include <vector>
#include "onnxruntime_cxx_api.h"
// path of model, Change to user's own model path
const char* model_path = "./onnx/resnet50_Opset16.onnx";
/**
* @brief Input data preparation provided by user.
*
* @param num_input_nodes The number of model input nodes.
* @return A collection of input data.
*/
std::vector<std::vector<float>> input_prepare(size_t num_input_nodes) {
std::vector<std::vector<float>> input_datas;
input_datas.reserve(num_input_nodes);
constexpr size_t input_data_size = 3 * 224 * 224;
std::vector<float> input_data(input_data_size);
// initialize input data with values in [0.0, 1.0]
for (unsigned int i = 0; i < input_data_size; i++)
input_data[i] = (float)i / (input_data_size + 1);
input_datas.push_back(input_data);
return input_datas;
}
/**
* @brief Model output data processing logic(For User updates).
*
* @param output_tensors The results of the model output.
*/
void output_postprocess(std::vector<Ort::Value>& output_tensors) {
auto floatarr = output_tensors.front().GetTensorMutableData<float>();
for (int i = 0; i < 5; i++) {
std::cout << "Score for class [" << i << "] = " << floatarr[i] << '\n';
}
std::cout << "Done!" << std::endl;
}
/**
* @brief The main functions for model inference.
*
* The complete model inference process, which generally does not need to be
* changed here
*/
void inference() {
const auto& api = Ort::GetApi();
Ort::Env env(ORT_LOGGING_LEVEL_WARNING);
// Enable cann graph in cann provider option.
OrtCANNProviderOptions* cann_options = nullptr;
api.CreateCANNProviderOptions(&cann_options);
// Configurations of EP
std::vector<const char*> keys{
"device_id",
"npu_mem_limit",
"arena_extend_strategy",
"enable_cann_graph"};
std::vector<const char*> values{"0", "4294967296", "kNextPowerOfTwo", "1"};
api.UpdateCANNProviderOptions(
cann_options, keys.data(), values.data(), keys.size());
// Convert to general session options
Ort::SessionOptions session_options;
api.SessionOptionsAppendExecutionProvider_CANN(
static_cast<OrtSessionOptions*>(session_options), cann_options);
Ort::Session session(env, model_path, session_options);
Ort::AllocatorWithDefaultOptions allocator;
// Input Process
const size_t num_input_nodes = session.GetInputCount();
std::vector<const char*> input_node_names;
std::vector<Ort::AllocatedStringPtr> input_names_ptr;
input_node_names.reserve(num_input_nodes);
input_names_ptr.reserve(num_input_nodes);
std::vector<std::vector<int64_t>> input_node_shapes;
std::cout << num_input_nodes << std::endl;
for (size_t i = 0; i < num_input_nodes; i++) {
auto input_name = session.GetInputNameAllocated(i, allocator);
input_node_names.push_back(input_name.get());
input_names_ptr.push_back(std::move(input_name));
auto type_info = session.GetInputTypeInfo(i);
auto tensor_info = type_info.GetTensorTypeAndShapeInfo();
input_node_shapes.push_back(tensor_info.GetShape());
}
// Output Process
const size_t num_output_nodes = session.GetOutputCount();
std::vector<const char*> output_node_names;
std::vector<Ort::AllocatedStringPtr> output_names_ptr;
output_names_ptr.reserve(num_input_nodes);
output_node_names.reserve(num_output_nodes);
for (size_t i = 0; i < num_output_nodes; i++) {
auto output_name = session.GetOutputNameAllocated(i, allocator);
output_node_names.push_back(output_name.get());
output_names_ptr.push_back(std::move(output_name));
}
// User need to generate input date according to real situation.
std::vector<std::vector<float>> input_datas = input_prepare(num_input_nodes);
auto memory_info = Ort::MemoryInfo::CreateCpu(
OrtAllocatorType::OrtArenaAllocator, OrtMemTypeDefault);
std::vector<Ort::Value> input_tensors;
input_tensors.reserve(num_input_nodes);
for (size_t i = 0; i < input_node_shapes.size(); i++) {
auto input_tensor = Ort::Value::CreateTensor<float>(
memory_info,
input_datas[i].data(),
input_datas[i].size(),
input_node_shapes[i].data(),
input_node_shapes[i].size());
input_tensors.push_back(std::move(input_tensor));
}
auto output_tensors = session.Run(
Ort::RunOptions{nullptr},
input_node_names.data(),
input_tensors.data(),
num_input_nodes,
output_node_names.data(),
output_node_names.size());
// Processing of out_tensor
output_postprocess(output_tensors);
}
int main(int argc, char* argv[]) {
inference();
return 0;
}
Unterstützte Ops
Folgende Ops werden vom CANN Execution Provider im Single-Operator-Inferenzmodus unterstützt.
| Operator | Hinweis |
|---|---|
| ai.onnx:Abs | |
| ai.onnx:Add | |
| ai.onnx:AveragePool | Nur 2D-Pooling wird unterstützt. |
| ai.onnx:BatchNormalization | |
| ai.onnx:Cast | |
| ai.onnx:Ceil | |
| ai.onnx:Conv | Nur 2D Conv wird unterstützt. Gewichte und Bias müssen konstant sein. |
| ai.onnx:Cos | |
| ai.onnx:Div | |
| ai.onnx:Dropout | |
| ai.onnx:Exp | |
| ai.onnx:Erf | |
| ai.onnx:Flatten | |
| ai.onnx:Floor | |
| ai.onnx:Gemm | |
| ai.onnx:GlobalAveragePool | |
| ai.onnx:GlobalMaxPool | |
| ai.onnx:Identity | |
| ai.onnx:Log | |
| ai.onnx:MatMul | |
| ai.onnx:MaxPool | Nur 2D-Pooling wird unterstützt. |
| ai.onnx:Mul | |
| ai.onnx:Neg | |
| ai.onnx:Reciprocal | |
| ai.onnx:Relu | |
| ai.onnx:Reshape | |
| ai.onnx:Round | |
| ai.onnx:Sin | |
| ai.onnx:Sqrt | |
| ai.onnx:Sub | |
| ai.onnx:Transpose |
Zusätzliche Ressourcen
Zusätzliche Operatorunterstützung und Leistungsoptimierung werden bald hinzugefügt.