DeepLabV3.cpp 12.8 KB
Newer Older
shangxl's avatar
shangxl committed
1
2
3
4
#include <DeepLabV3.h>

#include <migraphx/onnx.hpp>
#include <migraphx/gpu/target.hpp>
5
6
#include <migraphx/quantization.hpp>
#include <hip/hip_runtime_api.h>
shangxl's avatar
shangxl committed
7
8
9
10
#include <Filesystem.h>
#include <SimpleLog.h>
#include <algorithm>

11
namespace migraphxSamples{
shangxl's avatar
shangxl 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
61
62

static std::vector<float> softmax(vector<float> v){

    std::vector<float> probs(v.size());
    float max_val = *std::max_element(v.begin(),v.end());
    float sum_exp = 0.0f;
    for (int i = 0; i < v.size(); ++i) {
        probs[i] = std::exp(v[i] - max_val);
        sum_exp += probs[i];
    }
    for (int i = 0; i < v.size(); ++i) {
       probs[i] /= sum_exp;
    }

    return probs;
}

// 定义21个类别的颜色映射表(BGR格式)
std::vector<cv::Scalar> create_color_map() {
    return {
        cv::Scalar(0, 0, 0),       // 0: 黑色(背景)
        cv::Scalar(255, 0, 0),     // 1: 蓝色
        cv::Scalar(0, 255, 0),     // 2: 绿色
        cv::Scalar(0, 0, 255),     // 3: 红色
        cv::Scalar(255, 255, 0),   // 4: 青色
        cv::Scalar(255, 0, 255),   // 5: 品红
        cv::Scalar(0, 255, 255),   // 6: 黄色
        cv::Scalar(128, 0, 0),     // 7: 深蓝
        cv::Scalar(0, 128, 0),     // 8: 深绿
        cv::Scalar(0, 0, 128),     // 9: 深红
        cv::Scalar(128, 128, 0),   // 10: 深青
        cv::Scalar(128, 0, 128),   // 11: 深品红
        cv::Scalar(0, 128, 128),   // 12: 深黄
        cv::Scalar(192, 192, 192), // 13: 灰色
        cv::Scalar(128, 128, 128), // 14: 深灰
        cv::Scalar(64, 0, 0),      // 15: 暗蓝
        cv::Scalar(0, 64, 0),      // 16: 暗绿
        cv::Scalar(0, 0, 64),      // 17: 暗红
        cv::Scalar(64, 64, 0),     // 18: 暗青
        cv::Scalar(64, 0, 64),     // 19: 暗品红
        cv::Scalar(0, 64, 64)      // 20: 暗黄
    };
}



DeepLabV3::DeepLabV3() {}

DeepLabV3::~DeepLabV3() { configurationFile.release(); }


63
64
ErrorCode DeepLabV3::Initialize(InitializationParameterOfSegmentation initParamOfSegmentationUnet){

shangxl's avatar
shangxl committed
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
    // 读取配置文件
    std::string configFilePath = initParamOfSegmentationUnet.configFilePath;
    if(!Exists(configFilePath))
    {
        LOG_ERROR(stdout, "no configuration file!\n");
        return CONFIG_FILE_NOT_EXIST;
    }
    if(!configurationFile.open(configFilePath, cv::FileStorage::READ))
    {
        LOG_ERROR(stdout, "fail to open configuration file\n");
        return FAIL_TO_OPEN_CONFIG_FILE;
    }
    LOG_INFO(stdout, "succeed to open configuration file\n");

    // 获取配置文件参数
    cv::FileNode netNode  = configurationFile["DeepLabV3"];
    std::string modelPath = (std::string)netNode["ModelPath"];
82
83
84
    useInt8               = (bool)(int)netNode["UseInt8"];
    useFP16               = (bool)(int)netNode["UseFP16"];
    useOffloadCopy        = (bool)(int)netNode["UseOffloadCopy"];
shangxl's avatar
shangxl committed
85
86
87
88
89
90
91

    // 加载模型
    if(!Exists(modelPath))
    {
        LOG_ERROR(stdout, "%s not exist!\n", modelPath.c_str());
        return MODEL_NOT_EXIST;
    }
92
93
94
95
96
97
98
99

    migraphx::onnx_options onnx_options;
    if(initParamOfSegmentationUnet.loadMode){
        onnx_options.map_input_dims["input"] = {1, 3, 513, 513};
    }else{
        onnx_options.map_input_dims["input"] = {3, 3, 513, 513};
    }
    net = migraphx::parse_onnx(modelPath,onnx_options);
shangxl's avatar
shangxl committed
100
101
102
103
104
105
106
    LOG_INFO(stdout, "succeed to load model: %s\n", GetFileName(modelPath).c_str());

    // 获取模型输入/输出节点信息
    std::unordered_map<std::string, migraphx::shape> inputs  = net.get_inputs();
    std::unordered_map<std::string, migraphx::shape> outputs = net.get_outputs();
    inputName = inputs.begin()->first;
    inputShape = inputs.begin()->second;
107
108
109
110
111
112
113
114
    outputName                                               = outputs.begin()->first;
    outputShape                                              = outputs.begin()->second;
    auto it = outputs.begin();
    ++it;
    outputName2                                              = it->first;
    outputShape2                                             = it->second;


shangxl's avatar
shangxl committed
115
116
117
118
119
120
    int N = inputShape.lens()[0];
    int C = inputShape.lens()[1];
    int H = inputShape.lens()[2];
    int W = inputShape.lens()[3];
    inputSize = cv::Size(W, H);

121
 
shangxl's avatar
shangxl committed
122
123
124
    // 设置模型为GPU模式
    migraphx::target gpuTarget = migraphx::gpu::target{};

125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
    if(useInt8){
        std::vector<cv::Mat> calibrateImages;
        std::string folderPath = "../Resource/Images/calibrateImages/";
        std::string calibrateImageExt = "*.jpg";
        std::vector<cv::String> calibrateImagePaths;
        cv::glob(folderPath + calibrateImageExt, calibrateImagePaths, false);
        for(const auto& path : calibrateImagePaths){
            calibrateImages.push_back(cv::imread(path, 1));
        }
        cv::Mat inputcalibrateBlob;
        cv::dnn::blobFromImages(calibrateImages, inputcalibrateBlob, 1 / 255.0, inputSize, cv::Scalar(0, 0, 0), true, false);
        std::unordered_map<std::string, migraphx::argument> inputData;
        inputData[inputName] = migraphx::argument{inputShape, (float *)inputcalibrateBlob.data};
        std::vector<std::unordered_map<std::string, migraphx::argument>> calibrationData = {inputData};
         // INT8量化
        migraphx::quantize_int8(net, gpuTarget, calibrationData);
    }else{
        migraphx::quantize_fp16(net);
    }

shangxl's avatar
shangxl committed
145
146
147
    // 编译模型
    migraphx::compile_options options;
    options.device_id    = 0; // 设置GPU设备,默认为0号设备
148
149
150
151
152
153
    if(useOffloadCopy){
        options.offload_copy = true;
    }else{
        options.offload_copy = false;
    }

shangxl's avatar
shangxl committed
154
155
    net.compile(gpuTarget, options);
    LOG_INFO(stdout, "succeed to compile model: %s\n", GetFileName(modelPath).c_str());
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
    if(!useOffloadCopy){
        inputBufferDevice = nullptr;
        hipMalloc(&inputBufferDevice, inputShape.bytes());
        modalDataMap[inputName] = migraphx::argument{inputShape, inputBufferDevice};                   
    
        outputBufferDevice = nullptr;
        hipMalloc(&outputBufferDevice, outputShape.bytes());
        outputBufferDevice2 = nullptr;
        hipMalloc(&outputBufferDevice2, outputShape2.bytes());
        modalDataMap[outputName] = migraphx::argument{outputShape, outputBufferDevice};
        modalDataMap[outputName2] = migraphx::argument{outputShape2, outputBufferDevice2};
        outputBufferHost             = nullptr; // host内存
        outputBufferHost             = malloc(outputShape.bytes());
        outputBufferHost2            = nullptr; // host内存
        outputBufferHost2            = malloc(outputShape2.bytes());
    }
shangxl's avatar
shangxl committed
172
    // warm up
173
174
175
176
177
178
179
180
181
    if(useOffloadCopy){
        std::unordered_map<std::string, migraphx::argument> inputData;                                   
        inputData[inputName] = migraphx::argument{inputShape};                                           
        net.eval(inputData);
    }else{
        migraphx::argument inputData = migraphx::argument{inputShape};                                  //创建数据
        hipMemcpy(inputBufferDevice, inputData.data(), inputShape.bytes(), hipMemcpyHostToDevice);      //将数据复制到device上
        net.eval(modalDataMap);
    }
shangxl's avatar
shangxl committed
182
183
184
185

    // log输出日志信息
    LOG_INFO(stdout, "InputSize:%dx%d\n", inputSize.width, inputSize.height);
    LOG_INFO(stdout, "InputName:%s\n", inputName.c_str());
186
187
188
189
    LOG_INFO(stdout, "UseInt8:%d\n", (int)useInt8);
    LOG_INFO(stdout, "UseFP16:%d\n", (int)useFP16);
    LOG_INFO(stdout, "useOffloadCopy:%d\n", (int)useOffloadCopy);

shangxl's avatar
shangxl committed
190
191
192
193
194

    return SUCCESS;
}


195
196
197
ErrorCode DeepLabV3::Segmentation(std::vector<cv::Mat> srcImages, std::vector<cv::Mat> & maskImages){

    if(srcImages.size()==0 || srcImages[0].empty() || srcImages[0].type() != CV_8UC3)
shangxl's avatar
shangxl committed
198
199
200
201
202
203
    {
        LOG_ERROR(stdout, "image error!\n");
        return IMAGE_ERROR;
    }

    // 数据预处理并转换为NCHW格式
204
205
    cv::Mat inputBatchBlob;
    cv::dnn::blobFromImages(srcImages, inputBatchBlob, 1 / 255.0, inputSize, cv::Scalar(0, 0, 0), true, false);
shangxl's avatar
shangxl committed
206

207
208
    // 创建颜色映射表
    std::vector<cv::Scalar> color_map = create_color_map();
shangxl's avatar
shangxl committed
209

210
211
212
213
    if(useOffloadCopy){
        // 创建输入数据
        std::unordered_map<std::string, migraphx::argument> inputData;
        inputData[inputName] = migraphx::argument{inputShape, (float*)inputBatchBlob.data};
shangxl's avatar
shangxl committed
214

215
216
        // 推理
        std::vector<migraphx::argument> results = net.eval(inputData);
shangxl's avatar
shangxl committed
217
        
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
        // 获取输出节点的属性
        migraphx::argument result   = results[0];                 // 获取第一个输出节点的数据
        migraphx::shape outputShape = result.get_shape();         // 输出节点的shape
        std::vector<std::size_t> outputSize = outputShape.lens(); // 每一维大小,维度顺序为(N,C,H,W)

        int numberOfOutput = outputShape.elements();              // 输出节点元素的个数
        float* data        = (float*)result.data();               // 输出节点数据指针

        int N = outputShape.lens()[0];
        int C = outputShape.lens()[1];
        int H = outputShape.lens()[2];
        int W = outputShape.lens()[3];

        for(int m = 0;m < N;m++){
            cv::Mat outputImage(cv::Size(W, H), CV_8UC3);
            for(int i = 0;i < H; i++){
                for(int j = 0;j < W;j++){
                    std::vector<float> channel_value;
                    for(int k = 0;k < C;k++){
                        channel_value.push_back(data[m*C*H*W+k*(H*W)+i*W+j]);
                    }
                    std::vector<float> probs = softmax(channel_value);
                    // 找到概率最高的类别索引
                    int max_index = std::max_element(probs.begin(),probs.end())-probs.begin();
                    cv::Scalar sc = color_map[max_index];
                    outputImage.at<cv::Vec3b>(i, j)[0]= sc.val[0]; 
                    outputImage.at<cv::Vec3b>(i, j)[1]= sc.val[1];
                    outputImage.at<cv::Vec3b>(i, j)[2]= sc.val[2];
                }
            }
            maskImages.push_back(outputImage);
        }
shangxl's avatar
shangxl committed
250
        
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
    }else{

        migraphx::argument inputData = migraphx::argument{inputShape, (float*)inputBatchBlob.data};
        // 拷贝到device输入内存
        hipMemcpy(inputBufferDevice, inputData.data(), inputShape.bytes(), hipMemcpyHostToDevice);
        // 推理
        std::vector<migraphx::argument> results = net.eval(modalDataMap);

        // 获取输出节点的属性
        migraphx::argument result    = results[0];                                      // 获取第一个输出节点的数据
        migraphx::shape outputShapes = result.get_shape();                              // 输出节点的shape
        std::vector<std::size_t> outputSize = outputShapes.lens();                      // 每一维大小,维度顺序为(N,C,H,W)
        int numberOfOutput = outputShapes.elements();                                   // 输出节点元素的个数
        // 将device输出数据拷贝到分配好的host输出内存
        hipMemcpy(outputBufferHost,outputBufferDevice, outputShapes.bytes(),hipMemcpyDeviceToHost); // 直接使用事先分配好的输出内存拷贝
        int N = outputSize[0];
        int C = outputSize[1];
        int H = outputSize[2];
        int W = outputSize[3];
       


        // 获取输出节点的属性
        migraphx::argument result2    = results[1];                                         // 获取第2个输出节点的数据
        migraphx::shape outputShapes2 = result2.get_shape();                                // 输出节点的shape
        std::vector<std::size_t> outputSize2 = outputShapes2.lens();                        // 每一维大小,维度顺序为(N,C,H,W)
         // 将device输出数据拷贝到分配好的host输出内存
        hipMemcpy(outputBufferHost2,outputBufferDevice2, outputShapes2.bytes(),hipMemcpyDeviceToHost); // 直接使用事先分配好的输出内存拷贝
        for(int m = 0;m < N;m++){
            cv::Mat outputImage(cv::Size(W, H), CV_8UC3);
            for(int i = 0;i < H; i++){
                for(int j = 0;j < W;j++){
                    std::vector<float> channel_value;
                    for(int k = 0;k < C;k++){
                        channel_value.push_back(((float *)outputBufferDevice2)[m*C*H*W+k*(H*W)+i*W+j]);
                    }
                    std::vector<float> probs = softmax(channel_value);
                    // 找到概率最高的类别索引
                    int max_index = std::max_element(probs.begin(),probs.end())-probs.begin();
                    cv::Scalar sc = color_map[max_index];
                    outputImage.at<cv::Vec3b>(i, j)[0]= sc.val[0]; 
                    outputImage.at<cv::Vec3b>(i, j)[1]= sc.val[1];
                    outputImage.at<cv::Vec3b>(i, j)[2]= sc.val[2];
                }
shangxl's avatar
shangxl committed
295
            }
296
            maskImages.push_back(outputImage);
shangxl's avatar
shangxl committed
297
        }
298
299
300
301
302
303
304
        // 释放
        hipFree(inputBufferDevice);
        hipFree(outputBufferDevice);
        hipFree(outputBufferDevice2);
        free(outputBufferHost);
        free(outputBufferHost2);
    }    
shangxl's avatar
shangxl committed
305
306
307
308
309

    return SUCCESS;
}

}