昇思报错"The function construct need xx positional argument …"怎么办
1. 系统环境
Hardware Environment(Ascend/GPU/CPU): ALL
Software Environment:
MindSpore version (source or binary): 1.6.0 & Earlier versions
Python version (e.g., Python 3.7.5): 3.7.6
OS platform and distribution (e.g., Linux Ubuntu 16.04): Ubuntu
GCC/Compiler version (if compiled from source):
2. python代码样例
from mindspore.nn import Cell
class Net(Cell):
def construct(x):
return x
net = Net()
net(2)
3. 报错信息
Traceback (most recent call last):
File “error_map/01/param_not_match.py”, line 10, in
net(2)
File “/usr/local/python3.7/lib/python3.7/site-packages/mindspore/nn/cell.py”, line 469, in call
self._check_construct_args(*args, **kwargs)
File “/usr/local/python3.7/lib/python3.7/site-packages/mindspore/nn/cell.py”, line 400, in _check_construct_args
f"The function construct needs {positional_args} positional argument and {default_args} default "
TypeError: The function construct needs 0 positional argument and 0 default argument, but provided 1
4. 原因分析
首先查看报错信息“TypeError: The function construct needs 0 positional argument and 0 default argument, but provided 1”
报错信息直译为:函数construct
需要0个位置参数和0个默认参数,但提供了1个
为了理解报错信息的含义,需要解释两个名词positional argument
和default argument
。要解释这两个名词首先要理解什么是argument(调用时输入的实参,有具体的值),说argument就必须要说Parameter(函数定义时声明的形参,没有具体的值)。以样例代码为列函数def construct(x)
定义中的x
是Parameter, net(2)
中的2
是argument。positional argument
是需要通过输入顺序(位置)来识别具体输入和Parameter
绑定关系的argument。 Python官方资料中并没有default argument
这个概念,只有default value
;含有default value
的Parameter在函数调用时可以不输入对应的argument, 框架在函数调用时会使用default value
作为argument。
理解位置参数
和默认参数
后,可以将报错信息更直白表述为:类Net
的construct
函数需要0个入参,但提供了1个
这样一来文字本身的含义是清晰了, 但依然存在两个疑问:
- 什么时候如何调用了类
Net
的construct
函数? - 类
Net
的construct
函数原型def construct(x)
有一个入参数x
,为何报错信息胡扯需要0个入参?
疑问1的答案是:
MindSpore框架代码为类
nn.Cell
重写了魔法函数__call__
,并在__call__
中调用了construct
,重写__call__
的效果是可以像调用函数一样调用类实例,例如样例代码中的:net(2)
;感兴趣的同学可以自行查看框架发布包中nn.Cell.__call__
的定义。
疑问2的答案是:
construct
是通过Net
的Instance methods
机制调用的,construct
的首个入参是由Python框架插入的类实例(与函数声明中的第一个Parameter对应,一般叫作self, 样例中叫x),调用时输入的2
其实是它的第2个argument。经过python框架的调用原型为construct(net, 2)
,它有2个arguments。
用如下Python原生代码会报类似错误:TypeError: construct() takes 1 positional argument but 2 were given
class Net:
def construct(x):
print(str(x))
net = Net()
net.construct(1)
MindSpore的报错信息是站在直接调用Instance methods
角度来报的,它并不认为Python框架插入的类实例为用户输入argument,从def construct(x)
的声明来看,它不需要调用方提供arguments,所以样例代码中MindSpore报错:“TypeError: The function construct needs 0 positional argument and 0 default argument, but provided 1”
5. 解决方法
通过上一章节的分析可以看出def construct(x):
的定义是错误的,缺少了self
入参,其正确定义为:def construct(self, x):
6. 平台改进点
报错信息上尽量与原生python保持一致,方便开发者进行理解。
优化后报错信息如下:
Traceback (most recent call last):
File “/home/zhangzhaoju/ms_dev/error_map/01/param_not_match.py”, line 10, in
net(2)
File “/usr/local/python3.7/lib/python3.7/site-packages/mindspore/nn/cell.py”, line 475, in call
self._check_construct_args(*args, **kwargs)
File “/usr/local/python3.7/lib/python3.7/site-packages/mindspore/nn/cell.py”, line 402, in _check_construct_args
raise TypeError(f"Method construct() of class {self.class.name}, "
TypeError: Method construct() of class Net takes 0 positional arguments but 1 were given.
7. 总结
MindSpore前端语法是Python语法的子集, 撰写模型时需要遵循Python语法。学习一些python语言的书籍,对于MindSpore运行机制理解和问题定位很有帮助。
8. 参考文档
魔法函数原理:https://docs.python.org/3/reference/datamodel.html#special-method-names
实例函数原理:https://docs.python.org/3/reference/datamodel.html#the-standard-type-hierarchy (instanse method 章节)
9.工程案例
可以访问https://gitee.com/qmckw/mindspore_test/blob/master/%E6%AD%A3%E5%88%99%E5%8C%96%E5%AE%9E%E9%AA%8C.ipynb查看。