昇思MindSpore动静结合中list和dict方法实现

news2025/2/27 5:28:06

01 概述

静态图和动态图是神经学习框架中的重要概念,昇思MindSpore同时支持动态图和静态图两种模式,在动态图与静态图的结合方面做了很多工作。本文以昇思MindSpore框架中图模式下list和dict的实现方式为例,介绍昇思MindSpore框架中的动静结合知识。

02 背景知识

2.1 动态图与静态图

目前主流的神经学习框架大概可以分为静态图和动态图两种。

在动态图中,每次编译都会重新构建一个新的计算图。这意味着计算图的构建和计算同时发生(define by run),这种机制由于能够实时得到中间结果的值,使得调试更加容易,同时我们将大脑中的想法转化为代码方案也变得更加容易,对于编程实现来说更友好。动态图以PyTorch框架为代表。

在静态图中,会事先了解和定义好整个运算流,在运行前可以对图结构进行优化,可以获得更快的前向速度,从性能上来说更加高效。但是只有运行起来之后才能看到变量的值,无法像动态图一样随时拿到中间计算结果。静态图以早期的TensorFlow框架为代表。

2.2 昇思MindSpore中的动静结合

昇思MindSpore支持动态图和静态图两种模式,动态图通过解释执行,具有动态语法亲和性,表达灵活;静态图使用JIT编译优化执行,偏静态语法,在语法上有较多限制。动态图模式是昇思MindSpore的默认模式,主要用于调试等用途,而静态图模式拥有更高效的执行性能,主要用于部署。

昇思MindSpore提供了静态图和动态图统一的编码方式,大大增加了静态图和动态图的可兼容性,用户无需开发多套代码,仅变更一行代码便可切换静态图/动态图模式。例如,在静态图模式下,使用 context.set_context(mode=context.PYNATIVE_MODE) 切换为动态图(PyNative)模式; 同理,昇思MindSpore处于动态图(PyNative)模式时,可以通过 context.set_context(mode=context.GRAPH_MODE) 切换为静态图(Graph)模式。

为了提高动态图模式下的前向计算任务执行速度,昇思MindSpore提供了jit装饰器,可以通过修饰Python函数或者Python类的成员函数使其被编译成计算图,通过图优化等技术提高运行速度。昇思MindSpore支持在动态图下使用静态编译的方式来进行混合执行,通过使用jit装饰符来修饰需要用静态图来执行的函数对象,即可实现动态图和静态图的混合执行。

import numpy as np
import mindspore.ops as ops
import mindspore as ms

#设置运行模式为动态图模式
ms.set_context(mode=ms.PYNATIVE_MODE)

#使用装饰器,指定静态图模式下执行
@ms.jit
def add_func(x,y):
    return ops.add(x,y)

x = ms.Tensor(np.array([1.0, 2.0, 3.0]).astype(np.float32))
y = ms.Tensor(np.array([4.0, 5.0, 6.0]).astype(np.float32))

out = add_func(x,y)
print(out)

03 实现方案和过程

为了实现静态图模式(Graph 模式)和动态图模式(PyNative 模式)的灵活切换,部分动态图的语法需要昇思MindSpore在静态图下单独进行开发。为了提高运算效率,昇思MindSpore引入了Pybind11库,使Python代码可以方便的调用C++代码,一些重要的功能使用C++代码实现。

3.1 图模式下 list.extend 方法支持

list.extend(obj) 方法会在原list后追加obj list内容。在昇思MindSpore图模式中,该方法的实现是使用ListGetItem算子取出原list和objlist中的所有元素,将所有元素按顺序添加到一个std::vector中,再使用MakeList算子构建新list,并将该list返回,替代原list。关键代码如下所示。

FuncGraphPtr ListExtend::GenerateFuncGraph(const abstract::AbstractBasePtrList &args_list) {
  abstract::CheckArgsSize("ListExtend", args_list, 2);

  FuncGraphPtr ret = std::make_shared<FuncGraph>();
  ret->set_flag(FUNC_GRAPH_FLAG_CORE, true);
  ret->debug_info()->set_name("extend");

  std::vector<AnfNodePtr> elems;
  elems.push_back(NewValueNode(prim::kPrimMakeList));
  AddNodeToElems(args_list[0], ret, &elems);
  AddNodeToElems(args_list[1], ret, &elems);
  auto out = ret->NewCNode(elems);
  ret->set_output(out);
  return ret;
}

void ListExtend::AddNodeToElems(const AbstractBasePtr &arg, const FuncGraphPtr &ret, std::vector<AnfNodePtr> *elems) { 
  abstract::AbstractListPtr arg_list = dyn_cast<abstract::AbstractList>(arg);
  MS_EXCEPTION_IF_NULL(arg_list);
  int64_t len = SizeToLong(arg_list->size());
  AnfNodePtr arg_node = ret->add_parameter();
  for (int64_t i = 0; i < len; ++i) {
    auto value = ret->NewCNode({NewValueNode(prim::kPrimListGetItem), arg_node, NewValueNode(i)});
    elems->push_back(value);
  }
}

3.2 图模式下 list.extend 方法支持

list.count(item) 会统计item元素在原list中的数量。在图模式中,顺序遍历原list中的元素,逐个与obj进行比较,首先判断元素类型,Tensor类型单独处理,其余类型使用其各自对应的比较符号比较。关键代码如下所示。

FuncGraphPtr ListCount::GenerateFuncGraph(const abstract::AbstractBasePtrList &args_list) {
  const size_t list_count_args_size = 2;
  abstract::CheckArgsSize("ListCount", args_list, list_count_args_size);
  auto &list_input = args_list[0];
  auto &element_value = args_list[1];

  auto arg_list = dyn_cast_ptr<abstract::AbstractList>(list_input);
  MS_EXCEPTION_IF_NULL(arg_list);
  FuncGraphPtr ret = std::make_shared<FuncGraph>();
  ret->set_flag(FUNC_GRAPH_FLAG_CORE, true);
  ret->debug_info()->set_name("count");
  (void)ret->add_parameter();
  (void)ret->add_parameter();

  ValuePtr count_value = element_value->BuildValue();
  const auto &values = arg_list->elements();
  int64_t count = 0;
  for (auto value : values) {
    if (ComparesTwoValues(count_value, value->BuildValue())) {
      ++count;
    }
  }

  auto out = NewValueNode(MakeValue(count));
  ret->set_output(out);
  return ret;
}

3.3 图模式下 dict.fromkeys 方法支持

dict.fromkeys(seq[, value=None])根据给定的可迭代对象seq和value(默认为None),创建一个新的dict并返回。在图模式中,首先判断传入seq对象是否是支持的可迭代对象(目前支持list、tuple、dict、string),不支持将抛出异常。之后遍历该可迭代对象,判断每个元素是否为string类型,不通过将抛出异常。最后根据该key与传入的value值创建新的dict对象,并返回。关键代码如下所示。

FuncGraphPtr DictFromKeys::GenerateFuncGraph(const abstract::AbstractBasePtrList &args_list) {
  constexpr size_t dict_fromkeys_args_size = 3; 
  abstract::CheckArgsSize("DictFromKeys", args_list, dict_fromkeys_args_size);
  const auto &values = ParseIterableObject(args_list[1]);
  auto value_node = args_list[2]->BuildValue();
  MS_EXCEPTION_IF_NULL(value_node);

  FuncGraphPtr ret = std::make_shared<FuncGraph>();
  ret->set_flag(FUNC_GRAPH_FLAG_CORE, true);
  ret->debug_info()->set_name("fromkeys");
  (void)ret->add_parameter();
  (void)ret->add_parameter();
  (void)ret->add_parameter();

  std::vector<std::pair<std::string, ValuePtr>> key_values;
  for (auto &value : values) {
    auto key = value->BuildValue();
    if (!key->IsSameTypeId(StringImm::kTypeId)) {
      MS_LOG(EXCEPTION) << "The key should be string, but got " << key->type_name();
    }

    std::string key_node = GetValue<std::string>(key);
    (void)key_values.emplace_back(std::make_pair(key_node, value_node));
  }

  ret->set_output(NewValueNode(std::make_shared<ValueDictionary>(key_values)));
  return ret;
}

3.4 图模式下 dict.update 方法支持

dict.update(obj) 会在原dict后追加obj dict内容。在图模式中,首先创建一个AnfNodePtrList对象用来保存value值,并创建unordered_map对象记录dict key和value的index值,之后遍历原dict和obj dict,使用kPrimDictGetItem算子取出key对应的value值,并将value插入到AnfNodePtrList对象中,并将key和value index插入到unordered_map中,如存在重复key,则取出对应的index,替换AnfNodePtrList中对应的value。遍历完成后,使用kPrimMakeTuple算子和kPrimMakeDict算子创建新dict,使用该dict对象代替原dict对象。关键代码如下所示。

FuncGraphPtr DictUpdate::GenerateFuncGraph(const abstract::AbstractBasePtrList &args_list) {
  constexpr size_t dict_update_args_size = 2;
  abstract::CheckArgsSize("DictUpdate", args_list, dict_update_args_size);

  FuncGraphPtr ret = std::make_shared<FuncGraph>();
  ret->set_flag(FUNC_GRAPH_FLAG_CORE, true);
  ret->debug_info()->set_name("update");

  AnfNodePtrList key_inputs;
  AnfNodePtrList value_inputs;
  (void)key_inputs.emplace_back(NewValueNode(prim::kPrimMakeTuple));
  (void)value_inputs.emplace_back(NewValueNode(prim::kPrimMakeTuple));

  std::unordered_map<std::string, size_t> hash_map;
  AddNodeToLists(args_list[0], ret, &key_inputs, &value_inputs, &hash_map);
  AddNodeToLists(args_list[1], ret, &key_inputs, &value_inputs, &hash_map);

  ret->set_output(ret->NewCNode(
    {NewValueNode(prim::kPrimMakeDict), ret->NewCNode(std::move(key_inputs)), ret->NewCNode(std::move(value_inputs))}));
  return ret;
}

04 总结

首先感谢昇思MindSpore社区提供的这次机会,感谢在完成任务过程中导师的帮助。之前对开源的了解一直都是模糊的,通过这次机会,才让我了解到开源项目,并且加入到了开源贡献之中。在刚开始做任务的时候,读昇思MindSpore源码,不断地惊讶于它巧妙的设计,同时学习了深度框架的知识。在最后提交PR的过程中,使自己认识到代码规范和注释的细节,同时有很多专家会对代码的结构提出很多建议,在这个过程中学到了很多的知识,成长了很多。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/105294.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C与C++如何互相调用

个人主页&#xff1a;董哥聊技术我是董哥&#xff0c;嵌入式领域新星创作者创作理念&#xff1a;专注分享高质量嵌入式文章&#xff0c;让大家读有所得&#xff01;文章目录1、为什么会有差异&#xff1f;2、extern "C"3、C调用C正确方式4、C调用C5、总结在项目开发过…

[第十二届蓝桥杯/java/算法]C——卡片

&#x1f9d1;‍&#x1f393;个人介绍&#xff1a;大二软件生&#xff0c;现学JAVA、Linux、MySQL、算法 &#x1f4bb;博客主页&#xff1a;渡过晚枫渡过晚枫 &#x1f453;系列专栏&#xff1a;[编程神域 C语言]&#xff0c;[java/初学者]&#xff0c;[蓝桥杯] &#x1f4d6…

中外法律文献查找下载常用数据库大盘点

中外法律文献查找下载常用数据库有&#xff1a; 一、Westlaw&#xff08;法律全文数据库&#xff09; 是法律出版集团Thomson Legal and Regulator’s于1975年开发的&#xff0c;为国际法律专业人员提供的互联网的搜索工具。 Westlaw International其丰富的资源来自法律、法规…

图(Graph)详解 - 数据结构

文章目录&#xff1a;图的基本概念图的存储结构邻接矩阵邻接矩阵的实现邻接表邻接表实现图的遍历图的广度优先搜索&#xff08;BFS&#xff09;图的深度优先搜索&#xff08;DFS&#xff09;最小生成树Kruskal算法Prim算法最短路径单源最短路径 - Dijkstra算法单源最短路径 - B…

Linux学习-91-Discuz论坛安装

17.22 Discuz论坛安装 通过 Discuz! 搭建社区论坛、知识付费网站、视频直播点播站、企业网站、同城社区、小程序、APP、图片素材站&#xff0c;游戏交流站&#xff0c;电商购物站、小说阅读、博客、拼车系统、房产信息、求职招聘、婚恋交友等等绝大多数类型的网站。Discuz!自2…

《教养的迷思》

在读《穷查理宝典》时&#xff0c;查理芒格在有一讲&#xff0c;专门谈及《教养的迷思》一书&#xff0c;说到作者朱迪斯哈里斯。查理芒格认为哈里斯在探求真理的道路上走得很顺利&#xff0c;取得成功的因素之一就是她热衷于摧毁自己的观念。 朱迪斯在书的开端首先严肃地纠正了…

【案例教程】无人机生态环境监测、图像处理与GIS数据分析综合实践

【查看原文】无人机生态环境监测、图像处理与GIS数据分析综合实践技术应用 构建“天空地”一体化监测体系是新形势下生态、环境、水文、农业、林业、气象等资源环境领域的重大需求&#xff0c;无人机生态环境监测在一体化监测体系中扮演着极其重要的角色。通过无人机航空遥感技…

Fabric系列 - 多通道技术(Muti-channel)

可在节点&#xff0c;通道和联盟级别上配置。 一个Fabric网络中能够运行多个账本&#xff0c;每个通道间的逻辑相互隔离不受影响&#xff0c;如下图所示&#xff0c;每种颜色的线条代表一个逻辑上的通道&#xff0c;每个Peer节点可以加入不同的通道&#xff0c;每个通道都拥有…

AI编译器XLA调研

文章目录一、XLA简介二、XLA在TensorFlow中的应用2.1 XLA是什么&#xff1f;&#xff08;tensorflow\compiler\xla&#xff09;2.2 TensorFlow怎样转化为XLA &#xff08;tensorflow\compiler\tf2xla&#xff09;2.3 JIT(just in time) 即时编译 &#xff08;tensorflow\compil…

【大数据技术Hadoop+Spark】Flume、Kafka的简介及安装(图文解释 超详细)

Flume简介 Flume是Cloudera提供的一个高可用、高可靠、分布式的海量日志采集、聚合和传输的系统&#xff0c;Flume支持在日志系统中定制各类数据发送方&#xff0c;用于收集数据&#xff1b;同时&#xff0c;Flume提供对数据进行简单处理&#xff0c;并写到各种数据接受方&…

NLP学习笔记(四) Seq2Seq基本介绍

大家好&#xff0c;我是半虹&#xff0c;这篇文章来讲序列到序列模型 (Sequence To Sequence, Seq2Seq) 本文写作思路如下&#xff1a; 从循环神经网络的应用场景引入&#xff0c;介绍循环神经网络作为编码器和解码器使用&#xff0c;最后是序列到序列模型 在之前的文章中&am…

微信消息收发与微信内部emoji表情转义

微信消息收发与微信内部emoji表情转义 目录 微信内部emoji表情转义与消息收发 一、概述 二、常用标准emoji表情字符、微信内部转义符、unicode对照表 1、比如 2、微信聊天窗口emoji表情字符 2.1、PC端表情选择&#xff0c;01~03排&#xff1a; 2.2、PC端表情选择&#…

华为IMC培训——通信基础

目录 一、华为设备图标 二、数据的传递 三、专业术语 四、网络设备及相关知识 五、OSI七层模型 六、TCP和UDP数据报格式 七、TCP的三次握手 八、 TCP窗口滑动机制 一、华为设备图标 AP&#xff1a;相当于家用路由器一般配和AC使用。 AC和AP的区别_wangzhibo_csdn的博客…

创意被盗用,这3个加水印方法,让照片刻上我们专属印记

一般我们为了保护自己的图片不被别人盗用&#xff0c;都会选择在图片上刻上专属印记。那么便是加水印方法&#xff0c;它包含两种&#xff1a;文字水印和图片水印。想知道怎么给图片添加水印吗&#xff1f;其实有很多种法子可以做到&#xff0c;下面就由我来分享这3个简单好用的…

代码随想录刷题记录 day48 两个字符串的删除操作+编辑距离

代码随想录刷题记录 day48 两个字符串的删除操作编辑距离 583. 两个字符串的删除操作 思想 两个元素都能删除了&#xff0c;还是考虑第i-1个字符和第j-1个字符是不是相同的&#xff0c;不相同的话考虑三种情况&#xff0c;删除i-1&#xff1b;删除j-1&#xff0c;同时删除 1…

css实现鼠标禁用(鼠标滑过显示红色禁止符号)

css实现鼠标禁用&#xff08;鼠标滑过显示红色禁止符号&#xff09;创作背景css鼠标禁用创作背景 从本文开始&#xff0c;将会用三篇文章来一步一步实现vueantdts实战后台管理系统中table表格的不可控操作。中间会补充两篇css知识文章&#xff0c;方便后续功能的实现。实现表格…

非零基础自学Golang 第14章 反射 14.2 基本用法 14.2.2 获取类型的值 14.2.3 使用反射调用函数

非零基础自学Golang 文章目录非零基础自学Golang第14章 反射14.2 基本用法14.2.2 获取类型的值14.2.3 使用反射调用函数第14章 反射 14.2 基本用法 14.2.2 获取类型的值 Go语言使用reflect.TypeOf来获取类型信息&#xff0c;使用reflect.ValueOf来获取变量值的信息。 refle…

云原生|kubernetes|CKA真题解析-------(6-10题)

第六题&#xff1a; service配置 解析&#xff1a; 考察两个知识点&#xff1a; deployment控制器内的port命名 暴露一个pod内的端口到新建的服务内的 这里有一个需要注意的地方&#xff0c;没有告诉你deployment控制器在哪个namespace。假设这个front-end这个pod是在A这个…

前端CSS Flex布局8大重难点知识,收藏起来吧

2009年&#xff0c;W3C提出了一种新的方案—-Flex布局&#xff0c;可以简便、完整、响应式地实现各种页面布局。目前&#xff0c;它已经得到了所有浏览器的支持&#xff0c;这意味着&#xff0c;现在就能很安全地使用这项功能。 Flex布局将成为未来布局的首选方案。这也是学习前…

Spring之底层架构核心概念-BeanDefinition

目录1.什么是BeanDefinition&#xff1f;2.如何生成BeanDefinition?2.1. Component2.1. bean标签2.3. Bean注解2.4. AbstractBeanDefinition2.5. 利用BeanDefinition 读取器-解析类2.6. XmlBeanDefinitionReader - 解析 xml文件2.7. ClassPathBeanDefinitionScanner 扫描生成 …