最形象的卷积神经网络详解:从算法思想到编程实现(转载)

mark一下,感谢作者分享!


原标题:最形象的卷积神经网络详解:从算法思想到编程实现


1 新智元推荐

来源:知乎专栏 作者授权转载

作者:张觉非

【新智元导读】本文作者是阿里工程师,文章分别形象解说“卷积”和“神经网络”的概念,手绘卷积神经网络图,层层递进详细解读。最后以手写数字识别为例,使用keras库,例如kaggle数据集实现CNN,并附上代码和数据集。

一、卷积

我们在2维上说话。有两个的函数 f(x, y) 和 g(x, y)。f 和 g 的卷积就是一个新的的函数。通过下式得到:

这式子的含义是:遍览从负无穷到正无穷的全部 s 和 t 值,把 g 在 位置上的值乘上 f 在 (s, t) 位置上的值之后“加和”(积分意义上)到一起,就是为 c 在 (x, y) 位置上的值。说白了卷积就是一种“加权求和”。以 (x, y) 为中心,把 g 距离中心 位置上的值乘上 f 在 (s, t) 的值,最后加到一起。把卷积公式写成离散形式就更清楚了:

如果表示一幅 100×100 大小的灰度图像,取值 [0, 255] 区间内的整数,是图像在 (x, y) 的灰度值。范围外的 (x, y) 上的值全取0。令在 s 和 t 取 {-1,0,1}的时候有值,其他位置全是0。可以看作是一个 3×3 的网格。如下图:

图1

每个小格子里的值就是图像在 (x, y)的灰度值。每个小格子里的值就是在(s, t)的值。

图2

如上图所示,将的中心(0, 0)对准的(5, 6)。把和对应的9个位置上各自的函数值相乘,再将9个乘积加在一起,就得到了卷积值 C (5, 6)。对的每一个位置求 C值,就得到了一幅新的图像。其中有两个问题:

  1. 如果的所有值之和不等于1.0,则 C值有可能不落在 [0,255] 区间内,那就不是一个合法的图像灰度值。所以如果需要让结果是一幅图像,就得将归一化——令它的所有位置之和等于1.0;

  2. 对于边缘上的点,有可能它的周围位置超出了图像边缘。此时可以把图像边缘之外的值当做0。或者只计算其周围都不超边缘的点的 C。这样计算出来的图像 C就比原图像小一些。在上例中是小了一圈,如果覆盖范围更大,那么小的圈数更多。

上述操作其实就是对数字图像进行离散卷积操作,又叫滤波。称作卷积核滤波器。不同的滤波器起不同的作用。想象一下,如果的大小是 3×3,每个格子里的值都是1/9。那么滤波就相当于对原图像每一个点计算它周围 3×3 范围内9个图像点的灰度平均值。这应该是一种模糊。看看效果:

图3

左图是 lena 灰度原图。中图用 3×3值都为1/9的滤波器去滤,得到一个轻微模糊的图像。模糊程度不高是因为滤波器覆盖范围小。右图选取了 9×9 值为1/81的滤波器,模糊效果就较明显了。滤波器还有许多其他用处。例如下面这个滤波器:

尝试用它来滤 lena 图。注意该滤波器没有归一化(和不是1.0),故滤出来的值可能不在[0,255]之内。通过减去最小值、除以最大/最小值之差、再乘以255并取整,把结果值归一到[0,255]之内,使之成为一幅灰度图像。

图4

该滤波器把图像的边缘检测出来了。它就是 Sobel算子。图像模糊、边缘检测等等都是人们设计出来的、有专门用途的滤波器。如果搞一个 9×9 的随机滤波器,会是什么效果呢?

图5

如上图,效果也类似于模糊。因为把一个像素点的值用它周围 9×9 范围的值随机加权求和,相当于“捣浆糊”。但可以看出模糊得并不润滑。

这时我们不禁要想,如果不是由人来设计一个滤波器,而是从一个随机滤波器开始,根据某种目标、用某种方法去逐渐调整它,直到它接近我们想要的样子,可行么?这就是卷积神经网络(Convolutional Neural Network, CNN)的思想了。可调整的滤波器是CNN的“卷积”那部分;如何调整滤波器则是CNN的“神经网络”那部分。

二、神经网络

人工神经网络(Neural Network, NN)作为一个计算模型,其历史甚至要早于计算机。W.S.McCulloch 和 W.Pitts 在四十年代就提出了人工神经元模型。但是单个人工神经元甚至无法计算异或。人工智能领域的巨擘马文.明斯基认为这个计算模型是没有前途的。在那时人们已经认识到将多个人工神经元连接成网络就能克服无法计算异或的问题,但是当时没有找到多层人工神经网络的训练方法,以至于人工神经网络模型被压抑多年。直到人们找到了多层人工神经网络的训练方法,人工神经网络才迎来了辉煌。

人工神经元就是用一个数学模型简单模拟人的神经细胞。人的神经细胞有多个树突和一个伸长的轴突。一个神经元的轴突连接到其他神经元的树突,并向其传导神经脉冲。一个神经元会根据来自它的若干树突的信号决定是否从其轴突向其他神经元发出神经脉冲。

图6

一个人工神经元就是对生物神经元的数学建模。见下图。

图7

是人工神经元的输入。a 是人工神经元的输出。人工神经元将输入加权求和后再加上偏置值 b,最后再施加一个函数 f,即:

上式最后是这个式子的向量形式。P 是输入向量,W是权值向量,b 是偏置值标量 。f称为“激活函数”。激活函数可以采用多种形式。例如 Sigmoid函数:

这是单个人工神经元的定义。人工神经网络就是把这样的人工神经元互联成一个网络:一个神经元的输出作为另一个神经元的输入。神经网络可以有多种多样的拓扑结构。其中最简单的就是“多层全连接前向神经网络”。它的输入连接到网络第一层的每个神经元。前一层的每个神经元的输出连接到下一层每个神经元的输入。最后一层神经元的输出就是整个神经网络的输出。

如下图,是一个三层神经网络。它接受10个输入,也就是一个10元向量。第一层和第二层各有12个神经元。最后一层有6个神经元。就是说这个神经网络输出一个6元向量。

图8

整个神经网络的计算可以用矩阵式给出。我们给出人工神经网络单层的式子。每层的神经元个数不一样,输入/输出维度也就不一样,计算式中的矩阵和向量的行列数也就不一样,但形式是一致的。假设我们考虑的这一层是第层。它接受个输入,拥有个神经元(个输出),那么这一层的计算如下式所示:

上标 i 表示第 i 层。是输出向量,n 元,因为第 i 层有 n 个神经元。第 i 层的输入,即第 i -1 层的输出,是 m 元向量。权值矩阵 W是 n×m 矩阵:n 个神经元,每个神经元有 m 个权值。W乘以第 i -1 层输出的 m 向量,得到一个 n 向量,加上 n 元偏置向量 b,再对结果的每一个元素施以激活函数 f,最终得到第 i 层的 n 元输出向量。

若不嫌繁琐,可以将第 i -1 层的输出也展开,最终能写出一个巨大的式子。它就是整个全连接前向神经网络的计算式。可以看出整个神经网络其实就是一个向量到向量的函数。至于它是什么函数,就取决于网络拓扑结构和每一个神经元的权值和偏置值。如果随机给出权值和偏置值,那么这个神经网络是无用的。我们想要的是有用的神经网络。它应该表现出我们想要的行为。

要达到这个目的,首先准备一个从目标函数采样的包含若干“输入-输出对儿”的集合——训练集。把训练集的输入送给神经网络,得到的输出肯定不是正确的输出。因为一开始这个神经网络的行为是随机的。

把一个训练样本输入给神经网络,计算输出与正确输出的(向量)差的模平方(自己与自己的内积)。再把全部 n 个样本的差的模平方求平均,得到 e:

e 称为均方误差 mse。e 越小则神经网络的输出与正确输出越接近。神经网络的行为就与想要的行为越接近。

目标是使 e 变小。在这里 e 可以看做是全体权值和偏置值的一个函数。这就成为了一个无约束优化问题。如果能找到一个全局最小点,e 值在可接受的范围内,就可以认为这个神经网络训练好了。它能够很好地拟合目标函数。这里待优化的函数也可以是 mse 外的其他函数,统称 Cost Function,都可以用 e 表示。

经典的神经网络的训练算法是反向传播算法(BP,Back Propagation)。BP 算法属于优化理论中的梯度下降法(Gradient Descend)。将误差 e 作为全部权值 W 和全部偏置值 B的函数。算法的目的是在自变量空间内找到 e 的全局极小点。

首先随机初始化全体权值 W和全体偏置值 B,之后在自变量空间中沿误差函数 e 在该点的梯度方向的反方向(该方向上方向导数最小,函数值下降最快)前进一个步长。步长称为学习速率(Learning Rate,η)。如此反复迭代,最终(至少是期望)解运动到误差曲面的全局最小点。

下图是用 matlab训练一个极简单的神经网络。它只有单输入单输出。输入层有两个神经元,输出层有一个神经元。整个网络有4个权值加3个偏置。图中展示了固定其他权值,只把第一层第一个神经元的权值和偏置做自变量时候的 mse 曲面,以及随着算法迭代,解的运动轨迹。

图9

最终算法没有收敛到全局最优解(红+)。但是解已经运动到了一个峡谷的底部。由于底部过于平缓,解“走不动”了。所得解比最优也差不到哪去。

对于一个稍复杂的神经网络,e 对 WB的函数将是一个非常复杂的函数。求梯度需要计算该函数对每一个权值和偏置值的偏导数。所幸的是,每一个权值或偏置值的偏导数公式不会因为这个权值或偏置值距离输出层越远而越复杂。计算过程中有一个中间量,每层的权值和偏置值的偏导数都可根据后一层的以统一形式计算出来。每层再把计算过程中产生的传递给前一层。这就是“反向传播”名称的由来——沿着反向向前传。这与计算网络输出时,计算结果向后传相反。如此可逐层计算出全部权值和偏置值的偏导数,得到梯度。具体推导这里不给出了,可以参考[1]第八章和[2]第十一章。正是反向传播能够让我们训练神经网络“深处”的参数,这就是“Deep Learning”的含义。

梯度下降法有很多变体。通过调整步长 η 可以提高收敛速度;通过增加冲量可以避免解陷入局部最优点。还可以每一次不计算全部样本的 mse,而是随机取一部分样本,根据它们的 mse 更新权值。这样可以减少计算量。梯度下降是基于误差函数的一阶性质。还有其他方法基于二阶性质进行优化,比如共轭法、牛顿法等等。优化作为一门应用数学学科,是机器学习的一个重要理论基础,在理论和实现上均有众多结论和方法。参考[1]。

三、卷积神经网络

现在把卷积滤波器和神经网络两个思想结合起来。卷积滤波器无非就是一套权值。而神经网络也可以有(除全连接外的)其它拓扑结构。可以构造如下图所示意的神经网络:

图10

该神经网络接受个输入,产生个输出。图中左边的平面包含 n×n 个格子,每个格子中是一个[0,255]的整数值。它就是输入图像,也是这个神经网络的输入。右边的平面也是 n×n 个格子,每个格子是一个神经元。每个神经元根据二维位置关系连接到输入上它周围 3×3 范围内的值。每个连接有一个权值。所有神经元都如此连接(图中只画了一个,出了输入图像边缘的连接就认为连接到常数 0)。右边层的个神经元的输出就是该神经网络的输出。

这个网络有两点与全连接神经网络不同。首先它不是全连接的。右层的神经元并非连接上全部输入,而是只连接了一部分。这里的一部分就是输入图像的一个局部区域。我们常听说 CNN 能够把握图像局部特征、alphaGO 从棋局局部状态提取信息等等,就是这个意思。这样一来权值少了很多,因为连接就少了。权值其实还更少,因为每一个神经元的9个权值都是和其他神经元共享的。全部个神经元都用这共同的一组9个权值,并且不要偏置值。那么这个神经网络其实一共只有9个参数需要调整。

看了第一节的同学们都看出来了,这个神经网络不就是一个卷积滤波器么?只不过卷积核的参数未定,需要我们去训练——它是一个“可训练滤波器”。这个神经网络就已经是一个拓扑结构特别简单的 CNN 了。

试着用 sobel 算子滤出来的图片作为目标值去训练这个神经网络。给网络的输入是灰度 lena 图,正确输出是经过 sobel 算子滤波的 lena 图,见图4。这唯一的一对输入输出图片就构成了训练集。网络权值随机初始化,训练2000轮。如下图:

图11

从左上到右下依次为:初始随机滤波器输出、每个200轮训练后的滤波器输出(10幅)、最后一幅是 obel 算子的输出,也就是用作训练的目标图像。可以看到经过最初200轮后,神经网络的输出就已经和 sobel 算子的输出看不出什么差别了。后面那些轮的输出基本一样。输入与输出的均方误差 mse 随着训练轮次的变化如下图:

图12

1500轮过后,mse 基本就是0了。训练完成后网络的权值是:

与 sobel 算子比较一下:

注意训练出来的滤波器负数列在右侧而不是左侧。因为用 sobel 算子算卷积的时候也许库函数是把滤波器“反着扣上去”的。这并不重要。关键是一正列、一负列,中间零值列。正/负列值之比近似1:2:1。它就是近似的 sobel 算子。我们以训练神经网络的方式把一个随机滤波器训练成了 sobel 算子。这就是优化的魔力。alphaGO 之神奇的核心也在于此:优化。

在 CNN 中,这样的滤波器层叫做卷积层。一个卷积层可以有多个滤波器,每一个叫做一个 channel,或者叫做一个 feature map。可以给卷积层的输出施加某个激活函数 Sigmoid、tanh 等等。激活函数也构成 CNN 的一层——激活层,这样的层没有可训练的参数。

还有一种层叫做 Pooling 层。它也没有参数,起到降维的作用。将输入切分成不重叠的一些 n×n 区域。每一个区域就包含个值。从这个值计算出一个值。计算方法可以是求平均、取最大 max 等等。假设 n=2,那么4个输入变成一个输出。输出图像就是输入图像的1/4大小。若把2维的层展平成一维向量,后面可再连接一个全连接前向神经网络。

通过把这些组件进行组合就得到了一个CNN。它直接以原始图像为输入,以最终的回归或分类问题的结论为输出,内部兼有滤波图像处理和函数拟合,所有参数放在一起训练。这就是卷积神经网络。

四、举个例子

手写数字识别。数据集中一共有42000个28×28的手写数字灰度图片。十个数字(0~9)的样本数量大致相等。下图展示其中一部分(前100个):

图13

将样本集合的75%用作训练,剩下的25%用作测试。构造一个结构如下图的CNN:

图14

该CNN共有8层(不包括输入层)。它接受784元向量作为输入,就是一幅 28×28 的灰度图片。这里没有将图片变形成 28×28 再输入,因为在CNN的第一层放了一个 reshape 层,它将784元的输入向量变形成 1×28×28 的阵列。最开始那个 1× 表示只有一个 channel,因为这是灰度图像,并没有 RGB 三个 channel。

接下来放一个卷积层。它包含32个滤波器,所以它的输出维度是 32×28×28。32个滤波器搞出来32幅图像(channel),每个都是 28×28 大小。后面又是一个32个滤波器的卷积层,输出维度也是 32×28×28。

后面接上一个 Pooling 层,降降维。一个 2×2 的取平均值 Pooling 层,把输出维度减小了一半:32×14×14。接着是一个展平层,没有运算也没有参数,只变化一下数据形状:把 32×14×14 展平成了6272元向量。

该6272元向量送给后面一个三层的全连接神经网络。该网络的神经元个数是 1000×1000×10。两个隐藏层各有1000个神经元,最后的输出层有10个神经元,代表10个数字。假如第六个输出为1,其余输出为0,就表示网络判定这个手写数字为“5”(数字“0”占第一个输出,所以“5”占第六个输出)。数字“5”就编码成了:

训练集和测试集的数字标签都这么编码(one-hot 编码)。

全连接神经网络这部分的激活函数都采用了 Sigmoid。这出于我一个过时且肤浅的理解:用“弯弯绕”较多的 Sigmoid 给网络贡献非线性。实际上当代深度学习从生物神经的行为中得到启发,设计了其它一些表现优异的激活函数,比如单边线性 Relu。

误差函数采用均方误差 mse。优化算法采用 rmsprop,这是梯度下降的一个变体。它动态调整学习速率(步长 η)。训练过程持续10轮。注意这里10轮不是指当前解在解空间只运动10步。一轮是指全部31500个训练样本都送进网络迭代一次。每次权值更新以32个样本为一个 batch 提交给算法。下图展示了随着训练,mse 的下降情况:

图15

下图是分类正确率随着训练的变化情况:

图16

该CNN在测试集上的正确率(accuracy)是96.7%,各数字的准确率 / 召回率 / f1-score 如下:

该CNN对测试集10种数字分类的混淆矩阵为:

图17

训练完成神经网络后,最有趣的是将其内部权值以某种方式展现出来。看着那些神秘的、不明所以的连接强度最后竟产生表观上有意义的行为,不由让我们联想起大脑中的神经元连接竟构成了我们的记忆、人格、情感 … 引人遐思。

在CNN上就更适合做这种事情。因为卷积层训练出来的是滤波器。用这些滤波器把输入图像滤一滤,看看CNN到底“看到”了什么。下图用第一、二卷积层的32个滤波器滤了图13第8行第8列的那个手写数字“6”。32个 channel 显示如下:

图18

图19

其中有些把边缘高亮(输出值较大),有些把“6”的圈圈高亮,等等。这些就是CNN第一步滤波后“看到”的信息。再经过后面的各神经层,抽象程度逐层提高,它就这样“认出”了手写数字。

最后把代码附上。CNN使用的是 keras 库。数据集来自kaggle:这里。

五、参考书目

[1]《最优化导论》(美)Edwin K. P. Chong(美) Stanislaw H. Zak

[2]《神经网络设计》(美)Martin T.Hagan(美)Howard B.Demuth(美)Mark Beale

原文链接:https://zhuanlan.zhihu.com/p/25249694

【寻找AI独角兽】新智元联手10大资本

启动2017创业大赛

AI 创业大赛由新智元与10 家主流 AI 创投机构:蓝驰创投、红杉资本中国基金、高瓴智成人工智能基金、蓝湖资本、蓝象资本、IDG资本、高榕资本、中信建投证券、明势资本、松禾远望基金携手发起,由新智元主办,北京市中关村科技园区管理委员会、中关村科技园区海淀园管理委员会支持,是一场聚合了 AI 技术领袖和投资领袖的盛会。新智元向满怀雄心的未来AI独角兽提供强大的创投资源对接机会,顶级风投 TS 等你来拿。

http://form.mikecrm.com/gthejw

点击文章下方阅读原文,在线填写报名申请报名表。该报名表为参与评选必填资料。

如有更多介绍资料(例如BP等),可发送至 xzy100@aiera.com.cn,邮件标题请注明公司名称。如有任何咨询问题,也欢迎向该邮箱发信联系。

大赛咨询,请添加新智元微信号:返回搜狐,查看更多

责任编辑:

  • 9
    点赞
  • 54
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: CNN(卷积神经网络)是一种深度学习模型,它在计算机视觉领域中被广泛应用于图像分类、目标检测和图像生成等任务。其中,运动想象分类是一个特殊的任务,它要求网络根据输入的脑电波数据来判断用户所想象的运动。 实现运动想象分类的CNN代码首先需要准备标记好的脑电波数据集,其中包含了用户想象的运动信息及相应的标签。接着,可以使用深度学习框架(如TensorFlow或PyTorch)来搭建CNN模型。 模型的输入是脑电波数据,可以通过预处理步骤来将其表示为适当的输入格式,如向量或矩阵。然后,可以根据需求设计并添加一系列的卷积层、池化层和全连接层来构建CNN模型。在卷积层中,可以选择合适的卷积核大小和步长来提取输入数据的空间特征。在池化层中,可以使用最大池化或平均池化来降低特征图的维度。最后,通过全连接层将提取到的特征映射到不同的运动类别上。 为了增加模型的鲁棒性,可以使用批次归一化(batch normalization)和dropout等技术来防止过拟合。此外,选择合适的损失函数(如交叉熵损失)和优化器(如SGD或Adam)也是很重要的。 在训练过程中,可以通过反向传播算法来优化模型参数,使得模型能够更好地对用户的运动想象进行分类。可以使用训练集来调整模型参数,并利用验证集对模型进行评估和调整。当训练损失收敛并且模型在验证集上表现良好时,可以使用测试集来评估模型的性能。 最后,可以将训练好的模型保存下来,用来对新的脑电波数据进行运动想象分类。通过将新的脑电波数据输入到已训练好的CNN模型中,可以得到分类结果,从而判断用户的运动想象。 总之,通过使用CNN模型和适当的脑电波数据集,我们可以实现对运动想象的分类。这个过程需要设计合适的网络结构、损失函数和优化器,并利用大量的训练数据来调整模型参数,以实现良好的分类性能。 ### 回答2: 卷积神经网络(Convolutional Neural Network,CNN)是一种用于图像处理和模式识别的深度学习算法。在运动想象分类问题中,CNN可以帮助我们对运动想象活动进行分类。 首先,我们需要准备训练数据集和测试数据集。训练数据集应包含多个样本,每个样本包括运动想象的脑电图信号和对应的标签(分类)。测试数据集也是同样的格式。 接下来,我们可以使用Python编程语言和深度学习框架(如TensorFlow或PyTorch)来实现CNN的运动想象分类代码。 首先,我们定义CNN的网络结构。一个典型的CNN包含多个卷积层、池化层、全连接层和激活函数。卷积层用于提取图像特征,池化层用于降低特征的维度,全连接层用于将特征映射到具体的分类。激活函数常用的有ReLU函数。 然后,我们将训练数据集输入到CNN中进行训练。训练过程中,CNN会不断地调整网络参数,使得网络输出与标签的误差最小化。这个过程叫做反向传播(Backpropagation)。 训练完成后,我们可以使用测试数据集来评估CNN分类的性能。将测试数据输入到已经训练好的CNN中,可以获得预测的分类结果。我们可以计算预测结果与真实结果之间的误差,以此评估CNN的准确性。 最后,我们可以对新的运动想象数据进行分类。将新的脑电图信号输入到已经训练好的CNN中,可以得到预测的分类结果。 综上所述,通过CNN的卷积操作和深度学习框架,我们可以实现运动想象分类的代码。 ### 回答3: 卷积神经网络(Convolutional Neural Network, CNN)可以用于运动想象分类任务的代码实现。 首先,我们需要导入所需的库,如TensorFlow和Keras。 ```python import tensorflow as tf from tensorflow.keras import layers, models ``` 接下来,我们可以定义CNN模型。模型的架构可以根据具体任务进行设计和调整。一个简单的CNN模型可以有卷积层、池化层和全连接层。 ```python model = models.Sequential() model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(28, 28, 1))) model.add(layers.MaxPooling2D((2, 2))) model.add(layers.Conv2D(64, (3, 3), activation='relu')) model.add(layers.MaxPooling2D((2, 2))) model.add(layers.Conv2D(64, (3, 3), activation='relu')) model.add(layers.Flatten()) model.add(layers.Dense(64, activation='relu')) model.add(layers.Dense(10)) ``` 然后,我们可以编译模型,指定损失函数和优化算法。 ```python model.compile(optimizer='adam', loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True), metrics=['accuracy']) ``` 在数据准备阶段,我们可以将图像数据加载和预处理。这里以MNIST数据集为例。 ```python (train_images, train_labels), (test_images, test_labels) = tf.keras.datasets.mnist.load_data() train_images = train_images.reshape((60000, 28, 28, 1)) train_images = train_images / 255.0 test_images = test_images.reshape((10000, 28, 28, 1)) test_images = test_images / 255.0 ``` 接下来,我们可以训练模型。 ```python model.fit(train_images, train_labels, epochs=10, validation_data=(test_images, test_labels)) ``` 最后,我们可以用训练好的模型进行预测。 ```python predictions = model.predict(test_images) ``` 以上就是使用CNN实现运动想象分类的代码实现。当然,具体的实现可以根据具体情况进行调整和优化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值