Commit a27c38fe authored by liucong's avatar liucong
Browse files

加入offload为false的工程示例

parent c1f9a061
...@@ -86,6 +86,7 @@ blobFromImagesWithParams()函数支持多个输入图像,首先对输入图像 ...@@ -86,6 +86,7 @@ blobFromImagesWithParams()函数支持多个输入图像,首先对输入图像
... ...
<UseInt8>0</UseInt8> // 设置为1时,开启INT8量化 <UseInt8>0</UseInt8> // 设置为1时,开启INT8量化
<UseFP16>0</UseFP16> // 设置为1时,开启FP16量化 <UseFP16>0</UseFP16> // 设置为1时,开启FP16量化
...
</Classifier> </Classifier>
</opencv_storage> </opencv_storage>
``` ```
...@@ -135,21 +136,42 @@ ErrorCode Classifier::Classify(const std::vector<cv::Mat> &srcImages,std::vector ...@@ -135,21 +136,42 @@ ErrorCode Classifier::Classify(const std::vector<cv::Mat> &srcImages,std::vector
// 预处理 // 预处理
// 创建输入数据 // 创建输入数据
std::unordered_map<std::string, migraphx::argument> inputData; migraphx::argument result;
inputData[inputName]= migraphx::argument{inputShape, (float*)inputBlob.data}; if(useoffloadcopy)
{
std::unordered_map<std::string, migraphx::argument> inputData;
inputData[inputName]= migraphx::argument{inputShape, (float*)inputBlob.data};
// 推理
std::vector<std::string> outputNames={"resnetv24_dense0_fwd"}; // 设置返回的输出节点
std::vector<migraphx::argument> results = net.eval(inputData,outputNames);
result = results[0]; // 获取第一个输出节点的数据
}
else
{
// 为输出节点分配device内存,用于保存输出数据
std::unordered_map<std::string, migraphx::argument> modelData=CreateOutputData(net);
// 将输入转换为device数据
migraphx::argument inputData=migraphx::gpu::to_gpu(migraphx::argument{inputShape, (float*)inputBlob.data});
// 推理 // 使用device数据作为输入数据,inputData.data()返回的是device地址
std::vector<migraphx::argument> results = net.eval(inputData); modelData[inputName]= migraphx::argument{inputShape, inputData.data()};
// 获取输出节点的属性 // 推理
migraphx::argument result = results[0]; // 获取第一个输出节点的数据 std::vector<std::string> outputNames={"resnetv24_dense0_fwd"}; // 设置返回的输出节点
std::vector<migraphx::argument> results = net.eval(modelData,outputNames);
result = migraphx::gpu::from_gpu(results[0]); // 将第一个输出节点的数据拷贝到host端
}
... ...
} }
``` ```
- inputData表示MIGraphX的输入数据,inputData是一个映射关系,每个输入节点名都会对应一个输入数据,如果有多个输入,则需要为每个输入节点名创建数据,inputName表示输入节点名,migraphx::argument{inputShape, (float*)inputBlob.data}表示该节点名对应的数据,这里是通过前面预处理的数据inputBlob来创建的,第一个参数表示数据的shape,第二个参数表示数据指针。 - 输入数据根据是否需要数据拷贝分为两种:offload=true、offload=false。当offload为true时,执行if分支,不需要进行内存拷贝,inputData表示MIGraphX的输入数据,inputData是一个映射关系,每个输入节点名都会对应一个输入数据,如果有多个输入,则需要为每个输入节点名创建数据,inputName表示输入节点名,migraphx::argument{inputShape, (float*)inputBlob.data}表示该节点名对应的数据,这里是通过前面预处理的数据inputBlob来创建的,第一个参数表示数据的shape,第二个参数表示数据指针。当offload为false时,执行else分支,需要进行内存拷贝,为输入节点和输出节点分配device内存,用来保存输入数据和输出数据,使用device数据作为输入数据,执行推理。
- net.eval(inputData)返回模型的推理结果,由于这里只有一个输出节点,所以std::vector中只有一个数据,results[0]表示第一个输出节点,这里对应resnetv24_dense0_fwd节点,获取输出数据。 - net.eval(inputData)返回模型的推理结果,由于这里只有一个输出节点,所以std::vector中只有一个数据,results[0]表示第一个输出节点,这里对应resnetv24_dense0_fwd节点,获取输出数据。
另外,如果想要指定输出节点,可以在eval()方法中通过提供outputNames参数来实现: 另外,如果想要指定输出节点,可以在eval()方法中通过提供outputNames参数来实现:
......
...@@ -109,6 +109,8 @@ if __name__ == '__main__': ...@@ -109,6 +109,8 @@ if __name__ == '__main__':
```python ```python
if __name__ == '__main__': if __name__ == '__main__':
... ...
# 编译
model.compile(t=migraphx.get_target("gpu"),device_id=0) # device_id: 设置GPU设备,默认为0号设备
# 预处理 # 预处理
pathOfImage ="../Resource/Images/ImageNet_01.jpg" pathOfImage ="../Resource/Images/ImageNet_01.jpg"
...@@ -129,3 +131,36 @@ if __name__ == '__main__': ...@@ -129,3 +131,36 @@ if __name__ == '__main__':
- Preprocessing()函数返回输入数据(numpy类型),然后通过{inputName: migraphx.argument(image)}构造一个字典输入模型执行推理,如果模型有多个输入,则在字典中需要添加多个输入数据。 - Preprocessing()函数返回输入数据(numpy类型),然后通过{inputName: migraphx.argument(image)}构造一个字典输入模型执行推理,如果模型有多个输入,则在字典中需要添加多个输入数据。
- model.run()返回模型的推理结果,返回结果是一个list类型,results[0]表示第一个输出节点的输出,是一个migraphx.argument类型,由于示例模型只有一个输出节点,所以results[0]对应resnetv24_dense0_fwd节点。最后,通过np.array(result)获取分类结果。 - model.run()返回模型的推理结果,返回结果是一个list类型,results[0]表示第一个输出节点的输出,是一个migraphx.argument类型,由于示例模型只有一个输出节点,所以results[0]对应resnetv24_dense0_fwd节点。最后,通过np.array(result)获取分类结果。
在Classifier_OffloadFalse.py脚本中,主要在推理阶段有所不同,需要进行内存拷贝。
```python
if __name__ == '__main__':
...
# 编译
model.compile(t=migraphx.get_target("gpu"),offload_copy=False,device_id=0) # device_id: 设置GPU设备,默认为0号设备
# 为输出节点分配device内存,用于保存输出数据
modelData=AllocateOutputMemory(model)
# 预处理并转换为NCHW
pathOfImage ="../Resource/Images/ImageNet_01.jpg"
image = Preprocessing(pathOfImage)
modelData[inputName]=migraphx.to_gpu(migraphx.argument(image))
# 推理
results = model.run(modelData)
# 获取输出节点属性
result=migraphx.from_gpu(results[0]) # 获取第一个输出节点的数据,migraphx.argument类型
outputShape=result.get_shape() # 输出节点的shape,migraphx.shape类型
outputSize=outputShape.lens() # 每一维大小,维度顺序为(N,C,H,W),list类型
numberOfOutput=outputShape.elements() # 输出节点元素的个数
# 获取分类结果
print(np.array(result))
```
- AllocateOutputMemory()函数主要用于为输出节点分配device内存,用来保存输出数据。
- Preprocessing()函数返回输入数据后,通过migraphx.to_gpu(migraphx.argument(image))方法,将输入数据转换为device数据。
\ No newline at end of file
# -*- coding: utf-8 -*-
"""
offload为false时的分类器示例
"""
import argparse
import cv2
import numpy as np
import migraphx
def AllocateOutputMemory(model):
outputData={}
for key in model.get_outputs().keys():
outputData[key] = migraphx.allocate_gpu(s=model.get_outputs()[key])
return outputData
def Preprocessing(pathOfImage):
# 读取图像
image = cv2.imread(pathOfImage, cv2.IMREAD_COLOR)
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
# 调整大小,使短边为256,保持长宽比
ratio = float(256) / min(image.shape[0], image.shape[1])
if image.shape[0] > image.shape[1]:
new_size = [int(round(ratio * image.shape[0])), 256]
else:
new_size = [256, int(round(ratio * image.shape[1]))]
image = np.array(cv2.resize(image, (new_size[1],new_size[0])))
# 裁剪中心窗口为224*224
h, w, c = image.shape
start_x = w//2 - 224//2
start_y = h//2 - 224//2
image = image[start_y:start_y+224, start_x:start_x+224, :]
# transpose
image = image.transpose(2, 0, 1)
# 将输入数据转换为float32
img_data = image.astype('float32')
# normalize
mean_vec = np.array([123.675, 116.28, 103.53])
stddev_vec = np.array([58.395, 57.12, 57.375])
norm_img_data = np.zeros(img_data.shape).astype('float32')
for i in range(img_data.shape[0]):
norm_img_data[i,:,:] = (img_data[i,:,:] - mean_vec[i]) / stddev_vec[i]
# 调整尺寸
norm_img_data = norm_img_data.reshape(1, 3, 224, 224).astype('float32')
return norm_img_data
if __name__ == '__main__':
# 量化方法选项
use_int8 = False
use_fp16 = False
# 设置最大输入shape
maxInput={"data":[1,3,224,224]}
# 加载模型
model = migraphx.parse_onnx("../Resource/Models/resnet50-v2-7.onnx", map_input_dims=maxInput)
# 获取模型输入/输出节点信息
print("inputs:")
inputs = model.get_inputs()
for key,value in inputs.items():
print("{}:{}".format(key,value))
print("outputs:")
outputs = model.get_outputs()
for key,value in outputs.items():
print("{}:{}".format(key,value))
inputName = model.get_parameter_names()[0]
inputShape=inputs[inputName].lens()
# INT8量化
if use_int8:
dic = dict()
testofImage = "../Resource/Images/ImageNet_test.jpg"
testimage = Preprocessing(testofImage)
dic[inputName] = migraphx.argument(testimage)
calibration = [dic]
migraphx.quantize_int8(model, migraphx.get_target("gpu"), calibration)
if use_fp16:
migraphx.quantize_fp16(model)
# 编译
model.compile(t=migraphx.get_target("gpu"),offload_copy=False,device_id=0) # device_id: 设置GPU设备,默认为0号设备
# 为输出节点分配device内存,用于保存输出数据
modelData=AllocateOutputMemory(model)
# 预处理并转换为NCHW
pathOfImage ="../Resource/Images/ImageNet_01.jpg"
image = Preprocessing(pathOfImage)
modelData[inputName]=migraphx.to_gpu(migraphx.argument(image))
# 推理
results = model.run(modelData)
# 获取输出节点属性
result=migraphx.from_gpu(results[0]) # 获取第一个输出节点的数据,migraphx.argument类型
outputShape=result.get_shape() # 输出节点的shape,migraphx.shape类型
outputSize=outputShape.lens() # 每一维大小,维度顺序为(N,C,H,W),list类型
numberOfOutput=outputShape.elements() # 输出节点元素的个数
# 获取分类结果
print(np.array(result))
\ No newline at end of file
...@@ -74,9 +74,18 @@ cd Python/ ...@@ -74,9 +74,18 @@ cd Python/
# 安装依赖 # 安装依赖
pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
```
# 运行示例
​ 1.offload为true的模型推理
```
python Classifier.py python Classifier.py
```
2.offload为false的模型推理
```
python Classifier_OffloadFalse.py
``` ```
### C++版本推理 ### C++版本推理
...@@ -124,6 +133,8 @@ cd build/ ...@@ -124,6 +133,8 @@ cd build/
./ResNet50 ./ResNet50
``` ```
默认offload为true,如果想要offload为false,可以在./Resource/Configuration.xmlwen文件中修改Useoffloadcopy为1,再执行示例程序。
## result ## result
### Python版本 ### Python版本
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
<ModelPath>"../Resource/Models/resnet50-v2-7.onnx"</ModelPath> <ModelPath>"../Resource/Models/resnet50-v2-7.onnx"</ModelPath>
<UseInt8>0</UseInt8><!--是否使用int8,不支持--> <UseInt8>0</UseInt8><!--是否使用int8,不支持-->
<UseFP16>0</UseFP16><!--是否使用FP16--> <UseFP16>0</UseFP16><!--是否使用FP16-->
<Useoffloadcopy>0</Useoffloadcopy><!--是否使用offloadcopy-->
</Classifier> </Classifier>
</opencv_storage> </opencv_storage>
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
#include <migraphx/onnx.hpp> #include <migraphx/onnx.hpp>
#include <migraphx/gpu/target.hpp> #include <migraphx/gpu/target.hpp>
#include <migraphx/quantization.hpp> #include <migraphx/quantization.hpp>
#include <migraphx/gpu/hip.hpp>
#include <Filesystem.h> #include <Filesystem.h>
#include <SimpleLog.h> #include <SimpleLog.h>
#include <algorithm> #include <algorithm>
...@@ -42,6 +42,7 @@ ErrorCode Classifier::Initialize(InitializationParameterOfClassifier initializat ...@@ -42,6 +42,7 @@ ErrorCode Classifier::Initialize(InitializationParameterOfClassifier initializat
std::string modelPath=(std::string)netNode["ModelPath"]; std::string modelPath=(std::string)netNode["ModelPath"];
useInt8=(bool)(int)netNode["UseInt8"]; useInt8=(bool)(int)netNode["UseInt8"];
useFP16=(bool)(int)netNode["UseFP16"]; useFP16=(bool)(int)netNode["UseFP16"];
useoffloadcopy=(bool)(int)netNode["Useoffloadcopy"];
// 设置最大输入shape // 设置最大输入shape
migraphx::onnx_options onnx_options; migraphx::onnx_options onnx_options;
...@@ -142,14 +143,30 @@ ErrorCode Classifier::Initialize(InitializationParameterOfClassifier initializat ...@@ -142,14 +143,30 @@ ErrorCode Classifier::Initialize(InitializationParameterOfClassifier initializat
// 编译模型 // 编译模型
migraphx::compile_options options; migraphx::compile_options options;
options.device_id=0; // 设置GPU设备,默认为0号设备 options.device_id=0; // 设置GPU设备,默认为0号设备
options.offload_copy=true; if(useoffloadcopy)
{
options.offload_copy=true;
}
else
{
options.offload_copy=false;
}
net.compile(gpuTarget,options); net.compile(gpuTarget,options);
LOG_INFO(stdout,"succeed to compile model: %s\n",GetFileName(modelPath).c_str()); LOG_INFO(stdout,"succeed to compile model: %s\n",GetFileName(modelPath).c_str());
// warm up // warm up
std::unordered_map<std::string, migraphx::argument> inputData; if(useoffloadcopy)
inputData[inputName]=migraphx::argument{inputShape}; {
net.eval(inputData); std::unordered_map<std::string, migraphx::argument> inputData;
inputData[inputName]=migraphx::argument{inputShape};
net.eval(inputData);
}
else
{
std::unordered_map<std::string, migraphx::argument> modelData_warm=CreateOutputData(net);
modelData_warm[inputName]=migraphx::gpu::to_gpu(migraphx::argument{inputShape});
net.eval(modelData_warm);
}
// log // log
LOG_INFO(stdout,"InputSize:%dx%d\n",inputSize.width,inputSize.height); LOG_INFO(stdout,"InputSize:%dx%d\n",inputSize.width,inputSize.height);
...@@ -206,14 +223,37 @@ ErrorCode Classifier::Classify(const std::vector<cv::Mat> &srcImages,std::vector ...@@ -206,14 +223,37 @@ ErrorCode Classifier::Classify(const std::vector<cv::Mat> &srcImages,std::vector
blobFromImagesWithParams(image,inputBlob,image2BlobParams); blobFromImagesWithParams(image,inputBlob,image2BlobParams);
// 创建输入数据 // 创建输入数据
std::unordered_map<std::string, migraphx::argument> inputData; migraphx::argument result;
inputData[inputName]= migraphx::argument{inputShape, (float*)inputBlob.data}; if(useoffloadcopy)
{
std::unordered_map<std::string, migraphx::argument> inputData;
inputData[inputName]= migraphx::argument{inputShape, (float*)inputBlob.data};
// 推理 // 推理
std::vector<migraphx::argument> results = net.eval(inputData); std::vector<std::string> outputNames={"resnetv24_dense0_fwd"}; // 设置返回的输出节点
std::vector<migraphx::argument> results = net.eval(inputData,outputNames);
result = results[0]; // 获取第一个输出节点的数据
}
else
{
// 为输出节点分配device内存,用于保存输出数据
std::unordered_map<std::string, migraphx::argument> modelData=CreateOutputData(net);
// 将输入转换为device数据
migraphx::argument inputData=migraphx::gpu::to_gpu(migraphx::argument{inputShape, (float*)inputBlob.data});
// 使用device数据作为输入数据,inputData.data()返回的是device地址
modelData[inputName]= migraphx::argument{inputShape, inputData.data()};
// 推理
std::vector<std::string> outputNames={"resnetv24_dense0_fwd"}; // 设置返回的输出节点
std::vector<migraphx::argument> results = net.eval(modelData,outputNames);
result = migraphx::gpu::from_gpu(results[0]); // 将第一个输出节点的数据拷贝到host端
}
// 获取输出节点的属性 // 获取输出节点的属性
migraphx::argument result = results[0]; // 获取第一个输出节点的数据
migraphx::shape outputShape=result.get_shape(); // 输出节点的shape migraphx::shape outputShape=result.get_shape(); // 输出节点的shape
std::vector<std::size_t> outputSize=outputShape.lens();// 每一维大小,维度顺序为(N,C,H,W) std::vector<std::size_t> outputSize=outputShape.lens();// 每一维大小,维度顺序为(N,C,H,W)
int numberOfOutput=outputShape.elements();// 输出节点元素的个数 int numberOfOutput=outputShape.elements();// 输出节点元素的个数
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment