问题
跟着问题学——深度学习基础
深度学习属于机器学习的一个子集,可以分为无监督学习、强化学习和有监督学习。在无监督学习中,由于缺乏足够的先验知识,有些数据难以进行人工标注类别或是标注成本过高,所以无监督算法通常是基于无标签数据 x 隐式的或是显式的学习数据中的概率分布。在有监督学习中,输入的数据必须是带有真实标签的样本集合,样本 x 和标签 y 必须是一一对应关系。监督算法通过学习 x 和 y 的对应关系,从中发现有效的特征分布,从而具备基于输入 x 预测输出近似y的结果。在强化学习中,样本数据更加复杂,比如在许多状态决策或是智能控制的问题上,所研究的数据通常都是结构化无规则的。强化学习当前的研究也十分火热,应用领域包括工业控制、机器人控制和网络路由。
从买香蕉说起
假如小明想去买香蕉吃,在店里询问香蕉单价为2元每斤,为了促进环保,使用塑料袋的话需要额外加1元费用,小明买了3斤,那么总价y便可以根据公式:
总价=单价*数量+塑料袋费用
计算得出,
y=2*3+1=7元;
无论买多少斤(设为x),都可以套用这个公式得出总价:
y=2x+1;
也就是说,在我们知道运算公式的情况下,给定输入,便可以得到输出。
那如果再考虑这样一种情况,大明想在某地投资一家水果店,想要根据该地其他水果店香蕉的单价(每家的价格根据折扣都不太一样)来设定一个合理的价格,便安排小明去每个水果店购买香蕉,但由于小明比较粗心,把价格标签弄丢且忘记了,只根据付款记录知道在哪家付了多少钱,回来之后又根据包装袋名称称出在每家店购买的质量,那么该如何得出合理的单价呢?
自古以来,人们便尝试在数据分析中获得规律,揭示现在,预示未来。科学家们观测收集自然界中存在的数据,做实验产生记录大量的数据,并希望通过分析这些数据,找到其内在规律。
比如在天文学研究方面的开普勒三定律,就是德国天文学家开普勒在丹麦天文学家第谷大量精确的观测数据的基础上,历经多年艰辛的推导计算,终于推导出了开普勒三定律。再比如高中课本上的遗传定律,也是孟德尔多年进行豌豆杂交实验,并研究分析实验数据归纳推理出的。
不过在当今这个信息时代,人们面对海量杂乱的数据,想要从中推理出内在规律,并利用公式或定律的方式进行描述的难度是无法想象的。
年代 数据样本个数 内存 每秒浮点计算数
1970 100(Iris) 1 KB 100 K(Intel 8080)
1980 1 K(波士顿房价) 100 KB 1 M(Intel 80186)
1990 10 K(手写字符识别) 10 MB 10 M(Intel 80486)
2000 10 M(网页) 100 MB 1 G(Intel Core)
2010 10 G(广告) 1 GB 1 T(NVIDIA C2050)
2020 1 T(社交网络) 100 GB 1 P(NVIDIA DGX-2)
因此,人们将目光转向神经科学与生物仿生学,希望通过逆向模拟人类智能机理,在数据处理上获得一定的启发与应用。伴随着计算机计算能力和存储能力的飞速提升,关于人工智能的研究也就获得了飞速的发展。
人工神经网络(英语:Artificial Neural Network,ANN),简称神经网络(Neural Network,NN)或类神经网络,是一种模仿生物神经网络(动物的中枢神经系统,特别是大脑)的结构和功能的数学模型,用于对函数进行估计或近似。
神经元模型
受生物神经元的启发,人工神经元接收来自其他神经元或外部源的输入,每个输入都有一个相关的权值参数(w),它是根据前面输入对当前神经元的重要性来确定的,对输入加权并与其他输入求和后,经过一个激活函数 f,计算得到该神经元的输出。
其中: ,
,…
为各个输入的分量;
,
,…
为各个输入分量对应的权重参数;b为偏置;f为阶跃函数,用以根据前面求和得到的数输出1或0;y为神经元的输出;
使用数学公式表示就是:
1943 年,McCulloch 和 Pitts 将生物神经系统归纳为上图所示的“M-P神经元模型”。把许多这样的神经元按照一定的层次结构连接起来,就得到了神经网络。
在这里,神经元的功能是求得输入向量与权向量的内积后,经一个非线性传递函数得到一个标量结果。进一步概括,神经元就是将前面的输入数据(特征),经过各种变换后,得到新的输出数据(特征)的结构,神经元的数量等价于输出数据的数量。在卷积神经网络中我们可以进一步观察这个。
单层神经网络——线性回归模型
单层神经网络是最基本的神经元网络形式,由有限个神经元构成,每一个神经元都会产生一个标量结果,所以需要得到多少维度的特征或输出,该层就需要多少个神经元。
我们拿神经网络入门最常见的波士顿房价预测为例,即网络由最简单的一个神经元组成(即最终输出值为标量),介绍一下神经网络的基本流程。
模型创建
房子的价格取决于很多因素,如房子的面积,房龄,地段,市场行情,城市发展状况等等(这些就是能够输出房子价格的特征),数据集里面有13个特征,这里进行简化仅说明网络结构即可,假设价格只取决于面积(平方米),房龄(年)和到市中心的距离(km),并认为三者和价格线性相关。
设房子的面积为,房龄为
,到市中心距离为
,售出价格为
。
即使我们知道是线性关系:+
但却不知道公式中的参数,
和
。而神经网络的作用就是收集大量数据,建立一个模型,学习到这些参数,然后便可以利用这些参数根据新房子的特征推测房价(看到这里,或许会有疑问,不是一直说,深度学习是黑箱子吗?这里不是获得了参数吗?这个问题我们后面再回答)。
图 单层神经网络
如图所示,我们创建了线性回归的神经网络模型,这个模型包括输入层和输出层,输入层的输入个数为2。输入个数也叫特征数或特征向量维度。输出层的输出个数为1,由于输入层并不涉及计算,按照惯例不算到神经网络的层数里,图3.1所示的神经网络的层数为1。所以,线性回归是一个单层神经网络。也可以说,神经网络的层是数据经过了几次变换得到了输出(每层都是对前面的输入特征进行了变换)。
另外,输出层中的神经元和输入层中各个输入完全连接。因此,这里的输出层又叫全连接层(fully-connected layer)或稠密层(dense layer)。后面在讲到卷积神经网络的时候会再进一步介绍。
模型训练的本质就是利用已知的数据获得想要的参数。
数据收集
数据是人工智能的基础和核心,本节暂且简单说明一下,卷积神经网络章节再详细介绍。
通过收集大量的真实数据,每组数据包括房子的真实售价和它们对应的面积,房龄和到市中心距离,我们希望在这个数据上面寻找模型参数来使模型的预测价格与真实价格的误差最小。
在机器学习术语里,该数据集被称为训练数据集(training data set)或训练集(training set),一组数据被称为一个样本(sample),数据里房子的真实售价叫作标签(label),用来预测标签的两个因素叫作特征(feature)。特征用来表征样本的特点。
假设我们采集的样本数为n,索引为i的样本的特征为,标签为
。对于索引为i的房屋,线性回归模型的房屋价格预测表达式为
也就是说输入数据的维度是n*3*1,输出维度是1,中间无隐藏层,权重参数维度为1*3。
参数初始化
我们建立好模型后,却并不知道参数是多少,那如何得到预测售价呢?答案就是先手动设置参数的初始值,方法有很多,比如全设置为0,比如随机初始化。神经网络参数初始化是深度学习中的关键步骤之一。它涉及设置神经网络中的权重和偏置的初始值。参数初始化的选择和设置对于网络的训练和性能具有重要影响。在后面我们将进一步讨论。这里我们先选择全设置为0。
损失函数
有了预测模型,我们便可以基于输入的数据特征来预测房价,那么怎么知道房价预测的准确性呢?研究人员提出来损失函数这个概念,损失函数又可称为代价函数或目标函数,是用来衡量算法模型预测结果和真实标签之间吻合程度(误差)的函数。
通常会选择非负数作为预测值和真实值之间的误差,误差越小,则模型越好。本例中选用简单的平方函数,即:
训练模型的目标便是将此损失函数的值尽可能的小。后面再介绍其它的损失函数。通常,我们用训练数据集中所有样本误差的平均来衡量模型预测的质量,在模型训练中,我们希望找出一组模型参数,来使训练样本平均损失最小。
优化算法
有了模型和初始参数,我们便得到了预测目标值;有了预测目标值和真实标签值,代入到损失函数便可以得到误差;也就是说预测值和真实值的误差是关于参数的函数,那么优化算法就是用来寻找模型参数,使得训练样本的平均损失最小。
当模型和损失函数形式较为简单时,上面的误差最小化问题的解可以直接用公式表达出来。这类解叫作解析解(analytical solution)。本节使用的线性回归和平方误差刚好属于这个范畴。
然而,大多数深度学习模型并没有解析解,只能通过优化算法有限次迭代模型参数来尽可能降低损失函数的值。这类解叫作数值解(numerical solution)。
在求数值解的优化算法中,小批量随机梯度下降(mini-batch stochastic gradient descent)在深度学习中被广泛使用。它的算法很简单:先选取一组模型参数的初始值
多层神经网络——多层感知机
隐藏层与全连接层
多层神经网络在单层神经网络的基础上引入了一到多个隐藏层(hidden layer)。隐藏层位于输入层和输出层之间。隐藏层的本质就是对输入数据的特征进行提取变换,深度学习网络设计的核心也是寻找更有效的隐藏层,使得输入数据的特征能够更高效地变换流转。
常见的多层神经网络有如下结构:
输入层(Input layer),众多神经元(Neuron)接受大量输入消息。输入的消息称为输入向量。但值得注意的是输入层一般不计入神经网络的总层数里。
输出层(Output layer),消息在神经元链接中传输、分析、权衡,形成输出结果。输出的消息称为输出向量。
隐藏层(Hidden layer),简称“隐层”,是输入层和输出层之间众多神经元和链接组成的各个层面。隐层可以有一层或多层。隐层的节点(神经元)数目不定,但数目越多神经网络的非线性越显著,从而神经网络的强健性(robustness)更显著。
从图中可以看到,第 N 层的每个神经元和第 N-1 层的所有神经元相连(这就是full connected的含义),第 N-1 层神经元的输出就是第 N 层神经元的输入
所谓的全连接层就是在前一层的输出的基础上进行一次Y=Wx+b的变化(不考虑激活函数的情况下就是一次线性变化,所谓线性变化就是平移(+b)和缩放的组合(*w))
利用神经元来构建神经网络,相邻层之间的神经元相互连接,并给每一个连接分配一个权重,如下图所示:
具体来说,给定一个小批量样本,其批量大小为
,输入数据维度为
。假设多层感知机只有一个隐藏层,其中隐藏单元个数为
。记隐藏层的输出(也称为隐藏层变量或隐藏变量)为
,最后输出为
。
我们先来看一种含单隐藏层的多层感知机的设计。其输出的计算为,也就是将隐藏层的输出直接作为输出层的输入。如果将以上两个式子联立起来,可以得到
因为隐藏层和输出层均是全连接层,可以设隐藏层的权重参数和偏差参数分别为和
,输出层的权重和偏差参数分别为
和
。
将上述公式联立可得:
可以看到,即使中间加了一个隐藏层,输出和最初输入之间仍是线性相关,其和单层神经网络仍是等价的,差别仅在于权重参数做了乘加运算,这样看来,中间加隐藏层的作用就不那么大了。为了解决这个问题,研究人员提出了神经网络的非线性单元——激活函数。
激活函数
在神经网络中,常常加入激活函数来为网络模型提供非线性特性。激活函数作为一种非线性因素加入到网络中去,能够大大提升网络表达能力。如图2-10 所示,卷积神经网络中常用的激活函数包括 Tanh 函数、Sigmoid 函数、可调参线性整流单元(Parametric Rectified Linear Unit, PReLU)函数和线性整流单元(Rectified Linear Unit, ReLU)函数函数等。
(1)Sigmoid 函数
Sigmoid 函数是一种被广泛加入到网络中去的 S 型激活函数,其表达式如下所示:
该函数可以将属于(−∞, +∞)的输入 x 映射到(0,1)区间内,函数的输出区间小,因此数据在前向传播的过程当中能够聚合不发散,而且输出区间(0,1)还可以作为概率的表示范围。但是Sigmoid 函数也有其缺点,如图 2-10 所示,在函数的饱和区域十分容易产生梯度消失现象,增加网络的训练难度。
(2)Tanh 函数
Tanh函数是Sigmoid函数的变体,其表达式如下所示:
式中,x的范围是(−∞, +∞),对应的输出范围是(-1,1),Tanh 函数以零为中心,相比 Sigmoid 函数收敛速度更快,但是仍然存在梯度消失的问题
(3)ReLU 函数
ReLU 函数是一种最常用的激活函数,其表达式如下所示:
ReLU 函数的运算非常简单,直接取 0 或 x 的最大值即可且不包含指数运算,间接提升了机器的运行效率。而且该函数与人体神经元细胞对信号的响应非常相似,积极回应正向信号,消极回应负向信号。虽然在ReLU函数的正区间内不存在饱和区有效避免了梯度消失现象,但是当输入为负数时输出为 0,神经元被抑制。
(4)PReLU 函数
PReLU 函数针对 ReLU 函数的负值输入完全被抑制问题进行了改进,其表达式如下:
式中,a是一个可以在训练中学习的参数,并不是预先设置的常数
多层感知机
多层感知机就是含有至少一个隐藏层的由全连接层组成的神经网络,且每个隐藏层的输出通过激活函数进行变换。多层感知机的层数和各隐藏层中隐藏单元个数都是超参数。以单隐藏层为例并沿用本节之前定义的符号,多层感知机按以下方式计算输出
其中表示激活函数。
前向传播与反向传播
在单层神经网络的优化算法里,我们讲到优化算法是为了寻找模型参数使得网络的损失值最小,这里详细介绍一下应用的基础——反向传播算法。
在神经网络中,梯度计算是通过反向传播算法来实现的。反向传播算法用于计算损失函数相对于网络参数(如权重和偏置)的梯度,从而进行参数的更新和优化。梯度计算的过程可以分为两个关键步骤:前向传播和反向传播。
前向传播:
输入数据通过网络的每一层,从输入层传递到输出层。在每个神经元中,进行线性变换和激活函数操作,计算每个神经元的输出值。
前向传播过程中,将输入数据逐层传递,直到得到最终的输出预测结果。
以前面的多层感知机为例:
其中表示激活函数。
设损失函数,记作L,真实标签是
,
则
图 前向传播计算图
反向传播:
在前向传播之后,计算损失函数相对于网络参数的梯度,以衡量预测结果与实际标签之间的差异。
在计算梯度的过程中,反向传播算法的基本思想是通过计算输出误差对网络中各个权重的偏导数,然后根据这些偏导数结合使用梯度下降法则调整权重,使得网络的输出误差逐渐减小,使得网络能够更好地逼近真实标签。它使用了链式法则来计算网络中每个神经元的偏导数。涉及到每个神经元的激活函数导数、权重和偏置的导数等。
反向传播算法的关键在于通过链式法则计算每个神经元的误差贡献,并根据这些误差贡献来调整权重。它使得神经网络能够学习如何将输入映射到期望的输出,并且可以处理大量的训练样本以提高网络的泛化能力。
反向传播算法通常结合使用梯度下降法则来进行权重的调整。梯度下降法则是一种基于优化的方法,通过沿着误差曲面的负梯度方向进行迭代,以找到误差最小的权重值。反向传播算法利用了梯度下降法则来计算权重调整量,从而优化神经网络的性能。
反向传播实例计算
这是一个简单的两层神经网络,输入数据是1*2的向量,中间一个含有3个神经元的隐藏层,输出层为1*1的向量,简化起见,偏置b设为0,激活函数选择ReLu,根据前面推导的公式,
给定值,
,并给定参数初始化值均为0.5;标签值(真实值)y=2;
则 ;
;
;
到了这里,神经网络的前向传播过程就已经完成了,最后输出的便是前向神经网络计算出来的预测结果,并不一定是准确值(真实的标签值y)
因此,最终输出的预测结果与y是有一定出入,然后利用上文所说的损失函数和优化算法来更新参数,使得误差最小。
最常见的损失函数就是最小二乘法损失函数:
所以这里的总损失值(误差) :
现在开始进行反向传播,反向传播的目的是为了更新权重W,至于每个权重W对最后的误差造成了多少影响,可以用整体误差对特定权重参数求偏导得出:这是根据链式法则得到的
下面分别计算上面链式当中的最后一个偏导:
到这里我们就计算出整体误差L对的偏导值,这个值的含义就是指这个参数对最后整体误差的影响程度(叫做梯度值),可正可负。
梯度更新
计算得到损失函数对参数的偏导值之后,便可以根据设置的超参数学习率η利用梯度下降法来更新参数,这里设置成0.1:
再来计算一下前面层的参数偏导数:
同上,根据学习率更新参数即可。
这就是对一个前向传播中的某个参数进行梯度更新的过程,当然这个更新过程不可能是一次完成的,在进行完一次反向传播更新梯度后紧接着会进行下一个前向传播,然后重新计算误差,这样多次循环之后会使得损失值逐渐降低,当达到某个设定值时这个循环更新梯度的过程就会停止,从而完成一整个训练流程。
总结起来,神经元梯度计算的过程是通过反向传播算法,在每一层中根据当前层的输出和上一层的梯度,计算当前层的梯度。这样,根据梯度计算的结果,可以使用特定的梯度更新算法来更新模型的参数。常用的梯度更新算法包括随机梯度下降(Stochastic Gradient Descent,SGD)、Adam等
步骤总结
以下是反向传播算法的基本步骤:
正向传播:将输入样本通过网络的前向传递,计算出网络的输出。
计算误差:将网络的输出与期望的输出进行比较,计算出网络的输出误差。
反向传播误差:从输出层开始,根据误差的链式法则,逐层计算每个神经元的误差贡献。
计算权重调整量:根据每个神经元的误差贡献,计算每个权重的调整量。通常使用梯度下降法则来计算权重调整量,即将每个权重按照其梯度方向进行微小的调整。
更新权重:将计算得到的权重调整量应用于网络中的权重,更新它们的数值。
重复以上步骤:重复执行步骤1到步骤5,直到网络的输出误差达到可接受的范围或达到预定的训练轮数。
思考以下几个问题:
1.参数权重矩阵和个别参数更新的关系:如上图是函数的变量是以矩阵的形式体现的,但在计算参数偏导时是具体到每个参数的,所以注意求偏导时函数要展开成针对参数矩阵里特定的参数。
2.反向传播的顺序;从的计算可以看到,前面网络层的参数更新依赖后面网络层的参数,所以参数如果过小,经过连乘效应,前面的参数基本得不到更新,这就是所谓的参数消失。
3.网络保存着前向传播计算得到的值,包括隐藏层,所以在反向传播计算时候可以直接拿到这些值,不过这也需要存储空间。
梯度消失/梯度爆炸
梯度消失指的是在反向传播过程中,梯度逐渐变小,导致网络难以学习。梯度爆炸指的是梯度变得非常大,导致权重更新过大,网络不稳定。
梯度消失/梯度爆炸概念:二者问题问题都是因为网络太深,网络权值更新不稳定造成的。本质上是因为梯度反向传播中的连乘效应(小于1连续相乘多次)。梯度消失时,越靠近输入层的参数w越是几乎纹丝不动;梯度爆炸时,越是靠近输入层的参数w越是上蹿下跳。
解决方法:归一初始化(normalized initialization)和中间归一化(intermediate normalization)+BN,加快网络收敛。
超参数
超参数是指在网络训练前人为指定的参数,比如前面讲到的学习率,学习率是指在梯度下降算法中更新权重时的步长。学习率过小会导致模型收敛缓慢,而学习率过大会导致模型在极小值点附近震荡或发散。一般来说,初始学习率可以设置为0.01,如果模型训练不稳定,可以尝试降低学习率。
后面会具体介绍超参数对网络训练的影响及如何调整超参数。
参考资料
https://zh.d2l.ai/index.html