日期

心得
通过这次的学习,主要是了解过张量的基础概念,同时也知道有关构造张量的方法。通过索引查询张量,张量的运算。通过concat\stack 将张量进行维度链接。Tensor与NumPy的互相转换,但是我似乎并不了解什么它们的概念。也认知到了稀疏张量的概念,确实牛逼。
昇思MindSpore 基础入门学习 张量Tensor (AI 代码解析)
张量基础介绍
张量(Tensor)是一个可用来表示在一些矢量、标量和其他张量之间的线性关系的多线性函数,这些线性关系的基本例子有内积、外积、线性映射以及笛卡儿积。其坐标在 n𝑛 维空间内,有 nr𝑛𝑟 个分量的一种量,其中每个分量都是坐标的函数,而在坐标变换时,这些分量也依照某些规则作线性变换。r𝑟 称为该张量的秩或阶(与矩阵的秩和阶均无关系)。
张量是一种特殊的数据结构,与数组和矩阵非常相似。张量(Tensor)是MindSpore网络运算中的基本数据结构,本教程主要介绍张量和稀疏张量的属性及用法。
导入代码解析
import numpy as np
import mindspore
from mindspore import ops
from mindspore import Tensor, CSRTensor, COOTensor
解析:
- import numpy as np:- 导入NumPy库并将其简写为np,NumPy是一个用于科学计算的Python库,提供了支持多维数组和矩阵运算的高效操作。
 
- 导入NumPy库并将其简写为
- import mindspore:- 导入MindSpore库,MindSpore是一个由华为公司开发的开源深度学习框架,旨在支持从端到端的AI开发过程。
 
- from mindspore import ops:- 从MindSpore库中导入ops模块,ops中包含了各种神经网络操作和函数,如矩阵运算、激活函数等。
 
- 从MindSpore库中导入
- from mindspore import Tensor, CSRTensor, COOTensor:- 从MindSpore库中导入Tensor、CSRTensor和COOTensor类:- Tensor:MindSpore中的基本数据结构,用于存储多维数组和执行张量操作。
- CSRTensor:一种稀疏张量格式,使用压缩稀疏行(CSR)格式存储稀疏矩阵,以节省内存和加速稀疏矩阵运算。
- COOTensor:另一种稀疏张量格式,使用坐标列表(COO)格式存储稀疏矩阵,同样用于高效处理稀疏数据。
 
 
- 从MindSpore库中导入
数据张量 自动运算
data = [1, 0, 1, 0]
x_data = Tensor(data)
print(x_data, x_data.shape, x_data.dtype)
解析:
- data = [1, 0, 1, 0]:- 定义一个列表data,包含四个整数元素:1、0、1、0。
 
- 定义一个列表
- x_data = Tensor(data):- 使用MindSpore的Tensor类,将data列表转换为一个张量(Tensor)。这个张量将存储data中的元素,并支持张量运算。
 
- 使用MindSpore的
- print(x_data, x_data.shape, x_data.dtype):- 打印x_data的内容、形状和数据类型。- x_data:输出张量的具体元素值。
- x_data.shape:输出张量的形状,即张量的维度。由于- data是一个包含四个元素的列表,所以张量的形状将是(4,)。
- x_data.dtype:输出张量的数据类型。这里数据类型将根据- data中的元素自动推断,通常是整型(如- int32或- int64)。
 
 
- 打印
NumPy数据张量
np_array = np.array(data)
x_np = Tensor(np_array)
print(x_np, x_np.shape, x_np.dtype)
解析:
- np_array = np.array(data):- 使用NumPy库的array函数,将data列表转换为一个NumPy数组np_array。该数组包含与data列表相同的元素:1、0、1、0。
 
- 使用NumPy库的
- x_np = Tensor(np_array):- 使用MindSpore的Tensor类,将NumPy数组np_array转换为一个张量x_np。这样做的目的是利用张量的高级操作和MindSpore的计算功能。
 
- 使用MindSpore的
- print(x_np, x_np.shape, x_np.dtype):- 打印x_np的内容、形状和数据类型。- x_np:输出张量的具体元素值,与- np_array相同。
- x_np.shape:输出张量的形状。由于- np_array是一个一维数组,包含四个元素,所以张量的形状将是(4,)。
- x_np.dtype:输出张量的数据类型。- np_array的数据类型会被保留用于张量- x_np中。通常,如果- np_array的元素是整数,数据类型可能是- int32或- int64。
 
 
- 打印
使用init初始化器构造张量
from mindspore.common.initializer import One, Normal
# Initialize a tensor with ones
tensor1 = mindspore.Tensor(shape=(2, 2), dtype=mindspore.float32, init=One())
# Initialize a tensor from normal distribution
tensor2 = mindspore.Tensor(shape=(2, 2), dtype=mindspore.float32, init=Normal())
print("tensor1:\n", tensor1)
print("tensor2:\n", tensor2)
解析:
- from mindspore.common.initializer import One, Normal:- 从mindspore.common.initializer模块中导入One和Normal两个类,它们用于初始化张量的值。- One:初始化张量的所有元素为1。
- Normal:从正态分布中随机初始化张量的元素。
 
 
- 从
- tensor1 = mindspore.Tensor(shape=(2, 2), dtype=mindspore.float32, init=One()):- 创建一个张量tensor1。这个张量的形状为(2, 2),数据类型为mindspore.float32,并使用One()初始化,即张量中的每个元素都被设置为1。
 
- 创建一个张量
- tensor2 = mindspore.Tensor(shape=(2, 2), dtype=mindspore.float32, init=Normal()):- 创建一个张量tensor2。这个张量的形状为(2, 2),数据类型为mindspore.float32,并使用Normal()初始化,即张量中的每个元素都从标准正态分布中随机抽取。
 
- 创建一个张量
- print("tensor1:\n", tensor1):- 打印tensor1的内容。输出将是一个2x2的矩阵,其中所有元素都为1。
 
- 打印
- print("tensor2:\n", tensor2):- 打印tensor2的内容。输出将是一个2x2的矩阵,其中的元素是从标准正态分布中随机抽取的浮点数。
 
- 打印
from mindspore.common.initializer import One, Normal
解析:
 One 和 Normal 都是MindSpore中的初始化类,用于初始化张量的值。以下是它们的详细解释:
One()
- 功能:将张量的所有元素初始化为1。
- 用途:这种初始化方法在需要将张量的初始值设置为统一值的情况下非常有用,例如在某些特殊的网络结构或调试过程中。
示例:
tensor1 = mindspore.Tensor(shape=(2, 2), dtype=mindspore.float32, init=One())
在此示例中,tensor1将被初始化为一个2x2的矩阵,其中所有的元素都是1。
tensor1:
[[1.0, 1.0],
 [1.0, 1.0]]
Normal()
- 功能:从正态分布(也称为高斯分布)中随机生成张量的元素。
- 用途:这种初始化方法在深度学习中非常常见,因为它有助于打破对称性并加速收敛。正态分布的均值通常为0,标准差为1,当然也可以根据需求调整这些参数。
示例:
tensor2 = mindspore.Tensor(shape=(2, 2), dtype=mindspore.float32, init=Normal())
在此示例中,tensor2将被初始化为一个2x2的矩阵,其中的元素是从标准正态分布(均值为0,标准差为1)中随机生成的浮点数。
tensor2:
[[-0.832, 0.123],
 [0.456, -1.234]]
请注意,实际生成的数值会因随机性而有所不同。
总结:
- One():初始化张量的所有元素为1。
- Normal():从正态分布中随机初始化张量的元素。
继承张量属性
from mindspore import ops
x_ones = ops.ones_like(x_data)
print(f"Ones Tensor: \n {x_ones} \n")
x_zeros = ops.zeros_like(x_data)
print(f"Zeros Tensor: \n {x_zeros} \n")
解析:
- from mindspore import ops:- 从MindSpore库中导入ops模块,该模块包含了常见的张量操作函数。
 
- 从MindSpore库中导入
- x_ones = ops.ones_like(x_data):- 使用ops.ones_like函数创建一个与x_data形状和数据类型相同的张量x_ones,并将其所有元素初始化为1。- x_data:这是一个已有的张量,- ops.ones_like会根据它的形状和数据类型来创建新的张量。
- x_ones:结果张量,其所有元素都是1。
 
 
- 使用
- print(f"Ones Tensor: \n {x_ones} \n"):- 打印x_ones张量的内容。输出将是一个与x_data形状相同的张量,其中所有元素都是1。
 
- 打印
- x_zeros = ops.zeros_like(x_data):- 使用ops.zeros_like函数创建一个与x_data形状和数据类型相同的张量x_zeros,并将其所有元素初始化为0。- x_data:这是一个已有的张量,- ops.zeros_like会根据它的形状和数据类型来创建新的张量。
- x_zeros:结果张量,其所有元素都是0。
 
 
- 使用
- print(f"Zeros Tensor: \n {x_zeros} \n"):- 打印x_zeros张量的内容。输出将是一个与x_data形状相同的张量,其中所有元素都是0。
 
- 打印
总结:
- ops.ones_like(x_data):创建一个与- x_data形状和数据类型相同的张量,并将其所有元素初始化为1。
- ops.zeros_like(x_data):创建一个与- x_data形状和数据类型相同的张量,并将其所有元素初始化为0。
张量的属性
张量的属性包括形状、数据类型、转置张量、单个元素大小、占用字节数量、维数、元素个数和每一维步长。
- 形状(shape):Tensor的shape,是一个tuple。
- 数据类型(dtype):Tensor的dtype,是MindSpore的一个数据类型。
- 单个元素大小(itemsize): Tensor中每一个元素占用字节数,是一个整数。
- 占用字节数量(nbytes): Tensor占用的总字节数,是一个整数。
- 维数(ndim): Tensor的秩,也就是len(tensor.shape),是一个整数。
- 元素个数(size): Tensor中所有元素的个数,是一个整数。
- 每一维步长(strides): Tensor每一维所需要的字节数,是一个tuple。
x = Tensor(np.array([[1, 2], [3, 4]]), mindspore.int32)
print("x_shape:", x.shape)
print("x_dtype:", x.dtype)
print("x_itemsize:", x.itemsize)
print("x_nbytes:", x.nbytes)
print("x_ndim:", x.ndim)
print("x_size:", x.size)
print("x_strides:", x.strides)
解析:
- x = Tensor(np.array([[1, 2], [3, 4]]), mindspore.int32):- 使用NumPy数组np.array([[1, 2], [3, 4]])创建一个MindSpore张量x,并指定数据类型为mindspore.int32。
 
- 使用NumPy数组
- print("x_shape:", x.shape):- 打印张量x的形状(shape),即张量的维度大小。对于x,其形状为(2, 2),表示这是一个2x2的矩阵。
 
- 打印张量
- print("x_dtype:", x.dtype):- 打印张量x的数据类型(dtype),即张量中元素的数据类型。对于x,其数据类型为mindspore.int32。
 
- 打印张量
- print("x_itemsize:", x.itemsize):- 打印张量x的每个元素的字节大小(itemsize)。对于mindspore.int32类型的数据,每个元素占用4个字节。
 
- 打印张量
- print("x_nbytes:", x.nbytes):- 打印张量x的总字节数(nbytes),即所有元素占用的字节数总和。对于一个2x2的mindspore.int32张量,总字节数为2 * 2 * 4 = 16字节。
 
- 打印张量
- print("x_ndim:", x.ndim):- 打印张量x的维度数(ndim),即张量的轴数。对于x,其维度数为2,表示这是一个二维张量(矩阵)。
 
- 打印张量
- print("x_size:", x.size):- 打印张量x的元素总数(size),即张量中所有元素的数量。对于一个2x2的张量,元素总数为2 * 2 = 4。
 
- 打印张量
- print("x_strides:", x.strides):- 打印张量x的步长(strides),即在每个维度上移动到下一个元素所需的字节数。对于一个2x2的mindspore.int32张量,步长通常为(8, 4),表示在第一个维度上移动一个元素需要8个字节(2个int32元素),在第二个维度上移动一个元素需要4个字节(1个int32元素)。
 
- 打印张量
总结:
- x.shape:张量的形状。
- x.dtype:张量的数据类型。
- x.itemsize:每个元素的字节大小。
- x.nbytes:张量的总字节数。
- x.ndim:张量的维度数。
- x.size:张量的元素总数。
- x.strides:张量的步长。
张量索引
tensor = Tensor(np.array([[0, 1], [2, 3]]).astype(np.float32))
print("First row: {}".format(tensor[0]))
print("value of bottom right corner: {}".format(tensor[1, 1]))
print("Last column: {}".format(tensor[:, -1]))
print("First column: {}".format(tensor[..., 0]))
解析:
- tensor = Tensor(np.array([[0, 1], [2, 3]]).astype(np.float32)):- 使用NumPy数组np.array([[0, 1], [2, 3]])创建一个MindSpore张量tensor,并将数组的类型转换为np.float32。- 张量tensor的内容为:
 
- 张量
 
- 使用NumPy数组
[[0.0, 1.0],
 [2.0, 3.0]]
- print("First row: {}".format(tensor[0])):- 打印张量tensor的第一行。- tensor[0]表示取张量- tensor的第一行,即:
 
 
- 打印张量
[0.0, 1.0]
- print("value of bottom right corner: {}".format(tensor[1, 1])):- 打印张量tensor右下角的值。- tensor[1, 1]表示取张量- tensor第二行第二列的元素(索引从0开始),即值为- 3.0。
 
 
- 打印张量
- print("Last column: {}".format(tensor[:, -1])):- 打印张量tensor的最后一列。- tensor[:, -1]表示取张量- tensor中所有行的最后一列,即:
 
 
- 打印张量
[1.0, 3.0]
- print("First column: {}".format(tensor[..., 0])):- 打印张量tensor的第一列。- tensor[..., 0]表示取张量- tensor中所有行的第一列,即:
 
 
- 打印张量
[0.0, 2.0]
总结:
- tensor[0]:获取张量的第一行。
- tensor[1, 1]:获取张量右下角的值。
- tensor[:, -1]:获取张量的最后一列。
- tensor[..., 0]:获取张量的第一列。
张量运算
x = Tensor(np.array([1, 2, 3]), mindspore.float32)
y = Tensor(np.array([4, 5, 6]), mindspore.float32)
output_add = x + y
output_sub = x - y
output_mul = x * y
output_div = y / x
output_mod = y % x
output_floordiv = y // x
print("add:", output_add)
print("sub:", output_sub)
print("mul:", output_mul)
print("div:", output_div)
print("mod:", output_mod)
print("floordiv:", output_floordiv)
解析:
- x = Tensor(np.array([1, 2, 3]), mindspore.float32):- 创建一个MindSpore张量x,包含元素[1, 2, 3],数据类型为mindspore.float32。
 
- 创建一个MindSpore张量
- y = Tensor(np.array([4, 5, 6]), mindspore.float32):- 创建一个MindSpore张量y,包含元素[4, 5, 6],数据类型为mindspore.float32。
 
- 创建一个MindSpore张量
- output_add = x + y:- 对张量x和y进行元素加法操作,生成新张量output_add:- 计算过程:[1+4, 2+5, 3+6]=[5, 7, 9]
 
- 计算过程:
 
- 对张量
- output_sub = x - y:- 对张量x和y进行元素减法操作,生成新张量output_sub:- 计算过程:[1-4, 2-5, 3-6]=[-3, -3, -3]
 
- 计算过程:
 
- 对张量
- output_mul = x * y:- 对张量x和y进行元素乘法操作,生成新张量output_mul:- 计算过程:[1*4, 2*5, 3*6]=[4, 10, 18]
 
- 计算过程:
 
- 对张量
- output_div = y / x:- 对张量y和x进行元素除法操作,生成新张量output_div:- 计算过程:[4/1, 5/2, 6/3]=[4.0, 2.5, 2.0]
 
- 计算过程:
 
- 对张量
- output_mod = y % x:- 对张量y和x进行元素取模操作,生成新张量output_mod:- 计算过程:[4%1, 5%2, 6%3]=[0.0, 1.0, 0.0]
 
- 计算过程:
 
- 对张量
- output_floordiv = y // x:- 对张量y和x进行元素整除操作,生成新张量output_floordiv:- 计算过程:[4//1, 5//2, 6//3]=[4.0, 2.0, 2.0]
 
- 计算过程:
 
- 对张量
- print("add:", output_add):- 打印output_add的结果,即[5, 7, 9]。
 
- 打印
- print("sub:", output_sub):
- 打印output_sub的结果,即[-3, -3, -3]。
- print("mul:", output_mul):
- 打印output_mul的结果,即[4, 10, 18].
- print("div:", output_div):
- 打印output_div的结果,即[4.0, 2.5, 2.0]。
- print("mod:", output_mod):
- 打印output_mod的结果,即[0.0, 1.0, 0.0]。
- print("floordiv:", output_floordiv):
- 打印output_floordiv的结果,即[4.0, 2.0, 2.0]。
总结:
- x + y:张量元素加法。
- x - y:张量元素减法。
- x * y:张量元素乘法。
- y / x:张量元素除法。
- y % x:张量元素取模。
- y // x:张量元素整除。
concat 维度 链接
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)
print(output)
print("shape:\n", output.shape)
解析:
- data1 = Tensor(np.array([[0, 1], [2, 3]]).astype(np.float32)):- 创建一个MindSpore张量data1,包含元素[[0, 1], [2, 3]],数据类型为np.float32。- 张量data1的内容为:
 
- 张量
 
- 创建一个MindSpore张量
[[0.0, 1.0],
 [2.0, 3.0]]
- data2 = Tensor(np.array([[4, 5], [6, 7]]).astype(np.float32)):- 创建一个MindSpore张量data2,包含元素[[4, 5], [6, 7]],数据类型为np.float32。- 张量data2的内容为:
 
- 张量
 
- 创建一个MindSpore张量
[[4.0, 5.0],
 [6.0, 7.0]]
- output = ops.concat((data1, data2), axis=0):- 使用ops.concat在指定轴axis=0上将张量data1和data2进行拼接。- 拼接后的张量output的内容为:
 
- 拼接后的张量
 
- 使用
[[0.0, 1.0],
 [2.0, 3.0],
 [4.0, 5.0],
 [6.0, 7.0]]
  - 这里在轴0上拼接,即沿着行的方向拼接,结果是一个4x2的矩阵。
- print(output):- 打印拼接后的张量output,输出结果为:
 
- 打印拼接后的张量
[[0. 1.]
 [2. 3.]
 [4. 5.]
 [6. 7.]]
- print("shape:\n", output.shape):- 打印拼接后张量output的形状(shape),输出结果为:
 
- 打印拼接后张量
shape:
(4, 2)
总结:
- 张量data1和data2在轴0上进行拼接,结果是一个新的张量output。
- output的形状为- (4, 2),表示包含4行2列。
stack 维度链接
data1 = Tensor(np.array([[0, 1], [2, 3]]).astype(np.float32))
data2 = Tensor(np.array([[4, 5], [6, 7]]).astype(np.float32))
output = ops.stack([data1, data2])
print(output)
print("shape:\n", output.shape)
解析:
- data1 = Tensor(np.array([[0, 1], [2, 3]]).astype(np.float32)):- 创建一个MindSpore张量data1,包含元素[[0, 1], [2, 3]],数据类型为np.float32。- 张量data1的内容为:
 
- 张量
 
- 创建一个MindSpore张量
[[0.0, 1.0],
 [2.0, 3.0]]
- data2 = Tensor(np.array([[4, 5], [6, 7]]).astype(np.float32)):- 创建一个MindSpore张量data2,包含元素[[4, 5], [6, 7]],数据类型为np.float32。- 张量data2的内容为:
 
- 张量
 
- 创建一个MindSpore张量
[[4.0, 5.0],
 [6.0, 7.0]]
- output = ops.stack([data1, data2]):- 使用ops.stack将张量data1和data2沿着新的轴进行堆叠。默认情况下,新的轴是第一个轴(axis=0)。- 堆叠后的张量output的内容为:
 
- 堆叠后的张量
 
- 使用
[[[0.0, 1.0],
  [2.0, 3.0]],
 [[4.0, 5.0],
  [6.0, 7.0]]]
  - 这里在新的轴0上堆叠,结果是一个2x2x2的张量。
- print(output):- 打印堆叠后的张量output,输出结果为:
 
- 打印堆叠后的张量
[[[0. 1.]
  [2. 3.]]
 [[4. 5.]
  [6. 7.]]]
- print("shape:\n", output.shape):- 打印堆叠后张量output的形状(shape),输出结果为:
 
- 打印堆叠后张量
shape:
(2, 2, 2)
总结:
- 张量data1和data2在新的轴0上进行堆叠,结果是一个新的张量output。
- output的形状为- (2, 2, 2),表示包含2个2x2的矩阵。
Tensor转换为NumPy
t = Tensor([1., 1., 1., 1., 1.])
print(f"t: {t}", type(t))
n = t.asnumpy()
print(f"n: {n}", type(n))
解析:
- t = Tensor([1., 1., 1., 1., 1.]):- 创建一个MindSpore张量t,包含元素[1., 1., 1., 1., 1.],数据类型默认是float32。- 张量t的内容为:
 
- 张量
 
- 创建一个MindSpore张量
[1.0, 1.0, 1.0, 1.0, 1.0]
- print(f"t: {t}", type(t)):- 使用格式化字符串打印张量t的内容和类型。
- 输出结果为:
 
- 使用格式化字符串打印张量
t: [1. 1. 1. 1. 1.] <class 'mindspore.common.tensor.Tensor'>
- n = t.asnumpy():- 将MindSpore张量t转换为NumPy数组n。- 转换后的NumPy数组n的内容为:
 
- 转换后的NumPy数组
 
- 将MindSpore张量
[1.0, 1.0, 1.0, 1.0, 1.0]
- print(f"n: {n}", type(n)):- 使用格式化字符串打印NumPy数组n的内容和类型。
- 输出结果为:
 
- 使用格式化字符串打印NumPy数组
n: [1. 1. 1. 1. 1.] <class 'numpy.ndarray'>
总结:
- t是一个包含五个元素的MindSpore张量,类型为- mindspore.common.tensor.Tensor。
- n是由张量- t转换得到的NumPy数组,类型为- numpy.ndarray。
- asnumpy()方法用于将MindSpore张量转换为NumPy数组。
NumPy转换为Tensor
n = np.ones(5)
t = Tensor.from_numpy(n)
np.add(n, 1, out=n)
print(f"n: {n}", type(n))
print(f"t: {t}", type(t))
解析:
- n = np.ones(5):- 使用NumPy创建一个包含5个元素的数组n,所有元素都初始化为1.0,数据类型为float64(NumPy默认浮点数类型)。- 数组n的内容为:
 
- 数组
 
- 使用NumPy创建一个包含5个元素的数组
[1.0, 1.0, 1.0, 1.0, 1.0]
- t = Tensor.from_numpy(n):- 使用Tensor.from_numpy方法将NumPy数组n转换为MindSpore张量t。- 张量t的内容为:
 
- 张量
 
- 使用
[1.0, 1.0, 1.0, 1.0, 1.0]
  - 由于NumPy数组的默认数据类型为`float64`,因此张量`t`的数据类型也是`float64`。
- np.add(n, 1, out=n):- 使用NumPy的add函数对数组n中的每个元素加1,并将结果存储到n中。- 数组n的内容更新为:
 
- 数组
 
- 使用NumPy的
[2.0, 2.0, 2.0, 2.0, 2.0]
- print(f"n: {n}", type(n)):- 使用格式化字符串打印NumPy数组n的内容和类型。
- 输出结果为:
 
- 使用格式化字符串打印NumPy数组
n: [2. 2. 2. 2. 2.] <class 'numpy.ndarray'>
- print(f"t: {t}", type(t)):- 使用格式化字符串打印MindSpore张量t的内容和类型。
- 输出结果为:
 
- 使用格式化字符串打印MindSpore张量
t: [1. 1. 1. 1. 1.] <class 'mindspore.common.tensor.Tensor'>
总结:
- n是一个包含五个元素的NumPy数组,类型为- numpy.ndarray。在执行- np.add操作后,其内容变为- [2.0, 2.0, 2.0, 2.0, 2.0]。
- t是由NumPy数组- n转换得到的MindSpore张量,类型为- mindspore.common.tensor.Tensor,其内容依然是- [1.0, 1.0, 1.0, 1.0, 1.0],未受到后续对- n的修改影响,因为其是在- np.add操作之前创建的。
稀疏张量
稀疏张量是一种特殊张量,其中绝大部分元素的值为零。
在某些应用场景中(比如推荐系统、分子动力学、图神经网络等),数据的特征是稀疏的,若使用普通张量表征这些数据会引入大量不必要的计算、存储和通讯开销。这时就可以使用稀疏张量来表征这些数据。
MindSpore现在已经支持最常用的CSR和COO两种稀疏数据格式。
常用稀疏张量的表达形式是<indices:Tensor, values:Tensor, shape:Tensor>。其中,indices表示非零下标元素, values表示非零元素的值,shape表示的是被压缩的稀疏张量的形状。在这个结构下,我们定义了三种稀疏张量结构:CSRTensor、COOTensor和RowTensor。
解析:
 稀疏张量是一种特殊类型的张量,其特点是大部分元素的值为零。这种特性在处理某些类型的数据时非常有用,例如在推荐系统、分子动力学模拟、图神经网络等领域中,数据通常具有稀疏性。使用稀疏张量可以显著减少计算、存储和通讯的开销,因为只需要存储和处理非零元素及其位置信息,而不需要处理大量的零元素。
 MindSpore是一个深度学习框架,它支持两种最常用的稀疏数据格式:
- CSR (Compressed Sparse Row) 格式:这种格式适用于行稀疏性较高的矩阵,它通过三个数组来表示稀疏矩阵:一个数组存储非零元素的值,另一个数组存储每行第一个非零元素在值数组中的位置,第三个数组存储每个非零元素在列中的位置。
- COO (Coordinate) 格式:这种格式也称为三元组格式,它通过三个数组来表示稀疏矩阵:一个数组存储非零元素的值,另外两个数组分别存储这些非零元素的行和列索引。
在MindSpore中,稀疏张量的表达形式通常是 <indices:Tensor, values:Tensor, shape:Tensor>。这里:
- indices是一个张量,表示非零元素的索引位置。
- values是一个张量,表示这些非零元素的实际值。
- shape是一个张量,表示原始稀疏张量的形状(维度)。
基于这种结构,MindSpore定义了三种稀疏张量类型:
- CSRTensor:使用CSR格式表示的稀疏张量。
- COOTensor:使用COO格式表示的稀疏张量。
- RowTensor:一种特殊的稀疏张量,用于表示行稀疏性较高的张量。
使用这些稀疏张量类型,可以在处理稀疏数据时提高效率,减少资源消耗。
CSRTensor
CSR(Compressed Sparse Row)稀疏张量格式有着高效的存储与计算的优势。其中,非零元素的值存储在values中,非零元素的位置存储在indptr(行)和indices(列)中。各参数含义如下:
- indptr: 一维整数张量, 表示稀疏数据每一行的非零元素在values中的起始位置和终止位置, 索引数据类型支持int16、int32、int64。
- indices: 一维整数张量,表示稀疏张量非零元素在列中的位置, 与values长度相等,索引数据类型支持int16、int32、int64。
- values: 一维张量,表示CSRTensor相对应的非零元素的值,与indices长度相等。
- shape: 表示被压缩的稀疏张量的形状,数据类型为Tuple,目前仅支持二维CSRTensor。
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)
print(csr_tensor.astype(mindspore.float64).dtype)
解析:
- indptr = Tensor([0, 1, 2]):- 创建一个张量indptr,表示CSR格式中每行第一个非零元素在值数组中的位置。
- indptr的内容为:
 
- 创建一个张量
[0, 1, 2]
- indices = Tensor([0, 1]):- 创建一个张量indices,表示非零元素的列索引。
- indices的内容为:
 
- 创建一个张量
[0, 1]
- values = Tensor([1, 2], dtype=mindspore.float32):- 创建一个张量values,表示非零元素的值,并将数据类型设置为float32。
- values的内容为:
 
- 创建一个张量
[1.0, 2.0]
- shape = (2, 4):- 定义稀疏张量的形状为(2, 4),意味着原始矩阵有2行4列。
 
- 定义稀疏张量的形状为
- csr_tensor = CSRTensor(indptr, indices, values, shape):- 使用indptr、indices、values和shape创建一个CSR格式的稀疏张量csr_tensor。
- 该稀疏张量表示一个2x4的矩阵,其非零元素分别位于(0,0)和(1,1)位置,值为1.0和2.0。
 
- 使用
- print(csr_tensor.astype(mindspore.float64).dtype):- 将csr_tensor的值数据类型转换为float64,然后打印转换后的稀疏张量的数据类型。
- 输出结果为:
 
- 将
Float64
总结:
- 这个例子展示了如何在MindSpore中创建一个CSR格式的稀疏张量csr_tensor。
- 使用astype方法,可以将稀疏张量中的值的数据类型从float32转换为float64。
- 最后,打印出转换后的稀疏张量的数据类型,验证其类型为float64。
COOTensor
COO(Coordinate Format)稀疏张量格式用来表示某一张量在给定索引上非零元素的集合,若非零元素的个数为N,被压缩的张量的维数为ndims。各参数含义如下:
- indices: 二维整数张量,每行代表非零元素下标。形状:[N, ndims], 索引数据类型支持int16、int32、int64。
- values: 一维张量,表示相对应的非零元素的值。形状:[N]。
- shape: 表示被压缩的稀疏张量的形状,目前仅支持二维COOTensor。
COOTensor的详细文档,请参考mindspore.COOTensor。
from mindspore import Tensor
import mindspore
from mindspore import COOTensor
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)
print(coo_tensor.values)
print(coo_tensor.indices)
print(coo_tensor.shape)
print(coo_tensor.astype(mindspore.float64).dtype)  # COOTensor to float64
解析:
- indices = Tensor([[0, 1], [1, 2]], dtype=mindspore.int32):- 创建一个二维张量indices,表示非零元素的行和列索引。数据类型为int32。
- indices的内容为:
 
- 创建一个二维张量
[[0, 1],
 [1, 2]]
- 意味着非零元素位于矩阵的(0, 1)和(1, 2)位置。
- values = Tensor([1, 2], dtype=mindspore.float32):- 创建一个一维张量values,表示非零元素的值。数据类型为float32。
- values的内容为:
 
- 创建一个一维张量
[1.0, 2.0]
- shape = (3, 4):- 定义稀疏张量的形状为(3, 4),意味着原始稀疏矩阵有3行4列。
 
- 定义稀疏张量的形状为
- coo_tensor = COOTensor(indices, values, shape):- 使用indices、values和shape创建一个COO格式的稀疏张量coo_tensor。
- 这个稀疏张量表示一个3x4的矩阵,其非零元素分别位于(0, 1)和(1, 2)位置,值为1.0和2.0。
 
- 使用
- print(coo_tensor.values):- 打印稀疏张量coo_tensor中的非零元素的值。
- 输出结果为:
 
- 打印稀疏张量
[1. 2.]
- print(coo_tensor.indices):- 打印稀疏张量coo_tensor中的非零元素的行和列索引。
- 输出结果为:
 
- 打印稀疏张量
[[0 1]
 [1 2]]
- print(coo_tensor.shape):- 打印稀疏张量coo_tensor的形状。
- 输出结果为:
 
- 打印稀疏张量
(3, 4)
- print(coo_tensor.astype(mindspore.float64).dtype):- 将coo_tensor的值数据类型从float32转换为float64,然后打印转换后的稀疏张量的数据类型。
- 输出结果为:
 
- 将
Float64
总结:
- 这个例子展示了如何在MindSpore中创建一个COO格式的稀疏张量coo_tensor。
- 使用astype方法,可以将稀疏张量中的值的数据类型从float32转换为float64。
- 最后,打印出转换后的稀疏张量的数据类型,验证其类型为float64。



















