介绍
假设您要定义以下神经网络,其中一个输入层,两个隐藏层和一个输出层,中间层使用relu激活,而输出层使用sigmoid激活函数,如下所示:
全连接(前馈)网络 这是一个全连接的16x12x10x1神经网络。
1.手动建立权重和偏差
一种方法是构建所有的块。这是一种低级的方法,但是如果您试图理解深度学习体系结构(或者如果你想开发一个定制层),那么它可能非常适合您。这里的关键是,您需要告诉PyTorch在您的网络中什么是可变的或可优化的,以便PyTorch知道如何在您的网络中执行梯度下降。让我们看看在低层PyTorch中人们是如何处理这个问题的:
2.扩展torch.nn.Model类
在实践中,我们大多数人可能会使用预定义的层和激活函数来训练我们的网络。如果这样则有两种方法。一种方法是通过从torch.nn扩展Model类来创建自己的神经网络python类。以这种方式定义一个神经网络有许多优点,它允许继承torch.nn模块的所有功能,同时允许灵活地覆盖默认模型的构造和forward pass 方法。在这个方法中,我们将定义两个方法:
1.__init__
2. forward方法
第一个是该类的初始化程序,在这里您将定义组成网络的层。通常,我们不需要在这里定义激活函数,因为它们可以在forward pass中定义,但这不是规定。
第二个方法是定义forward pass。该方法采用代表模型将在其上进行训练的特征的输入。在这里,您可以调用激活函数,并将之前在构造函数方法中定义的层作为参数传入。您需要将输入作为参数传递给第一层,并且在处理激活之后,可以将输出输入到下一层,依此类推。
让我们看一下如何在Python中做到这一点:
这是上面的输出
3.使用torch.nn.Sequential
这是一种模块化的方法。这与Keras的序列API非常相似,它利用了torch.cn的预构建层和激活函数。利用这种方法,我们的前馈网络可以定义为:
实际上,我们可以检查单层,并通过简单地为模型对象建立索引来调试模型权重。
print(model[0], model[0].weight)
但是如果你有很多不同种类的层和激活函数呢?在这种情况下,用索引来调用它们似乎是不可行的。您可以使用相同的结构命名这些层,并从python集合模块中传递一个OrderedDict作为参数。换句话说,您保持层的顺序并命名它们,这允许更简单和直接地引用层。
现在,让我们检查第二层及其权重:
print(model.fc2, model.fc2.weight)
混合方法
在pytorch中创建神经网络时,有时您可能更喜欢混合方法。PyTorch非常灵活,例如,你可以在一个基于类的方法中使用序列方法,就像这样:
输出如下:
结论
尽管在本文中作为示例使用的前馈神经网络很简单,这里的主要思想是展示有许多不同的方法来定义一个神经网络。