MindSpore静态图语法支持
MindSpore靜態圖語法支持
概述
在Graph模式下,Python代碼并不是由Python解釋器去執行,而是將代碼編譯成靜態計算圖,然后執行靜態計算圖。
關于Graph模式和計算圖,可參考文檔:https://www.mindspore.cn/tutorial/training/zh-CN/r1.1/advanced_use/debug_in_pynative_mode.html
當前僅支持編譯@ms_function裝飾器修飾的函數、Cell及其子類的實例。 對于函數,則編譯函數定義;對于網絡,則編譯construct方法及其調用的其他方法或者函數。
ms_function使用規則可參考文檔:https://www.mindspore.cn/doc/api_python/zh-CN/r1.1/mindspore/mindspore.html#mindspore.ms_function
Cell定義可參考文檔:https://www.mindspore.cn/doc/programming_guide/zh-CN/r1.1/cell.html
由于語法解析的限制,當前在編譯構圖時,支持的數據類型、語法以及相關操作并沒有完全與Python語法保持一致,部分使用受限。
本文主要介紹,在編譯靜態圖時,支持的數據類型、語法以及相關操作,這些規則僅適用于Graph模式。
以下所有示例都運行在Graph模式下的網絡中,為了簡潔,并未將網絡的定義都寫出來。
數據類型
Python內置數據類型
當前支持的Python內置數據類型包括:Number、String、List、Tuple和Dictionary。
Number
支持int、float、bool,不支持complex(復數)。
支持在網絡里定義Number,即支持語法:y = 1、y = 1.2、 y = True。
不支持在網絡里強轉Number,即不支持語法:y = int(x)、y = float(x)、y = bool(x)。
String
支持在網絡里構造String,即支持語法y = “abcd”。
不支持在網絡里強轉String,即不支持語法 y = str(x)。
List
支持在網絡里構造List,即支持語法y = [1, 2, 3]。
不支持在網絡里強轉List,即不支持語法y = list(x)。
計算圖中最終需要輸出的List會轉換為Tuple輸出。
? 支持接口
append: 向list里追加元素。
示例如下:
x = [1, 2, 3]
x.append(4)
結果如下:
x: (1, 2, 3, 4)
? 支持索引取值和賦值
支持單層和多層索引取值以及賦值。
取值和賦值的索引值僅支持int。
賦值時,所賦的值支持Number、String、Tuple、List、Tensor。
示例如下:
x = [[1, 2], 2, 3, 4]
y = x[0][1]
x[1] = Tensor(np.array([1, 2, 3]))
x[2] = “ok”
x[3] = (1, 2, 3)
x[0][1] = 88
結果如下:
y: 2
x: ([1, 88], Tensor(shape=[3], dtype=Int64, value=[1, 2, 3]), ‘ok’, (1, 2, 3))
Tuple
支持在網絡里構造Tuple,即支持語法y = (1, 2, 3)。
不支持在網絡里強轉Tuple,即不支持語法y = tuple(x)。
? 支持索引取值
索引值支持int、slice、Tensor,也支持多層索引取值,即支持語法data = tuple_x[index0][index1]…。
索引值為Tensor有如下限制:
o tuple里存放的都是Cell,每個Cell要在tuple定義之前完成定義,每個Cell的入參個數、入參類型和入參shape要求一致,每個Cell的輸出個數、輸出類型和輸出shape也要求一致。
o 索引Tensor是一個dtype為int32的標量Tensor,取值范圍在[-tuple_len, tuple_len)。
o 該語法不支持if、while、for控制流條件為變量的運行分支,僅支持控制流條件為常量。
o 僅支持GPU后端。
int、slice索引示例如下:
x = (1, (2, 3, 4), 3, 4, Tensor(np.array([1, 2, 3])))
y = x[1][1]
z = x[4]
m = x[1:4]
結果如下:
y: 3
z: Tensor(shape=[3], dtype=Int64, value=[1, 2, 3])
m: (2, 3, 4), 3, 4)
Tensor索引示例如下:
class Net(nn.Cell):
def init(self):
super(Net, self).init()
self.relu = nn.ReLU()
self.softmax = nn.Softmax()
self.layers = (self.relu, self.softmax)
def construct(self, x, index):ret = self.layers[index](x)return ret
Dictionary
支持在網絡里構造Dictionary,即支持語法y = {“a”: 1, “b”: 2},當前僅支持String作為key值。
計算圖中最終需要輸出的Dictionary,會取出所有的value組成Tuple輸出。
? 支持接口
keys:取出dict里所有的key值,組成Tuple返回。
values:取出dict里所有的value值,組成Tuple返回。
示例如下:
x = {“a”: Tensor(np.array([1, 2, 3])), “b”: Tensor(np.array([4, 5, 6])), “c”: Tensor(np.array([7, 8, 9]))}
y = x.keys()
z = x.values()
結果如下:
y: (“a”, “b”, “c”)
z: (Tensor(shape=[3], dtype=Int64, value=[1, 2, 3]), Tensor(shape=[3], dtype=Int64, value=[4, 5, 6]), Tensor(shape=[3], dtype=Int64, value=[7, 8, 9]))
? 支持索引取值和賦值
取值和賦值的索引值都僅支持String。賦值時,所賦的值支持Number、Tuple、Tensor。
示例如下:
x = {“a”: Tensor(np.array([1, 2, 3])), “b”: Tensor(np.array([4, 5, 6])), “c”: Tensor(np.array([7, 8, 9]))}
y = x[“b”]
x[“a”] = (2, 3, 4)
結果如下:
y: Tensor(shape=[3], dtype=Int64, value=[4, 5, 6])
x: {“a”: (2, 3, 4), Tensor(shape=[3], dtype=Int64, value=[4, 5, 6]), Tensor(shape=[3], dtype=Int64, value=[7, 8, 9])}
MindSpore自定義數據類型
當前MindSpore自定義數據類型包括:Tensor、Primitive和Cell。
Tensor
當前不支持在網絡里構造Tensor,即不支持語法x = Tensor(args…)。
可以通過@constexpr裝飾器修飾函數,在函數里生成Tensor。
關于@constexpr的用法可參考:https://www.mindspore.cn/doc/api_python/zh-CN/r1.1/mindspore/ops/mindspore.ops.constexpr.html
對于網絡中需要用到的常量Tensor,可以作為網絡的屬性,在init的時候定義,即self.x = Tensor(args…),然后在construct里使用。
如下示例,通過@constexpr生成一個shape = (3, 4), dtype = int64的Tensor。
@constexpr
def generate_tensor():
return Tensor(np.ones((3, 4)))
下面將介紹下Tensor支持的屬性、接口、索引取值和索引賦值。
? 支持屬性:
shape:獲取Tensor的shape,返回一個Tuple。
dtype:獲取Tensor的數據類型,返回一個MindSpore定義的數據類型。
? 支持接口:
all:對Tensor通過all操作進行歸約,僅支持Bool類型的Tensor。
any:對Tensor通過any操作進行歸約,僅支持Bool類型的Tensor。
view:將Tensorreshape成輸入的shape。
expand_as:將Tensor按照廣播規則擴展成與另一個Tensor相同的shape。
示例如下:
x = Tensor(np.array([[True, False, True], [False, True, False]]))
x_shape = x.shape
x_dtype = x.dtype
x_all = x.all()
x_any = x.any()
x_view = x.view((1, 6))
y = Tensor(np.ones((2, 3), np.float32))
z = Tensor(np.ones((2, 2, 3)))
y_as_z = y.expand_as(z)
結果如下:
x_shape: (2, 3)
x_dtype: Bool
x_all: Tensor(shape=[], dtype=Bool, value=False)
x_any: Tensor(shape=[], dtype=Bool, value=True)
x_view: Tensor(shape=[1, 6], dtype=Bool, value=[[True, False, True, False, True, False]])
y_as_z: Tensor(shape=[2, 2, 3], dtype=Float32, value=[[[1.0, 1.0, 1.0], [1.0, 1.0, 1.0]], [[1.0, 1.0, 1.0], [1.0, 1.0, 1.0]]])
? 索引取值
索引值支持int、True、None、slice、Tensor、Tuple。
o int索引取值
支持單層和多層int索引取值,單層int索引取值:tensor_x[int_index],多層int索引取值:tensor_x[int_index0][int_index1]…。
int索引取值操作的是第0維,索引值小于第0維長度,在取出第0維對應位置數據后,會消除第0維。
例如,如果對一個shape為(3, 4, 5)的tensor進行單層int索引取值,取得結果的shape是(4, 5)。
多層索引取值可以理解為,后一層索引取值在前一層索引取值結果上再進行int索引取值。
示例如下:
tensor_x = Tensor(np.arange(2 * 3 * 2).reshape((2, 3, 2)))
data_single = tensor_x[0]
data_multi = tensor_x[0][1]
結果如下:
data_single: Tensor(shape=[3, 2], dtype=Int64, value=[[0, 1], [2, 3], [4, 5]])
data_multi: Tensor(shape=[2], dtype=Int64, value=[2, 3])
o True索引取值
支持單層和多層True索引取值,單層True索引取值:tensor_x[True],多層True索引取值:tensor_x[True][True]…。
True索引取值操作的是第0維,在取出所有數據后,會在axis=0軸上擴展一維,該維長度為1。
例如,對一個shape為(3, 4, 5)的tensor進行單層True索引取值,取得結果的shape是(1, 3, 4, 5)。
多層索引取值可以理解為,后一層索引取值在前一層索引取值結果上再進行True索引取值。
示例如下:
tensor_x = Tensor(np.arange(2 * 3 ).reshape((2, 3)))
data_single = tensor_x[True]
data_multi = tensor_x[True][True]
結果如下:
data_single: Tensor(shape=[1, 2, 3], dtype=Int64, value=[[[0, 1, 2], [3, 4, 5]]])
data_multi: Tensor(shape=[1, 1, 2, 3], dtype=Int64, value=[[[[0, 1, 2], [3, 4, 5]]]])
o None索引取值
None索引取值和True索引取值一致,可參考True索引取值,這里不再贅述。
o ellipsis索引取值
支持單層和多層ellipsis索引取值,單層ellipsis索引取值:tensor_x[…],多層ellipsis索引取值:tensor_x[…][…]…。
ellipsis索引取值操作的是所有維度,原樣不動取出所有數據。一般多作為Tuple索引的組成元素,Tuple索引將于下面介紹。
例如,對一個shape為(3, 4, 5)的tensor進行ellipsis索引取值,取得結果的shape依然是(3, 4, 5)。
示例如下:
tensor_x = Tensor(np.arange(2 * 3 ).reshape((2, 3)))
data_single = tensor_x[…]
data_multi = tensor_x[…][…]
結果如下:
data_single: Tensor(shape=[2, 3], dtype=Int64, value=[[0, 1, 2], [3, 4, 5]])
data_multi: Tensor(shape=[2, 3], dtype=Int64, value=[[0, 1, 2], [3, 4, 5]])
o slice索引取值
支持單層和多層slice索引取值,單層slice索引取值:tensor_x[slice_index],多層slice索引取值:tensor_x[slice_index0][slice_index1]…。
slice索引取值操作的是第0維,取出第0維所切到位置的元素,slice不會降維,即使切到長度為1,區別于int索引取值。
例如,tensor_x[0:1:1] != tensor_x[0],因為shape_former = (1,) + shape_latter。
多層索引取值可以理解為,后一層索引取值在前一層索引取值結果上再進行slice索引取值。
slice有start、stop和step組成。start默認值為0,stop默認值為該維長度,step默認值為1。
例如,tensor_x[:] == tensor_x[0:length:1]。
示例如下:
tensor_x = Tensor(np.arange(4 * 2 * 2).reshape((4, 2, 2)))
data_single = tensor_x[1:4:2]
data_multi = tensor_x[1:4:2][1:]
結果如下:
data_single: Tensor(shape=[2, 2, 2], dtype=Int64, value=[[[4, 5], [6, 7]], [[12, 13], [14, 15]]])
data_multi: Tensor(shape=[1, 2, 2], dtype=Int64, value=[[[12, 13], [14, 15]]])
o Tensor索引取值
支持單層和多層Tensor索引取值,單層Tensor索引取值:tensor_x[tensor_index],多層Tensor索引取值:tensor_x[tensor_index0][tensor_index1]…。
Tensor索引取值操作的是第0維,取出第0維對應位置的元素。
索引Tensor數據類型必須是int32,元素不能是負數,值小于第0維長度。
Tensor索引取值得到結果的data_shape = tensor_index.shape + tensor_x.shape[1:]。
例如,對一個shape為(6, 4, 5)的tensor通過shape為(2, 3)的tensor進行索引取值,取得結果的shape為(2, 3, 4, 5)。
多層索引取值可以理解為,后一層索引取值在前一層索引取值結果上再進行Tensor索引取值。
示例如下:
tensor_x = Tensor(np.arange(4 * 2 * 3).reshape((4, 2, 3)))
tensor_index0 = Tensor(np.array([[1, 2], [0, 3]]), mstype.int32)
tensor_index1 = Tensor(np.array([[0, 0]]), mstype.int32)
data_single = tensor_x[tensor_index0]
data_multi = tensor_x[tensor_index0][tensor_index1]
結果如下:
data_single: Tensor(shape=[2, 2, 2, 3], dtype=Int64, value=[[[[4, 5], [6, 7]], [[8, 9], [10, 11]]], [[[0, 1], [2, 3]], [[12, 13], [14, 15]]]])
data_multi: Tensor(shape=[1, 2, 2, 2, 3], dtype=Int64, value=[[[[[4, 5], [6, 7]], [[8, 9], [10, 11]]], [[[4, 5], [6, 7]], [[8, 9], [10, 11]]]]])
o Tuple索引取值
索引Tuple的數據類型必須是int32,支持單層和多層Tuple索引取值,單層Tuple索引取值:tensor_x[tuple_index],多層Tuple索引取值:tensor_x[tuple_index0][tuple_index1]…。
Tuple索引里的元素可以包含int、slice、ellipsis、Tensor。
索引里除ellipsis外每個元素操作對應位置維度,即Tuple中第0個元素操作第0維,第1個元素操作第1維,以此類推,每個元素的索引規則與該元素類型索引取值規則一致。
Tuple索引里最多只有一個ellipsis,ellipsis前半部分索引元素從前往后對應Tensor第0維往后,后半部分索引元素從后往前對應Tensor最后一維往前,其他未指定的維度,代表全取。
元素里包含的Tensor數據類型必須是int32,且Tensor元素不能是負數,值小于操作維度長度。
例如,tensor_x[0:3, 1, tensor_index] == tensor_x[(0:3, 1, tensor_index)],因為0:3, 1, tensor_index就是一個Tuple。
多層索引取值可以理解為,后一層索引取值在前一層索引取值結果上再進行Tuple索引取值。
示例如下:
tensor_x = Tensor(np.arange(2 * 3 * 4).reshape((2, 3, 4)))
tensor_index = Tensor(np.array([[1, 2, 1], [0, 3, 2]]), mstype.int32)
data = tensor_x[1, 0:1, tensor_index]
結果如下:
data: Tensor(shape=[2, 3, 1], dtype=Int64, value=[[[13], [14], [13]], [[12], [15], [14]]])
? 索引賦值
索引值支持int、ellipsis、slice、Tensor、Tuple。
索引賦值可以理解為對索引到的位置元素按照一定規則進行賦值,所有索引賦值都不會改變原Tensor的shape。
同時支持增強索引賦值,即支持+=、-=、*=、/=、%=、**=、//=。
o int索引賦值
支持單層和多層int索引賦值,單層int索引賦值:tensor_x[int_index] = u,多層int索引賦值:tensor_x[int_index0][int_index1]… = u。
所賦值支持Number和Tensor,Number和Tensor都會被轉為與被更新Tensor數據類型一致。
當所賦值為Number時,可以理解為將int索引取到位置元素都更新為Number。
當所賦值為Tensor時,Tensor的shape必須等于或者可廣播為int索引取到結果的shape,在保持二者shape一致后,然后將賦值Tensor元素更新到索引取出結果對應元素的原Tensor位置。
例如,對shape = (2, 3, 4)的Tensor,通過int索引1賦值為100,更新后的Tensorshape仍為(2, 3, 4),但第0維位置為1的所有元素,值都更新為100。
示例如下:
tensor_x = Tensor(np.arange(2 * 3).reshape((2, 3)).astype(np.float32))
tensor_y = Tensor(np.arange(2 * 3).reshape((2, 3)).astype(np.float32))
tensor_z = Tensor(np.arange(2 * 3).reshape((2, 3)).astype(np.float32))
tensor_x[1] = 88.0
tensor_y[1][1] = 88.0
tensor_z[1]= Tensor(np.array([66, 88, 99]).astype(np.float32))
結果如下:
tensor_x: Tensor(shape=[2, 3], dtype=Float32, value=[[0.0, 1.0, 2.0], [88.0, 88.0, 88.0]])
tensor_y: Tensor(shape=[2, 3], dtype=Float32, value=[[0.0, 1.0, 2.0], [3.0, 88.0, 5.0]])
tensor_z: Tensor(shape=[2, 3], dtype=Float32, value=[[0.0, 1.0, 2.0], [66.0, 88.0, 99.0]])
o ellipsis索引賦值
支持單層和多層ellipsis索引賦值,單層ellipsis索引賦值:tensor_x[…] = u,多層ellipsis索引賦值:tensor_x[…][…]… = u。
所賦值支持Number和Tensor,Number和Tensor里的值都會轉為與被更新Tensor數據類型一致。
當所賦值為Number時,可以理解為將所有元素都更新為Number。
當所賦值為Tensor時,Tensor里元素個數必須為1或者等于原Tensor里元素個數,元素為1時進行廣播,個數相等shape不一致時進行reshape, 在保證二者shape一致后,將賦值Tensor元素按照位置逐一更新到原Tensor里。
例如,對shape = (2, 3, 4)的Tensor,通過…索引賦值為100,更新后的Tensorshape仍為(2, 3, 4),所有元素都變為100。
示例如下:
tensor_x = Tensor(np.arange(2 * 3).reshape((2, 3)).astype(np.float32))
tensor_y = Tensor(np.arange(2 * 3).reshape((2, 3)).astype(np.float32))
tensor_z = Tensor(np.arange(2 * 3).reshape((2, 3)).astype(np.float32))
tensor_x[…] = 88.0
tensor_y[…] = Tensor(np.array([22, 44, 55, 22, 44, 55]).astype(np.float32))
結果如下:
tensor_x: Tensor(shape=[2, 3], dtype=Float32, value=[[88.0, 88.0, 88.0], [88.0, 88.0, 88.0]])
tensor_y: Tensor(shape=[2, 3], dtype=Float32, value=[[22.0, 44.0, 55.0], [22.0, 44.0, 55.0]])
o slice索引賦值
支持單層和多層slice索引賦值,單層slice索引賦值:tensor_x[slice_index] = u,多層slice索引賦值:tensor_x[slice_index0][slice_index1]… = u。
所賦值支持Number和Tensor,Number和Tensor里的值都會轉為與被更新Tensor數據類型一致。
當所賦值為Number時,可以理解為將slice索引取到位置元素都更新為Number。
當所賦值為Tensor時,Tensor里元素個數必須為1或者等于slice索引取到Tensor里元素個數,元素為1時進行廣播,個數相等shape不一致時進行reshape, 在保證二者shape一致后,將賦值Tensor元素按照位置逐一更新到原Tensor里。
例如,對shape = (2, 3, 4)的Tensor,通過0:1:1索引賦值為100,更新后的Tensorshape仍為(2, 3, 4),但第0維位置為0的所有元素,值都更新為100。
示例如下:
tensor_x = Tensor(np.arange(3 * 3).reshape((3, 3)).astype(np.float32))
tensor_y = Tensor(np.arange(3 * 3).reshape((3, 3)).astype(np.float32))
tensor_z = Tensor(np.arange(3 * 3).reshape((3, 3)).astype(np.float32))
tensor_x[0:1] = 88.0
tensor_y[0:2][0:2] = 88.0
tensor_z[0:2] = Tensor(np.array([11, 12, 13, 11, 12, 13]).astype(np.float32))
結果如下:
tensor_x: Tensor(shape=[3, 3], dtype=Float32, value=[[88.0, 88.0, 88.0], [3.0, 4.0, 5.0], [6.0, 7.0, 8.0]])
tensor_y: Tensor(shape=[3, 3], dtype=Float32, value=[[88.0, 88.0, 88.0], [88.0, 88.0, 88.0], [6.0, 7.0, 8.0]])
tensor_z: Tensor(shape=[3, 3], dtype=Float32, value=[[11.0, 12.0, 13.0], [11.0, 12.0, 13.0], [6.0, 7.0, 8.0]])
o Tensor索引賦值
僅支持單層Tensor索引賦值,即tensor_x[tensor_index] = u。
索引Tensor支持int32和bool類型。
所賦值支持Number、Tuple和Tensor,Number、Tuple和Tensor里的值必須與原Tensor數據類型一致。
當所賦值為Number時,可以理解為將Tensor索引取到位置元素都更新為Number。
當所賦值為Tensor時,Tensor的shape必須等于或者可廣播為索引取到結果的shape,在保持二者shape一致后,然后將賦值Tensor元素更新到索引取出結果對應元素的原Tensor位置。
當所賦值為Tuple時,Tuple里元素只能全是Number或者全是Tensor。
當全是Number時,Number的類型必須與原Tensor數據類型是一類,且元素的個數必須等于索引取到結果shape的最后一維,然后廣播為索引取到結果shape;
當全是Tensor的時候,這些Tensor在axis=0軸上打包之后成為一個新的賦值Tensor,這時按照所賦值為Tensor的規則進行賦值。
例如,對一個shape為(6, 4, 5)、dtype為float32的tensor通過shape為(2, 3)的tensor進行索引賦值,如果所賦值為Number,則Number必須是float; 如果所賦值為Tuple,則tuple里的元素都得是float,且個數為5;如果所賦值為Tensor,則Tensor的dtype必須為float32,且shape可廣播為(2, 3, 4, 5)。
示例如下:
tensor_x = Tensor(np.arange(3 * 3).reshape((3, 3)).astype(np.float32))
tensor_y = Tensor(np.arange(3 * 3).reshape((3, 3)).astype(np.float32))
tensor_index = Tensor(np.array([[2, 0, 2], [0, 2, 0], [0, 2, 0]], np.int32))
tensor_x[tensor_index] = 88.0
tensor_y[tensor_index] = Tensor(np.array([11.0, 12.0, 13.0]).astype(np.float32))
結果如下:
tensor_x: Tensor(shape=[3, 3], dtype=Float32, value=[[88.0, 88.0, 88.0], [3.0, 4.0, 5.0], [88.0, 88.0, 88.0]])
tensor_y: Tensor(shape=[3, 3], dtype=Float32, value=[[11.0, 12.0, 13.0], [3.0, 4.0, 5.0], [11.0, 12.0, 13.0]])
o Tuple索引賦值
支持單層和多層Tuple索引賦值,單層Tuple索引賦值:tensor_x[tuple_index] = u,多層Tuple索引賦值:tensor_x[tuple_index0][tuple_index1]… = u。
Tuple索引賦值和Tuple索引取值對索引的支持一致, 但多層Tuple索引賦值不支持Tuple里包含Tensor。
所賦值支持Number、Tuple和Tensor,Number、Tuple和Tensor里的值必須與原Tensor數據類型一致。
當所賦值為Number時,可以理解為將Tensor索引取到位置元素都更新為Number。
當所賦值為Tensor時,Tensor的shape必須等于或者可廣播為索引取到結果的shape,在保持二者shape一致后,然后將賦值Tensor元素更新到索引取出結果對應元素的原Tensor位置。
當所賦值為Tuple時,Tuple里元素只能全是Number或者全是Tensor。
當全是Number時,Number的類型必須與原Tensor數據類型是一類,且元素的個數必須等于索引取到結果shape的最后一維,然后廣播為索引取到結果shape;
當全是Tensor的時候,這些Tensor在axis=0軸上打包之后成為一個新的賦值Tensor,這時按照所賦值為Tensor的規則進行賦值。
示例如下:
tensor_x = Tensor(np.arange(3 * 3).reshape((3, 3)).astype(np.float32))
tensor_y = Tensor(np.arange(3 * 3).reshape((3, 3)).astype(np.float32))
tensor_z = Tensor(np.arange(3 * 3).reshape((3, 3)).astype(np.float32))
tensor_index = Tensor(np.array([[0, 1], [1, 0]]).astype(np.int32))
tensor_x[1, 1:3] = 88.0
tensor_y[1:3, tensor_index] = 88.0
tensor_z[1:3, tensor_index] = Tensor(np.array([11, 12]).astype(np.float32))
結果如下:
tensor_x: Tensor(shape=[3, 3], dtype=Float32, value=[[0.0, 1.0, 2.0], [3.0, 88.0, 88.0], [6.0, 7.0, 8.0]])
tensor_y: Tensor(shape=[3, 3], dtype=Float32, value=[[0.0, 1.0, 2.0], [88.0, 88.0, 5.0], [88.0, 88.0, 8.0]])
tensor_z: Tensor(shape=[3, 3], dtype=Float32, value=[[0.0, 1.0, 2.0], [12.0, 11.0, 5.0], [12.0, 11.0, 8.0]])
Primitive
當前支持在網絡里構造Primitive及其子類的實例,即支持語法reduce_sum = ReduceSum(True)。
但在構造時,參數只能通過位置參數方式傳入,不支持通過鍵值對方式傳入,即不支持語法reduce_sum = ReduceSum(keep_dims=True)。
當前不支持在網絡調用Primitive及其子類相關屬性和接口。
Primitive定義可參考文檔:https://www.mindspore.cn/doc/programming_guide/zh-CN/r1.1/operators.html
當前已定義的Primitive可參考文檔:https://www.mindspore.cn/doc/api_python/zh-CN/r1.1/mindspore/mindspore.ops.html
Cell
當前支持在網絡里構造Cell及其子類的實例,即支持語法cell = Cell(args…)。
但在構造時,參數只能通過位置參數方式傳入,不支持通過鍵值對方式傳入,即不支持在語法cell = Cell(arg_name=value)。
當前不支持在網絡調用Cell及其子類相關屬性和接口,除非是在Cell自己的contrcut中通過self調用。
Cell定義可參考文檔:https://www.mindspore.cn/doc/programming_guide/zh-CN/r1.1/cell.html
當前已定義的Cell可參考文檔:https://www.mindspore.cn/doc/api_python/zh-CN/r1.1/mindspore/mindspore.nn.html
運算符
算術運算符和賦值運算符支持Number和Tensor運算,也支持不同dtype的Tensor運算。
之所以支持,是因為這些運算符會轉換成同名算子進行運算,這些算子支持了隱式類型轉換。
規則可參考文檔:https://www.mindspore.cn/doc/note/zh-CN/r1.1/operator_list_implicit.html
算術運算符
賦值運算符
邏輯運算符
成員運算符
身份運算符
表達式
條件控制語句
if
使用方式:
? if (cond): statements…
? x = y if (cond) else z
參數:cond – 支持類型Number、Tuple、List、String、None、Tensor、Function,也可以是計算結果類型是其中之一的表達式。
限制:
? 在構圖時,如果if未能消除,則if分支return的數據類型和shape,與if分支外return的數據類型和shape必須一致。
? 當只有if時,if分支變量更新后數據類型和shape,與更新前數據類型和shape必須一致。
? 當即有if又有else時,if分支變量更新后數據類型和shape,與else分支更新后數據類型和shape必須一致。
示例1:
if x > y:
return m
else:
return n
if分支返回的m和else分支返回的n,二者數據類型和shape必須一致。
示例2:
if x > y:
out = m
else:
out = n
return out
if分支更新后out和else分支更新后out,二者數據類型和shape必須一致。
循環語句
for
使用方式:for i in sequence
示例如下:
z = Tensor(np.ones((2, 3)))
x = (1, 2, 3)
for i in x:
z += i
return z
結果如下:
z: Tensor(shape=[2, 3], dtype=Int64, value=[[7, 7], [7, 7], [7, 7]])
參數:sequence – 遍歷序列(Tuple、List)
while
使用方式:while(cond)
參數:cond – 與if一致。
限制:
? 在構圖時,如果while未能消除,則while內return的數據類型和shape,與while外return的數據類型和shape必須一致。
? while內變量更新后數據類型和shape,與更新前數據類型和shape必須一致。
示例1:
while x > y:
x += 1
return m
return n
while內返回的m和while外返回的n數據類型必須和shape一致。
示例2:
out = m
while x > y:
x += 1
out = n
return out
while內,out更新后和更新前的數據類型和shape必須一致。
流程控制語句
當前流程控制語句支持了break、continue和pass。
break
可用于for和while代碼塊里,用于終止整個循環。
示例如下:
for i in x:
if i == 2:
break
statement_a
statement_b
當 i == 2時,循環終止,執行statement_b。
continue
可用于for和while語句塊里,用于終止本輪循環,直接進入下一輪循環。
示例如下:
for i in x:
if i == 2:
continue
statement_a
statement_b
當 i == 2時,本輪循環終止,不會往下執行statement_a,進入下一輪循環。
pass
不做任何事情,占位語句。
函數定義語句
def關鍵字
用于定義函數。
使用方式:
def function_name(args): statements…
示例如下:
def number_add(x, y):
return x + y
ret = number_add(1, 2)
結果如下:
ret: 3
lambda表達式
用于生成函數。
使用方式:lambda x, y: x + y
示例如下:
number_add = lambda x, y: x + y
ret = number_add(2, 3)
結果如下:
ret: 5
函數
Python內置函數
當前支持的Python內置函數包括:len、isinstance、partial、map、range、enumerate、super和pow。
len
功能:求序列的長度。
調用:len(sequence)
入參:sequence – Tuple、List、Dictionary或者Tensor。
返回值:序列的長度,類型為int。當入參是Tensor時,返回的是Tensor第0維的長度。
示例如下:
x = (2, 3, 4)
y = [2, 3, 4]
d = {“a”: 2, “b”: 3}
z = Tensor(np.ones((6, 4, 5)))
x_len = len(x)
y_len = len(y)
d_len = len(d)
z_len = len(z)
結果如下:
x_len: 3
y_len: 3
d_len: 2
z_len: 6
isinstance
功能:判斷對象是否為類的實例。
調用:isinstance(obj, type)
入參:
? obj – 任意支持類型的任意一個實例。
? type – MindSpore dtype模塊下的一個類型。
返回值:obj為type的實例,返回True,否則返回False。
示例如下:
x = (2, 3, 4)
y = [2, 3, 4]
z = Tensor(np.ones((6, 4, 5)))
x_is_tuple = isinstance(x, mstype.tuple_)
y_is_list= isinstance(y, mstype.list_)
z_is_tensor = isinstance(z, mstype.tensor)
結果如下:
x_is_tuple: True
y_is_list: True
z_is_tensor: True
partial
功能:偏函數,固定函數入參。
調用:partial(func, arg, …)
入參:
? func – 函數。
? arg – 一個或多個要固定的參數,支持位置參數和鍵值對傳參。
返回值:返回某些入參固定了值的函數。
示例如下:
def add(x, y):
return x + y
add_ = partial(add, x=2)
m = add_(y=3)
n = add_(y=5)
結果如下:
m: 5
n: 7
map
功能:根據提供的函數對一個或者多個序列做映射,由映射的結果生成一個新的序列。 如果多個序列中的元素個數不一致,則生成的新序列與最短的那個長度相同。
調用:map(func, sequence, …)
入參:
? func – 函數。
? sequence – 一個或多個序列(Tuple或者List)。
返回值:返回一個Tuple。
示例如下:
def add(x, y):
return x + y
elements_a = (1, 2, 3)
elements_b = (4, 5, 6)
ret = map(add, elements_a, elements_b)
結果如下:
ret: (5, 7, 9)
zip
功能:將多個序列中對應位置的元素打包成一個個元組,然后由這些元組組成一個新序列, 如果各個序列中的元素個數不一致,則生成的新序列與最短的那個長度相同。
調用:zip(sequence, …)
入參:sequence – 一個或多個序列(Tuple或List)`。
返回值:返回一個Tuple。
示例如下:
elements_a = (1, 2, 3)
elements_b = (4, 5, 6)
ret = zip(elements_a, elements_b)
結果如下:
ret: ((1, 4), (2, 5), (3, 6))
range
功能:根據起始值、結束值和步長創建一個Tuple。
調用:
? range(start, stop, step)
? range(start, stop)
? range(stop)
入參:
? start – 計數起始值,類型為int,默認為0。
? stop – 計數結束值,但不包括在內,類型為int。
? step – 步長,類型為int,默認為1。
返回值:返回一個Tuple。
示例如下:
x = range(0, 6, 2)
y = range(0, 5)
z = range(3)
結果如下:
x: (0, 2, 4)
y: (0, 1, 2, 3, 4)
z: (0, 1, 2)
enumerate
功能:生成一個序列的索引序列,索引序列包含數據和對應下標。
調用:
? enumerate(sequence, start)
? enumerate(sequence)
入參:
? sequence – 一個序列(Tuple、List、Tensor)。
? start – 下標起始位置,類型為int,默認為0。
返回值:返回一個Tuple。
示例如下:
x = (100, 200, 300, 400)
y = Tensor(np.array([[1, 2], [3, 4], [5 ,6]]))
m = enumerate(x, 3)
n = enumerate(y)
結果如下:
m: ((3, 100), (4, 200), (5, 300), (5, 400))
n: ((0, Tensor(shape=[2], dtype=Int64, value=[1, 2])), (1, Tensor(shape=[2], dtype=Int64, value=[3, 4])), (2, Tensor(shape=[2], dtype=Int64, value=[5, 6])))
super
功能:用于調用父類(超類)的一個方法,一般在super之后調用父類的方法。
調用:
? super().xxx()
? super(type, self).xxx()
入參:
? type – 類。
? self – 對象。
返回值:返回父類的方法。
示例如下:
class FatherNet(nn.Cell):
def init(self, x):
super(FatherNet, self).init(x)
self.x = x
def construct(self, x, y):
return self.x * x
def test_father(self, x):
return self.x + x
class SingleSubNet(FatherNet):
def init(self, x, z):
super(SingleSubNet, self).init(x)
self.z = z
def construct(self, x, y):
ret_father_construct = super().construct(x, y)
ret_father_test = super(SingleSubNet, self).test_father(x)
return ret_father_construct, ret_father_test
pow
功能:求冪。
調用:pow(x, y)
入參:
? x – 底數, Number或Tensor。
? y – 冪指數, Number或Tensor。
返回值:返回x的y次冪,Number或Tensor。
示例如下:
x = Tensor(np.array([1, 2, 3]))
y = Tensor(np.array([1, 2, 3]))
ret = pow(x, y)
結果如下:
ret: Tensor(shape=[3], dtype=Int64, value=[1, 4, 27]))
print
功能:用于打印。
調用:print(arg, …)
入參:arg – 要打印的信息(String或Tensor)。
返回值:無返回值。
示例如下:
x = Tensor(np.array([1, 2, 3]))
print(“result”, x)
結果如下:
result Tensor(shape=[3], dtype=Int64, value=[1, 2, 3]))
函數參數
? 參數默認值:目前不支持默認值設為Tensor類型數據,支持int、float、bool、None、str、tuple、list、dict類型數據。
? 可變參數:支持帶可變參數網絡的推理和訓練。
? 鍵值對參數:目前不支持帶鍵值對參數的函數求反向。
? 可變鍵值對參數:目前不支持帶可變鍵值對的函數求反向。
網絡定義
整網實例類型
? 帶@ms_function裝飾器的普通Python函數。
? 繼承自nn.Cell的Cell子類。
網絡構造組件
網絡使用約束
-
當前整網入參(即最外層網絡入參)默認僅支持Tensor,如果要支持非Tensor,可設置網絡的support_non_tensor_inputs屬性為True。
在網絡初始化的時候,設置self.support_non_tensor_inputs = True,該配置目前僅支持正向網絡,暫不支持反向網絡,即不支持對整網入參有非Tensor的網絡求反向。
支持最外層傳入標量示例如下:
class ExpandDimsNet(nn.Cell):
def init(self):
super(ExpandDimsNet, self).init()
self.support_non_tensor_inputs = True
self.expandDims = ops.ExpandDims()def construct(self, input_x, input_axis):
return self.expandDims(input_x, input_axis)
expand_dim_net = ExpandDimsNet()
input_x = Tensor(np.random.randn(2,2,2,2).astype(np.float32))
expand_dim_net(input_x, 0) -
不允許修改網絡的非Parameter類型數據成員。
示例如下:
class Net(Cell):
def init(self):
super(Net, self).init()
self.num = 2
self.par = Parameter(Tensor(np.ones((2, 3, 4))), name=“par”)def construct(self, x, y):
return x + y
上面所定義的網絡里,self.num不是一個Parameter,不允許被修改,而self.par是一個Parameter,可以被修改。 -
當construct函數里,使用未定義的類成員時,不會像Python解釋器那樣拋出AttributeError,而是作為None處理。
示例如下:
class Net(Cell):
def init(self):
super(Net, self).init()def construct(self, x):
return x + self.y
上面所定義的網絡里,construct里使用了并未定義的類成員self.y,此時會將self.y作為None處理。
總結
以上是生活随笔為你收集整理的MindSpore静态图语法支持的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MindInsight张量可视设计介绍
- 下一篇: MindArmour差分隐私