算子分类

image0image1image2

概述

算子按功能可分为张量操作、网络操作、数组操作、图像操作、编码操作、调试操作和量化操作等模块。所有的算子在Ascend AI处理器、GPU和CPU的支持情况,参见算子支持列表

张量操作

张量操作包括张量的结构操作和张量的数学运算。

张量结构操作有:张量创建、索引切片、维度变换和合并分割。

张量数学运算有:标量运算、向量运算和矩阵运算。

这里以张量的数学运算和运算的广播机制为例,介绍使用方法。

数学运算

张量的数学运算符可以分为标量运算符、向量运算符以及矩阵运算符。

加减乘除乘方,以及三角函数、指数、对数等常见函数,逻辑比较运算符等都是标量运算符。

标量运算

标量运算符的特点是对张量实施逐元素运算。

有些标量运算符对常用的数学运算符进行了重载。并且支持类似NumPy的广播特性。

以下代码实现了对input_x作乘方数为input_y的乘方操作:

[6]:
import numpy as np
import mindspore
from mindspore import Tensor

input_x = mindspore.Tensor(np.array([1.0, 2.0, 4.0]), mindspore.float32)
input_y = 3.0
print(input_x**input_y)
[ 1.  8. 64.]
加法

上述代码中input_xinput_y的相加实现方式如下:

[7]:
print(input_x + input_y)
[4. 5. 7.]
Element-wise乘法

以下代码实现了Element-wise乘法示例:

[8]:
import numpy as np
import mindspore
from mindspore import Tensor
import mindspore.ops as ops

input_x = Tensor(np.array([1.0, 2.0, 3.0]), mindspore.float32)
input_y = Tensor(np.array([4.0, 5.0, 6.0]), mindspore.float32)
mul = ops.Mul()
res = mul(input_x, input_y)

print(res)
[ 4. 10. 18.]
求三角函数

以下代码实现了Acos:

import numpy as np
import mindspore
from mindspore import Tensor
import mindspore.ops as ops

acos = ops.ACos()
input_x = Tensor(np.array([0.74, 0.04, 0.30, 0.56]), mindspore.float32)
output = acos(input_x)
print(output)

输出如下:

[0.7377037, 1.5307858, 1.2661037,0.97641146]

向量运算

向量运算符只在一个特定轴上运算,将一个向量映射到一个标量或者另外一个向量。

Squeeze

以下代码实现了压缩第3个通道维度为1的通道:

[9]:
import numpy as np
import mindspore
from mindspore import Tensor
import mindspore.ops as ops

input_tensor = Tensor(np.ones(shape=[3, 2, 1]), mindspore.float32)
squeeze = ops.Squeeze(2)
output = squeeze(input_tensor)

print(output)
[[1. 1.]
 [1. 1.]
 [1. 1.]]

矩阵运算

矩阵运算包括矩阵乘法、矩阵范数、矩阵行列式、矩阵求特征值、矩阵分解等运算。

矩阵乘法

以下代码实现了input_xinput_y的矩阵乘法:

[10]:
import numpy as np
import mindspore
from mindspore import Tensor
import mindspore.ops as ops

input_x = Tensor(np.ones(shape=[1, 3]), mindspore.float32)
input_y = Tensor(np.ones(shape=[3, 4]), mindspore.float32)
matmul = ops.MatMul()
output = matmul(input_x, input_y)

print(output)
[[3. 3. 3. 3.]]

广播机制

广播表示输入各变量channel数目不一致时,改变他们的channel数以得到结果。

  • 以下代码实现了广播机制的示例:

from mindspore import Tensor
import mindspore.ops as ops
import numpy as np

shape = (2, 3)
input_x = Tensor(np.array([1, 2, 3]).astype(np.float32))
broadcast_to = ops.BroadcastTo(shape)
output = broadcast_to(input_x)

print(output)

输出如下:

[[1. 2. 3.]
 [1. 2. 3.]]

网络操作

网络操作包括特征提取、激活函数、LossFunction、优化算法等。

特征提取

特征提取是机器学习中的常见操作,核心是提取比原输入更具代表性的Tensor。

卷积操作

以下代码实现了常见卷积操作之一的2D convolution 操作:

[11]:
from mindspore import Tensor
import mindspore.ops as ops
import numpy as np
import mindspore

input = Tensor(np.ones([10, 32, 32, 32]), mindspore.float32)
weight = Tensor(np.ones([32, 32, 3, 3]), mindspore.float32)
conv2d = ops.Conv2D(out_channel=32, kernel_size=3)
res = conv2d(input, weight)

print(res)
[[[[288. 288. 288. ... 288. 288. 288.]
   [288. 288. 288. ... 288. 288. 288.]
   [288. 288. 288. ... 288. 288. 288.]
   ...
   [288. 288. 288. ... 288. 288. 288.]
   [288. 288. 288. ... 288. 288. 288.]
   [288. 288. 288. ... 288. 288. 288.]]]

  ...

  [[288. 288. 288. ... 288. 288. 288.]
   [288. 288. 288. ... 288. 288. 288.]
   [288. 288. 288. ... 288. 288. 288.]
   ...
   [288. 288. 288. ... 288. 288. 288.]
   [288. 288. 288. ... 288. 288. 288.]
   [288. 288. 288. ... 288. 288. 288.]]


 ...


  [[288. 288. 288. ... 288. 288. 288.]
   [288. 288. 288. ... 288. 288. 288.]
   [288. 288. 288. ... 288. 288. 288.]
   ...
   [288. 288. 288. ... 288. 288. 288.]
   [288. 288. 288. ... 288. 288. 288.]
   [288. 288. 288. ... 288. 288. 288.]]]]

卷积的反向传播算子操作

以下代码实现了反向梯度算子传播操作的具体代码,输出存于dout, weight:

[12]:
from mindspore import Tensor
import mindspore.ops as ops
import numpy as np
import mindspore

dout = Tensor(np.ones([10, 32, 30, 30]), mindspore.float32)
weight = Tensor(np.ones([32, 32, 3, 3]), mindspore.float32)
x = Tensor(np.ones([10, 32, 32, 32]))
conv2d_backprop_input = ops.Conv2DBackpropInput(out_channel=32, kernel_size=3)
res = conv2d_backprop_input(dout, weight, ops.shape(x))

print(res)
[[[[ 32.  64.  96. ...  96.  64.  32.]
   [ 64. 128. 192. ... 192. 128.  64.]
   [ 96. 192. 288. ... 288. 192.  96.]
   ...
   [ 96. 192. 288. ... 288. 192.  96.]
   [ 64. 128. 192. ... 192. 128.  64.]
   [ 32.  64.  96. ...  96.  64.  32.]]

  ...

  [[ 32.  64.  96. ...  96.  64.  32.]
   [ 64. 128. 192. ... 192. 128.  64.]
   [ 96. 192. 288. ... 288. 192.  96.]
   ...
   [ 96. 192. 288. ... 288. 192.  96.]
   [ 64. 128. 192. ... 192. 128.  64.]
   [ 32.  64.  96. ...  96.  64.  32.]]]]

激活函数

以下代码实现Softmax激活函数计算:

[13]:
from mindspore import Tensor
import mindspore.ops as ops
import numpy as np
import mindspore

input_x = Tensor(np.array([1, 2, 3, 4, 5]), mindspore.float32)
softmax = ops.Softmax()
res = softmax(input_x)

print(res)
[0.01165623 0.03168492 0.08612853 0.23412164 0.63640857]

LossFunction

以下代码实现了L1 loss function:

[14]:
from mindspore import Tensor
import mindspore.ops as ops
import numpy as np
import mindspore

loss = ops.SmoothL1Loss()
input_data = Tensor(np.array([1, 2, 3]), mindspore.float32)
target_data = Tensor(np.array([1, 2, 2]), mindspore.float32)
res = loss(input_data, target_data)
print(res)
[0.  0.  0.5]

优化算法

以下代码实现了SGD梯度下降算法的具体实现,输出是result:

[15]:
from mindspore import Tensor
import mindspore.ops as ops
import numpy as np
import mindspore

sgd = ops.SGD()
parameters = Tensor(np.array([2, -0.5, 1.7, 4]), mindspore.float32)
gradient = Tensor(np.array([1, -1, 0.5, 2]), mindspore.float32)
learning_rate = Tensor(0.01, mindspore.float32)
accum = Tensor(np.array([0.1, 0.3, -0.2, -0.1]), mindspore.float32)
momentum = Tensor(0.1, mindspore.float32)
stat = Tensor(np.array([1.5, -0.3, 0.2, -0.7]), mindspore.float32)
result = sgd(parameters, gradient, learning_rate, accum, momentum, stat)

print(result)
(Tensor(shape=[4], dtype=Float32, value= [ 1.99000001e+00, -4.90300000e-01,  1.69500005e+00,  3.98009992e+00]),)

数组操作

数组操作指操作对象是一些数组的操作。

DType

返回跟输入的数据类型一致的并且适配Mindspore的Tensor变量,常用于Mindspore工程内。

具体可参见示例:

[16]:
from mindspore import Tensor
import mindspore.ops as ops
import numpy as np
import mindspore

input_tensor = Tensor(np.array([[2, 2], [2, 2]]), mindspore.float32)
typea = ops.DType()(input_tensor)

print(typea)
Float32

Cast

转换输入的数据类型并且输出与目标数据类型相同的变量。

具体参见以下示例:

[17]:
from mindspore import Tensor
import mindspore.ops as ops
import numpy as np
import mindspore

input_np = np.random.randn(2, 3, 4, 5).astype(np.float32)
input_x = Tensor(input_np)
type_dst = mindspore.float16
cast = ops.Cast()
result = cast(input_x, type_dst)
print(result.dtype)
Float16

Shape

返回输入数据的形状。

以下代码实现了返回输入数据input_tensor的操作:

[18]:
from mindspore import Tensor
import mindspore.ops as ops
import numpy as np
import mindspore

input_tensor = Tensor(np.ones(shape=[3, 2, 1]), mindspore.float32)
shape = ops.Shape()
output = shape(input_tensor)
print(output)
(3, 2, 1)

图像操作

图像操作包括图像预处理操作,如图像剪切(Crop,便于得到大量训练样本)和大小变化(Reise,用于构建图像金字塔等)。

以下代码实现了Crop和Resize操作:

from mindspore import Tensor
import mindspore.ops as ops
import numpy as np

BATCH_SIZE = 1
NUM_BOXES = 5
IMAGE_HEIGHT = 256
IMAGE_WIDTH = 256
CHANNELS = 3
image = np.random.normal(size=[BATCH_SIZE, IMAGE_HEIGHT, IMAGE_WIDTH, CHANNELS]).astype(np.float32)
boxes = np.random.uniform(size=[NUM_BOXES, 4]).astype(np.float32)
box_index = np.random.uniform(size=[NUM_BOXES], low=0, high=BATCH_SIZE).astype(np.int32)
crop_size = (24, 24)
crop_and_resize = ops.CropAndResize()
output = crop_and_resize(Tensor(image), Tensor(boxes), Tensor(box_index), crop_size)
print(output.asnumpy())

输出如下:

[[[[ 6.51672244e-01 -1.85958534e-01 5.19907832e-01]
[ 1.53466597e-01 4.10562098e-01 6.26138210e-01]
[ 6.62892580e-01 3.81776541e-01 4.69261825e-01]
...
[-5.83377600e-01 -3.53377648e-02 -6.01786733e-01]
[ 1.36125124e+00 5.84172308e-02 -6.41442612e-02]
[-9.11651254e-01 -1.19495761e+00 1.96810793e-02]]

[[ 6.06956100e-03 -3.73778701e-01 1.88935513e-03]
[-1.06859171e+00 2.00272346e+00 1.37180305e+00]
[ 1.69524819e-01 2.90421434e-02 -4.12243098e-01]
...

[[-2.04489112e-01 2.36615837e-01 1.33802962e+00]
[ 1.08329034e+00 -9.00492966e-01 -8.21497202e-01]
[ 7.54147097e-02 -3.72897685e-01 -2.91040149e-02]
...
[ 1.12317121e+00 8.98950577e-01 4.22795087e-01]
[ 5.13781667e-01 5.12095273e-01 -3.68211865e-01]
[-7.04941899e-02 -1.09924078e+00 6.89047515e-01]]]]

以上代码运行于MindSpore的Ascend版本。

编码运算

编码运算包括BoundingBox Encoding、BoundingBox Decoding、IOU计算等。

BoundingBoxEncode

对物体所在区域方框进行编码,得到类似PCA的更精简信息,以便做后续类似特征提取,物体检测,图像恢复等任务。

以下代码实现了对anchor_box和groundtruth_box的boundingbox encode:

[19]:
from mindspore import Tensor
import mindspore.ops as ops
import mindspore

anchor_box = Tensor([[2,2,2,3],[2,2,2,3]],mindspore.float32)
groundtruth_box = Tensor([[1,2,1,4],[1,2,1,4]],mindspore.float32)
boundingbox_encode = ops.BoundingBoxEncode(means=(0.0, 0.0, 0.0, 0.0), stds=(1.0, 1.0, 1.0, 1.0))
res = boundingbox_encode(anchor_box, groundtruth_box)
print(res)
[[-1.          0.25        0.          0.40546513]
 [-1.          0.25        0.          0.40546513]]

BoundingBoxDecode

编码器对区域位置信息解码之后,用此算子进行解码。

以下代码实现了:

[20]:
from mindspore import Tensor
import mindspore.ops as ops
import mindspore

anchor_box = Tensor([[4,1,2,1],[2,2,2,3]],mindspore.float32)
deltas = Tensor([[3,1,2,2],[1,2,1,4]],mindspore.float32)
boundingbox_decode = ops.BoundingBoxDecode(means=(0.0, 0.0, 0.0, 0.0), stds=(1.0, 1.0, 1.0, 1.0), max_shape=(768, 1280), wh_ratio_clip=0.016)
res = boundingbox_decode(anchor_box, deltas)
print(res)
[[ 4.194528   0.         0.         5.194528 ]
 [ 2.1408591  0.         3.8591409 60.59815  ]]

IOU计算

计算预测的物体所在方框和真实物体所在方框的交集区域与并集区域的占比大小,常作为一种损失函数,用以优化模型。

以下代码实现了计算两个变量anchor_boxesgt_boxes之间的IOU,以out输出:

[21]:
from mindspore import Tensor
import mindspore.ops as ops
import numpy as np
import mindspore

iou = ops.IOU()
anchor_boxes = Tensor(np.random.randint(1.0, 5.0, [3, 4]), mindspore.float16)
gt_boxes = Tensor(np.random.randint(1.0, 5.0, [3, 4]), mindspore.float16)
out = iou(anchor_boxes, gt_boxes)
print(out)
[[ 0. -0.  0.]
 [ 0. -0.  0.]
 [ 0.  0.  0.]]

调试操作

调试操作指的是用于调试网络的一些常用算子及其操作,例如HookBackward等, 此操作非常方便,对入门深度学习重要,极大提高学习者的学习体验。

HookBackward

打印中间变量的梯度,是比较常用的算子,目前仅支持PyNative模式。

以下代码实现了打印中间变量(例中x,y)的梯度:

[22]:
from mindspore import Tensor
import mindspore.ops as ops
import numpy as np
from mindspore import dtype as mstype
from mindspore import context

context.set_context(mode=context.PYNATIVE_MODE)

def hook_fn(grad_out):
    print(grad_out)

grad_all = ops.GradOperation(get_all=True)
hook = ops.HookBackward(hook_fn)

def hook_test(x, y):
    z = x * y
    z = hook(z)
    z = z * y
    return z

def backward(x, y):
    return grad_all(hook_test)(Tensor(x, mstype.float32), Tensor(y, mstype.float32))

print(backward(1, 2))
(Tensor(shape=[], dtype=Float32, value= 2),)
(Tensor(shape=[], dtype=Float32, value= 4), Tensor(shape=[], dtype=Float32, value= 4))