专栏首页AI算法与图像处理PyTorch中CNN的Forward方法 | PyTorch系列(十七)

PyTorch中CNN的Forward方法 | PyTorch系列(十七)

神经网络程序设计系列(综述)

到目前为止,在这个系列中,我们已经准备好了我们的数据,现在构建我们的模型。

我们通过扩展nn.Module PyTorch基类来创建网络,然后在类构造函数中将网络层定义为类属性。现在,我们需要实现网络的 forward() 方法,最后,我们将准备训练我们的模型。

  • 准备数据
  • 构建模型
    • 创建一个扩展nn.Module基类的神经网络类。
    • 在类构造函数中,将网络层定义为类属性。
    • 使用网络的层属性以及nn.functional API操作来定义网络的前向传递
  • 训练模型
  • 分析模型的结果

回顾一下网络

目前,我们知道forward()方法接受张量作为输入,然后返回张量作为输出。现在,返回的张量与传递的张量相同。

但是,在构建实现之后,返回的张量将是网络的输出。

这意味着forward 方法实现将使用我们在构造函数内部定义的所有层。这样,前向方法显式定义了网络的转换。

forward()方法是实际的网络转换。forward 方法是将输入张量映射到预测输出张量的映射。让我们看看这是如何完成的。

回想一下,在网络的构造函数中,我们可以看到定义了五层。

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

我们有两个卷积层和三个Linear 层。如果算上输入层,这将为我们提供一个总共六层的网络。

实现forward 方法

让我们对此进行代码编写。我们将从输入层开始。

输入层#1

任何神经网络的输入层都由输入数据确定。例如,如果我们的输入张量包含三个元素,那么我们的网络将在其输入层中包含三个节点。

因此,我们可以将输入层视为 identity transformation 。从数学上讲,这是下面的函数

f(x)=x.

我们给任何x 作为输入,我们得到相同的结果 x 作为输出。无论我们使用的是具有三个元素的张量,还是表示具有三个通道的图像的张量,此逻辑都是相同的。输入是数据输出!

这非常琐碎,这就是使用神经网络API时通常看不到输入层的原因。输入层隐式存在。

绝对不是必需的,但是为了完整起见,我们将在forward方法中显示标识操作。

# (1) input layert = t

隐藏的卷积层:第2层和第3层

就执行转换而言,两个隐藏的卷积层都将非常相似。在深度学习基础知识系列中,我们在有关层的文章中解释说,不是输入或输出层的所有层都称为隐藏层,这就是为什么我们将这些卷积层称为隐藏层。

深度学习基础:https://deeplizard.com/learn/video/gZmobeGL0Yg

层的解释:https://deeplizard.com/learn/video/FK77zZxaBoI

为了执行卷积运算,我们将张量传递给第一卷积层self.conv1的forward 方法。我们已经了解了所有PyTorch神经网络模块如何具有forward() 方法,并且当我们调用nn.Module的forward() 方法时,有一种特殊的调用方法。

当要调用nn.Module实例的forward() 方法时,我们将调用实际实例,而不是直接调用forward() 方法。

代替执行此self.conv1.forward(tensor),我们执行此self.conv1(tensor)。确保您看到了本系列的上一篇文章,以了解有关此主题的所有详细信息。

让我们继续并添加实现两个卷积层所需的所有调用。

 #(2) hidden conv layert = self.conv1(t)t = F.relu(t)t = F.max_pool2d(t, kernel_size=2, stride=2)
# (3) hidden conv layert = self.conv2(t)t = F.relu(t)t = F.max_pool2d(t, kernel_size=2, stride=2)

正如我们在这里看到的那样,当我们在卷积层中移动时,输入张量将发生变换。第一卷积层具有卷积运算,然后是 relu 激活运算,其输出随后传递到kernel_size = 2和stride = 2的最大池化中。

然后将第一个卷积层的输出张量 t 传递到下一个卷积层,除了我们调用self.conv2()而不是self.conv1()以外,其他卷积层均相同。

这些层中的每一个都由权重(数据)和收集操作(代码)组成。权重封装在nn.Conv2d() 类实例中。relu() 和max_pool2d() 调用只是纯运算。这些都不具有权重,这就是为什么我们直接从nn.functional API调用它们的原因。

有时,我们可能会看到称为池化层的池化操作。有时我们甚至可能听到称为激活层的激活操作。

但是,使层与操作区分开的原因在于层具有权重。由于池操作和激活功能没有权重,因此我们将它们称为操作,并将其视为已添加到层操作集合中。

例如,我们说网络中的第二层是一个卷积层,其中包含权重的集合,并执行三个操作,即卷积操作,relu激活操作和最大池化操作。

请注意,此处的规则和术语并不严格。这只是描述网络的一种方式。还有其他表达这些想法的方法。我们需要知道的主要事情是哪些操作是使用权重定义的,哪些操作不使用任何权重。

从历史上看,使用权重定义的操作就是我们所说的层。后来,其他操作被添加到mix中,例如激活功能和池化操作,这引起了术语上的一些混乱。

从数学上来说,整个网络只是函数的组合,函数的组合就是函数本身。因此,网络只是一种函数。诸如层,激活函数和权重之类的所有术语仅用于帮助描述不同的部分。

不要让这些术语混淆整个网络只是函数的组合这一事实,而我们现在正在做的就是在forward()方法中定义这种组合。

隐藏的Linear层:第4层和第5层

在将输入传递到第一个隐藏的Linear 层之前,我们必须reshape() 或展平我们的张量。每当我们将卷积层的输出作为Linear层的输入传递时,都是这种情况。

由于第四层是第一个Linear层,因此我们将reshape操作作为第四层的一部分。

# (4) hidden linear layert = t.reshape(-1, 12 * 4 * 4)t = self.fc1(t)t = F.relu(t)
# (5) hidden linear layert = self.fc2(t)t = F.relu(t)

我们在CNN权重的文章中看到,reshape 操作中的数字 12 由来自前一个卷积层的输出通道数确定。

然而,4 * 4仍然是一个悬而未决的问题。让我们现在揭示答案。4 * 4实际上是12个输出通道中每个通道的高度和宽度。

我们从1 x 28 x 28输入张量开始。这样就给出了一个单一的彩色通道,即28 x 28的图像,并且在我们的张量到达第一 Linear 层时,尺寸已经改变。

通过卷积和池化操作,将高度和宽度尺寸从28 x 28减小到4 x 4。

卷积和池化操作是对高度和宽度尺寸的化简操作。我们将在下一篇文章中看到这是如何工作的,并看到用于计算这些减少量的公式。现在,让我们完成实现此forward() 方法。

张量重构后,我们将展平的张量传递给 Linear 层,并将此结果传递给relu() 激活函数。

输出层#6

我们网络的第六层也是最后一层是 Linear 层,我们称为输出层。当我们将张量传递到输出层时,结果将是预测张量。由于我们的数据具有十个预测类别,因此我们知道我们的输出张量将具有十个元素。

# (6) output layert = self.out(t)#t = F.softmax(t, dim=1)

十个组件中的每个组件内的值将对应于我们每个预测类的预测值。

在网络内部,我们通常使用relu() 作为我们的非线性激活函数,但是对于输出层,每当我们尝试预测一个类别时,我们就使用softmax()。softmax函数针对每个预测类返回正概率,并且概率之和为1。

但是,在本例中,我们不会使用softmax(),因为我们将使用的损失函数F.cross_entropy()在其输入上隐式执行softmax()操作,因此我们只返回 最后的线性变换。

这意味着我们的网络将使用softmax操作进行训练,但是当训练过程完成后将网络用于推理时,无需计算额外的操作。

结论

很好!我们做到了。这就是我们在PyTorch中实现神经网络forward方法的方式。

PyTorch在__ call __()方法中运行的额外代码就是我们从不直接调用forward()方法的原因。如果我们这样做,额外的PyTorch代码将不会被执行。因此,每当我们想要调用forward()方法时,我们都会调用对象实例。这既适用于层,也适用于网络,因为它们都是PyTorch神经网络模块。

现在可以实现网络的forward()方法了。

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

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

原始发表时间:2020-06-04

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

我来说两句

0 条评论
登录 后参与评论

相关文章

  • CNN中张量的输入形状和特征图 | Pytorch系列(三)

    在这个神经网络编程系列中,我们正在努力构建卷积神经网络(CNN),所以让我们看看在CNN中的张量输入。

    AI算法与图像处理
  • CNN输出大小公式 | PyTorch系列(二十)

    原标题:CNN Output Size Formula - Bonus Neural Network Debugging Session

    AI算法与图像处理
  • PyTorch神经网络中可学习的参数——CNN权重 | PyTorch系列(十五)

    在本系列的最后几篇文章中,我们已经开始构建CNN,我们做了一些工作来理解我们在网络构造函数中定义的层。

    AI算法与图像处理
  • 大赛评委共论技术趋势,大咖观点干货满满!

    5月18日,2020腾讯广告算法大赛开启《后疫情时代的“智”者未来》专题直播,6大评委就疫情之后,营销&技术人最为关心的企业数字化转型、职业发展等多方面议题展开...

    腾讯智能钛AI开发者
  • 安利一下WebView内存泄漏的方法

    Xiaolei123
  • PyTorch神经网络中可学习的参数——CNN权重 | PyTorch系列(十五)

    在本系列的最后几篇文章中,我们已经开始构建CNN,我们做了一些工作来理解我们在网络构造函数中定义的层。

    AI算法与图像处理
  • 多微信公共账号同时接入微信公共平台API(PHP)

    子勰
  • 助力「宅家抗疫」,腾讯云大学大咖分享不停!

    抗“疫”攻坚时刻,「腾讯云大学」联合「腾讯云最具价值专家(TVP)团队」重磅打造抗“疫”特别专题

    腾讯云大学
  • 说一下Dubbo 的工作原理?注册中心挂了可以继续通信吗?

    说一下的 dubbo 的工作原理?注册中心挂了可以继续通信吗?说说一次 rpc 请求的流程?

    李红
  • keras教程:手把手教你做聊天机器人(上)

    AI传送门

扫码关注云+社区

领取腾讯云代金券