异构执行¶
异构执行能够在多个设备上执行一个模型的推理。其目的是:
利用加速器的力量处理模型最繁重的部分,并在回退设备(如 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 xdotxdot 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