摘要
- Tensor 类 相关学习笔记
ov::Tensor 详解
ov::Tensor
是 OpenVINO Runtime 的核心类之一,表示模型推理过程中使用的张量(数据存储的基本单元)。它封装了张量的数据类型、形状、内存管理等功能,是输入输出数据传递的主要接口。
主要功能
数据存储
提供对张量数据的管理和访问,支持多种数据类型和形状。内存管理
支持自动分配内存,也允许用户绑定自定义的内存缓冲区。动态形状
支持动态形状,用于模型的动态输入输出。设备支持
张量可以绑定到不同的设备(如 CPU、GPU),支持设备内存与主机内存之间的交互。
创建 Tensor
ov::Tensor
可以通过多种方式创建,支持动态或固定形状,并且可以指定数据类型。
1. 使用默认内存分配创建张量
1 | // 创建静态形状张量 |
2. 使用自定义内存缓冲区创建张量
1 | float* custom_buffer = new float[1 * 3 * 224 * 224]; |
- 自定义缓冲区由用户管理,OpenVINO 不负责其生命周期。
3. 从其他张量复制创建
1 | ov::Tensor source_tensor = ov::Tensor(ov::element::f32, {1, 3, 224, 224}); |
常用方法
以下是 ov::Tensor
的一些常用方法及其作用:
1. 获取张量形状
1 | ov::Shape shape = tensor.get_shape(); |
get_shape()
返回张量的静态形状。
2. 获取张量大小
1 | size_t size = tensor.get_size(); |
- 返回张量包含的元素总数,而不是字节数。
3. 获取数据类型
1 | ov::element::Type type = tensor.get_element_type(); |
- 数据类型可以是
f32
(float32)、i32
(int32)等。
4. 访问张量数据
直接访问数据指针:
1 | float* data = tensor.data<float>(); |
- 注意:访问的数据类型需要与张量的数据类型匹配。
访问设备内存:
如果张量绑定到设备内存,需通过特定方法访问设备数据。
5. 动态形状相关操作
检查形状是否动态:
1 | bool is_dynamic = tensor.get_partial_shape().is_dynamic(); |
设置动态形状的具体形状:
1 | tensor.set_shape({1, 3, 224, 224}); |
- 对动态形状张量,在推理前需设置具体形状。
6. 设置外部缓冲区
可以动态绑定新的内存缓冲区:
1 | float* new_buffer = new float[1 * 3 * 224 * 224]; |
- 注意:确保新缓冲区的大小与张量形状匹配。
7. 获取 Tensor 内存句柄
1 | void* buffer = tensor.data<void>(); |
- 返回一个泛型指针,用于操作张量的底层内存。
典型用法示例
以下示例展示了如何创建张量、设置数据并用于推理:
1 |
|
设备内存支持
主机内存张量
- 默认情况下,张量使用主机内存存储数据,适合 CPU 推理。
设备内存张量
- 如果张量与设备(如 GPU)绑定,其数据存储在设备内存中。
- 必须通过设备特定的方法访问或操作数据。
性能优化
避免频繁的张量创建
- 尽可能重用张量实例,减少内存分配和销毁的开销。
使用外部缓冲区
- 如果数据已经存在,可以绑定现有内存缓冲区,避免数据拷贝。
批量处理
- 使用张量的批量维度,提高推理效率。
注意事项
内存管理
- 默认情况下,
ov::Tensor
会管理自身的内存,但使用自定义缓冲区时,用户需负责内存的分配和释放。
- 默认情况下,
动态形状
- 对于动态形状模型,推理前必须设置张量的具体形状。
类型匹配
- 在访问张量数据时,必须确保访问的类型与张量定义的类型一致,否则会导致未定义行为。
总结
ov::Tensor
是 OpenVINO 推理过程中重要的工具类,用于描述模型输入输出数据。通过其灵活的内存管理、动态形状支持和多设备兼容性,ov::Tensor
能够满足多种推理需求。合理使用张量的方法,可以优化推理性能并简化数据处理流程。