认识张量
张量,是一个数据结构,也可以说是一个函数,它描述了标量、矢量和张量之间线性关系。这些关系包括 内积、外积、线性映射以及笛卡尔积。张量中既有大小、又有方向。张量由多个数值构成,在n维空间里,会出现 n r n^r nr 个分量,r是张量的秩或阶。
使用张量
环境配置
import numpy as np
import mindspore
from mindspore import ops
from mindspore import Tensor, CSRTensor, COOTensor
创建张量
可以通过多种方式进行张量的创建
- 通过数据创建
data = [1, 0, 1, 0]
x_data = Tensor(data)
- 从numpy数组创建
np_array = np.array(data)
x_np = Tensor(np_array)
- 使用init初始化器创建
# init函数是One(),因此创建了都是1的张量
tensor1 = mindspore.Tensor(shape=(2, 2), dtype=mindspore.float32, init=One())
# init函数是Normal(),因此张量内的值遵循正态分布
tensor2 = mindspore.Tensor(shape=(2, 2), dtype=mindspore.float32, init=Normal())
- 继承另一个张量的属性
from mindspore import ops
# 继承全1,张量内容为 [1 1 1 1]
x_ones = ops.ones_like(x_data)
# 集成全0,张量内容为 [0 0 0 0]
x_zeros = ops.zeros_like(x_data)
张量属性
- shape 形状:是个tuple
- dtype 数据类型
- itemsize 每个元素大小:tensor中每个元素占用的字节数
- nbytes 占用字节数量:tensor占用的总字节数
- ndim 维数:tensor的秩,len(tensor.shape)的结果,是个整数
- size 元素个数:tensor中所有元素的个数,是个整数
- strides 每一维步长:tensor中每一维需要的字节数,是个tuple
举例,有这样一个张量x
x = Tensor(np.array([[1, 2], [3, 4]]), mindspore.int32)
它的属性如下
x_shape: (2, 2)
x_dtype: Int32
x_itemsize: 4
x_nbytes: 16
x_ndim: 2
x_size: 4
x_strides: (8, 4)
解释一下strides为什么是(8,4)
实际上,strides指的是遍历tensor时,移动到下一个元素需要跳过的字节数。当前张量时22,类型为int32,也就是4个字节。
对于第一维(行维度),移动到下一行,就需要跨越这行所有的元素,一行有两个元素,也就是24 = 8字节。
对于第二维(列维度),则不需要跨越行,直接取同行的下一个元素,则只需要跨越一个元素,也就是1*4 = 4字节。
张量索引
由0开始编制,使用方法与numpy类似,支持:和…切片,支持负索引
print("Last column: {}".format(tensor[:, -1]))
# Last column: [1. 3.]
print("First column: {}".format(tensor[..., 0]))
# First column: [0. 2.]
张量运算
包括 算数、线性代数、矩阵处理(转置、标引、切片)、采样等。
output_add = x + y
output_sub = x - y
output_mul = x * y
output_div = y / x
output_mod = y % x
output_floordiv = y // x
还可以进行张量连接
data1 = Tensor(np.array([[0, 1], [2, 3]]).astype(np.float32))
data2 = Tensor(np.array([[4, 5], [6, 7]]).astype(np.float32))
output = ops.concat((data1, data2), axis=0)
# [[0. 1.]
# [2. 3.]
# [4. 5.]
# [6. 7.]]
#shape:
# (4, 2)
以及张量合并
output = ops.stoutput = ops.stack([data1, data2])
# [[[0. 1.]
# [2. 3.]]
#
# [[4. 5.]
# [6. 7.]]]
# shape:
# (2, 2, 2)
tensor和numpy互转
# tensor转numpy
t = Tensor([1., 1., 1., 1., 1.])
n = t.asnumpy()
# numpy转tensor
n = np.ones(5)
t = Tensor.from_numpy(n)
稀疏张量
稀疏是稠密的反义词,稠密就是张量里都是元素,稀疏就是张量里零星几个元素,其他都是0.
如果使用普通张量来存储这类向量会造成不必要的计算、存储和通讯浪费。MindSpore有CSRTensor和COOTensor、RowTensor三种稀疏矩张量。
稀疏张量的表达形式是<indices:Tensor, values:Tensor, shape:Tensor>。其中,indices表示非零下标元素, values表示非零元素的值,shape表示的是被压缩的稀疏张量的形状。
CSRTensor
全称Compressed Sparse Row。s。各参数含义为:
- indptr: 一维整数张量, 表示稀疏数据每一行的非零元素在values中的起始位置和终止位置。
- indices: 一维整数张量,表示稀疏张量非零元素在列中的位置。长度等于values.
- values: 一维张量,非零元素的值
- shape: 表示被压缩的稀疏张量的形状,数据类型为Tuple
indptr = Tensor([0, 1, 2])
indices = Tensor([0, 1])
values = Tensor([1, 2], dtype=mindspore.float32)
shape = (2, 4)
# Make a CSRTensor
csr_tensor = CSRTensor(indptr, indices, values, shape)
要特别说一下,indptr一共三个值,表示第0行的非零元素从索引0开始,第1行的非零元素从索引1开始,而且这个数组的长度比实际的行数多一个,最后一个元素用于表示非零元素的总数。最后得到的张量这样的。
行0: [1, 0, 0, 0]
行1: [0, 2, 0, 0]
COOTensor
全称 Coordinate Format,各参数含义如下:
indices: 二维张量,每行代表非零元素下标。形状:[N, ndims]。
values: 一维张量,非零元素的值。形状:[N]。
shape: 稀疏张量的形状
indices = Tensor([[0, 1], [1, 2]], dtype=mindspore.int32)
values = Tensor([1, 2], dtype=mindspore.float32)
shape = (3, 4)
# Make a COOTensor
coo_tensor = COOTensor(indices, values, shape)
indices = [[0, 1], [1, 2]]意味着有两个非零元素,分别位于坐标(0,1)和(1,2)。得到的张量如下
0 1 0 0
0 0 2 0
0 0 0 0
总结
今天学习了张量的基本概念,如何创建张量、张量属性、张量计算以及稀疏张量的创建。