机器学习——神经网络基础与手写数字识别(MNIST)学习记录

学习文档

RT-Thread 卷积神经网络(CNN) 手写体识别 (MNIST)

报错解决

(1)CUDA缺少文件

在这里插入图片描述

解决方法

解决tensorflow-gpu 2.1出现错误“Could not load dynamic library ‘cudart64_101.dll’

(2)tensorflow更新后库文件被删除导致无法导入

在这里插入图片描述

解决方法

ModuleNotFoundError: No module named ‘tensorflow.examples.tutorials’

建议卸载你刚下载的tensorflow的CPU和GPU版,因为最新版都是没有tutorials这个库的。我看过比较新的2.3版本的,依然有,所以可以下载。

pip uninstall tensorflow-cpu tensorflow-gpu
pip install tensorflow==2.3

也可以直接复制这个链接下载

https://gitee.com/irving_gao/tensorflow-0.6.0/repository/archive/r2.3.zip

机器学习学习心得

其实神经网络的模型非常简单,用到的数学知识也不多,只需要知道矩阵乘法,函数求导就可以了。

线性回归问题

线性回归方程

要做机器学习训练预测,我们首先得知道自己训练的模型是什么样的,还是以最经典的线性回归模型为例,后面的人工神经网络 (ANN) 其实可以看做多个线性回归组合。那么什么是线性回归模型呢?

比如下面图上这些散点,希望能找到一条直线进行拟合,线性回归拟合的模型就是:
在这里插入图片描述
不过上面的公式通常使用另外一种表示方法,最终的预测值也就是 y 通常用 hθ (hypothesis) 表示,而它的下标 θ 代表不同训练参数也就是 k, b。这样模型就成了:
在这里插入图片描述
所以 θ0 对应着 b,θ1 对应着k。但是这样表示模型还不够通用,比如 x 可能不是一个一维向量,例如经典的房价预测,我们要知道房价,可能需要房子大小,房间数等很多因素,因此把上面的用更通用的方法表示:
在这里插入图片描述
θ 需要一个转置 θT,是因为我们通常都习惯使用列向量上面这个公式和 y=kx+b 其实是一样的,只是换了一种表示方法而已,不过这种表示方法就更加通用,而且也更加简洁优美了:
在这里插入图片描述

评价指标

为了让上面的模型能够很好的拟合这些散点,我们的目标就是改变模型参数 θ0 和 θ1,也就是这条直线的斜率和截距,让它能很好的反应散点的趋势,下面的动画就很直观的反应了训练过程。
在这里插入图片描述

一个很直接的想法就是求出所有散点实际值 y 和我们模型的测试值 hθ 相差的绝对值,这个评价指标我们就称为损失函数 J(θ) (cost function)
在这里插入图片描述

函数右边之所以除以了2是为了求倒数的时候更加方便,因为如果右边的公式求导,上面的平方就会得到一个2,刚好和分母里的2抵消了。

这样我们就有了评价指标了,损失函数计算出来的值越小越好,这样就知道当前的模型是不时能很好地满足需求,下一步就是告诉模型该如何往更好的方向优化了,这就是训练 (Training) 过程。

模型训练

为了让模型的参数 θ 能够往更好的方向运动,也就是很自然的想法就是向下坡的方向走,比如上面的损失函数其实是个双曲线,我们只要沿着下坡的方向走总能走到函数的最低点:
在这里插入图片描述

那么什么是"下坡"的方向呢?其实就是导数的方向,从上面的动画也可以看出来,黑点一直是沿着切线方向逐渐走到最低点的,如果我们对损失函数求导,也就是对 J(θ) 求导
在这里插入图片描述
我们**现在知道 θ 应该往哪个方向走了,那每一次应该走多远呢?**就像上面的动画那样,黑点就算知道了运动方向,每一次运动多少也是需要确定的。这个每次运动的多少称之为学习速率 α (learning rate),这样我们就知道参数每次应该向哪个方向运动多少了:
在这里插入图片描述
这种训练方法就是很有名的 梯度下降法(Gradient Descent),当然现在也有很多改进的训练方法例如 Adam,其实原理都差不多,这里就不做过多的介绍了。

总结

机器学习的流程总结出来就是,我们先要设计一个模型,然后定义一个评价指标称之为损失函数,这样我们就知道怎么去判断模型的好坏,接下来就是用一种训练方法,让模型参数能朝着能让损失函数减少的方向运动当损失函数几乎不再减少的时候,我们就可以认为训练结束了最终训练得到的就是模型的参数,使用训练好的模型我们就可以对其他的数据进行预测了。

非线性回归问题

我们回到手写体识别的例子,上面介绍的线性回归最后得到的是一个连续的数值,但是手写体识别最后的目标是得到一个离散的数值,也就是 0-9,那么这要怎么做到呢?
在这里插入图片描述
这个就是上一部分的模型,其实很简单,只需要在最后的结果再加一个 sigmoid 函数(激活函数),把最终得到的结果限制在 0-1 就可以了。通过激活函数将连续量变为一个0和1的离散量。
在这里插入图片描述
就像上面图中的公式那样,sigmoid 函数就是:
在这里插入图片描述
如果把它应用到线性回归的模型,我们就得到了一个非线性回归模型,也就是 Logistic Regression:
在这里插入图片描述
这样就可以确保我们最后得到的结果肯定是在 0-1 之间了,然后我们可以定义如果最后的结果大于 0.5 就是 1,小于 0.5 就是 0,这样一个连续的输出就被离散了。

总结

非线性回归问题本质上仍是线性回归问题,只是将线性回归最后得出的连续输出量用激活函数进行离散处理,使其变为0和1的输出。
非线性回归问题和线性回归时解决问题的方式相同,建立模型、建立评估指标(损失函数,通过损失函数判断模型下降方向)、确定学习率和训练方法(决定损失函数下降率和最快下降到达最优的关键参数),训练。

人工神经网络 (ANN)

现在我们介绍了连续的线性回归模型 Linear Regression,和离散的非线性回归模型 Logistic Regression,模型都非常简单,写在纸上也就不过几厘米的长度。那么这么简单的模型到底是怎么组合成非常好用的神经网络的呢?

其实上面的模型可以看做是只有一层的神经网络,我们输入 x 经过一次计算就得到输出 hθ 了:
在这里插入图片描述
如果我们不那么快得到计算结果,而是在中间再插入一层呢?就得到了有一层隐藏层的神经网络了。在这里插入图片描述
上面这张图里,我们用 a 代表 激活函数 (activation function) 的输出激活函数也就是上一部分提到的 sigmoid 函数,为了将输出限制在 0-1,如果不这么做,很有可能经过几层神经网络的计算,输出值就爆炸到一个很大很大的数了。当然除了 sigmoid 函数外,激活函数还有很多,例如下一部分在卷积神经网络里非常常用的 Relu

另外,我们用带括号的上标代表神经网络的层数。例如 a(1) 代表第一层神经网络输出。当然,第一层就是输入层,并不需要经过任何计算,所以可以看到图上的 a(1)=x,第一层的激活函数输出直接就是我们的输入 x。但是,θ(1) 不是代表第一层的参数,而是第一层与第二层之间的参数,毕竟参数存在于两层网络之间的计算过程。

于是,我们可以总结一下上面的神经网络结构:
在这里插入图片描述
如果我们设置最后的输出层节点是 10 个,那就刚好可以用来表示 0-9 这 10 个数字了。

如果我们再多增加几个隐藏层,是不是看起来就有点像是互相连接的神经元了?
在这里插入图片描述如果我们再深入一点这样我们就得到一个深度神经网络了:
在这里插入图片描述
如果你想知道,具体应当选多少层隐藏层,每个隐藏层应该选几个节点,这就跟你从哪里来,要到哪里去一样,是神经网络的终极问题了。

最后,神经网络的训练方法是用的 反向传播 (Back Propagation)

卷积神经网络 (CNN)

终于到了后面会用到的卷积神经网络了,从前面的介绍可以看到,其实神经网络的模型非常简单,用到的数学知识也不多,只需要知道矩阵乘法,函数求导就可以了,而深度神经网络只不过是反复地进行矩阵乘法和激活函数的运算:
在这里插入图片描述这样重复相同的运算显得有些单调了,下面要介绍的卷积神经网络就引入了更多更有意思的操作,主要有:

  • Cov2D
  • Maxpooling
  • Relu
  • Dropout
  • Flatten
  • Dense
  • Softmax

接下来就对这些算子逐一介绍。

Conv2D

首先图像领域的神经网络最大的特点就是引入了卷积操作,虽然这个名字看起来有点神秘,其实卷积运算非常简单。

这里说明一下为什么要引入卷积运算,尽管前面的矩阵乘法其实已经可以解决很多问题了,但是一旦到了图像领域,对一个 1920*1080 的图像做乘法,就是一个 [1, 2,073,600] 的矩阵了,这个运算量已经不算小了,而用卷积操作,计算量就会大大缩减;另一方面,如果用矩阵乘法,把一个二维的图像压缩成一个一维的向量,其实就丢失了像素点在上下左右方向相互关联的信息,例如一个像素点和周围的颜色通常比较相近,这些信息很多时候是很重要的图像信息。

介绍完了卷积操作的优势,那么到底什么是卷积运算呢?其实卷积就是简单的加减乘除,我们需要一幅图像,然后是一个卷积核 (Kernel):
在这里插入图片描述
上面这张图像经过一个 3x3 的卷积核操作,就很好地把图像的边缘提取出来了,下面这个动画就很清晰地介绍了矩阵运算:
在这里插入图片描述
上面动画用到的卷积核是一个 3x3 的矩阵:
在这里插入图片描述

如果我们把动画暂停一下:
在这里插入图片描述

可以看到卷积操作实际上就是把卷积核在图像上按照行列扫描一遍,把对应位置的数字相乘,然后求和,例如上面的左上角的卷积结果 4 是这么计算得到的 (这里用 ∗ 代表卷积):
在这里插入图片描述

当然上面的计算过程用等号连接是不严谨的,不过可以方便地说明卷积的计算过程。可以看到,卷积的计算量相比全连接的神经网络是非常小的,而且保留了图像在二维空间的关联性,所以在图像领域应用地非常多。

卷积操作非常好用,但是卷积后图像大小变小了,例如上面的 5x5 矩阵经过一个 3x3 的卷积核运算最后得到的是一个 3x3 的矩阵,所以有的时候为了保持图像大小不变,会在图像周围一圈用 0 填充,这个操作称之为 padding

但是 padding 也没有办法完全保证图像大小不变,因为上面动画的卷积核每次都只向一个方向运动一格,如果每次运动 2 格,那么 5x5 的图像经过 3x3 的卷积就成了 2x2 的矩阵了,卷积核每次移动的步数我们称之为 stride

下面是一幅图像经过卷积运算后得到的图像大小计算公式:
在这里插入图片描述
比如上面图像宽度 W = 5,卷积核大小 F = 3,没有使用 padding 所以 P = 0,每次移动步数 S = 1:
在这里插入图片描述
这里说明一下,上面的计算都是针对一个卷积核而言的(是一个卷积核的输出OUTPUT),实际上一层卷积层可能有多个卷积核,而且实际上很多 CNN 模型也是卷积核随着层数往后,越来越多的。

Maxpooling

上面提到卷积可以通过 padding 保持图像大小不变,但是很多时候我们希望能随着模型的推进,逐渐减小图像大小,因为最后的输出例如手写体识别,实际上只有 0-9 这 10 个数字,但是图像的输入却是 1920x1080,所以 maxpooling 就是为了减少图像尺寸的

其实这个计算比卷积要简单多了:本质上就是取区域内的最大值。
在这里插入图片描述
比如左边 4x4 的输入,经过 2x2 的 maxpooling,其实就是把左上角 2x2 的方块取最大值:
在这里插入图片描述
所以这样一个 4x4 的矩阵经过 2x2 的 maxpooling 一下尺寸就缩小了一半,这也就是 maxpooling 的目的了。

Relu

之前介绍 sigmoid 函数的时候,提到过它是激活函数的一种,而 Relu 就是另一种在图像领域更为常用的激活函数, Relu 相比 sigmoid 就非常简单了:
在这里插入图片描述
其实就是当数字小于0的时候取0,大于0的时候保持不变。就这么简单。

Dropout

到这里一共介绍了3个算子,conv2d, maxpooling,relu,每一个的运算都非常简单,但是 Dropout 甚至更简单,连计算都没有,于是在这个部分一个公式都没有。

之前没有提到模型过拟合的问题,因为神经网络模型在训练过程中,很有可能出现模型对自己提供的训练集拟合非常好,但是一旦碰到没有见过的数据,就完全预测不出正确的结果了,这种时候就是出现了过拟合。

那么,怎么解决过拟合问题呢?Dropout 就是一种非常简单粗暴的方法,从已经训练好的参数当中,随机挑一些出来丢弃掉重置为 0,这也是为什么它的名字叫 Dropout,就是随机丢掉一些参数。

这是个简单到不可思议的方法,但是却意外地好用,例如仅仅是在 maxpooling 后随机丢弃掉 60% 训练好的参数,就可以很好地解决过拟合问题。

Flatten

依旧是卷积神经网络的简单风格,这里也不会有公式。

Flatten 就是像字面意思那样,把一个2维的矩阵压平,比如这样一个矩阵:
在这里插入图片描述
就是这么简单 。

Dense

Dense 其实前面已经介绍过了,就是矩阵的乘法,然后加法
在这里插入图片描述
所以卷积部分其实确实不需要知道太多的数学运算。

Softmax

这一个就是最后一个算子了,比如我们要做手写体识别,那么最后的输出就会是 0-9,这将是一个 1x10 的矩阵,例如下面的预测结果 (实际上是一行,为了方便显示写成两行了)Softmax本质上就是对模型的输出结果相加并给出每个结果占总输出结果的概率值,概率大的即为预测结果。

在这里插入图片描述
上面的 1x10 的矩阵可以看到第 7 个数 0.753 远远大于其他几个数 (下标我们从 0 开始),所以我们可以知道当前预测结果是 7。 所以 softmax 会作为模型的输出层输出 10 个数字,每个数字分别代表图片是 0-9 的概率,我们取最大的一个概率就是预测结果了。

另一方面,上面 10 个数相加刚好是 1,所以其实每个数就代表一个概率,模型认为这个数是1个概率是 0.000498,是 2 的概率是 0.000027,以此类推,这么直观方便的结果就是用 softmax 计算得到的。
在这里插入图片描述
比如有两个数 [1, 2] 经过 softmax 运算:
在这里插入图片描述
最后得到的两个数字就是 [0.269, 0.731]。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值