神经网络实验代码 | PyTorch系列(二十七)

点击上方“AI算法与图像处理”,选择加"星标"或“置顶”

重磅干货,第一时间送达

文 |AI_study

原标题:Training Loop Run Builder - Neural Network Experimentation Code

推荐

这个系列很久没有更新了,最新有小伙伴反馈官网的又更新了,因此,我也要努力整理一下。这个系列在CSDN上挺受欢迎的,希望小伙伴无论对你现在是否有用,请帮我分享一下,后续会弄成电子书,帮助更多人!

欢迎来到这个神经网络编程系列。 在本文中,我们将编写一个RunBuilder类,该类将允许我们使用不同的参数生成多个运行。

使用RunBuilder类

本文以及本系列最后几节的目的是使自己处于能够有效地尝试我们所构建的训练过程的位置。因此,我们将扩展在超参数实验中该情节涉及的内容。我们将使那里看到的更加干净。

我们将构建一个名为RunBuilder的类。但是,在介绍如何构建类之前。让我们看看它将允许我们做什么。我们将从import 开始。

from collections import OrderedDict
from collections import namedtuple
from itertools import product

我们正在从 collections 中导入OrderedDict和namedtuple,并且正在从itertools中导入一个名为product的函数。这个product()函数是我们上次看到的函数,它在给定多个列表输入的情况下计算笛卡尔乘积。

好的。这是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])

在这里,我们在字典中定义了一组参数和值。我们有一组要尝试的学习率和一组批batch的大小。当我们说“尝试”时,是指我们要针对字典中的每个学习率和每个批次大小进行一次训练。

要获得这些运行,我们只需调用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类已经构建并返回了四个运行的列表。这些运行中的每一个都有学习率和定义运行的batch大小。

我们可以通过索引到列表来访问单个运行,如下所示:

> run = runs[0]
> run


Run(lr=0.01, batch_size=1000)

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

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

> print(run.lr, run.batch_size)


0.01 1000

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

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

输出:

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

输出:

[
    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

输出:

[
    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的列表。然后,我们使用itertools中的product()函数使用字典中每个参数的值来创建笛卡尔乘积。这给了我们一组定义运行的有序对。我们遍历所有这些,将运行添加到每个运行的列表中。

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

最后,我们将此代码包装在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()方法是静态的,因此我们可以使用类本身来调用它。我们不需要该类的实例。

现在,这使我们可以通过以下方式更新我们的训练代码:

之前:

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

之后

for run in RunBuilder.get_runs(params):
    comment = f'-{run}'
    
    # Training process given the set of parameters

什么是笛卡尔积?

您知道笛卡尔积吗?像生活中的许多事物一样,笛卡尔积是一个数学概念。笛卡尔积是二进制运算。该操作将两组作为参数,并返回第三组作为输出。让我们看一个通用的数学示例。

假设 X  是一个集合。

假设 Y 是一个集合。

两组之间的笛卡尔积表示为:X * Y。集合X和集合Y的笛卡尔积被定义为所有有序对的集合对(x, y), x∈X  和 y∈Y。这可以用以下方式表示:

这种表示笛卡尔乘积的输出的方式称为集合生成器符号。很酷。所以X *Y  是所有有序对的集合(x, y), x∈X  和 y∈Y。

计算X*Y

我们执行以下操作:对于每个x∈X  和 y∈Y,我们收集相应的对(x, y)。结果集合给我们的是所有有序对的集合

这是用Python表达的具体示例:

X = {1,2,3}
Y = {1,2,3}


{ (x,y) for x in X for y in Y }

输出:

{(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

输出:

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

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

文章中内容都是经过仔细研究的,本人水平有限,翻译无法做到完美,但是真的是费了很大功夫,希望小伙伴能动动你性感的小手,分享朋友圈或点个“在看”,支持一下我 ^_^

英文原文链接是:

https://deeplizard.com/learn/video/NSKghk0pcco

加群交流

欢迎小伙伴加群交流,目前已有交流群的方向包括:AI学习交流群,目标检测,秋招互助,资料下载等等;加群可扫描并回复感兴趣方向即可(注明:地区+学校/企业+研究方向+昵称)

 谢谢你看到这里! ????

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
神经网络实验步骤详细分析具体-神经网络大作业(一).doc 本人做的神经网络实验,步骤详细,分析具体,适合做入门学习用-I do neural network experiments, the steps detailed analysis of specific, suitable for entry to study 截取某些内容,方便参考: 用BP网络识别雷达测速的三类信号 一.数据来源      此信号来自一部测速雷达获得的三种目标的回波信号,三种目标分别是行人W、自行车B和卡车T,信号中包含目标的速度信息。 二.信号的分析与处理      根据所给的三类信号的样本,每一个样本中均包含1024个数据,由于每一个样本的数据量较大,不可能将所有1024个数据全都作为神经元的输入,计算量太大,所以必须首先对信号进行分析,提取最有价值的特征信息。      首先可以看看每一个样本中的数据图,以各类信号中的第一个样本为例,如图1所示。 (1)                                       (2)                                        (3) 图1 (1)行人数据图  (2)自行车数据图  (3)卡车数据图              从上图的时域数据基本上观察不出规律,因此我们要对数据进行傅立叶变换,从频域分析数据的特征,如下图2所示。 图2 行人数据频谱图 从上图中看到行人的数据的频谱的幅度很小,原因是因为信号在零点处的值特别大,所以要将在零点处的值去掉,得到如图3所示。 图3 行人数据去掉零点后的频谱图 这时可以观察到信号的一些特征,从图中发现信号的频谱图是基本对称分布的,而且信号的峰值也很大,可以对它首先进行归一化,如下图4所示。 图4 (1)行人数据归一化后的频谱图 (2)取绝对值后的频谱图 同时将自行车和卡车的频谱图来做比较如图5,6所示 图5 (1)自行车数据归一化后的频谱图        (2)取绝对值后的频谱图 图6 (1)卡车数据归一化后的频谱图              (2)取绝对值后的频谱图 从上面三幅图中,可以观察到信号都有明显的峰值,但是出现的位置不同,另外,信号的均值和方差明显不同。但是考虑到雷达所测数据中,会有一些速度反常规的游离数据,所以考虑采用受游离数据影响小的平均绝对值偏差来代替样本方差作为输入特征。同时,以数据的样本中位数来作为输入特征来减少游离数据的影响。根据这些特征进行提取来作为输入。 三.特征提取 1.取信号归一化后的均值作为一个特征量。 2.取信号归一化后的平均绝对值偏差作为一个特征量。 3.取信号归一化后的样本中位数作为一个特征量。 4.由三幅图的比较可以发现,信号的每两点之间的起伏程度也不尽相同,所以可以设定一个特征量,来纪录信号两点间的起伏程度的大小。 5.信号在经过归一化后,可以将信号全部的值加起来,用这个总的值来作为一个特征量。 除了上述的特征,还有很多特征可以提取,但是特征越多,需要的输入神经元越多,依照隐层神经元约为输入神经元的两倍的原则,隐层的神经元也将越多。则网络训练的时间将花费很大。所以,本实验只提取了上述特征中的1,2,3。 四.算法与实现 根据提取的特征的维数,来决定输入神经元的个数。因为提取的三个特征的维数分别为8,1和1,所以输入神经元的个数为10。输出神经元的个数定为3个,考虑到被识别的三种信号分别对应三个输出,虽然用两个神经元就可以表示三种输出状态,但是用三个神经元能更好地分辨,减少出错的概率。至于隐层的神经元个数则按照约为输入神经元个数的两倍的原则,设为20个。当然还可以在调试过程中根据输出的识别率来找到一个一个较为合适的个数。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值