py script
获得脚本运行时传入的参数
启动CPP_EXE,并将脚本收到的参数传入cpp可执行文件
os.system(CPP_EXE + console_params)
main
1. 系统初始化 HIAI_Init(kDeviceId);
2. 创建并启动图 hiai::Graph::CreateGraph(kGraphConfigFilePath);
3. 获取图的实例 graph = hiai::Graph::GetInstance(kGraphId);
4. 设置回调函数(根据规则自定义:重载RecvData),
main中的回调函数是最后一个Engine传出的数据,这里不需要做什么,只是flag--
graph->SetDataRecvFunctor(
target_port_config,
std::shared_ptr<CustomDataRecvInterface>(
new (nothrow) CustomDataRecvInterface()));
其中 CustomDataRecvInterface 类的定义有要求:
// https://www.huaweicloud.com/ascend/doc/Atlas%20200%20DK/1.32.0.0(beta)/zh/zh-cn_topic_0204323953.html
// https://www.huaweicloud.com/ascend/doc/Atlas%20200%20DK/1.32.0.0(beta)/zh/zh-cn_topic_0204323784.html
1. 继承 hiai::DataRecvInterface
2. 重载RecvData方法
class CustomDataRecvInterface : public hiai::DataRecvInterface {
public:
/*** @brief: Constructor */
CustomDataRecvInterface() = default;
~CustomDataRecvInterface() = default;
/*
* @brief: Receive data from call back engine
* @param [in]: received message
* @return: result */
HIAI_StatusT RecvData(const std::shared_ptr<void>& message);
};
// 重写的内容如下,全局flag--,
HIAI_StatusT CustomDataRecvInterface::RecvData(
const std::shared_ptr<void>& message) {
// no need to read any message, only decrease flag
mt.lock();
flag--;
mt.unlock();
return HIAI_OK;
}
5. 发送数据,启动第一个Engine (general_image)
graph->SendData(engine_id, "ConsoleParams",
static_pointer_cast<void>(param_ptr));
// 发送到第一个Engine的数据是 shared_ptr<ConsoleParams> param_ptr 类型
// https://support.huaweicloud.com/api-matrix-atlas200dkappc32/atlasmatrix_07_0041.html
回调函数,重载而来,需要继承hiai::DataRecvInterface
,
https://www.huaweicloud.com/ascend/doc/Atlas%20200%20DK/1.32.0.0(beta)/zh/zh-cn_topic_0204323784.html
Engine1 - general_image
Init 没做什么
该引擎运行前需要的初始化操作。
// GeneralImage 继承 hiai::Engine
class GeneralImage : public hiai::Engine {
// Init什么也没做
HIAI_StatusT GeneralImage::Init(
const hiai::AIConfig& config,
const vector<hiai::AIModelDescription>& model_desc) {
// do noting
return HIAI_OK;
}
HIAI_IMPL_ENGINE_PROCESS
HIAI_IMPL_ENGINE_PROCESS
宏方法,上个引擎往本引擎发送数据,在这个宏里处理数据,发一次处理一次。
1. 检查arg0,提取input_path
2. 提取文件路径到file_vec
3. for,send每张图到 inference engine
用cv读取图像,把图像信息存入shared_ptr<EngineTrans> &image_handle
发送SendData(kSendDataPort, "EngineTrans", static_pointer_cast<void>(image_handle));
发送成功则sleep 200ms,image_handle->is_finished = true; 否则再下一张
4. 发送结束标志
image_handle->is_finished = true;
SendData(kSendDataPort, "EngineTrans",
static_pointer_cast<void>(image_handle));
// 发送到下一个Engine的数据是 shared_ptr<EngineTrans> &image_handle类型
继承 hiai::Engine 的 GeneralImage 通过HIAI_IMPL_ENGINE_PROCESS参数 与 底层产生联系,
HIAI_IMPL_ENGINE_PROCESS("general_image",
GeneralImage, INPUT_SIZE) {
Engine2 - general_inference
接受Engine1 - general_image
发过来的图片,
dvpp预处理后交给模型管家前向传播得到输出结果,
发送处理结果到Engine3 - general_post
。
Init
1. 初始化 AI模型管家 aiModelManager
std::make_shared<hiai::AIModelManager>();
2. 设置模型描述,从graph.config文件获取模型路径
hiai::AIModelDescription fd_model_desc;
fd_model_desc.set_path(model_path);
3. 初始化模型管理器
vector<hiai::AIModelDescription> model_desc_vec;
model_desc_vec.push_back(fd_model_desc);
ai_model_manager_->Init(config, model_desc_vec); // 初始化模型管理器
HIAI_IMPL_ENGINE_PROCESS
1. 检查参数arg0,转化参数类型
shared_ptr<EngineTrans> image_handle = static_pointer_cast<EngineTrans>(arg0);
2. 判断结束标志,发送数据到推理Engine
if (image_handle->is_finished)
SendToEngine(image_handle)
SendData(kSendDataPort, "EngineTrans",
static_pointer_cast<void>(image_handle));
// https://support.huaweicloud.com/api-matrix-atlas200dkappc32/atlasmatrix_07_0041.html
3. 如果没有接收到结束标志,则预处理图片resize 返回 ImageData
没有接收到结束标志,但一定接收到了图片(否则不会进入PROCESS),可以预处理图片咯 ^v^
用dvpp resize图片,保证左顶even,右底odd
4. 目的是丢到AI模型管家前向传播,inference
从dvpp的 ImageData 格式 到 neural格式 到 hiai::IAITensor格式
ImageData -- > hiai::AINeuralNetworkBuffer --> hiai::IAITensor
把 hiai::IAITensor 图片push到vector<shared_ptr<hiai::IAITensor>>
创建输出Tensor
vector<shared_ptr<hiai::IAITensor>> output_data; // 实参
ai_model_manager_->CreateOutputTensor(input_data_vec,
output_data_vec); // 形参
开始推理Process
ai_model_manager_->Process(ai_context,
input_data_vec,
output_data_vec,
kAiModelProcessTimeout);
5. 发送结果
SendResult(image_handle, output_data);
for, 对于每个输出Tensor,output_data_vec
image_handle->inference_res.emplace_back(out);
SendData(kSendDataPort, "EngineTrans",
static_pointer_cast<void>(image_handle));
Engine3 - general_post
接收模型输出的结果,后处理
Init
什么也没做
HIAI_IMPL_ENGINE_PROCESS
1. 检查参数arg0,转化参数类型
shared_ptr<EngineTrans> result = static_pointer_cast<EngineTrans>(arg0);
2. 判断结束标志 若结束发送空字符串
if (result->is_finished)
SendSentinel() // 哨兵
shared_ptr<string> sentinel_msg(new (nothrow) string);
SendData(kSendDataPort, "string",
static_pointer_cast<void>(sentinel_msg));
3. 如果不是结束标志 则后处理模型输出 PostProcess
解码模型输出的Tensor decodeTensor (yolo3的精髓)
非极大值抑制算法 nonMaximumSuppression (yolo3的精髓)
返回 std::vector<BoundingBox> result;
画框框保存图片
一些宏接口
1. HIAI_REGISTER_DATA_TYPE 自定义数据结构 的宏接口
宏原型 HIAI_REGISTER_DATA_TYPE(name, type)
为用户自定义的数据结构类型提供序列化和反序列化机制。
https://support.huaweicloud.com/api-matrix-atlas200dkappc32/atlasmatrix_07_0063.html
2. HIAI_DEFINE_PROCESS 定义引擎输入出端口数
https://support.huaweicloud.com/api-matrix-atlas200dkappc32/atlasmatrix_07_0048.html
宏原型HIAI_DEFINE_PROCESS(inputPortNum, outputPortNum)
用户直接调用该宏
定义Engine的输入与输出端口数 [1 , 16]
。
用户调用宏的顺序应该是:HIAI_DEFINE_PROCESS
--> HIAI_IMPL_ENGINE_PROCESS
3. HIAI_IMPL_ENGINE_PROCESS 接受处理数据
https://support.huaweicloud.com/api-matrix-atlas200dkappc32/atlasmatrix_07_0049.html
宏原型HIAI_IMPL_ENGINE_PROCESS(name, engineClass, inPortNum)
engineClass 需要继承 hiai::Engine
需要重写Init
4. HIAI_ENGINE_LOG
https://support.huaweicloud.com/api-matrix-atlas200dkappc30/atlasmatrix_07_0149.html
宏原型很多,打印日志的格式有8种。
调用HIAI_ENGINE_LOG
后,系统将日志记录日志文件中,日志文件在Host侧
或开发者板的/var
目录下。
Device侧
的日志被记录在文件名称以device-id
开头的日志文件中,
Host侧
的日志被记录在文件名称以host-0
开头的日志文件中。
最简单的一种
HIAI_ENGINE_LOG("Start initialize!");