MNN createRuntime(二)

news2025/2/25 21:16:26

在这里插入图片描述

系列文章目录


MNN createFromBuffer(一)
MNN createRuntime(二)
MNN createSession 之 Schedule(三)
MNN createSession 之创建流水线后端(四)
MNN Session::resize 之流水线编码(五)
MNN Session 创建执行器(六)


文章目录

  • 系列文章目录
  • 1、createRuntime
    • 1.1 RuntimeInfo
    • 1.2 Schedule::getApprociateType
    • 1.2.1 MNNGetExtraRuntimeCreator
    • 1.2.1.1 registerBackend
    • 1.2.1.2 GetExtraCreator
    • 1.3 RuntimeFactory::create
    • 1.3.1 VulkanRuntimeCreator
    • 1.3.2 VulkanRuntimeCreator
    • 1.4 ScheduleConfig
    • 1.5 BackendConfig


1、createRuntime

    根据 ScheduleConfig 创建运行时 RuntimeRuntimeInfo 的定义见 2.1,其 first 用来存放根据 configs 创建的 Runtime(如 VulkanRuntime,CUDARuntime),它的 second 存放的是默认 Runtime,一般为 CPURuntime

在这里插入图片描述

RuntimeInfo Interpreter::createRuntime(const std::vector<ScheduleConfig>& configs) {
    RuntimeInfo res;
    // 根据 configs 创建的 Runtime 存放在这里
    auto& mRuntimes = res.first;
    for (auto& config : configs) {
        Backend::Info compute;
        compute.type      = Schedule::getApprociateType(config);
        compute.numThread = config.numThread;
        if(config.type == MNN_FORWARD_AUTO) {
            if(compute.type == MNN_FORWARD_OPENCL || compute.type == MNN_FORWARD_METAL) {
                // AUTO set default gpu-mode MNN_GPU_TUNING_FAST
                compute.numThread = 16;
            }
        }
        compute.user      = config.backendConfig;
        if (mRuntimes.find(compute.type) == mRuntimes.end()) {
            auto newBn = RuntimeFactory::create(compute);
            if (nullptr == newBn) {
                MNN_ERROR("Can't create Runtime: %s\n", EnumNameForwardType((ForwardType)compute.type));
                continue;
            }
            mRuntimes[compute.type].reset(newBn);
        }
    }
    _getDefaultBackend(res);
    return res;
}

1.1 RuntimeInfo

typedef std::pair< std::map<MNNForwardType, std::shared_ptr<Runtime>>, \
					 std::shared_ptr<Runtime>> RuntimeInfo;

1.2 Schedule::getApprociateType

// source/core/Schedule.cpp
MNNForwardType Schedule::getApprociateType(const ScheduleConfig& config) {
    MNNForwardType type = config.type;
    // FIXME: Support Auto determine
    // MNN_FORWARD_AUTO 的处理逻辑
    if (MNN_FORWARD_AUTO == config.type) {
	//Define Auto choose priority
        std::vector<MNNForwardType> priorityList;
        priorityList.push_back(MNN_FORWARD_USER_0); //HIAI
        priorityList.push_back(MNN_FORWARD_NN);     //CoreML
        priorityList.push_back(MNN_FORWARD_USER_1); //TensoRT
        priorityList.push_back(MNN_FORWARD_CUDA);   //CUDA
        priorityList.push_back(MNN_FORWARD_OPENCL); //OpenCL
        priorityList.push_back(MNN_FORWARD_METAL);  //METAL
        priorityList.push_back(MNN_FORWARD_VULKAN); //Vulkan
        priorityList.push_back(MNN_FORWARD_CPU);    //CPU

        for (auto bn : priorityList) {
            if (MNNGetExtraRuntimeCreator(bn) != nullptr) {
                type = (MNNForwardType)bn;
                break;
            }
        }
    }
    auto creator = MNNGetExtraRuntimeCreator(type);
    if (nullptr == creator) {
        MNN_PRINT("Can't Find type=%d backend, use %d instead\n", type, config.backupType);
        type = config.backupType;
    } else {
        // TODO : Not Limited to opencl
        if(type == MNN_FORWARD_OPENCL && config.backendConfig != nullptr) {
            if(config.backendConfig->power == BackendConfig::Power_Low) {
                Backend::Info info;
                info.type = type;
                std::shared_ptr<Runtime> bn(creator->onCreate(info));
                bool isSupportLowPower = bn->onGetRuntimeStatus(RuntimeStatus::STATUS_SUPPORT_POWER_LOW);
                if(!isSupportLowPower) {
                    MNN_PRINT("type=%d backend don't Support Low Power, use %d instead\n", type, config.backupType);
                    type = config.backupType;
                }
            }
        }
    }
    

    return type;
}

1.2.1 MNNGetExtraRuntimeCreator

// source/core/Backend.cpp
const RuntimeCreator* MNNGetExtraRuntimeCreator(MNNForwardType type) {
    registerBackend();

	// 获取运行时创建器
	// (std::map<MNNForwardType, std::pair<const RuntimeCreator*, bool>>类型)
    auto& gExtraCreator = GetExtraCreator();
    // 根据推理类型查找运行时创建器
    auto iter           = gExtraCreator.find(type);
    if (iter == gExtraCreator.end()) {
        return nullptr;
    }
    // iter->second 的类型为 std::pair<const RuntimeCreator* creator, bool needCheck>
    if (!iter->second.second) {
        return iter->second.first;
    }
    Backend::Info info;
    info.type = type;
    std::shared_ptr<Runtime> bn(iter->second.first->onCreate(info));
    if (nullptr != bn.get()) {
        return iter->second.first;
    }
    return nullptr;
}

1.2.1.1 registerBackend

static std::once_flag s_flag;
void registerBackend() {
    std::call_once(s_flag, [&]() {
#ifdef MNN_INTERNAL_ENABLED
        LogInit();
#endif
		// 注册 CPU 的运行时创建器和一些核心函数
        registerCPURuntimeCreator();
#ifndef MNN_BUILD_MINI
        SizeComputerSuite::init();
        // 图像着色器 ?
        GeometryComputer::init();
#endif
#if MNN_COREML_ENABLED
        registerCoreMLRuntimeCreator();
#endif
#ifdef MNN_NNAPI_ENABLED
        registerNNAPIRuntimeCreator();
#endif
#if MNN_OPENCL_ENABLED
        OpenCL::registerOpenCLRuntimeCreator();
#endif
#if MNN_METAL_ENABLED
        registerMetalRuntimeCreator();
#endif
    });
}

1.2.1.2 GetExtraCreator

static std::map<MNNForwardType, std::pair<const RuntimeCreator*, bool>>& GetExtraCreator() {
    static std::once_flag gInitFlag;
    static std::map<MNNForwardType, std::pair<const RuntimeCreator*, bool>>* gExtraCreator;
    std::call_once(gInitFlag,
                   [&]() { gExtraCreator = new std::map<MNNForwardType, std::pair<const RuntimeCreator*, bool>>; });
    return *gExtraCreator;
}

    获取 RuntimeCreator ,然后根据类型创建对应的 Runtime。gExtraCreator 是一个 map 类型,其是通过函数 MNNInsertExtraRuntimeCreator 进行注册的。

// source/core/Backend.cpp
bool MNNInsertExtraRuntimeCreator(MNNForwardType type, const RuntimeCreator* creator, bool needCheck) {
    auto& gExtraCreator = GetExtraCreator();
    if (gExtraCreator.find(type) != gExtraCreator.end()) {
        MNN_ASSERT(false && "duplicate type");
        return false;
    }
    gExtraCreator.insert(std::make_pair(type, std::make_pair(creator, needCheck)));
    return true;
}
  • VULKAN 注册
// source/backend/vulkan/runtime/VulkanRuntime.cpp
static bool gResistor = []() {
    MNNInsertExtraRuntimeCreator(MNN_FORWARD_VULKAN, new VulkanRuntimeCreator, false);
    return false;
}();
  • CUDA 注册
// source/backend/cuda/Register.cpp
static const auto __cuda_global_initializer = []() {
    MNNInsertExtraRuntimeCreator(MNN_FORWARD_CUDA, new CUDARuntimeCreator, false);
    return true;
}();
  • OPENGL 注册
// source/backend/opengl/GLBackend.cpp
bool placeholder = []() {
    static std::once_flag createOnce;
    std::call_once(createOnce, []() {
        MNNInsertExtraRuntimeCreator(MNN_FORWARD_OPENGL, new GLRuntimeCreator, false);
    });
    return true;
}();
  • Metal 注册,在 registerBackend 中主动调用
// source/backend/metal/MetalBackend.mm
void registerMetalRuntimeCreator() {
    // according to
    // https://developer.apple.com/library/archive/documentation/DeviceInformation/Reference/iOSDeviceCompatibility/HardwareGPUInformation/HardwareGPUInformation.html
    // not all device with iOS 8+ supports metal.
    id<MTLDevice> device = MTLCreateSystemDefaultDevice();
    if (nil != device) {
        registerMetalOps();
#ifdef MNN_SUPPORT_RENDER
        registerMetalRenderOps();
#endif
        MNNInsertExtraRuntimeCreator(MNN_FORWARD_METAL, new MetalRuntimeCreator(device), false);
    } else {
        MNN_ERROR("Init Metal Error\n");
    }
}

1.3 RuntimeFactory::create

Runtime* RuntimeFactory::create(const Backend::Info& info) {
    auto creator = MNNGetExtraRuntimeCreator(info.type);
    if (nullptr == creator) {
        MNN_PRINT("Create Runtime Failed because no creator for %d\n", info.type);
        return nullptr;
    }
    // 调用具体 RuntimeCreator,如 VulkanRuntimeCreator,MetalRuntimeCreator,GLRuntimeCreator
    auto runtime = creator->onCreate(info);
    if (nullptr == runtime) {
        MNN_PRINT("Create Runtime failed, the creator return nullptr, type = %d\n", info.type);
    }
    return runtime;
}

1.3.1 VulkanRuntimeCreator

    若 RuntimeFactory::createinfo.typeMNN_FORWARD_VULKAN,则 creator->onCreate(info) 实际调用的是 VulkanRuntimeCreator::onCreate 函数。

// source/backend/vulkan/runtime/VulkanRuntime.cpp
class VulkanRuntimeCreator : public RuntimeCreator {
public:
    virtual Runtime* onCreate(const Backend::Info& info) const {
    	// 初始化 Vulkan 库,获取相应的 API 函数
        if (InitVulkan()) {
            if (_testVulkan()) {
            // 创建 Vulkan 运行时
                return new VulkanRuntime(info);
            }
        }
        return nullptr;
    }
    virtual bool onValid(Backend::Info& info) const {
        return true;
    }
};

static bool gResistor = []() {
    MNNInsertExtraRuntimeCreator(MNN_FORWARD_VULKAN, new VulkanRuntimeCreator, false);
    return false;
}();
}

1.3.2 VulkanRuntimeCreator

    若 RuntimeFactory::createinfo.typeMNN_FORWARD_CPU,则 creator->onCreate(info) 实际调用的是 CPURuntimeCreator ::onCreate 函数。

class CPURuntimeCreator : public RuntimeCreator {
public:
    virtual Runtime* onCreate(const Backend::Info& info) const override {
        return new CPURuntime(info);
    }
};


#ifdef MNN_SUPPORT_BF16
extern void registerBF16Backend();
#endif
#ifdef ENABLE_ARMV82
extern void registerArm82RuntimeCreator();
#endif
void registerCPURuntimeCreator() {
    CPUBackend::initCreatorMap();
    registerCPUOps();
#ifdef MNN_SUPPORT_BF16
    registerBF16Backend();
#endif
#ifdef MNN_USE_ARMV82
    registerArm82RuntimeCreator();
#endif
    // TODO: Merge _initCoreFunction MNNFunctionInit and cpuinfo_arm_init
    MNNCoreFunctionInit();
    MNNInsertExtraRuntimeCreator(MNN_FORWARD_CPU, new CPURuntimeCreator);
};

1.4 ScheduleConfig

// project/android/demo/app/includes/MNN/Interpreter.hpp
/** session schedule config */
struct ScheduleConfig {
    /** which tensor should be kept */
    std::vector<std::string> saveTensors;
    /** forward type */
    MNNForwardType type = MNN_FORWARD_CPU;
    /** number of threads in parallel */
    int numThread = 4;

    /** subpath to run */
    struct Path {
        std::vector<std::string> inputs;
        std::vector<std::string> outputs;

        enum Mode {
            /**
             * Op Mode
             * - inputs means the source op, can NOT be empty.
             * - outputs means the sink op, can be empty.
             * The path will start from source op, then flow when encounter the sink op.
             * The sink op will not be compute in this path.
             */
            Op = 0,

            /**
             * Tensor Mode (NOT supported yet)
             * - inputs means the inputs tensors, can NOT be empty.
             * - outputs means the outputs tensors, can NOT be empty.
             * It will find the pipeline that compute outputs from inputs.
             */
            Tensor = 1
        };

        /** running mode */
        Mode mode = Op;
    };
    Path path;

    /** backup backend used to create execution when desinated backend do NOT support any op */
    MNNForwardType backupType = MNN_FORWARD_CPU;

    /** extra backend config */
    BackendConfig* backendConfig = nullptr;
};

1.5 BackendConfig

// project/android/demo/app/includes/MNN/MNNForwardType.h
struct BackendConfig {
    enum MemoryMode {
        Memory_Normal = 0,
        Memory_High,
        Memory_Low
    };
    
    MemoryMode memory = Memory_Normal;
    
    enum PowerMode {
        Power_Normal = 0,
        Power_High,
        Power_Low
    };
    
    PowerMode power = Power_Normal;
    
    enum PrecisionMode {
        Precision_Normal = 0,
        Precision_High,
        Precision_Low
    };
    
    PrecisionMode precision = Precision_Normal;
    
    /** user defined context */
    void* sharedContext = nullptr;
};

   

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

后端开发要不要转鸿蒙?

看到一条很有意思的提问&#xff0c;互联网太卷了&#xff0c;熬过了2023才发现&#xff0c;2024更难熬&#xff01;只因行业发展多年&#xff0c;人才过度饱和&#xff01;那后端的出路在哪里&#xff1f; 我推荐大家学【鸿蒙应用开发】新兴行业需求大&#xff0c;各大厂都在…

AI大模型智能大气科学探索之:ChatGPT在大气科学领域建模、数据分析、可视化与资源评估中的高效应用及论文写作

本文深度探讨人工智能在大气科学中的应用&#xff0c;特别是如何结合最新AI模型与Python技术处理和分析气候数据。课程介绍包括GPT-4等先进AI工具&#xff0c;旨在帮助大家掌握这些工具的功能及应用范围。本文内容覆盖使用GPT处理数据、生成论文摘要、文献综述、技术方法分析等…

camunda流程引擎事务管理和乐观锁

本文重点介绍camunda开源流程引擎的事务配置&#xff0c;以及在高并发多线程情况下&#xff0c;可能会发生多个线程尝试对相同流程实例数据进行更改的情况&#xff0c;Camunda如何通过数据库的乐观锁解决这种并发冲突的&#xff0c;并介绍了乐观锁和悲观锁的适用场景、性能影响…

MySQL数据库概念及安装

一、数据库的基本概率 1.1 数据 记录每个人的信息 或者记录数据 1.2 表 存放信息的集合 或者存放行和列的信息 1.3 数据库 表的集合 二、数据库管理系统&#xff08;DBMS&#xff09; 2.1 DBMS定义 &#xff08;DBMS&#xff09;是一种软件&#xff0c;用于创建和管理…

【Python脚本随手笔记】 --- 复制文件并修改权限

&#x1f48c; 所属专栏&#xff1a;【Python脚本随手笔记】 &#x1f600; 作  者&#xff1a;我是夜阑的狗&#x1f436; &#x1f680; 个人简介&#xff1a;一个正在努力学技术的CV工程师&#xff0c;专注基础和实战分享 &#xff0c;欢迎咨询&#xff01; &#…

HarmonyOS 通知意图

之前的文章 我们讲了 harmonyos 中的 基础和进度条通知 那么 今天 我们来说说 任何给通知添加意图 通知意图 简单说 就是 当我们点击某个通知 如下图 然后 就会拉起某个 应用 就例如说 我们某个微信好友发消息给我们 我们 点击系统通知 可以直接跳到你们的聊天界面 好 回到…

Vue+SpringBoot打造民宿预定管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 用例设计2.2 功能设计2.2.1 租客角色2.2.2 房主角色2.2.3 系统管理员角色 三、系统展示四、核心代码4.1 查询民宿4.2 新增民宿4.3 新增民宿评价4.4 查询留言4.5 新增民宿订单 五、免责说明 一、摘要 1.1 项目介绍 基于…

VsCode中高效书写Vue3代码的插件

Vue-Official&#xff08;原Volar&#xff09; 就是原先的Volar&#xff0c;现已弃用。 Vue-Official 提供的功能&#xff1a; 语法高亮: Vue-Official 扩展可以为 Vue 单文件组件&#xff08;.vue 文件&#xff09;中的 HTML、CSS 和 JavaScript 部分提供语法高亮&#xff…

linux系统------------Mysql数据库

目录 一、数据库基本概念 1.1数据(Data) 1.2表 1.3数据库 1.4数据库管理系统(DBMS) 数据库管理系统DBMS原理 1.5数据库系统&#xff08;DBS) 二、数据库发展史 1、第一代数据库 2、第二代数据库 3、第三代数据库 三、关系型数据库 3.1关系型数据库应用 3.2主流的…

Echo服务器学习__01(基础)

ASIO是一个跨平台&#xff0c;主要用于实现异步网络和其他一些底层I/O操作的C库 可以基于ASIO实现Echo服务端&#xff0c;在这之前&#xff0c;学习一些基础的知识和概念 ​ 1&#xff1a;IO多路复用 简单的来说&#xff0c;一个线程同时监听多个I/O事件就是I/O多路复用。任…

⭐北邮复试刷题1793. 好子数组的最大分数___(基于快排的划分思想/基于快排的划分思想的优化过程/基于贪心的双指针操作)__每日一题

Problem: 1793. 好子数组的最大分数 文章目录 思路Code: 思路 法一: 基于快排的划分思想 1.即开始为拿到数组全部 计算分数 后来对每次找到的min值的下标左右两侧进行划分 即将min去掉 从而可以构建出两个新数组; 2.对新数组继续计算分数 与前一次比较取最大 接着继续找到min值…

51、CR-GCN:EEG通道拓扑结构+脑功能连接捕获EEG通道关系,用于情感识别[我处理的是原始EEG数据哦]

文章&#xff1a; CR-GCN: Channel-Relationships-Based Graph Convolutional Network for EEG Emotion Recognition 单位&#xff1a; 上海大学计算机学院、上海工业计算机、喀什大学计算机学院。提出CR-GCN&#xff0c;使用GCN的邻接矩阵提取情感数据中的特征用于分类。 2…

云计算太卷了,腾讯云服务器一年61元起,2核2G3M配置

腾讯云服务器多少钱一年&#xff1f;61元一年起。2024年最新腾讯云服务器优惠价格表&#xff0c;腾讯云轻量2核2G3M服务器61元一年、2核2G4M服务器99元一年可买三年、2核4G5M服务器165元一年、3年756元、轻量4核8M12M服务器646元15个月、4核16G10M配置32元1个月、312元一年、8核…

Flutter开发入门——路由

什么是路由&#xff1f; 移动端应用开发中&#xff0c;路由技术是一个非常重要的组成部分。路由技术负责管理应用中各个页面之间的跳转、导航以及参数传递等关键功能。在移动端应用中&#xff0c;一个高效、易于维护的路由系统对于提高开发效率和用户体验具有重要意义。 Flut…

AndroidLinux GPIO控制方法

目录 1 GPIO整体架构 2 user space 层 gpio使用方法 2.1 sysfs控制方法 2.1.1 kernel版本区别 2.1.2 /sys/class/gpio 2.1.3 /sys/bug/gpio/devices 2.2 chardev控制方法 2.2.1 chardev 示例代码 2.2.2 示例代码主要步骤描述 2.2.3 include/linux/gpio.h 全部代码 2.3…

代码随想录算法训练营第四十三天|卡码网52. 携带研究材料(第七期模拟笔试)、518. 零钱兑换 II、377. 组合总和 Ⅳ

卡码网52. 携带研究材料&#xff08;第七期模拟笔试&#xff09; 刷题https://kamacoder.com/problempage.php?pid1052文章讲解https://programmercarl.com/%E8%83%8C%E5%8C%85%E9%97%AE%E9%A2%98%E7%90%86%E8%AE%BA%E5%9F%BA%E7%A1%80%E5%AE%8C%E5%85%A8%E8%83%8C%E5%8C%85.…

STM32通信协议

STM32通信协议 STM32通信协议 STM32通信协议一、通信相关概念二、通信协议引脚作用三、通信方式四、采样方式五、电平信号六、通信对象 一、通信相关概念 通信接口 通信的目的&#xff1a;将一个设备的数据传送到另一个设备&#xff0c;扩展硬件系统 通信协议&#xff1a;制定…

sqlserver字段2按字段1分组后;合并字段2

效果 相同dzbm的mc通过‘;’合并 sqlserver语句 按字段dzbm分组,有相同dzbm的mc通过 ;合并成一个字段,其它字段都选择第一个 SELECT dzbm, STUFF((SELECT DISTINCT ; + mc FROM tablenameWHERE dzbm = p.dzbm FOR XML PATH()), 1

Json Web Token(JWT) 快速入门

推荐视频&#xff1a;【从零开始掌握JWT】 目录 第一章 会话跟踪 01 使用Cookie和Session&#xff0c;jsessionid 02 使用token 例子一&#xff1a;自定义token 例子二&#xff1a;使用redis存储token 第一章 会话跟踪 应用背景 &#xff1a;浏览器访问web应用&#xff…

Linux工具 - 强大的vim编辑器

~~~~ 前言vim是什么为什么有vimvim怎么用vim模式介绍模式切换命令模式(Normal mode)i/a/o 切换到插入模式: 切换到底行模式R 切换到替换模式光标移动删除文字复制撤销更改 插入模式(Insert mode)底行模式(last line mode)&#xff08;需整理20240311&#xff09;替换模式vim简单…