141 lines
4.0 KiB
Markdown
141 lines
4.0 KiB
Markdown
# C++ 快速开始
|
||
|
||
本教程带你从源码编译到 C++ 推理,完成一个端到端的图像分类任务。
|
||
|
||
## 1. 编译 MNN
|
||
|
||
```bash
|
||
cd MNN
|
||
mkdir build && cd build
|
||
cmake .. -DMNN_BUILD_CONVERTER=ON
|
||
make -j8
|
||
```
|
||
|
||
> 更多平台(iOS/Android/Windows)编译方式请参考 [从源码构建](../compile/engine.md)。
|
||
|
||
## 2. 转换模型
|
||
|
||
```bash
|
||
./MNNConvert -f ONNX --modelFile mobilenet_v1.onnx --MNNModel mobilenet_v1.mnn --weightQuantBits 8
|
||
```
|
||
|
||
## 3. 编写推理代码
|
||
|
||
使用推荐的 **Module API** 进行推理(参考 `demo/exec/pictureRecognition_module.cpp`):
|
||
|
||
```cpp
|
||
#include <stdio.h>
|
||
#include <MNN/expr/Module.hpp>
|
||
#include <MNN/expr/Executor.hpp>
|
||
#include <MNN/expr/ExprCreator.hpp>
|
||
#include <MNN/ImageProcess.hpp>
|
||
|
||
using namespace MNN;
|
||
using namespace MNN::Express;
|
||
|
||
int main(int argc, const char* argv[]) {
|
||
if (argc < 3) {
|
||
printf("Usage: ./classify model.mnn input.jpg\n");
|
||
return 1;
|
||
}
|
||
|
||
// 1. 创建 RuntimeManager 配置后端
|
||
ScheduleConfig sConfig;
|
||
sConfig.type = MNN_FORWARD_CPU;
|
||
sConfig.numThread = 4;
|
||
auto rtmgr = std::shared_ptr<Executor::RuntimeManager>(
|
||
Executor::RuntimeManager::createRuntimeManager(sConfig));
|
||
|
||
// 2. 加载模型(空 vector 表示自动检测输入输出名)
|
||
std::shared_ptr<Module> net(
|
||
Module::load({}, {}, argv[1], rtmgr));
|
||
if (!net) {
|
||
printf("Failed to load model\n");
|
||
return 1;
|
||
}
|
||
|
||
// 3. 创建输入 (NC4HW4 是 MNN 内部优化格式)
|
||
int width = 224, height = 224;
|
||
auto input = _Input({1, 3, height, width}, NC4HW4);
|
||
|
||
// 4. 图像预处理(使用 MNN ImageProcess)
|
||
// 实际项目中用 stb_image/opencv 读图后用 ImageProcess 转换
|
||
// 此处简化为填充测试数据
|
||
auto inputPtr = input->writeMap<float>();
|
||
// ... 填充预处理后的图像数据到 inputPtr ...
|
||
input->unMap();
|
||
|
||
// 5. 推理
|
||
auto outputs = net->onForward({input});
|
||
|
||
// 6. 读取输出
|
||
auto output = _Convert(outputs[0], NHWC);
|
||
output = _Reshape(output, {0, -1});
|
||
auto outputPtr = output->readMap<float>();
|
||
// 找到概率最大的类别
|
||
int classId = 0;
|
||
float maxVal = outputPtr[0];
|
||
int outputSize = output->getInfo()->size;
|
||
for (int i = 1; i < outputSize; i++) {
|
||
if (outputPtr[i] > maxVal) {
|
||
maxVal = outputPtr[i];
|
||
classId = i;
|
||
}
|
||
}
|
||
printf("预测类别编号: %d, 置信度: %f\n", classId, maxVal);
|
||
return 0;
|
||
}
|
||
```
|
||
|
||
## 4. 编译并运行
|
||
|
||
在 MNN build 目录下:
|
||
```bash
|
||
g++ -std=c++11 -o classify classify.cpp \
|
||
-I ../include \
|
||
-L . -lMNN -lMNN_Express
|
||
|
||
./classify mobilenet_v1.mnn test.jpg
|
||
```
|
||
|
||
## 5. 完整的图像处理示例
|
||
|
||
实际项目中使用 `ImageProcess` 完成图像解码和预处理,参考 `demo/exec/pictureRecognition_module.cpp`,核心流程:
|
||
|
||
```cpp
|
||
#include <MNN/ImageProcess.hpp>
|
||
|
||
// 配置预处理参数
|
||
MNN::CV::ImageProcess::Config imgConfig;
|
||
imgConfig.filterType = MNN::CV::BILINEAR;
|
||
imgConfig.sourceFormat = MNN::CV::RGBA;
|
||
imgConfig.destFormat = MNN::CV::RGB;
|
||
imgConfig.mean[0] = 103.94f;
|
||
imgConfig.mean[1] = 116.78f;
|
||
imgConfig.mean[2] = 123.68f;
|
||
imgConfig.normal[0] = 0.017f;
|
||
imgConfig.normal[1] = 0.017f;
|
||
imgConfig.normal[2] = 0.017f;
|
||
|
||
auto pretreat = std::shared_ptr<MNN::CV::ImageProcess>(
|
||
MNN::CV::ImageProcess::create(imgConfig));
|
||
|
||
// 设置缩放矩阵
|
||
MNN::CV::Matrix trans;
|
||
trans.setScale((float)(inputWidth - 1) / (width - 1),
|
||
(float)(inputHeight - 1) / (height - 1));
|
||
pretreat->setMatrix(trans);
|
||
|
||
// 转换图像数据到 input VARP
|
||
pretreat->convert(imageData, inputWidth, inputHeight, 0,
|
||
input->writeMap<float>(), width, height, 4, 0,
|
||
halide_type_of<float>());
|
||
```
|
||
|
||
## 下一步
|
||
|
||
- [Module API 详解](../inference/module.md) — 完整的 C++ 推理接口说明
|
||
- [LLM 部署指南](../transformers/llm.md) — 部署大语言模型
|
||
- [模型压缩](../tools/compress.md) — 权值量化、离线量化等
|
||
- [Session API](../inference/session.md) — 低层推理接口(特殊场景使用)
|