第 7 章 PyTorch PyTorch
本作品已使用人工智能进行翻译。欢迎您提供反馈和意见:translation-feedback@oreilly.com
在第6章和第5 章中,你通过从头开始实现卷积神经网络和递归神经网络,了解了它们的工作原理。不过,虽然了解它们的工作原理很有必要,但仅靠这些知识并不能让它们在实际问题中发挥作用;为此,你需要能够在高性能库中实现它们。我们可以用一整本书来介绍如何构建一个高性能的神经网络库,但那将是一本大相径庭的书(或者说是一本篇幅更长的书),面向的读者也大相径庭。相反,我们将在最后一章介绍 PyTorch,这是一个基于自动微分的神经网络框架,越来越受欢迎,我们在第 6 章开头介绍了它。
与本书的其他部分一样,我们将以映射神经网络工作原理模型的方式编写代码,为Layers、Trainers 等编写类。在这样做的时候,我们不会按照 PyTorch 的常见做法来编写代码,但我们会在本书的 GitHub repo上提供链接,让你了解更多关于按照 PyTorch 设计的方式来表达神经网络的知识。在此之前,我们先来学习 PyTorch 核心的数据类型,它能够实现自动区分,从而能够干净利落地表达神经网络训练:Tensor 。
PyTorch 张量器
在 上一章中,我们展示了一个简单的NumberWithGrad ,通过跟踪对其执行的操作来累积梯度。这意味着,如果我们写
a=NumberWithGrad(3)b=a*4c=b+3d=(a+2)e=c*de.backward()
那么a.grad 就等于35 ,它实际上是e 相对于a 的偏导数。
PyTorch 的Tensor 类就像一个 "ndarrayWithGrad":它与NumberWithGrad 类似,只是使用了数组 (如numpy),而不仅仅是floats 和ints。让我们使用 PyTorchTensor 重写前面的例子。首先,我们将手动初始化一个Tensor :
a=torch.Tensor([[3.,3.,],[3.,3.]],requires_grad=True)
请注意这里的几件事:
-
我们可以通过简单地用
torch.Tensor封装Tensor中包含的数据来初始化 ,就像我们使用ndarrays 一样。 -
在以这种方式初始化
Tensor时,我们必须传入参数requires_grad=True,告诉Tensor累加梯度。
完成后,我们就可以像以前一样进行计算了:
b=a*4c=b+3d=(a+2)e=c*de_sum=e.sum()e_sum.backward()
你可以看到,与NumberWithGrad 的例子相比,这里多了一个步骤:在调用backward 的和之前,我们必须先求和 e 。这是因为,正如我们在第一章中所论证的,"一个数相对于一个数组的导数 "是没有意义的:但是,我们可以推理出e_sum 相对于a 的每个元素的偏导数是多少--事实上,我们看到答案与我们在前面几章中发现的是一致的:
(a.grad)
tensor([[35., 35.],
[35., 35.]], dtype=torch.float64)
PyTorch 的这一特性使我们能够简单地定义模型,只需定义前向传递,计算损失,然后在损失上调用.backward ,就能自动计算每个parameters 相对于该损失的导数。特别是,我们不必担心在前向传递中多次重复使用相同的量(这是我们在前几章中使用的 ...