0%

ov::Tensor

摘要

  • Tensor 类 相关学习笔记

ov::Tensor 详解

ov::Tensor 是 OpenVINO Runtime 的核心类之一,表示模型推理过程中使用的张量(数据存储的基本单元)。它封装了张量的数据类型、形状、内存管理等功能,是输入输出数据传递的主要接口。


主要功能

  1. 数据存储
    提供对张量数据的管理和访问,支持多种数据类型和形状。

  2. 内存管理
    支持自动分配内存,也允许用户绑定自定义的内存缓冲区。

  3. 动态形状
    支持动态形状,用于模型的动态输入输出。

  4. 设备支持
    张量可以绑定到不同的设备(如 CPU、GPU),支持设备内存与主机内存之间的交互。


创建 Tensor

ov::Tensor 可以通过多种方式创建,支持动态或固定形状,并且可以指定数据类型。

1. 使用默认内存分配创建张量

1
2
3
4
5
// 创建静态形状张量
ov::Tensor tensor(ov::element::f32, {1, 3, 224, 224}); // f32: 32位浮点数

// 创建动态形状张量
ov::Tensor tensor_dynamic(ov::element::f32, ov::PartialShape::dynamic());

2. 使用自定义内存缓冲区创建张量

1
2
float* custom_buffer = new float[1 * 3 * 224 * 224];
ov::Tensor tensor(ov::element::f32, {1, 3, 224, 224}, custom_buffer);
  • 自定义缓冲区由用户管理,OpenVINO 不负责其生命周期。

3. 从其他张量复制创建

1
2
ov::Tensor source_tensor = ov::Tensor(ov::element::f32, {1, 3, 224, 224});
ov::Tensor copied_tensor = source_tensor; // 共享同一内存

常用方法

以下是 ov::Tensor 的一些常用方法及其作用:

1. 获取张量形状

1
2
3
4
ov::Shape shape = tensor.get_shape();
for (size_t dim : shape) {
std::cout << "Dimension: " << dim << std::endl;
}
  • get_shape() 返回张量的静态形状。

2. 获取张量大小

1
2
size_t size = tensor.get_size();
std::cout << "Tensor size (elements): " << size << std::endl;
  • 返回张量包含的元素总数,而不是字节数。

3. 获取数据类型

1
2
ov::element::Type type = tensor.get_element_type();
std::cout << "Data type: " << type << std::endl;
  • 数据类型可以是 f32(float32)、i32(int32)等。

4. 访问张量数据

直接访问数据指针:

1
2
float* data = tensor.data<float>();
data[0] = 1.0f; // 修改第一个元素
  • 注意:访问的数据类型需要与张量的数据类型匹配。

访问设备内存:

如果张量绑定到设备内存,需通过特定方法访问设备数据。


5. 动态形状相关操作

检查形状是否动态:

1
2
bool is_dynamic = tensor.get_partial_shape().is_dynamic();
std::cout << "Is dynamic: " << is_dynamic << std::endl;

设置动态形状的具体形状:

1
tensor.set_shape({1, 3, 224, 224});
  • 对动态形状张量,在推理前需设置具体形状。

6. 设置外部缓冲区

可以动态绑定新的内存缓冲区:

1
2
float* new_buffer = new float[1 * 3 * 224 * 224];
tensor.set_memory(new_buffer);
  • 注意:确保新缓冲区的大小与张量形状匹配。

7. 获取 Tensor 内存句柄

1
void* buffer = tensor.data<void>();
  • 返回一个泛型指针,用于操作张量的底层内存。

典型用法示例

以下示例展示了如何创建张量、设置数据并用于推理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <openvino/openvino.hpp>
#include <iostream>

int main() {
// 创建一个张量 (1x3x224x224, float32)
ov::Tensor tensor(ov::element::f32, {1, 3, 224, 224});

// 填充张量数据
float* data = tensor.data<float>();
for (size_t i = 0; i < tensor.get_size(); ++i) {
data[i] = static_cast<float>(i);
}

// 输出部分张量数据
for (size_t i = 0; i < 10; ++i) {
std::cout << "Tensor[" << i << "] = " << data[i] << std::endl;
}

return 0;
}

设备内存支持

  1. 主机内存张量

    • 默认情况下,张量使用主机内存存储数据,适合 CPU 推理。
  2. 设备内存张量

    • 如果张量与设备(如 GPU)绑定,其数据存储在设备内存中。
    • 必须通过设备特定的方法访问或操作数据。

性能优化

  1. 避免频繁的张量创建

    • 尽可能重用张量实例,减少内存分配和销毁的开销。
  2. 使用外部缓冲区

    • 如果数据已经存在,可以绑定现有内存缓冲区,避免数据拷贝。
  3. 批量处理

    • 使用张量的批量维度,提高推理效率。

注意事项

  1. 内存管理

    • 默认情况下,ov::Tensor 会管理自身的内存,但使用自定义缓冲区时,用户需负责内存的分配和释放。
  2. 动态形状

    • 对于动态形状模型,推理前必须设置张量的具体形状。
  3. 类型匹配

    • 在访问张量数据时,必须确保访问的类型与张量定义的类型一致,否则会导致未定义行为。

总结

ov::Tensor 是 OpenVINO 推理过程中重要的工具类,用于描述模型输入输出数据。通过其灵活的内存管理、动态形状支持和多设备兼容性,ov::Tensor 能够满足多种推理需求。合理使用张量的方法,可以优化推理性能并简化数据处理流程。

感谢老板支持!敬礼(^^ゞ