
快速入門【免費下載鏈接】geGEGraph Engine是面向昇騰的圖編譯器和執(zhí)行器提供了計算圖優(yōu)化、多流并行、內(nèi)存復用和模型下沉等技術(shù)手段加速模型執(zhí)行效率減少模型內(nèi)存占用。 GE 提供對 PyTorch、TensorFlow 前端的友好接入能力并同時支持 onnx、pb 等主流模型格式的解析與編譯。項目地址: https://gitcode.com/cann/ge使用ATC命令轉(zhuǎn)換ONNX模型本節(jié)介紹如何使用ATC命令轉(zhuǎn)換.onnx格式的模型文件并在AI處理器上執(zhí)行推理。對于PyTorch、TensorFlow、MindSpore等前端框架導出的模型文件GE提供了模型轉(zhuǎn)換的能力支持通過ATC命令行工具將模型轉(zhuǎn)化為適配AI處理器的離線模型并基于圖模式執(zhí)行推理。ATC目前已支持*.onnx格式的模型轉(zhuǎn)換成*.om格式的模型*.pb格式的模型轉(zhuǎn)換成*.om格式的模型*.air格式的模型轉(zhuǎn)換成*.om格式的模型*.prototxt與*.caffemodel格式的模型轉(zhuǎn)換成*.om格式的模型下面以*.onnx格式的模型轉(zhuǎn)換成*.om格式的模型為例介紹基本使用方法獲取ONNX網(wǎng)絡(luò)模型。單擊Link下載該文件再以CANN軟件包運行用戶將獲取的文件上傳至開發(fā)環(huán)境任意目錄例如上傳到$HOME_/module__/_目錄下。使用ATC命令行工具進行模型轉(zhuǎn)換以*.onnx模型舉例。atc --model$HOME/module/resnet50.onnx --framework5 --output$HOME/module/out/onnx_resnet50 --soc_versionsoc_version--model原始網(wǎng)絡(luò)模型文件路徑與文件名。--framework原始網(wǎng)絡(luò)模型框架類型“3”代表TensorFlow模型“5”代表ONNX模型“1”代表MindSpore框架*.air格式的模型文件或TorchAir通過export導出的標準*.air格式文件--output存放轉(zhuǎn)換后的離線模型的路徑以及文件名例如若配置為“$HOME__/module__/out/tf_resnet50”則轉(zhuǎn)換后的離線模型存儲路徑為“$HOME__/module__/out/”轉(zhuǎn)換后的離線模型名稱為“tf_resnet50.om”。--soc_versionAI處理器的型號。取值查詢方法如下針對如下產(chǎn)品在安裝AI處理器的服務器執(zhí)行npu-smi info命令進行查詢獲取Name信息。實際配置值為AscendName例如Name取值為xxxyy實際配置值為Ascendxxxyy。Atlas A2 訓練系列產(chǎn)品/Atlas A2 推理系列產(chǎn)品Atlas 200I/500 A2 推理產(chǎn)品Atlas 推理系列產(chǎn)品Atlas 訓練系列產(chǎn)品針對Atlas A3 訓練系列產(chǎn)品/Atlas A3 推理系列產(chǎn)品在安裝AI處理器的服務器執(zhí)行npu-smi info -t board -i id -c chip_id命令進行查詢獲取Chip Name和NPU Name信息實際配置值為Chip Name_NPU Name。例如Chip Name取值為AscendxxxNPU Name取值為1234實際配置值為Ascendxxx_1234。其中id設(shè)備id通過npu-smi info -l命令查出的NPU ID即為設(shè)備id。chip_id芯片id通過npu-smi info -m命令查出的Chip ID即為芯片id。針對Ascend 950PR/Ascend 950DT在安裝AI處理器的服務器執(zhí)行npu-smi info -t board -i id命令進行查詢獲取Chip Name和NPU Name信息實際配置值為Chip Name_NPU Name。例如Chip Name取值為AscendxxxNPU Name取值為1234實際配置值為Ascendxxx_1234。其中id為設(shè)備id通過npu-smi info -l命令查出的NPU ID即為設(shè)備id。更多參數(shù)以及詳細使用方法請參見《ATC離線模型編譯工具》。3.若提示如下信息則說明模型轉(zhuǎn)換成功。ATC run success, welcome to the next use.成功執(zhí)行命令后*.onnx模型將會被轉(zhuǎn)換成適配AI處理器的*.om離線模型在--output參數(shù)指定的路徑下可查看生成的*.om離線模型文件。4.后續(xù)操作。轉(zhuǎn)換成*.om離線模型后可以調(diào)用模型加載接口加載轉(zhuǎn)換好的*.om離線模型再調(diào)用模型執(zhí)行接口進行推理。如下為從文件加載模型文件并執(zhí)行推理的簡要流程詳細的模型加載與推理的方法可參見《應用開發(fā) (CC)》中的“模型推理”章節(jié)。// 1.指定模型路徑 const char* omModelPath ./model/onnx_resnet50.om; uint32_t modelId; // 2.加載離線模型文件模型加載成功返回標識模型的ID ret aclmdlLoadFromFile(omModelPath, modelId); // 3.執(zhí)行模型inputDs和outputDs為模型輸入輸出的Dataset對象 ret aclmdlExecute(modelId, inputDs, outputDs); // 4.卸載模型 ret aclmdlUnload(modelId);使用接口全新構(gòu)建GraphGE的C圖引擎接口提供了兩種構(gòu)圖方式使用圖引擎接口全新構(gòu)建Graph用戶通過圖引擎接口逐個將算子添加到計算圖中構(gòu)建成Ascend IR表示的計算圖。使用Parser接口將原始模型解析為Graph用戶通過Parser接口將框架模型文件如*.onnx和*.pb等格式解析成Ascend IR表示的計算圖。本章節(jié)綜合上述兩種場景為您介紹如何構(gòu)建一個Graph構(gòu)建完Graph后可以根據(jù)自身需要修改Graph然后將該Graph編譯為適配AI處理器的離線模型。整體流程如下流程說明如下進行構(gòu)建Graph操作之前先進行環(huán)境搭建安裝相應的CANN軟件包并進行網(wǎng)絡(luò)結(jié)構(gòu)分析如果有不支持的算子則開發(fā)對應算子并部署到硬件環(huán)境。如果使用圖引擎接口全新構(gòu)建Graph需要根據(jù)原始網(wǎng)絡(luò)明確如下信息網(wǎng)絡(luò)中包含哪些算子以及這些算子的輸入、輸出、屬性等信息。網(wǎng)絡(luò)中算子之間的關(guān)聯(lián)關(guān)系。確認原始網(wǎng)絡(luò)中的算子在AI處理器是否支持當前支持的算子請參見《算子庫》中的“Ascend IR算子規(guī)格說明”章節(jié)。如果不支持或不滿足實際需要開發(fā)者可以《Ascend C算子開發(fā)指南》自定義Ascend C算子或者參見《TBEAI CPU算子開發(fā)》自定義TBE算子選定一種方式后將算子部署到硬件環(huán)境即可。如果使用Parser接口將原始模型解析為Graph需要確認原始網(wǎng)絡(luò)中的算子在AI處理器是否支持當前支持的算子請參見《算子庫》中的“Ascend IR算子規(guī)格說明”章節(jié)。如果不支持或不滿足實際需要可參見《Ascend C算子開發(fā)指南》自定義Ascend C算子或者參見《TBEAI CPU算子開發(fā)》自定義TBE算子選定一種方式后將算子部署至硬件環(huán)境即可。構(gòu)建Graph開發(fā)者可以使用圖引擎接口全新構(gòu)建Graph也可以使用Parser接口將原始模型解析為Graph。修改Graph如果開發(fā)者想要優(yōu)化Graph結(jié)構(gòu)則可以基于構(gòu)建好的Graph直接將Graph修改為期望的結(jié)構(gòu)。編譯和運行Graph開發(fā)者可以將修改后的Graph編譯成適配AI處理器的離線模型然后通過模型加載接口加載后上板推理也可以直接運行Graph得到Graph的運行結(jié)果。獲取樣例單擊使用接口構(gòu)建Graph獲取樣例代碼目錄結(jié)構(gòu)如下├── src │ ├──main.cpp // 實現(xiàn)文件 ├── Makefile // 編譯腳本 ├── CMakeLists.txt // 編譯腳本 ├── data │ ├──data_generate.py // 使用圖引擎接口全新構(gòu)建Graph時用于生成Graph所需要的數(shù)據(jù)信息例如權(quán)重、偏置等數(shù)據(jù) │ ├──tensorflow_generate.py // 使用Parser接口將TensorFlow原始模型解析為Graph時用于生成.pb格式的TensorFlow模型 │ ├──caffe_generate.py // 使用Parser接口將Caffe原始模型解析為Graph時用于生成.pbtxt格式的Caffe模型與.caffemodel格式的權(quán)重文件 ├── scripts │ ├──host_version.conf // version配置 │ ├──testcase_300.sh // 測試腳本該樣例主要包括如下功能構(gòu)建Graph。使用圖引擎接口全新構(gòu)建Graph本樣例構(gòu)造的Graph結(jié)構(gòu)如下使用Parser接口將原始模型解析為Graph此處以TensorFlow為例進行介紹。本樣例給出的TensorFlow原始模型結(jié)構(gòu)為解析后的Graph結(jié)構(gòu)為修改Graph此處以使用Parser接口將TensorFlow模型解析得到的Graph為例進行說明。修改后的Graph結(jié)構(gòu)如下在Add算子和Const算子之間插入Abs算子編譯Graph將上述最終的Graph編譯為離線模型。編譯運行準備環(huán)境。參見環(huán)境準備搭建環(huán)境并配置環(huán)境變量。如果將TensorFlow框架原始模型解析為Graph需要搭建TensorFlow1.15.0環(huán)境如下為root用戶在x86架構(gòu)安裝示例pip3 install tensorflow-cpu1.15如果為非root用戶安裝需要在上述命令末尾增加--user參數(shù)如果為aarch64架構(gòu)安裝方法請參見《TensorFlow 1.15模型遷移》 安裝開源框架TensorFlow 1.15。準備構(gòu)圖數(shù)據(jù)。使用圖引擎接口全新構(gòu)建Graph。在data目錄執(zhí)行數(shù)據(jù)生成腳本命令如下python3 data_generate.py執(zhí)行完成后在data目錄下生成.bin格式的數(shù)據(jù)后續(xù)模型構(gòu)建時會從該文件讀取權(quán)重、偏置等數(shù)據(jù)。使用Parser接口將原始模型解析為Graph。在data目錄執(zhí)行原始模型生成腳本命令如下python3 tensorflow_generate.py執(zhí)行完成后在data目錄下生成.pb格式的模型文件后續(xù)將原始模型解析時會使用該模型名稱為tf_test.pb。編譯代碼。可選打開Makefile文件修改如下ASCEND_PATH路徑修改為CANN軟件安裝目錄/cann例如root用戶修改為/usr/local/Ascend/cann。ifeq (${ASCEND_INSTALL_PATH},) ASCEND_PATH : /usr/local/Ascend/cann執(zhí)行編譯。在Makefile文件同級目錄執(zhí)行如下命令進行編譯make clean make ir_build編譯完成后在當前路徑out文件夾下生成可執(zhí)行文件ir_build。運行代碼。使用圖引擎接口全新構(gòu)建Graph。在out文件夾下執(zhí)行如下命令./ir_build soc_version gen若提示如下信息則說明運行成功在同級目錄生成*.om離線模型文件。 Generate Graph1 Success! Build Model1 SUCCESS! Save Offline Model1 SUCCESS!使用Parser接口將原始模型解析為Graph。在out文件夾下執(zhí)行如下命令./ir_build soc_version tfsoc_version取值查詢方法請參見使用ATC命令轉(zhuǎn)換ONNX模型。 若提示如下信息則說明運行成功在同級目錄生成*.om離線模型文件。 Generate graph from tensorflow origin model success. Modify Graph Start. Find src node: const. Find dst node: add. Modify Graph Success. Modify tensorflow origin graph success. Build Model1 SUCCESS! Save Offline Model1 SUCCESS!后續(xù)操作。轉(zhuǎn)換成*.om離線模型后可以調(diào)用模型加載接口加載轉(zhuǎn)換好的*.om離線模型再調(diào)用模型執(zhí)行接口進行推理。詳細的模型加載與推理的方法可參見《應用開發(fā) (CC)》中的“模型推理”。代碼解析體驗快速入門樣例的編譯運行后若還想了解代碼的實現(xiàn)邏輯可查看下文的代碼解析。此處按各函數(shù)的功能來介紹代碼邏輯為了便于閱讀、理解代碼將各函數(shù)相關(guān)的變量與函數(shù)放在一起介紹。打開“src/main.cpp”文件先從main函數(shù)開始了解整個樣例的代碼串接邏輯再分別了解各自定義函數(shù)的實現(xiàn)。main函數(shù)用來串聯(lián)整個構(gòu)建Graph的代碼邏輯。int main(int argc, char* argv[]) { // 1.構(gòu)建Graph Graph graph1(IrGraph1); // 1.1使用圖引擎接口全新構(gòu)建Graph ret GenGraph(graph1); // 1.2使用Parser接口將原始模型解析為Graph std::string tfPath ../data/tf_test.pb; std::mapAscendString, AscendString parser_options; tfStatus ge::aclgrphParseTensorFlow(tfPath.c_str(), parser_options, graph1); // 2.修改Graph此處以從TensorFlow模型解析得到的Graph為例進行修改 ModifyGraph(graph1); // 3.系統(tǒng)初始化并申請資源 std::mapAscendString, AscendString global_options { {AscendString(ge::ir_option::SOC_VERSION), AscendString(argv[kSocVersion])} , }; auto status aclgrphBuildInitialize(global_options); // 4.編譯Graph ModelBufferData model1; std::mapAscendString, AscendString options; PrepareOptions(options); status aclgrphBuildModel(graph1, options, model1); // 5.將內(nèi)存緩沖區(qū)中的模型保存為離線模型文件 status aclgrphSaveModel(ir_build_sample1, model1); // 6.釋放資源 aclgrphBuildFinalize(); }include依賴的頭文件。#include string.h #include tensorflow_parser.h #include graph.h #include types.h #include tensor.h #include attr_value.h #include ge_error_codes.h #include ge_api_types.h #include ge_ir_build.h #include all_ops.h ... ... using namespace std; using namespace ge; using ge::Operator;構(gòu)建Graph。使用算子原型衍生接口定義算子并連接算子。詳細代碼示例為bool GenGraph(Graph graph) { auto shape_data vectorint64_t({ 1,1,28,28 }); TensorDesc desc_data(ge::Shape(shape_data), FORMAT_ND, DT_FLOAT16); // 創(chuàng)建Data算子實例 auto data op::Data(data); data.update_input_desc_x(desc_data); data.update_output_desc_y(desc_data); // 創(chuàng)建Add算子實例并與Data算子連接 auto add op::Add(add) .set_input_x1(data) .set_input_x2(data); // 創(chuàng)建AscendQuant算子實例并與Data算子連接 auto quant op::AscendQuant(quant) .set_input_x(data) .set_attr_scale(1.0) .set_attr_offset(0.0); auto conv_weight op::Const(Conv2D/weight) .set_attr_value(weight_tensor); // 創(chuàng)建Conv2D算子實例并與AscendQuant算子連接 auto conv2d op::Conv2D(Conv2d1) .set_input_x(quant) .set_input_filter(conv_weight) .set_attr_strides({ 1, 1, 1, 1 }) .set_attr_pads({ 0, 1, 0, 1 }) .set_attr_dilations({ 1, 1, 1, 1 }); ... ... auto dequant_scale op::Const(dequant_scale) .set_attr_value(dequant_tensor); // 創(chuàng)建AscendDequant算子實例并與Conv2D算子連接 auto dequant op::AscendDequant(dequant) .set_input_x(conv2d) .set_input_deq_scale(dequant_scale); ... ... auto bias_weight_1 op::Const(Bias/weight_1) .set_attr_value(weight_bias_add_tensor_1); // 創(chuàng)建BiasAdd算子實例并與AscendDequant算子連接 auto bias_add_1 op::BiasAdd(bias_add_1) .set_input_x(dequant) .set_input_bias(bias_weight_1) .set_attr_data_format(NCHW); ... ... auto dynamic_const op::Const(dynamic_const).set_attr_value(dynamic_const_tensor); // 創(chuàng)建Reshape算子實例并與BiasAdd算子連接 auto reshape op::Reshape(Reshape) .set_input_x(bias_add_1) .set_input_shape(dynamic_const); ... ... auto matmul_weight_1 op::Const(dense/kernel) .set_attr_value(matmul_weight_tensor_1); // 創(chuàng)建MatMul算子實例并與Reshape算子連接 auto matmul_1 op::MatMul(MatMul_1) .set_input_x1(reshape) .set_input_x2(matmul_weight_1); ... ... auto bias_add_const_1 op::Const(dense/bias) .set_attr_value(bias_add_const_tensor_1); // 創(chuàng)建BiasAdd算子實例并與MatMul算子連接 auto bias_add_2 op::BiasAdd(bias_add_2) .set_input_x(matmul_1) .set_input_bias(bias_add_const_1) .set_attr_data_format(NCHW); // 創(chuàng)建Relu6算子實例并與BiasAdd算子連接 auto relu6 op::Relu6(relu6) .set_input_x(bias_add_2); ... ... auto matmul_weight_2 op::Const(OutputLayer/kernel) .set_attr_value(matmul_weight_tensor_2); // 創(chuàng)建MatMul算子實例并與Relu6算子連接 auto matmul_2 op::MatMul(MatMul_2) .set_input_x1(relu6) .set_input_x2(matmul_weight_2); ... ... auto bias_add_const_3 op::Const(OutputLayer/bias) .set_attr_value(bias_add_const_tensor_3); // 創(chuàng)建BiasAdd算子實例并與MatMul算子連接 auto bias_add_3 op::BiasAdd(bias_add_3) .set_input_x_by_name(matmul_2, y) .set_input_bias_by_name(bias_add_const_3, y) .set_attr_data_format(NCHW); // 創(chuàng)建SoftmaxV2算子實例并與BiasAdd算子連接 auto softmax op::SoftmaxV2(Softmax) .set_input_x_by_name(bias_add_3, y); std::vectorOperator inputs{ data }; std::vectorOperator outputs{ softmax, add }; std::vectorstd::pairge::Operator, std::string outputs_with_name {{softmax, y}}; // 調(diào)用接口設(shè)置Graph的輸入輸出 graph.SetInputs(inputs).SetOutputs(outputs); return true; }修改Graph此處以從TensorFlow模型解析得到的Graph為例進行修改。在Add算子和Const算子之間插入Abs算子bool ModifyGraph(Graph graph) { const std::string CONST const1; const std::string ADD input3_add; GNode src_node; GNode dst_node; // 獲取圖中的所有節(jié)點 std::vectorGNode nodes graph.GetAllNodes(); graphStatus ret GRAPH_FAILED; for (auto node : nodes) { ge::AscendString name; // 獲取圖中算子的名稱 ret node.GetName(name); std::string node_name(name.GetString()); } // 刪除圖中的指定連接邊 ret graph.RemoveEdge(src_node, 0, dst_node, 1); auto abs op::Abs(input3_abs); // 新增abs節(jié)點到圖上 GNode node_abs graph.AddNodeByOp(abs); //新增數(shù)據(jù)邊連接新增的節(jié)點 ret graph.AddDataEdge(src_node, 0, node_abs, 0); ret graph.AddDataEdge(node_abs, 0, dst_node, 1); return true; }編譯Graph。構(gòu)建和修改完Graph之后調(diào)用接口進行Graph編譯操作接口調(diào)用流程如下圖所示詳細流程請參見main()函數(shù)。【免費下載鏈接】geGEGraph Engine是面向昇騰的圖編譯器和執(zhí)行器提供了計算圖優(yōu)化、多流并行、內(nèi)存復用和模型下沉等技術(shù)手段加速模型執(zhí)行效率減少模型內(nèi)存占用。 GE 提供對 PyTorch、TensorFlow 前端的友好接入能力并同時支持 onnx、pb 等主流模型格式的解析與編譯。項目地址: https://gitcode.com/cann/ge創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考