PyTorch学习系列教程:Tensor如何实现自动求导

简介: 今天本文继续PyTorch学习系列。虽然前几篇推文阅读效果不是很好(大体可能与本系列推文是新开的一个方向有关),但自己选择的路也要坚持走下去啊!前篇推文介绍了搭建一个深度学习模型的基本流程,通过若干个Epoch即完成了一个简单的手写数字分类模型,效果还不错。在这一过程中,一个重要的细节便是模型如何学习到最优参数,答案是通过梯度下降法。实际上,梯度下降法是一类优化方法,是深度学习中广泛应用甚至可称得上是深度学习的基石。本篇不打算讲解梯度下降法,而主要来谈一谈Tensor如何实现自动求导,明白这一过程方能进一步理解各种梯度下降法的原理。

讲解Tensor如何实现自动求导,本文分别从理论分析和代码实践的角度加以陈述:

  • Tensor中的自动求导:与梯度相关的属性,前向传播和反向传播
  • 自动求导探索实践:以线性回归为例,探索自动求导过程


01 Tensor中的自动求导分析


Tensor是PyTorch中的基础数据结构,构成了深度学习的基石,其本质上是一个高维数组。在前序推文中,实际上提到过在创建一个Tensor时可以指定其是否需要梯度。那么是否指定需要梯度(requires_grad)有什么区别呢?实际上,这个参数设置True/False将直接决定该Tensor是否支持自动求导并参与后续的梯度更新。具体来说,Tensor数据结构中,与梯度直接相关的几个重要属性间的关系如下:


640.png


原创拙图,权当意会


透过上面这个类图,大概想表达以下含义:

  • 在一个Tensor数据结构中,最核心的属性是data,这里面存储了Tensor所代表的高维数组(当然,这里虽然称之为高维,但实际上可以是从0维开始的任意维度);
  • 通过requires_grad参数控制两个属性,grad和grad_fn,其中前者代表当前Tensor的梯度,后者代表经过当前Tensor所需求导的梯度函数;当requires_grad=False时,grad和grad_fn都为None,且不会存在任何取值,而只有当requires_grad=True时,此时grad和grad_fn初始取值仍为None,但在后续反向传播中可以予以赋值更新
  • backward(),是一个函数,仅适用于标量Tensor,即维度为0的Tensor
  • is_leaf:标记了当前Tensor在所构建的计算图中的位置,其中计算图既可看做是一个有向无环图(DAG),也可视作是一个树结构。当Tensor是初始节点时,即为叶子节点,is_leaf=True,否则为False。


目前,Tensor支持自动求导功能对数据类型的要求是仅限于浮点型:" As of now, we only support autograd for floating point Tensor types ( half, float, double and bfloat16) and complex Tensor types (cfloat, cdouble). "——引自PyTorch官方文档


了解了Tensor所具有上述属性和方法,那么它是如何实现自动求导的呢?这就又要涉及到前向传播和反向传播这两个重要概念。简单来说,如果将神经网络的每层比作一系列函数映射(f1, f2, ..., fn)的话,那么:


  • 前向传播,就是依据计算流程实现数据(data)的计算和计算图的构建:

微信截图_20220528085721.png


  • 反向传播,反向传播就是依据所构建计算图的反方向递归求导和赋值梯度:


微信截图_20220528085730.png


而如果用图形化描述这一过程,则是:


640.png


其中,在前向传播过程中,是按照流程完成从初始输入(一般是训练数据+网络权重)直至最终输出(一般是损失函数)的计算过程,同步完成计算图的构建;而在反向传播过程中,则是通过调用loss.backward()函数,依据计算图的相反方向递归完成各级求导(本质上就是求导的链式法则)。同时,对于requires_grad=False的tensor,在反向传播过程中实际不予以求导和更新,相应的反向链条被切断。


另外值得补充说明的是,在PyTorch早期版本中设计用于支持自动求导的数据类型为Variable,英文含义即为参数,特指网络中待优化的参数。其中,Variable与Tensor的关系是:Variable是对Tensor的二次封装,专门用于支持梯度求解。而在后来,Variable逐渐弃用(deprecated),并将其特有的自动求导功能与Tensor合并,并通过Tensor的requires_grad属性来区分一个Tensor是否支持求导。显然,这样的设计是更为合理的,对使用也更加方便统一。


640.png

已进入历史舞台的Variable类型


02 Tensor中的自动求导实践


这里,我们以一个简单的单变量线性回归为例演示Tensor的自动求导过程。


1.创建训练数据x, y和初始权重w, b


# 训练数据,目标拟合线性回归 y = 2*x + 3
x = torch.tensor([1., 2.])
y = torch.tensor([5., 7.])
# 初始权重,w=1.0, b=0.0
w = torch.tensor(1.0, requires_grad=True)
b = torch.tensor(0.0, requires_grad=True)


此时查看w, b和x, y的梯度相关的各项属性,结果如下


# 1. 注意:x和y设置为requires_grad=False
x.grad, x.grad_fn, x.is_leaf, y.grad, y.grad_fn, y.is_leaf
# 输出:(None, None, True, None, None, True)
# 2. w和b初始梯度均为None,且二者均为叶子节点
w.grad, w.grad_fn, w.is_leaf, b.grad, b.grad_fn, b.is_leaf
# 输出:(None, None, True, None, None, True)


2.构建计算流程,实现前向传播


# 按计算流程逐步操作,实现前向传播
wx = w*x
wx_b = wx + b
loss = (wx_b - y)
loss2 = loss**2
loss2_sum = sum(loss2)


查看各中间变量的梯度相关属性:


# 1.查看是否叶子节点
wx.is_leaf, wx_b.is_leaf, loss.is_leaf, loss2.is_leaf, loss2_sum.is_leaf
# 输出:(False, False, False, False, False)
# 2.查看grad
wx.grad, wx_b.grad, loss.grad, loss2.grad, loss2_sum.grad
# 触发Warning
# UserWarning: The .grad attribute of a Tensor that is not a leaf Tensor is being accessed. Its .grad attribute won't be populated during autograd.backward(). If you indeed want the .grad field to be populated for a non-leaf Tensor, use .retain_grad() on the non-leaf Tensor. If you access the non-leaf Tensor by mistake, make sure you access the leaf Tensor instead. See github.com/pytorch/pytorch/pull/30531 for more informations. (Triggered internally at  aten\src\ATen/core/TensorBody.h:417.)
  return self._grad
# 输出:(None, None, None, None, None)
3.查看grad_fn
wx.grad_fn, wx_b.grad_fn, loss.grad_fn, loss2.grad_fn, loss2_sum.grad_fn
# 输出:
(<MulBackward0 at 0x23a875ee550>,
 <AddBackward0 at 0x23a875ee8e0>,
 <SubBackward0 at 0x23a875ee4c0>,
 <PowBackward0 at 0x23a875ee490>,
 <AddBackward0 at 0x23a93dde040>)


3.对最终的loss调用backward,实现反向传播


loss2_sum.backward()


依次查看各中间变量和初始输入的梯度


# 1. 中间变量(非叶子节点)的梯度仅用于反向传播,但不对外暴露
wx.grad, wx_b.grad, loss.grad, loss2.grad, loss2_sum.grad
# 输出:(None, None, None, None, None)
# 2. 检查叶子节点是否获得梯度:w, b均获得梯度,x, y不支持求导,仍为None
w.grad, b.grad, x.grad, y.grad
# 输出:(tensor(-28.), tensor(-18.), None, None)


至此,即通过前向传播的计算图和反向传播的梯度传递,完成了初始权重参数的梯度赋值过程。注意,这里w和b是网络待优化参数,而一旦二者有了梯度,则可进一步应用梯度下降法予以更新。


那么进一步地,这里w.grad和b.grad的数值是如何得到的呢?我们实际手动求解一遍。首先分别推导loss对w和b的偏导公式:


微信截图_20220528090041.png


而后,带入两组训练数据(x, y)=(1, 5)和(x, y)=(2, 7),并将两组训练数据对应的梯度求和:


# w的梯度:2*(1*1 + 0 - 5)*1 + 2*(1*2 + 0 - 7)*2 = -28
# b的梯度:2*(1*1 + 0 - 5) + 2*(1*2 + 0 - 7) = -18


显然,手动计算结果与上述演示结果是一致的。


注意:在多个训练数据(batch_size)参与一次反向传播时,返回的参数梯度是在各训练数据上的求得的梯度之和。


640.png

                                         摘自PyTorch官网


640.png



目录
相关文章
|
1月前
|
存储 物联网 PyTorch
基于PyTorch的大语言模型微调指南:Torchtune完整教程与代码示例
**Torchtune**是由PyTorch团队开发的一个专门用于LLM微调的库。它旨在简化LLM的微调流程,提供了一系列高级API和预置的最佳实践
158 59
基于PyTorch的大语言模型微调指南:Torchtune完整教程与代码示例
|
2月前
|
PyTorch Linux 算法框架/工具
pytorch学习一:Anaconda下载、安装、配置环境变量。anaconda创建多版本python环境。安装 pytorch。
这篇文章是关于如何使用Anaconda进行Python环境管理,包括下载、安装、配置环境变量、创建多版本Python环境、安装PyTorch以及使用Jupyter Notebook的详细指南。
314 1
pytorch学习一:Anaconda下载、安装、配置环境变量。anaconda创建多版本python环境。安装 pytorch。
|
1月前
|
并行计算 监控 搜索推荐
使用 PyTorch-BigGraph 构建和部署大规模图嵌入的完整教程
当处理大规模图数据时,复杂性难以避免。PyTorch-BigGraph (PBG) 是一款专为此设计的工具,能够高效处理数十亿节点和边的图数据。PBG通过多GPU或节点无缝扩展,利用高效的分区技术,生成准确的嵌入表示,适用于社交网络、推荐系统和知识图谱等领域。本文详细介绍PBG的设置、训练和优化方法,涵盖环境配置、数据准备、模型训练、性能优化和实际应用案例,帮助读者高效处理大规模图数据。
48 5
|
6月前
|
机器学习/深度学习 自然语言处理 算法
【从零开始学习深度学习】49.Pytorch_NLP项目实战:文本情感分类---使用循环神经网络RNN
【从零开始学习深度学习】49.Pytorch_NLP项目实战:文本情感分类---使用循环神经网络RNN
|
2月前
|
机器学习/深度学习 缓存 PyTorch
pytorch学习一(扩展篇):miniconda下载、安装、配置环境变量。miniconda创建多版本python环境。整理常用命令(亲测ok)
这篇文章是关于如何下载、安装和配置Miniconda,以及如何使用Miniconda创建和管理Python环境的详细指南。
477 0
pytorch学习一(扩展篇):miniconda下载、安装、配置环境变量。miniconda创建多版本python环境。整理常用命令(亲测ok)
|
4月前
|
并行计算 Ubuntu PyTorch
Ubuntu下CUDA、Conda、Pytorch联合教程
本文是一份Ubuntu系统下安装和配置CUDA、Conda和Pytorch的教程,涵盖了查看显卡驱动、下载安装CUDA、添加环境变量、卸载CUDA、Anaconda的下载安装、环境管理以及Pytorch的安装和验证等步骤。
754 1
Ubuntu下CUDA、Conda、Pytorch联合教程
|
4月前
|
PyTorch 算法框架/工具
【Pytorch】解决Fan in and fan out can not be computed for tensor with fewer than 2 dimensions
本文提供了两种解决PyTorch中由于torchtext版本问题导致的“Fan in and fan out can not be computed for tensor with fewer than 2 dimensions”错误的方法。
101 2
|
4月前
|
存储 PyTorch API
Pytorch入门—Tensors张量的学习
Pytorch入门—Tensors张量的学习
30 0
|
6月前
|
机器学习/深度学习 资源调度 PyTorch
【从零开始学习深度学习】15. Pytorch实战Kaggle比赛:房价预测案例【含数据集与源码】
【从零开始学习深度学习】15. Pytorch实战Kaggle比赛:房价预测案例【含数据集与源码】
|
6月前
|
机器学习/深度学习 算法 PyTorch
【从零开始学习深度学习】50.Pytorch_NLP项目实战:卷积神经网络textCNN在文本情感分类的运用
【从零开始学习深度学习】50.Pytorch_NLP项目实战:卷积神经网络textCNN在文本情感分类的运用