Static Graph Syntax —— Python Statements
Simple Statements
raise Statements
Support the use of raise
to trigger an exception. raise
syntax format: raise[Exception [, args]]
. The Exception
in the statement is the type of the exception, and the args
is the user-supplied argument to the exception, usually a string or other object. The following types of errors are supported: NoExceptionType, UnknownError, ArgumentError, NotSupportError, NotExistsError, DeviceProcessError, AbortedError, IndexError, ValueError, TypeError, KeyError, AttributeError, NameError, AssertionError, BaseException, KeyboardInterrupt, Exception, StopIteration, OverflowError, ZeroDivisionError, EnvironmentError, IOError, OSError, ImportError, MemoryError, UnboundLocalError, RuntimeError, NotImplementedError, IndentationError, RuntimeWarning.
For example:
import mindspore.nn as nn
import mindspore as ms
class Net(nn.Cell):
def __init__(self):
super(Net, self).__init__()
def construct(self, x, y):
if x <= y:
raise ValueError("x should be greater than y.")
else:
x += 1
return x
ms.set_context(mode=ms.GRAPH_MODE)
net = Net()
net(ms.Tensor(-2), ms.Tensor(-1))
The output result:
ValueError: x should be greater than y.
assert Statements
Supports the use of assert for exception checking, assert
syntax format: assert[Expression [, args]]
, where Expression
is the judgment condition. If the condition is true, nothing will be done, while if the condition is false, an exception message of type AssertError
will be thrown. The args
are user-supplied exception arguments, which can usually be strings or other objects.
import mindspore.nn as nn
import mindspore as ms
class Net(nn.Cell):
def __init__(self):
super(Net, self).__init__()
def construct(self, x):
assert x in [2, 3, 4]
return x
ms.set_context(mode=ms.GRAPH_MODE)
net = Net()
net(ms.Tensor(-1))
Appears normally in the output:
AssertionError.
pass Statements
The pass
statement doesn’t do anything and is usually used as a placeholder to maintain structural integrity. For example:
import mindspore as ms
from mindspore import nn, set_context
set_context(mode=ms.GRAPH_MODE)
class Net(nn.Cell):
def construct(self, x):
i = 0
while i < 5:
if i > 3:
pass
else:
x = x * 1.5
i += 1
return x
net = Net()
ret = net(10)
print("ret:", ret)
The result is as follows:
ret: 50.625
return Statements
The return
statement usually returns the result to the place where it was called, and statements after the return
statement are not executed. If the return statement does not have any expression or the function does not have a return
statement, a None
object is returned by default. There can be more than one return
statement within a function, depending on the situation. For example:
import mindspore as ms
from mindspore import nn, set_context
set_context(mode=ms.GRAPH_MODE)
class Net(nn.Cell):
def construct(self, x):
if x > 0:
return x
else:
return 0
net = Net()
ret = net(10)
print("ret:", ret)
The result is as follows:
ret: 10
As above, there can be multiple return
statements in a control flow scenario statement. If there is no return
statement in a function, the None object is returned by default, as in the following use case:
from mindspore import jit, context
context.set_context(mode=context.GRAPH_MODE)
@jit
def foo():
x = 3
print("x:", x)
res = foo()
assert res is None
break Statements
The break
statement is used to terminate a loop statement, i.e., it stops execution of the loop statement even if the loop condition does not have a False
condition or if the sequence is not fully recursive, usually used in while
and for
loops. In nested loops, the break
statement stops execution of the innermost loop.
import mindspore as ms
from mindspore import nn, set_context
set_context(mode=ms.GRAPH_MODE)
class Net(nn.Cell):
def construct(self, x):
for i in range(8):
if i > 5:
x *= 3
break
x = x * 2
return x
net = Net()
ret = net(10)
print("ret:", ret)
The result is as follows:
ret: 1920
continue Statements
The continue
statement is used to jump out of the current loop statement and into the next round of the loop. This is different from the break
statement, which is used to terminate the entire loop statement. continue
is also used in while
and for
loops. For example:
import mindspore as ms
from mindspore import nn, set_context
set_context(mode=ms.GRAPH_MODE)
class Net(nn.Cell):
def construct(self, x):
for i in range(4):
if i > 2:
x *= 3
continue
return x
net = Net()
ret = net(3)
print("ret:", ret)
The result is as follows:
ret: 9
Compound Statements
Conditional Control Statements
if Statements
Usage:
if (cond): statements...
x = y if (cond) else z
Parameter: cond
– Variables of Bool
type and constants of Bool
, List
, Tuple
, Dict
and String
types are supported.
Restrictions:
If
cond
is not a constant, the variable or constant assigned to a same sign in different branches should have same data type. If the data type of assigned variables or constants isTensor
, the variables and constants should have same shape and element type.
Example 1:
import mindspore as ms
x = ms.Tensor([1, 4], ms.int32)
y = ms.Tensor([0, 3], ms.int32)
m = 1
n = 2
@ms.jit()
def test_cond(x, y):
if (x > y).any():
return m
else:
return n
ret = test_cond(x, y)
print('ret:{}'.format(ret))
The data type of m
returned by the if
branch and n
returned by the else
branch must be same.
The result is as follows:
ret:1
Example 2:
import mindspore as ms
x = ms.Tensor([1, 4], ms.int32)
y = ms.Tensor([0, 3], ms.int32)
m = 1
n = 2
@ms.jit()
def test_cond(x, y):
out = 3
if (x > y).any():
out = m
else:
out = n
return out
ret = test_cond(x, y)
print('ret:{}'.format(ret))
The variable or constant m
assigned to out
in if
branch and the variable or constant n
assigned to out in false
branch must have same data type.
The result is as follows:
ret:1
Example 3:
import mindspore as ms
x = ms.Tensor([1, 4], ms.int32)
y = ms.Tensor([0, 3], ms.int32)
m = 1
@ms.jit()
def test_cond(x, y):
out = 2
if (x > y).any():
out = m
return out
ret = test_cond(x, y)
print('ret:{}'.format(ret))
The variable or constant m
assigned to out
in if
branch and the variable or constant init
initially assigned to out
must have same data type.
The result is as follows:
ret:1
Loop Statements
for Statements
Usage:
for i in sequence statements...
for i in sequence statements... if (cond) break
for i in sequence statements... if (cond) continue
Parameter: sequence
– Iterative sequences (Tuple
, List
, range
and so on).
Restrictions:
The total number of graph operations is a multiple of number of iterations of the
for
loop. Excessive number of iterations of thefor
loop may cause the graph to occupy more memory than usage limit.The
for...else...
statement is not supported.
Example:
import numpy as np
import mindspore as ms
z = ms.Tensor(np.ones((2, 3)))
@ms.jit()
def test_cond():
x = (1, 2, 3)
for i in x:
z += i
return z
ret = test_cond()
print('ret:{}'.format(ret))
The result is as follows:
ret:[[7. 7. 7.]
[7. 7. 7.]]
while Statements
Usage:
while (cond) statements...
while (cond) statements... if (cond1) break
while (cond) statements... if (cond1) continue
Parameter: cond
– Variables of Bool
type and constants of Bool
, List
, Tuple
, Dict
and String
types are supported.
Restrictions:
If
cond
is not a constant, the variable or constant assigned to a same sign inside body ofwhile
and outside body ofwhile
should have same data type.If the data type of assigned variables or constants isTensor
, the variables and constants should have same shape and element type.The
while...else...
statement is not supported.
Example 1:
import mindspore as ms
m = 1
n = 2
@ms.jit()
def test_cond(x, y):
while x < y:
x += 1
return m
return n
ret = test_cond(1, 5)
print('ret:{}'.format(ret))
The data type of m
returned inside while
and data type of n
returned outside while
must have same data type.
The result is as follows:
ret:1
Example 2:
import mindspore as ms
m = 1
n = 2
def ops1(a, b):
return a + b
@ms.jit()
def test_cond(x, y):
out = m
while x < y:
x += 1
out = ops1(out, x)
return out
ret = test_cond(1, 5)
print('ret:{}'.format(ret))
The variable op1
assigned to out
inside while
and the variable or constant init
initially assigned to out
must have same data type.
The result is as follows:
ret:15
Function Definition Statements
def Keyword
def
is used to define a function, followed by the function identifier name and the original parentheses ()
, which may contain the function parameters.
Usage: def function_name(args): statements...
.
For example:
import mindspore as ms
def number_add(x, y):
return x + y
@ms.jit()
def test(x, y):
return number_add(x, y)
ret = test(1, 5)
print('ret:{}'.format(ret))
The result is as follows:
ret:6
Instructions:
The defined function supported has no
return
statement. That means the return value of default functions is None.Construct
function of the outermost network and the inner network function is support kwargs, like:def construct(**kwargs):
.Mixed use of variable argument and non-variable argument is supported, like:
def function(x, y, *args)
anddef function(x = 1, y = 1, **kwargs)
.
lambda Expression
A lambda
expression is used to generate an anonymous function. Unlike normal functions, it computes and returns only one expression. Usage: lambda x, y: x + y
.
For example:
import mindspore as ms
@ms.jit()
def test(x, y):
number_add = lambda x, y: x + y
return number_add(x, y)
ret = test(1, 5)
print('ret:{}'.format(ret))
The result is as follows:
ret:6
Partial function partial
Function: partial function, fixed function input parameter. Usage: partial(func, arg, ...)
.
Input parameter:
func
– function.arg
– One or more parameters to be fixed, support positional parameters and key-value pair parameters.
Return Value: Returns some functions with fixed input value.
The example is as follows:
import mindspore as ms
from mindspore import ops
def add(x, y):
return x + y
@ms.jit()
def test():
add_ = ops.partial(add, x=2)
m = add_(y=3)
n = add_(y=5)
return m, n
m, n = test()
print('m:{}'.format(m))
print('n:{}'.format(n))
The result is as follows:
m:5
n:7
Function Parameters
Default parameter value: The default value set to
Tensor
type data is currently not supported, andint
,float
,bool
,None
,str
,tuple
,list
,dict
type data is supported.Variable parameters: Inference and training of networks with variable parameters are supported.
Key-value pair parameter: Functions with key-value pair parameters cannot be used for backward propagation.
Variable key-value pair parameter: Functions with variable key-value pairs cannot be used for backward propagation.
List Comprehension and Generator Expression
Support for List Comprehension and Generator Expression. Support for constructing a new sequence.
List Comprehension
List comprehension are used to generate lists. Usage: [arg for loop if statements]
.
The example is as follows:
import mindspore as ms
@ms.jit()
def test():
l = [x * x for x in range(1, 11) if x % 2 == 0]
return l
ret = test()
print('ret:{}'.format(ret))
The result is as follows:
ret:[4, 16, 36, 64, 100]
Restrictions:
The use of multiple levels of nested iterators is not supported in graph mode.
The example usage of the restriction is as follows (two levels of iterators are used):
l = [y for x in ((1, 2), (3, 4), (5, 6)) for y in x]
An error will be prompted:
TypeError: The `generators` supports one `comprehension` in ListComp/GeneratorExp, but got 2 comprehensions.
Generator Expression
Generator expressions are used to generate lists. Usage: (arg for loop if statements)
.
For example:
import mindspore as ms
@ms.jit()
def test():
l = (x * x for x in range(1, 11) if x % 2 == 0)
return l
ret = test()
print('ret:{}'.format(ret))
The result is as follows:
ret:[4, 16, 36, 64, 100]
Usage restrictions are the same as list comprehension, i.e., the use of multiple levels of nested iterators is not supported in graph mode.
With Statement
In graph mode, the with
statement is supported with limitations. The with
statement requires that the object must have two magic methods: __enter__()
and __exit__()
.
For example:
import mindspore as ms
import mindspore.nn as nn
from mindspore import set_context
set_context(mode=ms.GRAPH_MODE)
@ms.jit_class
class Sample:
def __init__(self):
super(Sample, self).__init__()
self.num = ms.Tensor([2])
def __enter__(self):
return self.num * 2
def __exit__(self, exc_type, exc_value, traceback):
return self.num * 4
class TestNet(nn.Cell):
def construct(self):
res = 1
obj = Sample()
with obj as sample:
res += sample
return res, obj.num
test_net = TestNet()
out1, out2 = test_net()
print("out1:", out1)
print("out2:", out2)
The result is as follows:
out1: [5]
out2: [2]