1 系统环境
硬件环境(Ascend/GPU/CPU): CPU
MindSpore版本: mindspore=2.0
执行模式(PyNative/ Graph):不限
Python版本: Python=3.9
操作系统平台: 不限
2 报错信息
2.1 问题描述
在执行stree.get_network()语句时报错,报错信息如下图所示:
2.2 报错信息
2.3 脚本代码
import mindspore.nn as nn
from mindspore.rewrite import SymbolTree
old_model=nn.Conv2d(3,64,1,1)
stree = SymbolTree.create(old_model)
copy_model = stree.get_network()
3 根因分析
官网文档
涉及两个接口create 和 get_network
首先看Conv2d 继承了_Conv,_Conv又继承了Cell, 因此SymbolTree.create(old_model)old_model也是个Cell对象,因此不会报错。
class Conv2d(_Conv):
class _Conv(Cell):
报的错是get_network返回的。获取SymbolTree所对应的生成的网络对象。
def _get_cls_through_file(self):
"""
Load rewritten network class of current SymbolTree.
1. Get source code of current SymbolTree.
2. Saving source code to a tempfile.
3. Import rewritten network class using "__import__" function.
Returns:
A class handle.
"""
self._update_container()
file_path = os.getcwd()
file_path = os.path.join(file_path, "rewritten_network")
if not os.path.exists(file_path):
os.mkdir(file_path)
file_name = "{0}_{1}.py".format(self._opt_cls_name, id(self))
network_file = os.path.join(file_path, file_name)
with os.fdopen(os.open(network_file, os.O_WRONLY | os.O_CREAT, stat.S_IRWXU), 'wb') as f:
source = self.get_code()
f.write(source.encode('utf-8'))
f.flush()
os.fsync(f)
调用的是上面的函数,从当前网络中获取所对应的生成的网络对象的源码,然后再进行导入。
问题就出在这,自动生成的代码如下。
import sys
sys.path.append('C:\\Users\\yuany\\.conda\\envs\\mindspore_py39\\lib\\site-packages\\mindspore\\nn\\layer')
import mindspore
import numpy as np
from mindspore._extends import cell_attr_register
class _Conv(Cell):
'\n Applies a N-D convolution over an input signal composed of several input planes.\n '
def __init__(self, obj):
super(_Conv, self).__init__()
for (key, value) in obj.__dict__.items():
setattr(self, key, value)
def construct(self, *inputs):
'Must be overridden by all subclasses.'
raise NotImplementedError
def extend_repr(self):
s = 'input_channels={}, output_channels={}, kernel_size={}, stride={}, pad_mode={}, padding={}, dilation={}, group={}, has_bias={}, weight_init={}, bias_init={}, format={}'.format(self.in_channels, self.out_channels, self.kernel_size, self.stride, self.pad_mode, self.padding, self.dilation, self.group, self.has_bias, self.weight_init, self.bias_init, self.data_format)
return s
class Conv2dOpt(_Conv):
'\n Calculates the 2D convolution on the input tensor.\n The input is typically of shape :math:`(N, C_{in}, H_{in}, W_{in})`,\n where :math:`N` is batch size, :math:`C_{in}` is a number of channels,\n :math:`H_{in}, W_{in}` are the height and width of the feature layer respectively.\n For the tensor of each batch, its shape is :math:`(C_{in}, H_{in}, W_{in})`, the formula is defined as:\n\n .. math::\n\n \\text{out}(N_i, C_{\\text{out}_j}) = \\text{bias}(C_{\\text{out}_j}) +\n \\sum_{k = 0}^{C_{in} - 1} \\text{ccor}({\\text{weight}(C_{\\text{out}_j}, k), \\text{X}(N_i, k)})\n\n where :math:`ccor` is the `cross-correlation <https://en.wikipedia.org/wiki/Cross-correlation>`_,\n :math:`C_{in}` is the channel number of the input, :math:`out_{j}` corresponds to the :math:`j`-th channel of\n the output and :math:`j` is in the range of :math:`[0, C_{out}-1]`. :math:`\\text{weight}(C_{\\text{out}_j}, k)`\n is a convolution kernel slice with shape :math:`(\\text{kernel_size[0]}, \\text{kernel_size[1]})`,\n where :math:`\\text{kernel_size[0]}` and :math:`\\text{kernel_size[1]}` are the height and width of the convolution\n kernel respectively. :math:`\\text{bias}` is the bias parameter and :math:`\\text{X}` is the input tensor.\n In this case, `data_format` of the input tensor is \'NCHW\' and the shape of full convolution kernel is\n :math:`(C_{out}, C_{in} / \\text{group}, \\text{kernel_size[0]}, \\text{kernel_size[1]})`,\n where `group` is the number of groups to split the input `x` in the channel dimension. If `data_format` of the\n input tensor is \'NHWC\', the shape of full convolution kernel will be\n :math:`(C_{out}, \\text{kernel_size[0]}, \\text{kernel_size[1]}), C_{in} / \\text{group}`.\n\n For more details, please refers to the paper `Gradient Based Learning Applied to Document\n Recognition <http://vision.stanford.edu/cs598_spring07/papers/Lecun98.pdf>`_.\n\n Note:\n On Ascend platform, only group convolution in depthwise convolution scenarios is supported.\n That is, when `group>1`, condition `in\\_channels` = `out\\_channels` = `group` must be satisfied.\n\n Args:\n in_channels (int): The channel number of the input tensor of the Conv2d layer.\n out_channels (int): The channel number of the output tensor of the Conv2d layer.\n kernel_size (Union[int, tuple[int]]): Specifies the height and width of the 2D convolution kernel.\n The data type is an integer or a tuple of two integers. An integer represents the height\n and width of the convolution kernel. A tuple of two integers represents the height\n and width of the convolution kernel respectively.\n stride (Union[int, tuple[int]]): The movement stride of the 2D convolution kernel.\n The data type is an integer or a tuple of two integers. An integer represents the movement step size\n in both height and width directions. A tuple of two integers represents the movement step size in the height\n and width directions respectively. Default: 1.\n pad_mode (str): Specifies padding mode. The optional values are\n "same", "valid", "pad". Default: "same".\n\n - same: The width of the output is the same as the value of the input divided by `stride`.\n If this mode is set, the value of `padding` must be 0.\n\n - valid: Returns a valid calculated output without padding. Excess pixels that do not satisfy the\n calculation will be discarded. If this mode is set, the value of `padding` must be 0.\n\n - pad: Pads the input. Padding `padding` size of zero on both sides of the input.\n If this mode is set, the value of `padding` must be greater than or equal to 0.\n\n padding (Union[int, tuple[int]]): The number of padding on the height and width directions of the input.\n The data type is an integer or a tuple of four integers. If `padding` is an integer,\n then the top, bottom, left, and right padding are all equal to `padding`.\n If `padding` is a tuple of 4 integers, then the top, bottom, left, and right padding\n is equal to `padding[0]`, `padding[1]`, `padding[2]`, and `padding[3]` respectively.\n The value should be greater than or equal to 0. Default: 0.\n dilation (Union[int, tuple[int]]): Dilation size of 2D convolution kernel.\n The data type is an integer or a tuple of two integers. If :math:`k > 1`, the kernel is sampled\n every `k` elements. The value of `k` on the height and width directions is in range of [1, H]\n and [1, W] respectively. Default: 1.\n group (int): Splits filter into groups, `in_channels` and `out_channels` must be\n divisible by `group`. If the group is equal to `in_channels` and `out_channels`,\n this 2D convolution layer also can be called 2D depthwise convolution layer. Default: 1.\n has_bias (bool): Whether the Conv2d layer has a bias parameter. Default: False.\n weight_init (Union[Tensor, str, Initializer, numbers.Number]): Initialization method of weight parameter.\n It can be a Tensor, a string, an Initializer or a numbers.Number. When a string is specified,\n values from \'TruncatedNormal\', \'Normal\', \'Uniform\', \'HeUniform\' and \'XavierUniform\' distributions as well\n as constant \'One\' and \'Zero\' distributions are possible. Alias \'xavier_uniform\', \'he_uniform\', \'ones\'\n and \'zeros\' are acceptable. Uppercase and lowercase are both acceptable. Refer to the values of\n Initializer for more details. Default: \'normal\'.\n bias_init (Union[Tensor, str, Initializer, numbers.Number]): Initialization method of bias parameter.\n Available initialization methods are the same as \'weight_init\'. Refer to the values of\n Initializer for more details. Default: \'zeros\'.\n data_format (str): The optional value for data format, is \'NHWC\' or \'NCHW\'.\n Default: \'NCHW\'.\n\n Inputs:\n - **x** (Tensor) - Tensor of shape :math:`(N, C_{in}, H_{in}, W_{in})` \\\n or :math:`(N, H_{in}, W_{in}, C_{in})`.\n\n Outputs:\n Tensor of shape :math:`(N, C_{out}, H_{out}, W_{out})` or :math:`(N, H_{out}, W_{out}, C_{out})`.\n\n pad_mode is \'same\':\n\n .. math::\n \\begin{array}{ll} \\\\\n H_{out} = \\left \\lceil{\\frac{H_{in}}{\\text{stride[0]}}} \\right \\rceil \\\\\n W_{out} = \\left \\lceil{\\frac{W_{in}}{\\text{stride[1]}}} \\right \\rceil \\\\\n \\end{array}\n\n pad_mode is \'valid\':\n\n .. math::\n \\begin{array}{ll} \\\\\n H_{out} = \\left \\lceil{\\frac{H_{in} - \\text{dilation[0]} \\times (\\text{kernel_size[0]} - 1) }\n {\\text{stride[0]}}} \\right \\rceil \\\\\n W_{out} = \\left \\lceil{\\frac{W_{in} - \\text{dilation[1]} \\times (\\text{kernel_size[1]} - 1) }\n {\\text{stride[1]}}} \\right \\rceil \\\\\n \\end{array}\n\n pad_mode is \'pad\':\n\n .. math::\n \\begin{array}{ll} \\\\\n H_{out} = \\left \\lfloor{\\frac{H_{in} + padding[0] + padding[1] - (\\text{kernel_size[0]} - 1) \\times\n \\text{dilation[0]} - 1 }{\\text{stride[0]}} + 1} \\right \\rfloor \\\\\n W_{out} = \\left \\lfloor{\\frac{W_{in} + padding[2] + padding[3] - (\\text{kernel_size[1]} - 1) \\times\n \\text{dilation[1]} - 1 }{\\text{stride[1]}} + 1} \\right \\rfloor \\\\\n \\end{array}\n\n Raises:\n TypeError: If `in_channels`, `out_channels` or `group` is not an int.\n TypeError: If `kernel_size`, `stride`, `padding` or `dilation` is neither an int not a tuple.\n ValueError: If `in_channels`, `out_channels`, `kernel_size`, `stride` or `dilation` is less than 1.\n ValueError: If `padding` is less than 0.\n ValueError: If `pad_mode` is not one of \'same\', \'valid\', \'pad\'.\n ValueError: If `padding` is a tuple whose length is not equal to 4.\n ValueError: If `pad_mode` is not equal to \'pad\' and `padding` is not equal to (0, 0, 0, 0).\n ValueError: If `data_format` is neither \'NCHW\' not \'NHWC\'.\n\n Supported Platforms:\n ``Ascend`` ``GPU`` ``CPU``\n\n Examples:\n >>> net = nn.Conv2d(120, 240, 4, has_bias=False, weight_init=\'normal\')\n >>> x = Tensor(np.ones([1, 120, 1024, 640]), mindspore.float32)\n >>> output = net(x).shape\n >>> print(output)\n (1, 240, 1024, 640)\n '
@cell_attr_register
def __init__(self, obj):
super(Conv2dOpt, self).__init__(obj)
for (key, value) in obj.__dict__.items():
setattr(self, key, value)
def construct(self, x):
self_weight = self.weight
output = self.conv2d(x, self_weight)
# If node has been replaced by False branch.
return output
以上代码的路径是在当前代码的rewritten_network目录下。
从上面的代码可以看出,它把nn.Conv2d(3,64,1,1)作为网络,获取的是nn.Conv2d的定义。
而nn.Conv2d是系统定义的,所以导入肯定会出错。即使解决Cell的导入问题,最终代码也不能运行,因为会有循环导入的问题存在。
4 解决方案
创建一个网络,然后再进行create操作。
import mindspore.nn as nn
from mindspore.rewrite import SymbolTree
class Net(nn.Cell):
def construct(self, x):
x = nn.Conv2d(3, 64, 1, 1)(x)
return x
old_model = Net()
stree = SymbolTree.create(old_model)
copy_model = stree.get_network()
运行无报错。
rewritten_network下生成的代码如下:可以看出自动获取的网络对象的定义代码是正确的。
import sys
sys.path.append('D:\\f')
import mindspore
from mindspore import nn
import mindspore.nn as nn
import numpy as np
class NetOpt(nn.Cell):
def __init__(self, obj):
super().__init__()
for (key, value) in obj.__dict__.items():
setattr(self, key, value)
def construct(self, x):
x_1 = nn.Conv2d(3, 64, 1, 1)(x)
return x_1



