当前位置: 首页 > news >正文

多用户商城系统网站建设网站开发语言数据库有几种

多用户商城系统网站建设,网站开发语言数据库有几种,旅游网站怎么做的,自建房设计1. 计算机视觉的发展历程 计算机视觉作为一门让机器学会如何去“看”的学科#xff0c;具体的说#xff0c;就是让机器去识别摄像机拍摄的图片或视频中的物体#xff0c;检测出物体所在的位置#xff0c;并对目标物体进行跟踪#xff0c;从而理解并描述出图片或视频里的场…1. 计算机视觉的发展历程 计算机视觉作为一门让机器学会如何去“看”的学科具体的说就是让机器去识别摄像机拍摄的图片或视频中的物体检测出物体所在的位置并对目标物体进行跟踪从而理解并描述出图片或视频里的场景和故事以此来模拟人脑视觉系统。因此计算机视觉也通常被叫做机器视觉其目的是建立能够从图像或者视频中“感知”信息的人工系统。 计算机视觉技术经过几十年的发展已经在交通车牌识别、道路违章抓拍、安防人脸闸机、小区监控、金融刷脸支付、柜台的自动票据识别、医疗医疗影像诊断、工业生产产品缺陷自动检测等多个领域应用影响或正在改变人们的日常生活和工业生产方式。未来随着技术的不断演进必将涌现出更多的产品和应用为我们的生活创造更大的便利和更广阔的机会。 飞桨为计算机视觉任务提供了丰富的 API并通过底层优化和加速保证了这些 API 的性能。同时飞桨还提供了丰富的模型库覆盖图像分类、检测、分割、文字识别和视频理解等多个领域。用户可以直接使用这些 API 组建模型也可以在飞桨提供的模型库基础上进行二次研发。 由于篇幅所限本章将重点介绍计算机视觉的经典模型卷积神经网络和两个典型任务图像分类和目标检测。主要涵盖如下内容 卷积神经网络卷积神经网络Convolutional Neural Networks, CNN是计算机视觉技术最经典的模型结构。本教程主要介绍卷积神经网络的常用模块包括卷积、池化、激活函数、批归一化、丢弃法等。 图像分类介绍图像分类算法的经典模型结构包括LeNet、AlexNet、VGG、GoogLeNet、ResNet并通过眼疾筛查的案例展示算法的应用。目标检测介绍目标检测 YOLOv3 算法并通过林业病虫害检测案例展示 YOLOv3 算法的应用。 计算机视觉的发展历程要从生物视觉讲起。对于生物视觉的起源目前学术界尚没有形成定论。有研究者认为最早的生物视觉形成于距今约 7 亿年前的水母之中也有研究者认为生物视觉产生于距今约 5 亿年前寒武纪。寒武纪生物大爆发的原因一直是个未解之谜不过可以肯定的是在寒武纪动物具有了视觉能力捕食者可以更容易地发现猎物被捕食者也可以更早的发现天敌的位置。视觉能力加剧了猎手和猎物之间的博弈也催生出更加激烈的生存演化规则。视觉系统的形成有力地推动了食物链的演化加速了生物进化过程是生物发展史上重要的里程碑。经过几亿年的演化目前人类的视觉系统已经具备非常高的复杂度和强大的功能人脑中神经元数目达到了 1000 亿个这些神经元通过网络互相连接这样庞大的视觉神经网络使得我们可以很轻松的观察周围的世界如下图所示。 对人类来说识别猫和狗是件非常容易的事。但对计算机来说即使是一个精通编程的高手也很难轻松写出具有通用性的程序比如假设程序认为体型大的是狗体型小的是猫但由于拍摄角度不同可能一张图片上猫占据的像素比狗还多。那么如何让计算机也能像人一样看懂周围的世界呢研究者尝试着从不同的角度去解决这个问题由此也发展出一系列的子任务如 下图所示。 图像分类Image Classification用于识别图像中物体的类别如bottle、cup、cube。目标监测Object Detection目标检测用于检测图像中每个物体的类别并准确标出它们的位置。图像语义分割Semantic Segmentation用于标出图像中每个像素点所属的类别属于同一类别的像素点用一个颜色标识。实例分割Instance Segmentation 值得注意的是2 中的目标检测任务只需要标注出物体位置而 4 中的实例分割任务不仅要标注出物体位置还需要标注出物体的外形轮廓。 在早期的图像分类任务中通常是先人工提取图像特征再用机器学习算法对这些特征进行分类分类的结果强依赖于特征提取方法往往只有经验丰富的研究者才能完成如下图所示。 在这种背景下基于神经网络的特征提取方法应运而生。Yann LeCun 是最早将卷积神经网络应用到图像识别领域的其主要逻辑是使用卷积神经网络提取图像特征并对图像所属类别进行预测通过训练数据不断调整网络参数最终形成一套能自动提取图像特征并对这些特征进行分类的网络如下图所示。 这一方法在手写数字识别任务上取得了极大的成功但在接下来的时间里却没有得到很好的发展。其主要原因一方面是数据集不完善只能处理简单任务在大尺寸的数据上容易发生过拟合另一方面是硬件瓶颈网络模型复杂时计算速度会特别慢。 目前随着互联网技术的不断进步数据量呈现大规模的增长越来越丰富的数据集不断涌现。另外得益于硬件能力的提升计算机的算力也越来越强大。不断有研究者将新的模型和算法应用到计算机视觉领域。由此催生了越来越丰富的模型结构和更加准确的精度同时计算机视觉所处理的问题也越来越丰富包括分类、检测、分割、场景描述、图像生成和风格变换等甚至还不仅仅局限于 2 维图片包括视频处理技术和 3D 视觉等。 2. 卷积神经网络Convolutional Neural Networks, CNN 卷积神经网络是目前计算机视觉中使用最普遍的模型结构。本章节主要介绍卷积神经网络的一些基础模块包括 卷积Convolution池化PoolingReLU 激活函数批归一化Batch Normalization丢弃法Dropout 回顾一下在之前我们介绍了手写数字识别任务里面有两个模型第一个就是全连接网络进行特征提取代码如下 # 全连接层神经网络实现 class MNIST_FC_Model(nn.Layer): def __init__(self): super(MNIST_FC_Model, self).__init__() # 定义两层全连接隐含层输出维度是10当前设定隐含节点数为10可根据任务调整 self.classifier nn.Sequential(nn.Linear(in_features784, out_features256),nn.Sigmoid(),nn.Linear(in_features256, out_features64),nn.Sigmoid())# 定义一层全连接输出层输出维度是1 self.head nn.Linear(in_features64, out_features10) def forward(self, x): # x.shape: [bath size, 1, 28, 28]x paddle.flatten(x, start_axis1) # [bath size, 784]x self.classifier(x) y self.head(x)return y我们看到在 forward 函数中我们首先需要将图片展平为一维向量之后再输入特征提取层classifier但这样会存在如下两个问题 输入数据的空间信息被丢失。 空间上相邻的像素点往往具有相似的 RGB 值RGB 的各个通道之间的数据通常密切相关但是转化成 1 维向量时这些信息被丢失。同时图像数据的形状信息中可能隐藏着某种本质的模式但是转变成 1 维向量输入全连接神经网络时这些模式也会被忽略。 模型参数过多容易发生过拟合。 在手写数字识别案例中每个像素点都要跟所有输出的神经元相连接。当图片尺寸变大时输入神经元的个数会按图片尺寸的平方增大导致模型参数过多容易发生过拟合。 为了解决上述问题我们引入卷积神经网络CNN进行特征提取代码如下 # 多层卷积神经网络实现 class MNIST_CNN_Model(nn.Layer):def __init__(self):super(MNIST_CNN_Model, self).__init__()self.classifier nn.Sequential(nn.Conv2D( in_channels1, out_channels20, kernel_size5, stride1, padding2),nn.ReLU(),nn.MaxPool2D(kernel_size2, stride2),nn.Conv2D(in_channels20, out_channels20, kernel_size5, stride1, padding2),nn.ReLU(),nn.MaxPool2D(kernel_size2, stride2))self.head nn.Linear(in_features980, out_featuresargs.num_classes)def forward(self, x):# x.shape: [10, 1, 28, 28]x self.classifier(x) # [bath size, 20, 7, 7]x x.flatten(1) # [batch size, 980]x self.head(x) # [batch size, num_classes]return x我们发现CNN 网络不需要先对图片进行展平操作可以直接对图片进行特征提取。这样做既能提取到相邻像素点之间的特征模式又能保证参数的个数不随图片尺寸变化。下图是一个典型的卷积神经网络结构多层卷积和池化层组合作用在输入图片上在网络的最后通常会加入一系列全连接层ReLU 激活函数一般加在卷积或者全连接层的输出上网络中通常还会加入 Dropout 来防止过拟合。 还需要说明的一点就是在 CNN 中计算范围是在像素点的空间邻域内进行的卷积核参数的数目也远小于全连接层。卷积核本身与输入图片大小无关它代表了对空间邻域内某种特征模式的提取。比如有些卷积核提取物体边缘特征有些卷积核提取物体拐角处的特征图像上不同区域共享同一个卷积核。当输入图片大小不一样时仍然可以使用同一个卷积核进行操作。 3. 卷积Convolution 这一小节将介绍卷积算法的原理和实现方案并通过具体的案例展示如何使用卷积对图片进行操作主要涵盖如下内容 卷积计算填充padding步幅stride感受野Receptive Field多输入通道、多输出通道和批量操作飞桨卷积 API 介绍卷积算子应用举例 3.1 卷积计算 卷积是数学分析中的一种积分变换的方法在图像处理中采用的是卷积的离散形式。这里需要说明的是在卷积神经网络中卷积层的实现方式实际上是数学中定义的互相关 Cross-Correlation运算与数学分析中的卷积定义有所不同这里跟其他框架和卷积神经网络的教程保持一致都使用互相关运算作为卷积的定义具体的计算过程如下图所示。 互相关cross-correlation是一种在信号处理和图像处理中常用的操作用于衡量两个信号之间的相似性。在数学上互相关表示两个函数之间的一种比较通常用来找出一个信号中的某种模式在另一个信号中的位置。 给定两个离散信号 (x) 和 (y)它们的互相关可以通过以下公式来计算 ( x ⋆ y ) [ n ] ∑ m − ∞ ∞ x [ m ] ⋅ y [ n − m ] (x \star y)[n] \sum_{m-\infty}^{\infty} x[m] \cdot y[n-m] (x⋆y)[n]m−∞∑∞​x[m]⋅y[n−m] 其中 ( x [ m ] ) (x[m]) (x[m]) 和 ( y [ n − m ] ) (y[n-m]) (y[n−m]) 分别是信号 ( x ) (x) (x) 和 ( y ) (y) (y) 在不同位置上的取值 ( n ) (n) (n) 是结果信号的索引。 互相关的计算过程可以理解为将一个信号 ( x ) (x) (x) 在时间上滑动与另一个信号 ( y ) (y) (y) 进行点乘 ⋅ \cdot ⋅ 并求和 ∑ \sum ∑得到一个新的信号表示在不同位置上两个信号的相似程度。如果在某个位置上两个信号的形状相似那么互相关结果的值会较大。 在图像处理中互相关可以用来在一个图像中寻找另一个图像的匹配模式。在深度学习中卷积操作实际上就是互相关的一种形式用来在图像中提取特征。 说明 卷积核kernel也被叫做滤波器filter假设卷积核的高和宽分别为 k h k_h kh​ 和 k w k_w kw​则将称为 k h × k w k_h \times k_w kh​×kw​ 卷积比如 3 × 5 3×5 3×5卷积就是指卷积核的高为 3, 宽为 5。在卷积神经网络中一个卷积算子除了上面描述的卷积过程之外还包括加上偏置项的操作。例如假设偏置为 1则上面卷积计算的结果为 0 × 1 1 × 2 2 × 4 3 × 5 1 26 0 × 2 1 × 3 2 × 5 3 × 6 1 32 0 × 4 1 × 5 2 × 7 3 × 8 1 44 0 × 5 1 × 6 2 × 8 3 × 9 1 50 0 × 1 1 × 2 2 × 4 3×5 1 26 \\ 0 ×2 1 × 3 2 × 5 3×6 1 32\\ 0×4 1×5 2×7 3×8 144\\ 0×5 1×6 2 × 8 3 × 9 1 50 0×11×22×43×51260×21×32×53×61320×41×52×73×81440×51×62×83×9150 3.2 填充Padding 在上面的例子中输入图片尺寸为 3 × 3 3×3 3×3输出图片尺寸为 2 × 2 2×2 2×2经过一次卷积之后图片尺寸变小。卷积输出特征图的尺寸计算方法如下卷积核的高和宽分别为 k h k_h kh​ 和 k w k_w kw​ H o u t H − k h 1 W o u t W − k w 1 H_{\mathrm{out}} H - k_h 1\\ W_{\mathrm{out}} W - k_w 1 Hout​H−kh​1Wout​W−kw​1 如果输入尺寸为 4卷积核大小为 3 时输出尺寸为 4 − 3 1 2 4−312 4−312。我们可以自行检查当输入图片和卷积核为其他尺寸时上述计算式是否成立。当卷积核尺寸大于 1 时输出特征图的尺寸会小于输入图片尺寸。如果经过多次卷积输出图片尺寸会不断减小。为了避免卷积之后图片尺寸变小通常会在图片的外围进行填充(padding)如下图所示。 如上图所示 填充的大小为 1填充值为 0。填充之后输入图片尺寸从 4 × 4 4×4 4×4 变成了 6 × 6 6×6 6×6使用 3 × 3 3×3 3×3 的卷积核输出图片尺寸为 4 × 4 4×4 4×4。填充的大小为 2填充值为 0。填充之后输入图片尺寸从 4 × 4 4×4 4×4 变成了 8 × 8 8×8 8×8使用 3 × 3 3×3 3×3 的卷积核输出图片尺寸为 6 × 6 6×6 6×6。 如果在图片高度方向在第一行之前填充 p h 1 p_{h1} ph1​ 行在最后一行之后填充 p h 2 p_{h2} ph2​ 行在图片的宽度方向在第 1 列之前填充 p w 1 p_{w1} pw1​ 列在最后 1 列之后填充 p w 2 p_{w2} pw2​ 列则填充之后的图片尺寸为 ( H p h 1 p h 2 ) × ( W p w 1 p w 2 ) (H p_{h1} p_{h2}) \times (W p_{w1} p_{w2}) (Hph1​ph2​)×(Wpw1​pw2​)。经过大小为 k h × k w k_h \times k_w kh​×kw​ 的卷积核操作之后输出图片的尺寸为 H o u t H p h 1 p h 2 − k h 1 W o u t W p w 1 p w 2 − k w 1 H_{\mathrm{out}} H p_{h1} p_{h_2} - k_h 1\\ W_{\mathrm{out}} W p_{w1} p_{w_2} - k_w 1 Hout​Hph1​ph2​​−kh​1Wout​Wpw1​pw2​​−kw​1 在卷积计算过程中通常会在高度或者宽度的两侧采取等量填充即 p h 1 p h 2 p h p_{h1} p_{h2} p_h ph1​ph2​ph​ p w 1 p w 2 p w p_{w1} p_{w2} p_w pw1​pw2​pw​上面计算公式也就变为 H o u t H 2 p h − k h 1 W o u t W 2 p w − k w 1 H_{\mathrm{out}} H 2p_h - k_h 1\\ W_{\mathrm{out}} W 2p_w - k_w 1 Hout​H2ph​−kh​1Wout​W2pw​−kw​1 卷积核大小通常使用 { 1 3 5 7 } \{1357\} {1357} 这样的奇数如果使用的填充大小为 p h ( k h − 1 ) / 2 p_{h} (k_h - 1) / 2 ph​(kh​−1)/2 p w ( k w − 1 ) / 2 p_w (k_w - 1) / 2 pw​(kw​−1)/2则卷积之后图像尺寸不变。例如当卷积核大小为 3 时padding 大小为 1卷积之后图像尺寸不变同理如果卷积核大小为 5padding 大小为 2也能保持图像尺寸不变。 3.3 步幅 / 步长Stride 上面那张图中卷积核每次滑动一个像素点这是步幅为 1 的特殊情况。下图是步幅为 2 的卷积过程卷积核在图片上移动时每次移动大小为 2 个像素点。 当宽和高方向的步幅分别为 s h s_h sh​ 和 s w s_w sw​ 时输出特征图尺寸的计算公式是 H o u t H 2 p h − k h s h 1 W o u t W 2 p w − k w s w 1 H_{\mathrm{out}} \frac{H 2p_h - k_h}{s_h} 1\\ W_{\mathrm{out}} \frac{W 2p_w - k_w}{s_w} 1 Hout​sh​H2ph​−kh​​1Wout​sw​W2pw​−kw​​1 假设输入图片尺寸是 H × W 100 × 100 H×W100×100 H×W100×100卷积核大小 k h × k w 3 × 3 k_h \times k_w 3×3 kh​×kw​3×3填充 p h p w 1 p_h p_w 1 ph​pw​1步幅为 s h s w 2 s_h s_w 2 sh​sw​2则输出特征图的尺寸为 H o u t 100 2 − 3 2 1 50 W o u t 100 2 − 3 2 1 50 H_{\mathrm{out}} \frac{100 2 - 3}{2} 1 50\\ W_{\mathrm{out}} \frac{100 2 - 3}{2} 1 50 Hout​21002−3​150Wout​21002−3​150 3.4 感受野Receptive Field 输出特征图上每个点的数值是由输入图片上大小为 k h × k w k_h \times k_w kh​×kw​ 的区域的元素与卷积核每个元素相乘再相加得到的所以输入图像上 k h × k w k_h \times k_w kh​×kw​ 区域内每个元素数值的改变都会影响输出点的像素值。我们将输入图像Input的这个区域叫做输出特征图上对应点的感受野。 切记感受野一般都是说输入图片 感受野内每个元素数值的变动都会影响输出点的数值变化。比如 3 × 3 3×3 3×3 卷积对应的感受野大小就是 3 × 3 3×3 3×3如下图所示。 而当通过两层 3 × 3 3×3 3×3 的卷积之后感受野的大小将会增加到 5 × 5 5×5 5×5如下图所示。 因此当增加卷积网络深度的同时感受野将会增大输出特征图中的一个像素点将会包含更多的图像语义信息。 随着网络的加深特征图的会越来越小那么感受野也会越来越大。就拿上面这个图举例子输出特征图 2 的感受野为 5 × 5 5 \times 5 5×5意思就是说输出特征图 2 上的一点包含、融合了原始输入图片上 5 × 5 5 \times 5 5×5 个像素点因此就具有了一定的语义信息。随着网络层数的加深特征图尺寸越来越小它的语义信息就越来越丰富也就具有了高级语义信息。 3.5 多输入通道、多输出通道和批量操作 前面介绍的卷积计算过程比较简单实际应用时处理的问题要复杂的多。例如对于彩色图片有 RGB 三个通道需要处理多输入通道的场景。输出特征图往往也会具有多个通道而且在神经网络的计算中常常是把一个批次的样本放在一起计算所以卷积算子需要具有批量处理多输入和多输出通道数据的功能下面将分别介绍这几种场景的操作方式。 3.5.1 多输入通道场景 上面的例子中卷积层的数据是一个 2 维数组但实际上一张图片往往含有 RGB 三个通道要计算卷积的输出结果卷积核的形式也会发生变化。假设输入图片的通道数为 C i n C_{in} Cin​输入数据的形状是 C i n × H i n × W i n C_{in} × H_{in} \times W_{in} Cin​×Hin​×Win​计算过程如下图所示。 对每个通道分别设计一个 2 维数组作为卷积核卷积核数组的形状是 c i n × k h × k w c_{in} \times k_h \times k_w cin​×kh​×kw​。对任一通道 c i n ∈ [ 0 , C i n ) c_{in} \in [0, C_{in}) cin​∈[0,Cin​)分别用大小为 k h × k w k_h \times k_w kh​×kw​ 的卷积核在大小为 H i n × W i n H_{in} \times W_{in} Hin​×Win​ 的二维数组上做卷积。将这 C i n C_{in} Cin​ 个通道的计算结果相加得到的是一个形状为 H o u t × W o u t H_{out} \times W_{out} Hout​×Wout​ 的二维数组。 3.5.2 多输出通道场景 一般来说卷积操作的输出特征图也会具有多个通道 C o u t C_{out} Cout​这时我们需要设计 C o u t C_{out} Cout​ 个维度为 C i n × k h × h w C_{in} \times k_h \times h_w Cin​×kh​×hw​ 的卷积核卷积核数组的维度是 C o u t C_{out} Cout​如下图所示。 对任一输出通道 c o u t ∈ [ 0 , C o u t ) c_{out} \in [0, C_{out}) cout​∈[0,Cout​)分别使用上面描述的形状为 C i n × k h × k w C_{in} \times k_h \times k_w Cin​×kh​×kw​ 的卷积核对输入图片做卷积。将这 C o u t C_{out} Cout​ 个形状为 H o u t × W o u t H_{out} \times W_{out} Hout​×Wout​ 的二维数组拼接在一起形成维度为 C o u t × H o u t × W o u t C_{out} \times H_{out} \times W_{out} Cout​×Hout​×Wout​ 的三维数组。 注意❗️通常将卷积核的输出通道数叫做卷积核的个数。 3.5.3 批量操作Batch 在卷积神经网络的计算中通常将多个样本放在一起形成一个 mini-batch 进行批量操作即输入数据的维度是 N × C i n × H i n × W i n N \times C_{in} \times H_{in} \times W_{in} N×Cin​×Hin​×Win​。由于会对每张图片使用同样的卷积核进行卷积操作卷积核的维度与上面多输出通道的情况一样仍然是 C o u t × H o u t × W o u t C_{out} \times H_{out} \times W_{out} Cout​×Hout​×Wout​输出特征图的维度是 N × C o u t × H o u t × W o u t N \times C_{out} \times H_{out} \times W_{out} N×Cout​×Hout​×Wout​如下图所示。 3.6 PaddlePaddle 卷积的 API 介绍 飞桨卷积算子对应的 API 是 paddle.nn.Conv2D用户可以直接调用 API 进行计算也可以在此基础上修改。Conv2D 名称中的 “2D” 表明卷积核是二维的多用于处理图像数据。类似的也有 Conv3D 可以用于处理视频数据图像的序列。 需要注意的是在 PyTorch 中卷积的 API 为torch.nn.Conv2d其中维度 D 是小写的。 class paddle.nn.Conv2D (in_channels, out_channels, kernel_size, stride1, padding0, dilation1, groups1, padding_mode‘zeros’, weight_attrNone, bias_attrNone, data_format‘NCHW’)常用的参数如下 in_channels (int)输入图像的通道数。out_channels (int)卷积核的个数和输出特征图通道数相同相当于上文中的 C o u t C_{out} Cout​。kernel_size (int | list | tuple)卷积核大小可以是整数比如 3表示卷积核的高和宽均为 3 或者是两个整数的 list例如 [3,2]表示卷积核的高为 3宽为 2。stride (int | list | tuple可选)步长大小可以是整数默认值为 1表示垂直和水平滑动步幅均为 1或者是两个整数的 list例如 [3,2]表示垂直滑动步幅为 3水平滑动步幅为 2。padding (int | list | tuple可选)填充大小可以是整数比如 1表示竖直和水平边界填充大小均为 1或者是两个整数的 list例如 [2,1]表示竖直边界填充大小为 2水平边界填充大小为 1。 使用元素对 kernel_size 进行赋值时也是遵循 先 H 后 W 的。 形状总结 输入数据维度 [ N , C i n , H i n , W i n ] [N, C_{in}, H_{in}, W_{in}] [N,Cin​,Hin​,Win​]输出数据维度 [ N , C o u t , H o u t , W o u t ] [N, C_{out}, H_{out}, W_{out}] [N,Cout​,Hout​,Wout​]权重参数 w w w卷积核参数 w w w [ o u t _ c h a n n e l s , C i n , f i l t e r _ s i z e _ h , f i l t e r _ s i z e _ w ] [\mathrm{out\_channels}, C_{in}, \mathrm{filter\_size\_h}, \mathrm{filter\_size\_w}] [out_channels,Cin​,filter_size_h,filter_size_w]偏置参数 b b b [ o u t _ c h a n n e l s , ] [\mathrm{out\_channels}, ] [out_channels,] 注意❗️即使输入只有一张灰度图片 [ H i n , W i n ] [H_{in}, W_{in}] [Hin​,Win​]也需要处理成四个维度的输入向量 [ 1 , 1 , H i n , W i n ] [1, 1, H_{in}, W_{in}] [1,1,Hin​,Win​]。 3.7 卷积算子 paddle.nn.Conv2D 应用举例 下面介绍卷积算子 paddle.nn.Conv2D 在图片中应用的三个案例并观察其计算结果。 3.7.1 案例 1 —— 简单的黑白边界检测 下面是使用 Conv2D 算子完成一个图像边界检测的任务。图像左边为光亮部分右边为黑暗部分需要检测出光亮跟黑暗的分界处。 设置宽度方向的卷积核参数为 [ 1 , 0 , − 1 ] [1,0,−1] [1,0,−1]此卷积核会将宽度方向间隔为 1 的两个像素点的数值相减。当卷积核在图片上滑动时如果它所覆盖的像素点位于亮度相同的区域则左右间隔为 1 的两个像素点数值的差为 0。只有当卷积核覆盖的像素点有的处于光亮区域有的处在黑暗区域时左右间隔为 1 的两个点像素值的差才不为 0。将此卷积核作用到图片上输出特征图上只有对应黑白分界线的地方像素值才不为 0。具体代码如下所示结果输出在下方的图案中。 import matplotlib.pyplot as plt import numpy as np import paddle import paddle.nn as nn from paddle.nn.initializer import Assignif __name__ __main__:# 创建初始化权重参数 ww np.array([1, 0, -1], dtypefloat32)# 将权重矩阵调整为 卷积核 的样式 - [C_out, c_in, k_h, k_w]w w.reshape(1, 1, 1, 3)# 创建卷积算子设置输出通道数、卷积核大小和初始化权重参数# 创建卷积算子的时候通过参数属性weight_attr指定参数初始化方式conv nn.Conv2D(in_channels1, out_channels1, kernel_size(1, 3), # k_h 1, k_w 3padding0, stride1,weight_attrpaddle.ParamAttr(initializerAssign(valuew)))# 创建输入图片图片左边的像素点取值为1右边的像素点取值为0img np.ones(shape[50, 50], dtypefloat32)img[:, 30:] 0.0# 调整图片尺寸以符合Conv2D的输入要求x img.reshape(1, 1, 50, 50)# 将 ndarray 转换为 tensorx paddle.to_tensor(x)# 使用卷积对输入图片进行特征提取out conv(x)# 将 tensor 转换为 ndarray 以方便我们画图out out.numpy()# 开始画图fig, axes plt.subplots(1, 2, dpi100)axes[0].imshow(img, cmapgray)axes[0].set_title(origin image)axes[1].imshow(np.squeeze(out), cmapgray)axes[1].set_title(convolved image)plt.show()3.7.2 案例 2 —— 图像中物体边缘检测 上面展示的是一个人为构造出来的简单图片使用卷积网络检测图片明暗分界处的示例。对于真实的图片也可以使用合适的卷积核( 3 × 3 3 \times 3 3×3 卷积核的中间值是 8周围一圈的值是 8 个 -1)对其进行操作用来检测物体的外形轮廓观察输出特征图跟原图之间的对应关系如下代码所示 import matplotlib.pyplot as plt import numpy as np import paddle import paddle.nn as nn from paddle.nn.initializer import Assign from PIL import Imageif __name__ __main__:# 创建初始化权重参数 ww np.array([[-1, -1, -1],[-1, 8, -1],[-1, -1, -1]], dtypefloat32) / 8# 将权重矩阵调整为 卷积核 的样式 - [C_out, c_in, k_h, k_w]w w.reshape(1, 1, 3, 3)# 由于输入通道数是3因此需要调整卷积核的通道数与输入图片一致w np.repeat(w, repeats3, axis1) # 沿着通道方向重复3次# 创建卷积算子设置输出通道数、卷积核大小和初始化权重参数# 创建卷积算子的时候通过参数属性weight_attr指定参数初始化方式conv nn.Conv2D(in_channels3, out_channels1, kernel_size(3, 3), # k_h 1, k_w 3padding0, stride1,weight_attrpaddle.ParamAttr(initializerAssign(valuew)))# 读取输入图片img Image.open(Tom_and_Jerry.jpg)# 转换图片格式x np.array(img, dtypefloat32)# 调整图片形状以符合Conv2D的输入要求# [H, W, C] - [C, H, W]x np.transpose(x, [2, 0, 1])# 添加Batch维度x x.reshape(1, 3, img.height, img.width)# 将 ndarray 转换为 tensorx paddle.to_tensor(x)# 使用卷积对输入图片进行特征提取out conv(x)# 将 tensor 转换为 ndarray 以方便我们画图out out.numpy()# 开始画图fig, axes plt.subplots(1, 2, dpi100)axes[0].imshow(img)axes[0].set_title(origin image)axes[1].imshow(np.squeeze(out), cmapgray)axes[1].set_title(convolved image)plt.savefig(应用2.png, dpi300)plt.show()3.7.3 案例 3 —— 图像均值模糊 另外一种比较常见的卷积核 5 × 5 5\times 5 5×5 的卷积核中每个值均为 1是用当前像素跟它邻域内的像素取平均这样可以使图像上噪声比较大的点变得更平滑如下代码所示 import matplotlib.pyplot as plt import numpy as np import paddle import paddle.nn as nn from paddle.nn.initializer import Assign from PIL import Imageif __name__ __main__:# 创建初始化权重参数 ww np.ones([1, 1, 5, 5], dtypefloat32) / 25 # [C_out, c_in, k_h, k_w]# 创建卷积算子设置输出通道数、卷积核大小和初始化权重参数# 创建卷积算子的时候通过参数属性weight_attr指定参数初始化方式conv nn.Conv2D(in_channels1, out_channels1, kernel_size(5, 5), # k_h 1, k_w 3padding0, stride1,weight_attrpaddle.ParamAttr(initializerAssign(valuew)))# 读取输入图片img Image.open(Tom_and_Jerry.jpg).convert(L)# 转换图片格式img np.array(img, dtypefloat32)# 调整图片形状以符合Conv2D的输入要求# [H, W] - [C, H, W]x img.reshape(1, 1, img.shape[0], img.shape[1])# 将 ndarray 转换为 tensorx paddle.to_tensor(x)# 使用卷积对输入图片进行特征提取out conv(x)# 将 tensor 转换为 ndarray 以方便我们画图out out.numpy()# 开始画图fig, axes plt.subplots(1, 2, dpi100)axes[0].imshow(img, cmapgray)axes[0].set_title(origin image)axes[1].imshow(np.squeeze(out), cmapgray)axes[1].set_title(convolved image)plt.savefig(应用3.png, dpi300)plt.show()4. 池化Pooling 池化是使用某一位置的相邻输出的总体统计特征代替网络在该位置的输出其好处是当输入数据做出少量平移时经过池化函数后的大多数输出还能保持不变。比如当识别一张图像是否是人脸时我们需要知道人脸左边有一只眼睛右边也有一只眼睛而不需要知道眼睛的精确位置这时候通过池化某一片区域的像素点来得到总体统计特征会显得很有用。由于池化之后特征图会变得更小如果后面连接的是全连接层能有效的减小神经元的个数节省存储空间并提高计算效率。 如下图所示将一个 2 × 2 2×2 2×2 的区域池化成一个像素点。通常有两种方法平均池化和最大池化。 图a平均池化Average Pooling。这里使用大小为 2 × 2 2×2 2×2 的池化窗口每次移动的步幅为 2对池化窗口覆盖区域内的像素取平均值得到相应的输出特征图的像素值。图b最大池化Max Pooling。对池化窗口覆盖区域内的像素取最大值得到输出特征图的像素值。 当池化窗口在图片上滑动时会得到整张输出特征图。池化窗口的大小称为池化大小用 k h × k w k_h \times k_w kh​×kw​ 表示。在卷积神经网络中用的比较多的是窗口大小为 2 × 2 2×2 2×2步幅为 2 的池化。 与卷积核类似池化窗口在图片上滑动时每次移动的步长称为步幅当宽和高方向的移动大小不一样时分别用 s h × s w s_h \times s_w sh​×sw​ 表示。也可以对需要进行池化的图片进行填充填充方式与卷积类似假设在第一行之前填充 p h 1 p_{h1} ph1​ 行在最后一行后面填充 p h 2 p_{h2} ph2​ 行。在第一列之前填充 p w 1 p_{w1} pw1​ 列在最后一列之后填充 p w 2 p_{w2} pw2​ 列则池化层的输出特征图大小为 H o u t H p h 1 p h 2 − k h s h 1 W o u t W p w 1 p w 2 − k w s w 1 H_{out} \frac{H p_{h1} p_{h2} - k_h}{s_h} 1\\ W_{out} \frac{W p_{w1} p_{w2} - k_w}{s_w} 1 Hout​sh​Hph1​ph2​−kh​​1Wout​sw​Wpw1​pw2​−kw​​1 在卷积神经网络中通常使用 2 × 2 2×2 2×2 大小的池化窗口步幅也使用 2填充为 0则输出特征图的尺寸为 H o u t H 2 W o u t W 2 H_{out} \frac{H}{2}\\ W_{out} \frac{W}{2} Hout​2H​Wout​2W​ 通过这种方式的池化输出特征图的高和宽都减半但通道数不会改变。 5. ReLU激活函数 5.1 Sigmoid 和 ReLU 激活函数对比 前面介绍的网络结构中普遍使用 Sigmoid 函数做激活函数。在神经网络发展的早期Sigmoid 函数用的比较多而目前用的较多的激活函数是 ReLU。这是因为 Sigmoid 函数在反向传播过程中容易造成梯度的衰减。让我们仔细观察 Sigmoid 函数的形式就能发现这一问题。 Sigmoid 激活函数定义如下 y 1 1 e − x y \frac{1}{1 e^{-x}} y1e−x1​ ReLU 激活函数的定义如下 y { 0 , ( x 0 ) x , ( x ≥ 0 ) y \begin{cases} 0, \quad (x 0) \\ x, \quad (x \ge 0) \end{cases} y{0,(x0)x,(x≥0)​ 下面的程序画出了 Sigmoid 和 ReLU 函数的曲线图 import numpy as np import matplotlib.pyplot as plt plt.figure(figsize(10, 5))# 创建数据x x np.arange(-10, 10, 0.1)# 计算Sigmoid函数 s 1.0 / (1 np.exp(0. - x))# 计算ReLU函数 y np.clip(x, a_min0., a_maxNone)# 以下部分为画图代码 f plt.subplot(121) plt.plot(x, s, colorr) currentAxisplt.gca() plt.text(-9.0, 0.9, r$ySigmoid(x)$, fontsize13) currentAxis.xaxis.set_label_text(x, fontsize15) currentAxis.yaxis.set_label_text(y, fontsize15)f plt.subplot(122) plt.plot(x, y, colorg) plt.text(-3.0, 9, r$yReLU(x)$, fontsize13) currentAxisplt.gca() currentAxis.xaxis.set_label_text(x, fontsize15) currentAxis.yaxis.set_label_text(y, fontsize15)plt.savefig(两种激活函数对比.png) plt.show()5.2 梯度消失现象 在神经网络里将经过反向传播之后梯度值衰减到接近于零的现象称作梯度消失现象。 从上面的函数曲线可以看出当 x x x 为较大的正数的时候Sigmoid 函数数值非常接近于 1函数曲线变得很平滑在这些区域 Sigmoid 函数的导数接近于零。当 x x x 为较小的负数时Sigmoid 函数值也非常接近于 0函数曲线也很平滑在这些区域 Sigmoid 函数的导数也接近于 0。只有当 x x x 的取值在 0 附近时Sigmoid 函数的导数才比较大。对 Sigmoid 函数求导数结果如下所示 d y d x − 1 ( 1 e − x ) ⋅ d ( e − x ) d x 1 2 e x e − x \begin{aligned} \frac{dy}{dx} -\frac{1}{(1 e^{-x})} \cdot \frac{d(e^{-x})}{dx}\\ \frac{1}{2 e^x e^{-x}} \end{aligned} dxdy​​−(1e−x)1​⋅dxd(e−x)​2exe−x1​​ 从上面的式子可以看出Sigmoid 函数的导数 d y d x \frac{dy}{dx} dxdy​ 最大值为 1 4 \frac{1}{4} 41​ 。前向传播时 y S i g m o i d ( x ) y\mathrm{Sigmoid}(x) ySigmoid(x)而在反向传播过程中 x x x 的梯度等于 y y y 的梯度乘以 Sigmoid 函数的导数如下所示 ∂ L ∂ x ∂ L ∂ y ⋅ ∂ y ∂ x \frac{\partial L}{\partial x} \frac{\partial L}{\partial y} \cdot \frac{\partial y}{\partial x} ∂x∂L​∂y∂L​⋅∂x∂y​ 使得 x x x 的梯度数值最大也不会超过 y y y 的梯度的 1 4 \frac{1}{4} 41​。 由于最开始是将神经网络的参数随机初始化的 x x x 的取值很有可能在很大或者很小的区域这些地方都可能造成 Sigmoid 函数的导数接近于 0导致 x x x 的梯度接近于 0即使 x x x 取值在接近于 0 的地方按上面的分析经过 Sigmoid 函数反向传播之后 x x x的梯度不超过 y y y 的梯度的 1 4 \frac{1}{4} 41​如果有多层网络使用了 Sigmoid 激活函数则比较靠后的那些层梯度将衰减到非常小的值。 ReLU 函数则不同虽然在 x 0 x0 x0 的地方ReLU 函数的导数为 0。但是在 x ≥ 0 x≥0 x≥0 的地方ReLU 函数的导数为 1能够将 y y y 的梯度完整的传递给 x x x而不会引起梯度消失。 6. 批归一化Batch Normalization 批归一化方法Batch NormalizationBatchNorm是由 Ioffe 和 Szegedy 于 2015 年提出的已被广泛应用在深度学习中其目的是对神经网络中间层的输出进行标准化处理使得中间层的输出更加稳定。 通常我们会对神经网络的数据进行标准化处理处理后的样本数据集满足均值 μ \mu μ 为 0方差 σ \sigma σ 为1的统计分布这是因为当输入数据的分布比较固定时有利于算法的稳定和收敛。对于深度神经网络来说由于参数是不断更新的即使输入数据已经做过标准化处理但是对于比较靠后的那些层其接收到的输入仍然是剧烈变化的通常会导致数值不稳定模型很难收敛。BatchNorm 能够使神经网络中间层的输出变得更加稳定并有如下三个优点 使学习快速进行能够使用较大的学习率降低模型对初始值的敏感性从一定程度上抑制过拟合 BatchNorm 主要思路是在训练时以 mini-batch 为单位对神经元的数值进行归一化使数据的分布满足均值 μ \mu μ 为 0方差 σ \sigma σ 为1。具体计算过程如下 6.1 第一步计算 mini-batch 内样本的均值 μ B \mu_B μB​ μ B ← 1 m ∑ i 1 m x ( i ) \mu_B \leftarrow \frac{1}{m} \sum_{i1}^m x^{(i)} μB​←m1​i1∑m​x(i) 其中 x ( i ) x^{(i)} x(i) 表示 mini-batch中的第 i i i 个样本。 例如输入 mini-batch 包含 3 个样本每个样本有 2 个特征分别是 x ( 1 ) ( 1 , 2 ) , x ( 2 ) ( 3 , 6 ) , x ( 3 ) ( 5 , 10 ) x^{(1)} (1, 2), \quad x^{(2)} (3, 6), \quad x^{(3)} (5, 10) x(1)(1,2),x(2)(3,6),x(3)(5,10) 对每个特征分别计算 mini-batch 内样本的均值 μ B 0 1 3 5 3 3 , μ B 1 2 6 10 3 6 \mu_{B0} \frac{135}{3}3, \quad \mu_{B1} \frac{2610}{3}6 μB0​3135​3,μB1​32610​6 则样本均值是 μ B ( μ B 0 , μ B 1 ) ( 3 , 6 ) \mu_{B} (\mu_{B0}, \mu_{B1}) (3, 6) μB​(μB0​,μB1​)(3,6) 求均值是按特征维度进行的 6.2 第二步计算 mini-batch 内样本的方差 σ B 2 \sigma_B^2 σB2​ σ B 2 ← 1 m ∑ i 1 m ( x ( i ) − μ B ) 2 \sigma_B^2 \leftarrow \frac{1}{m} \sum_{i 1}^m (x^{(i)} - \mu_B)^2 σB2​←m1​i1∑m​(x(i)−μB​)2 上面的计算公式先计算一个批次内样本的均值 μ B \mu_B μB​ 和方差 σ B 2 \sigma_B^2 σB2​然后再对输入数据做归一化将其调整成均值为 0方差为 1 的分布。 对于上述给定的输入数据 x ( 1 ) , x ( 2 ) , x ( 3 ) x^{(1)}, x^{(2)}, x^{(3)} x(1),x(2),x(3)可以计算出每个特征对应的方差 σ B 0 2 1 3 ⋅ [ ( 1 − 3 ) 2 ( 3 − 3 ) 2 ( 5 − 3 ) 2 ] 8 3 σ B 1 2 1 3 ⋅ [ ( 2 − 6 ) 2 ( 6 − 6 ) 2 ( 10 − 6 ) 2 ] 32 3 \sigma_{B0}^2 \frac{1}{3} \cdot \left[(1-3)^2 (3-3)^2 (5-3)^2 \right] \frac{8}{3}\\ \sigma_{B1}^2 \frac{1}{3} \cdot \left[ (2-6)^2 (6-6)^2 (10-6)^2 \right] \frac{32}{3} σB02​31​⋅[(1−3)2(3−3)2(5−3)2]38​σB12​31​⋅[(2−6)2(6−6)2(10−6)2]332​ 则样本方差是 σ B 2 ( σ B 0 2 , σ B 1 2 ) ( 8 3 , 32 3 ) \sigma_{B}^2 (\sigma_{B0}^2, \sigma_{B1}^2) (\frac{8}{3}, \frac{32}{3}) σB2​(σB02​,σB12​)(38​,332​) 求方差也是按特征维度进行的 6.3 计算标准化之后的输出 x ^ ( i ) \hat{x}^{(i)} x^(i) x ^ ( i ) ← x ( i ) − μ B ( σ B 2 ϵ ) \hat{x}^{(i)} \leftarrow \frac{x^{(i)} - \mu_B}{\sqrt{(\sigma_B^2 \epsilon)}} x^(i)←(σB2​ϵ) ​x(i)−μB​​ 其中 ϵ \epsilon ϵ 是一个微小值例如 1e−7其主要作用是为了防止分母为 0。 对于上述给定的输入数据 x ( 1 ) , x ( 2 ) , x ( 3 ) x^{(1)}, x^{(2)}, x^{(3)} x(1),x(2),x(3)可以计算出标准化之后的输出 x ^ ( 1 ) ( 1 − 3 8 3 , 2 − 6 32 3 ) ( − 3 2 , − 3 2 ) x ^ ( 2 ) ( 3 − 3 8 3 , 6 − 6 32 3 ) ( 0 , 0 ) x ^ ( 3 ) ( 5 − 3 8 3 , 10 − 6 32 3 ) ( 3 2 , 3 2 ) \begin{aligned} \hat{x}^{(1)} \left( \frac{1 - 3}{\sqrt{\frac{8}{3}}}, \frac{2 - 6}{\sqrt{\frac{32}{3}}} \right) \left( -\sqrt{\frac{3}{2}}, -\sqrt{\frac{3}{2}} \right) \\ \hat{x}^{(2)} \left( \frac{3 - 3}{\sqrt{\frac{8}{3}}}, \frac{6 - 6}{\sqrt{\frac{32}{3}}} \right) \left( 0,0 \right) \\ \hat{x}^{(3)} \left( \frac{5 - 3}{\sqrt{\frac{8}{3}}}, \frac{10 - 6}{\sqrt{\frac{32}{3}}} \right) \left(\sqrt{\frac{3}{2}}, \sqrt{\frac{3}{2}} \right) \end{aligned} ​x^(1) ​38​ ​1−3​,332​ ​2−6​ ​(−23​ ​,−23​ ​)x^(2) ​38​ ​3−3​,332​ ​6−6​ ​(0,0)x^(3) ​38​ ​5−3​,332​ ​10−6​ ​(23​ ​,23​ ​)​ 我们可以验证一下 输入数据 x ( 1 ) , x ( 2 ) , x ( 3 ) x^{(1)}, x^{(2)}, x^{(3)} x(1),x(2),x(3) 是否满足 均值为 0方差为 1 的要求 import numpy as npdef calc_mean_and_var(data):# 计算均值mean np.mean(data, axis0)# 计算方差variance np.var(data, axis0)return mean, variancedef normalization(data, mean, var):return (data - mean) / np.sqrt(var)if __name__ __main__:# 定义输入数据origin_data np.array([[1, 2], [3, 6], [5, 10]])mean, var calc_mean_and_var(origin_data)print([原始数据] 均值, mean)print([原始数据] 方差, var)# 求归一化的数据normalization_data normalization(origin_data, mean, var)print(归一化后的数据\n, normalization_data)# 验证过归一化数据是否符合均值为0方差为1mean_norm, var_norm calc_mean_and_var(normalization_data)print([归一化] 均值, mean_norm)print([归一化] 方差, var_norm)结果 [原始数据] 均值 [3. 6.] [原始数据] 方差 [ 2.66666667 10.66666667] 归一化后的数据[[-1.22474487 -1.22474487][ 0. 0. ][ 1.22474487 1.22474487]] [归一化] 均值 [0. 0.] [归一化] 方差 [1. 1.]如果强行限制输出层的分布是标准化的可能会导致某些特征模式的丢失所以在标准化之后BatchNorm 会紧接着对数据做缩放和平移。 y i ← γ x ^ i β y_i \leftarrow \gamma \hat{x}_i \beta yi​←γx^i​β 其中 γ \gamma γ 和 β \beta β 是可学习的参数可以赋初始值 γ 1 , β 0 \gamma1, \beta0 γ1,β0在训练过程中不断学习调整。 上面列出的是 BatchNorm 方法的计算逻辑下面针对两种类型的输入数据格式分别进行举例。PaddlePaddle 支持输入数据的维度大小为 2、3、4、5 四种情况这里给出的是维度大小为 2 和 4 的示例。 6.4 示例 6.4.1 示例一 当输入数据形状是 [ N , K ] [N, K] [N,K] 时 当输入数据形状是 [ N , K ] [N, K] [N,K] 时一般对应全连接层的输出。这种情况下会分别对 K K K 的每一个分量计算 N N N 个样本的均值和方差数据和参数对应如下 输入Shape x x x [ N , C ] [N, C] [N,C] y y y [ N , C ] [N, C] [N,C]均值 μ B \mu_B μB​ [ C , ] [C, ] [C,]方差 σ B 2 \sigma_B^2 σB2​ [ C , ] [C, ] [C,]缩放参数 γ \gamma γ [ C , ] [C, ] [C,]平移参数 β \beta β [ C , ] [C, ] [C,] 示例代码如下所示 import numpy as np import paddle import paddle.nn as nndef calc_mean_and_var(data):# 计算均值mean np.mean(data, axis0)# 计算方差variance np.var(data, axis0)return mean, varianceif __name__ __main__:# 定义数据data np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]], dtypefloat32) # [N, C]# 使用 BN 计算归一化后的输出bn nn.BatchNorm1D(num_features3) # 参数为通道数x paddle.to_tensor(data)y bn(x).numpy() # [N, C]print(fBN 层的输出为:\n{y}\n其shape为: {y.shape})# 验证mean, var calc_mean_and_var(y)print(fBN 后的均值为: {mean}, 其shape为: {mean.shape}) # [C, ]print(fBN 后的方差为: {var}, 其shape为: {var.shape}) # [C]print(fBN 的缩放参数为: {bn.weight}) # [C, ]print(fBN 的平移参数为: {bn.bias}) # [C, ]BN 层的输出为: [[-1.2247438 -1.2247438 -1.2247438][ 0. 0. 0. ][ 1.2247438 1.2247438 1.2247438]] 其shape为: (3, 3)BN 后的均值为: [0. 0. 0.], 其shape为: (3,) BN 后的方差为: [0.99999833 0.99999833 0.99999833], 其shape为: (3,) BN 的缩放参数为: Parameter containing: Tensor(shape[3], dtypefloat32, placePlace(gpu:0), stop_gradientFalse, [1., 1., 1.]) BN 的平移参数为: Parameter containing: Tensor(shape[3], dtypefloat32, placePlace(gpu:0), stop_gradientFalse, [0., 0., 0.])6.4.1 示例二 当输入数据形状是 [ N , C , H , W ] [N, C, H, W] [N,C,H,W] 时 当输入数据形状是 [ N , C , H , W ] [N, C, H, W] [N,C,H,W] 时 一般对应卷积层的输出这种情况下会沿着 C C C 这一维度进行展开分别对每一个通道计算 N N N 个样本中总共 N × H × W N×H×W N×H×W 个像素点的均值和方差数据和参数对应如下 输入Shape x x x [ N , C , H , W ] [N, C, H, W] [N,C,H,W] y y y [ N , C , H , W ] [N, C, H, W] [N,C,H,W]均值 μ B \mu_B μB​ [ C , ] [C, ] [C,]方差 σ B 2 \sigma_B^2 σB2​ [ C , ] [C, ] [C,]缩放参数 γ \gamma γ [ C , ] [C, ] [C,]平移参数 β \beta β [ C , ] [C, ] [C,] 可能有人会问“BatchNorm 里面不是还要对标准化之后的结果做仿射变换吗怎么使用 Numpy 计算的结果与 BatchNorm 算子一致” 这是因为 BatchNorm 算子里面自动设置初始值 γ 1 , β 0 \gamma1, \beta0 γ1,β0上面代码的结果中我们就可以看到了这时候仿射变换相当于是恒等变换。在训练过程中这两个参数会不断的学习这时仿射变换就会起作用。 示例代码如下所示。 import numpy as np import paddle import paddle.nn as nndef calc_mean_and_var(data):# 计算均值mean np.mean(data, axis0)# 计算方差variance np.var(data, axis0)return mean, varianceif __name__ __main__:paddle.seed(100)np.random.seed(100)# 定义数据data np.random.random((10, 3, 64, 64)).astype(float32) # [N, C, H, W]print(data.shape) # (10, 3, 64, 64)# 使用 BN 计算归一化后的输出bn nn.BatchNorm2D(num_features3) # 参数为通道数x paddle.to_tensor(data)y bn(x).numpy() # [N, C, H, W]print(fBN 层的输出.shape为: {y.shape})print(fBN 层的输出.shape为: {y.shape})mean, var calc_mean_and_var(y)print(fBN 后的均值.shape为: {mean.shape}) # [C, ]print(fBN 后的方差.shape为: {var.shape}) # [C, ]print(fBN 的缩放参数.shape: {bn.weight.shape}) # [C, ]print(fBN 的平移参数为.shape: {bn.bias.shape}) # [C, ]结果 BN 层的输出.shape为: (10, 3, 64, 64) BN 层的输出.shape为: (10, 3, 64, 64) BN 后的均值.shape为: (3, 64, 64) BN 后的方差.shape为: (3, 64, 64) BN 的缩放参数.shape: [3] BN 的平移参数为.shape: [3]提示这里通过 numpy 计算出来的输出与 BatchNorm2D 算子的结果略有差别因为在 BatchNorm2D 算子为了保证数值的稳定性在分母里面加上了一个比较小的浮点数 epsilon1e-05。 6.5 预测时使用BatchNorm 上面介绍了在训练过程中使用 BatchNorm 对一批样本进行归一化的方法但如果使用同样的方法对需要预测的一批样本进行归一化则预测结果会出现不确定性。 例如样本 A、样本 B 作为一批样本计算均值和方差与样本 A、样本 C 和样本 D 作为一批样本计算均值和方差得到的结果一般来说是不同的。那么样本 A 的预测结果就会变得不确定这对预测过程来说是不合理的。解决方法是在训练过程中将大量样本的均值和方差保存下来预测时直接使用保存好的值而不再重新计算。实际上在 BatchNorm 的具体实现中训练时会计算均值和方差的移动平均值。在 PaddlePaddle 中默认是采用如下方式计算 s a v e d _ μ B ← s a v e d _ μ B × 0.9 μ B × ( 1 − 0.9 ) s a v e d _ σ B 2 ← s a v e d _ σ B 2 × 0.9 σ B 2 × ( 1 − 0.9 ) \mathrm{saved\_\mu_B} \leftarrow \mathrm{saved\_\mu_B} \times 0.9 \mu_B \times (1 - 0.9)\\ \mathrm{saved\_\sigma_B^2} \leftarrow \mathrm{saved\_\sigma_B^2} \times 0.9 \sigma_B^2 \times (1 - 0.9) saved_μB​←saved_μB​×0.9μB​×(1−0.9)saved_σB2​←saved_σB2​×0.9σB2​×(1−0.9) 在训练过程的最开始将 s a v e d _ μ B \mathrm{saved}\_\mu_B saved_μB​ 和 s a v e d _ σ B 2 \mathrm{saved\_\sigma_B^2} saved_σB2​ 设置为 0每次输入一批新的样本计算出 μ B \mu_B μB​ 和 σ B 2 \sigma_B^2 σB2​然后通过上面的公式更新 s a v e d _ μ B \mathrm{saved}\_\mu_B saved_μB​ 和 s a v e d _ σ B 2 \mathrm{saved\_\sigma_B^2} saved_σB2​在训练的过程中不断的更新它们的值并作为 BatchNorm 层的参数保存下来。预测的时候将会加载参数 s a v e d _ μ B \mathrm{saved}\_\mu_B saved_μB​ 和 s a v e d _ σ B 2 \mathrm{saved\_\sigma_B^2} saved_σB2​用他们来代替 μ B \mu_B μB​ 和 σ B 2 \sigma_B^2 σB2​。 7. 丢弃法Dropout 丢弃法Dropout是深度学习中一种常用的抑制过拟合的方法其做法是在神经网络学习过程中随机删除一部分神经元。训练时随机选出一部分神经元将其输出设置为 0这些神经元将不对外传递信号。 下图是 Dropout 示意图左边是完整的神经网络右边是应用了 Dropout 之后的网络结构。应用 Dropout 之后会将标了 × \times × 的神经元从网络中删除让它们不向后面的层传递信号。在学习过程中丢弃哪些神经元是随机决定因此模型不会过度依赖某些神经元能一定程度上抑制过拟合。 Q1Dropout 操作是对输入特征图进行的吗 A1是的Dropout 操作是对输入特征图进行的。 Q2如果是一张图片送入网络那么 Dropout 会怎么丢弃呢丢弃像素点 A2是的当一张图片作为输入送入神经网络时Dropout 操作会随机丢弃一部分像素点。具体来说Dropout 会在每次前向传播过程中独立地随机选择一些像素点并将它们设置为零从而“关闭”这些像素点对应的信息。这个过程相当于对输入图片进行了遮挡模拟了一些像素信息丢失的情况。 请注意❗️Dropout 一般应用在特征图上具体来说就是将特征图某些像素点设置为 0。 在预测场景时会向前传递所有神经元的信号可能会引出一个新的问题训练时由于部分神经元被随机丢弃了输出数据的总大小会变小。比如计算其 L 1 L_1 L1​ 范数会比不使用 Dropout 时变小但是预测时却没有丢弃神经元这将导致训练和预测时数据的分布不一样。为了解决这个问题PaddlePaddle 支持如下两种方法 downscale_in_infer训练时以比例 r r r 随机丢弃一部分神经元不向后传递它们的信号预测时向后传递所有神经元的信号但是将每个神经元上的数值乘以 ( 1 − r ) (1−r) (1−r)。upscale_in_train训练时以比例 r r r 随机丢弃一部分神经元不向后传递它们的信号但是将那些被保留的神经元上的数值除以 ( 1 − r ) (1−r) (1−r)预测时向后传递所有神经元的信号不做任何处理。 在 PaddlePaddle Dropout API中通过 mode 参数来指定用哪种方式对神经元进行操作 paddle.nn.Dropout(p0.5, axisNone, modeupscale_in_train”, nameNone)主要参数如下 p (float) 将输入节点置为 0 的概率即丢弃概率默认值0.5。该参数对元素的丢弃概率是针对于每一个元素而言而不是对所有的元素而言。举例说假设矩阵内有 12 个数字经过概率为 0.5 的 dropout 未必一定有 6 个零。mode (str) 丢弃法的实现方式有 ’downscale_in_infer’ 和 ’upscale_in_train’ 两种默认是 ’upscale_in_train’。 不同框架对于 Dropout 的默认处理方式可能不同在使用时可以查看 API 详细了解。 下面这段程序展示了经过 Dropout 之后输出数据的形式。 import paddle import paddle.nn as nn import numpy as npif __name__ __main__:np.random.seed(100)# 创建数据data_1 np.random.rand(1, 3, 2, 2).astype(float32) # [N, C, H, W]data_2 np.arange(1, 13).reshape([-1, 3]).astype(float32) # [N, C]# 使用dropout作用到输入数据上x_1 paddle.to_tensor(data_1)x_2 paddle.to_tensor(data_2)方式1downgrade_in_infer模式下drop_method_1 nn.Dropout(p0.5, modedownscale_in_infer)droped_train_11 drop_method_1(x_1)droped_train_12 drop_method_1(x_1)# 切换到eval模式。在动态图模式下使用eval()切换到求值模式该模式禁用了dropoutdrop_method_1.eval()drop_11_eval_11 drop_method_1(x_1)drop_12_eval_12 drop_method_1(x_1)方式2upscale_in_train模式下drop_method_2 nn.Dropout(p0.5, modeupscale_in_train)droped_train_21 drop_method_2(x_2)droped_train_22 drop_method_2(x_2)# 切换到eval模式。在动态图模式下使用eval()切换到求值模式该模式禁用了dropoutdrop_method_2.eval()drop_21_eval_21 drop_method_2(x_2)drop_22_eval_22 drop_method_2(x_2)# 输出print(x1 {}, \n\n droped_train_11 \n\n {}, \n\n drop_11_eval_11 \n {}\n\n.format(data_1, droped_train_11.numpy(), drop_11_eval_11.numpy()))print(x1 {}, \n\n droped_train_12 \n\n {}, \n\n drop_12_eval_12 \n {}\n\n.format(data_1, droped_train_12.numpy(), drop_12_eval_12.numpy()))print(x2 {}, \n\n droped_train_21 \n\n {}, \n\n drop_21_eval_21 \n {}\n\n.format(data_2, droped_train_21.numpy(), drop_21_eval_21.numpy()))print(x2 {}, \n\n droped_train_22 \n\n {}, \n\n drop_22_eval_22 \n {}\n\n.format(data_2, droped_train_22.numpy(), drop_22_eval_22.numpy()))结果 x1 [[[[0.54340494 0.2783694 ][0.4245176 0.84477615]][[0.00471886 0.12156912][0.67074907 0.82585275]][[0.13670659 0.5750933 ][0.89132196 0.20920213]]]],droped_train_11[[[[0.54340494 0.2783694 ][0.4245176 0. ]][[0.00471886 0. ][0.67074907 0. ]][[0.13670659 0.5750933 ][0. 0.20920213]]]],drop_11_eval_11[[[[0.27170247 0.1391847 ][0.2122588 0.42238808]][[0.00235943 0.06078456][0.33537453 0.41292638]][[0.0683533 0.28754666][0.44566098 0.10460106]]]]x1 [[[[0.54340494 0.2783694 ][0.4245176 0.84477615]][[0.00471886 0.12156912][0.67074907 0.82585275]][[0.13670659 0.5750933 ][0.89132196 0.20920213]]]],droped_train_12[[[[0. 0. ][0.4245176 0.84477615]][[0.00471886 0.12156912][0.67074907 0. ]][[0.13670659 0.5750933 ][0. 0. ]]]],drop_12_eval_12[[[[0.27170247 0.1391847 ][0.2122588 0.42238808]][[0.00235943 0.06078456][0.33537453 0.41292638]][[0.0683533 0.28754666][0.44566098 0.10460106]]]]x2 [[ 1. 2. 3.][ 4. 5. 6.][ 7. 8. 9.][10. 11. 12.]],droped_train_21[[ 0. 0. 0.][ 0. 10. 0.][14. 0. 18.][20. 0. 0.]],drop_21_eval_21[[ 1. 2. 3.][ 4. 5. 6.][ 7. 8. 9.][10. 11. 12.]]x2 [[ 1. 2. 3.][ 4. 5. 6.][ 7. 8. 9.][10. 11. 12.]],droped_train_22[[ 2. 0. 6.][ 0. 0. 12.][ 0. 0. 0.][20. 22. 0.]],drop_22_eval_22[[ 1. 2. 3.][ 4. 5. 6.][ 7. 8. 9.][10. 11. 12.]]从上述代码的输出可以发现经过 dropout 之后tensor 中的某些元素变为了 0这个就是 dropout 实现的功能通过随机将输入数据的元素置 0消除减弱了神经元节点间的联合适应性增强模型的泛化能力。 知识来源 https://www.paddlepaddle.org.cn/tutorials/projectdetail/4282406
http://www.dnsts.com.cn/news/79932.html

相关文章:

  • wordpress 建站教程手机网站开发解决方案
  • 网站备案值得吗许昌网站建设费用
  • 后缀是.cc的网站百度统计手机版
  • 建站工具帝国ps制作网站产品图片
  • 做网站需要多长时间才能做好浏览器网页版入口
  • 网站面包屑导航设计即位置导航购物网站备案
  • SOHO英文网站制作乌兰察布市建设局网站
  • 网站颜色正确搭配实例wordpress 5.2.2
  • 黄山网站设计公司做网站的首页下拉列表
  • 成都网站建设 Vr为什么网站开发需要写php
  • 阳网站建设怎样拍照产品做网站
  • 网页制作建立站点电脑网页打不开是什么原因
  • 天津网站开发平台水果网页设计模板图片
  • 武安做网站建网站 开发app
  • 网站建设 经验温州网站外包
  • 网站服务器价格表创网站 灵感
  • 济南网站设计公司推荐百度网页安全警告怎么解除
  • 如何用服务器代替空间做网站富平网站建设
  • 找工程做在哪个网站?广州佛山旅居人员
  • 科技部网站建设合同中国中铁建设集团门户网
  • 外贸soho通过网站开发客户天津网站建设定制公司
  • 大学做网站有哪些网站建设网页设计培训班
  • wordpress企业站模板楚雄市住房和城乡建设局门户网站
  • 云南城市建设职业学院spoc网站信阳做网站汉狮网络
  • 唐山的网站建设公司网站建设与管理 十四五国规教材
  • 阿联酋网站后缀html代码有哪些
  • 简单设置网站首页上海建网站
  • 做网站怎么移动图片wordpress内存耗尽
  • 免费php企业网站小程序源码网免费下载
  • 营销网站建设都是专业技术人员吗怎么推广游戏代理赚钱