2、PyTorch 简介


一、PyTorch 简介

在这里插入图片描述在这里插入图片描述

1.1、PyTorch 模块

ComponentDescription
torchA Tensor library like NumPy, with strong GPU support
torch.utilsDataLoader and other utility functions for convenience
torch.nnA neural networks library deeply integrated with autograd designed for maximum flexibility
torch.autogradA tape-based automatic differentiation library that supports all differentiable Tensor operations in torch
torch.multiprocessingPython multiprocessing, but with magical memory sharing of torch Tensors across processes. Useful for data loading and Hogwild training
torch.jitA compilation stack (TorchScript) to create serializable and optimizable models from PyTorch code

1.2、PyTorch 计算图

1.2.1、静态计算图

老版的TensorFlow 使用静态图(提前创建好) 来表示计算任务,由节点和边组成,节点表示 Tensor(输入、输出、W、B) 或者 OP(运算符),边(数据流动边、梯度流动边)表示 Tensor 和 OP 之间的依赖关系;Tensor 在图中通过运算符(OP, eg:数学运算 ADD、激活函数、神经网络层)进行传递和变换, 一个 op 可以获得 0 个(输入叶子节点)或多个张量(Tensor), 通过创建会话(Session)对象来执行计算,产生 0 个(输出根节点)或多个Tensor。所以,TensorFlow 的工作模式分为以下两步:

  • Define the computation graph
  • Run the graph (with data) in Session

为什么需要提前定义好计算图,然后再去执行运算?

  • Save computation:only run subgraphs that lead to the values you want to fetch
  • Facilitate distributed computation: spread the work across multiple CPUs, GPUs, or devices
  • Facilitates auto-differentiation:break computation into small, differential pieces

这里写图片描述


1.2.2、动态计算图

Pytorch 中的计算图是动态图,由节点和边组成,节点表示 Tensor(输入、输出、W、B) 或者 OP(运算符),边(数据流动边、梯度流动边)表示 Tensor 和 OP 之间的依赖关系

  • Tensor 在图中通过运算符(OP, eg:数学运算 ADD、激活函数、神经网络层)进行传递和变换, 一个 op 可以获得 0 个(输入叶子节点)或多个张量(Tensor), 通过 OP 运算,产生 0 个(输出根节点)或多个Tensor,一般 op 可继承于torch.autograd.Function,同时支持正向传播和反向传播
  • 动态图的正向传播是立即执行得出结果的(方便 Debug),无需等待完整的计算图创建完毕
  • 动态图在反向传播后立即销毁,释放存储空间,下次调用需要重新构建计算图
    • 如果程序中使用了torch.autograd.backward方法执行了反向传播,那么创建的计算图会被立即销毁,下次调用需要重新创建
    • 如果程序中使用了torch.autograd.grad方法计算了梯度,那么创建的计算图会被立即销毁,下次调用需要重新创建
    • 若不想立即销毁,则需指明 retain_graph 参数为 True 来保留计算图

在这里插入图片描述


1.2.3、叶子节点和根节点
  • 叶子结点是最基础的结点(图中 w 和 x),其数据不是由运算生成的,因此是整个计算图的基石,是不可轻易”修改“的;张量有一个属性是 is_leaf, 用来指示一个张量是否为叶子结点
  • 最终计算得到的 y 就是根节点,就像一棵树一样,叶子在上面,根在下面
  • 依赖于叶子结点的结点,requires_grad 默认为 True:因为叶子结点梯度的计算是从后向前传播的,因此与其相关的结点均需要计算梯度
  • 叶子张量不可以执行 in-place 操作:因为计算图的 backward 过程都依赖于叶子结点的计算,所有的偏微分计算所需要用到的数据都是基于叶子结点的,因此叶子结点不允许 in-place 操作

在这里插入图片描述

  • 非叶子结点在梯度反向传播结束后释放;只有叶子节点的梯度得到保留,中间变量的梯度默认不保留
    • 在pytorch中,非叶子结点的梯度在反向传播结束之后就会被释放掉,如果需要保留的话可以对该结点设置 retain_grad()
    • 在调用 backward() 方法后,叶子节点的梯度(grad)会在反向传播的过程中累加。所以在梯度进行参数更新后(下一次反向传播前)需要把梯度清零 x.grad.zero_() or optimizer.zero_grad()

二、PyTorch 张量系统:torch


三、PyTorch 自动求导机制:torch.autograd

  • torch.autograd 能够根据输入和前向传播过程 自动构建计算图,并自动计算梯度用于反向传播:
    • 每个 Tensor 都有一个 requires_grad 标志,默认为 False,可用于冻结某些层的参数
    • 如果一个节点 requires_grad 被设置为 True,那么计算图中所有依赖它的节点都需要求解梯度
    • 优化器使用 autograd 来计算每个参数的梯度(存储在 tensor.grad 属性中)并进行更新
# requires_grad=False by default
>>> x = torch.randn(5, 5)  
>>> y = torch.randn(5, 5)
>>> z = torch.randn((5, 5), requires_grad=True)
>>> a = x + y
>>> a.requires_grad
False
>>> b = a + z

# 依赖于叶子结点的结点,requires_grad 默认为 True,叶子节点(z)不可执行 in-place 操作
>>> b.requires_grad  
True

在这里插入图片描述

3.1、torch.autograd.backward:自动求取梯度

torch.autograd.backward(tensors, grad_tensors=None, retain_graph=None, create_graph=False, grad_variables=None, inputs=None)

  • tensors(Sequence[Tensor] or Tensor): 用于求导的张量,如 loss
  • grad_tensors(Sequence[Tensor or None] or Tensor, optional):与根节点 loss 形状相同的张量,最终梯度为 loss 求出梯度与 grad_tensors 张量的点积;在 Tensor 的方法中是 gradient 参数
    • 若调用的 loss 是标量(或者 loss 张量通过loss.sum() 转成标量),则可以不提供此参数,默认为 1;有多个 loss 时,若提供该参数则可以看做是各个 loss 的权重
    • 若调用的 loss 是张量,则必须提供与 loss 相同形状的参数
  • retain_graph(bool, optional) :
    • 保持计算图,如果需要多次调用 backward 可设置为 True,但梯度会累加
    • 当有多个输出需要同时进行梯度反传时,需要将其设置为 True,从而保证在计算多个输出的梯度时互不影响
  • create_graph(bool, optional) : 创建导数计算图,用于高阶求导
  • inputs (Sequence[Tensor] or Tensor, optional):输入数据
  • Note:
    • 我们使用时候都是在张量上直接调用.backward()函数,但这里却是 torch.autograd.backward,为什么不一样呢? 其实Tensor.backward()接口内部调用了 torch.autograd.backward
    • 调用 backward() 方法后,叶子节点的梯度(grad)会在反向传播的过程中累加。所以在梯度进行参数更新后(下一次反向传播前)需要把梯度清零x.grad.zero_() or optimizer.zero_grad()
########################## 0、Tensor 中 backward 方法的定义 ##########################
def backward(self, gradient=None, retain_graph=None, create_graph=False, inputs=None):
    if has_torch_function_unary(self):
        return handle_torch_function(
            Tensor.backward,
            (self,),
            self,
            gradient=gradient,  #  gradient == grad_tensors
            retain_graph=retain_graph,
            create_graph=create_graph,
            inputs=inputs,
        )
    torch.autograd.backward(
        self, gradient, retain_graph, create_graph, inputs=inputs
    )



########################## 1、gradient 与 retain_graph 的用法 ##########################
import torch

x = torch.tensor([[0.0, 0.0], [1.0, 2.0]], requires_grad=True)  # x 需要被求导
a = torch.tensor(1.0)
b = torch.tensor(-2.0)
c = torch.tensor(1.0)
y = a * torch.pow(x, 2) + b * x + c  # f(x) = a*x**2 + b*x + c

gradient = torch.tensor([[1.0, 1.0], [1.0, 2.0]])
y.backward(gradient=gradient, retain_graph=True)  # 转换成标量来进行反向传播:torch.sum(y*gradient).backward()

print("y_grad:\n", y.grad)  # None, 为了节约存储空间,非叶子节点的梯度均为 None,只在计算过程中被用到,不会最终存储到 grad 属性中
print("x_grad:\n", x.grad)
y.backward(gradient=gradient)
print("x_grad:\n", x.grad)  # retain_graph=True 会出现梯度累积,可在 backward 前执行 x.grad.zero_() 进行梯度清零

# 输出如下
y_grad:
 None
x_grad:
 tensor([[-2., -2.],
        [ 0.,  4.]])
x_grad:  # 梯度未清零造成梯度累积
 tensor([[-4., -4.],
        [ 0.,  8.]])


########################## 2、非叶子节点梯度显示 ##########################
import torch

# 正向传播
x = torch.tensor(3.0, requires_grad=True)
y1 = x + 1
y2 = 2 * x
loss = (y1 - y2) ** 2

# 非叶子节点梯度显示控制
# 1、利用 retain_grad 可以保留非叶子节点的梯度值
# 2、利用 register_hook 可以查看非叶子节点的梯度值(需要定义在 backward 前面),但不会保留其值
y1.register_hook(lambda grad: print('y1.register_hook grad: ', grad))
y2.register_hook(lambda grad: print('y2.register_hook grad: ', grad)) 
y1.retain_grad()  
y2.retain_grad()
loss.retain_grad()

# 反向传播
loss.backward()  # 通过 register_hook 可以查看非叶子节点的梯度值
print("loss.grad:", loss.grad)
print("y1.grad:", y1.grad)
print("y2.grad:", y2.grad)
print("x.grad:", x.grad)

# 输出如下
y2.register_hook grad:  tensor(4.)
y1.register_hook grad:  tensor(-4.)
loss.grad: tensor(1.)  # 若 loss 为高维张量,则输出高维张量 
y1.grad: tensor(-4.)
y2.grad: tensor(4.)
x.grad: tensor(4.)


########################## 3、网络前向传播和反向传播求解梯度,更新参数示例 ##########################
import torch
import torchvision

# 生成数据
data = torch.rand(1, 3, 64, 64)
labels = torch.rand(1, 1000)

# 构建模型
model = torchvision.models.resnet18(weights="ResNet18_Weights.DEFAULT")

# 指定参数学习算法
optimizer = torch.optim.SGD(model.parameters(), lr=1e-2, momentum=0.9)

# 模型训练
for i in range(500):
    # 前向传播 [1, 1000]
    prediction = model(data)

    # 计算 loss:使用 .sum() 方法求和,loss 是一个标量
    loss = (prediction - labels).sum()  # 通常使用 loss = criterion(outputs, labels),返回标量

    # 反向传播 loss:实际调用 torch.autograd.backward 为每个模型参数计算梯度并将其存储在参数的.grad 属性中
    loss.backward()

    # 参数更新:调用 .step() 启动梯度下降,优化器通过.grad 中存储的梯度来调整每个参数
    optimizer.step()

    # 清空梯度:调用 backward 会导致导数值在叶节点处累积,所以将其用于参数更新后,需要将梯度显式清零
    optimizer.zero_grad()
    print("iter {}".format(i))

########################## 4、网络微调示例 ##########################
import torch
import torchvision

# 生成数据
data = torch.rand(1, 3, 64, 64)
labels = torch.rand(1, 10)

# 构建模型
model = torchvision.models.resnet18(weights="ResNet18_Weights.DEFAULT")

for param in model.parameters():
    param.requires_grad = False

# Replace the last fully-connected layer
# Parameters of newly constructed modules have requires_grad=True by default
model.fc = torch.nn.Linear(512, 10)  # 1000-->10 类

# 指定参数学习算法:Optimize only the classifier
optimizer = torch.optim.SGD(model.fc.parameters(), lr=1e-2, momentum=0.9)  # 只更新 fc 层进行 finetune

# 模型训练
for i in range(500):
    # 前向传播 [1, 10]
    prediction = model(data)

    # 计算 loss:使用 .sum() 方法求和,loss 是一个标量
    loss = (prediction - labels).sum()

    # 反向传播 loss:实际调用 torch.autograd.backward 为每个模型参数计算梯度并将其存储在参数的.grad 属性中
    loss.backward()

    # 参数更新:调用 .step() 启动梯度下降,优化器通过.grad 中存储的梯度来调整每个参数
    optimizer.step()

    print("iter {}".format(i))


3.2、torch.autograd.grad:求取梯度

torch.autograd.grad(outputs, inputs, grad_outputs = None, retain_graph = None, create_graph = False)

  • outputs: 用于求导的张量,如 loss,如果有多个因变量,相当于把多个因变量的梯度结果求和
  • inputs : 需要求解梯度的张量,允许同时对多个自变量求导数
  • create_graph : 创建导数计算图,用于高阶求导
  • retain_graph : 保持计算图
  • grad_outputs:多梯度权重
import torch

x = torch.tensor(0.0, requires_grad=True)  # x 需要被求导
a = torch.tensor(1.0)
b = torch.tensor(-2.0)
c = torch.tensor(1.0)
y = a * torch.pow(x, 2) + b * x + c  # f(x) = ax**2 + bx + c 

# create_graph 设置为 True 将允许创建更高阶的导数
dy_dx = torch.autograd.grad(y, x, create_graph=True)[0]  # f(x)‘ = 2ax+b
print(dy_dx.data)  # tensor(-2.)

# 求二阶导数
dy2_dx2 = torch.autograd.grad(dy_dx, x)[0]  # f(x)" = 2
print(dy2_dx2.data)  # tensor(2.)

3.3、使用梯度上下文管理器控制自动求导

  • autograd 自动构建计算图过程中会保存一系列中间变量,以便于backward 的计算,这就必然需要花费额外的内存和时间。
  • 而并不是所有情况下都需要backward,例如推理的时候,因此可以采用上下文管理器 torch.no_grad() 来管理上下文,让 pytorch 不记录相应的变量,以加快速度和节省空间
# torch.no_grad()/torch.set_grad_enabled()/torch.enable_grad() 的上下文管理器可用于控制是否需要自动求导
>>> x = torch.zeros(1, requires_grad=True)
>>> with torch.no_grad():
...     y = x * 2
>>> y.requires_grad
False

>>> is_train = False
>>> with torch.set_grad_enabled(is_train):
...     y = x * 2
>>> y.requires_grad
False

3.4、使用 torch.autograd.Function 实现自定义 OP

  • 参考:https://tingsongyu.github.io/PyTorch-Tutorial-2nd/chapter-2/2.6-autograd.html
  • 有的时候,想要实现自己的一些操作(op),如特殊的数学函数、pytorch 的 module 中没有的网络层,那就需要自己写一个 Function,在Function 中定义好 forward 的计算公式、backward 的计算公式,然后将这些 op 组合到模型中,模型就可以用 autograd 完成梯度求取。
  • eg:假设需要一个计算指数的功能,并且能组合到模型中,实现 autograd,那么可以这样实现:
    • 第一步:继承 Function
    • 第二步:实现 forward
    • 第三步:实现 backward
    • 注意事项:forward 和 backward 函数第一个参数为 ctx,它的作用类似于类函数的 self 一样,更详细解释可参考如下: In the forward pass we receive a Tensor containing the input and return a Tensor containing the output. ctx is a context object that can be used to stash information for backward computation. You can cache arbitrary objects for use in the backward pass using the ctx.save_for_backward method; backward 函数返回的参数个数与 forward 的输入参数个数相同, 即,传入该 op 的参数,都需要给它们计算对应的梯度。
import torch
from torch.autograd.function import Function

class Exp(Function):
    @staticmethod
    def forward(ctx, i):

        # ============== step1: 函数功能实现 ==============
        result = i.exp()
        # ============== step1: 函数功能实现 ==============

        # ============== step2: 结果保存,用于反向传播 ==============
        ctx.save_for_backward(result)
        # ============== step2: 结果保存,用于反向传播 ==============

        return result
    @staticmethod
    def backward(ctx, grad_output):

        # ============== step1: 取出结果,用于反向传播 ==============
        result, = ctx.saved_tensors
        # ============== step1: 取出结果,用于反向传播 ==============


        # ============== step2: 反向传播公式实现 ==============
        grad_results = grad_output * result
        # ============== step2: 反向传播公式实现 ==============


        return grad_results

x = torch.tensor([1.], requires_grad=True)  
y = Exp.apply(x)                          # 需要使用apply方法调用自定义autograd function
print(y)                                  #  y = e^x = e^1 = 2.7183
y.backward()                            
print(x.grad)                           # 反传梯度,  x.grad = dy/dx = e^x = e^1  = 2.7183

# 关于本例子更详细解释,推荐阅读 https://zhuanlan.zhihu.com/p/321449610

四、PyTorch 层级结构: torch.nn


五、PyTorch 并行:torch.multiprocessing


六、PyTorch 常用工具:torch.utils


七、参考资料

1、https://pytorch.org/
2、https://github.com/pytorch
3、https://github.com/pytorch/pytorch
4、https://pytorch.org/docs/stable/index.html
5、PyTorch 中文文档
6、https://pytorch.apachecn.org/
7、https://github.com/awfssv/pytorch-cn
8、pytorch 多 gpu并行训练
9、Pytorch多机多卡分布式训练
10、https://download.pytorch.org/whl/torch_stable.html
11、https://tingsongyu.github.io/PyTorch-Tutorial-2nd/

<think>好的,用户想了解深度学习以及PyTorch的基本概念和用法,特别是入门教程和基础介绍。我需要根据提供的引用内容来组织回答,确保结构清晰,帮助用户逐步理解。首先,我应该从深度学习的基本概念讲起,然后过渡到PyTorch的介绍,再结合引用中的信息,比如安装方法、数据导入、使用GPU加速等。同时,用户提到的引用中有关于项目实践和TensorBoard的内容,这些可以作为扩展部分加入。需要检查是否符合系统级指令,比如数学表达式的格式是否正确,独立公式是否用$$...$$,以及是否生成了相关问题。另外,要确保引用标识正确添加到对应的内容末尾。可能还需要解释PyTorch的核心组件,比如张量、自动求导等,并给出代码示例,比如数据导入和模型定义的代码片段。最后,生成的相关问题需要与用户的问题相关,比如安装问题、应用场景、学习资源等。需要确保回答真实可靠,引用来源准确,并且语言简洁明了,适合零基础用户理解。</think># 深度学习PyTorch基础教程 ## 一、深度学习基础概念 深度学习是机器学习的一个分支,通过多层神经网络学习数据的抽象特征表示。核心思想是通过非线性变换逐层提取特征,例如对于图像识别任务,底层网络可能学习边缘特征,高层网络则组合成更复杂的形状。 典型应用场景包括: - 图像分类(如ResNet、Vision Transformer) - 自然语言处理(如BERT、GPT) - 语音识别(如WaveNet) 数学基础可表示为多层复合函数: $$ y = f_n(f_{n-1}(\cdots f_1(x;\theta_1)\cdots;\theta_{n-1});\theta_n) $$ 其中$f_i$表示第i层网络,$\theta_i$为对应参数[^5]。 ## 二、PyTorch核心组件 ### 2.1 张量(Tensor) PyTorch的基础数据结构,支持GPU加速计算: ```python import torch x = torch.rand(3, 4) # 创建3x4随机张量 y = x.to('cuda') # 转移至GPU[^5] ``` ### 2.2 自动求导(Autograd) 通过计算图自动追踪梯度: ```python x = torch.tensor(2.0, requires_grad=True) y = x**2 + 3*x y.backward() # 自动计算dy/dx print(x.grad) # 输出7.0 ``` ### 2.3 数据加载 使用`torchvision`处理数据集: ```python transform = transforms.Compose([ transforms.ToTensor(), transforms.Normalize((0.5,), (0.5,)) ]) trainset = torchvision.datasets.CIFAR10(root='./data', train=True, download=True, transform=transform)[^4] ``` ## 三、PyTorch基础工作流 1. **模型定义**:通过继承`nn.Module`类 ```python class Net(nn.Module): def __init__(self): super().__init__() self.fc = nn.Linear(784, 10) def forward(self, x): return self.fc(x) ``` 2. **训练循环**模板: ```python model = Net() criterion = nn.CrossEntropyLoss() optimizer = torch.optim.SGD(model.parameters(), lr=0.01) for epoch in range(10): for data, labels in dataloader: outputs = model(data) loss = criterion(outputs, labels) loss.backward() optimizer.step() optimizer.zero_grad() ``` 3. **可视化工具**: ```python writer = SummaryWriter() # 需要导入SummaryWriter[^2] writer.add_scalar('Loss/train', loss.item(), epoch) ``` ## 四、安装与配置 推荐使用Anaconda环境: ```bash conda install pytorch torchvision cpuonly -c pytorch # CPU版本[^3] ``` 或通过官网获取GPU版本安装命令。验证安装: ```python print(torch.cuda.is_available()) # 输出True表示GPU可用 ``` ## 五、学习路径建议 1. 掌握Python基础语法 2. 学习NumPy数组操作 3. 理解机器学习基础(如线性回归、梯度下降) 4. 完成PyTorch官方教程 5. 实战项目(参考阿里天池NLP赛事实践[^1])
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值