mirror of
https://github.com/PaddlePaddle/FastDeploy.git
synced 2025-10-13 04:13:58 +08:00

* add horizon backend and PPYOLOE examples * 更改horizon头文件编码规范 * 更改horizon头文件编码规范 * 更改horizon头文件编码规范 * 增加horizon packages下载及自动安装 * Add UseHorizonNPUBackend Method * 删除编译FD SDK后多余的头文件,同时更改部分规范 * Update horizon.md * Update horizon.md --------- Co-authored-by: DefTruth <31974251+DefTruth@users.noreply.github.com>
399 lines
13 KiB
C++
399 lines
13 KiB
C++
// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
#include "fastdeploy/runtime/backends/horizon/horizon_backend.h"
|
|
namespace fastdeploy{
|
|
|
|
HorizonBackend::~HorizonBackend() {
|
|
int ret = -1;
|
|
// Release memory uniformly here
|
|
if (input_properties_ != nullptr){
|
|
free(input_properties_);
|
|
}
|
|
if (output_properties_ != nullptr){
|
|
free(output_properties_);
|
|
}
|
|
if(input_mems_ == nullptr){
|
|
return;
|
|
}
|
|
for(int i = 0; i < NumInputs(); i++){
|
|
|
|
ret = hbSysFreeMem(&(input_mems_[i].sysMem[0]));
|
|
|
|
if(ret != 0){
|
|
FDERROR << "release input mem fail! ret=" << ret << std::endl;
|
|
}
|
|
if(input_mems_ != nullptr){
|
|
free(input_mems_);
|
|
}
|
|
}
|
|
|
|
for(int i = 0; i < NumOutputs(); i++){
|
|
ret = hbSysFreeMem(&(output_mems_[i].sysMem[0]));
|
|
|
|
if(ret != 0){
|
|
FDERROR << "release output mem fail! ret=" << ret << std::endl;
|
|
}
|
|
if(output_mems_ != nullptr){
|
|
free(output_mems_);
|
|
}
|
|
}
|
|
ret = hbDNNRelease(packed_dnn_handle_);
|
|
if(ret != 0){
|
|
FDERROR << "hbDNNRelease fail! ret=" << ret << std::endl;
|
|
}
|
|
}
|
|
|
|
bool HorizonBackend::GetModelInputOutputInfos(){
|
|
const char **model_name_list;
|
|
int model_count = 0;
|
|
int ret;
|
|
// get model name
|
|
ret = hbDNNGetModelNameList(&model_name_list, &model_count, packed_dnn_handle_);
|
|
if(ret != 0){
|
|
FDERROR << "get model name fail! ret=" << ret << std::endl;
|
|
return false;
|
|
}
|
|
// get dnn handle
|
|
ret = hbDNNGetModelHandle(&dnn_handle_, packed_dnn_handle_, model_name_list[0]);
|
|
if(ret != 0){
|
|
FDERROR << "get dnn handle fail! ret=" << ret << std::endl;
|
|
return false;
|
|
}
|
|
// get input infos
|
|
// Get detailed input parameters
|
|
int input_count = 0;
|
|
ret = hbDNNGetInputCount(&input_count, dnn_handle_);
|
|
if(ret != 0){
|
|
FDERROR << "get input count fail! ret=" << ret << std::endl;
|
|
return false;
|
|
}
|
|
input_properties_ = (hbDNNTensorProperties*)malloc(sizeof(hbDNNTensorProperties) * input_count);
|
|
memset(input_properties_, 0, input_count * sizeof(hbDNNTensorProperties));
|
|
|
|
inputs_desc_.resize(input_count);
|
|
|
|
// get input info and copy to input tensor info
|
|
for (uint32_t i = 0; i < input_count; i++) {
|
|
ret = hbDNNGetInputTensorProperties(&input_properties_[i], dnn_handle_, i);
|
|
|
|
if(ret != 0){
|
|
FDERROR << "get input tensor properties fail! ret=" << ret << std::endl;
|
|
return false;
|
|
}
|
|
|
|
if ((input_properties_[i].tensorLayout != HB_DNN_LAYOUT_NHWC)) {
|
|
FDERROR << "horizon_backend only support input layout is NHWC"
|
|
<< std::endl;
|
|
}
|
|
if(input_properties_[i].tensorType!= HB_DNN_IMG_TYPE_RGB){
|
|
FDERROR << "horizon_backend only support input format is RGB"
|
|
<< std::endl;
|
|
}
|
|
|
|
const char *name;
|
|
|
|
ret = hbDNNGetInputName(&name, dnn_handle_, i);
|
|
if(ret != 0){
|
|
FDERROR << "get input tensor name fail! ret=" << ret << std::endl;
|
|
return false;
|
|
}
|
|
// copy input proper to input tensor info
|
|
std::string temp_name = name;
|
|
std::vector<int> temp_shape{};
|
|
int n_dims = input_properties_[i].validShape.numDimensions;
|
|
|
|
temp_shape.resize(n_dims);
|
|
for (int j = 0; j < n_dims; j++) {
|
|
temp_shape[j] = (int)input_properties_[i].validShape.dimensionSize[j];
|
|
}
|
|
|
|
// Only support RGB format, so input type is UINT8
|
|
FDDataType temp_dtype = FDDataType::UINT8;
|
|
TensorInfo temp_input_info = {temp_name, temp_shape, temp_dtype};
|
|
inputs_desc_[i] = temp_input_info;
|
|
}
|
|
|
|
// get output infos
|
|
// Get detailed output parameters
|
|
int output_count = 0;
|
|
ret = hbDNNGetOutputCount(&output_count, dnn_handle_);
|
|
if(ret != 0){
|
|
FDERROR << "get output count fail! ret=" << ret << std::endl;
|
|
return false;
|
|
}
|
|
output_properties_ = (hbDNNTensorProperties*)malloc(sizeof(hbDNNTensorProperties) * output_count);
|
|
memset(output_properties_, 0, output_count * sizeof(hbDNNTensorProperties));
|
|
|
|
outputs_desc_.resize(output_count);
|
|
|
|
for (uint32_t i = 0; i < output_count; i++){
|
|
// get model output size
|
|
ret = hbDNNGetOutputTensorProperties(&output_properties_[i], dnn_handle_, i);
|
|
|
|
const char *name;
|
|
ret = hbDNNGetOutputName(&name, dnn_handle_, i);
|
|
if(ret != 0){
|
|
FDERROR << "get output tensor name fail! ret=" << ret << std::endl;
|
|
return false;
|
|
}
|
|
|
|
// copy output proper to output tensor info
|
|
std::string temp_name = name;
|
|
std::vector<int> temp_shape{};
|
|
int n_dims = output_properties_[i].validShape.numDimensions;
|
|
|
|
if ((n_dims == 4) && (output_properties_[i].validShape.dimensionSize[3] == 1)) {
|
|
n_dims--;
|
|
}
|
|
temp_shape.resize(n_dims);
|
|
for (int j = 0; j < n_dims; j++) {
|
|
temp_shape[j] = (int)output_properties_[i].validShape.dimensionSize[j];
|
|
}
|
|
|
|
FDDataType temp_dtype = HorizonTensorTypeToFDDataType(output_properties_[i].tensorType);
|
|
|
|
TensorInfo temp_input_info = {temp_name, temp_shape, temp_dtype};
|
|
outputs_desc_[i] = temp_input_info;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
TensorInfo HorizonBackend::GetInputInfo(int index){
|
|
FDASSERT(index < NumInputs(),
|
|
"The index: %d should less than the number of inputs: %d.", index,
|
|
NumInputs());
|
|
return inputs_desc_[index];
|
|
}
|
|
|
|
std::vector<TensorInfo> HorizonBackend::GetInputInfos(){
|
|
return inputs_desc_;
|
|
}
|
|
|
|
TensorInfo HorizonBackend::GetOutputInfo(int index){
|
|
FDASSERT(index < NumOutputs(),
|
|
"The index: %d should less than the number of outputs %d.", index,
|
|
NumOutputs());
|
|
|
|
return outputs_desc_[index];
|
|
}
|
|
|
|
std::vector<TensorInfo> HorizonBackend::GetOutputInfos(){
|
|
return outputs_desc_;
|
|
}
|
|
|
|
|
|
bool HorizonBackend::LoadModel(const char *model){
|
|
int ret = -1;
|
|
ret = hbDNNInitializeFromFiles(&packed_dnn_handle_, &model , 1);
|
|
if(ret != 0){
|
|
FDERROR << "horizon_init fail! ret=" << ret << std::endl;
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
bool HorizonBackend::Init(const RuntimeOption& runtime_option){
|
|
// Init model from file
|
|
if (!LoadModel((char*)runtime_option.model_file.data())) {
|
|
FDERROR << "load model failed" << std::endl;
|
|
return false;
|
|
}
|
|
|
|
// GetModelInputOutputInfos
|
|
if (!GetModelInputOutputInfos()) {
|
|
FDERROR << "get model input output infos failed" << std::endl;
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
bool HorizonBackend::Infer(std::vector<FDTensor>& inputs,
|
|
std::vector<FDTensor>* outputs, bool copy_to_fd){
|
|
|
|
// Judge whether the input and output size are the same
|
|
if (inputs.size() != inputs_desc_.size()) {
|
|
FDERROR << "[HorizonBackend] Size of the inputs(" << inputs.size()
|
|
<< ") should keep same with the inputs of this model("
|
|
<< inputs_desc_.size() << ")." << std::endl;
|
|
return false;
|
|
}
|
|
RUNTIME_PROFILE_LOOP_H2D_D2H_BEGIN
|
|
int ret = -1;
|
|
if(!infer_init_){
|
|
// Create input tensor memory
|
|
int input_count = NumInputs();
|
|
int output_count = NumOutputs();
|
|
|
|
input_mems_ = (hbDNNTensor*)malloc(sizeof(hbDNNTensor) * input_count);
|
|
output_mems_ = (hbDNNTensor*)malloc(sizeof(hbDNNTensor) * output_count);
|
|
|
|
for(uint32_t i = 0; i < input_count; i++){
|
|
input_mems_[i].properties = input_properties_[i];
|
|
|
|
input_mems_[i].properties.alignedShape = input_mems_[i].properties.validShape;
|
|
|
|
auto current_shape = GetInputInfo(i).shape;
|
|
auto &mem = input_mems_[i].sysMem[0];
|
|
int intput_memSize = input_properties_[i].alignedByteSize;
|
|
|
|
ret = hbSysAllocCachedMem(&mem, intput_memSize);
|
|
|
|
if(ret != 0){
|
|
FDERROR << "hbSysAllocCachedMem fails." << std::endl;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
for(uint32_t i = 0; i < output_count; i++){
|
|
|
|
output_mems_[i].properties = output_properties_[i];
|
|
|
|
auto current_shape = GetOutputInfo(i).shape;
|
|
auto &mem = output_mems_[i].sysMem[0];
|
|
int output_memSize = output_properties_[i].alignedByteSize;
|
|
|
|
ret = hbSysAllocCachedMem(&mem, output_memSize);
|
|
if(ret != 0){
|
|
FDERROR << "hbSysAllocCachedMem fails." << std::endl;
|
|
return false;
|
|
}
|
|
}
|
|
infer_init_ = true;
|
|
}
|
|
// Copy input data to input tensor memory
|
|
for (uint32_t i = 0; i < NumInputs(); i++) {
|
|
if (inputs[i].Data() == nullptr) {
|
|
FDERROR << "inputs[i].Data is NULL." << std::endl;
|
|
return false;
|
|
}
|
|
auto &mem = input_mems_[i].sysMem[0];
|
|
|
|
memcpy(mem.virAddr, inputs[i].Data(), inputs[i].Nbytes());
|
|
ret = hbSysFlushMem(&mem, HB_SYS_MEM_CACHE_CLEAN);
|
|
if(ret != 0){
|
|
FDERROR << "hbSysFlushMem fails." << std::endl;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
hbDNNTaskHandle_t task_handle = nullptr;
|
|
hbDNNInferCtrlParam infer_ctrl_param;
|
|
HB_DNN_INITIALIZE_INFER_CTRL_PARAM(&infer_ctrl_param);
|
|
|
|
RUNTIME_PROFILE_LOOP_BEGIN(1)
|
|
ret = hbDNNInfer(&task_handle,
|
|
&output_mems_,
|
|
input_mems_,
|
|
dnn_handle_,
|
|
&infer_ctrl_param);
|
|
RUNTIME_PROFILE_LOOP_END
|
|
if(ret != 0){
|
|
FDERROR << "hbDNNInference fails." << std::endl;
|
|
return false;
|
|
}
|
|
ret = hbDNNWaitTaskDone(task_handle, 0);
|
|
if(ret !=0){
|
|
FDERROR << "hbDNNWaitTaskDone fails." << std::endl;
|
|
return false;
|
|
}
|
|
ret = hbDNNReleaseTask(task_handle);
|
|
if(ret !=0){
|
|
FDERROR << "hbDNNReleaseTask fails." << std::endl;
|
|
return false;
|
|
}
|
|
// get result
|
|
outputs->resize(outputs_desc_.size());
|
|
std::vector<int64_t> temp_shape(4);
|
|
for (size_t i = 0; i < outputs_desc_.size(); ++i) {
|
|
temp_shape.resize(outputs_desc_[i].shape.size());
|
|
for (int j = 0; j < outputs_desc_[i].shape.size(); ++j) {
|
|
temp_shape[j] = outputs_desc_[i].shape[j];
|
|
}
|
|
(*outputs)[i].Resize(temp_shape, outputs_desc_[i].dtype,
|
|
outputs_desc_[i].name);
|
|
|
|
hbSysFlushMem(&(output_mems_[i].sysMem[0]), HB_SYS_MEM_CACHE_INVALIDATE);
|
|
auto data = (float *)(output_mems_[i].sysMem[0].virAddr);
|
|
|
|
auto shift = output_mems_[i].properties.shift.shiftData;
|
|
auto scale = output_mems_[i].properties.scale.scaleData;
|
|
|
|
for(int j = 0; j < (*outputs)[i].Nbytes(); j++){
|
|
if (output_mems_[i].properties.quantiType == SHIFT) {
|
|
data[j] = data[j] / (1 << shift[j]);
|
|
} else if (output_mems_[i].properties.quantiType == SCALE) {
|
|
data[j] = data[j] * scale[j];
|
|
}
|
|
}
|
|
|
|
memcpy((*outputs)[i].MutableData(), (float*)output_mems_[i].sysMem[0].virAddr,
|
|
(*outputs)[i].Nbytes());
|
|
}
|
|
RUNTIME_PROFILE_LOOP_H2D_D2H_END
|
|
return true;
|
|
}
|
|
|
|
FDDataType HorizonBackend::HorizonTensorTypeToFDDataType(int32_t type){
|
|
if (type == hbDNNDataType::HB_DNN_TENSOR_TYPE_F16) {
|
|
return FDDataType::FP16;
|
|
}
|
|
if (type == hbDNNDataType::HB_DNN_TENSOR_TYPE_F32) {
|
|
return FDDataType::FP32;
|
|
}
|
|
if (type == hbDNNDataType::HB_DNN_TENSOR_TYPE_S8) {
|
|
return FDDataType::INT8;
|
|
}
|
|
if (type == hbDNNDataType::HB_DNN_TENSOR_TYPE_S16) {
|
|
return FDDataType::INT16;
|
|
}
|
|
if (type == hbDNNDataType::HB_DNN_TENSOR_TYPE_S32) {
|
|
return FDDataType::INT32;
|
|
}
|
|
if (type == hbDNNDataType::HB_DNN_TENSOR_TYPE_U8) {
|
|
return FDDataType::UINT8;
|
|
}
|
|
|
|
FDERROR << "FDDataType don't support this type" << std::endl;
|
|
return FDDataType::UNKNOWN1;
|
|
}
|
|
|
|
hbDNNDataType HorizonBackend::FDDataTypeToHorizonTensorType(FDDataType type){
|
|
if (type == FDDataType::FP16) {
|
|
return hbDNNDataType::HB_DNN_TENSOR_TYPE_F16;
|
|
}
|
|
if (type == FDDataType::FP32) {
|
|
return hbDNNDataType::HB_DNN_TENSOR_TYPE_F32;
|
|
}
|
|
if (type == FDDataType::INT8) {
|
|
return hbDNNDataType::HB_DNN_TENSOR_TYPE_S8;
|
|
}
|
|
if (type == FDDataType::INT16) {
|
|
return hbDNNDataType::HB_DNN_TENSOR_TYPE_S16;
|
|
}
|
|
if (type == FDDataType::INT32) {
|
|
return hbDNNDataType::HB_DNN_TENSOR_TYPE_S32;
|
|
}
|
|
if (type == FDDataType::UINT8) {
|
|
return hbDNNDataType::HB_DNN_TENSOR_TYPE_U8;
|
|
}
|
|
FDERROR << "horizon_tensor_type don't support this type" << std::endl;
|
|
|
|
return hbDNNDataType::HB_DNN_TENSOR_TYPE_MAX;
|
|
}
|
|
|
|
} //namespace fastdeploy
|