resnet50作者(resnet50原理)

resnet50作者(resnet50原理)p br p p 假设你现在是个人工智能知识小白 如果让你设计一个可以识别图片的神经网络 你会怎么做 p p 我之前问过自己这个问题 思来想去 我的答案是 p

大家好,我是讯享网,很高兴认识大家。




讯享网

<p><br /></p> <p>假设你现在是个人工智能知识小白&#xff0c;如果让你设计一个可以识别图片的神经网络&#xff0c;你会怎么做&#xff1f;</p> <p>我之前问过自己这个问题&#xff0c;思来想去&#xff0c;我的答案是&#xff1a;我可能不知道如何下手。</p> <p>突然有一天&#xff0c;当我把Resnet50这个网络中的所有算法都写了一遍之后&#xff0c;我突然发现&#xff0c;只要我深入了解了这些算法背后的原理&#xff0c;或许我也能设计出这个网络出来&#xff08;后知后觉的大话而已&#xff09;。</p> <p>于是&#xff0c;有了这篇文章。</p> <p>接下来&#xff0c;我会从头开始&#xff0c;一步步拆解Resnet50中用到的算法和其背后的原理&#xff0c;聊聊一个图像识别网络到底是怎么工作的。</p> <p>你可能会想&#xff0c;看懂这些需要懂很多专业的知识么&#xff1f;</p> <p>不需要&#xff01;</p> <p>我会尽可能把每一步写的通俗易懂&#xff0c;尽可能让大家了解&#xff0c;一个AI模型&#xff0c;是如何模拟人的眼睛和大脑&#xff0c;来完成一幅图像的识别的。</p> <h5 id="h0">从像素说起</h5> <p>我们先从图像最最基础的——像素&#xff0c;开始说起。</p> <p>要实现图像识别&#xff0c;最离不开的&#xff0c;就是像素。</p> <p>我们都知道&#xff0c;图像是由像素组成的。</p> <p>实际上&#xff0c;神经网络计算&#xff0c;算的并不是很深奥的东西&#xff0c;它计算的&#xff0c;恰恰就是像素之间的关系&#xff0c;以及这些背后隐藏的信息。</p> <p>相机摄像头像素2000万&#xff0c;拍出来的照片比1000万像素的清晰&#xff0c;因此我们更容易看到图片中的物体是什么。</p> <p>这是为什么&#xff1f;因为像素越多&#xff0c;像素之间的关系&#xff08;色彩&#xff0c;轮廓&#xff09;越丰富&#xff0c;我们所能看到的信息就越多&#xff0c;自然而然获取到的信息就多。</p> <p style="text-align:center;"><img src="https://i-blog.csdnimg.cn/blog_migrate/2e8fbe9dbf94e404acd0d80e3a2b93a3.png" alt="Resnet50算法原理_卷积核" style="width: 517px; visibility: visible;" /></p> <p>上图是不同分辨率下的图片对比。1080p的图片&#xff0c;我们可以很容易辨别出图像中的物体是山还是水&#xff0c;这是因为更多的像素会给眼睛更丰富的图片细节。</p> <p>但是&#xff0c;你有没有发现&#xff0c;当我们去看一张图片时&#xff0c;我们绝对不是盯着某一个像素点或某几个像素看&#xff0c;而是看了整个图像的大部分区域&#xff0c;或者说&#xff0c;大部分像素&#xff01;</p> <p>因为只有看到了大部分的图片&#xff0c;才能知道图中是座山。</p> <p>举个不恰当的例子——就像是聚沙成山&#xff01;</p> <p>山之所以是山&#xff0c;是由大量的石头、树木而定义的。绝不是少了一粒沙&#xff0c;山就不是山&#xff0c;多了一粒沙&#xff0c;就变成了山。</p> <p>图片也是如此。</p> <h5 id="h1">像素局部性</h5> <p style="text-align:center;"><img src="https://i-blog.csdnimg.cn/blog_migrate/54fffa9ad76c68ce93d11e7b5065a2a1.png" alt="Resnet50算法原理_人工智能_02" style="width: 453px; visibility: visible;" /></p> <p>上图哆啦A梦&#xff0c;虽然不是很清晰&#xff0c;像素点数很少&#xff0c;但一眼望去&#xff0c;依然可以分清是哆啦A梦&#xff0c;甚至&#xff0c;用手捂住一半的图像&#xff0c;依然可以。</p> <p>这是因为人眼对于图像信息的识别&#xff0c;是建立在对像素局部性分析的基础上的。</p> <p>所谓局部性&#xff0c;通俗点说&#xff0c;就是眼睛或大脑会将相邻的像素或大片的像素连接起来分析&#xff0c;从而组合成嘴巴&#xff0c;然后是耳朵&#xff0c;最后是哆啦A梦。</p> <p>神经网络识别图片大致就是这样的原理&#xff0c;它模拟的&#xff0c;就是人们看到图片之后的信息处理过程。</p> <p>当我们盯着一个图片看时&#xff0c;我们首先会获取到图片的细节特征——比如哆啦A梦红色的大嘴巴。</p> <p>但是如果仅仅盯着大嘴巴&#xff0c;又反而让人有一种“只缘身在此山中”的感觉&#xff0c;看不到图片的全貌。</p> <p>因此还需要再看一下图像的轮廓。于是&#xff0c;我们的眼睛识别一张图片&#xff0c;大致就有了以下两个过程&#xff1a;</p> <ul><li>瞳孔放大&#xff0c;盯着某一处细节&#xff08;如大嘴巴&#xff09;看</li><li>瞳孔缩小&#xff0c;模糊的看一张图片的大致轮廓</li></ul> <p>两个过程获取的信息叠加&#xff0c;Bingo&#xff0c;看清楚了&#xff0c;是哆啦A梦&#xff01;</p> <p>那么神经网络是否可以模拟这种瞳孔放大、缩小的方式呢&#xff1f;</p> <p>很幸运&#xff0c;可以&#xff01;</p> <p>那就是卷积算法。</p> <h5 id="h2">卷积</h5> <p style="text-align:center;"><img src="https://i-blog.csdnimg.cn/blog_migrate/28afbebed91f199ed5232b39050f92fe.png" alt="Resnet50算法原理_卷积核_03" style="width: 659px; visibility: visible;" /></p> <p>卷积核的设计&#xff0c;就可以很直观的模拟上面说的这种获取图片信息的方法。</p> <p>人们通过调整卷积核的大小&#xff0c;来模拟瞳孔张开、缩小的局部视角。</p> <p>并且大量的实验和论文表明&#xff0c;卷积这一针对图像局部性识别的算法&#xff0c;可以非常有效的模拟人眼识别物体的过程。</p> <p>关于卷积算法以及卷积核的设计原理&#xff0c;后面会专门来讲&#xff0c;因为卷积这一算法&#xff0c;在图像处理领域&#xff0c;太重要了。我们现在继续沿着像素这一话题讲下去。</p> <h5 id="h3">色彩分量RGB</h5> <p>回到像素这一话题&#xff0c;你有没有想过&#xff0c;为什么一张图片会是彩色的。</p> <p>学过摄影的小明同学可能这时会回答&#xff1a;因为图片是由RGB三种颜色来表示的&#xff0c;每个像素实际是不同的R/G/B分量的叠加&#xff0c;混合起来&#xff0c;就表示成了不同的颜色。</p> <p>回答正确。</p> <p style="text-align:center;"><img src="https://i-blog.csdnimg.cn/blog_migrate/e59dd7a5b9f9085d0e.png" alt="Resnet50算法原理_人工智能_04" style="width: 423px; visibility: visible;" /></p> <p> <br /></p> <p>三张分别表示R/G/B分量的图片&#xff0c;合成一张彩色图片</p> <p>对于上面一张RGB的图&#xff0c;我们人眼可以很直观的看到红色和蓝色&#xff0c;可以察觉到一张图片的色彩和轮廓。</p> <p>那么&#xff0c;如果让计算机来处理图片&#xff0c;他又是如何知道色彩和轮廓的呢&#xff1f;</p> <p>其实对于计算机来说&#xff0c;一张图片只是一堆数据&#xff0c;计算机是无法知道这堆数据代表的是什么。</p> <p>这就需要人为的给这堆数据一种表示方法&#xff0c;让计算机知道&#xff0c;哦&#xff0c;这1/3的数据是红色分量&#xff0c;这1/3的是蓝色分量&#xff0c;这些数据&#xff08;像素&#xff09;组合起来&#xff0c;可能代表的是个“帽子”。</p> <p>怎么做呢&#xff1f;</p> <p>通过设计数据在计算机中的存储方式来解决。</p> <p>数据在计算机的存储中&#xff0c;最常见的存储方式是连续存储的。比如C语言&#xff0c;定义一个数组&#xff0c;那么数组在内存中的位置是连续的。</p> <div> </div> <p>内存怎么理解&#xff0c;它就是一排连着门牌号的公寓宿舍。门牌号为101里面住着的&#xff0c;是data的第一个数据0&#xff0c;门牌号102里面住着的&#xff0c;是data的第二个数据1&#xff0c;...&#xff0c;以此类推。</p> <p style="text-align:center;"><img src="https://i-blog.csdnimg.cn/blog_migrate/d0fefe8ff8ad797fdb6b.png" alt="Resnet50算法原理_人工智能_05" style="width: 1071px; visibility: visible;" /></p> <p>哈利波特的女贞路4号</p> <p>内存也是类似于门牌号规则&#xff0c;数据就像人一样&#xff0c;存储在以地址为标识的一个个的内存地址上&#xff08;房子&#xff09;。</p> <p>只不过&#xff0c;在计算机存储器中&#xff0c;没有门牌号&#xff0c;有的都是地址。</p> <p>这个时候&#xff0c;计算机根本就不关心数据是啥&#xff0c;计算机用到的时候&#xff0c;就把数据从内存对应的地址中取出来用。</p> <h5 id="h4">计算机是如何取像素数据的</h5> <p>人们为数据存储设计一种格式&#xff0c;告诉计算机&#xff0c;这堆数据大概是什么样的。</p> <p>只有这样&#xff0c;通过这种约定的方式&#xff0c;计算机才能正确的取到R分量或者B分量。</p> <p>对于一张图片来说&#xff0c;最常见的两个参数是长和宽&#xff0c;一般用H&#xff08;height) 和W(width) 来表示&#xff0c;那么RGB三个分量&#xff0c;看作是3个通道&#xff08;channel)&#xff0c;一般用 C 来表示。</p> <p>如此一来&#xff0c;一张长宽分别是224像素*224像素的RGB图像&#xff0c;就可以用 HWC &#61; [224, 224, 3]来表示。</p> <p>两张类似的图片就用 NHWC &#61; [2, 224, 224, 3]表示&#xff0c;其中N代表图片张数。</p> <p> <br /></p> <p style="text-align:center;"><img src="https://i-blog.csdnimg.cn/blog_migrate/8a880bb54991ba9472f21046b1895bcf.png" alt="Resnet50算法原理_卷积核_06" style="width: 302px; visibility: visible;" /></p> <p>友好的数据表示方法&#xff0c;可以减少大量的计算复杂度。虽然这样表示不太利于人们的直观理解&#xff0c;但是计算机处理这种数据是十分方便的。</p> <p>在目前主流的深度学习框架中&#xff0c;对于图片的数据格式&#xff0c;基本都支持了NHWC或NCHW这种数据摆放格式。说到底&#xff0c;都是为了更高效地进行图片数据的处理和运算。</p> <h5 id="h5">这里加个餐</h5> <p>熟悉OpenCV或者计算机视觉的同学&#xff0c;可能对于上面的RGB分量图片中的女神很熟悉。没错&#xff0c;在很多的教程中&#xff0c;这位女神不止一次的出场。</p> <p style="text-align:center;"><img src="https://i-blog.csdnimg.cn/blog_migrate/f6e0c24a3d08d0a49.png" alt="Resnet50算法原理_卷积_07" style="width: 314px; visibility: visible;" /></p> <p>这位女士名叫Lena。</p> <p>电气电子工程师学会图像处理汇刊&#xff08;IEEE Transactions on Image Processing&#xff09;主编曾在1996年1月出版的一期中解释道&#xff0c;Lena的流行&#xff0c;因为她是一张好的测试图片&#xff0c;其中包含了很多细节&#xff0c;平滑区域&#xff0c;阴影和纹理。</p> <p>她流行的另外一个原因&#xff0c;就是漂亮美女的图片自然受到男性居多的研究领域的欢迎。</p> <p>加餐完毕&#xff0c;我们继续看看图像的色彩空间。</p> <p style="text-align:center;"><img src="https://i-blog.csdnimg.cn/blog_migrate/49e495ee385dac037a3dcb7f.png" alt="Resnet50算法原理_人工智能_08" style="width: 474px; visibility: visible;" /></p> <h5 id="h6">图像的色彩空间</h5> <p>RGB——Red&#xff0c;Green&#xff0c;Blue&#xff08;RGB&#xff09;是我们最常见的图像表示方法。</p> <p>这个非常好理解&#xff0c;三原色的融合&#xff0c;几乎可以构造出所有需要的颜色。三张RGB分量图片的融合&#xff0c;就可以构成一幅色彩斑斓的图片。</p> <p style="text-align:center;"><img src="https://i-blog.csdnimg.cn/blog_migrate/b8f65ed577e3e29e143bd0ccd4419bb8.png" alt="Resnet50算法原理_卷积核_09" style="width: 654px; visibility: visible;" /></p> <p>平时我们说&#xff0c;分辨率为1920*1080的图片&#xff0c;它代表的是在长宽两个方向上&#xff0c;有 1920 * 1080 个像素&#xff0c;但是&#xff0c;在色彩这个方向上&#xff0c;还有 3 个通道&#xff08;channel&#xff09;&#xff0c;也就是RGB&#xff0c;往往被我们忽略。</p> <p>我们看到的一个像素点的颜色&#xff0c;在计算系统中&#xff0c;并不是简单的由一个数值来表示的&#xff0c;而是由RGB三个分量的三个数值来表示的。</p> <p style="text-align:center;"><img src="https://i-blog.csdnimg.cn/blog_migrate/c95190eaa68d655cf0ab6aad013e5cc7.png" alt="Resnet50算法原理_卷积核_10" style="width: 367px; visibility: visible;" /></p> <p>因此&#xff0c;想要计算一张1920*1080的图片的大小&#xff0c;或者说计算这张图片在计算机内存中所占用的大小时&#xff0c;不能仅仅用图片的长度乘以宽度这么算&#xff0c;还需要考虑通道数。</p> <p>我们可能用过画图这一软件来调过颜色。</p> <p>通过简单的设置红色&#xff0c;绿色&#xff0c;蓝色的数值&#xff0c;就可以在调色板中得到一个颜色。</p> <p>有没有注意到&#xff0c;无论红色&#xff0c;还是绿色&#xff0c;还是蓝色&#xff0c;其表示的数值都没有超过255。</p> <p>为什么&#xff1f;</p> <p>因为像素值&#xff0c;在计算机语言中&#xff0c;是用一个 uint8 的数据来表示的。而 uint8&#xff0c;指的是 8bit 无符号整数&#xff0c;其能表示的范围就是 0 - 255。</p> <p style="text-align:center;"><img src="https://i-blog.csdnimg.cn/blog_migrate/a6f21e5512ed1705c.png" alt="Resnet50算法原理_数据_11" style="width: 446px; visibility: visible;" /></p> <p>画图面板&#xff1a;自从几年前微软宣布停止更新画图软件之后&#xff0c;画图就越来越少的出现在人们的视野中&#xff0c;你或许可以打开电脑看看&#xff0c;左下角的菜单里&#xff0c;是否还有画图软件&#xff0c;就像当年window xp 系统被停用一样&#xff0c;慢慢的就会消失在人们的记忆里</p> <p>说到这&#xff0c;我们就可以算一算&#xff0c;一张1920 * 1080 的RGB图像&#xff0c;在计算机的表示中&#xff0c;到底占多少的内存&#xff1f;</p> <p>很简单&#xff0c;长宽方向上每个像素由 3 个通道组成&#xff0c;每个通道由一个 8 bit 的数值表示&#xff0c;一个 8 bit 数值代表一个字节&#xff08;Byte&#xff09;。</p> <p>因此&#xff0c;一张1920 * 1080的 RGB 图像&#xff0c;占计算机存储大小为</p> <p>1920* 1080 * 3 * 1 Bytes &#61; 6075 KB &#61; 5.9 MB</p> <p>5.9 MB 的内存占用&#xff01;</p> <p>大么&#xff1f;和目前动辄几个G的手机内存相比&#xff0c;不算大。</p> <p>小么&#xff1f;和边缘侧图像识别终端内存&#xff0c;比如摄像头里的嵌入式芯片内存相比&#xff0c;又不算小。</p> <p>更何况在公路违法拍照的摄像头场景下&#xff0c;在车流量很大的时候&#xff0c;需要实时处理的图片&#xff0c;可远远不止一张&#xff01;</p> <p>那怎么办&#xff1f;</p> <p>有没有办法可以在进行图像处理时&#xff0c;减少图片的数据量&#xff0c;从而减少图片大小和内存占用呢&#xff1f;</p> <p>有&#xff0c;YUV就是其中一种办法。</p> <p>YUV是将亮度信息和颜色信息进行编码的一种颜色空间表示方法。和RGB类似&#xff0c;YUV 也使用3个字母维度来表示颜色。</p> <p>为了简单点&#xff0c;我们暂时将这3个值称为Y&#xff0c;U和V。&#xff08;事实上&#xff0c;YUV的称呼很多&#xff0c;比如Y&#39;CbCr&#xff0c;也很细节&#xff0c;这里不多描述&#xff0c;我们只要知道它是另外一种表示颜色的方法就可以。&#xff09;</p> <p>Y 代表亮度&#xff0c;U 代表色彩度&#xff0c;V代表饱和度。</p> <p style="text-align:center;"><img src="https://i-blog.csdnimg.cn/blog_migrate/8c659fd26158bc485fd60bccf8b7517e.png" alt="Resnet50算法原理_人工智能_12" style="width: 421px; visibility: visible;" /></p> <p style="text-align:center;"><img src="https://i-blog.csdnimg.cn/blog_migrate/fceb08447a1adc5d765feea8.png" alt="Resnet50算法原理_人工智能_13" style="width: 404px; visibility: visible;" /></p> <p> <br /></p> <p>上面的几张图片&#xff0c;除了原图之外&#xff0c;我们可能更加倾向于使用只有Y分量的图片&#xff0c;也就是那张黑白图像。</p> <p>因为即使没有色彩&#xff0c;但是它的轮廓以及明亮程度&#xff0c;也足以让我们分辨出图片中的物体。这也是为什么&#xff0c;黑白电视照样可以风靡一时的原因。</p> <p>其视觉效果远远好于其他两个分量的图片。相反&#xff0c;只有色度和饱和度的图片&#xff0c;反而变得模糊不堪。</p> <p>这就是问题所在&#xff01;</p> <p><strong>人眼对于亮度具有更高的敏感度&#xff0c;而对色度和饱和度反而显得迟钝一些。</strong></p> <p>说到这&#xff0c;有没发现什么&#xff1f;</p> <p>既然人眼对于色度和饱和度的反应不敏感&#xff0c;那就没有必要把所有的色度和饱和度信息都放在图片里了啊。</p> <p>举个例子&#xff0c;色度和饱和度我隔一个像素放一个&#xff0c;剩下的像素没有饱和度&#xff0c;不就可以了么。</p> <p>没错&#xff0c;是可以&#xff0c;而且效果很好。</p> <p>这就是YUV的不同编码。</p> <p style="text-align:center;"><img src="https://i-blog.csdnimg.cn/blog_migrate/1d1b8ea2a16e5c6436e26af.png" alt="Resnet50算法原理_数据_14" style="width: 482px; visibility: visible;" /></p> <p>实际上&#xff0c;YUV的编码方式有很多种&#xff0c;比如YUV444, YUV422等。</p> <p>大致意思就是&#xff0c;保留全部的Y分量&#xff08;人眼最敏感的亮度分量&#xff09;&#xff0c;但是只保留部分的U/V分量&#xff08;人眼不敏感&#xff09;&#xff0c;以此来减少图片的占用&#xff0c;但又不失重要信息。</p> <p>还记得上面的1920*1080的RGB图片的内存占用么&#xff0c;为5.9MB。</p> <p>如果用YUV444的编码&#xff0c;结果也同样是5.9MB&#xff0c;因为YUV444也是全采样&#xff0c;所有的亮度、色度、饱和度信息都保留了。</p> <p>而如果采用YUV422的编码&#xff0c;相当于U分量减少一半&#xff0c;V分量减少一半。那么最终的图片占用大小就变成了</p> <div> </div> <p>只有3.9MB&#xff0c;减少了1/3的内存占用&#xff01;</p> <p>是不是好很多&#xff1f;更多关于YUV的编码知识&#xff0c;有兴趣的同学可以Google。如果不做相关课题&#xff0c;可以不用深究。</p> <p>我们只需要知道&#xff0c;YUV这一色彩编码方法&#xff0c;在保留亮度这一人眼最敏感信息的基础上&#xff0c;通过降低其他人眼不太需要的信息&#xff0c;可以来达到降低图片大小的目的&#xff0c;就够了&#xff01;</p> <h5 id="h7">YUV编码的用途</h5> <p>原始图片&#xff0c;channel数代表的是RGB通道&#xff0c;可以理解为原始图片具有的三个特征。可在深度学习网络中&#xff0c;随着网络深度的增加&#xff0c;图片的channel数会不断的增大。</p> <p>就拿Resnet50这个网络来说&#xff0c;最后面的一层图片&#xff0c;channel数已经增大到了2048。</p> <p>这时每个channel代表的信息&#xff0c;早已不再是RGB这种基础的特征了。</p> <p>而是通过了神经网络的多轮训练&#xff0c;代表了图片的更多维度信息的特征&#xff0c;比如是猫的特征还是狗的特征。这个后面会详细说。</p> <h5 id="h8">再加餐&#xff0c;讲个色彩编码的小故事</h5> <p>公元663年&#xff0c;唐代诗人王勃游历南昌&#xff0c;登滕王阁而做序&#xff0c;大笔一挥&#xff0c;豪气万丈。</p> <p>当时的王勃&#xff0c;傲立在滕王阁楼顶时&#xff0c;看到的应该是怎样的一副壮美图景&#xff0c;才使得中国文坛留下了一句千古绝唱。</p> <p>潦水尽而寒潭清&#xff0c; 烟光凝而暮山紫。</p> <p>当时的王勃&#xff0c;应该怎么也不会想到&#xff0c;1000年后的今天&#xff0c;聪明华夏后人&#xff0c;将&#34;暮山紫&#34;这一颜色进行了编码。</p> <p>从此&#xff0c;暮山紫&#xff0c;不只存在于人们的想象中&#xff0c;而是精确地存在了计算机里。</p> <p style="text-align:center;"><img src="https://i-blog.csdnimg.cn/blog_migrate/ad210aef883a3a538e462a4f0973c8b8.png" alt="Resnet50算法原理_卷积_15" style="width: 583px; visibility: visible;" /></p> <h5 id="h9">初识卷积</h5> <p>图片是做深度学习任务的原材料&#xff0c;就像是做饭&#xff0c;不了解原材料的特性&#xff0c;怎么能快速高效的做出一顿美味的大餐&#xff1f;</p> <p>在基本料及了图片的基础特性——像素和RGB之后&#xff0c;下面开始聊聊做大餐的工具&#xff0c;卷积算法。</p> <h5 id="h10">人脑是怎么记住东西的&#xff1f;</h5> <p>在说卷积之前&#xff0c;先务虚一下&#xff0c;说说记忆。</p> <p>或许你已经听说过很多AI故事了&#xff0c;比如大名鼎鼎的阿尔法狗大战柯洁。但是&#xff0c;你有没有想过一个问题。</p> <p>阿尔法狗确实是学会了下棋&#xff0c;但是它下棋的记忆到底是什么样的&#xff1f;存在什么地方呢&#xff1f;</p> <p>高中生物老师教过我们&#xff0c;人脑中有大量的脑神经元。每个脑神经元都可以看做是一个小的记忆体&#xff0c;神经元之间通过树突连接起来。整个大脑的神经元&#xff0c;可以说是一张十分复杂的网络。</p> <p>人脑处理信息&#xff0c;就是利用这个复杂的网络处理信息&#xff0c;并最终得到一个结果。通过神经元网络&#xff0c;我们才能知道&#xff0c;眼睛看到的是一只猫&#xff0c;还是是一只狗。</p> <p>稍微简化一下大脑神经元的复杂结构成如下的网络。</p> <p style="text-align:center;"><img src="https://i-blog.csdnimg.cn/blog_migrate/0002d8c2f18cb8650b63ee26bdae8fc4.png" alt="Resnet50算法原理_人工智能_16" style="width: 329px; visibility: visible;" /></p> <p>上图中&#xff0c;每个黑点代表一个神经元脑细胞&#xff0c;每个神经元都有自己负责记忆的东西。</p> <p>当我们看到一张画着猫的图片的时候&#xff0c;图片信息通过视神经传给大脑神经元&#xff0c;于是&#xff0c;信息到达了最左边一排竖着的黑点&#xff08;神经元&#xff09;。</p> <p>假如一个黑点&#xff08;神经元&#xff09;之前见过猫&#xff0c;那么这个黑点就会把信息往后传&#xff0c;此时神经元处于激活状态。</p> <p>假如一个黑点从来没见过猫&#xff0c;那么这个黑点&#xff08;神经元&#xff09;就啥也不知道&#xff0c;啥也不做&#xff0c;此时神经元处于静止状态。</p> <p>像不像初中课堂上&#xff0c;老师问了你一个超难的问题&#xff0c;而你不知道的时候&#xff0c;你也只能站着&#xff0c;可怜又无助&#xff0c;啥也不会做&#xff1f;没错&#xff0c;神经元如果没见过猫&#xff0c;他啥也不会做&#xff01;</p> <p style="text-align:center;"><img src="https://i-blog.csdnimg.cn/blog_migrate/c8ba5e6d9c2967bb159a38fc89804d61.png" alt="Resnet50算法原理_人工智能_17" style="width: 361px; visibility: visible;" /></p> <p>图片的信息就这样&#xff0c;一层一层的通过“见过猫且确信它是一只猫的”神经元往后传递&#xff0c;直到在最后输出一个结果——</p> <p>这是一只猫。</p> <p>这个过程叫做大脑的<strong>推理</strong>。</p> <p style="text-align:center;"><img src="https://i-blog.csdnimg.cn/blog_migrate/11bd743adba8fe88890d16bdfe.png" alt="Resnet50算法原理_卷积_18" style="width: 444px; visibility: visible;" /></p> <p>整个推理过程你应该注意到了一件事。所有的黑点&#xff08;神经元&#xff09;&#xff0c;都可能是有记忆的&#xff0c;只不过记得东西各有不同&#xff0c;有的认识猫&#xff0c;有的认识狗&#xff0c;就像下面这样。</p> <p style="text-align:center;"><img src="https://i-blog.csdnimg.cn/blog_migrate/f4d59bd57c0c02e4ee385.png" alt="Resnet50算法原理_数据_19" style="width: 485px; visibility: visible;" /></p> <p>所有认识猫的神经元都会让信息通过&#xff0c;其他不认识猫的神经元都静止了。</p> <p>但是只要信息能传到最后&#xff0c;人脑最终就可以得出一个结论&#xff0c;这就是一只猫。</p> <p>那神经元的这些记忆是怎么获取的呢&#xff1f;当然是训练&#xff01;</p> <p>人们在日常生活中不断地训练大脑&#xff0c;时刻观察着周围的事物。</p> <p>见得多了&#xff0c;就会了&#xff01;</p> <p>那么计算机又是怎么模拟这个记忆过程呢&#xff1f;答案很简单&#xff1a;因为计算机只会计算&#xff0c;那就让它计算好了。</p> <p>如果某个黑点认识猫&#xff0c;有什么办法可以把“这是一只猫”这一信息传递到后面呢&#xff1f;乘以1啊&#xff0c;任何数乘以1都是它自己&#xff0c;一只猫乘以1也还是他自己。</p> <p>如果某个黑点压根没见过猫&#xff0c;有什么办法可以什么都不做呢&#xff1f;乘以0啊&#xff0c;任何数乘以0都是0&#xff0c;信息也就没了&#xff0c;一只猫乘以零&#xff0c;猫也就没了。</p> <p>于是——</p> <p>在深度学习的网络中&#xff0c;每个黑点&#xff08;神经元&#xff09;都有一个与之对应的数字&#xff08;实际的网络中&#xff0c;不是0或者1这样简单的数字&#xff0c;而是一堆更复杂的数字&#xff0c;这里仅仅是为了说明示意&#xff09;&#xff0c;这些数字&#xff0c;在深度学习中&#xff0c;我们称之为权值。</p> <p>神经元可以通过与权值的加权计算来判断是否让某一信息经过神经元&#xff0c;到达下一层。权值乘以输入的信息&#xff08;猫&#xff09;&#xff0c;然后经过激活函数去激活&#xff08;类似于人脑神经元的激活&#xff09;。</p> <p>如果能成功激活&#xff0c;那么信息就往下传。</p> <p>如果没有成功激活&#xff0c;信息就在此丢失。</p> <p>当然神经网络中的权值不是简单的0或1&#xff0c;所以经过激活函数计算出来的只是一个概率值&#xff0c;也就是说某个黑点&#xff08;神经元&#xff09;觉得它是一只猫的概率。</p> <p>最终如果得到95%的概率觉的它是一只猫&#xff0c;那基本就是一只猫。</p> <p>这个权值&#xff0c;就是AI 的记忆。</p> <p>这个权值&#xff0c;就是AI 在训练的过程中学到的东西&#xff1a;千百万次计算得出的最优解。</p> <p>这个权值&#xff0c;可以保证&#xff0c;只要AI 在训练过程中看过猫&#xff0c;那么新的猫咪来的时候&#xff0c;猫咪乘以权值有很高的概率能通过激活函数&#xff0c;确保神经元被激活。</p> <p>为什么可以这么确定呢。</p> <p>因为AI 的训练过程早已经模拟了成千上万次“识猫”的过程了。</p> <p>权值就是训练出来的&#xff01;就像我们的记忆被训练出来的一样&#xff01;</p> <p>...</p> <p>而卷积这一算法&#xff0c;就存在一个记忆体&#xff0c;或者说权值。</p> <p>那就是卷积核。</p> <h5 id="h11">卷积-Convolution</h5> <p>说到卷积&#xff0c;首先不要被这个名字吓到了。</p> <p>不管数学好不好的同学&#xff0c;看到卷积的第一反应&#xff0c;可能是记得有一个卷积公式&#xff0c;貌似可以进行信号处理。</p> <p style="text-align:center;"><img src="https://i-blog.csdnimg.cn/blog_migrate/f18608c6328bc1f2a6432fb81e39f76c.png" alt="Resnet50算法原理_卷积_20" style="width: 524px; visibility: visible;" /></p> <p>一个代表卷积核的曲线在原始信号曲线上滑来滑去&#xff0c;得到不同的输出。在什么地方学过来着&#xff1f;好像是时频转换的时候&#xff0c;又好像不是。(当然不是&#xff01;)</p> <p>但是&#xff0c;不用回忆之前的知识&#xff0c;不用管它&#xff01;</p> <p>因为&#xff0c;深度学习中的卷积&#xff0c;和信号处理中的卷积&#xff0c;有相似之处&#xff0c;但又不完全一样。</p> <p>深度学习中的卷积&#xff0c;完完全全模拟的&#xff0c;就是人眼看物体的过程&#xff01;</p> <p style="text-align:center;"><img src="https://i-blog.csdnimg.cn/blog_migrate/298e908a4ca90d7d2fdb2897fc96a562.gif" alt="Resnet50算法原理_数据_21" style="width: 244px; visibility: visible;" /></p> <p>卷积过程示意图</p> <h5 id="h12">卷积模拟人眼</h5> <p>上图是深度学习中卷积的示意图。</p> <p>图片是由像素组成的&#xff0c;示意图下方的4x4 的像素方格就是卷积需要处理的图片&#xff08;模拟人眼观看图片的过程&#xff09;&#xff0c;示意图上方的2x2 的像素方格就是卷积的输出&#xff08;人眼看到图片之后得出的结论&#xff09;。</p> <p>那么卷积核在哪&#xff1f;4x4方格上移动的灰色阴影&#xff0c;3x3的像素方格就是卷积核&#xff01;</p> <p>可以理解为人眼此时聚焦看到的区域&#xff08;称之为感受野&#xff0c;人眼的视野&#xff09;&#xff0c;只不过&#xff0c;这个示意图中每次看到的都是一个3x3的像素方格&#xff01;</p> <p>而卷积过程&#xff0c;就是用3x3的卷积核&#xff0c;去逐步扫描图片。横着扫完竖着扫。每扫一次&#xff0c;就将逐个像素点的值相乘然后加一起&#xff0c;得到一个输出。<br /></p> <p style="text-align:center;"><img src="https://i-blog.csdnimg.cn/blog_migrate/e8aa29c3ad1cfa4cee2.gif" alt="Resnet50算法原理_数据_22" style="width: 535px; visibility: visible;" /></p> <p> 再换个更直观的角度看一眼。</p> <p style="text-align:center;"><img src="https://i-blog.csdnimg.cn/blog_migrate/6032d98ba36b35293ca6546bdbc3134a.gif" alt="Resnet50算法原理_卷积核_23" style="width: 1079px; visibility: visible;" /></p> <p>上图第一次扫到的是左上角的9个点&#xff0c;与卷积核中9个点逐点相乘&#xff0c;然后相加&#xff0c;就得到了输出图片的左上角的一个点的值。<br /></p> <p>卷积&#xff0c;就是这么简单的过程。</p> <p>我们可以通过调整卷积核的大小&#xff0c;比如把上图3x3的卷积核扩大到5x5&#xff0c;来控制 “人眼” 看到的图片范围&#xff0c;从而获取到不同的图片信息。</p> <p>在实际神经网络中&#xff0c;存在这个各种各样的卷积变种。</p> <p>科学家或工程师们通过设计不同的卷积核以及卷积每次移动的多少等参数&#xff0c;来实现不同的功能。但卷积操作万变不离其宗&#xff01;</p> <p>AI 之所以能够记住它所学的东西&#xff0c;关键在于神经网络有权值这一参数的存在&#xff0c;它的存在就类似人脑的记忆。并且&#xff0c;权值和人脑的记忆一样&#xff0c;都是通过训练来获得的。</p> <p>卷积这一算法&#xff0c;除了利用“感受野”获取到不同图片区域的信息&#xff0c;从而将图片在长宽两个维度的尺寸缩放之外&#xff0c;还存在channel维度的升降。而这&#xff0c;才是卷积这一算法的核心&#xff0c;称之为特征提取。</p> <h5 id="h13">卷积的特征提取</h5> <p>通俗点讲&#xff0c;卷积就是模仿的人眼识图的过程&#xff0c;以“感受野”的视角去扫描图片&#xff0c;从而获取不同区域的图片信息。</p> <p>但其实&#xff0c;卷积的核心&#xff0c;是通过设计多个卷积核&#xff0c;同时对一张图片进行卷积操作&#xff0c;以完成不同特征的提取。</p> <p>先简单看看一个卷积算法的数学描述。_不想看数学描述的同学可以略过&#xff0c;不影响后面的阅读。_</p> <p>有了之前文章的铺垫&#xff0c;这里说一张图片的尺寸是 [n, h, w, c]&#xff0c;应该不陌生了吧&#xff0c;其中&#xff0c;</p> <ul><li>n 代表的是图片的张数。</li><li>h 代表的是图片的高度&#xff0c;通俗的讲&#xff0c;高度方向上有多少像素。</li><li>w 代表的是图片的宽度&#xff0c;通俗的讲&#xff0c;宽度方向上有多少像素。</li><li>c 代表图片的通道数&#xff0c;例如 RGB 图片&#xff0c;c 等于3。</li></ul> <p> <br /></p> <p style="text-align:center;"><img src="https://i-blog.csdnimg.cn/blog_migrate/96af7f8b84ca4bbe2ff.png" alt="Resnet50算法原理_数据_24" style="width: 669px; visibility: visible;" /></p> <p>不论是图片&#xff0c;还是卷积核&#xff0c;其数学描述都是具有n,h,w,c四个维度的数据。</p> <p>对于卷积算法而言&#xff0c;输入图片尺寸为[n, hi, wi, c]&#xff08;下标i代表input&#xff0c;输入&#xff09;&#xff0c;卷积核尺寸为 [co, kh, kw, c]&#xff0c;输出图片尺寸为[n, ho, wo, co]&#xff08;下标o代表output&#xff09;。</p> <p>有没有发现&#xff0c;输出图片的channel数与输入图片的channel数不一致&#xff01;</p> <p>输出图片的channel数与卷积核的个数一致&#xff01;</p> <h5 id="h14">图片的特征</h5> <p>这意味着什么&#xff1f;还记得么&#xff0c;channel代表的是图片的特征&#xff0c;如果我们想让图片呈现出100个特征&#xff0c;怎么办&#xff1f;</p> <p>用卷积&#xff0c;使用100个卷积核计算&#xff0c;输出图片就具有100个特征&#xff01;卷积算法&#xff0c;可以通过设计卷积核的个数&#xff0c;提取图片中不同数量的特征&#xff01;</p> <p>说的数学一点&#xff0c;卷积算法&#xff0c;就是通过变换&#xff0c;将图片映射到特征空间&#xff01;</p> <p>有点绕&#xff1f;没关系&#xff0c;现在只知道&#xff0c;卷积可以提取图片的特征就行了。</p> <p>那么&#xff0c;特征怎么理解呢&#xff1f;</p> <p>一幅图像特征主要有颜色特征、纹理特征、形状特征和空间关系特征。</p> <p> <br /></p> <p style="text-align:center;"><img src="https://i-blog.csdnimg.cn/blog_migrate/fedd19f1e1fdb6359f2ae22dee.png" alt="Resnet50算法原理_数据_25" style="width: 1059px; visibility: visible;" /></p> <p>RGB图片有3个通道&#xff0c;可以说有3个颜色特征&#xff0c;分别为红色&#xff0c;绿色和蓝色。</p> <p>那么纹理特征&#xff0c;形状特征和空间特征又是什么意思呢&#xff1f;纹理特征就是图片的纹理&#xff0c;比如下面这样。</p> <p style="text-align:center;"><img src="https://i-blog.csdnimg.cn/blog_migrate/e2979b95664c86edb82cf64e41c414f1.png" alt="Resnet50算法原理_卷积_26" style="width: 729px; visibility: visible;" /></p> <p>那么卷积这一算法在神经网络的训练过程中学习到这些特征了么&#xff1f;</p> <p>答案是肯定的&#xff01;</p> <p>卷积不仅学到了这些特征&#xff0c;而且还学到了更多人们不太好描述的特征&#xff0c;这些特征对于人类来说可能毫无意义&#xff0c;但对于神经网络来说&#xff0c;确实十分重要的。</p> <p style="text-align:center;"><img src="https://i-blog.csdnimg.cn/blog_migrate/4aba48285f21f1af07d8c9e71c01a1d8.png" alt="Resnet50算法原理_数据_27" style="width: 500px; visibility: visible;" /></p> <p>上图是著名的论文《Visualizing and Understanding Convolutional Networks》中的截图&#xff0c;文中提出通过反卷积这一算法&#xff0c;以可视化的视角&#xff0c;形象的展示卷积神经网络在训练过程中到底看到了什么。</p> <p>反卷积&#xff0c;通俗的理解就是卷积的逆运算。</p> <p>可以看到&#xff0c;随着神经网络深度的不断加深&#xff0c;卷积提取到的特征逐渐清晰起来。</p> <p>由浅层次的纹理特征&#xff0c;逐步到深层次的形状特征&#xff01;比如&#xff0c;在Layer 4&#xff08;Renset50d的第4层卷积&#xff09;中已经可以看到狗狗的形象&#xff01;</p> <p>事实上&#xff0c;我们希望神经网络展现出来的能力&#xff0c;是它看到一张画着小猫的图片&#xff0c;最终的输出结果中&#xff0c;有一个代表猫的特征通道&#xff0c;并且该通道的得分或者概率最高。</p> <p>到这里&#xff0c;即使你是一个AI算法小白&#xff0c;那也应该对卷积有了一些感性的认识。如果你希望了解到更多细节的东西&#xff0c;后面会逐步进行拆解。请继续阅读。</p> <p>在这里先插播一下&#xff0c;介绍一下Resnet网络。孙剑博士领导研究的Resnet网络&#xff08;残差网络&#xff09;&#xff0c;曾多次荣获图片分类大赛冠军&#xff0c;开启了一个卷积图像分类的热潮。</p> <p>而本文拆解的就是这个网络&#xff0c;它是一个图像分类网络。</p> <p>所谓图像分类&#xff0c;就是它可以将一张图片进行分类。猫就是猫&#xff0c;狗就是狗&#xff0c;飞机就是飞机&#xff0c;大树就是大树。与图像分类不同的&#xff0c;还有图像检测网络。比如物体识别&#xff0c;需要在一张图片上准确的标注出物体是啥以及物体的位置。</p> <p style="text-align:center;"><img src="https://i-blog.csdnimg.cn/blog_migrate/d1c9fb9dbdff780c21fa5f44.png" alt="Resnet50算法原理_卷积_28" style="width: 569px; visibility: visible;" /></p> <p>这些网络里都大量使用了卷积算法。因此这些网络我们也可以称之为卷积神经网络&#xff08;Convolution Neural Network, CNN)。</p> <p>除了CNN&#xff0c;还有循环神经网络&#xff08;Recurrent Neural Network, RNN&#xff09;&#xff0c;之前写过一篇关于LSTM的文 章LSTM最通俗的解释 中提到的LSTM就是一种RNN结构。</p> <p>回到Resnet50这一卷积神经网络&#xff0c;这一网络由50个卷积层前后连接而成&#xff0c;因此叫Resnet50&#xff0c;除此之外&#xff0c;还有Resnet18&#xff0c;Resnet101等&#xff0c;大致网络结构相似&#xff0c;只是卷积的层数不同。</p> <p>为什么会有不同的卷积层数呢&#xff1f;神经网络在学习的时候&#xff0c;每一层学习到的特征是不同的&#xff0c;就比如第一层&#xff0c;它的输入只有3个特征&#xff0c;输出有64个特征&#xff0c;至于这64个特征代表的是什么&#xff0c;可能连神经网络自己也说不清&#xff0c;它就只管学习。</p> <p>一直到最后一层有2048个特征&#xff0c;到了最后一层&#xff0c;可以比较形象的这么比喻&#xff1a;最后一层共2048个特征&#xff0c;实际上已经代表了2048种物体的分类了。</p> <p>针对一张图片是猫的原始输入&#xff0c;2048个特征中&#xff0c;只有猫这一特征最后的得分最高&#xff0c;因此&#xff0c;网络会把它推理成猫。</p> <p>这就是卷积算法的核心&#xff0c;通过不同层的卷积算法&#xff0c;一步步的进行特征的提取&#xff0c;直到网络最后&#xff0c;提取出2048个宏观特征&#xff0c;完成图像的分类。</p> <h5 id="h15">残差结构</h5> <p>Resnet50 网络之所以叫这个名字&#xff0c;是因为这个网络的核心思想&#xff0c;就藏在名字里。</p> <p>Res &#43; net &#43; 50&#xff0c;Res 是 Residual &#xff08;残差&#xff09;的缩写&#xff0c;50指的是整个网络中有50个卷积层。</p> <p>下图是Resnet50的网络结构图&#xff0c;可以看到&#xff0c;从第一层到最后一层&#xff0c;总共50个卷积算法。</p> <p style="text-align:center;"><img src="https://i-blog.csdnimg.cn/blog_migrate/83c3cac3bb2cc97b1382d5af3aab607d.png" alt="Resnet50算法原理_卷积核_29" style="width: 1027px; visibility: visible;" /></p> <p> 那么Res&#xff08;Residual&#xff09;残差又是个什么东西呢&#xff1f;<br /></p> <p>所谓残差结构&#xff0c;其实就是在正常的神经网络中&#xff0c;增加一个short cut 分支结构&#xff0c;也称为高速公路。</p> <p>比如下图中&#xff0c;左侧是正常的卷积层&#xff0c;一层层往下传&#xff0c;在右侧增加一条连线&#xff0c;使得整个网络结构形成了一个残差结构。</p> <p>这样&#xff0c;网络的输出不再是单纯卷积的输出F(x)&#xff0c;而是卷积的输出和前面输入的叠加F(x) &#43; X。</p> <p style="text-align:center;"><img src="https://i-blog.csdnimg.cn/blog_migrate/ae8960eefa457e8b1c9fb61bc13ce915.png" alt="Resnet50算法原理_人工智能_30" style="width: 505px; visibility: visible;" /></p> <h5 id="h16">为什么要增加残差结构&#xff1f;</h5> <p>在前面说过&#xff0c;深度卷积神经网络在网络深度不断加深的过程中&#xff0c;神经网络会学到不同的特征。但是&#xff0c;能无限制地加深么&#xff1f;比如使用1000层卷积层进行网络的训练的。</p> <p>答案显然是不行的。</p> <p>原因在于神经网络训练的过程是不断与目标值进行拟合的过程&#xff0c;直到拟合的误差降低到人们的预期&#xff0c;代表着神经网络训练完毕&#xff0c;一个会识图的AI就诞生了。</p> <p>但是在实际训练过程中&#xff0c;数据的传递除了从网络前端往后传之外&#xff0c;还需要将最后一层与目标值的误差传回到网络前端&#xff0c;从而进行下一轮的训练&#xff0c;得到更小的误差&#xff0c;这一过程称为神经网络的反向传播。</p> <p>在往回传的过程中&#xff0c;由于误差本身就很小&#xff0c;如果卷积层数过多&#xff0c;在经过激活函数时&#xff0c;很容易发生误差传着传着就消失了&#xff0c;称为梯度消失。</p> <p>梯度消失的原因有很多种&#xff0c;不好的激活函数、过深的网络层数等都有可能导致误差消失。</p> <p>想象一下&#xff0c;上一轮训练结果的误差传不回来&#xff0c;下一轮如何在上一轮的基础上进行进一步优化训练&#xff1f;结果就会导致怎么训练神经网络最终的结果都无法收敛。</p> <p>AI根本训练不出来&#xff01;</p> <p> <br /></p> <p style="text-align:center;"><img src="https://i-blog.csdnimg.cn/blog_migrate/aa11757ca64de5baa6e2c9d5cf9f0ee3.png" alt="Resnet50算法原理_数据_31" style="width: 422px; visibility: visible;" /></p> <p>残差结构这个时候就可以发挥作用&#xff01;</p> <p>想象一下&#xff0c;这个高速公路的存在&#xff0c;可以使得输入数据无损地通过。</p> <p>如果左侧卷积层学习到的数据不够好&#xff0c;那么叠加上无损通过的原始数据&#xff0c;依然保留了原始数据&#xff0c;不至于丢掉原始数据。</p> <p>而如果左侧卷积层学习到的效果很好&#xff0c;那么依然会保留着学习到的数据&#xff0c;下面的卷积层依然可以在这些数据基础上进一步学习优化。</p> <p>反向传递也是一样&#xff0c;高速公路的存在&#xff0c;可以确保即使很小的误差也能传递过来&#xff0c;从而避免了梯度消失的发生。说回Resnet50&#xff0c;这个网络就是通过50层卷积的计算&#xff0c;外加残差结构连接&#xff0c;来完成图像分类的。</p> <p style="text-align:center;"><img src="https://i-blog.csdnimg.cn/blog_migrate/9cd2cc357bcdcc69e4941b53bd9444a5.png" alt="Resnet50算法原理_卷积核_32" style="width: 530px; visibility: visible;" /></p> <p>实际上&#xff0c;目前直接使用Resnet50进行图像分类是很少的。</p> <p>大多数会在这个网络的基础上&#xff0c;结合实际的业务场景进行改造&#xff0c;或者直接借鉴Resnet50的网络设计思想&#xff0c;重新设计新的网络&#xff0c;以期获得更加高效的识图效果。</p> <p>一句话&#xff0c;Resnet50的核心是卷积和残差&#xff0c;卷积的核心是特征抽取。</p> <h5 id="h17">激活函数</h5> <p>Resnet50网络是由一层层的算法搭建而成的神经网络&#xff0c;由卷积层、激活层、池化层等组成。而每一个卷积层的后面&#xff0c;都会跟着一个激活层。</p> <p> Resnet50网络的完整结构&#xff0c;可以查看 长图展示Resnet全貌&#xff01; </p> <p>在Resnet50中&#xff0c;激活函数用的是Relu激活函数。那为什么在神经网络中&#xff0c;每一层卷积后面都需要跟着一个激活函数呢&#xff1f;</p> <h5 id="h18">非线性</h5> <p>敲黑板&#xff0c;划重点&#xff0c;为了非线性。</p> <p>我们都学过线性关系&#xff0c;最简单的 y &#61; kx &#43; b&#xff0c;画出来就是一条直线。这个函数就是一个线性函数&#xff0c;称y 和 x 是线性关系。</p> <p> <br /></p> <p style="text-align:center;"><img src="https://i-blog.csdnimg.cn/blog_migrate/1b7af915bc720f01d3da9e93381b860d.png" alt="Resnet50算法原理_人工智能_33" style="width: 383px; visibility: visible;" /></p> <p>如果这个时候&#xff0c;又有一个线性关系 z &#61; hy &#43; d&#xff0c;那么&#xff0c;可以通过如下的线性变换&#xff0c;得到变量 z 和 x 同样也是线性关系&#xff01;</p> <p>z&#61; hy &#43; d &#61; h(kx&#43;b) &#43; d  &#61; hkx &#43; hb &#43; d &#61; Ax &#43; B</p> <p>其中&#xff1a;A &#61; hk&#xff0c; B &#61; hb &#43; d。</p> <p>所以&#xff0c;不管有多少个线性关系&#xff0c;只要在数学上首尾相连&#xff0c;最终都可以等效成一个线性关系&#xff01;</p> <p>然而&#xff0c;卷积算法是由大量的乘法和加法组成&#xff0c;因此&#xff0c;卷积运算也是一种线性运算。</p> <p>这就导致&#xff0c;由大量卷积算法组成的卷积神经网络&#xff08;CNN&#xff09;&#xff0c;如果没有非线性因素的引入&#xff0c;会退化成一个简单的线性模型。这就使得多层卷积失去了意义。</p> <p>比如&#xff0c;Resnet50网络中的50层卷积&#xff0c;就会退化为一个卷积。而在神经网络中&#xff0c;使用多层卷积的一个重要目的&#xff0c;就是利用不同卷积核的大小&#xff0c;来抽取不同卷积核尺度下的图像特征。</p> <p>因此&#xff0c;在神经网络设计时&#xff0c;在每层的卷积后面&#xff0c;都增加一个非线性函数&#xff0c;就可以完成两个卷积层的线性隔离&#xff0c;确保每个卷积层完成自己的卷积任务。</p> <p>目前常见的激活函数&#xff0c;主要有Sigmoid、tanh、Relu等。Resnet50中的激活函数就是Relu。</p> <p>下面主要介绍下这三个函数。</p> <h5 id="h19">sigmoid</h5> <p style="text-align:center;"><img src="https://i-blog.csdnimg.cn/blog_migrate/8616cdbfc54ca75d0ec16e950a2292a5.png" alt="Resnet50算法原理_人工智能_34" style="width: 456px; visibility: visible;" /></p> <p>Sigmoid 函数的图像看起来像一个 S 形曲线。公式为&#xff1a;</p> <p>f(z)&#61; 1/(1&#43; e^-z)</p> <p>Sigmoid 在神经网络中使用&#xff0c;是有一些优点的&#xff0c;主要体现在&#xff1a;</p> <ul><li>Sigmoid函数的输出范围是 0 到 1。由于输出值限定在0 到 1&#xff0c;因此它对每个神经元的输出进行了归一化&#xff1b;</li><li>用于将预测概率作为输出的模型。由于概率的取值范围是 0 到 1&#xff0c;因此Sigmoid 函数非常合适&#xff1b;</li><li>梯度平滑&#xff0c;避免「跳跃」的输出值&#xff1b;</li><li>函数是可微的。这意味着可以找到任意两个点的 sigmoid 曲线的斜率&#xff1b;</li><li>明确的预测&#xff0c;即非常接近 1 或0&#xff1b;</li></ul> <h5 id="h20">tanh</h5> <p style="text-align:center;"><img src="https://i-blog.csdnimg.cn/blog_migrate/2975f5f95c7396eb819b70b0f.png" alt="Resnet50算法原理_人工智能_35" style="width: 422px; visibility: visible;" /></p> <p>tanh激活函数的图像也是 S 形&#xff0c;tanh 是一个双曲正切函数。</p> <p>tanh 函数和sigmoid 函数的曲线相对相似。但是它比 sigmoid 函数更有一些优势。</p> <p style="text-align:center;"><img src="https://i-blog.csdnimg.cn/blog_migrate/facb6000e1cf5ea725.png" alt="Resnet50算法原理_卷积核_36" style="width: 482px; visibility: visible;" /></p> <p>首先&#xff0c;当输入比较大或者比较小时&#xff0c;函数的输出几乎是平滑的并且梯度较小&#xff0c;这不利于权重更新。二者的区别在于输出间隔&#xff0c;tanh的输出间隔为 1&#xff0c;并且整个函数以 0 为中心&#xff0c;比sigmoid 函数更好&#xff1b;</p> <p>在tanh 图中&#xff0c;负输入将被强映射为负&#xff0c;而零输入被映射为接近零。</p> <h5 id="h21">Relu</h5> <p style="text-align:center;"><img src="https://i-blog.csdnimg.cn/blog_migrate/689fb6e4878d3cdf7c.png" alt="Resnet50算法原理_人工智能_37" style="width: 518px; visibility: visible;" /></p> <p>ReLU激活函数图像如上图所示&#xff0c;函数表达式如下&#xff1a;</p> <p style="text-align:center;"><img src="https://i-blog.csdnimg.cn/blog_migrate/c723f95ad80c2128edd424c18cc41e2d.png" alt="Resnet50算法原理_数据_38" style="width: 438px; visibility: visible;" /></p> <p> <br /></p> <p>ReLU 函数是深度学习中较为流行的一种激活函数&#xff0c;相比于 sigmoid 函数和 tanh 函数&#xff0c;它具有如下优点&#xff1a;</p> <ul><li>当输入为正时&#xff0c;不存在梯度饱和问题。</li><li>计算速度快得多。ReLU 函数中只存在线性关系&#xff0c;因此它的计算速度比sigmoid 和 tanh 更快。</li></ul> <p>当然&#xff0c;它也有缺点&#xff1a;Dead ReLU 问题。当输入为负时&#xff0c;ReLU 完全失效&#xff0c;在正向传播过程中&#xff0c;这不是问题。有些区域很敏感&#xff0c;有些则不敏感。但是在反向传播过程中&#xff0c;如果输入负数&#xff0c;则梯度将完全为零&#xff0c;sigmoid函数和 tanh 函数也具有相同的问题&#xff1b;</p> <p>我们发现ReLU 函数的输出为 0 或正数&#xff0c;这意味着 ReLU 函数不是以 0 为中心的函数。</p> <p>除了上面的3种激活函数之外&#xff0c;还有很多其他激活函数&#xff0c;比如Relu函数就有很多变种&#xff0c;如PRelu、LeakyRelu等。</p> <p>每种激活函数&#xff0c;都在一种或几种特定的深度学习网络中有优势。</p> <p>判断一个激活函数的好与坏&#xff0c;绝不仅仅是从函数的数学表达式上来判断&#xff0c;而是需要在实际的深度学习网络中不断地实验和实践&#xff0c;来找到最适合这个网络的激活函数。</p> <h5 id="h22">池化</h5> <p>在 Resnet50 的网络中&#xff0c;存在一个最大池化层和一个全局平均池化层&#xff0c;而在其他的CNN网络中&#xff0c;也会时而看到池化层的出现。</p> <p>那么&#xff0c;什么是池化层呢&#xff1f;在CNN网络中&#xff0c;池化层又能起到什么作用&#xff1f;</p> <p>池化一般接在卷积过程后。</p> <p>池化&#xff0c;也叫Pooling&#xff0c;其本质其实就是采样。</p> <p>池化对于输入的图片&#xff0c;选择某种方式对其进行压缩&#xff0c;以加快神经网络的运算速度。这里说的某种方式&#xff0c;其实就是池化的算法&#xff0c;比如最大池化或平均池化。</p> <p style="text-align:center;"><img src="https://i-blog.csdnimg.cn/blog_migrate/fd834f4fae9bafbeb1655c6e5d94a7ae.png" alt="Resnet50算法原理_卷积核_39" style="width: 658px; visibility: visible;" /></p> <p> <br /></p> <p>池化过程类似于卷积过程。</p> <p>上图表示的就是对一个图片邻域内的值&#xff0c;用一个2x2 的池化kernel&#xff0c;步长为2进行扫描&#xff0c;选择最大值输出&#xff0c;称为最大池化。</p> <p>最大池化MaxPool 常用的参数为 kernel  &#61; 2, stride &#61; 2 &#xff0c;这样的参数处理效果就是输出图片的高度、宽度减半&#xff0c;通道数不变。</p> <p>还有一种叫平均池化&#xff0c;和最大池化类似&#xff0c;就是将取区域内最大值改为求这个区域的平均值。</p> <h5 id="h23">和卷积类比</h5> <p>和卷积类比&#xff0c;池化操作也有一个核(kernel)&#xff0c;但它不是卷积核。</p> <p>池化的核只负责框定某次池化计算需要的图片的范围&#xff0c;核里面并没有数据参与计算&#xff0c;也就是说&#xff0c;在训练过程中&#xff0c;池化层不像卷积层那样&#xff0c;需要学习权重。</p> <p>另一个与卷积不同的是&#xff0c;在卷积的计算中&#xff0c;需要channel维度的数据累加&#xff0c;而池化层的channel维度的数据不需要累加&#xff0c;每个channel中的数据是独立的&#xff0c;这也导致&#xff0c;池化的运算复杂度比卷积简单很多</p> <p>下图是卷积和池化的示意图&#xff0c;通过两张图&#xff0c;大致可以看出两者的不同。<br /></p> <p style="text-align:center;"><img src="https://i-blog.csdnimg.cn/blog_migrate/369b3bbd6af45e8ce0cac2.gif" alt="Resnet50算法原理_卷积核_40" style="width: 761px; visibility: visible;" /></p> <p> 卷积示意图</p> <p style="text-align:center;"><img src="https://i-blog.csdnimg.cn/blog_migrate/b8959ae6606d95a7e86.gif" alt="Resnet50算法原理_卷积_41" style="width: 1000px; visibility: visible;" /></p> <p> 池化示意图</p> <h5 id="h24">神经网络中为什么需要池化层</h5> <h5 id="h25">特征不变性</h5> <p>池化层支持了一定的平移、旋转、拉伸不变性&#xff0c;这个特性有点抽丝剥茧的意思&#xff0c;用小特征对大特征进行精简。</p> <p>如下图&#xff0c;通过池化操作&#xff0c;图片中的黑色特征在输出图片中&#xff0c;仍然被保留了下来&#xff0c;虽然有些许的误差。</p> <p style="text-align:center;"><img src="https://i-blog.csdnimg.cn/blog_migrate/5fbfd889c78028d8831bf19319.gif" alt="Resnet50算法原理_卷积_42" style="width: 600px; visibility: visible;" /></p> <p>池化的特征不变性</p> <h5 id="h26">降维</h5> <p>如上的例子&#xff0c;图片经过池化的操作&#xff0c;可以减小图片的尺寸&#xff0c;同时又可以保留相应特征&#xff0c;所以主要用来降维。</p> <h5 id="h27">防止过拟合</h5> <p>由于池化层没有需要学习的参数&#xff0c;因此&#xff0c;在训练的过程中&#xff0c;可以在一定程度上防止过拟合的发生。</p> <h5 id="h28">降低模型计算量</h5> <p>池化的操作&#xff0c;会在保留原始图片特征不变的情况下&#xff0c;将图片尺寸缩小&#xff0c;从而减少整个模型的计算量。</p> <p>在神经网络的训练和推理过程中&#xff0c;一个维度的计算量减倍&#xff0c;往往会带来一个数量级的性能提升&#xff0c;尤其是在训练过程动辄迭代成千上万次的训练场景中。</p> <p>使用池化算法&#xff0c;在减少图片的宽和高尺寸的同时&#xff0c;也会给模型的训练和推理带来更优异的性能提升。</p> <h5 id="h29">全连接</h5> <p>在网络的最后&#xff0c;还有一个全连接层&#xff08;Fully Connected Layer&#xff09;。CNN中为什么还需要一个全连接层呢&#xff0c;它的作用是什么&#xff1f;</p> <p> <br /></p> <p style="text-align:center;"><img src="https://i-blog.csdnimg.cn/blog_migrate/67cb74ae3e163e069388c395d8e48c7c.png" alt="Resnet50算法原理_卷积核_43" style="width: 454px; visibility: visible;" /></p> <p>全连接层&#xff0c;指的是每一个结点都与上一层的所有结点相连&#xff08;示意图如上图所示&#xff09;&#xff0c;用来把前面几层提取到的特征综合起来。</p> <p>由于其全连接的特性&#xff0c;一般全连接层的参数也是最多的。</p> <p>前面提到卷积的作用是完成图像的特征提取&#xff0c;那提取出了特征之后&#xff0c;还是无法根据提取的一堆特征来完成图像的识别。因为卷积层提取出来的特征太多了&#xff01;</p> <p>举个例子&#xff0c;一张画着猫咪的图片&#xff0c;经过几十层卷积的特征提取&#xff0c;很有可能已经提取出了几十个甚至上百个特征&#xff0c;那我们如何根据这几十上百个特征来最终确认&#xff0c;这是一只猫呢&#xff1f;</p> <p>把上面的问题细化并且简化一下&#xff0c;不说几十上百个特征&#xff0c;就说卷积层只提取了3个特征&#xff1a;分别是鼻子&#xff0c;耳朵和眼睛。</p> <p>实际上&#xff0c;有鼻子、耳朵和眼睛这三个特征的动物有很多&#xff0c;我们并不能只根据某个动物有鼻子、耳朵和眼睛&#xff0c;就把它简单的认为是一只猫。</p> <p style="text-align:center;"><img src="https://i-blog.csdnimg.cn/blog_migrate/6af34ebd5bc460cf8977f90b2fae3696.png" alt="Resnet50算法原理_人工智能_44" style="width: 456px; visibility: visible;" /></p> <p>那么就需要一种方法&#xff0c;把鼻子、耳朵和眼睛这三个特征进一步融合&#xff0c;使得神经网络看到这三个特征的融合集合之后&#xff0c;可以区分这是一只猫而不是一只狗。</p> <p>上面的例子比较简单&#xff0c;实际网络中卷积提取的特征远远不止3个&#xff0c;而是成百上千个&#xff0c;将这些特征进一步融合的算法&#xff0c;就是全连接。</p> <p>或者说&#xff0c;全连接&#xff0c;可以完成特征的进一步融合。</p> <p>使得神经网络最终看到的特征是个全局特征&#xff08;一只猫&#xff09;&#xff0c;而不是局部特征&#xff08;眼睛或者鼻子&#xff09;。</p> <p>知乎上对于这个问题有个比较形象的回答&#xff0c;大意是说&#xff1a;</p> <p>假设你是一只蚂蚁&#xff0c;你的任务是找小面包。</p> <p>这时候你的视野比较窄&#xff0c;只能看到很小一片区域&#xff0c;也就只能看到一个大面包的部分。</p> <p>当你找到一片面包之后&#xff0c;你根本不知道你找到的是不是全部的面包&#xff0c;所以你们所有的蚂蚁开了个会&#xff0c;互相把自己找到的面包的信息分享出来&#xff0c;通过开会分享&#xff0c;最终你们确认&#xff0c;哦&#xff0c;你们找到了一个大面包。</p> <p>上面说的蚂蚁开会的过程&#xff0c;就是全连接&#xff0c;这也是为什么&#xff0c;全连接需要把所有的节点都连接起来&#xff0c;尽可能的完成所有节点的信息共享。</p> <p>说到这&#xff0c;大概就能理解全连接的作用了吧。</p> <h5 id="h30">卷积和全连接作用的对比</h5> <p>卷积是对图像的局部区域进行连接&#xff0c;完成的是感受野内的长宽方向以及channel 方向的数据连接。</p> <p>因此&#xff0c;卷积提取的特征是局部特征&#xff0c;也就是说&#xff0c;卷积是“不是庐山真面目&#xff0c;只缘身在此山中”。</p> <p>而全连接层呢&#xff1f;它每次完成的是所有channel方向的连接&#xff0c;它看到的是全局特征。全连接是“不畏浮云遮望眼&#xff0c;自缘身在最高层”。</p> <p>除此之外&#xff0c;卷积和全连接在算法上是可以转换的。通常情况下&#xff0c;在进行全连接的计算时&#xff0c;可以把它等效于卷积核为1x1的卷积运算。</p> <p>全连接的作用&#xff0c;说的学术专业一点&#xff0c;就是把卷积层学到的特征空间映射到样本标记空间。</p> <p>说的通俗易懂点&#xff0c;就是把卷积学到的一堆特征互相融合一下&#xff0c;变成样本&#xff08;比如一只猫&#xff09;的代表。</p> <p>在使用Resnet50对ImageNet2012数据集进行分类时&#xff0c;最终完成某个图片的分类&#xff0c;全连接层会输出一个值&#xff0c;每个值都对应一个索引。</p> <p>在ImageNet 中&#xff0c;281-287都代表猫。比如282这个索引&#xff0c;代表的是一只虎猫&#xff0c;而这个索引&#xff0c;就是把所有的虎猫的特征进行了融合后计算而来的。</p> <ul><li>_281 n0 猫, tabby, tabby cat _</li><li>_282 n0 猫, tiger cat _</li><li>_283 n0 猫, Persian cat _</li><li>_284 n0 猫, Siamese cat, Siamese _</li><li>_285 n0 猫, Egyptian cat _</li><li>_286 n0 猫, cougar, puma, catamount, mountain lion, painter, panther, Felis concolor _</li><li><em>287 n0 猫, lynx, catamount</em></li></ul> <h5 id="h31">SoftMax</h5> <p>很多同学在做深度学习时&#xff0c;都会遇到难以理解的算法&#xff0c;SoftMax肯定是其中一个。</p> <p>初学者大都对它一知半解&#xff0c;只知道SoftMax可以用来做分类&#xff0c;输出属于某个类别的概率。</p> <p>但是&#xff0c;为什么要用SoftMax呢&#xff1f;这个算法又是如何将神经网络推理的数值&#xff0c;转换为一个类别的分类的呢&#xff1f;</p> <h5 id="h32">先看下softmax的应用场景。</h5> <p>假设要使用神经网络做图片分类&#xff0c;现在有3个类别&#xff1a;猫&#xff0c;狗&#xff0c;人。</p> <p>给你下面一张图片&#xff0c;神经网络需要在这3个类别中选出一个。</p> <p> <br /></p> <p style="text-align:center;"><img src="https://i-blog.csdnimg.cn/blog_migrate/44ea3b7f7767b60a06a39849fb650c93.png" alt="Resnet50算法原理_卷积_45" style="width: 454px; visibility: visible;" /></p> <p>上图人眼一看就知道是猫咪&#xff0c;但是神经网络需要通过计算才知道。</p> <p>好&#xff0c;我们使用Resnet50这一分类网络进行推理运算&#xff0c;算到最后面的全连接层时&#xff0c;全连接输出了3个数值&#xff0c;分别为2&#xff0c;1&#xff0c;0.1。</p> <p>看过前面文章的同学可能知道&#xff0c;全连接输出的数值&#xff0c;代表了这一分类的得分。</p> <p>现在我们假设这三个分类的得分分别为&#xff1a;</p> <p style="text-align:center;"><img src="https://i-blog.csdnimg.cn/blog_migrate/fd9cbb73c8bda097fbd28c076fb48a45.png" alt="Resnet50算法原理_卷积_46" style="width: 1045px; visibility: visible;" /></p> <p>猫得了2分&#xff0c;狗得了1分&#xff0c;人得了0.1分。<br /></p> <p>单看这个结果&#xff0c;我们大概知道&#xff0c;因为猫的得分最高&#xff0c;那最终神经网络会认为这张图片是一只猫。</p> <p>错了&#xff01;错在哪&#xff1f;至少两点。</p> <p>第一&#xff0c;神经网络最终选择某一分类&#xff0c;依据的不是得分&#xff0c;而是概率&#xff0c;也就是说&#xff0c;最终神经网络会选择一个概率最高的分类作为它识别的结果。</p> <p>为什么要把得分转为概率呢&#xff1f;因为多分类模型中&#xff0c;输出值为概率更利于反向推导和模型的迭代&#xff0c;概率之间更好的计算距离&#xff0c;而数值之间的计算的距离是无含义的。所以&#xff0c;我们需要一种方法&#xff0c;将上面的得分转换为概率。</p> <p>第二&#xff0c;得分是神经网络经过了几十层卷积运算计算出来的。例子中猫的得分是2&#xff0c;狗的得分是1&#xff0c;人的得分是0.1&#xff0c;我们可以比较肯定的说&#xff0c;因为猫的得分最高&#xff0c;而且比狗和人都高很多&#xff0c;肯定就是猫。</p> <p>但实际中&#xff0c;有很大的可能算出的猫的得分是2.1&#xff0c;狗的得分是1.9&#xff0c;人的得分是0.1。这个时候&#xff0c;我们可能就没有像刚才那么肯定了。</p> <p>因为猫的得分和狗的得分相差很少&#xff0c;而且两者都很高&#xff01;</p> <p>由于上述两个原因的存在&#xff0c;人们想到了SoftMax算法。而这个算法&#xff0c;也几乎完美地解决了这两个问题。</p> <h5 id="h33">为什么叫SoftMax以及它的实现原理</h5> <p>不知你有没有想过&#xff0c;为什么这个算法叫SoftMax呢&#xff1f;Soft 是软的意思&#xff0c;与之对应肯定有 HardMax。</p> <p>而 HardMax&#xff0c;可以理解为我们平时认知的Max。比如给你两个数&#xff08;3, 4), 那么这两个数的 HardMax(3,4) 结果就是4。</p> <p>这个逻辑&#xff0c;小学生学会了10以内的加减法都知道。</p> <p>但正如上面所说&#xff0c;SoftMax不一样&#xff0c;它是要处理多个类别分类的问题。并且&#xff0c;需要把每个分类的得分值换算成概率&#xff0c;同时解决两个分类得分值接近的问题。</p> <p>先从公式上看&#xff0c;SoftMmax是怎么做到的。</p> <p style="text-align:center;"><img src="https://i-blog.csdnimg.cn/blog_migrate/b8bbe0e6d8f52961f3009b03ce083673.png" alt="Resnet50算法原理_人工智能_47" style="width: 415px; visibility: visible;" /></p> <p>公式中&#xff0c;每个 z 就对应了多个分类的得分值。SoftMax对得分值进行了如下处理&#xff1a;</p> <ul><li>以e为底数进行了指数运算&#xff0c;算出每个分类的 eZi&#xff0c;作为公式的分子</li><li>分母为各分类得分指数运算的加和。</li><li>根据公式很自然可以想到&#xff0c;各个分类的SoftMax值加在一起是1&#xff0c;也就是100%。</li></ul> <p>所以&#xff0c;每个分类的SoftMax的值&#xff0c;就是将得分转化为了概率&#xff0c;所有分类的概率加在一起是100%。</p> <p>这个公式很自然的就解决了从得分映射到概率的问题。那&#xff0c;它又是怎么解决两个得分相近的问题的呢&#xff1f;</p> <p>其实也很简单&#xff0c;重点在选择的指数操作上。我们知道指数的曲线是下面的样子。</p> <p style="text-align:center;"><img src="https://i-blog.csdnimg.cn/blog_migrate/59928aab088af142eaf73dbb.png" alt="Resnet50算法原理_卷积_48" style="width: 462px; visibility: visible;" /></p> <p>指数曲线&#xff0c;恒大于零&#xff0c;并且在正半轴&#xff0c;离零越远&#xff0c;增长越快&#xff08;指数增长&#xff09;</p> <p>指数增长的特性就是&#xff0c;横轴变化很小的量&#xff0c;纵轴就会有很大的变化。所以&#xff0c;从1.9变化到2.1&#xff0c;经过指数的运算&#xff0c;两者的差距立马被的拉大了。</p> <p>从而&#xff0c;我们可以更加明确的知道&#xff0c;图片的分类应该属于最大的那个。下面是将猫、狗、人三个分类经过SoftMax计算之后得到的概率。</p> <p style="text-align:center;"><img src="https://i-blog.csdnimg.cn/blog_migrate/6ae6813c8b2794cbfc1b3b0aea81cffd.png" alt="Resnet50算法原理_数据_49" style="width: 1055px; visibility: visible;" /></p> <p>可以看到&#xff0c;分类是猫的概率遥遥领先。所以&#xff0c;神经网络在经过softmax层之后&#xff0c;会以70%的概率&#xff0c;认为这张图片是一张猫。</p> <p>这就是SoftMax的底层原理。</p> <p>指数让得分大的分类最终的概率更大&#xff0c;得分小的分类最终的概率更小&#xff0c;而得分为负数的分类&#xff0c;几乎可以忽略。</p> <p style="text-align:center;"><img src="https://i-blog.csdnimg.cn/blog_migrate/5825d3f86a800ce1354a8ffbfa95413c.png" alt="Resnet50算法原理_卷积_50" style="width: 967px; visibility: visible;" /></p> <p>写到这&#xff0c;基本上整个Resnet50中涉及到到的算法和相关的背景知识都写完了。<br /></p> <p>其实Resnet50这个网络比较简单&#xff0c;涉及到的算法也很少&#xff0c;只有卷积、池化、激活、全连接、Softmax 这些算法。</p> <p>而其使用背景就更简单&#xff0c;仅仅是为了更好的完成图像的分类。阅读完本文后&#xff0c;如感觉有收获&#xff0c;欢迎点赞转发。</p> 

讯享网
小讯
上一篇 2025-04-23 13:06
下一篇 2025-04-22 07:38

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/147172.html