专栏首页AI算法与图像处理面向对象编程的方式搭建CNN网络 | PyTorch系列(十三)

面向对象编程的方式搭建CNN网络 | PyTorch系列(十三)

文 |AI_study

从我们深度学习项目的高层视角或概括的角度来看,我们准备了数据,现在,我们准备构建我们的模型。

  • 准备数据
  • 构建模型
  • 训练模型
  • 分析模型的结果

说到模型,我们指的是我们的网络。“模型”和“网络”是同一个意思。我们希望我们的网络最终做的是建模或近似一个将图像输入映射到正确输出类的函数。


一、前提

为了在PyTorch中构建神经网络,我们扩展了PyTorch类 torch.nn.Module。这意味着我们需要在Python中利用一点面向对象编程(OOP)。

在这篇文章中,我们将快速回顾一下使用PyTorch神经网络所需的细节,但是如果您发现还需要更多,Python文档中有一个概述教程。

https://docs.python.org/3/tutorial/classes.html

要构建卷积神经网络,我们需要对CNN的工作原理以及用于构建CNN的组件有一个大致的了解。 这个深度学习基础知识系列是该系列的一个很好的先决条件,因此,我强烈建议您(如果尚未)涵盖该系列。 如果您只想使用CNN速成班,可以查看以下特定文章:

  • 卷积神经网络(CNN)的解释
  • 可视化来自CNN的卷积滤波器
  • 卷积神经网络中的零填充解释
  • 卷积神经网络中的最大池解释
  • 卷积神经网络(CNN)中的可学习参数解释

现在让我们快速进行面向对象的编程回顾。

https://deeplizard.com/learn/video/YRhxdVk_sIs https://deeplizard.com/learn/video/cNBBNAxC8l4 https://deeplizard.com/learn/video/qSTv_m-KFk0 https://deeplizard.com/learn/video/ZjM_XQa5s6s https://deeplizard.com/learn/video/gmBfb6LNnZs

二、快速回顾面向对象编程

当我们编写程序或构建软件时,有两个关键组件:代码和数据。有了面向对象编程,我们就可以围绕对象来确定程序设计和结构的方向。

使用类在代码中定义对象。类定义了对象的规范,它指定了类的每个对象应该具有的数据和代码。

当我们创建一个类的对象时,我们称这个对象为类的一个实例,并且一个给定类的所有实例都有两个核心组件:

  • Methods(代码)
  • Attributes(数据)

方法表示代码,而属性表示数据,因此方法和属性是由类定义的。

在一个给定的程序中,有许多对象。给定类的一个实例可以同时存在,所有实例都具有相同的可用属性和相同的可用方法。从这个角度来看,它们是一致的。

相同类的对象之间的区别在于每个属性的对象中包含的值。每个对象都有自己的属性值。这些值决定了对象的内部状态。每个对象的代码和数据都被封装在对象中。

让我们构建一个简单的Lizard 类来演示类如何封装数据和代码:

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

我们通过指定类名并传递构造函数参数来创建类的对象实例。构造函数将接收这些参数,构造函数代码将运行并保存传递的名称。

然后,我们可以访问名称并打印它,还可以调用set_name()方法来更改名称。一个程序中可以存在多个这样的Lizard 实例,每个实例都包含自己的数据。

从面向对象的角度来看,这种设置的重要部分是将属性和方法组合起来并包含在对象中。

现在让我们转换一下,看看面向对象编程如何适合PyTorch。

PyTorch 的torch .nn 包

为了在PyTorch中构建神经网络,我们使用了torch.nn包,这是PyTorch的神经网络(nn)库。我们通常是这样导入包的:

import torch.nn as nn

这允许我们使用nn别名访问神经网络包。所以从现在开始,如果我们说nn,就是指torch.nn 。PyTorch的神经网络库包含构建神经网络所需的所有典型组件。

构建神经网络所需的主要组件是一个层,因此,正如我们所期望的那样,PyTorch的神经网络库包含一些类,可以帮助我们构建层。

PyTorch的nn.Module类

众所周知,深层神经网络是由多层结构构成的。这就是网络 深 的原因。神经网络中的每一层都有两个主要的组成部分:

  • 转换(代码)
  • 一组权重(数据)

与生活中的许多事情一样,这一事实使得层成为使用OOP表示对象的最佳候选对象。OOP是面向对象编程的简称。

实际上,PyTorch就是这种情况。在神经网络包中,有一个类叫做Module,它是所有神经网络模块的基类,包括层。

这意味着PyTorch中的所有层都扩展了nn.Module类,并继承了PyTorch在nn.Module 中的所有内置功能。在面向对象编程中,这个概念被称为继承。

甚至神经网络也会扩展nn.Module的类。这是有道理的,因为神经网络本身可以被认为是一个大的层(如果需要,让它随着时间的推移而下沉)。

PyTorch中的神经网络和层扩展了nn.Module类。这意味着在PyTorch中构建新层或神经网络时,我们必须扩展nn.Module类。

PyTorch的nn.Modules 有一个forward()方法

当我们把一个张量作为输入传递给网络时,张量通过每一层变换向前流动,直到张量到达输出层。这个张量通过网络向前流动的过程被称为前向传递。

The tensor input is passed forward though the network.

PyTorch的nn.functional包

当我们实现nn.Module子类的forward() 方法时,通常将使用nn.functional包中的函数。 该软件包为我们提供了许多可用于构建层的神经网络操作。 实际上,许多nn.Module层类都使用nn.functional函数来执行其操作。

nn.functional软件包中包含nn.Module子类用于实现其forward() 函数的方法。 稍后,通过查看nn.Conv2d卷积层类的PyTorch源代码,来观察一个示例。

在PyTorch中建立神经网络

现在,我们有足够的信息来提供在PyTorch中构建神经网络的概述。 步骤如下:

精简版:

  1. 扩展nn.Module基类。
  2. 将层定义为类属性。
  3. 实现forward() 方法。

更详细的版本:

  1. 创建一个扩展nn.Module基类的神经网络类。
  2. 在类构造函数中,使用torch.nn中的预构建层将网络的图层定义为类属性。
  3. 使用网络的层属性以及nn.functional API中的操作来定义网络的前向传播。

(1)扩展PyTorch的nn.Module类

就像我们在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,我们必须做另外两件事:

  1. 在第1行的括号中指定nn.Module类。
  2. 在构造函数内部的第3行上插入对super 类构造函数的调用。

这给了我们:

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类的所有功能。

(2)将网络的层定义为类属性

目前,我们的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的Python类,该类扩展了PyTorch的nn.Module类。 在Network类内部,我们有五个定义为属性的层。 我们有两个卷积层,self.conv1和self.conv2,以及三个线性层,self.fc1,self.fc2,self.out。

我们在fc1和fc2中使用了缩写fc,因为线性层也称为完全连接层。 它们也有一个我们可能会听到的叫做 “dense” 的名字。 因此,linear, dense, 和 fully connected 都是指同一类型的层的所有方法。 PyTorch使用线性这个词,因此使用nn.Linear类名。

我们将名称out用作最后一个线性层,因为网络中的最后一层是输出层。

总结

现在,我们应该对如何使用torch.nn库开始在PyTorch中构建神经网络有一个好主意。 在下一篇文章中,我们将研究层的不同类型的参数,并了解如何选择它们。 下一个见。

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

英文原文链接是:

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

本文分享自微信公众号 - AI算法与图像处理(AI_study),作者:AI_study

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-05-22

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 基于UNet网络实现的人像分割 | 附数据集

    人像分割的相关应用非常广,例如基于人像分割可以实现背景的替换做出各种非常酷炫的效果。我们将训练数据扩充到人体分割,那么我们就是对人体做美颜特效处理,同时对背景做...

    AI算法与图像处理
  • 万字长文!攻克目标检测难点秘籍一,模型加速之轻量化网络

    目标检测是计算机视觉中一个重要问题,在行人跟踪、车牌识别、无人驾驶等领域都具有重要的研究价值。近年来,随着深度学习对图像分类准确度的大幅度提高,基于深度学习的目...

    AI算法与图像处理
  • 非CS科班算法岗(规控方向)面经

    先说一下背景,top2本博控制专业,一年前没有任何数据结构和算法系统知识,一年内系统的选了数据结构和算法课,同时先后经历了春招实习和秋招校招的洗礼,也完成了自己...

    AI算法与图像处理
  • torch.nn.ModuleList

    在列表中保持子模块。ModelList可以像正常Python列表一样检索,但是它所包含的模块已正确注册,并且对所有模块方法都可见。

    于小勇
  • iOS优美的侧滑返回FDFullscreenPopGesture

    Raindew
  • PyQt5 GUI应用程序工具包入门(3)—信号槽

    上一讲,我们编制了一个简单的登录对话框。而真正的登录对话框需要将输入的用户名和密码发送出去,进行处理。PyQt通过信号(signal)和槽(slot)机制实现对...

    Python中文社区
  • NAB SHOW 2018视频影像专题丨HHI带来全新VR视频编解码器,夏普将展示其8K生态系统

    VRPinea
  • Linux命令(35)——iconv命令

    iconv命令是用来转换文件的编码方式,比如它可以将UTF8编码的转换成GB18030的编码。Linux下的iconv开发库包括iconv_open,iconv...

    Dabelv
  • 干货|Python大佬手把手带你破解哔哩哔哩网滑动验证(上篇)

    有爬虫经验的各位小伙伴都知道,正常我们需要登录才能获取信息的网站,是比较难爬的。原因就是在于,现在各大网站为了反爬,与爬虫机制斗智斗勇,一般的都加入了图片验证...

    Python进阶者
  • 随笔——关于网站建设

    FHYC

扫码关注云+社区

领取腾讯云代金券