小孢子的神奇之旅-如何阅读MindSpore报错信息(3)

老子曰:一生二,二生三,三生万物。本孢的第三篇分享选在2022第一天,希望2022可以是生机无限的一年。上回书我们用三步论+翘脚论解决了一个nn算子问题,所谓站的高看的远,翘脚论的精髓在于尝试了解一些系统的内部原理,这样问题处理就不再像它看起来的那么难。接着上回书挖的坑继续唠扯MindSpore报错的那些事。

什么是Cell

先看官网怎么描述Cell

如果熟悉pytorch,Cell的定位与pytorch的nn.Module是一样的,都是用来定义网络的接口,从这个描述可以提取一些价值信息:

• 是网络的基本单元:意味着一个网络应该是由一个或者多个Cell组成。

• 用户自定义网络需要继承Cell类:说明Cell类是用户自定义网络的编程接口。

如果觉得有点难理解,可以把MindSpore想象成一个3D打印机,Cell就是模型设计软件,通过在Cell中完成模型设计,MindSpore就可以根据设计生产出你需要的模型。或者更直白把Cell理解为一个画板,在画板里边画了啥,最终打印机就会把作品打印出来,是用你的智慧操控MindSpore创作艺术的入口。

Graph模式与PyNative模式

如果你对深度学习框架有一定的了解,你应该听说过深度学习框架的两种运行模式,一种是静态图模式,一种是动态图模式。静态图模式,先进行将网络编译成图,然后按照图结构完成执行。动态图模式并不会先编译生成图结构,而是按照代码顺序依次执行。

一个歪例子,可以想象成物流公司运货,静态图模式就是货车在出发前已经规划了本次运输所有站点的路线图,这样可以提前规划出最优线路。动态图模式则是货车出发前并不知道应该去哪里,只有出发后才知道去哪个站点,在运货途中可以灵活的转变线路。

MindSpore同时支持静态图与动态图模式,被分别叫做Graph模式和PyNative模式。从两种模式的原理可见,Graph模式可以着眼全局,能在执行前进行深度优化这样而带来更好的执行性能,而为着眼全局的代价就是必须遵从一些规则要求(例如:静态图语法),且有较长的编译过程,这些代价也就带来的网络的编写与调试困难。PyNative模式则刚好相反,执行性能弱于Graph模式,但语法灵活更为方便用户编写和调试网络。

那应该选择哪种模式呢,两把锤子,一个势大力沉、能干重活,但用起来要多使点力气。一个小巧灵活多功能,但干不了太重的活。所以选哪种还是要根据你所要训练的网络的诉求来。当然作为一个人类高质量用户,我们需要的是要重量时有重量,要灵活时有灵活,是否可以有一种模式同时具备这两种特质。对于这种要求,老人家孟子已经曰过了 “鱼,我所欲也,熊掌亦我所欲也;二者不可得兼,舍鱼而取熊掌者也”,当前MindSpore也还没办法鱼与熊掌兼得,但可以提供给你灵活切换的手段,虽然还不完善。

如果对这个话题感兴趣,推荐读下MindSpore总架构师对动静图的分析https://zhuanlan.zhihu.com/p/416643687

写到这里才算完成本次想要分享内容的铺垫,现在从报错的角度来分析下两种模式下的一些特点。

如何通过报错区分两种运行模式

实际上报错信息中并没有直接的信息给出运行模式,这里本孢尝试了一个曲线的方法。先来个翘脚论,看看框架的Cell的源码,Cell的__call__函数是网络执行必然调用,其中可以看到Graph mode 和 PyNative mode 执行的是不同分支代码。

def __call__(self, *args, **kwargs):
……
# Run in Graph mode.
if context._get_mode() == context.GRAPH_MODE:
……
out = self.compile_and_run(*args)
return out
……
# Run in PyNative mode.
……
with self.CellGuard():
try:
output = self.run_construct(cast_inputs, kwargs)
except Exception as err:
_pynative_executor.clear_res()
raise err
……

这样就可以通过堆栈的报错信息来判断是哪种执行模式,以上篇分享的报错信息为例,我们可以看到调用了函数self.compile_and_run(*args),此函数为图模式下执行的函数,由此可判断这个报错是图模式下执行的报错。

Traceback (most recent call last):
File "test1.py", line 26, in <module>
output = net(x)
File "/root/anaconda3/envs/test/lib/python3.7/site-packages/mindspore/nn/cell.py", line 479, in __call__
out = self.compile_and_run(*args)
File "/root/anaconda3/envs/test/lib/python3.7/site-packages/mindspore/nn/cell.py", line 802, in compile_and_run
……
arg_name, prim_name, rel_str, arg_value, type(arg_value).__name__))
ValueError: `axis` in `ReduceMean` should be in range of [-4, 4), but got 5.000e+00 with type `int`.

另外一种直接的方法,是可通过MindSpore的context API的get_context,执行

context.get_context("mode")

关于The function call stack

在上次分享的报错中,除了python的堆栈信息外,你会发现还有一个叫做“The function call stack”的堆栈信息,如下:

The function call stack (See file '/root/mindspore_test/rank_0/om/analyze_fail.dat' for more details):
# 0 In file /root/anaconda3/envs/test/lib/python3.7/site-packages/mindspore/nn/layer/math.py(1003)
if tensor_dtype == mstype.float16:
# 1 In file /root/anaconda3/envs/test/lib/python3.7/site-packages/mindspore/nn/layer/math.py(1007)
if not self.keep_dims:
# 2 In file /root/anaconda3/envs/test/lib/python3.7/site-packages/mindspore/nn/layer/math.py(1005)
mean = self.reduce_mean(x, self.axis)
^

那这个堆栈又是哪来的?我们前边提到过Graph模式,网络会先编译生成图结构,然后再执行图来完成训练。那这里就有个问题,如果图中某个节点执行失败,我们如何找到这个节点是哪行代码产生的呢?为了解决这个问题,MindSpore提供了静态图节点的跟踪机制,“The function call stack”这个堆栈就是记录图中的节点是如何从代码转化为图中节点的过程。我们可以通过这个堆栈找到这个算子是怎么从代码生成的,从而找到出问题的代码。以这个问题为例,出错的reduce_mean算子,来源于mindspore/nn/layer/math.py的1005行,也就是上次分享看到的nn接口Moments的代码。我们理解Cell概念后,你会发现Moments也是继承了Cell而实现的类,换句话Moments也可以看成是一个由框架定义的网络,当这个网络在静态图执行时出现报错,我们就可以通过“The function call stack”来定位到具体的代码行。同理用户继承Cell类自定义的网络也可以用此方法来定位静态图场景下的报错问题。

The function call stack (See file '/root/mindspore_test/rank_0/om/analyze_fail.dat' for more details):

另外你可能注意到报错中有这么一条描述,analyze_fail.dat详细的记录了出错节点的产生过程,对于一些复杂问题的定位比较有帮忙,这个孢子会做专题分享,如果急着看,可参考官网的说明:

https://www. mindspore.cn/docs/progr amming_guide/zh- CN/r1.5/read_ir_files.html?highlight=analyze_fail.dat

新年第一天,新年贺词:

“让我们一起向未来!祝福国泰民安!”

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值