EP01:【DL 第二弹】张量(Tensor)的创建和常用方法
一、张量的基本创建及类型
张量作为 PyTorch 中最核心的数据结构,其本质与 NumPy 中的ndarray
一样,都是对大量数据的结构化组织。这种结构化的特点让张量能够高效地存储和处理多维数据,这也是它在深度学习中成为核心工具的重要原因 —— 无论是图像、文本还是语音数据,都可以通过张量的形式进行统一表示和运算。而张量的创建方法与 NumPy 数组的创建逻辑高度相似,这也降低了使用者的学习成本,尤其是对于熟悉 NumPy 的开发者来说,上手会更加容易。
1.1 张量的函数创建
张量最基础的创建方式是通过torch.tensor()
函数,该函数可以接收多种序列类型的数据作为输入,包括列表、元组和 NumPy 数组等。这种灵活性使得我们可以从已有的数据结构中快速构建张量,无需重新组织数据格式。
1.1.1 通过列表创建
列表是 Python 中最常用的序列类型之一,torch.tensor()
可以直接将列表转换为张量。这背后的逻辑是,列表中的元素会被依次读取并按照原有的顺序存储在张量中。张量的维度也与列表的嵌套层数相关 —— 单层列表对应一维张量,双层列表对应二维张量,以此类推。这种方式非常适合快速创建小规模的张量,尤其是在我们需要手动输入少量数据进行测试时,列表的直观性让数据的组织和修改都十分方便。
t1 = torch.tensor([1, 2])
print(f"t1:{t1}")
- 运行结果:
t1:tensor([1, 2])
1.1.2 通过元组创建
元组与列表在结构上类似,唯一的区别是元组是不可变的(创建后无法修改元素)。但在创建张量时,torch.tensor()
对元组的处理方式与列表完全一致。这意味着当我们有现成的元组数据时,无需先将其转换为列表,可直接用于创建张量,节省了数据处理的中间步骤。
t2 = torch.tensor((3, 4))
print(f"t2:{t2}")
- 运行结果:
t2:tensor([3, 4])
1.1.3 通过数组创建
NumPy 数组是科学计算中常用的数据结构,torch.tensor()
也支持直接将 NumPy 数组转换为张量。需要注意的是,张量会继承原数组的数据类型(如示例中的int32
),这保证了数据精度的一致性。这种跨库的数据转换能力非常重要,因为在实际项目中,我们常常需要先用 NumPy 进行数据预处理(如读取文件、清洗数据),再将处理好的数组转换为张量进行深度学习模型的训练或推理。
arr1 = np.array((5, 6))
t3 = torch.tensor(arr1)
print(f"t3:{t3}")
- 运行结果:
t3:tensor([5, 6], dtype=torch.int32)
1.2 张量的类型
和 NumPy 数组一样,张量也有明确的数据类型(通过dtype
属性查看),不同的数据类型对应不同的存储精度和运算效率,适用于不同的场景。
数据类型 | dtype |
---|---|
32bit浮点数 | torch.float32或torch.float |
64bit浮点数 | torch.float64或torch.double |
16bit浮点数 | torch.float16或torch.half |
8bit无符号整数 | torch.unit8 |
8bit有符号整数 | torch.int8 |
16bit有符号整数 | torch.int16或torch.short |
16bit有符号整数 | torch.int16或torch.short |
32bit有符号整数 | torch.int32或torch.int |
64bit有符号整数 | torch.int64或torch.long |
布尔型 | torch.bool |
复数型 | torch.complex64 |
import torch
import numpy as np# 1. 通过列表创建张量
t1 = torch.tensor([1, 2])
print(f"t1类型:{t1.dtype}")# 2. 通过元组创建张量
t2 = torch.tensor((3, 4))
print(f"t2类型:{t2.dtype}")# 3.通过数组创建张量
arr3 = np.array((5, 6))
t3 = torch.tensor(arr3)
print(f"t3类型:{t3.dtype}")# 4. 浮点型
print(f"{np.array([1,1, 2.2]).dtype}")
print(f"{torch.tensor(np.array([1.1, 2.2])).dtype}")
print(f"{torch.tensor([1.1, 2.2]).dtype}")# 5. 指定类型
t5 = torch.tensor([1.1, 2.5], dtype=torch.int16)
print(f"t5:{t5}")# 6. 复数型
t6 = torch.tensor(1+2j)
print(f"t6:{t6},t6类型:{t6.dtype}")
- 运行结果:
t1类型:torch.int64
t2类型:torch.int64
t3类型:torch.int32
float64
torch.float64
torch.float32
t5:tensor([1, 2], dtype=torch.int16)
t6:(1+2j),t6类型:torch.complex64
- 示例解读:
用列表或元组创建的整数张量,默认类型为
torch.int64
;
用 NumPy 数组创建的张量,类型会与原数组保持一致;
包含浮点数的列表或数组,转换后的张量类型会根据数值自动调整;
此外,我们还可以通过dtype
参数手动指定张量类型,这在需要控制内存占用或满足特定模型要求时非常有用。
1.3 张量的类型转化
在实际操作中,我们常常需要根据任务需求转换张量的数据类型,例如模型的输入和参数必须保持相同类型才能进行运算,这就需要用到张量的类型转化功能。
1.3.1 隐式转化
当张量中包含不同类型的元素时,系统会自动进行隐式转化,以保证张量中所有元素的类型一致。这种自动转化机制避免了因类型不一致导致的运算错误,但也需要我们注意 —— 隐式转化可能会导致精度损失(如整数转浮点数不会损失精度,但浮点数转整数会截断小数部分),因此在关键场景中需要手动控制类型。
# 浮点型与整型
t1 = torch.tensor([1.1, 2, 3.7])
print(f"t1: {t1},t1类型: {t1.dtype}")
# 布尔型与整型
t2 = torch.tensor([False, 2])
print(f"t2: {t2},t2类型: {t2.dtype}")
- 运行结果:
t1: tensor([1.1000, 2.0000, 3.7000]),t1类型: torch.float32
t2: tensor([0, 2]),t2类型: torch.int64
1.3.2 显示转化
显式转化在模型训练中尤为重要,例如当我们加载预训练模型时,需要确保输入数据的类型与模型参数的类型一致(通常是float32
),否则会出现运行时错误;在计算精度要求较高的场景(如科学计算),则可能需要将张量转换为float64
类型以保证结果的准确性。
(1)type()
方法
type(dtype=None, non_blocking=False, **kwargs)
- 功能:将张量转换为指定的
dtype
类型。 - 参数:
dtype
:指定要转换到的目标数据类型(如torch.float32
、torch.int64
等),如果为None
,则返回当前张量的类型。non_blocking
:可选参数,布尔值,默认为False
,当张量位于GPU上时,设置为True
可能有助于异步转换(具体行为取决于环境)。** kwargs
:其他可能的参数(较少使用)。
x = torch.tensor([1, 2, 3], dtype=torch.int32)
x_float = x.type(torch.float32)
(2)类型转化函数
t3 = torch.tensor([1, 2])
print(f"t3类型:{t3.dtype}")
print(f"t3转为浮点型:{t3.float()}")
print(f"t3转为双精度浮点型:{t3.double()}")
print(f"t3转为16位整型:{t3.short()}")
- 运行结果:
t3类型:torch.int64
t3转为浮点型:tensor([1., 2.])
t3转为双精度浮点型:tensor([1., 2.], dtype=torch.float64)
t3转为16位整型:tensor([1, 2], dtype=torch.int16)
二、张量的维度与形变
张量的维度是描述其结构的核心属性,类似于 NumPy 数组的维度概念。简单来说,维度可以理解为 “数据的组织层次”:一维张量是线性排列的元素(如向量),二维张量是由多个一维张量组成的表格(如矩阵),三维及以上的张量则可以理解为更高层次的嵌套结构(如多个矩阵组成的集合)。掌握张量的维度和形变操作,是灵活处理复杂数据的基础。
2.1 高维张量的创建
2.1.1 一维数组
一维张量是最基础的张量类型,由一组简单元素(如数字)组成的单层序列即可创建。
t1 = torch.tensor([1, 2, 3])
print(f"t1维度:{t1.ndim}")
print(f"t1形状:{t1.shape}")
print(f"t1形状:{t1.size()}")
print(f"t1中(n-1)维元素的个数:{len(t1)}")
print(f"t1中元素的个数:{t1.numel()}")
- 运行结果:
t1维度:1
t1形状:torch.Size([3])
t1形状:torch.Size([3])
t1中(n-1)维元素的个数:3
t1中元素的个数:3
2.1.2 二维数组
二维张量可以理解为由多个形状相同的一维张量组成的集合,通常用于表示矩阵,创建时需要传入双层嵌套的序列。二维张量在实际中应用广泛,例如灰度图像可以表示为二维张量(高度 × 宽度),表格数据(如 Excel 表格)也可以用二维张量存储(行 × 列)。
t2 = torch.tensor([[1, 2, 3], [4, 5, 6]])
print(f"t2维度:{t2.ndim}")
print(f"t2形状:{t2.shape}")
print(f"t2形状:{t2.size()}")
print(f"t2中(n-1)维元素的个数:{len(t2)}")
print(f"t2中元素的个数:{t2.numel()}")
- 运行结果:
t2维度:2
t2形状:torch.Size([2, 3])
t2形状:torch.Size([2, 3])
t2中(n-1)维元素的个数:2
t2中元素的个数:6
2.1.3 零维张量
零维张量是 PyTorch 中一种特殊的张量类型,它只包含一个元素,但并非 Python 原生的标量(如3),创建零维张量的方式是直接传入单个元素(而非序列)。虽然看起来与标量类似,但零维张量具有张量的所有属性(如可以放在 GPU 上进行运算、支持自动求导等),这使得它在深度学习中非常有用 —— 例如模型输出的损失值通常是零维张量,既可以参与张量运算,也能通过item()
方法转换为 Python 标量进行打印或保存。
t3 = torch.tensor([3])
print(f"t3维度:{t3.ndim}")
print(f"t3形状:{t3.shape}")
print(f"t3形状:{t3.size()}")
print(f"t3中(n-1)维元素的个数:{len(t3)}")
print(f"t3中元素的个数:{t3.numel()}")t0 = torch.tensor(3)
print(f"t0维度:{t0.ndim}")
print(f"t0形状:{t0.shape}")
print(f"t0形状:{t0.size()}")
print(f"t0中元素的个数:{t0.numel()}")
- 运行结果:
t3维度:1
t3形状:torch.Size([1])
t3形状:torch.Size([1])
t3中(n-1)维元素的个数:1
t3中元素的个数:1
t0维度:0
t0形状:torch.Size([])
t0形状:torch.Size([])
t0中元素的个数:1
2.1.4 高维张量
三维及以上的张量统称为高维张量,它们是更复杂数据的载体。以三维张量为例,它可以理解为由多个形状相同的二维张量组成的集合。三维张量在实际中常用于表示时序数据(如时间步 × 特征数)或彩色图像(通道数 × 高度 × 宽度);更高维的张量(如四维)则可能用于批量处理的图像数据(批量大小 × 通道数 × 高度 × 宽度)。理解高维张量的关键是从外到内分析其形状 —— 每个维度的数值代表该层次上包含的元素个数,总元素个数是各维度数值的乘积(如2×2×3=12)。
arr1 = np.array([[1, 2, 3], [4, 5, 6]])
arr2 = np.array([[7, 8, 9], [10, 11, 12]])
t4 = torch.tensor([arr1, arr2])
print(f"t4:{t4}")
print(f"t4维度:{t4.ndim}")
print(f"t4形状:{t4.shape}")
print(f"t4形状:{t4.size()}")
print(f"t4中(n-1)维元素的个数:{len(t4)}")
print(f"t4中元素的个数:{t4.numel()}")
- 运行结果:
t4:tensor([[[ 1, 2, 3],[ 4, 5, 6]],[[ 7, 8, 9],[10, 11, 12]]], dtype=torch.int32)
t4维度:3
t4形状:torch.Size([2, 2, 3])
t4形状:torch.Size([2, 2, 3])
t4中(n-1)维元素的个数:2
t4中元素的个数:12
2.2 张量的形变
张量的形状可以根据实际需求灵活调整,这一过程称为形变。形变不会改变张量的元素总数,只会改变元素的组织方式,常用于数据预处理或模型层之间的适配(如将卷积层的输出调整为全连接层的输入格式)。
2.2.1 flatten()
拉平
flatten(start_dim=0, end_dim=-1)
- 功能:将张量从
start_dim
到end_dim
的维度进行拉平操作,默认情况下会将整个张量拉平为一维张量。 - 参数:
start_dim
:指定开始拉平的维度,默认为0
(即从第0维开始)。end_dim
:指定结束拉平的维度,默认为-1
(即到最后一维结束)。
t1 = torch.tensor([[1, 2, 3], [4, 5, 6]])
print(f"t1拉平:{t1.flatten()}")arr1 = np.array([[1, 2, 3], [4, 5, 6]])
arr2 = np.array([[7, 8, 9], [10, 11, 12]])
t2 = torch.tensor([arr1, arr2])
print(f"t2拉平:{t2.flatten()}")t0 = torch.tensor(1)
print(f"t0拉平:{t0.flatten()}")
- 运行结果:
t1拉平:tensor([1, 2, 3, 4, 5, 6])
t2拉平:tensor([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], dtype=torch.int32)
t0拉平:tensor([1])
2.2.2 reshape()
任意变形
reshape(*shape)
- 功能:按照指定的形状对张量进行重新排列,返回一个新的张量,新张量与原张量共享数据(但如果形状不兼容则会复制数据)。
- 参数:
*shape
:一个整数序列,指定新张量的形状。形状中的元素需满足所有元素的乘积等于原张量中元素的总个数(即numel()
的结果)。可以使用-1
作为形状中的一个元素,此时该维度的大小会根据其他维度的大小和总元素个数自动计算得出。
arr1 = np.array([[1, 2, 3], [4, 5, 6]])
arr2 = np.array([[7, 8, 9], [10, 11, 12]])
t3 = torch.tensor([arr1, arr2])
print(f"t3转为2行6列:{t3.reshape(2, 6)}")
print(f"t3转为1行12列:{t3.reshape(12)}")
print(f"t3转为1行12列:{t3.reshape(12,)}")
print(f"t3转为(1, 2, 6):{t3.reshape(1, 2, 6)}")
- 运行结果:
t3转为2行6列:tensor([[ 1, 2, 3, 4, 5, 6],[ 7, 8, 9, 10, 11, 12]], dtype=torch.int32)
t3转为1行12列:tensor([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], dtype=torch.int32)
t3转为1行12列:tensor([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], dtype=torch.int32)
t3转为(1, 2, 6):tensor([[[ 1, 2, 3, 4, 5, 6],[ 7, 8, 9, 10, 11, 12]]], dtype=torch.int32)
三、特殊张量的创建
在数值计算和深度学习中,我们经常需要创建一些具有特殊取值的张量(如全 0、全 1、随机数等),这些张量通常用于初始化模型参数、生成占位符或构建测试数据。PyTorch 提供了一系列便捷的函数来创建这些特殊张量,避免了手动输入的繁琐。
3.1 特殊取值的张量
3.1.1 全0张量
全 0 张量常用于初始化模型的偏置参数(bias),或作为需要后续填充数据的占位符(例如在循环中累计结果时,先创建全 0 张量再逐步更新)。
t1 = torch.zeros([2, 3])
print(f"t1:{t1}")
- 运行结果:
t1:tensor([[0., 0., 0.],[0., 0., 0.]])
3.1.2 全1张量
全 1 张量的用途与全 0 张量类似,例如在某些模型中作为初始权重,或用于生成掩码(通过与其他张量相乘实现元素的选择)。
t2 = torch.ones([3, 3])
print(f"t2:{t2}")
- 运行结果:
t2:tensor([[1., 1., 1.],[1., 1., 1.],[1., 1., 1.]])
3.1.3 对角矩阵
对角矩阵在线性代数运算中很常见,例如表示缩放矩阵或协方差矩阵(当数据各维度独立时)。
t3 = torch.tensor([1, 2, 3])
t3_ = torch.diag(t3)
print(f"t3_:{t3_}")
- 运行结果:
t3_:tensor([[1, 0, 0],[0, 2, 0],[0, 0, 3]])
3.1.4 rand()
服从0-1均匀分布
均匀分布的随机张量常用于初始化模型权重,尤其是在需要打破对称性的场景(如神经网络的第一层权重),避免所有神经元的输出相同。
rand(*size, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False)
- 功能:创建一个指定形状的张量,其中的元素是从区间[0, 1)上的均匀分布中随机采样得到的。
- 参数:
*size
:整数序列,指定要创建的张量的形状(如rand(2, 3)
创建一个2行3列的张量)。out
:可选参数,用于指定输出张量(较少使用)。dtype
:可选参数,指定张量的数据类型,默认为torch.float32
。layout
:可选参数,指定张量的内存布局,默认为torch.strided
。device
:可选参数,指定张量所在的设备(如CPU或GPU)。requires_grad
:布尔值,默认为False
,指定张量是否需要计算梯度。
t4 = torch.rand(2, 3)
print(f"t4:{t4}")
- 运行结果:
t4:tensor([[0.4572, 0.3647, 0.4623],[0.9804, 0.5066, 0.3742]])
3.1.5 randn()
服从标准正态分布
标准正态分布的随机数在权重初始化中也很常用,例如在 ReLU 激活函数的网络中,常使用正态分布初始化权重以避免梯度消失或爆炸。
randn(*size, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False)
- 功能:创建一个指定形状的张量,其中的元素是从标准正态分布(均值为0,标准差为1)中随机采样得到的。
- 参数:
*size
:整数序列,指定要创建的张量的形状(如randn(2, 3)
创建一个2行3列的张量)。out
:可选参数,用于指定输出张量(较少使用)。dtype
:可选参数,指定张量的数据类型,默认为torch.float32
。layout
:可选参数,指定张量的内存布局,默认为torch.strided
。device
:可选参数,指定张量所在的设备(如CPU或GPU)。requires_grad
:布尔值,默认为False
,指定张量是否需要计算梯度。
t5 = torch.randn(2, 3)
print(f"t5:{t5}")
- 运行结果:
t5:tensor([[ 0.3925, -1.2600, 1.3201],[ 1.6919, 0.0334, -0.0843]])
3.1.6 normal()
服从指定正态分布
normal(mean, std, size=None, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False)
- 功能:创建一个张量,其中的元素是从指定均值(
mean
)和标准差(std
)的正态分布中随机采样得到的。 - 参数:
mean
:可以是标量或张量,指定正态分布的均值。如果是张量,其形状需与std
兼容,且生成的张量形状与mean
(或std
)一致(当size
为None
时)。std
:可以是标量或张量,指定正态分布的标准差,需与mean
的形状兼容。size
:可选参数,整数序列,指定要创建的张量的形状。如果提供了size
,则mean
和std
需为标量。out
:可选参数,用于指定输出张量(较少使用)。dtype
:可选参数,指定张量的数据类型。layout
:可选参数,指定张量的内存布局,默认为torch.strided
。device
:可选参数,指定张量所在的设备(如CPU或GPU)。requires_grad
:布尔值,默认为False
,指定张量是否需要计算梯度。
t6 = torch.normal(2, 3, size=(2, 2))
print(f"t6 均值为2,标准差为3:{t6}")
- 运行结果:
t6 均值为2,标准差为3:tensor([[ 4.3746, -2.2126],[-0.1069, 1.1403]])
3.1.7 randint()
整数随机采样结果
整数随机张量常用于生成索引(如随机选择样本)或模拟离散数据(如分类标签)。
randint(low=0, high, size=None, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False)
- 功能:创建一个指定形状的张量,其中的元素是从区间
[low, high)
(左闭右开)内随机采样的整数。 - 参数:
low
:可选参数,整数,指定随机整数的下界(包含),默认为0。high
:整数,指定随机整数的上界(不包含)。size
:整数序列,指定要创建的张量的形状。out
:可选参数,用于指定输出张量(较少使用)。dtype
:可选参数,指定张量的数据类型,默认为torch.int64
。layout
:可选参数,指定张量的内存布局,默认为torch.strided
。device
:可选参数,指定张量所在的设备(如CPU或GPU)。requires_grad
:布尔值,默认为False
,指定张量是否需要计算梯度。
t7 = torch.randint(1, 10, [2, 4])
print(f"t7 在1-10之间随机抽取整数组成2行4列的张量:{t7}")
- 运行结果:
t7 在1-10之间随机抽取整数组成2行4列的张量:tensor([[5, 2, 3, 1],[2, 3, 8, 8]])
3.1.8 arange()
/linspace()
arange()
arange(start=0, end, step=1, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False)
- 功能:创建一个包含从
start
到end
(左闭右开)的有序序列的张量,相邻元素的差值为step
。 - 参数:
start
:可选参数,整数或浮点数,指定序列的起始值,默认为0。end
:整数或浮点数,指定序列的结束值(不包含在序列中)。step
:可选参数,整数或浮点数,指定相邻元素的步长,默认为1。out
:可选参数,用于指定输出张量(较少使用)。dtype
:可选参数,指定张量的数据类型。layout
:可选参数,指定张量的内存布局,默认为torch.strided
。device
:可选参数,指定张量所在的设备(如CPU或GPU)。requires_grad
:布尔值,默认为False
,指定张量是否需要计算梯度。
linspace()
linspace(start, end, steps=100, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False)
- 功能:创建一个包含从
start
到end
(闭区间)的等距序列的张量,序列中元素的个数由steps
指定。 - 参数:
start
:整数或浮点数,指定序列的起始值。end
:整数或浮点数,指定序列的结束值(包含在序列中)。steps
:可选参数,整数,指定序列中元素的个数,默认为100。out
:可选参数,用于指定输出张量(较少使用)。dtype
:可选参数,指定张量的数据类型。layout
:可选参数,指定张量的内存布局,默认为torch.strided
。device
:可选参数,指定张量所在的设备(如CPU或GPU)。requires_grad
:布尔值,默认为False
,指定张量是否需要计算梯度。
t8 = torch.arange(5)
print(f"t8:{t8}")
t9 = torch.arange(1, 5, 0.5)
print(f"t9 从1-5(左闭右开),每隔0.5取1个值:{t9}")
t10 = torch.linspace(1, 5, 3)
print(f"t10 从1-5(闭),等距取3个数:{t10}")
- 运行结果:
t8:tensor([0, 1, 2, 3, 4])
t9 从1-5(左闭右开),每隔0.5取1个值:tensor([1.0000, 1.5000, 2.0000, 2.5000, 3.0000, 3.5000, 4.0000, 4.5000])
t10 从1-5(闭),等距取3个数:tensor([1., 3., 5.])
3.1.9 empty()
未初始化的指定形状矩阵
由于无需初始化值,empty()
的创建速度比zeros()
或ones()
更快,适合需要快速创建张量并立即填充数据的场景(如读取外部数据时先创建空张量,再写入数据)。
empty(*size, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False, pin_memory=False)
- 功能:创建一个具有指定形状的张量,张量中的元素值未经过初始化,是内存中当前存在的随机值。
- 参数:
*size
:整数序列,指定要创建的张量的形状(如empty(2, 3)
创建一个2行3列的张量)。out
:可选参数,用于指定输出张量(较少使用)。dtype
:可选参数,指定张量的数据类型,默认为torch.float32
。layout
:可选参数,指定张量的内存布局,默认为torch.strided
。device
:可选参数,指定张量所在的设备(如CPU或GPU)。requires_grad
:布尔值,默认为False
,指定张量是否需要计算梯度。pin_memory
:布尔值,默认为False
,若为True
,则在CPU上分配锁页内存(主要用于与GPU交互时提升性能)。
t11 = torch.empty(2, 3)
print(f"t11 2行3列:{t11}")
- 运行结果:
t11 2行3列:tensor([[0., 0., 0.],[0., 0., 0.]])
3.1.10 full()
根据指定形状填充数据
full()
比ones()
更灵活,可指定任意填充值,例如生成全为 0.5 的张量用于初始化概率分布参数。
full(size, fill_value, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False)
- 功能:创建一个具有指定形状的张量,张量中的所有元素都被填充为
fill_value
指定的值。 - 参数:
size
:整数序列,指定要创建的张量的形状(如full([2, 3], 5)
创建一个2行3列的张量)。fill_value
:标量,指定用于填充张量的数值。out
:可选参数,用于指定输出张量(较少使用)。dtype
:可选参数,指定张量的数据类型。layout
:可选参数,指定张量的内存布局,默认为torch.strided
。device
:可选参数,指定张量所在的设备(如CPU或GPU)。requires_grad
:布尔值,默认为False
,指定张量是否需要计算梯度。
t12 = torch.full([2, 3], 5)
print(f"t12:{t12}")
- 运行结果:
t12:tensor([[5, 5, 5],[5, 5, 5]])
3.2 指定形状数组的创建
当我们需要创建与已有张量形状相同的特殊张量时,可以使用带_like
后缀的函数,例如full_like()
、randint_like()
、zeros_like()
等。这些函数会自动匹配输入张量的形状,无需手动指定维度,大大减少了代码中的硬编码,也避免了因形状不匹配导致的错误。
这种形状复用的机制在处理批量数据时非常高效,例如对一批图像数据进行零填充时,zeros_like(images)
可以快速生成与图像形状相同的掩码。
import torcht1 = torch.tensor([1, 2, 3])
print(f"t1: {t1}")t1_ = torch.full_like(t1, 5)
print(f"t1_: {t1_}")t1_1 = torch.randint_like(t1, 1, 10)
print(f"t1_1: {t1_1}")t1_2 = torch.zeros_like(t1)
print(f"t1_2: {t1_2}")# ×1. 转化前后的数据类型需保持一致
# t1_3 = torch.randn_like(t1)
- 运行结果:
t1: tensor([1, 2, 3])
t1_: tensor([5, 5, 5])
t1_1: tensor([3, 9, 8])
t1_2: tensor([0, 0, 0])
四、张量和其他类型之间的转化
张量、NumPy 数组和 Python 列表是数据处理中常用的三种结构,它们各有优势:张量适合 GPU 加速和自动求导,NumPy 数组适合 CPU 上的科学计算,列表适合简单的数据存储和遍历。因此,这三种类型之间的相互转化是实际应用中频繁涉及的操作。
4.1 转化为数组
t1 = torch.tensor([1, 2, 3])
print(f"t1类型:{t1.dtype}")
# .numpy
t1_ = t1.numpy()
print(f"t1_类型:{t1_.dtype}")
# np.array()
t1_1 = np.array(t1)
print(f"t1_1类型:{t1_1.dtype}")
- 运行结果:
t1类型:torch.int64
t1_类型:int64
t1_1类型:int64
- 示例解读:
两种方法的选择取决于是否需要共享内存:如果只是临时使用数组进行计算,
numpy()
更高效(无需复制数据);如果需要独立修改数组,则np.array()
更安全。这种转化在需要使用 NumPy 的函数(如np.save()
保存数据、np.mean()
计算均值)时非常必要,因为很多传统科学计算库只支持 NumPy 数组。
4.2 转化为列表
t2 = torch.tensor([1, 2, 3])
# .tolist
t2_ = t2.tolist()
print(f"t2_:{t2_}")
# list()
t2_1 = list(t2)
print(f"t2_1:{t2_1}")
- 运行结果:
t2_:[1, 2, 3]
t2_1:[tensor(1), tensor(2), tensor(3)]
- 示例解读:
实际应用中,
tolist()
更为常用,因为它能将张量数据完全转换为原生 Python 类型,方便与其他不支持张量的库交互。
4.3 转化为数值
n = torch.tensor(1)
n.item()
- 示例解读:
零维张量(只包含一个元素)可以通过
item()
方法转换为 Python 原生数值(如int
或float
)。需要注意的是,只有零维张量支持item()
方法,高维张量会报错,此时需要先通过索引取出单个元素(如t1[0].item()
)再转换。
五、张量的深拷贝
在 Python 中,使用等号=
对张量进行赋值时,实际上是浅拷贝—— 新变量与原变量指向同一块内存,修改其中一个会影响另一个。这种特性在某些场景下会导致意外的数据修改(如保存中间结果时,原张量的变化会污染保存的副本)。
为了避免这种问题,需要使用clone()
方法进行深拷贝,即创建一个与原张量元素相同但内存独立的新张量。深拷贝在深度学习中非常重要,例如在记录模型训练过程中的参数时,需要通过clone()
保存参数的当前状态,避免后续参数更新影响历史记录;在实现某些算法(如动量法)时,也需要保存上一步的梯度值,此时深拷贝能保证数据的独立性。
import torcht1 = torch.arange(10)
print(f"t1:{t1}")print('--'*50)t1_1 = t1
print(f"t1_1:{t1_1}")
t1[0] = 100
print(f"t1:{t1}")
print(f"t1_1:{t1_1}")print('--'*50)t1_2 = t1.clone()
print(f"t1_2:{t1_2}")
t1[9] = 900
print(f"t1:{t1}")
print(f"t1_2:{t1_2}")
- 运行结果:
t1:tensor([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
----------------------------------------------------------------------------------------------------
t1_1:tensor([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
t1:tensor([100, 1, 2, 3, 4, 5, 6, 7, 8, 9])
t1_1:tensor([100, 1, 2, 3, 4, 5, 6, 7, 8, 9])
----------------------------------------------------------------------------------------------------
t1_2:tensor([100, 1, 2, 3, 4, 5, 6, 7, 8, 9])
t1:tensor([100, 1, 2, 3, 4, 5, 6, 7, 8, 900])
t1_2:tensor([100, 1, 2, 3, 4, 5, 6, 7, 8, 9])
微语录:不必问我,你可以有自己的答案。——《罗小黑战记》