异构执行¶
异构执行能够在多个设备上执行一个模型的推理。其目的是:
利用加速器的力量处理模型最繁重的部分,并在回退设备(如 CPU)上执行不支持的操作。
在一次推理中更有效地利用所有可用硬件。
在异构模式下执行可分成两个独立步骤:
设置操作的硬件相关性(
ov::Core::query_model
由异构设备在内部使用)将模型编译到异构设备需要将模型拆分为多个部分,在特定设备上对其进行编译(通过
ov::device::priorities
),并在异构模式下执行它们。根据相关性将模型分解为多个子图,其中具有相同相关性的一组相关联的操作将成为专用子图。每个子图都在一个专用设备上进行编译,并生成多个ov::CompiledModel
对象,这些对象通过自动分配的中间张量相互联系起来。
这两个步骤互不关联,相关性可以通过两种方式中的一种来设置,可以单独使用,也可以组合使用(如下所述):manual
或 automatic
模式。
定义和配置异构设备¶
按照 OpenVINO™ 的命名惯例,异构执行插件被赋予 "HETERO".
标签。可以在没有额外参数的情况下对其进行定义,从而使用默认值,或者通过以下设置选项来进一步配置:
参数名称和 C++ 属性 |
属性值 |
描述 |
---|---|---|
“MULTI_DEVICE_PRIORITIES”
ov::device::priorities
|
HETERO: <device names>
逗号分隔,无空格
|
列出可供选择的设备。
设备顺序即视为优先级,
顺序为由高到低。
|
分配相关性的手动和自动模式¶
手动模式¶
它需要使用带有 "affinity"
键值的 ov::Node::get_rt_info
为模型中的所有操作明确设置相关性。
for (auto && op : model->get_ops()) {
op->get_rt_info()["affinity"] = "CPU";
}
for op in model.get_ops():
rt_info = op.get_rt_info()
rt_info["affinity"] = "CPU"
自动模式¶
此模式根据专用设备(GPU
、CPU
、MYRIAD
等)的支持自动决定将哪个操作分配给哪个设备,而在模型编译期间,查询模型步骤由异构设备隐式调用。
自动模式会导致“贪婪”行为,它会根据您指定的优先级为其分配可在给定设备上执行的所有操作(如 ov::device::priorities("GPU,CPU")
)。它不考虑设备的特殊性,例如,如果在该层之前或之后没有其他特殊操作,就无法对某些操作进行推理。如果设备插件不支持由异构设备构建的子图拓扑,您应该手动设置相关性。
auto compiled_model = core.compile_model(model, "HETERO:GPU,CPU");
// or with ov::device::priorities with multiple args
compiled_model = core.compile_model(model, "HETERO", ov::device::priorities("GPU", "CPU"));
// or with ov::device::priorities with a single argument
compiled_model = core.compile_model(model, "HETERO", ov::device::priorities("GPU,CPU"));
compiled_model = core.compile_model(model, device_name="HETERO:GPU,CPU")
# device priorities via configuration property
compiled_model = core.compile_model(model, device_name="HETERO", config={"MULTI_DEVICE_PRIORITIES": "GPU,CPU"})
组合使用手动和自动模式¶
在某些情况下,您可能需要考虑手动调整自动设置的相关性。这通常用于最大限度减少子图总数量,从而优化内存传输。为此,您需要“修复”自动分配的相关性,如下所示:
// This example demonstrates how to perform default affinity initialization and then
// correct affinity manually for some layers
const std::string device = "HETERO:GPU,CPU";
// query_model result contains mapping of supported operations to devices
auto supported_ops = core.query_model(model, device);
// update default affinities manually for specific operations
supported_ops["operation_name"] = "CPU";
// set affinities to a model
for (auto&& node : model->get_ops()) {
auto& affinity = supported_ops[node->get_friendly_name()];
// Store affinity mapping using op runtime information
node->get_rt_info()["affinity"] = affinity;
}
// load model with manually set affinities
auto compiled_model = core.compile_model(model, device);
# This example demonstrates how to perform default affinity initialization and then
# correct affinity manually for some layers
device = "HETERO:GPU,CPU"
# query_model result contains mapping of supported operations to devices
supported_ops = core.query_model(model, device)
# update default affinities manually for specific operations
supported_ops["operation_name"] = "CPU"
# set affinities to a model
for node in model.get_ops():
affinity = supported_ops[node.get_friendly_name()]
node.get_rt_info()["affinity"] = "CPU"
# load model with manually set affinities
compiled_model = core.compile_model(model, device)
有一点很重要,如果模型中的任何操作的 "affinity"
已经初始化,那么自动模式将不再起作用。
备注
ov::Core::query_model
不依赖于用户设置的相关性。相反,它根据设备功能来查询操作支持。
配置回退设备¶
如果希望异构执行中的不同设备具有不同的设备特有配置选项,您可以使用特殊帮助器属性 ov::device::properties
:
auto compiled_model = core.compile_model(model, "HETERO",
// GPU with fallback to CPU
ov::device::priorities("GPU", "CPU"),
// profiling is enabled only for GPU
ov::device::properties("GPU", ov::enable_profiling(true)),
// FP32 inference precision only for CPU
ov::device::properties("CPU", ov::hint::inference_precision(ov::element::f32))
);
core.set_property("HETERO", {"MULTI_DEVICE_PRIORITIES": "GPU,CPU"})
core.set_property("GPU", {"PERF_COUNT": "YES"})
core.set_property("CPU", {"INFERENCE_PRECISION_HINT": "f32"})
compiled_model = core.compile_model(model=model, device_name="HETERO")
在上面的示例中,GPU
设备的配置用来启用分析数据并使用默认的执行精度,而 CPU
的配置属性用来在 fp32
中执行推理。
处理难解拓扑¶
有些拓扑对某些设备上的异构执行并不友好,甚至到了无法执行的地步。例如,具有在主设备上不支持的激活操作的模型被异构分解成多组子图,从而导致执行不理想。如果在异构模式中从一个子图向模型的另一部分传输数据,所需的时间比在正常执行的情况下更多,异构执行则可能无法验证。在这类情况下,您可以手动定义最繁重的部分,并设置相关性,以避免在一次推理过程中多次来回发送数据。
分析异构执行性能¶
在启用 OPENVINO_HETERO_VISUALIZE
环境变量后,您可以转储带有每个设备的操作注释的 GraphViz .dot
文件。
异构执行模式可生成两个文件:
hetero_affinity_<model name>.dot
- 每项操作的相关性注释。hetero_subgraphs_<model name>.dot
- 每个图形的相关性注释。
您可以使用 GraphViz 实用程序或文件转换器来查看图像。在 Ubuntu 操作系统上,您可以使用 xdot:
sudo apt-get install xdot
xdot hetero_subgraphs.dot
您可以使用性能数据(在示例应用中,它是 -pc
选项)来获取每个子图的性能数据。
下面的输出示例说明的是 Googlenet v1 在 HDDL 运行,可以回退到 CPU:
subgraph1: 1. input preprocessing (mean data/HDDL):EXECUTED layerType: realTime: 129 cpu: 129 execType:
subgraph1: 2. input transfer to DDR:EXECUTED layerType: realTime: 201 cpu: 0 execType:
subgraph1: 3. HDDL execute time:EXECUTED layerType: realTime: 3808 cpu: 0 execType:
subgraph1: 4. output transfer from DDR:EXECUTED layerType: realTime: 55 cpu: 0 execType:
subgraph1: 5. HDDL output postprocessing:EXECUTED layerType: realTime: 7 cpu: 7 execType:
subgraph1: 6. copy to IE blob:EXECUTED layerType: realTime: 2 cpu: 2 execType:
subgraph2: out_prob: NOT_RUN layerType: Output realTime: 0 cpu: 0 execType: unknown
subgraph2: prob: EXECUTED layerType: SoftMax realTime: 10 cpu: 10 execType: ref
Total time: 4212 microseconds
用例¶
OpenVINO™ 样本程序可以使用与 -d
选项配合使用的异构执行:
./hello_classification <path_to_model>/squeezenet1.1.xml <path_to_pictures>/picture.jpg HETERO:GPU,CPU
在此:
HETERO
代表异构执行GPU,CPU
指向回退策略,优先考虑 GPU,可回退到 CPU
您还可以指向两个以上的设备:-d HETERO:MYRIAD,GPU,CPU