在我们对线性回归的介绍中,我们介绍了各种组件,包括数据、模型、损失函数和优化算法。事实上,线性回归是最简单的机器学习模型之一。然而,训练它使用许多与本书中其他模型所需的组件相同的组件。因此,在深入了解实现细节之前,有必要设计一些贯穿本书的 API。将深度学习中的组件视为对象,我们可以从为这些对象及其交互定义类开始。这种面向对象的实现设计将极大地简化演示,您甚至可能想在您的项目中使用它。
受PyTorch Lightning等开源库的启发,在高层次上我们希望拥有三个类:(i)Module
包含模型、损失和优化方法;(ii)DataModule
提供用于训练和验证的数据加载器;(iii) 两个类结合使用该类 Trainer
,这使我们能够在各种硬件平台上训练模型。本书中的大部分代码都改编自Module
and DataModule
。Trainer
只有在讨论 GPU、CPU、并行训练和优化算法时,我们才会涉及该类。
No GPU/TPU found, falling back to CPU. (Set TF_CPP_MIN_LOG_LEVEL=0 and rerun for more info.)
3.2.1. 公用事业
我们需要一些实用程序来简化 Jupyter 笔记本中的面向对象编程。挑战之一是类定义往往是相当长的代码块。笔记本电脑的可读性需要简短的代码片段,穿插着解释,这种要求与 Python 库常见的编程风格不相容。第一个实用函数允许我们在创建类后将函数注册为类中的方法。事实上,即使我们已经创建了类的实例,我们也可以这样做!它允许我们将一个类的实现拆分成多个代码块。
让我们快速浏览一下如何使用它。我们计划 A
用一个方法来实现一个类do
。我们可以先声明类并创建一个实例,而不是在同一个代码块中A
同时 拥有两者的代码。do
A
a
do
接下来我们像往常一样 定义方法,但不在 classA
的范围内。相反,我们add_to_class
用类A
作为参数来装饰这个方法。这样做时,该方法能够访问 的成员变量,A
正如我们所期望的那样,如果它已被定义为 的A
定义的一部分。让我们看看当我们为实例调用它时会发生什么a
。
Class attribute "b" is 1
Class attribute "b" is 1
Class attribute "b" is 1
第二个是实用程序类,它将类 __init__
方法中的所有参数保存为类属性。这使我们无需额外代码即可隐式扩展构造函数调用签名。
我们将其实施推迟到第 23.7 节。HyperParameters
要使用它,我们定义继承自该方法并调用 save_hyperparameters
该方法的类__init__
。
self.a = 1 self.b = 2
There is no self.c = True
self.a = 1 self.b = 2
There is no self.c = True
self.a = 1 self.b = 2
There is no self.c = True
self.a = 1 self.b = 2
There is no self.c = True
最后一个实用程序允许我们在实验进行时以交互方式绘制实验进度。为了尊重更强大(和复杂)的TensorBoard,我们将其命名为ProgressBoard
。实现推迟到 第 23.7 节。现在,让我们简单地看看它的实际效果。
该方法在图中 draw
绘制一个点,并在图例中指定。可选的仅通过显示来平滑线条(x, y)
label
every_n
1/n图中的点。他们的价值是从平均n原始图中的邻居点。
class ProgressBoard(d2l.HyperParameters): #@save
"""The board that plots data points in animation."""
def __init__(self, xlabel=None, ylabel=None, xlim=None,
ylim=None, xscale='linear', yscale='linear',
ls=['-', '--', '-.', ':'], colors=['C0', 'C1', 'C2', 'C3'],
fig=None, axes=None, figsize=(3.5, 2.5), display=True):
self.save_hyperparameters()
def draw(self, x, y, label, every_n=1):
raise NotImpleme