鴻蒙進階——Mindspore Lite AI框架源碼解讀之模型加載詳解(五)

文章大綱

  • 引言
  • 一、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…