本篇文章是翻译:https://deeplizard.com网站中的关于Pytorch学习的文章,供学习使用。
原文地址为:https://deeplizard.com/learn/video/k4jY9L8H89U
欢迎回到基于Pytorch的神经网络系列课程。在这一篇文章中,我们将开始创建我们的第一个卷积神经网络(CNN)。废发不多说,现在开始吧。
在之前的文章中或之前的概述中我们可以了解到,我们准备了数据,现在我们准备创建我们的模型。
使用PtTorch创建一个神经网络,我们扩展torch.nn.Module类。意思是说我们需要在Python中利用一些面向对象编程的方法。
我们将对面向对象进行快速的复习,以涵盖使用pytorch神经网络所需的详细信息,但是,如果你需要发现更多的信息,请查看python文档
。
创建卷积神经网络,我们需要对卷积神经网络和组成部分有一个大致的了解。这个深度学习基础系类课程
是一个很好的前导课程。如果你还没有深度学习基础的话,强烈建议你先去进行学习。如果你知识想速成卷积神经网络,可以以下特定文章。
Convolutional Neural Networks (CNNs) explained
Visualizing Convolutional Filters from a CNN
Zero Padding in Convolutional Neural Networks explained
Max Pooling in Convolutional Neural Networks explained
Learnable Parameters in a Convolutional Neural Network (CNN) explained
当我们写程序或者编写软件时,一般包含两个关键的东西–代码和数据。在面向对象编程思想中,我们围绕对象定位程序设计和结构。
对象使用类来进行定义。一个类定义一个对象的规范,该规范指定该类的每个对象应具有的数据和代码。
当我们创建一个类的对象时,我们称作这个对象为该类的实例,一个类的所有实例都有两个核心部分:
class Lizard: #class declaration
def __init__(self, name): #class constructor (code)
self.name = name #attribute (data)
def set_name(self, name): #method declaration (code)
self.name = name #method implementation (code)
第一行定义了类并且指定了类名-Lizard
。
第二行定义了一个特殊的函数称为类的构造函数,当一个新的实例被创建时,类的构造函数将被调用。其中存在两个参数即self
和name
。
self
参数使我们能够创建一个存储或封装在对象内的属性值。当我们调用构造函数或其他函数时,我们不用传递self
参数,Python会自动为我们执行此操作。
调用方可以任意传递任何其他参数的参数值,这些传入方法的值可以在计算中使用,也可以稍后使用self
保存和访问。
在完成构造函数之后,我们可以创建许多指定的方法,比如下面代码中表示的允许调用者改变存储在self
中的名字(name
)的值。我们所需要做的是调用函数并传入一个名字的新值,如下所示:
> lizard = Lizard('deep')
> print(lizard.name)
deep
> lizard.set_name('lizard')
> print(lizard.name)
lizard
我们通过一个指定类名和传递构造函数参数的类创建一个实例对象。这个构造函数将会收到参数,并且构造函数将会运行,保存传入的名字。
从面向对象的角度来看,其重要部分是属性和方法被组织并包含在对象中。
现在,我们来看看面向对象编程如何与PyTorch相适应的。
使用PyTorch创建神经网络,我们使用PyTorch的神经网络库中的torch.nn数据包,典型的导入方式如下所示:
import torch.nn as nn
我们可以使用nn别名来访问神经网络包。所以从现在开始,我们提到nn
,就是在说torch.nn
。PyTorch的神经网络库包含所有我们需要的神经网络典型组件。
建立神经网络所需要的主要组件是层(layer),所以,正如我们所期待的那样,PyTorch神经网络库中包含可以帮助我们构建层的类。
正如我们所知的那样,深度神经网络是由许多的层构成的,这是使神经网络更深的原因。神经网络的每一个层包含两个组成部分:
nn
包中,有一个名为Module
的类,它是神经网络模块(包括层)的基类。nn.Module
类,并且继承nn.Module
类中的所有PyTorch的内置功能。在面向对象编程中,此概念被称为继承。nn.Module
类。这是有道理的,因为神经网络本身可以看作是一个很大的层(如果需要,可以让它随着时间的流逝而沉没)。nn.Module
类,这意味着当我们在使用PyTorch创建新的网络层的时候必须扩展nn.Module
。当我们向我们的网络中出入张量时,这个张量向前传递经过每一个层的转换最终到达输出层。张量通过网络向前流动的过程称为前向传递。
张量输入通过网络转发
张量穿过每一个层的时候便会被这个层所转换。所有单个层的组成部分都在进行网络前向传递的转换过程中发挥了一定的作用。
整体转换的目标是将输入转换或映射到正确的预测数据类别,并且在训练过程中,层的权重的更新方式会调整映射以输出更接近正确的预测。
这一切意味着,每个PyTorch的nn.Module
都有一个forward()
函数,并且当我们建立层和网络时,我们必须提供一个forward()
函数的实现。这个forward函数是实际的转换。
当我们实现我们nn.Module子类中的forward()
函数的时候,我们通常使用nn.functional
包中的函数。这个包提供给我们许多可用于构建图层的操作。实际上,许多nn.Module
层类的许多操作都是使用nn.functional的方法实现的。
nn.functional包中包含nn.Module
子类执行它们的forward()
函数的方法。最后,我们以一个例子来查看PyTorch中nn.Conv2d
的卷积层类的源代码。
我们现在可以使用PyTorch进行神经网络轮廓的创建,遵循下面的步骤:
精简版:
nn.Module
基类。forward()
方法。详细版:
以之前的Lizard类为例,创建一个简单的类来表示一个神经网络。
class Network:
def __init__(self):
self.layer = None
def forward(self, t):
t = self.layer(t)
return t
这个简单的神经网络在构造函数中有一个单一的虚拟层,并且这个虚拟层实现了forward函数。
这个forward()
函数中接收一个张量 t
,然后使用虚拟层对其进行转换。在这个张量被转换后,返回一个新的张量。
这是一个好的开始,但是这个类并没有扩展nn.Module类,让我们的Network类扩展nn.Module。我们必须做两件事:
class Network(nn.Module): # line 1
def __init__(self):
super().__init__() # line 3
self.layer = None
def forward(self, t):
t = self.layer(t)
return t
这个改变将我们简单的神经网络变成了PyTorch神经网络,其原因是我们扩展了Pytorch的nn.Module基类。
现在我们有了一个Network类,它具有PyTorch的nn.Module类的所有功能。
现在,我们的Network类有一个单一的虚拟层作为属性。让我们使用PyTorch的nn
库欲构建的真实层来代替它。我们创建一个CNN网络,所以我们将会使用线性层和卷积层这两个类型的层。
class Network(nn.Module):
def __init__(self):
super().__init__()
self.conv1 = nn.Conv2d(in_channels=1, out_channels=6, kernel_size=5)
self.conv2 = nn.Conv2d(in_channels=6, out_channels=12, kernel_size=5)
self.fc1 = nn.Linear(in_features=12 * 4 * 4, out_features=120)
self.fc2 = nn.Linear(in_features=120, out_features=60)
self.out = nn.Linear(in_features=60, out_features=10)
def forward(self, t):
# implement the forward pass
return t
现在,我们有一个叫做Network的类,这个类扩展了nn.Module类。在我们的Network
类中,我们有五个被定义为属性的层。两个卷积层,self.conv1
和self.conv2
,三个线性层self.fc1
,self.fc2
和self.out
。
因为线性层又叫全连接层(fully connected layers),所以我们使用缩写fc来表示线性层。线性层有时也被叫做dense层。所以线性层、dense和全连接层指的是一个类型的层。PyTorch使用linear
这个词表示,所以类名叫做nn.linear
。
我们使用out
表示最后一层,因为最后一层为输出层。
我们现在应该对使用torch.nn库构建神经网络有了一定的了解。在下一章中将介绍两个不同类型的参数并且知道如何选择它们。下次见。