我目前正在试用onnxruntime-gpu
,我希望使用NVIDIA DALI在GPU上执行图像预处理。一切正常,我能够预处理我的图像,但问题是,我希望保留设备上的所有数据,以免从设备和主机来回复制数据造成瓶颈。onnxruntime
库允许IO绑定来将输入和输出绑定到设备。问题是这是令人难以置信的静态,这使得在为不同形状的输出Tensor预分配内存时出现问题。例如,我使用的RetinaNet生成不同大小的预测,我似乎无法处理。
对于预处理,我使用以下代码:
class ImagePipeline(Pipeline):
def __init__(self, file_list, batch_size, num_threads, device_id):
super(ImagePipeline, self).__init__(batch_size, num_threads, device_id)
self.input = ops.readers.File(file_root="", file_list=file_list)
self.decode = ops.decoders.Image(device="mixed", output_type=types.RGB)
self.resize = ops.Resize(device="gpu", resize_x=800, resize_y=800)
self.normalize = ops.CropMirrorNormalize(
device="gpu",
dtype=types.FLOAT,
output_layout=types.NCHW,
crop=(800, 800),
mean=[0.485 * 255, 0.456 * 255, 0.406 * 255],
std=[0.229 * 255, 0.224 * 255, 0.225 * 255],
)
def define_graph(self):
inputs, labels = self.input()
images = self.decode(inputs)
images = self.resize(images)
images = self.normalize(images)
return images, labels
这可以正确地创建shape(BATCH_SIZE,800,800)图像的批处理。为了对这些批处理运行推理,我使用了以下代码片段:
def run_with_torch_tensors_on_device(x: torch.Tensor, CURR_SIZE: int, torch_type: torch.dtype = torch.float) -> torch.Tensor:
binding = session.io_binding()
x_tensor = x.contiguous()
z_tensor = torch.zeros(CURR_SIZE, 4, dtype=torch_type, device=DEVICE).contiguous()
binding.bind_input(
name=session.get_inputs()[0].name,
device_type=DEVICE_NAME,
device_id=DEVICE_INDEX,
element_type=np.float32,
shape=tuple(x_tensor.shape),
buffer_ptr=x_tensor.data_ptr())
binding.bind_output(
name=session.get_outputs()[0].name,
device_type=DEVICE_NAME,
device_id=DEVICE_INDEX,
element_type=np.int64,
shape=tuple(x_tensor.shape),
buffer_ptr=z_tensor.data_ptr())
session.run_with_iobinding(binding)
return z_tensor.squeeze(0)
这就是问题发生的地方。我不能创建正确形状的z_tensors。我使用www.example.com上预先训练的视网膜网络https://pytorch.org/vision/main/models/generated/torchvision.models.detection.retinanet_resnet50_fpn_v2.html#torchvision.models.detection.retinanet_resnet50_fpn_v2。
我找到了一个解决方法,如下所示:
def run_with_data_on_device(x):
x_ortvalue = ort.OrtValue.ortvalue_from_numpy(x)
io_binding = session.io_binding()
io_binding.bind_input(name=session.get_inputs()[0].name, device_type=x_ortvalue.device_name(), device_id=0, element_type=x.dtype, shape=x_ortvalue.shape(), buffer_ptr=x_ortvalue.data_ptr())
io_binding.bind_output(name=session.get_outputs()[-1].name, device_type=DEVICE_NAME, device_id=DEVICE_INDEX, element_type=x.dtype, shape=x_ortvalue.shape())
session.run_with_iobinding(io_binding)
z = io_binding.get_outputs()
return z[0]
但这自然会导致往返主机的问题,这是不必要的......我是否忽略了一些明显的问题?为什么我不能将z_tensor初始化为(None,None)并具有动态形状的输出Tensor?
1条答案
按热度按时间ql3eal8s1#
IO绑定的API:https://onnxruntime.ai/docs/api/python/api_summary.html#iobinding
实际上你可以只绑定输出变量name,因为其他参数都是可选的。如果是这样,内存将由onnxruntime分配。这对动态输出形状的情况很有帮助。
get_outputs()返回设备中的OrtValues,copy_outputs_to_cpu()可以将数据复制到CPU。
页面中也有很多示例,请参见“设备上的数据”部分中的第一个示例:https://onnxruntime.ai/docs/api/python/api_summary.html#data-on-device