文章大纲

  • 引言
  • 一、LiteSession::CompileGraph(Model *model)
  • 二、LiteSession::CompileGraph(Model *model) 核心流程
    • 1、MindirModel::ConvertTensors
      • 1.1、遍历并执行MindirModel::ConvertTensor
        • 1.1.1、MindirModel::LoadTensorData
  • 三、LiteSession::InitGraphInputTensors(model)
  • 四、LiteSession::InitGraphOutputTensors(model)
  • 五、Scheduler::Schedule(std::vector<mindspore::kernel::KernelExec *> *dst_kernels)

引言

书接上文继续补充LiteSession::CompileGraph(Model *model)的后续流程,前一篇文章介绍了Mindspore Lite AI 的核心LiteSession 的部分Init流程,这一篇接着往下介绍LiteSession处理Model对象的后续流程。

一、LiteSession::CompileGraph(Model *model)

在LiteSession中传入Model * (是从权重处理器的缓存区中读取出来的封封装而得到的Model *)到CompileGraph 时,先进行拆包转换Model->Tensor,不过先会先去判断Model 的模型类型,不同的模型使用不同的转换算法,其中Model 的子类有一个抽象父类AbstractBaseModel,目前只有MindIRModel 这个子类即用于描述MINDIR模型的。转为完成后,再把处理过的Model 传入用于初始化Graph,即vector< mslite:Tensor >

int LiteSession::CompileGraph(Model *model) {auto ret = PreCheck(model);MS_LOG(ERROR) << "NH#CompileGraph START";
...if (model->model_type_ != ModelType_MSLite) {MS_LOG(ERROR) << "NH#model typeModelType_MSLite: " << model->model_type_;ret = reinterpret_cast<AbstractBaseModel *>(model)->ConvertTensors(&this->tensors_);} else {MS_LOG(ERROR) << "NH#model (model->model_type_" << model->model_type_;// Convert to abstract base model interfaceret = ConvertTensors(model);context_->set_schema_version(reinterpret_cast<LiteModel *>(model)->GetSchemaVersion());}
...ret = lite::PackWeightManager::GetInstance()->StoreOriginTensorData(model, &tensors_);
...InitGraphInputTensors(model);InitGraphOutputTensors(model);PackedNodePass::GetInstance().Run(model, tensors_);MS_LOG(ERROR) << "NH#CompileGraph  create Scheduler";// scheduler kernelsScheduler scheduler(context_.get(), ms_context_, model, &tensors_, &inputs_, &outputs_, is_train_session_,&is_infershape_, &is_control_flow_, &infer_along_running_, execution_plan_, delegate_,delegate_device_type_);scheduler.SetupSchedulerCb(std::move(sched_cb_));scheduler.SetConfig(config_info_);MS_LOG(ERROR) << "NH#CompileGraph scheduler.Schedule";ret = scheduler.Schedule(&kernels_);...if (ms_context_->GetThreadNum() == 1 && !context_->IsCpuFloat16Enabled() && is_control_flow_) {context_->DeleteThreadPool();(void)context_->CreateThreadPool(is_control_flow_);}infer_along_running_ = infer_along_running_ && !is_control_flow_ && !is_train_session_ && (is_infershape_ != RET_OK);InitGraphInOutTensorsMap(model);non_tail_call_kernels_ = scheduler.NonTailCallNodes();ret = PrepareKernels(model);...if (is_train_session_ || is_prepare_session_) {is_running_.store(false);return RET_OK;}ret = InitExecutor();...MarkSharedWeight(kernels_);FreePackOpWeight(kernels_);infer_along_running_ = infer_along_running_ && (runtime_allocator_ == nullptr);if (infer_along_running_) {this->context_->set_infer_checker(InferCheckerAll);}is_running_.store(false);return RET_OK;
}

二、LiteSession::CompileGraph(Model *model) 核心流程

1、MindirModel::ConvertTensors

将模型中的张量(tensors)转换为Lite框架可以使用的格式

int MindirModel::ConvertTensors(std::vector<mindspore::lite::Tensor *> *lite_tensors) {if (lite_tensors == nullptr) {MS_LOG(ERROR) << "lite tensors is null.";return mindspore::lite::RET_NULL_PTR;}
//获取张量数量及输入输出索引uint32_t tensor_count = this->all_mindir_tensors_.size();auto model_input_indices = this->graph_.input_indices_;auto model_output_indices = this->graph_.output_indices_;
//遍历所有的MindIR张量,并通过ConvertTensor方法将其转换为Lite张量for (uint32_t i = 0; i < tensor_count; ++i) {auto src_tensor = this->all_mindir_tensors_[i];auto *dst_tensor = ConvertTensor(src_tensor);...if (mindspore::lite::IsContain(model_input_indices, i)) {dst_tensor->set_category(mindspore::lite::Category::GRAPH_INPUT);}if (mindspore::lite::IsContain(model_output_indices, i)) {// a tensor is as both input and output, would be treated as an input.if (!dst_tensor->IsGraphInput()) {dst_tensor->set_category(mindspore::lite::Category::GRAPH_OUTPUT);}}auto ret = CheckTensorValid(dst_tensor);....lite_tensors->emplace_back(dst_tensor);}return mindspore::lite::RET_OK;
}

1.1、遍历并执行MindirModel::ConvertTensor

mindspore::lite::Tensor *MindirModel::ConvertTensor(TensorProtoWrap mindir_tensor_wrap) {auto mindir_tensor = mindir_tensor_wrap.tensor_proto();auto data_type = MindirModelUtil::ProtoTypeToTypeId(mindir_tensor.data_type());std::vector<int> shape;for (int i = 0; i < mindir_tensor.dims_size(); i++) {shape.push_back(mindir_tensor.dims(i));}auto format = Format::NCHW;mindspore::lite::NodeType node_type;if (mindir_tensor.has_raw_data() || mindir_tensor.has_external_data()) {node_type = mindspore::lite::NodeType_ValueNode;} else {node_type = mindspore::lite::NodeType_CNode;}auto category = TensorCategory(node_type, mindir_tensor.dims_size(), data_type, mindir_tensor.raw_data().size());auto *lite_tensor = new mindspore::lite::Tensor(data_type, shape, format, category);lite_tensor->set_tensor_name(mindir_tensor_wrap.name());if (this->LoadTensorData(lite_tensor, mindir_tensor) != RET_OK) {MS_LOG(WARNING) << "MindirModel: Convert tensor failed, load tensor data failed, tensor data will be empty.";}return lite_tensor;
}
1.1.1、MindirModel::LoadTensorData
int MindirModel::LoadTensorData(mindspore::lite::Tensor *lite_tensor, const mind_ir::TensorProto &mindir_tensor) {if (mindir_tensor.has_raw_data()) {return memcpy_s(lite_tensor->MutableData(), lite_tensor->Size(), mindir_tensor.raw_data().data(),mindir_tensor.raw_data().size());}if (mindir_tensor.has_external_data()) {std::string file = this->GetModelPath() + "/" + mindir_tensor.external_data().location();// Read filestd::basic_ifstream<char> fid(file, std::ios::in | std::ios::binary);...fid.seekg(0, std::ios_base::end);size_t file_size = static_cast<size_t>(fid.tellg());fid.clear();fid.seekg(0);auto plain_data = std::make_unique<char[]>(file_size);constexpr uint8_t is_little_endian = 1;constexpr int byte_order_index = 0;fid.read(plain_data.get(), file_size);fid.close();// if byte order is not same return falseif ((plain_data[byte_order_index] == is_little_endian) != common::IsLittleByteOrder()) {MS_LOG(ERROR) << "The byte order of export MindIr device and load MindIr device is not same!";return mindspore::lite::RET_ERROR;}const uint8_t *data = reinterpret_cast<const uint8_t *>(plain_data.get());auto ret =common::huge_memcpy(reinterpret_cast<uint8_t *>(lite_tensor->MutableData()), lite_tensor->Size(),data + mindir_tensor.external_data().offset(), mindir_tensor.external_data().length());return mindspore::lite::RET_OK;}return mindspore::lite::RET_NOT_SUPPORT;
}

三、LiteSession::InitGraphInputTensors(model)

void LiteSession::InitGraphInputTensors(const lite::Model *model) {MS_ASSERT(model != nullptr);auto graph_in_size = model->graph_.input_indices_.size();MS_LOG(ERROR) << "NH#InitGraphInputTensors in_size: " << graph_in_size;for (size_t i = 0; i < graph_in_size; ++i) {auto in_tensor_idx = model->graph_.input_indices_[i];MS_ASSERT(in_tensor_idx < this->tensors_.size());auto *in_tensor = this->tensors_.at(in_tensor_idx);MS_ASSERT(in_tensor != nullptr);this->inputs_.emplace_back(in_tensor);}
}

四、LiteSession::InitGraphOutputTensors(model)

void LiteSession::InitGraphOutputTensors(const lite::Model *model) {MS_ASSERT(model != nullptr);MS_ASSERT(this->outputs_.empty());auto graph_out_size = model->graph_.output_indices_.size();for (size_t i = 0; i < graph_out_size; ++i) {auto out_tensor_idx = model->graph_.output_indices_[i];MS_ASSERT(out_tensor_idx < this->tensors_.size());auto *out_tensor = this->tensors_.at(out_tensor_idx);MS_ASSERT(out_tensor != nullptr);this->outputs_.emplace_back(out_tensor);}
}

五、Scheduler::Schedule(std::vector<mindspore::kernel::KernelExec *> *dst_kernels)

Scheduler::Schedule 何时调用?NNRT 方式由LiteSession::CompileGraph 触发进入到Shedule函数内部后CPU的话传入到InitDelegateKernels里的DelegateKernels为nullptr 直接返回;nnrt方式的话就会把前面LiteSession::CreateNNRTDelegate() Relace上去 DelegateKernels,
所以CPU方式加载模型就是直接把模型文件的Buffer 转为相应的对象,存储到LiteSession的std::vector<mindspore::lite::Tensor *> inputs_里,走nnrt需要先创建对应的Delegate,走mindspore则不需要创建,直接返回ret_ok

int Scheduler::Schedule(std::vector<kernel::KernelExec *> *dst_kernels) {MS_LOG(DEBUG) << "Start schedule.";int check_input_ret = CheckInputParam(dst_kernels);
...shape_fusion_pass_ =std::make_shared<ShapeFusionPass>(context_, reinterpret_cast<LiteModel *>(src_model_), src_tensors_);int ret = SchedulePreProcess();
...if (*is_control_flow_) {control_flow_scheduler_ = std::make_shared<ControlFlowScheduler>(context_, ms_context_, src_tensors_);}ret = ScheduleGraphToKernels(dst_kernels);FreeOpParameters();op_parameters_.clear();...if (context_->float_mode) {kernel::KernelExecUtil::FindAllInoutKernels(*dst_kernels);ret = DelQuantDTypeCastKernel(dst_kernels);if (ret != RET_OK) {MS_LOG(ERROR) << "Delete quant_dtype_cast kernel failed.";return ret;}}shape_fusion_pass_->StoreStateAndReset();MS_LOG(DEBUG) << "Start to init delegate kernels.";ret = InitDelegateKernels(dst_kernels);...MS_LOG(DEBUG) << "Finish to init delegate kernels.";ret = CheckCpuValid(dst_kernels);if (ret != RET_OK) {MS_LOG(ERROR) << "kernels invalid in set devices.";return ret;}kernel::KernelExecUtil::FindAllInoutKernels(*dst_kernels);ret = ConstructSubGraphs(dst_kernels);ret = ProcessSubGraphTranspose(dst_kernels);if (ret != RET_OK) {MS_LOG(ERROR) << "Process SubGraph with multi layout failed.";return ret;}if (*is_control_flow_) {
control_flow_scheduler_->SetSubgraphForPartialNode(&partial_kernel_subgraph_index_map_,                                              &subgraph_index_subgraph_kernel_map_);ret = control_flow_scheduler_->Schedule(dst_kernels);}auto status = RuntimePass(dst_kernels, src_tensors_);ret = InitKernels(std::move(*dst_kernels));if (ret != RET_OK) {MS_LOG(ERROR) << "InitKernels failed.";return ret;}shape_fusion_pass_->RestoreState();return RET_OK;
}

未完待续

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/912621.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/912621.shtml
英文地址,请注明出处:http://en.pswp.cn/news/912621.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

WireShark网络取证分析第一集到第五集和dvwa靶场环境分析漏洞

文章目录 一、WireShark网络取证是什么?二、WireShark网络取证1.WireShark网络取证分析第一集Ann的即时通讯好友叫什么名字?在捕获的即时通讯对话中第一条评论是什么?Ann传输的文件叫什么名字?您想提取的文件的魔数是什么(前四个字节)?文件的MD5sum是多少?什么是秘密配方…

【51单片机按下按键1,8位共阴极数码管输出2022-606。按下按键2,8位共阴极数码管输出606-1132。】2022-6-10

缘由单片极的共阴极数码管按下按键1和按键2输出的内容-编程语言-CSDN问答 #include "REG52.h" unsigned char code smgduan[]{0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0,64}; //共阴0~F消隐减号 unsigned char Js0, miao…

HDMI转12G- SDI GS12170+GS12281-富利威方案设计及技术支持

GS12281 是一款低功耗、多速率、重定时电缆驱动器&#xff0c;支持高达 12G UHD-SDI 的速率。它设计用于接收 100Ω 差分输入信号&#xff0c;自动从数字视频信号中恢复嵌入式时钟并重新定时输入数据&#xff0c;并通过 75Ω 同轴电缆传输重新定时的信号。 100Ω 走线输入支持…

自然语言处理:NLP入门

本文目录&#xff1a; 一、概念二、发展史三、核心任务和技术特别分享1&#xff1a;当前挑战和前沿方向特别分享2&#xff1a;大神名言启示 前言&#xff1a;从本章开始讲解自然语言处理&#xff08;NLP&#xff09;&#xff0c;今天先入个门~ 一、概念 自然语言处理&#xff…

用Fiddler中文版抓包工具掌控微服务架构中的接口调试:联合Postman与Charles的高效实践

随着微服务架构在项目中的广泛应用&#xff0c;系统被拆分成多个独立的服务&#xff0c;彼此通过API通信。虽然架构带来了灵活性&#xff0c;但也大幅增加了接口数量和调用链复杂度&#xff1a;一次用户操作可能触发跨多个服务的调用&#xff0c;导致前端调试难度飙升。要精准排…

MongoDB 更新文档指南

MongoDB 更新文档指南 引言 MongoDB 是一款高性能、可扩展的文档存储系统&#xff0c;它为存储和管理大量数据提供了强大的支持。在 MongoDB 中&#xff0c;更新文档是常见操作之一&#xff0c;它允许用户修改现有文档的内容。本文将详细讲解 MongoDB 中更新文档的各种方法&a…

Cursor + Serena MCP集成,更好的解析项目架构

项目地址&#xff0c;下到本地。 Serena可以更好的理解项目的架构并总结&#xff0c;而不是简单的阅读代码文件&#xff0c;可以直接用Cursor结合MCP的方式进行使用。&#xff1a;Serena 的语义代码分析功能建立在语言服务器上&#xff0c;使用广泛实施的语言服务器协议&#x…

【Python】numpy数组常用数据处理(测试代码+api例程)

目录 一、数列生成1.按照间隔生成数列&#xff08;np.array[]&#xff09;2.按照数列数字个数生成数列&#xff08;np.linspace&#xff09; 二、数列增删改查1.1 数组末尾添加数据&#xff08;np.append&#xff09;1.2 数组指定索引位置添加数据&#xff08;np.insert&#x…

CMU-15445(6)——PROJECT#2-BPlusTree-Task#1

PROJECT#2-BTree 在 PROJECT#2 中&#xff0c;我们需要实现一个B plus Tree&#xff0c;用过 MySQL 的同学肯定对它不陌生&#xff0c;BTree是实现高效数据检索的核心组件&#xff0c;其内部节点的作用是引导搜索过程&#xff0c;而实际的数据项则存于叶子节点中。该索引结构能…

向量数据库搜索原理解密:从暴力扫描到近似最近邻的演进之路

摘要 向量数据库已成为处理AI时代海量非结构化数据的核心基础设施。本文深入解析向量搜索的六大核心技术原理,涵盖暴力扫描、树结构索引、量化压缩、图导航算法等核心机制,通过10张架构图解与数学公式推导,揭示千万级向量毫秒级检索背后的工程奇迹。全文超5000字,包含Fais…

Yolov7训练自己的数据集和ONNX/TRT部署

Yolov7训练自己的数据集和ONNX/Trt部署 一、环境配置 1.1 项目下载 项目原地址&#xff1a;GitHub - WongKinYiu/yolov7: Implementation of paper - YOLOv7: Trainable bag-of-freebies sets new state-of-the-art for real-time object detectors 打开终端&#xff0c;输…

Python - 数据分析三剑客之NumPy

在Python中&#xff0c;NumPy、Pandas和Matplotlib是进行数据分析和数据可视化的三个核心库。它们各自有不同的功能&#xff0c;但经常一起使用来处理和分析数据。 1、NumPy NumPy&#xff08;Numerical Python&#xff09;是一个用于科学计算的库&#xff0c;提供了高性能的…

百度文库智能PPT月访问量超3400万,用户规模翻倍增长

6月27日&#xff0c;极光旗下月狐数据发布《2025年智能PPT行业市场研究报告》。报告显示&#xff0c;智能PPT市场整体增速年同比超50%&#xff0c;市场玩家成倍激增。其中&#xff0c;百度文库智能PPT月访问量超3400万、位列全球第一&#xff0c;市场份额在中国位于断崖式领先。…

远眺科技工业园区数字孪生方案,如何实现智能管理升级?

面对工业园区日益复杂的能耗管控、环境监测、安全运维需求&#xff0c;传统管理模式已经难以为继。而数字孪生技术&#xff0c;正好成为解决上述问题的关键“解药”。本文将以远眺工业园区数字孪生项目为例&#xff0c;为您剖析数字孪生技术如何解决数据孤岛、响应滞后等痛点。…

成都芯谷金融中心文化科技园:打造区域科技活力

在成渝地区双城经济圈建设加速推进的背景下&#xff0c;成都芯谷金融中心文化科技园正以"科技文化金融"的融合创新模式&#xff0c;重塑区域产业生态&#xff0c;成为驱动城市高质量发展的活力源泉。这座总建筑面积达45万平方米的产城综合体&#xff0c;不仅承载着双…

Claude Code 全面指南:从安装到高效开发的实用教程

在 AI 助手逐渐成为开发者标配的今天&#xff0c;Claude Code 作为 Anthropic 推出的一款智能编程工具&#xff0c;凭借其强大的自然语言交互和自动化能力&#xff0c;正迅速改变着软件开发的方式。本文将详细介绍 Claude Code 的功能、安装配置、使用方法及安全与成本管理&…

在Flutter中生成App Bundle并上架Google Play

Ran tool 要在Flutter中生成App Bundle并上架Google Play&#xff0c;请按照以下步骤操作&#xff1a; 1. 准备签名密钥 首先需要创建一个密钥库用于签名&#xff1a; keytool -genkey -v -keystore upload-keystore.jks -keyalg RSA -keysize 2048 -validity 10000 -alias …

kubernetes pod调度基础

目录 Replication Controller 和 ReplicaSet 标签与标签选择器 无状态应用管理Deployment 有状态应用管理StatefulSet 守护进程集DaemonSet Replication Controller 和 ReplicaSet RC用来确保Pod副本数达到期望值,这样可以确保一个或多七个同类Pod总是可用的 如果存在的P…

Vue 3 响应式核心源码详解(基于 @vue/reactivity)

&#x1f9ec; Vue 3 响应式核心源码详解&#xff08;基于 vue/reactivity&#xff09; ⚙️ 整理不易&#xff0c;记得点赞、收藏、关注&#xff0c;揭开 Vue 响应式的神秘面纱&#xff01; &#x1f9ed; 一、源码结构总览&#xff08;relevant files&#xff09; Vue 的响应…

编写shell脚本扫描工具,扫描服务器开放了哪些端口(再尝试用python编写一个)

先将需要扫描的服务器的端口显示出来&#xff0c;然后再显示哪些ip地址对应的服务器的哪些端口已开放或未开放 下面这个shell脚本可以同时扫描多个ip对应的多个服务器的多个端口是否开放&#xff1a; 以下是运行结果&#xff1a; nc 和 nmap 扫描别人的机器开放了哪些端口 ne…