昇思25天学习打卡营第02天|张量 Tensor

一、什么是张量 Tensor

  • 张量是一种特殊的数据结构,与数组和矩阵非常相似。张量(Tensor)是MindSpore网络运算中的基本数据结构。

  • 张量可以被看作是一个多维数组,但它比普通的数组更加灵活和强大,因为它支持在GPU等加速硬件上执行高效的计算

  • 张量(Tensor)是一个可用来表示在一些矢量、标量和其他张量之间的线性关系的多线性函数,这些线性关系的基本例子有内积、外积、线性映射以及笛卡儿积。

  • 其坐标在  𝑛 维空间内,有  𝑛的𝑟次方个分量的一种量,其中每个分量都是坐标的函数,而在坐标变换时,这些分量也依照某些规则作线性变换。 𝑟称为该张量的秩或阶(与矩阵的秩和阶均无关系)

学过线性代数矩阵的同学知道,矩阵其实也是向量的线性变换

环境准备:

python 复制代码
%%capture captured_output
# 实验环境已经预装了mindspore==2.2.14,如需更换mindspore版本,可更改下面mindspore的版本号
!pip uninstall mindspore -y
!pip install -i https://pypi.mirrors.ustc.edu.cn/simple mindspore==2.2.14
python 复制代码
import numpy as np
import mindspore
from mindspore import ops
from mindspore import Tensor, CSRTensor, COOTensor

二、创建张量

张量的创建方式有多种,构造张量时,支持传入Tensor、float、int、bool、tuple、listnumpy.ndarray类型。

Tensor(张量)和numpy.ndarray(NumPy数组)是两种在数据处理、科学计算和机器学习等领域中广泛使用的数据结构,它们都以数组的形式存储数据,但在细节和应用场景上有所不同。
定义numpy.ndarray是NumPy库中的核心数据结构,它是一个多维数组对象,提供了大量的数学函数库来操作数组。 特点:

高效的存储和计算性能。 支持大量的数学函数操作。 易于进行广播(broadcasting)操作。 维度固定,但大小可变。

应用场景:主要用于科学计算、数据分析等领域。 Tensor
定义Tensor(张量)是一个多维数组或矩阵的推广,它在深度学习和神经网络中广泛使用。TensorFlow、PyTorch等深度学习框架中的Tensor不仅仅是数据容器,还包含了在GPU或TPU等硬件上加速计算的能力。

特点: 支持自动微分(用于反向传播)。 可以在GPU或TPU等硬件上加速计算。 维度和大小都可以动态变化(在某些框架中)。

提供了丰富的API来构建和训练神经网络。 应用场景:主要用于深度学习和神经网络。

1、根据数据直接生成

可以根据数据创建张量,数据类型可以设置或者通过框架自动推断

python 复制代码
data = [1, 0, 1, 0]
x_data = Tensor(data)
print(x_data, x_data.shape, x_data.dtype)

输出:

python 复制代码
[1 0 1 0] (4,) Int64
# 张量的输出为(4,)表示它是一个一维张量(向量),这个一维张量有四个元素

张量的shape属性描述了张量的维度和每个维度的大小。简单来说,它告诉了我们这个张量有多少行、多少列(对于二维张量),或者更高维度的"尺寸"

  • 二维张量(矩阵),它的shape属性可能会是(m, n),其中m是行数,n是列数
    一个形状为(3, 4)的二维张量意味着这个张量有3行4列。
  • 对于更高维度的张量,shape属性会继续增加维度。例如,一个三维张量的shape可能是(a, b, c),其中a、b、c分别代表三个维度的大小。
    一个形状为(2, 3, 4)的三维张量意味着这个张量有2个二维数组(或称为矩阵),每个矩阵有3行4列。第一个维度代表层数,这个张量是由几个二维数组堆叠的;第二个维度表示二维数组的行数;第三个维度表示每行有几个元素
    在深度学习中,这样的三维张量经常用于表示图像数据(特别是当处理批量图像时)
    其中:
    1. 第一个维度(2)可以代表批量大小(batch size),即一次性处理2张图像。
    2. 第二个和第三个维度(3和4)可以代表图像的高度和宽度(或者反过来,取决于数据的具体排列方式)。如果考虑到颜色通道,那么可能还会有第四个维度来表示颜色通道数(例如,对于RGB图像,这个维度的大小为3)。
python 复制代码
data2 = [[1,0], [1,0]]
x_data2 = Tensor(data2)
print(x_data2, x_data2.shape, x_data2.dtype)

输出:

python 复制代码
[[1 0]
 [1 0]] (2, 2) Int64
 # 可以看出 此时的二维张量的shape属性为(2,2) 代表它是两行两列的矩阵
python 复制代码
data3 = [[[1,0,1,0], [1,0,1,0],[1,0,1,0]],[[1,0,1,0], [1,0,1,0],[1,0,1,0]]]
x_data3 = Tensor(data3)
print(x_data3, x_data3.shape, x_data3.dtype)

输出:

python 复制代码
[[[1 0 1 0]
  [1 0 1 0]
  [1 0 1 0]]

 [[1 0 1 0]
  [1 0 1 0]
  [1 0 1 0]]] (2, 3, 4) Int64
  # 这是一个有两个三行四列的矩阵组成的三维张量

用下图做对比会更直观

接下来看一下其他的张量创建方式,不要忘记张量(Tensor)支持哪些数据类型哦,可以上划文章重温一下张量支持的数据类型

2、从NumPy数组生成

可以从NumPy数组创建张量

python 复制代码
# data为上面的data数组 [1, 0, 1, 0]
np_array = np.array(data)
x_np = Tensor(np_array)
print(x_np, x_np.shape, x_np.dtype)

输出:

python 复制代码
[1 0 1 0] (4,) Int64

3、使用init初始化器构造张量

init主要用于并行模式下的延后初始化,在正常情况下不建议使用init对参数进行初始化。

当使用init初始化器对张量进行初始化时,支持传入的参数有initshapedtype

  1. init: 支持传入initializer的子类。如:下方示例中的 One()Normal()

  2. shape: 支持传入 list、tuple、 int。

  3. dtype: 支持传入mindspore.dtype

from mindspore.common.initializer import One, Normal

python 复制代码
# Initialize a tensor with ones   
# init=One() 生成一个值全为1的常量数组用于初始化Tensor。
tensor1 = mindspore.Tensor(shape=(2, 2), dtype=mindspore.float32, init=One())
# Initialize a tensor from normal distribution
# init=Normal() 生成一个服从正态分布的随机数组用于初始化Tensor
tensor2 = mindspore.Tensor(shape=(2, 2), dtype=mindspore.float32, init=Normal())

print("tensor1:\n", tensor1)
print("tensor2:\n", tensor2)

输出:

python 复制代码
tensor1:
 [[1. 1.]
 [1. 1.]]
tensor2:
 [[ 0.00225669 -0.00495323]
 [ 0.00214255  0.00696278]]

4、继承另一个张量的属性,形成新的张量

python 复制代码
from mindspore import ops
# 使用ops.ones_like创建与x_data形状相同的全1张量
x_ones = ops.ones_like(x_data)
print(f"Ones Tensor: \n {x_ones} \n")
# 使用ops.zeros_like创建与x_data形状相同的全0张量  
x_zeros = ops.zeros_like(x_data)
print(f"Zeros Tensor: \n {x_zeros} \n")

输出:

python 复制代码
Ones Tensor: 
 [1 1 1 1] 

Zeros Tensor: 
 [0 0 0 0] 

三、张量的属性

-张量的属性包括形状、数据类型、转置张量、单个元素大小、占用字节数量、维数、元素个数和每一维步长。

  • 形状(shape):Tensor的shape,是一个tuple。

  • 数据类型(dtype):Tensor的dtype,是MindSpore的一个数据类型。

  • 单个元素大小(itemsize): Tensor中每一个元素占用字节数,是一个整数。

  • 占用字节数量(nbytes): Tensor占用的总字节数,是一个整数。

  • 维数(ndim): Tensor的秩,也就是len(tensor.shape),是一个整数。

  • 元素个数(size): Tensor中所有元素的个数,是一个整数。

  • 每一维步长(strides): Tensor每一维所需要的字节数,是一个tuple。

python 复制代码
# 从NumPy数组创建张量
x = Tensor(np.array([[1, 2], [3, 4]]), mindspore.int32)

# 最难理解的shape属性我们上面已经解释过啦
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)

输出:

python 复制代码
x_shape: (2, 2)
x_dtype: Int32
x_itemsize: 4
x_nbytes: 16
x_ndim: 2
x_size: 4
x_strides: (8, 4)

四、张量索引

Tensor索引与Numpy索引类似,索引从0开始编制,负索引表示按倒序编制,冒号:...用于对数据进行切片。

python 复制代码
# 从NumPy数组创建 两行两列的二维张量  数据类型为float32类型的
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]))

print("First row: {}".format(tensor[0,:]))

输出:

python 复制代码
# 结合下面的图片看输出结果 

# tensor 中第一个参数代表行 索引从0开始 tensor[0]即为第0行
First row: [0. 1.]

# tensor 中第一个参数代表行,第二个参数代表列 指定行列索引号可以确定一个元素tensor[1, 1]
value of bottom right corner: 3.0

# tensor[:, -1] 和tensor[..., 0]展示了负索引和数据分片的效果 : 和 ... 是同样的作用 
# tensor[:, -1] 取负索引为 -1的列
# tensor[..., 0] 取索引为 0的列
Last column: [1. 3.]
First column: [0. 2.]

# tensor[0,:] 取第0行
First row: [0. 1.]

五、张量运算

张量之间有很多运算,包括算术、线性代数、矩阵处理(转置、标引、切片)、采样等,张量运算和NumPy的使用方式类似,下面介绍其中几种操作。

普通算术运算有:加(+)、减(-)、乘(*)、除(/)、取模(%)、整除(//)。

python 复制代码
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)

输出:

python 复制代码
# 两个张量对应位置的元素进行运算
add: [5. 7. 9.]
sub: [-3. -3. -3.]
mul: [ 4. 10. 18.]
div: [4.  2.5 2. ]
mod: [0. 1. 0.]
floordiv: [4. 2. 2.]

concat将给定维度上的一系列张量连接起来。

python 复制代码
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)

输出:

python 复制代码
[[0. 1.]
 [2. 3.]
 [4. 5.]
 [6. 7.]]
shape:
 (4, 2)

stack则是从另一个维度上将两个张量合并起来。

python 复制代码
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)

输出:

python 复制代码
[
[[0. 1.]
  [2. 3.]]

 [[4. 5.]
  [6. 7.]]
  ]
  # shape的结果说明,该张量由两个二维张量堆叠,二维张量为两行两列
shape:
 (2, 2, 2)

ps: 还不明白的话,去上面看张量的定义第一小节

六、Tensor与NumPy转换

Tensor可以和NumPy进行互相转换。

6.1 Tensor转换为NumPy

python 复制代码
t = Tensor([1., 1., 1., 1., 1.])
print(f"t: {t}", type(t))
n = t.asnumpy()
print(f"n: {n}", type(n))

输出:

python 复制代码
t: [1. 1. 1. 1. 1.] <class 'mindspore.common.tensor.Tensor'>
n: [1. 1. 1. 1. 1.] <class 'numpy.ndarray'>

6.2 NumPy转换为Tensor

python 复制代码
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))

输出:

python 复制代码
n: [2. 2. 2. 2. 2.] <class 'numpy.ndarray'>
t: [2. 2. 2. 2. 2.] <class 'mindspore.common.tensor.Tensor'>

七、稀疏张量

稀疏张量是一种特殊张量,其中绝大部分元素的值为零。

在某些应用场景中(比如推荐系统、分子动力学、图神经网络等),数据的特征是稀疏的,若使用普通张量表征这些数据会引入大量不必要的计算、存储和通讯开销。这时就可以使用稀疏张量来表征这些数据。

MindSpore现在已经支持最常用的CSRCOO两种稀疏数据格式。

常用稀疏张量的表达形式是<indices:Tensor, values:Tensor, shape:Tensor>。其中,indices表示非零下标元素, values表示非零元素的值,shape表示的是被压缩的稀疏张量的形状。在这个结构下,我们定义了三种稀疏张量结构:CSRTensorCOOTensorRowTensor

7.1 CSRTensor

CSR(Compressed Sparse Row)稀疏张量格式有着高效的存储与计算的优势。其中,非零元素的值存储在values中,非零元素的位置存储在indptr(行)和indices(列)中。各参数含义如下:

  • indptr: 一维整数张量, 表示稀疏数据每一行的非零元素在values中的起始位置和终止位置, 索引数据类型支持int16、int32、int64。indptr (Tensor) - shape为 M 的一维整数Tensor,其中M等于 shape[0] + 1 。默认值: None

  • indices: 一维整数张量,表示稀疏张量非零元素在列中的位置, 与values长度相等,索引数据类型支持int16、int32、int64。

  • values: 一维张量,表示CSRTensor相对应的非零元素的值,与indices长度相等。

  • shape: 表示被压缩的稀疏张量的形状,数据类型为Tuple,目前仅支持二维CSRTensor。

CSRTensor的详细文档,请参考mindspore.CSRTensor

python 复制代码
下面给出一些CSRTensor的使用示例:
# 每一行的非零元素在value 中起始位置为0 终止位置为2  形式为shape(M) M=shape(2)+1
indptr = Tensor([0, 1, 2])
# 表示非零元素在第 0 列和第 1 列
indices = Tensor([0, 1])
# 表示非零元素的值为 1 和 2
values = Tensor([1, 2], dtype=mindspore.float32)
# csr_tensor 二维张量形状为 两行四列
shape = (2, 4)

# Make a CSRTensor
csr_tensor = CSRTensor(indptr, indices, values, shape)

print(csr_tensor.astype(mindspore.float64).dtype)

上述代码会生成如下所示的CSRTensor:

输出:

python 复制代码
Float64

7.2 COOTensor

COO(Coordinate Format)稀疏张量格式用来表示某一张量在给定索引上非零元素的集合,若非零元素的个数为N,被压缩的张量的维数为ndims。各参数含义如下:

  • indices: 二维整数张量,每行代表非零元素下标。形状:[N, ndims], 索引数据类型支持int16、int32、int64。

  • values: 一维张量,表示相对应的非零元素的值。形状:[N]。

  • shape: 表示被压缩的稀疏张量的形状,目前仅支持二维COOTensor。

COOTensor的详细文档,请参考mindspore.COOTensor

下面给出一些COOTensor的使用示例:

python 复制代码
# 非零元素位于 第0行第1列  和  第1行第2列
indices = Tensor([[0, 1], [1, 2]], dtype=mindspore.int32)
# 非零元素的值为 1和2
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

上述代码会生成如下所示的COOTensor:

输出:

python 复制代码
[1. 2.]
[[0 1]
 [1 2]]
(3, 4)
Float64
相关推荐
西岸行者10 天前
学习笔记:SKILLS 能帮助更好的vibe coding
笔记·学习
悠哉悠哉愿意10 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
别催小唐敲代码10 天前
嵌入式学习路线
学习
毛小茛10 天前
计算机系统概论——校验码
学习
babe小鑫10 天前
大专经济信息管理专业学习数据分析的必要性
学习·数据挖掘·数据分析
winfreedoms10 天前
ROS2知识大白话
笔记·学习·ros2
在这habit之下10 天前
Linux Virtual Server(LVS)学习总结
linux·学习·lvs
我想我不够好。10 天前
2026.2.25监控学习
学习
im_AMBER10 天前
Leetcode 127 删除有序数组中的重复项 | 删除有序数组中的重复项 II
数据结构·学习·算法·leetcode
CodeJourney_J10 天前
从“Hello World“ 开始 C++
c语言·c++·学习