在我们对线性回归的介绍中,我们介绍了各种组件,包括数据、模型、损失函数和优化算法。事实上,线性回归是最简单的机器学习模型之一。然而,训练它使用许多与本书中其他模型所需的组件相同的组件。因此,在深入了解实现细节之前,有必要设计一些贯穿本书的 API。将深度学习中的组件视为对象,我们可以从为这些对象及其交互定义类开始。这种面向对象的实现设计将极大地简化演示,您甚至可能想在您的项目中使用它。
受PyTorch Lightning等开源库的启发,在高层次上我们希望拥有三个类:(i)Module
包含模型、损失和优化方法;(ii)DataModule
提供用于训练和验证的数据加载器;(iii) 两个类结合使用该类 Trainer
,这使我们能够在各种硬件平台上训练模型。本书中的大部分代码都改编自Module
and DataModule
。Trainer
只有在讨论 GPU、CPU、并行训练和优化算法时,我们才会涉及该类。
import time
import numpy as np
import torch
from torch import nn
from d2l import torch as d2l
import time
from dataclasses import field
from typing import Any
import jax
import numpy as np
from flax import linen as nn
from flax.training import train_state
from jax import numpy as jnp
from d2l import jax as d2l
No GPU/TPU found, falling back to CPU. (Set TF_CPP_MIN_LOG_LEVEL=0 and rerun for more info.)
import time
import numpy as np
import tensorflow as tf
from d2l import torch as d2l
3.2.1. 公用事业
我们需要一些实用程序来简化 Jupyter 笔记本中的面向对象编程。挑战之一是类定义往往是相当长的代码块。笔记本电脑的可读性需要简短的代码片段,穿插着解释,这种要求与 Python 库常见的编程风格不相容。第一个实用函数允许我们在创建类后将函数注册为类中的方法。事实上,即使我们已经创建了类的实例,我们也可以这样做!它允许我们将一个类的实现拆分成多个代码块。
def add_to_class(Class): #@save
"""Register functions as methods in created class."""
def wrapper(obj):
setattr(Class, obj.__name__, obj)
return wrapper
让我们快速浏览一下如何使用它。我们计划 A
用一个方法来实现一个类do
。我们可以先声明类并创建一个实例,而不是在同一个代码块中A
同时 拥有两者的代码。do
A
a
do
接下来我们像往常一样 定义方法,但不在 classA
的范围内。相反,我们add_to_class
用类A
作为参数来装饰这个方法。这样做时,该方法能够访问 的成员变量,A
正如我们所期望的那样,如果它已被定义为 的A
定义的一部分。让我们看看当我们为实例调用它时会发生什么a
。
@add_to_class(A)
def do(self):
print('Class attribute "b" is', self.b)
a.do()
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
评论
查看更多