0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

为OpenVINO添加对Paddle 2.5的支持

英特尔物联网 来源:英特尔物联网 2024-01-19 09:20 次阅读

作者:卢畅,英特尔 OpenVINO工具套件领航者联盟成员,PPDE

1. 前言

我是飞桨黑客马拉松第五期OpenVINO赛题获奖者——为 OpenVINO添加了对 Paddle 2.5 的支持。在此记录下来贡献的过程,希望有更多的同学可以参与到 OpenVINO的社区建设当中来。我在贡献代码的过程中,也遇到了一些问题,在此,非常感谢英特尔的技术老师们非常耐心地指导我,帮助我解决了问题!

那么,接下来就让我们正式进入正题!

2. 介绍

2.1OpenVINO 是什么?

OpenVINO是英特尔推出的一款深度学习推理框架,它可以将训练好的模型转换为 OpenVINO支持的 IR 格式,从而可以在 OpenVINO的推理引擎上进行推理。

OpenVINO支持多种深度学习框架,包括 Paddle、TensorFlow、PyTorch 等。

2.2任务说明

在这个任务完成之前,OpenVINO只支持 Paddle 2.4 的版本,由于 Paddle 2.5 的一些接口变动,OpenVINO无法直接支持 Paddle 2.5。同时,由于 Paddle 2.4 版本并不支持 Python 3.11,因此 OpenVINO默认关闭了对 Paddle 的支持,需要手动开启,在手动开启后,又会遇到无法编译出 Paddle 相关单侧的问题。

本任务的目标是为 OpenVINO添加对 Paddle 2.5 的支持,并确保 OpenVINO可以正常编译出 Paddle 相关单侧且线上 CI 均可通过。

3. 开发过程

3.1问题分析

在任务开始之前,OpenVINO开启对 Paddle 的支持后主要会遇到两个问题:

1API名称变动导致的编译报错,如:

paddle.fluid.layers.elementwise_add -> paddle.add

2API名称变动导致的编译报错,如:paddle.fluid.layers.elementwise_add -> paddle.add

针对上面这两个问题,主要的解决方案如下:

1将老 API 与新 API 名称映射

2修改名称/属性变动的 API

3修复因 Op 行为变动导致的单侧报错

3.2将老 API 与新 API 名称映射

由于 Paddle 2.5 版本在 API 层面发生了较大的变化,因此需要将老 API 与新 API 名称进行映射,这样 OpenVINO中的代码就可以使用新 API 名称,从而解决 API 名称变动导致的编译报错问题。该问题可参考 Paddle 官网的 API 映射表。

链接:

https://www.paddlepaddle.org.cn/documentation/docs/zh/guides/model_convert/convert_from_older_versions/paddle_api_mapping_cn.html#paddle-1-8-paddle-2-0-api

为了兼容老版本的 API,OpenVINO中的代码需要同时支持新 API 与老 API,因此需要在 generate_xxx.py中进行相应修改。

  with paddle.static.program_guard(paddle.static.Program(), paddle.static.Program()):
    node_x = paddle.static.data(name='x', shape=x.shape, dtype=x.dtype)
    node_i = paddle.full(shape=[1], fill_value=0, dtype='int64', name='i')
    if paddle.__version__ >= '2.0.0':
      node_i = paddle.add(node_i, node_x)
    else:
      paddle.fluid.layers.nn.elementwise_add(node_i, node_x)
    node_ten = paddle.full(shape=[1], fill_value=10, dtype='int64', name='ten')

左滑查看更多

代码中的paddle.fluid.layers.nn.elementwise_add就是老版本的 API,而 paddle.add就是新版本的 API。

3.3修改名称/属性变动的 API

对于部分 API 接口,老版本与新版本的名称或属性发生了变化,因此需要给 OpenVINO中的代码进行相应的修改。比如 paddle.fluid.layers.relu6(x, threshold=6.0, name=None)和 paddle.nn.functional.relu6(x, name=None)的属性发生了变化。

可以看到,paddle.fluid.dygraph.relu6中的 threshold属性在新版本中被删除了。

这种情况下需要确认 Python 源码中是否修改底层 C++ 源码,如果是修改了 C++ 源码,那么需要在 OpenVINO的op源码中进行相应的修改。如果没有修改 C++ 源码,那么只需要对应修改 Python 源码即可。

一般情况下,底层 C++ 源码不会修改,Python 层一般是修改属性的名称,修改属性的默认值,删除某个属性等。

比如新版本 relu6在 Paddle 的 Python 端的实现如下:

def relu6(x, name=None):
  threshold = 6.0
  if in_dynamic_or_pir_mode():
    return _C_ops.relu6(x)


  check_variable_and_dtype(
    x, 'x', ['float16', 'uint16', 'float32', 'float64'], 'relu6'
  )
  helper = LayerHelper('relu6', **locals())
  out = helper.create_variable_for_type_inference(x.dtype)
  helper.append_op(
    type='relu6',
    inputs={'X': x},
    outputs={'Out': out},
    attrs={'threshold': threshold},
  )
  return out

左滑查看更多

通过实现代码可以看到,新版本的 relu6在 Python 端并没有修改 C++ 源码,只是删除了 threshold属性,在调用 C++ 源码时,将 threshold属性设置为了默认值 6.0。

因此,对于这种情况,只需要修改 OpenVINO中的 Python 单侧代码即可,不需要修改 C++ 源码。OpenVINO在进行模型转化的时候是对底层op 进行转化,因此只要 Paddle 没有修改底层 Op 的行为,那么 OpenVINO就不需要修改 Op 相关的代码。

3.4修复因 Op 行为变动导致的单侧报错

在 Paddle 2.5 版本中,部分 Op 的行为发生了变化,导致 OpenVINO中的单侧报错。比如 paddle.argmax新增了 0-d tensor的支持,但是 OpenVINO中的 Op 并没有对应的修改。想要修复这种问题,需要结合单侧报错的具体情况进行相应的修改。

在介绍如何修复单侧报错之前,先介绍一下 OpenVINO的算子支持机制。

3.4.1 OpenVINO算子支持机制

接下来我们先看一下 OpenVINO中的算子支持机制。

通过 Paddle 官方提供的 Topk_v2 样例进行说明:

// Copyright (C) 2018-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0


#include "default_opset.hpp"
#include "openvino/frontend/paddle/node_context.hpp"


namespace ov {
namespace frontend {
namespace paddle {
namespace op {
NamedOutputs top_k_v2(const NodeContext& node) {
  auto x = node.get_input("X");
  Output k_expected_node;
  if (node.has_input("K")) {
    auto k_variable = node.get_input("K");
    auto k_var_node = std::make_shared(k_variable, element::i32);
    k_expected_node = std::make_shared(k_var_node);
  } else {
    const auto k_expected = node.get_attribute("k", 1);
    k_expected_node = default_opset::i32, {}, {k_expected});
  }


  auto axis = node.get_attribute("axis", -1);
  bool sorted = node.get_attribute("sorted", true);
  bool largest = node.get_attribute("largest", true);


  std::string sort_type = sorted ? "value" : "none";
  std::string mode = largest ? "max" : "min";


  auto node_topk = std::make_shared(x, k_expected_node, axis, mode, sort_type);


  NamedOutputs named_outputs;
  named_outputs["Out"] = OutputVector{node_topk->output(0)};
  named_outputs["Indices"] = OutputVector{node_topk->output(1)};


  return named_outputs;
}
} // namespace op
} // namespace paddle
} // namespace frontend
} // namespace ov

左滑查看更多

在 OpenVINO中,一般来说每个算子都是一个单独的文件,比如 Topk_v2 算子对应的文件就是 topk_v2.cpp。在这个文件中,我们可以看到 top_k_v2函数,这个函数就是 OpenVINO中的 Topk_v2 算子的实现。

在这个函数中,我们可以看到 auto x = node.get_input("X");,这个函数就是获取输入的 Tensor,auto node_topk = std::make_shared(x, k_expected_node, axis, mode, sort_type);这个函数就是创建 Topk_v2 算子,named_outputs["Out"] = OutputVector{node_topk->output(0)};这个函数就是获取输出的 Tensor。

每个Op都可以映射为一个图结构,数据根据图结构在不同的计算节点之间流通和计算,而Node便定义了图结构中的数据节点,通过实现每一个Node,便可以通过组合实现更多的算子。

Op 转换的代码需要写在 src/frontends/paddle/src/op/目录下,并在 src/frontends/paddle/src/op_table.cpp中进行注册。

单测代码需要写在 src/core/tests/frontend/paddle/test_models/gen_scripts目录中,并在 src/core/tests/frontend/paddle/op_fuzzy.cpp中进行注册。

3.4.2 修复因 Op 行为变动导致的单侧报错

下面以 paddle.argmax为例,介绍如何修复因 Op 行为变动导致的单侧报错。

修复此类问题一般只能见招拆招,需要结合单侧报错的具体情况进行相应的修改。比如 paddle.argmax新增了 0-d tensor的支持,但是 OpenVINO中的 Op 并没有对应的修改。因此,我们需要在 OpenVINO中的 Op 中添加对 0-d tensor的支持。经过对代码的分析我们可以发现,OpenVINO中该 Op 是通过 std::make_shared(node_reshape, k, axis, "max", "index", index_element_type);实现的,但是 TopK并没有对 0-d tensor进行支持。我们可以判断 output_size 是否为 0,如果为 0,那么就组合一个 Slice节点返回即可。以下是修改后的代码:

NamedOutputs argmax(const NodeContext& node) {
  auto data = node.get_input("X");
  bool flatten = node.get_attribute("flatten");
  const element::Type& index_element_type = element::i64;
  const Output k = ov::i64, {}, {1});


  if (!flatten) {
    auto axis = node.get_attribute("axis");
    const auto axis_to_remove = ov::u64, Shape{}, {axis});
    auto node_topk = std::make_shared(data, k, axis, "max", "index", index_element_type);
    const auto reshaped_indices = std::make_shared(node_topk->output(1), axis_to_remove);
    return node.default_single_output_mapping(
      {std::make_shared(reshaped_indices, element::i64)},
      {"Out"});
  } else {
    int64_t axis = 0;
    const Output reshape_flatten = ov::i64, {1}, {-1});
    auto node_reshape = std::make_shared(data, reshape_flatten, true);
    auto node_topk = std::make_shared(node_reshape, k, axis, "max", "index", index_element_type);
    const auto output_info = node.get_output_port_infos("Out");
    // 获取输出的维度
    size_t output_size = output_info[0].second.size();
    // 如果输出的维度为0,那么就组合一个Slice节点返回
    if (output_size == 0) {
      auto out = std::make_shared(node_topk->output(1));
      return node.default_single_output_mapping({std::make_shared(out, element::i64)},
                           {"Out"});
    } else {
      return node.default_single_output_mapping(
        {std::make_shared(node_topk->output(1), element::i64)},
        {"Out"});
    }
  }
}

左滑查看更多

除了 argmax 之外,还有一些 Op 也需要进行相应的修改:

•p_norm

•reduce_ops

•matmul_v2

•elementwise_floordiv

具体的修改可以参考 PR

4. 总结

这次的黑客松活动,让我对 OpenVINO有了更深入的了解。

OpenVINO的工程师们非常热心,对于社区的问题都会非常耐心的解答。我也是第一次在 PR 页面有 144 次的 Conversation。

整个 PR 的周期大概是 3 个月,期间经历了很多次的修改,最终才能够被合并。在这次的活动中,我也学到了很多知识,比如 OpenVINO的算子支持机制,Op 的单侧测试等。

希望有更多的同学可以参与到 OpenVINO的社区建设当中来,为 OpenVINO的发展及开源社区的建设贡献自己的力量!

审核编辑:汤梓红

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 英特尔
    +关注

    关注

    60

    文章

    9428

    浏览量

    168896
  • 模型
    +关注

    关注

    1

    文章

    2707

    浏览量

    47706
  • 代码
    +关注

    关注

    30

    文章

    4556

    浏览量

    66814
  • pytorch
    +关注

    关注

    2

    文章

    763

    浏览量

    12836
  • OpenVINO
    +关注

    关注

    0

    文章

    59

    浏览量

    91

原文标题:代码贡献:为 OpenVINO™ 支持 Paddle 2.5 | 开发者实战

文章出处:【微信号:英特尔物联网,微信公众号:英特尔物联网】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    PADS添加对象,添加一个BMP文件,为什么只显示图标?

    PADS9.3添加对象,添加一个BMP文件的LOGO,为什么只显示图标,如何显示图片内容?
    发表于 02-23 22:09

    请问u32 omap_bootmode=MMCSD_MODE_FAT要添加 bootmode的选择,该怎么添加?我想增加对nand的支持

    本帖最后由 一只耳朵怪 于 2018-6-20 15:16 编辑 在 SDK5.6 中。Boot_common.c 文件中 默认的启动方式是 SD 卡启动。u32 omap_bootmode=MMCSD_MODE_FAT我要添加 bootmode 的选择,该怎么添加
    发表于 06-20 01:43

    在USB库文件mass_mal.c中添加对flash和sd读写的函数

    在USB库文件mass_mal.c中添加对flash和sd读写的函数,USB库调用这些函数从而实现模拟U盘的功能 1 //mass_mal.c 2 /* Includes ------------------------------------------------------------------*/ 3 #
    发表于 08-03 07:24

    如何在stm32mp1上添加对动画启动画面的支持呢?

    大家好,如何在 stm32mp1 上添加对动画启动画面的支持?我了解用于自定义引导屏幕的 psplash 配方,它工作得很好。我想在系统启动时播放动画。任何输入都非常感谢。
    发表于 12-16 06:07

    如何使用交叉编译方法Raspbian 32位操作系统构建OpenVINO工具套件的开源分发

    提供如何使用交叉编译方法 Raspbian* 32 位操作系统构建 OpenVINO™ 工具套件的开源分发。 单击主题上的 了解详细信息: 系统要求注意本指南假定您的 Raspberry Pi* 主板
    发表于 08-15 06:28

    永久设置OpenVINO trade Windows reg10的工具套件环境变量

    ;gt;环境变量的控制面板。在系统变量下,以以下各项的相应值添加以下作为新变量,如下所示: 可变名称可变值笔记 INTEL_OPENVINO_DIRC:\\Program Files (x86
    发表于 08-15 07:18

    从Docker映像Raspbian OpenVINO工具套件的安装过程

    最大限度地提高了性能。英特尔英特尔® Distribution工具OpenVINO™工具套件还包括英特尔®深度学习部署工具套件。 本指南用户提供了创建 Docker* 映像的步骤,以安装适用于
    发表于 08-15 06:59

    无法使用Microsoft Visual Studio 2017Windows 10构建开源OpenVINO怎么解决?

    无法使用 Microsoft Visual Studio 2017 Windows 10 构建开源OpenVINO™。
    发表于 08-15 06:43

    Fedora项目团队宣布添加对树莓派2和3的系统支持

    Fedora项目团队于今天宣布添加对树莓派2和3的系统支持。项目负责人Peter Robinson说道:“过去几年反馈最多的要求就是对树莓派设备的支持,为此我们也付出了诸多努力。早期
    发表于 04-02 14:44 176次阅读

    AMD添加对高端线程撕裂者Pro平台支持

    在去年更新并发布了StoreMI 2.0后,用户在使用SSD加机械硬盘时就已经方便了不少。而最近,AMD再度更新StoreMI,为其添加了对于高端的线程撕裂者Pro平台的支持,并且新增了使用SSD分区进行缓存加速的特性。
    的头像 发表于 02-18 16:45 1304次阅读

    RT-Thread 4.1.0正式添加对Arm Compiler 6支持

    在 RT-Thread 4.1.0 正式发布版中,添加了对 Arm Compiler 6 的支持,用户可以修改 rtconfig.py 指定生成 mdk5 工程时使用的编译器
    的头像 发表于 06-01 15:20 1560次阅读
    RT-Thread 4.1.0正式<b class='flag-5'>添加对</b>Arm Compiler 6<b class='flag-5'>支持</b>

    基于OpenVINO™ 的飞桨版 PGNet 实现案例

    OpenVINO 工具套件2022.1版于2022年3月22日正式发布,根据官宣OpenVINO 迎来迄今为止最重大更新,2022.1新特性抢先看!,OpenVINO 2022.1将是迄今为止最大变化的版本,并可以直接
    发表于 08-04 16:25 703次阅读

    没有“中间商赚差价”, OpenVINO™ 直接支持 PyTorch 模型对象

    随着 OpenVINO 2023.0 版本的发布,OpenVINO 工具库中预置了全新的 PyTorch 前端,为开发者们提供了一条全新的 PyTorch 模型支持路径,带来更友好的用户
    的头像 发表于 06-27 16:39 428次阅读
    没有“中间商赚差价”, <b class='flag-5'>OpenVINO</b>™ 直接<b class='flag-5'>支持</b> PyTorch 模型对象

    OpenVINO™ C# API详解与演示

    OpenVINO C# API 支持 NuGet 程序包安装方式,这与 OpenVINO C++ 库的安装过程相比,更加简单。如果使用 Visual Studio 开发 AI 项目,则可以通过 NuGet 程序包管理功能直接安装
    的头像 发表于 10-13 16:39 396次阅读
    <b class='flag-5'>OpenVINO</b>™  C# API详解与演示

    iPhone将增加对RCS消息的支持

    根据9to5Mac的一份报告(9to5mac.com/2023/11/16/apple-rcs-coming-to-iphone/),苹果表示,2024年,iPhone将增加对RCS消息的支持
    的头像 发表于 11-20 16:55 457次阅读