MNN 执行推理(九)

2024-03-23 14:12
文章标签 推理 执行 mnn

本文主要是介绍MNN 执行推理(九),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在这里插入图片描述

系列文章目录


MNN createFromBuffer(一)
MNN createRuntime(二)
MNN createSession 之 Schedule(三)
MNN createSession 之创建流水线后端(四)
MNN Session 之维度计算(五)
MNN Session 之几何计算(六)
MNN Session 之 CPU 算子(七)
MNN Session 之 Vulkan 算子(八)
MNN 执行推理(九)


文章目录

  • 系列文章目录
  • 1、Interpreter::runSession
    • 1.1 Session::run
    • 1.1.1 Pipeline::execute
    • 1.1.1.1 VulkanBackend::onExecuteBegin
    • 1.1.1.2 Execution::onExecute
    • 1.1.1.3 Backend::onExecuteEnd
    • 1.1.1.3.1 _finish


1、Interpreter::runSession

在这里插入图片描述

// source/core/Interpreter.cpp
ErrorCode Interpreter::runSession(Session* session) const {std::unique_lock<std::mutex> _l(mNet->lock);
#ifdef MNN_INTERNAL_ENABLEDTimer timer;
#endifErrorCode errorcode = session->run();#ifdef MNN_INTERNAL_ENABLEDif (shouldLog(FREQ_LOW)) {waitSessionFinish(session);float costTime = (float)timer.durationInUs() / (float)1000;logForRunSession(session, costTime, "Interpreter::runSession");}
#endif // MNN_INTERNAL_ENABLEDreturn errorcode;
}

1.1 Session::run

Pipeline

// source/core/Session.cpp
ErrorCode Session::run() const {if (mNeedResize) {MNN_ERROR("Can't run session because not resized\n");return COMPUTE_SIZE_ERROR;}// mPipelines 类型为 std::vector<std::shared_ptr<Pipeline>>for (auto& iter : mPipelines) {auto error = iter->execute();if (NO_ERROR != error) {return error;}}return NO_ERROR;
}

1.1.1 Pipeline::execute

OpCacheInfo 、BackendCache、Command、CommandBuffer

// source/core/Pipeline.cpp
// typedef std::pair<BackendCache, std::vector<OpCacheInfo>> PipelineInfo
ErrorCode Pipeline::execute() {_copyInputs();auto& mBackend = mInfo.first.cache.first;auto& mBackupBackend = mInfo.first.cache.second;mBackend->onExecuteBegin();// mInfo 类型为 std::pair<BackendCache, std::vector<OpCacheInfo>>for (auto& info : mInfo.second) {auto& buffer = info.executeBuffer;
//#define LOG_VERPOSE
#ifdef LOG_VERPOSEFUNC_PRINT_ALL(info.op->name()->c_str(), s);
#endiffor (auto& cmdP : buffer.command) {auto& cmd = *cmdP;auto code = cmd.execution->onExecute(cmd.workInputs, cmd.workOutputs);
// #define LOG_VERPOSE
#ifdef LOG_VERPOSEauto dumpT = [](Tensor* t) {auto size = TensorUtils::getRawSize(t);size = size > 10 ? 10 : size;if (t->getType() == halide_type_of<float>()) {for (int i=0; i<size; ++i) {MNN_PRINT("%f, ", t->host<float>()[i]);}} else {for (int i=0; i<size; ++i) {MNN_PRINT("%d, ", t->host<int>()[i]);}}MNN_PRINT("\n");};if (/* cmd.op->name() && cmd.op->name()->str() == "/embed/embed_/Gather_output_0"*/cmd.op->type() == OpType_Convolution) {MNN_PRINT("%s Input begin:\n", EnumNameOpType(cmd.op->type()));for (auto t : cmd.workInputs) {dumpT(t);}MNN_PRINT("%s Output begin:\n", EnumNameOpType(cmd.op->type()));for (auto t : cmd.workOutputs) {dumpT(t);}}
#endifif (NO_ERROR != code) {mBackend->onExecuteEnd();return code;}}}mBackend->onExecuteEnd();return NO_ERROR;
}

1.1.1.1 VulkanBackend::onExecuteBegin

    在函数 Pipeline::execute 中调用 Backend::onExecuteBegin 函数的代码如下:

	mBackend->onExecuteBegin();

    onExecuteBegin 函数是个虚函数, mBackend->onExecuteBegin 调用是个多态,其基类为 Backend,此处 mBackendVulkanBackend,其具体实现代码如下:

// source/backend/vulkan/image/backend/VulkanBackend.cpp
void VulkanBackend::onExecuteBegin() const {if (!mDirect) {mCmdBuffers.push_back(mCmdBuffer->get());}// FUNC_PRINT_ALL(mDynamicMemoryPool->computeSize(), f);
}

VulkanBasicExecutionDirect::onExecute

1.1.1.2 Execution::onExecute

    在函数 Pipeline::execute 中调用 Execution::onExecute 函数的代码如下:

            auto code = cmd.execution->onExecute(cmd.workInputs, cmd.workOutputs);

    Execution::onExecute 函数是个虚函数,对于 Vulkan 来说,主要有 VulkanBasicExecutionDirect 和 VulkanBasicExecutionInDirect,我们以 VulkanBasicExecutionDirect 进行分析:

// source/backend/vulkan/image/execution/VulkanBasicExecution.cpp
ErrorCode VulkanBasicExecutionDirect::onExecute(const std::vector<Tensor *> &inputs, const std::vector<Tensor *> &outputs) {auto extra = static_cast<VulkanBackend *>(backend());extra->pushCommand(mCmdBuffer->get());return NO_ERROR;
}

1.1.1.3 Backend::onExecuteEnd

    在函数 Pipeline::execute 中调用 Backend::onExecuteEnd 函数的代码如下:

	mBackend->onExecuteEnd();

    Backend::onExecuteEnd 函数是个虚函数,对于 Vulkan 来说为 VulkanBackend ,以下为其代码:

// source/backend/vulkan/image/backend/VulkanBackend.cpp
void VulkanBackend::onExecuteEnd() const {_finish();
}

1.1.1.3.1 _finish

// source/backend/vulkan/image/backend/VulkanBackend.cpp
void VulkanBackend::_finish() const {if (mCmdBuffers.empty()) {return;}VkSubmitInfo submit_info = {/* .sType                = */ VK_STRUCTURE_TYPE_SUBMIT_INFO,/* .pNext                = */ nullptr,/* .waitSemaphoreCount   = */ 0,/* .pWaitSemaphores      = */ nullptr,/* .pWaitDstStageMask    = */ nullptr,/* .commandBufferCount   = */ (uint32_t)mCmdBuffers.size(),/* .pCommandBuffers      = */ mCmdBuffers.data(),/* .signalSemaphoreCount = */ 0,/* .pSignalSemaphores    = */ nullptr};auto fenceReal           = mFence->get();mFence->reset();CALL_VK(vkQueueSubmit(device().acquireDefaultDevQueue(), 1, &submit_info, fenceReal));auto res = mFence->wait();MNN_VK_CHECK(res);mCmdBuffers.clear();
}

   

这篇关于MNN 执行推理(九)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/838545

相关文章

如何使用 Bash 脚本中的time命令来统计命令执行时间(中英双语)

《如何使用Bash脚本中的time命令来统计命令执行时间(中英双语)》本文介绍了如何在Bash脚本中使用`time`命令来测量命令执行时间,包括`real`、`user`和`sys`三个时间指标,... 使用 Bash 脚本中的 time 命令来统计命令执行时间在日常的开发和运维过程中,性能监控和优化是不

C#如何优雅地取消进程的执行之Cancellation详解

《C#如何优雅地取消进程的执行之Cancellation详解》本文介绍了.NET框架中的取消协作模型,包括CancellationToken的使用、取消请求的发送和接收、以及如何处理取消事件... 目录概述与取消线程相关的类型代码举例操作取消vs对象取消监听并响应取消请求轮询监听通过回调注册进行监听使用Wa

PHP执行php.exe -v命令报错的解决方案

《PHP执行php.exe-v命令报错的解决方案》:本文主要介绍PHP执行php.exe-v命令报错的解决方案,文中通过图文讲解的非常详细,对大家的学习或工作有一定的帮助,需要的朋友可以参考下... 目录执行phpandroid.exe -v命令报错解决方案执行php.exe -v命令报错-PHP War

Oracle数据库执行计划的查看与分析技巧

《Oracle数据库执行计划的查看与分析技巧》在Oracle数据库中,执行计划能够帮助我们深入了解SQL语句在数据库内部的执行细节,进而优化查询性能、提升系统效率,执行计划是Oracle数据库优化器为... 目录一、什么是执行计划二、查看执行计划的方法(一)使用 EXPLAIN PLAN 命令(二)通过 S

maven 编译构建可以执行的jar包

💝💝💝欢迎莅临我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」👈,「stormsha的知识库」👈持续学习,不断总结,共同进步,为了踏实,做好当下事儿~ 专栏导航 Python系列: Python面试题合集,剑指大厂Git系列: Git操作技巧GO

jenkins 插件执行shell命令时,提示“Command not found”处理方法

首先提示找不到“Command not found,可能我们第一反应是查看目标机器是否已支持该命令,不过如果相信能找到这里来的朋友估计遇到的跟我一样,其实目标机器是没有问题的通过一些远程工具执行shell命令是可以执行。奇怪的就是通过jenkinsSSH插件无法执行,经一番折腾各种搜索发现是jenkins没有加载/etc/profile导致。 【解决办法】: 需要在jenkins调用shell脚

Lua 脚本在 Redis 中执行时的原子性以及与redis的事务的区别

在 Redis 中,Lua 脚本具有原子性是因为 Redis 保证在执行脚本时,脚本中的所有操作都会被当作一个不可分割的整体。具体来说,Redis 使用单线程的执行模型来处理命令,因此当 Lua 脚本在 Redis 中执行时,不会有其他命令打断脚本的执行过程。脚本中的所有操作都将连续执行,直到脚本执行完成后,Redis 才会继续处理其他客户端的请求。 Lua 脚本在 Redis 中原子性的原因

Smarty模板执行原理

为了实现程序的业务逻辑和内容表现页面的分离从而提高开发速度,php 引入了模板引擎的概念,php 模板引擎里面最流行的可以说是smarty了,smarty因其功能强大而且速度快而被广大php web开发者所认可。本文将记录一下smarty模板引擎的工作执行原理,算是加深一下理解。 其实所有的模板引擎的工作原理是差不多的,无非就是在php程序里面用正则匹配将模板里面的标签替换为php代码从而将两者

(function() {})();只执行一次

测试例子: var xx = (function() {     (function() { alert(9) })(); alert(10)     return "yyyy";  })(); 调用: alert(xx); 在调用的时候,你会发现只弹出"yyyy"信息,并不见弹出"10"的信息!这也就是说,这个匿名函数只在立即调用的时候执行一次,这时它已经赋予了给xx变量,也就是只是

Java程序到CPU上执行 的步骤

相信很多的小伙伴在最初学习编程的时候会容易产生一个疑惑❓,那就是编写的Java代码究竟是怎么一步一步到CPU上去执行的呢?CPU又是如何执行的呢?今天跟随小编的脚步去化解开这个疑惑❓。 在学习这个过程之前,我们需要先讲解一些与本内容相关的知识点 指令 指令是指导CPU运行的命令,主要由操作码+被操作数组成。 其中操作码用来表示要做什么动作,被操作数是本条指令要操作的数据,可能是内存地址,也