**torch
**是 PyTorch 库的核心模块,提供了以下关键功能:
-
张量(Tensor):类似于 NumPy 的 ndarray,但可以无缝地在 CPU 或 GPU 上运行,并且支持自动微分,是深度学习模型中数据的主要表示形式。
-
数学运算:包括基本的数学运算符重载(如加减乘除)、矩阵运算(如矩阵乘法、点积、卷积)、统计函数(如求和、平均值、最大值、最小值等)以及更复杂的数学操作。
-
数据类型转换 :允许用户创建不同数据类型的张量(例如
float
,double
,int8
,bool
等),并进行数据类型的相互转换。 -
随机数生成:提供了一系列方法用于生成符合不同分布(如均匀分布、正态分布、泊松分布等)的随机张量。
-
线性代数运算:包括矩阵分解(如 SVD、LU、QR 分解)、特征值与特征向量计算、矩阵逆、伪逆以及其他相关的线性代数操作。
-
自动微分 :通过
autograd
子模块实现,允许张量上的操作自动生成梯度,为训练神经网络提供便利。 -
存储和序列化:支持将张量保存到磁盘以及从磁盘加载,同时还能序列化和反序列化整个模型结构及其参数。
-
多GPU支持:能够将计算任务分配到多个GPU上进行并行处理,提高计算效率。
-
神经网络层与优化器 :虽然这些不是
torch
模块的一部分,但 PyTorch 中的torch.nn
和torch.optim
模块分别提供了构建和训练神经网络所需的层组件及优化算法。
1. 张量(Tensor)
在 PyTorch 中,张量(Tensor)是其核心数据结构之一,它类似于 NumPy 的 ndarray,但具备更多特性,尤其是支持 GPU 加速和自动微分。以下是 torch.Tensor
的详细介绍:
-
定义与创建:
-
张量可以表示多维数组,支持多种数据类型,包括浮点数、整数、布尔值等。
-
创建张量的常见方法有:
Python
1import torch 2 3# 直接从数据创建张量 4x = torch.tensor([1, 2, 3]) # 一维张量 5y = torch.tensor([[1, 2], [3, 4]]) # 二维张量 6 7# 根据现有张量或 Python 列表创建 8z = torch.from_numpy(np.array([1, 2, 3])) # 从 NumPy 数组创建 9a = torch.zeros(3, 4) # 创建全零张量 10b = torch.ones_like(x) # 创建与给定张量形状相同且元素为1的张量 11c = torch.randn(5, 6) # 创建服从正态分布的随机张量 12 13# 指定设备(CPU 或 GPU) 14if torch.cuda.is_available(): 15 device = torch.device('cuda') 16 d = torch.tensor([1, 2, 3], device=device) # 创建在 GPU 上的张量
-
-
属性:
- 张量的维度可以通过
.shape
或.size()
获取。 - 数据类型可通过
.dtype
查看。 - 存储位置(设备)通过
.device
获取。
- 张量的维度可以通过
-
操作:
- 张量支持丰富的数学运算,包括但不限于加法、减法、乘法、矩阵乘法、点积、求和、平均、最大值/最小值、指数、对数、索引访问、切片等。
- 可以进行广播机制下的运算,类似 NumPy。
-
动态特性:
- PyTorch 张量具有动态形状,可以在运行时修改张量的大小和形状(例如使用
torch.view()
或torch.reshape()
)。
- PyTorch 张量具有动态形状,可以在运行时修改张量的大小和形状(例如使用
-
自动微分:
- 当一个张量的
requires_grad
属性设置为True
时,它会记录在其上的所有运算,形成一个计算图。调用.backward()
方法时,会根据链式法则自动生成并累积梯度。
- 当一个张量的
-
存储和序列化:
- 张量可以通过
torch.save()
和torch.load()
进行持久化存储和加载。 - 使用
torch.jit.script
或torch.onnx.export
可将包含张量和运算的模型转换为可执行文件或ONNX格式,便于部署和跨平台使用。
- 张量可以通过
-
与其他库集成:
- 与 NumPy 的无缝交互:可以直接将张量转换为 NumPy 数组,并反之亦然。
总之,torch.Tensor
是 PyTorch 库中的基石,提供了构建和训练深度学习模型所需的数据容器和高效计算环境。
2. 数学运算
在 PyTorch 中,torch
模块提供了丰富的数学运算功能,这些运算可以应用于 torch.Tensor
对象。以下是 torch
模块中部分关键的数学运算:
-
基本数学运算:
- 加法:
a + b
或torch.add(a, b)
- 减法:
a - b
或torch.sub(a, b)
- 乘法(元素级):
a * b
或torch.mul(a, b)
- 除法(元素级):
a / b
或torch.div(a, b)
- 幂运算(元素级):
a ** b
或torch.pow(a, b)
- 点积(内积):对于向量
a
和b
,使用torch.dot(a, b)
或(a * b).sum(dim=-1)
- 矩阵乘法:
torch.mm(a, b)
或torch.matmul(a, b)
(支持广播和多维张量)
- 加法:
-
聚合操作:
- 求和:
a.sum(dim=...)
计算指定维度上的和 - 平均值:
a.mean(dim=...)
- 最大值和最小值:
a.max(dim=...)
和a.min(dim=...)
- 标准差和方差:
a.std(dim=...)
和a.var(dim=...)
- 求和:
-
指数与对数运算:
- 自然指数:
torch.exp(x)
- 自然对数:
torch.log(x)
- 常用对数:
torch.log10(x)
- 自然指数:
-
比较运算:
- 大于、小于、等于等比较操作符:
a > b
,a < b
,a == b
,返回的是布尔张量。
- 大于、小于、等于等比较操作符:
-
索引和切片:
- 类似 NumPy 的索引操作:
a[indices]
- 切片操作:
a[:, start:end:step]
- 类似 NumPy 的索引操作:
-
矩阵运算:
- 矩阵求逆:
torch.inverse(matrix)
- 矩阵转置:
matrix.T
或者torch.t(matrix)
- QR 分解:
torch.qr(matrix)
- SVD 分解:
torch.svd(matrix)
- Cholesky 分解:
torch.cholesky(matrix)
- LU 分解:
torch.lu(matrix)
- 矩阵求逆:
-
随机数生成:
- 正态分布:
torch.randn(size=(...))
- 均匀分布:
torch.rand(size=(...))
- 其他分布:例如泊松分布 (
torch.poisson(lamda, size=(...))
) 和伯努利分布 (torch.bernoulli(probs, size=(...))
)
- 正态分布:
-
线性代数运算:
- 行列式:
torch.det(matrix)
- 解线性系统:
torch.solve(b, A)
- 范数计算:
torch.norm(tensor, p=None, dim=None, keepdim=False, out=None)
- 行列式:
所有这些数学运算都支持自动微分,并且能够灵活地在 CPU 或 GPU 上运行。此外,如果涉及到的数据分布在多个设备上,还可以进行跨设备的运算。
3. 数据类型转换
在 PyTorch 中,数据类型转换是通过 torch.Tensor
类的方法或直接使用 torch.*Tensor
构造函数来实现的。以下是一些详细的数据类型转换方法:
-
通过构造函数转换: 当你创建一个新的张量时,可以通过指定其数据类型来完成转换。
Python
1# 创建一个浮点型张量并转换为整型 2float_tensor = torch.tensor([1.23, 4.56], dtype=torch.float32) 3int_tensor = torch.tensor(float_tensor, dtype=torch.int32) 4 5# 直接创建特定类型张量 6long_tensor = torch.tensor([1, 2, 3], dtype=torch.long)
-
通过
.to()
方法转换 : 张量上的.to()
方法可以用于改变现有张量的数据类型,并可以选择将其移动到不同的设备(如CPU或GPU)上。Python
1float_tensor = torch.tensor([1.0, 2.0]) 2int_tensor = float_tensor.to(torch.int32) # 只改变数据类型 3cuda_int_tensor = float_tensor.to(torch.device('cuda'), dtype=torch.int32) # 改变设备和数据类型
-
使用
.type()
或.astype()
方法:.type(new_type)
:将张量转换为新的数据类型。.type()
在旧版本中广泛使用,但在新版本中推荐使用.to()
方法。.astype(dtype, copy=True)
:与 NumPy 的接口类似,用于转换数据类型。此方法可能需要复制张量内容,取决于是否要求copy
参数为True
。
Python
1float_tensor = torch.tensor([1.0, 2.0]) 2int_tensor = float_tensor.type(torch.int32) # 老式用法 3new_float_tensor = int_tensor.astype(torch.float32) # 类似NumPy的接口,不过在PyTorch中不常用
常见的数据类型包括但不限于:
torch.float32
或torch.float
: 32位单精度浮点数torch.float64
或torch.double
: 64位双精度浮点数torch.int32
或torch.int
: 默认的32位有符号整数torch.int64
或torch.long
: 通常用于索引操作的64位有符号整数torch.uint8
: 无符号8位整数,常用于存储像素值
转换时需要注意的是,从浮点数到整数类型的转换会进行截断(不是四舍五入),并且从低精度到高精度转换通常是安全的,但反之可能会导致精度损失。
4. 随机数生成
在PyTorch中,随机数生成是通过torch库提供的多种方法来实现的,这些方法允许用户根据不同的概率分布创建不同形状和数据类型的随机张量。以下是一些常用的PyTorch随机数生成函数:
-
均匀分布(Uniform Distribution):
torch.rand(*sizes, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False)
该函数返回一个指定形状sizes
的张量,其中元素是从[0, 1)区间内的均匀分布中抽取的。
示例:
Python1uniform_tensor = torch.rand(3, 4)
-
标准正态分布(Standard Normal Distribution):
torch.randn(*sizes, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False)
这个函数返回一个形状为sizes
的张量,其元素服从标准正态分布(均值为0,方差为1)。
示例:
Python1normal_tensor = torch.randn(5, 2)
-
离散分布(Discrete Distributions):
torch.randint(low, high, *sizes, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False)
返回从low
到high-1
范围内的整数均匀分布中的随机数组成的张量。
示例:
Python1discrete_tensor = torch.randint(0, 10, (2, 3))
-
泊松分布(Poisson Distribution):
torch.poisson(lam=1, *size, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False)
生成形状为size
的张量,其元素服从参数为lam
的泊松分布。
示例:
Python1poisson_tensor = torch.poisson(torch.tensor([2.0, 3.0]), (2,))
-
随机排列(Random Permutation):
torch.randperm(n, out=None, dtype=torch.long, device=None)
返回一个大小为n
的一维张量,其中包含从0到n-1
之间的一个随机排列。
示例:
Python1permuted_indices = torch.randperm(10)
-
线性间距向量(Linearly-Spaced Vector):
torch.linspace(start, end, steps, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False)
不是严格意义上的随机数生成函数,但它会创建一个从start
到end
等间距的steps
个数的张量。
示例:
Python1linspace_tensor = torch.linspace(0, 1, 5)
-
其它分布 : PyTorch还支持更多复杂的概率分布,例如高斯分布、伯努利分布、指数分布等,可以通过
torch.distributions
模块来创建相应的分布对象并使用.sample()
方法来生成随机数。
确保在进行随机实验时,能够控制随机种子以确保可复现性,可以使用 torch.manual_seed(seed)
或 torch.cuda.manual_seed_all(seed)
来设置全局随机种子。
5. 线性代数运算
在PyTorch中,线性代数运算被广泛应用于深度学习和数值计算中。以下是一些PyTorch模块提供的主要线性代数操作:
-
矩阵乘法:
torch.matmul(a, b)
:进行矩阵乘法或向量-矩阵乘法(点积)。torch.mm(a, b)
:用于2维张量的矩阵乘法,等同于matmul
在特定场景下。torch.bmm(a, b)
:进行两个3D张量的批量矩阵乘法,每个2D切片独立相乘。
-
点积、内积与范数:
torch.dot(a, b)
:计算两个向量的点积(内积)。a @ b
:Python 3.5及更高版本中的矩阵乘法运算符,等价于torch.matmul(a, b)
。torch.norm(input, p=2, dim=None, keepdim=False, out=None)
:计算张量的各个维度上的范数(默认为L2范数)。
-
转置和矩阵求逆:
torch.t(input)
或input.T
:计算张量的转置。torch.transpose(input, dim0, dim1)
:根据指定的维度交换输入张量的轴。torch.inverse(A)
:计算方阵A的逆矩阵,返回一个与A形状相同的张量。
-
矩阵分解:
torch.svd()
:奇异值分解(Singular Value Decomposition)。torch.eig(eigenvectors=True)
:计算方阵的特征值和特征向量。torch.linalg.qr(input, mode='reduced')
:QR分解。torch.lu(input, pivot=True)
:LU分解。
-
行列式与迹:
torch.det(input)
:计算方阵的行列式。torch.trace(input)
:计算对角线上元素之和,即矩阵的迹。
-
特征值与特征向量:
torch.linalg.eigvals(A)
:只计算方阵A的特征值。torch.linalg.eigvalsh(A)
:计算Hermitian矩阵A的特征值。
-
正交化与归一化:
torch.nn.functional.normalize(input, p=2, dim, eps=1e-12, out=None)
:对张量进行长度规范化,使其成为单位向量。
-
标量与矩阵运算:
torch.mul(a, b)
或a * b
:按元素逐个相乘。torch.add(a, b)
或a + b
:按元素逐个相加。- 更多高级线性代数函数如矩阵求幂、解线性系统等可通过
torch.linalg
子模块实现。
-
广播规则下的数学运算: PyTorch支持NumPy风格的广播规则,在执行大多数线性代数运算时会自动应用这些规则来匹配不同大小的张量进行操作。
以上函数可以帮助用户在构建神经网络模型或者进行科学计算时方便地处理涉及线性代数的各种问题。
6. 存储和序列化
在PyTorch中,存储和序列化是模型部署、迁移学习以及持久保存训练结果的关键环节。以下是如何使用torch
模块中的功能进行存储和序列化的详细介绍:
存储张量与模型参数
-
存储张量 : 使用
torch.save()
函数可以将张量或任何可序列化的Python对象(如模型)保存到磁盘。Python
1# 保存单个张量 2torch.save(tensor, 'tensor.pt') 3 4# 保存字典或列表等复杂结构,其中包含张量 5model_params = {'weights': weights_tensor, 'bias': bias_tensor} 6torch.save(model_params, 'model_params.pt')
-
加载张量 : 使用
torch.load()
函数从磁盘加载先前保存的张量或其他对象。Python
1tensor = torch.load('tensor.pt') 2model_params = torch.load('model_params.pt')
序列化模型
-
保存整个模型 : 对于继承自
torch.nn.Module
的模型,可以直接保存整个模型及其状态(包括权重和优化器状态)。Python
1torch.save(model.state_dict(), 'model.pth') # 只保存模型参数 2torch.save({'model_state_dict': model.state_dict(), 3 'optimizer_state_dict': optimizer.state_dict()}, 4 'model_and_optimizer.pth') # 保存模型和优化器状态
-
加载模型 : 加载时,需要创建一个与保存时相同架构的新模型实例,并使用
.load_state_dict()
方法恢复其参数。Python
1model = MyModelClass() 2model.load_state_dict(torch.load('model.pth')) 3 4# 如果还保存了优化器状态 5optimizer = torch.optim.SGD(model.parameters(), lr=0.01) 6checkpoint = torch.load('model_and_optimizer.pth') 7model.load_state_dict(checkpoint['model_state_dict']) 8optimizer.load_state_dict(checkpoint['optimizer_state_dict'])
-
脚本模式(Scripting)与 TorchScript:
- 要序列化模型为独立运行的脚本,可以使用
torch.jit.script()
或者torch.jit.trace()
来编译模型到 TorchScript。 - 编译后的模型可以通过
torch.jit.save()
和torch.jit.load()
进行保存和加载,并且可以在不依赖 PyTorch 环境的情况下运行。
Python
1scripted_model = torch.jit.script(model) # 或者 trace_module() for tracing 2torch.jit.save(scripted_model, 'scripted_model.pt') 3 4loaded_scripted_model = torch.jit.load('scripted_model.pt')
- 要序列化模型为独立运行的脚本,可以使用
通过上述方法,用户能够灵活地保存和加载模型参数,甚至可以将模型转换成独立执行文件,便于部署到没有安装完整 PyTorch 的环境或者移动端设备上。
7. 多GPU支持
在PyTorch中,多GPU支持主要通过torch.nn.DataParallel
和torch.nn.parallel.DistributedDataParallel
两个模块实现。这两个模块都允许模型在多个GPU上并行执行,从而加速训练过程。
-
torch.nn.DataParallel
:-
nn.DataParallel
是一种简单且易于使用的多GPU并行机制,它将模型复制到所有可用的GPU设备上,并自动分配输入数据的不同部分到各个GPU进行前向传播计算。 -
使用时,需要将模型包装在一个
DataParallel
实例内:
Python1model = MyModel() 2if torch.cuda.device_count() > 1: 3 model = nn.DataParallel(model) 4model.to(device) # device可以是'cuda:0', 'cuda:1', etc.
-
在后向传播过程中,梯度会在各个GPU间同步,然后更新主GPU上的模型参数。
-
-
torch.nn.parallel.DistributedDataParallel
(DDP):-
DDP是一种更高级、更灵活也更高效的多GPU并行策略,适用于大规模分布式训练场景。
-
它不仅支持单机多卡(multi-GPU),还支持多机多卡训练,在大型集群上实现高效的大规模深度学习模型训练。
-
使用DPP需要初始化进程组、设置全局唯一的rank和world_size,并将模型封装进
DistributedDataParallel
:Python
1import torch.distributed as dist 2from torch.nn.parallel import DistributedDataParallel as DDP 3 4os.environ['MASTER_ADDR'] = 'localhost' 5os.environ['MASTER_PORT'] = '12355' 6 7rank = int(os.environ['RANK']) 8world_size = int(os.environ['WORLD_SIZE']) 9 10dist.init_process_group(backend='nccl', init_method='env://', rank=rank, world_size=world_size) 11 12model = MyModel() 13model = DDP(model, device_ids=[rank], output_device=rank)
-
DDP不仅会把模型参数分布在不同的GPU上,还会在每个GPU上维护模型的一份完整副本,这使得模型可以在每个GPU上独立地完成前向传播和反向传播,然后通过高效的通信库如NCCL来聚合梯度,最后在每个GPU上更新参数。
-
注意:使用多GPU并行时,要确保数据正确地分布在各个GPU之间。对于简单的数据并行处理,DataLoader
可以通过设置num_workers
和pin_memory
属性以优化CPU与GPU之间的数据传输。而对于DDP,通常会结合torch.utils.data.distributed.DistributedSampler
来均衡地将数据分配到不同进程中。此外,还需考虑网络结构中的批次归一化层(BatchNorm)在多GPU训练时的特殊性,以及可能需要调整的学习率和其他超参数。