Tutorial_Cpp.md 2.91 KB
Newer Older
liucong's avatar
liucong committed
1
2
3
4
5
6
7
8
9
10
# 分类器



本示例通过ResNet50模型说明如何使用MIGraphX C++ API进行分类模型的推理,包括如何预处理、推理并获取推理结果。



## 模型简介

liucong's avatar
liucong committed
11
本示例使用了经典的ResNet50模型,onnx文件在Resource/Models/文件夹下,模型结构可以通过netron (https://netron.app/) 查看,该模型的输入shape为[1,3,224,224] ,数据排布为NCHW。
liucong's avatar
liucong committed
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60



## 预处理

在将数据输入到模型之前,需要对图像做如下预处理操作:

- resize到224x224
- 将像素值归一化到[0.0, 1.0]
- 转换数据排布为NCHW



本示例代码采用了OpenCV的cv::dnn::blobFromImages()函数实现了预处理操作:

```c++
ErrorCode Classifier::Classify(const std::vector<cv::Mat> &srcImages,std::vector<std::vector<ResultOfPrediction>> &predictions)
{
	...
	
    // 预处理
    cv::Mat inputBlob;
    cv::dnn::blobFromImages(srcImages, // 输入数据,支持多张图像
                    inputBlob,   // 输出数据
                    scale,       // 缩放系数,这里为1/255.0
                    inputSize,   // 模型输入大小,这里为28x28
                    meanValue,   // 均值,这里不需要减均值,所以设置为0.0
                    swapRB,      // 多通道图像,这里设置为1
                    false);
                    
     ...
}
```

cv::dnn::blobFromImages()函数支持多个输入图像,首先将输入图像resize到inputSize,然后减去均值meanValue,最后乘以scale并转换为NCHW,最终将转换好的数据保存到inputBlob中,然后就可以输入到模型中执行推理了。



## 推理

完成预处理后,就可以执行推理了:

```c++
ErrorCode Classifier::Classify(const std::vector<cv::Mat> &srcImages,std::vector<std::vector<ResultOfPrediction>> &predictions)
{
	...
	
	// 预处理
	
liucong's avatar
liucong committed
61
	// 创建输入数据
liucong's avatar
liucong committed
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
    std::unordered_map<std::string, migraphx::argument> inputData;
    inputData[inputName]= migraphx::argument{inputShape, (float*)inputBlob.data};

    // 推理
    std::vector<migraphx::argument> results = net.eval(inputData);

    // 获取输出节点的属性
    migraphx::argument result  = results[0]; // 获取第一个输出节点的数据
   	
   	...
   	
}
```

- inputData表示MIGraphX的输入数据,inputData是一个映射关系,每个输入节点名都会对应一个输入数据,如果有多个输入,则需要为每个输入节点名创建数据,inputName表示输入节点名,migraphx::argument{inputShape, (float*)inputBlob.data}表示该节点名对应的数据,这里是通过前面预处理的数据inputBlob来创建的,第一个参数表示数据的shape,第二个参数表示数据指针。
- net.eval(inputData)返回模型的推理结果,由于这里只有一个输出节点,所以std::vector中只有一个数据,results[0]表示第一个输出节点,这里对应resnetv24_dense0_fwd节点,获取输出数据。