人工智能——深度学习——认识Tensor
一、什么是 Tensor?
想象你在做蛋糕:
- scalar(标量)就像一粒糖(单个数字)
- vector(向量)就像一排糖(一组数字)
- matrix(矩阵)就像一个方形糖盒(二维排列的数字),区分:矩阵特指二维结构,就像一个表格,只有行和列两个维度
- tensor(张量)则像是一整箱不同形状的糖盒(可以是三维、四维甚至更高维的数字集合)
类型 | 维度 | 例子 |
---|---|---|
标量 (Scalar) | 0 维 | 5, 3.14 |
向量 (Vector) | 1 维 | [1,2,3,4] |
矩阵 (Matrix) | 2 维 | [[1,2],[3,4]] |
张量 (Tensor) | 3 维及以上 | 图片数据 (宽 × 高 × 通道) |
简单说,Tensor 是一个可以有任意维度的数组,是向量和矩阵的高维扩展(本质就是一个数组),只是数组是编程语言中的概念,而张量是数学概念
- 所有张量都可以用数组表示
- 但不是所有数组都能称为张量(张量有特定的数学性质和运算规则)
二、Tensor和深度学习的关系
深度学习阶段为什么首先介绍Tensor(张量),因为在深度学习中,Tensor是数据的基本载体:
- 输入的图片可以表示为 3 维张量(宽度 × 高度 × 颜色通道)
- 一段文本经过处理后可能成为 3 维张量(句子数 × 单词数 × 词向量维度)
- 神经网络中的权重和偏置也是张量
- 整个神经网络的计算过程,本质上就是张量之间的一系列运算
三、Tensor的数据类型
PyTorch 中常用的 Tensor 数据类型:
torch.float32
/torch.float
:32 位浮点数(默认)torch.float64
/torch.double
:64 位浮点数torch.int32
/torch.int
:32 位整数torch.int64
/torch.long
:64 位整数torch.bool
:布尔类型
四、张量(tensor)的创建
Tensor创建方法有很多,比如用标量创建、用numpy的数组创建、用list列表创建——都是调用同一个API:torch.tensor
为什么能用numpy数组创建张量呢,张量不就是数组的一种吗?——因为张量是”增强版的数组“可以支持在GPU上加速计算(普通的Numpy数组智能在CPU上运行),数组创建张量实际上就是进行了个转换,就像你把手机里的照片传到电脑上编辑 —— 内容不变,但获得了电脑上的编辑功能
在实际应用中,深度学习模型(如 PyTorch 中的神经网络)只能接收 Tensor 作为输入,因此需要一个 “转换桥梁”
举例来说:
- 你用 OpenCV 读入一张图片,得到的是 NumPy 数组(形状为 [高,宽,3])
- 你需要用
torch.tensor(图片数组)
转换为 Tensor,才能输入到 PyTorch 模型中训练- 模型输出的 Tensor 也可以通过
.numpy()
转回数组,用于可视化或保存结果
用torch.tensor创建张量:
import torch import numpy as npdef test001():# 1. 用标量创建张量tensor = torch.tensor(5)print(tensor.shape)# 2. 使用numpy随机一个数组创建张量tensor = torch.tensor(np.random.randn(3, 5))print(tensor)print(tensor.shape)# 3. 根据list创建tensortensor = torch.tensor([[1, 2, 3], [4, 5, 6]])print(tensor)print(tensor.shape)print(tensor.dtype)if __name__ == '__main__':test001()
注意,此处torch.tensor是小写,torch.tensor和torch.Tensor的用法是不同的:
在 PyTorch 中,
torch.tensor()
(小写)和torch.Tensor()
(大写)是创建张量的两种常用方式,它们的核心区别在于数据类型的默认处理方式
torch.tensor()
:
会根据输入数据自动推断最合适的数据类型,保持与原始数据的一致性。
例如:
- 输入整数列表
[1,2,3]
,会创建int64
类型的张量(默认整数类型);- 输入浮点数列表
[1.0,2.0,3.0]
,会创建float32
类型的张量;- 也可以通过
dtype
参数手动指定类型(如dtype=torch.float64
)
torch.Tensor()
:
是torch.FloatTensor
的别名,默认创建float32
(32 位浮点数)类型的张量,无论输入数据是整数还是其他类型。
例如:
- 输入整数列表
[1,2,3]
,会自动转换为float32
类型(值变为1.0, 2.0, 3.0
);- 并且torch.Tensor是不支持指定dtype的
上面的区别了解即可,日常使用优先使用torch.tensor
其他创建特殊tensor的方法:
- 创建全零\全一张量:torch.zeros() \ torch.ones()
- 创建随机张量量(均匀分布,0到1之间):torch.rand()
- 创建随机张量(正态分布):torch.randn()
- 创建指定范围的线性张量:torch.linspace()
- 创建对角矩阵:torch.eye()
代码展示:
# 2. 创建全零张量 zero_tensor = torch.zeros(3, 4) # 3行4列 print("\n全零张量:", zero_tensor)# 3. 创建全一张量 ones_tensor = torch.ones(2, 3) # 2行3列 print("\n全一张量:", ones_tensor)# 4. 创建随机张量(均匀分布,0到1之间) rand_tensor = torch.rand(2, 2) print("\n均匀分布随机张量:", rand_tensor)# 5. 创建随机张量(正态分布,均值0,方差1) randn_tensor = torch.randn(3, 2) print("\n正态分布随机张量:", randn_tensor)# 6. 创建指定范围的线性张量 lin_tensor = torch.linspace(0, 10, 5) # 从0到10,生成5个均匀分布的数 print("\n线性张量:", lin_tensor)# 7. 创建对角矩阵 eye_tensor = torch.eye(3) # 3x3的单位矩阵 print("\n单位矩阵:", eye_tensor)
总结:
张量的创建包括:
- 创建张量基本方法:torch.tensor()
- 创建全零\全一张量:torch.zeros() \ torch.ones()
- 创建随机张量量(均匀分布,0到1之间):torch.rand()
- 创建随机张量(正态分布):torch.randn()
- 创建指定范围的线性张量:torch.linspace()
- 创建对角矩阵:torch.eye()
1、torch.tensor()
:灵活的数据转换器特点:
- 最灵活的创建方式,直接从已有数据(Python 列表、NumPy 数组等)转换而来
- 自动推断数据类型(如整数列表→
int64
,浮点数列表→float32
),也可通过dtype
手动指定应用场景:
- 已有明确数据(如标签、预处理后的特征),需要转为张量进行后续计算
2、torch.zeros()
/torch.ones()
:初始化全零 / 全一张量特点:
- 无需原始数据,直接通过形状参数(如
(2,3)
)创建张量- 所有元素值固定为 0(
zeros
)或 1(ones
),数据类型默认float32
应用场景:
- 初始化占位张量(如预先分配内存,后续填充数据)
- 神经网络中偏置项(Bias)的初始化(常初始化为 0)
- 构建掩码(Mask)张量(如用
ones
标记有效区域,zeros
标记无效区域)
3、torch.rand()
:均匀分布随机张量(其实就是生成0到1的随机数)特点:
- 生成元素值在
[0, 1)
区间均匀分布的随机张量- 只需指定形状(如
(3,4)
),无需原始数据应用场景:
- 神经网络权重初始化(如简单模型的权重,需要在小范围内随机取值)
4、torch.randn()
:标准正态分布随机张量特点:
- 生成元素值符合均值为 0、方差为 1的标准正态分布(高斯分布)的随机张量
- 只需指定形状,数据类型固定为
float32
应用场景:
- 深度学习中主流的权重初始化(如 MLP、CNN 的卷积核初始化)
5、torch.eye()
:单位对角矩阵特点:
- 创建主对角线元素为 1,其余元素为 0的方阵
应用场景:
- 生成 one-hot 编码的基础矩阵(结合索引提取对角线元素)
五、Tensor数据转换(tensor和numpy的互转)
张量(tensor)转数组(numpy)要考虑内存是否共存的问题,这就涉及到浅拷贝和深拷贝
理解浅拷贝和深拷贝,我们可以用 “文件管理” 来类比:假设你有一个笔记本(原始数据),浅拷贝就像是创建了一个 “快捷方式”,深拷贝则是 “完整复印了一本本笔记本”
浅拷贝的特点:转换后得到的 NumPy 数组和原 Tensor 共享同一块内存。就像笔记本和它的快捷方式 —— 修改其中一个,另一个会同时变化
深拷贝:转换后新开辟内存空间,复制一份新的数据,两个对象完全独立。
Tensor 转 NumPy:
tensor.numpy()
是浅拷贝NumPy 转 Tensor:
torch.from_numpy()
也是浅拷贝使用copy()方法可以实现深ten六、常见的ten
六、Tensor常见的操作
- 获取元素值:
核心作用:从张量中获取单个元素或部分元素,类似从多层抽屉中找到特定物品
- 访问单个元素:.item()方法
- 访问部分元素:切片
import torch# 创建一个2×3的张量 tensor = torch.tensor([[1, 2, 3], [4, 5, 6]]) print("原始张量:\n", tensor)# 获取单个元素(索引从0开始) element = tensor[0, 1] # 第一行,第二列 print("\n获取单个元素:", element.item())# 切片操作:获取第一行 row = tensor[0, :] print("第一行:", row)# 切片操作:获取第二列 col = tensor[:, 1] print("第二列:", col)# 切片操作:获取子矩阵 submatrix = tensor[0:2, 1:3] print("子矩阵:\n", submatrix)
- 元素值计算
核心作用:对张量中的每个元素单独做相同运算
- 基础运算(加减乘除、幂运算等)
比如a + b
(对应元素相加)、a * 2
(每个元素乘 2)、a **3
(每个元素立方)。
- 特点:两个张量必须形状相同,或符合 “广播规则”(如 3×2 的张量和 2 的标量相加,会自动扩展标量为 3×2 再运算)。
- 用途:数据缩放(如将图片像素值从 0-255 缩放到 0-1)、特征转换(如对每个特征做平方处理)
仅展示广播机制的代码:
# 广播机制:不同形状张量的运算 c = torch.tensor([[1, 2, 3], [4, 5, 6]]) d = torch.tensor([10, 20, 30]) print("\n广播机制结果:\n", c + d)
- 阿达玛积
阿达玛积是指两个形状相同的矩阵或张量对应位置的元素相乘。它与矩阵乘法不同,矩阵乘法是线性代数中的标准乘法,而阿达玛积是逐元素操作
- 例:
a = [[1,2],[3,4]]
,b = [[5,6],[7,8]]
,结果为[[5,12],[21,32]]
。- 类比:两个相同规格的表格,每个单元格对应相乘
- 用途:元素级的权重调整(如用掩码张量过滤无效元素)
- Tensor相乘
核心作用:两个张量按矩阵乘法规则运算(行 × 列求和)
- 操作方式:
torch.matmul(a, b)
或a @ b
。- 关键要求:前一个张量的最后一维长度,必须等于后一个张量的倒数第二维长度(如 3×2 的张量可与 2×4 的张量相乘,结果为 3×4
import torch# 创建两个矩阵 a = torch.tensor([[1, 2], [3, 4]]) # 2×2矩阵 b = torch.tensor([[5, 6], [7, 8]]) # 2×2矩阵# 矩阵乘法方法1: torch.matmul() result1 = torch.matmul(a, b)# 矩阵乘法方法2: @ 运算符 result2 = a @ b
- 形状操作
核心作用:改变张量的维度结构(不改变元素总数)
- 重塑(Reshape/View)用:
tensor.reshape(shape)
或tensor.view(shape)
,比如 3×4 的张量可重塑为 2×6、12×1 等
- 注意:新形状的元素总数必须与原张量相同(3×4=2×6=12)。
- 用途:适配神经网络输入要求(如将图片的 28×28 像素展平为 784 维向量输入全连接层)
- reshape和view的区别:view方法要求原始张量的内存必须是 “连续的”【对于多维张量,内存布局通常按照最后一个维度优先的顺序存储,即先存列,后存行 ,如果张量的内存布局与形状完全匹配,并且没有被某些操作(如转置、索引等)打乱,那么这个张量就是连续的 】
- 转置(Transpose):交换张量的维度,比如 2×3 的张量转置后为 3×2(
tensor.t()
或torch.transpose(tensor, 0, 1)
)
- 类比:把 “2 行 3 列的表格” 转成 “3 行 2 列”,行变列、列变行。
- 用途:矩阵运算前调整维度(如满足矩阵乘法的维度要求)、图像通道转换(如从 H×W×C 转为 C×H×W)
- 重新排列张量维度顺序(permute):自由调整维度顺序假设我们有一个 3 维张量,形状为
(A, B, C)
permute(2, 0, 1)
会将维度顺序改为(C, A, B)
与转置(
transpose
)的区别:维度数量
transpose()
只能交换两个维度(比如 2 维张量转置用transpose(0,1)
,3 维张量交换前两维用transpose(0,1)
)permute()
可以一次性重新排列所有维度(比如 3 维张量可直接permute(2,0,1)
,4 维张量可permute(3,1,2,0)
等import torch# 创建一个3×4的张量 tensor = torch.randn(3, 4) print("原始张量形状:", tensor.shape)# 1. view() 方法:重塑张量形状(需要元素总数匹配) reshaped = tensor.view(2, 6) print("view(2,6) 形状:", reshaped.shape)# 2. reshape() 方法:与view类似,但更灵活 reshaped2 = tensor.reshape(12, 1) print("reshape(12,1) 形状:", reshaped2.shape)# 3. 自动计算维度:用-1表示 reshaped3 = tensor.view(-1, 2) # 自动计算第一维 print("view(-1,2) 形状:", reshaped3.shape)# 4. 转置:适用于2D张量 transposed = tensor.t() print("转置后形状:", transposed.shape)# 5. 高维转置:permute() tensor3d = torch.randn(2, 3, 4) print("\n3D张量原始形状:", tensor3d.shape) permuted = tensor3d.permute(1, 0, 2) # 交换0维和1维 print("permute(1,0,2) 后形状:", permuted.shape)
- 升维降维
核心作用:增加或减少张量的维度(不改变元素值),类似给抽屉加一层隔板(升维)或拆掉一层(降维)
- 升维(Unsqueeze):用
tensor.unsqueeze(dim)
在指定位置增加一个维度,比如形状为 (3,4) 的张量,unsqueeze(0)
后变为 (1,3,4)
- 类比:把 “3 行 4 列的表格” 放进一个 “1 格的文件夹” 里,整体变成 “1 文件夹 ×3 行 ×4 列”
- 降维(Squeeze):用
tensor.squeeze(dim)
移除指定的单维度(前提:维度大小为 1,也就是元素的数量是 1),比如 (1,3,4) 的张量squeeze(0)
后变回 (3,4)
- 类比:把 “1 文件夹 ×3 行 ×4 列” 中的文件夹拆掉,直接保留表格
import torch# 创建一个1维张量 tensor = torch.tensor([1, 2, 3, 4]) print("原始张量形状:", tensor.shape)# 1. 升维:unsqueeze() unsqueezed = tensor.unsqueeze(0) # 在第0维增加一个维度 print("unsqueeze(0) 形状:", unsqueezed.shape)unsqueezed2 = tensor.unsqueeze(1) # 在第1维增加一个维度 print("unsqueeze(1) 形状:", unsqueezed2.shape)# 2. 降维:squeeze() # 创建一个含有单维度的张量 tensor2 = torch.tensor([[1, 2, 3]]) print("\ntensor2 形状:", tensor2.shape)squeezed = tensor2.squeeze(0) # 移除第0维 print("squeeze(0) 形状:", squeezed.shape)