MNN createRuntime(二)

本文详细介绍了MNN框架中的关键组件,如如何使用RuntimeInfo创建运行时,Schedule的自动选择机制,以及不同后端如Vulkan和CPU的RuntimeCreator。还涵盖了ScheduleConfig和BackendConfig的结构和用途。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在这里插入图片描述

系列文章目录


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



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;
}();
// 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;
};

   

### MNN框架概述 MNN(Mobile Neural Network)是一款阿里巴巴推出的轻量级深度学习端侧推理引擎[^2]。其设计目标是解决深度神经网络模型在移动端和其他资源受限设备上的高效运行问题。它不仅能够完成模型的优化和转换,还提供了强大的推理能力以及训练支持。 #### 核心特性 - **轻量性**:MNN文件大小通常仅为几兆字节,便于部署于移动设备和嵌入式硬件上[^3]。 - **通用性**:支持TensorFlow、Caffe、ONNX等多种主流模型格式,并兼容CNN、RNN、GAN等常见网络结构。 - **高效性**:通过高度优化的手写汇编代码实现核心运算,显著提升了执行效率。 - **易用性**:提供丰富的API接口,包括图像处理模块和支持回调机制的功能,允许开发者灵活定制逻辑流程。 --- ### 主要组件及其功能 以下是MNN的主要组成部分及各自的作用: 1. **MNN-Converter** - 这是一个用于将不同框架下的模型转化为MNN格式的工具[^1]。 它分为两部分: - Frontends:适配多种前端框架(如TensorFlow Lite、Caffe、PyTorch via ONNX),使得这些框架导出的模型可以直接被MNN加载并使用。 - Graph Optimize:通过对计算图进行算子融合、替换操作以及布局调整来进一步提高性能表现。 2. **MNN-Compress** - 提供了一套针对MNN模型的压缩方案,在保持一定精度损失的前提下减小存储空间占用率的同时加快预测速度。 3. **MNN-Express** - 支持带有复杂控制流(Control Flow)的动态图模型运行,并允许用户借助内置算子构建自定义层或节点。 4. **MNN-CV** - 类似OpenCV的一个计算机视觉库,不过它的底层依赖完全基于MNN重写而成,从而实现了更紧密集成的效果。 5. **MNN-Train** - 集成了完整的训练流水线,让使用者能够在任意平台上无缝切换至生产环境中实际使用的相同架构上去调试参数配置等问题。 --- ### 如何快速入门? 为了帮助初学者更快地上手该技术栈,官方给出了详细的教程说明如何搭建开发环境以及跑通首个实例程序——人体姿态估计Demo。具体步骤如下所示: 1. 下载源码包后解压放置合适位置; 2. 确保已安装好Protobuf v3.x及以上版本作为序列化协议的支持基础; 3. 执行命令进入工作目录`cd mnn && cd schema && ./generate.sh`生成描述文件; 4. 创建临时构建区`mkdir build && cd build`接着调用CMake工具指定选项开关开启样例工程编译模式`cmake -DMNN_BUILD_DEMO=ON ..`; 5. 启动多核并发制造过程加速产出最终产物`make -j8`. 上述完成后即可获得可供测试用途的应用进制文件! --- ### 示例代码展示 下面给出一段简单的Python脚本演示怎样加载预训练好的MNN权重文件并对输入图片做前向传播得到分类结果: ```python from MNN import Interpreter, Session def inference_mnn_model(mnn_path, input_data): interpreter = Interpreter(mnn_path) # 初始化解释器对象读取模型元信息 session = interpreter.createSession() # 构造会话句柄分配GPU/CPU资源 input_tensor = interpreter.getSessionInput(session) # 获取默认输入张量指针 tmp_input = input_tensor.host() for i in range(len(input_data)): tmp_input[i] = float(input_data[i]) / 255.0 # 归一化像素值范围 interpreter.runSession(session) # 开始正式推断环节 output_tensor = interpreter.getSessionOutput(session) # 抓取出最后输出特征映射表单 result = list(output_tensor.host())[:len(output_tensor)] return result.index(max(result)) # 返回最大概率对应的类别索引号 if __name__ == "__main__": model_file = "./example.mnn" test_image = [value for row in [[col for col in line.strip().split()] for line in open("./test.txt").readlines()] for value in map(int,row)] # 假设这里是从文本记录还原原始RGB数组形式的数据集样本之一 predicted_label = inference_mnn_model(model_file,test_image) print(f"The image is classified as class {predicted_label}.") ``` 此片段假设存在一个名为`./example.mnn`的目标识别系统保存下来的静态图表示法档案还有配套的一幅待测验的小尺寸灰阶照片存放在纯ASCII编码字符串里边等待解析成整数列表传进去函数内部参与后续处理动作链路当中去。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值