# Copyright 2024 Huawei Technologies Co., Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ============================================================================
"""Symbol implementation."""
__all__ = ['Symbol']
[docs]class Symbol:
r"""
Symbol is a data structure to indicate the symbolic info of shape.
For dynamic shape networks, compared with only setting the unknown dimensions ( ``None`` ) in `Tensor` , providing
more symbolic shape info can help the framework better optimize the computation graph, to improve the performance of
network execution.
Args:
max (int): The maximum length of this dimension, which is valid when it's greater than `min`. Default: ``0`` .
min (int): The minimum length of this dimension. Default: ``1`` .
divisor (int): The divisor( :math:`d` ). When `remainder` is 0, it means this dimension can be divided by
:math:`d` . Default: ``1`` .
remainder (int): The remainder( :math:`r` ) when symbol is represented by :math:`d * N + r, N \ge 1` .
Default: ``0`` .
unique (bool): When the symbol object is used multiple times, if `unique` is ``True`` , the shape items of this
symbol are considered to be same length, otherwise only symbol info is shared by multiple dimensions.
Default: ``False`` .
Outputs:
Symbol.
Raises:
TypeError: If `max`, `min`, `divisor`, `remainder` is not an int.
TypeError: If `unique` is not a bool.
ValueError: If `min` is not positive value.
ValueError: If `divisor` is not positive value.
ValueError: If `remainder` is not in the range :math:`[0, d)` .
Examples:
>>> import numpy as np
>>> import mindspore as ms
>>> from mindspore import nn, Tensor, Symbol
>>>
>>> class Net(nn.Cell):
... def __init__(self):
... super(Net, self).__init__()
... self.abs = ms.ops.Abs()
... def construct(self, x):
... return self.abs(x)
...
>>> net = Net()
>>> s1 = Symbol(divisor=8, remainder=1)
>>> s2 = Symbol(max=32, unique=True)
>>> dyn_t = Tensor(shape=(None, s1, s1, s2, s2), dtype=ms.float32)
>>> net.set_inputs(dyn_t)
>>> # the shape values of last two dimensions must be equal, because "s2" is set to "unique"
>>> net(Tensor(np.random.randn(1, 9, 17, 32, 32), dtype=ms.float32)).shape
(1, 9, 17, 32, 32)
>>> net(Tensor(np.random.randn(8, 25, 9, 30, 30), dtype=ms.float32)).shape
(8, 25, 9, 30, 30)
"""
def __init__(self, max=0, min=1, divisor=1, remainder=0, unique=False, **kawgs):
Symbol._check_args_type(max, min, divisor, remainder, unique)
if min <= 0:
raise ValueError("For 'Symbol', the 'min' value should be positive, but got {}".format(min))
if divisor <= 0:
raise ValueError("For 'Symbol', the 'divisor' value should be positive, but got {}".format(divisor))
if remainder < 0 or remainder >= divisor:
raise ValueError(
"For 'Symbol', the 'remainder' value should be in the range '[0, {})', but got {}".format(
divisor, remainder))
self.max = max
self.min = min
self.divisor = divisor
self.remainder = remainder
self.unique = unique
self.id = id(self)
def __str__(self):
return str(self.to_dict())
@staticmethod
def _check_args_type(maxv, minv, divisor, remainder, unique):
"""Check the type of arguments."""
if not isinstance(maxv, int):
raise TypeError(f"For 'Symbol', the argument 'max' must be int, but got {type(maxv)}")
if not isinstance(minv, int):
raise TypeError(f"For 'Symbol', the argument 'min' must be int, but got {type(minv)}")
if not isinstance(divisor, int):
raise TypeError(f"For 'Symbol', the argument 'divisor' must be int, but got {type(divisor)}")
if not isinstance(remainder, int):
raise TypeError(f"For 'Symbol', the argument 'remainder' must be int, but got {type(remainder)}")
if not isinstance(unique, bool):
raise TypeError(f"For 'Symbol', the argument 'unique' must be bool, but got {type(unique)}")
# pylint: disable=missing-docstring
def to_dict(self):
# Convert the symbolic info to dictionary.
# This method is not necessary to show in public api document, use comment instead of docstring.
res = {}
if self.max > self.min:
res["max"] = self.max
if self.min > self.divisor + self.remainder: # the symbol is "d * N + r" and N >= 1
res["min"] = self.min
if self.divisor != 1:
res["divisor"] = self.divisor
if self.remainder != 0:
res["remainder"] = self.remainder
if self.unique:
res["id"] = self.id
return res