python中backward_【PyTorch】聊聊 backward 背后的代码

本文详细探讨了PyTorch中`backward`函数的工作原理,从Tensor的`backward`方法到`torch.autograd.backward`,再到C++实现的`_ImperativeEngine.run_backward`。文章解释了反向传播过程中涉及的参数、内部机制,包括梯度计算、链式法则的运用,以及如何处理高阶微分和图的保留。此外,还介绍了`try_get_grad_accumulator`函数和`Engine::execute`在计算图执行中的作用,以及`pre_hooks`和`post_hooks`功能。
摘要由CSDN通过智能技术生成

说起backward大家肯定不陌生,用过PyTorch的肯定都知道,这个函数的作用是反向传播计算梯度的。比如下边这个例子,要反向传播计算梯度之后,才能调用优化器的step函数更新网络模型参数。

Example:

>>> optimizer = torch.optim.SGD(model.parameters(), lr=0.1, momentum=0.9)

>>> optimizer.zero_grad()

>>> loss_fn(model(input), target).backward()

>>> optimizer.step()

[1] torch.Tensor.backward

在 torch/tensor.py 文件中可以看到,class Tensor(torch._C._TensorBase)中有函数def backward。所以我们可以用tensor.backward()来进行反向传播。

def backward(self, gradient=None, retain_graph=None, create_graph=False):

r"""Computes the gradient of current tensor w.r.t. graph leaves.The graph is differentiated using the chain rule. If the tensor isnon-scalar (i.e. its data has more than one element) and requiresgradient, the function additionally requires specifying ``gradient``.It should be a tensor of matching type and location, that containsthe gradient of the differentiated function w.r.t. ``self``.This function accumulates gradients in the leaves - you might need tozero them before calling it.Arguments:gradient (Tensor or None): Gradient w.r.t. thetensor. If it is a tensor, it will be automatically convertedto a Tensor that does not require grad unless ``create_graph`` is True.None values can be specified for scalar Tensors or ones thatdon't require grad. If a None value would be acceptable thenthis argument is optional.retain_graph (bool, optional): If ``False``, the graph used to computethe grads will be freed. Note that in nearly all cases settingthis option to True is not needed and often can be worked aroundin a much more efficient way. Defaults to the value of``create_graph``.create_graph (bool, optional): If ``True``, graph of the derivative willbe constructed, allowing to compute higher order derivativeproducts. Defaults to ``False``."""

torch.autograd.backward(self, gradient, retain_graph, create_graph)

其中,create_graph参数的作用是,如果为True,那么就创建一个专门的graph of the derivative,这可以方便计算高阶微分。参数retain_graph可以忽略,因为绝大多数情况根本不需要,它的作用是要不要保留Graph。该函数实现代码也很简单,就是调用torch.autograd.backward。所以接下来看一下torch.autograd.backward中的实现。

[2] torch.autograd.backward

函数torch.autograd.backward的定义在文件 torch/autograd/__init__.py 中。借助于链式法则the chain rule和Jacobian-vector product可以很方便的计算梯度。下边就是具体的代码。

# ...

from .variable import Variable

# ...

def _make_grads(outputs, grads):

new_grads = []

for out, grad in zip(outputs, grads):

if isinstance(grad, torch.Tensor):

if not out.shape == grad.shape:

# raise RuntimeError ...

new_grads.append(grad)

elif grad is None:

if out.requires_grad:

if out.numel() != 1:

# raise RuntimeError ...

else:

new_grads.append(None)

else:

# raise TypeError ...

return tuple(new_grads)

def backward(tensors, grad_tensors=None, retain_graph=None, create_graph=False, grad_variables=None):

r"""Computes the sum of gradients of given tensors w.r.t. graph leaves.The graph is differentiated using the chain rule. If any of ``tensors``are non-scalar (i.e. their data has more than one element) and requiregradient, then the Jacobian-vector product would be computed, in thiscase the function additionally requires specifying ``grad_tensors``.It should be a sequence of matching length, that contains the "vector"in the Jacobian-vector product, usually the gradient of the differentiatedfunction w.r.t. corresponding tensors (``None`` is an acceptable value forall tensors that don't need gradient tensors).This function accumulates gradients in the leaves - you might need to zerothem before calling it."""

if grad_variables is not None:

warnings.warn("'grad_variables' is deprecated. Use 'grad_tensors' instead.")

if grad_tensors is None:

grad_tensors = grad_variables

else:

raise RuntimeError("'grad_tensors' and 'grad_variables' (deprecated) "

"arguments both passed to backward(). Please only "

"use 'grad_tensors'.")

tensors = (tensors,) if isinstance(tensors, torch.Tensor) else tuple(tensors)

if grad_tensors is None:

grad_tensors = [None] * len(tensors)

elif isinstance(grad_tensors, torch.Tensor):

grad_tensors = [grad_tensors]

else:

grad_tensors = list(grad_tensors)

grad_tensors = _make_grads(tensors, grad_tensors)

if retain_graph is None:

retain_graph = create_graph

Variable._execution_engine.run_backward(

tensors, grad_tensors, retain_graph, create_graph,

allow_unreachable=True) # allow_unreachable flag

# ...

if not torch._C._autograd_init():

raise RuntimeError("autograd initialization failed")

参数grad_variables是老版本的,已经被deprecated,现在使用的是grad_tensors。即便你使用了也没关系,代码会把参数grad_variables的

### 回答1: segmentation_models_pytorch 是一个基于 PyTorch 的图像分割库,可以用来训练语义分割模型。下面是使用 segmentation_models_pytorch 实现单模型训练的基本步骤: 1. 安装 segmentation_models_pytorch 和其依赖项: ``` pip install segmentation-models-pytorch ``` 2. 加载数据集并进行预处理。可以使用 torchvision 或者其他图像处理库加载数据集,并对数据进行预处理,如裁剪、缩放、归一化等操作。 3. 定义模型。使用 segmentation_models_pytorch 提供的模型类(如 UNet、FPN、PSPNet 等)来定义模型。 ```python import segmentation_models_pytorch as smp model = smp.Unet( encoder_name="resnet34", # 使用 ResNet34 作为编码器 encoder_weights="imagenet", # 加载预训练权重 in_channels=3, # 输入通道数 classes=2, # 分类数 ) ``` 4. 定义损失函数和优化器。可以选择使用交叉熵损失函数和 Adam 优化器。 ```python import torch.nn as nn import torch.optim as optim criterion = nn.CrossEntropyLoss() optimizer = optim.Adam(model.parameters(), lr=0.001) ``` 5. 训练模型。使用 DataLoader 加载数据集,并对模型进行训练。 ```python from torch.utils.data import DataLoader train_loader = DataLoader(dataset, batch_size=4, shuffle=True) for epoch in range(num_epochs): running_loss = 0.0 for i, data in enumerate(train_loader, 0): inputs, labels = data optimizer.zero_grad() outputs = model(inputs) loss = criterion(outputs, labels) loss.backward() optimizer.step() running_loss += loss.item() print(f"Epoch {epoch+1}, Loss: {running_loss/len(train_loader)}") ``` 6. 保存模型。训练完毕后,可以使用 torch.save() 方法将模型保存到本地。 ```python torch.save(model.state_dict(), "model.pth") ``` ### 回答2: segmentation_models_pytorch是一个基于PyTorch实现的语义分割模型库。使用segmentation_models_pytorch实现单模型训练可以通过以下步骤完成。 首先,安装segmentation_models_pytorch库。可以通过pip install segmentation_models_pytorch命令来安装。 导入所需的库和模型。常用的库包括torch,torchvision和segmentation_models_pytorch。可以使用以下命令导入库: ```python import torch import torchvision.transforms as transforms import segmentation_models_pytorch as smp ``` 加载和预处理训练数据。可以使用torchvision的transforms来定义一系列的数据预处理操作,例如裁剪、缩放和标准化等。之后,使用torch.utils.data.DataLoader来加载和批量处理数据。 定义模型架构。可以选择使用segmentation_models_pytorch预定义的模型架构,例如UNet、PSPNet和DeepLab等。根据任务需求选择合适的模型,并初始化相关参数。 定义优化器和损失函数。常见的优化器有Adam和SGD等,损失函数常选择交叉熵损失函数。可以使用torch.optim的函数来定义优化器,使用torch.nn的损失函数来定义损失函数。 进行模型训练。使用torch.utils.data.DataLoader加载训练数据集,并迭代训练数据集的每个批次。将批次数据输入模型进行前向传播,获取模型的输出。计算损失,并进行反向传播更新模型的参数。重复以上步骤直到达到预定的训练轮数或达到设定的训练目标。 保存和加载训练好的模型。可以使用torch.save函数将训练好的模型保存到指定的文件路径,使用torch.load函数加载保存的模型文件。 以上是使用segmentation_models_pytorch实现单模型训练的基本步骤。根据具体任务和数据的不同,可能还需要进行一些细节操作,例如数据增强、学习率调整和模型评估等。 ### 回答3: segmentation_models_pytorch是一个基于PyTorch的分割模型训练库,可以应用于图像分割任务。下面我将介绍如何使用segmentation_models_pytorch实现单模型训练。 首先,我们需要安装segmentation_models_pytorch库。可以使用pip命令进行安装: ``` pip install segmentation-models-pytorch ``` 在训练之前,我们需要准备好训练数据和标签。通常情况下,训练数据是一些图像,标签则是对应每个像素点的分类或分割结果。 接下来,我们需要导入所需的库: ``` import segmentation_models_pytorch as smp import torch import torch.nn as nn import torch.optim as optim from torch.utils.data import DataLoader, Dataset ``` 然后,我们需要创建一个自定义的数据集类,该类继承自torch.utils.data.Dataset类,并实现__len__和__getitem__方法,用于加载和处理数据。 接着,我们可以选择一个合适的分割模型,比如Unet、FPN等。这些模型可以通过调用smp库的函数进行初始化,比如: ``` model = smp.Unet( encoder_name="resnet34", encoder_weights="imagenet", classes=1, activation='sigmoid' ) ``` 在这里,我们选择了一个使用ResNet-34作为编码器、预训练权重为ImageNet数据集、分类数为1(二分类问题)的Unet模型。 然后,我们可以定义损失函数和优化器: ``` criterion = nn.BCELoss() optimizer = optim.Adam(model.parameters(), lr=0.001) ``` 接着,我们可以进行训练循环,依次迭代数据进行训练和优化: ``` for epoch in range(num_epochs): for batch in dataloader: inputs, labels = batch optimizer.zero_grad() outputs = model(inputs) loss = criterion(outputs, labels) loss.backward() optimizer.step() ``` 最后,我们可以保存模型并在需要预测时加载模型进行测试: ``` torch.save(model.state_dict(), "segmentation_model.pt") model.load_state_dict(torch.load("segmentation_model.pt")) ``` 以上就是使用segmentation_models_pytorch实现单模型训练的过程。根据具体任务需求,你也可以调整模型、损失函数、优化器等参数来进行更灵活的训练。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值