# 使用SymbolTree.get\_network处理conv2d算子时报错NameError:name "Cell" is not defined

**1. 系统环境**

硬件环境\(Ascend/GPU/CPU\): CPU

软件环境: MindSpore 版本: 2.0.0

执行模式（静态图/动态图）： 不限

Python 版本: 3.9

操作系统平台: linux

**2. 报错信息**

2.1 问题描述

在执行stree.get\_network\(\)语句时报错，报错信息如下图所示：

2.2 报错信息

![](figures/zh-cn_image_0000002135151189.png)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
```

