Training Loop Run Builder-神经网络实验(pytorch系列-27)

Training Loop Run Builder-神经网络实验

欢迎来到这个神经网络编程系列。在此小节中,我们将编写一个RunBuilder类,该类将定义我们运行的参数集。
在这里插入图片描述

使用RunBuilder

本节以及本系列最后几节的目的是使自己处于能够有效地尝试我们构建的训练过程的位置。因此,我们将扩展超参数实验章节中涉及的内容 。我们将更能清楚的理解超参数试验的原理。

我们将建立一个名为RunBuilder的类。但是,在我们看如何构建类之前。让我们看看它将允许我们做什么。我们导入以下资源。

from collections import OrderedDict #有序字典
from collections import namedtuple #定义具名元组
from itertools import product

我们正在从集合中导入OrderedDictnamedtuple并且正在从itertools中导入product函数。这个 product()函数是我们上次使用的函数,它在给定多个列表输入的情况下计算笛卡尔乘积。
关于namedtuple的解释可参考菜鸟教程
这是打造定义我们的运行参数集的RunBuilder类。下面是它的工作原理。

class RunBuilder():
    @staticmethod
    def get_runs(params):
        Run = namedtuple('Run', params.keys())
        runs = []
        for v in product(*params.values()):
            runs.append(Run(*v))
        return runs

使用此类的主要注意事项是它具有一个静态方法get_runs()。该方法将为我们提供基于传入参数构建的运行结果。

现在定义一些参数。

params = OrderedDict(
    lr = [.01, .001]
    ,batch_size = [1000, 10000]
)

在这里,我们在字典中定义了一组参数和值。我们有一组学习率和一组我们想尝试的批量大小。当我们说“尝试”时,是指我们要针对字典中的每个学习率和每个批次大小进行一次训练。
要获得这些运行,我们只需调用RunBuilder类的get_runs()函数,并传入我们要使用的参数即可。

> runs = RunBuilder.get_runs(params)
> runs

[
    Run(lr=0.01, batch_size=1000),
    Run(lr=0.01, batch_size=10000),
    Run(lr=0.001, batch_size=1000),
    Run(lr=0.001, batch_size=10000)
]

我们可以看到RunBuilder该类已构建并返回了四个运行的列表。这些运行中每一个都有学习率和定义运行的批处理大小。
我们可以通过索引到列表来访问单个运行,如下所示:

> run = runs[0]
> run
Run(lr=0.01, batch_size=1000)

注意:运行输出的字符串表示形式。这个字符串表示是由Run 元组类自动为我们生成的,如果我们想将运行统计信息写到TensorBoard或任何其他可视化程序的磁盘上,则可以使用该字符串来唯一标识运行 。

另外,由于run 具有命名属性的对象,因此我们可以使用点表示法访问值,如下所示:

> print(run.lr, run.batch_size)
output
0.01 1000

最后,由于运行列表是Python可迭代的,因此我们可以像这样干净地迭代运行:

for run in runs:
    print(run, run.lr, run.batch_size)

Output:

Run(lr=0.01, batch_size=1000) 0.01 1000
Run(lr=0.01, batch_size=10000) 0.01 10000
Run(lr=0.001, batch_size=1000) 0.001 1000
Run(lr=0.001, batch_size=10000) 0.001 10000

要添加其他值,我们要做的就是将它们添加到原始参数列表中,如果要添加其他类型的参数,我们要做的就是添加它。新参数及其值将自动变为可在运行中使用。运行的字符串输出也将更新。

两个参数:

params = OrderedDict(
    lr = [.01, .001]
    ,batch_size = [1000, 10000]
)
runs = RunBuilder.get_runs(params)
runs

Output:

[
    Run(lr=0.01, batch_size=1000),
    Run(lr=0.01, batch_size=10000),
    Run(lr=0.001, batch_size=1000),
    Run(lr=0.001, batch_size=10000)
]

三个参数:

params = OrderedDict(
    lr = [.01, .001]
    ,batch_size = [1000, 10000]
    ,device = ["cuda", "cpu"]
)

runs = RunBuilder.get_runs(params)
runs

Output:

[
    Run(lr=0.01, batch_size=1000, device='cuda'),
    Run(lr=0.01, batch_size=1000, device='cpu'),
    Run(lr=0.01, batch_size=10000, device='cuda'),
    Run(lr=0.01, batch_size=10000, device='cpu'),
    Run(lr=0.001, batch_size=1000, device='cuda'),
    Run(lr=0.001, batch_size=1000, device='cpu'),
    Run(lr=0.001, batch_size=10000, device='cuda'),
    Run(lr=0.001, batch_size=10000, device='cpu')
]

当我们在训练过程中尝试不同的值时,此功能将使我们能够更好地控制。
让我们看看如何构建此类RunBuilder

编码RunBuilder

我们要做的第一件事是创建一个我们想要实验的参数和值的字典。

params = OrderedDict(
    lr = [.01, .001]
    ,batch_size = [1000, 10000]
)

接下来,我们从字典中获得键列表。

> params.keys()
odict_keys(['lr', 'batch_size'])

然后,我们从字典中获取值列表。

> params.values()
odict_values([[0.01, 0.001], [1000, 10000]])

有了这两个功能之后,我们只需检查一下它们的输出,以确保我们理解它们的意思。完成后,我们将使用这些键和值进行下一步操作。我们将从键开始。

Run = namedtuple('Run', params.keys())

该行创建了一个名为且Run具有命名字段的新元组子类。此类 Run用于封装我们每次运行的数据。此类的字段名称由传递给构造函数的名称列表设置。首先,我们传递类名。然后,我们传递字段名称,在本例中,我们传递字典中的键列表。
现在,我们有了一个用于运行的类,我们准备创建一些类。

runs = []
for v in product(*params.values()):
    runs.append(Run(*v))

首先,我们创建一个名为的列表runs。然后,我们使用来自itertoolsproduct()函数-使用字典中每个参数的值创建笛卡尔乘积。这提供了我们一组定义运行的有序对。我们遍历所有这些有序对,并将每一个有序对添加到列表runs中,作为一个运行。

对于笛卡尔乘积中的每个值,我们都有一个有序的元组。笛卡尔积为我们提供了每个有序对,因此我们拥有所有可能的有序对,其学习率和批量大小均如此。当我们将这个tuple传递给Run的构造函数时,我们使用*运算符告诉构造函数接受元组值作为与tuple自身相对应的参数。
最后,我们将此代码包装在我们的RunBuilder类中。

class RunBuilder():
    @staticmethod
    def get_runs(params):
        Run = namedtuple('Run', params.keys())
        runs = []
        for v in product(*params.values()):
        runs.append(Run(*v))
        return runs

由于该get_runs()方法是静态的,因此我们可以使用类本身来调用它。我们不需要该类的实例。
现在,这使我们可以通过以下方式升级我们的训练代码:
before:

for lr, batch_size, shuffle in product(*param_values):
    comment = f' batch_size={batch_size} lr={lr} shuffle={shuffle}'
    # Training process given the set of parameters

after:

for run in RunBuilder.get_runs(params):
    comment = f'-{run}'

什么是笛卡尔积?

你知道笛卡尔积吗?笛卡尔积是一个数学概念。笛卡尔积是二进制运算。该操作将两组集合作为参数,并返回第三组集合作为输出。让我们看一个通用的数学示例:
假设 X 是一个集合。
假设 Y 是一个集合。
两个集合之间的笛卡尔积表示为:X×Y。集合X 和集合 Y之间的笛卡尔积被定义为所有有序对的集合 (x,y) 其中x∈X和y∈Y 。这可以用以下方式表示:
X×Y={(x,y)∣x∈X and y∈ Y}
这种表示笛卡尔乘积的输出的方式称为SetBuilder符号。
X×Y是所有有序对的集合(x,y)其中 x∈X和y∈Y 。
计算 X×Y, 我们执行以下操作:
对于每个x∈X和每个y∈Y ,我们得到相应的对 (x,y)。结果集合给出了所有有序对的集合(x,y)其中x∈X和y∈Y 。
用Python表达的具体示例:

X = {1,2,3}
Y = {1,2,3}
{ (x,y) for x in X for y in Y }

Output:

{(1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (2, 3), (3, 1), (3, 2), (3, 3)}

注意数学代码的强大,它涵盖了所有情况。也许你注意到,可以使用如下的for循环迭代来实现:

X = {1,2,3}
Y = {1,2,3}
cartesian_product = set()
for x in X:
    for y in Y:
        cartesian_product.add((x,y))
cartesian_product

Output:

{(1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (2, 3), (3, 1), (3, 2), (3, 3)}

总结

好了,现在我们知道了它是如何工作的,并且可以继续使用它。

欢迎来到这个神经网络编程系列。在本集中,我们将编写一个训练循环运行构建器类,该类将使我们能够生成具有不同参数的多个运行。这将有助于我们进行神经网络训练过程的实验。

在视频末尾,我们介绍了笛卡尔乘积。

英文原文链接是:https://deeplizard.com/learn/video/NSKghk0pcco

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值