0%

ov::Output

ov::Output 详解

ov::Output 是 OpenVINO 中的一个核心类,用于表示模型图中节点的输出。它封装了一个节点的输出端口,允许用户访问输出的形状、数据类型以及与其他节点的连接信息。通过 ov::Output,可以在计算图中导航并操作节点间的连接。


核心功能

  1. 表示节点的输出端口
    每个 ov::Node 可能有一个或多个输出端口,ov::Output 表示其中一个端口。

  2. 获取元信息
    包括输出的形状、数据类型和元素类型等。

  3. 管理连接关系
    用于查看输出与哪些节点的输入相连接。

  4. 支持模板化
    ov::Output<T> 可以作用于不同类型的节点,例如 ov::Nodeov::Function


创建和使用 ov::Output

通常,ov::Output 是从 ov::Nodeoutputs() 方法或 output(i) 方法获取的,而不是直接创建。

获取节点的输出

1
2
// 获取节点的第一个输出
ov::Output<ov::Node> output = node->output(0);

主要方法和属性

以下是 ov::Output 的常用方法及其功能:

1. 获取输出形状

1
2
3
4
5
6
ov::Shape shape = output.get_shape();
std::cout << "Shape: ";
for (const auto& dim : shape) {
std::cout << dim << " ";
}
std::cout << std::endl;
  • 返回输出的静态形状(ov::Shape)。

2. 获取数据类型

1
2
ov::element::Type type = output.get_element_type();
std::cout << "Data type: " << type << std::endl;
  • 返回输出的数据类型(例如 f32i32 等)。

3. 检查输出是否为动态形状

1
2
3
if (output.get_partial_shape().is_dynamic()) {
std::cout << "Output has a dynamic shape." << std::endl;
}
  • 使用 get_partial_shape() 检查是否为动态形状。

4. 获取连接的输入

1
2
3
4
for (const auto& target_input : output.get_target_inputs()) {
std::cout << "Connected to input of node: "
<< target_input.get_node()->get_friendly_name() << std::endl;
}
  • get_target_inputs() 返回所有连接到该输出的输入端口。

5. 获取输出所属的节点

1
2
3
auto owner_node = output.get_node();
std::cout << "Output belongs to node: "
<< owner_node->get_friendly_name() << std::endl;
  • get_node() 返回该输出所属的节点。

6. 设置输出名称

1
output.set_names({"custom_output_name"});
  • 设置输出的自定义名称,便于识别和访问。

动态修改模型图

通过 ov::Output,可以修改计算图中节点的连接关系。

1. 替换输出连接

1
2
3
4
ov::Output<ov::Node> new_output = some_other_node->output(0);

// 替换当前输出与新输出的连接
ov::replace_output(output, new_output);

2. 添加新连接

可以将一个输出连接到多个输入节点:

1
output.add_target_input(new_node->input(0));

实际应用示例

以下示例展示了如何遍历模型节点的输出,并动态修改模型:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <openvino/openvino.hpp>
#include <iostream>

int main() {
ov::Core core;

// 加载模型
auto model = core.read_model("model.xml");

// 遍历模型中的所有节点
for (const auto& node : model->get_ops()) {
for (size_t i = 0; i < node->get_output_size(); ++i) {
ov::Output<ov::Node> output = node->output(i);

// 输出节点信息
std::cout << "Node: " << node->get_friendly_name()
<< ", Output index: " << i
<< ", Shape: " << output.get_shape()
<< ", Type: " << output.get_element_type() << std::endl;

// 修改连接(例如替换输出连接)
if (output.get_element_type() == ov::element::f32) {
auto new_node = std::make_shared<ov::op::v0::Relu>(output);
ov::replace_output(output, new_node->output(0));
std::cout << "Replaced output with a ReLU node." << std::endl;
}
}
}

// 保存修改后的模型
core.compile_model(model, "CPU")->export_model("modified_model.xml");

return 0;
}

高级功能

使用动态形状的输出

对于动态形状的输出,可以进一步设置具体形状:

1
2
3
if (output.get_partial_shape().is_dynamic()) {
output.set_partial_shape({1, 3, 224, 224});
}

获取扩展的形状信息

获取动态形状的约束:

1
2
3
4
5
6
ov::PartialShape partial_shape = output.get_partial_shape();
if (partial_shape.rank().is_dynamic()) {
std::cout << "Rank is dynamic." << std::endl;
} else {
std::cout << "Rank: " << partial_shape.rank().get_length() << std::endl;
}

性能注意事项

  1. 批量操作
    尽量减少对输出的逐个操作,使用批量方法操作多个节点或输出。

  2. 减少拷贝
    使用引用或共享机制避免不必要的输出数据拷贝。

  3. 动态形状处理
    在动态模型中,尽量在推理开始前明确所有动态形状。


常见问题

  1. 动态形状的操作限制
    对动态形状的输出操作时,需要先设置具体形状,否则部分操作可能失败。

  2. 数据类型不匹配
    在连接节点时,确保输出和输入的数据类型一致。

  3. 输出未连接
    如果某些输出未连接,可能导致模型推理失败或结果异常。


总结

ov::Output 是 OpenVINO 图操作中的关键类,用于表示和管理节点的输出端口。通过 ov::Output,开发者可以轻松获取输出的元信息,管理节点间的连接关系,并动态修改计算图。熟练掌握 ov::Output 的功能,可以大大提升在 OpenVINO 图操作中的开发效率。

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