深度学习的基本概念 简单概括是,使用神经网络,进行不断学习训练和修正的过程。训练集就是有答案的习题,神经网络每一次写完作业都会去对答案,如果有偏差,就自动修正参数,谓之迭代,直到最后错误率越接近0越好。
一、单个神经元 数学模型(MP模型)
1943年,心理学家W.S.McCulloch和数理逻辑学家W.Pitts基于神经元的生理特征,建立了单个神经元的数学模型(MP模型)
文章图片
神经元的数学模型推导公式:
y k = φ ( ∑ i = 1 m ω k i x i + b k ) y_k = φ(\sum_{i=1}^mω_{ki}x_{i}+b_k) yk?=φ(i=1∑m?ωki?xi?+bk?)
公式参数:
- x:输入
- ω:权重
- b:偏置(b绝大部分情况下是一个向量,可以类比一下一元一次方程 y = k x + b y=kx+b y=kx+b的 b b b,使数值产生整体的偏移。)
- 激活函数φ:一个非线性函数,目的是将输入进行变化映射,得出输出信号。它模拟大脑电信号,对较小的刺激进行弱化甚至抑制,对较明显的刺激继续传递。
正向传播
数据是从输入到输出的流向传递过来的。当然,它是在一个假设有合适的w和b的基础上的,才可以实现对现实环境的正确拟合。但是,在实际过程中我们无法得知w和b的值具体是多少才算是正常。于是,我们加入一个训练过程,通过反向误差传递的方法让模型自动来修正,最终得到合适的W和b。
反向传播:
BP(Back Propagation process),BP是在估计权重的时候的必要过程,可被称为BP算法。深度学习的目的就是通过最小化损失函数,来估计神经网络的权重。 在这个过程中,需要用到BP进行反向传播。(损失函数下文会讲)
损失,指神经网络输出结果与实际值的差值(可为均方差等形式的差值)。为了让损失值最小化,我们选择一个损失函数,让这个表达式有最小值,接着通过对其求导的方式,找到最小值时刻的函数切线斜率(也就是梯度),让w和b沿着这个梯度来调整。
至于每次调整多少,我们引入一个叫做 “学习率” 的参数来控制,这样通过不断的迭代,使误差逐步接近最小值,从而达到我们的目标。
通常BP的步骤为:
- 明确损失函数
- 明确参数调整策略
激活函数(activation function): (同上文“一个非线性函数,目的是将输入进行变化映射,得出输出信号。它模拟大脑电信号,对较小的刺激进行弱化甚至抑制,对较明显的刺激继续传递。 ”)激活函数(也译作激励函数)的主要作用就是加入非线性因素,以解决线性模型表达能力不足的缺陷,在整个神经网络里起到至关重要的作用。
因为神经网络的数据基础是处处可微的,所以选取的激活函数要保证数据输入与输出也是可微的。在神经网络里常用的函数有Sigmoid、Tanh和Relu等,具体实现自行百度。
处理分类: softmax回归,对一些数据进行多种分类。softmax从字面上来说,可以分成soft和max两个部分。max故名思议就是最大值的意思。softmax的核心在于soft,而soft有软的含义,与之相对的是hard硬。很多场景中需要我们找出数组所有元素中值最大的元素,实质上都是求的hardmax。softmax的含义就在于不再唯一的确定某一个最大值,而是为每个输出分类的结果都赋予一个概率值,表示属于每个类别的可能性。如果判断输入属于某一个类的概率大于属于其他类的概率,那么这个类对应的值就逼近于1,其他类的值就逼近于0。该算法主要应用于多分类,而且是互斥的。公式为
s o f t m a x ( z i ) = e z i ∑ c = 1 C e z c softmax(z_i)=\frac{e^{z_i}}{\sum_{c=1}^Ce^{z_c}} softmax(zi?)=∑c=1C?ezc?ezi??
其中 z i z_i zi?为第i个节点的输出值,C为输出节点的个数,即分类的类别个数。通过softmax函数就可以将多分类的输出值转换为范围在[0, 1]和为1的概率分布。把所有值的e的n次方计算出来,求和后算每个值占的比率,保证总和为1,一般就可以认为softmax得出的是概率。
可参考:一文详解Softmax函数
损失函数: 损失函数是决定网络学习质量的关键。无论什么样的网络结构,如果使用的损失函数不正确,最终都将难以训练出正确的模型。使用于描述模型预测值与真实值的差距大小。一般有两种比较常见的算法——均值平方差(MSE)和交叉熵。
- 均值平方差(Mean Squared Error,MSE):y为真实标签,p即predict值。均方误差的值越小,表明模型越好。类似的损失算法还有均方根误差(RMSE)(将MSE开平方),平均绝对值误差(MAD)(对一个真实值与预测值相减的绝对值取平均值)等。
1 n ∑ i = 1 n ( y ? p ) 2 \frac{1}{n}\sum_{i=1}^n(y-p)^2 n1?i=1∑n?(y?p)2 - 交叉熵损失函数(Cross Entropy Loss Function):交叉熵一般用于分类问题上,表达的意思为预测输入样本属于某一类的概率。公式中y代表真实值分类(0或1),a代表预测值。交叉熵也是值越小,代表预测结果越准。
注意:这里用于计算的a也是通过分布统一化处理的(或者是经过Sigmoid函数激活等),取值范围在0~1之间。
c = 1 n ∑ x [ y l n a + ( 1 ? y ) l n ( 1 ? a ) ] c=\frac{1}{n}\sum_{x}[ylna+(1-y)ln(1-a)] c=n1?x∑?[ylna+(1?y)ln(1?a)]
损失函数的选取取决于输入标签数据的类型:如果输入的是实数、无界的值,损失函数使用MSE;如果输入标签是位矢量(分类label),使用交叉熵会更合适。
三、多层神经网络 1、传统前馈神经网络——对隐藏层概念的引入
单个神经元的拟合仅适用于线性可分(可被直线或平面分割)的情况。
文章图片
文章图片
文章图片
对于这类高维非线性问题,我们引入了一个隐藏层概念用来解决问题。
对于这个隐藏层来说,它的作用就是将“线性不可分”的数据映射到高维空间来,使映射后的数据变得“线性可分”。
我们通过异或数据集来介绍这种隐藏层的作用:
- 异或数据:来源于异或操作,两个数相同时,输出为0,不相同时输出为1。表示为两类数据就是(0,0)和(1,1)为一类,(0,1)和(1,0)为一类。
- 网络模型:本例使用了一个隐藏层来解决这个问题(如图)
文章图片
- 定义变量
第一步定义变量,在网络参数的定义中,输入是“2”代表两个数,输出是“1”代表最终的结果,再放一个隐藏层,该隐藏层里有两个节点。输入占位符为x,输出为y,学习率为0.0001。 - 定义学习参数
这里以字典的方式定义权重W和b,里面的h1代表隐藏层,h2代表最终的输出层。 - 定义网络模型
该例中模型的正向结构入口为x,经过与第一层的w相乘再加上b,通过Relu函数(大于0的留下,否则一律为0)进行激活转化,最终生成layer_1,再将layer_1代入第二层,使用Tanh激活(-1~1)函数生成最终的输出y_pred。
模型的反向使用均值平方差(即对预测值与真实值的差取平均值)计算loss,最终使用AdamOptimizer进行优化。 - 以下用Tensorflow进行代码演示:
# 定义变量
import tensorflow as tf
import numpy as nplearning_rate = 1e-4# 0.0001
n_input = 2 # 输入层节点个数
n_label = 1 # 最终的结果
n_hidden = 2 # 隐藏层节点个数x = tf.placeholder(tf.float32, [None,n_input])
y = tf.placeholder(tf.float32, [None, n_label])# 定义学习参数
weights = {
'h1': tf.Variable(tf.truncated_normal([n_input, n_hidden],stddev=0.1)),
'h2': tf.Variable(tf. truncated_normal ([n_hidden, n_label],stddev=0.1))
}
biases = {
'h1': tf.Variable(tf.zeros([n_hidden])),
'h2': tf.Variable(tf.zeros([n_label]))
}# 定义网络模型
layer_1 = tf.nn.relu(tf.add(tf.matmul(x, weights['h1']), biases['h1']))
y_pred = tf.nn.tanh(tf.add(tf.matmul(layer_1, weights['h2']),biases['h2']))loss=tf.reduce_mean((y_pred-y)**2)
train_step = tf.train.AdamOptimizer(learning_rate).minimize(loss)# 构建模拟数据:手动建立X和Y数据集,形成对应的异或关系。
X=[[0,0],[0,1],[1,0],[1,1]]
Y=[[0],[1],[1],[0]]
X=np.array(X).astype('float32')
Y=np.array(Y).astype('int16')# 运行session,生成结果:首先通过迭代10000次,将模型训练出来,然后将做好的X数据集放进去生成结果,接着再生成第一层的结果。
# 加载session
sess = tf.InteractiveSession()
sess.run(tf.global_variables_initializer())# 训练
for i in range(10000):
sess.run(train_step,feed_dict={x:X,y:Y} )# 计算预测值
print(sess.run(y_pred,feed_dict={x:X}))
# 输出:已训练100000次# 查看隐藏层的输出
print(sess.run(layer_1,feed_dict={x:X}))
运行上面的程序,得到如下结果:
[[ 0.10773809]
[ 0.60417336]
[ 0.76470393]
[ 0.26959091]]
[[ 0.00000000e+00 2.32602470e-05]
[ 7.25074887e-01 0.00000000e+00]
[ 0.00000000e+00 9.64471161e-01]
[ 2.06250161e-01 1.69421546e-05]]
第一个是4行1列的数组,用四舍五入法来取值,与我们定义的输出Y完全吻合。
第二个为4行2列的数组,为隐藏层的输出。其中第一列为隐藏层第一个节点的输出,第二列为隐藏层第二个节点的输出,将它们四舍五入取整显示如下:
[[ 0 0]
[ 1 0]
[ 0 1]
[ 0 0]]
可以很明显地看出,最后一层输出层其实是对隐藏层的AND运算,因为最终结果为[0,1,1,0]。这样就很清楚地表现了,这一个隐藏层将数据转化为线性可分的数据集,然后在输出层使用一个神经元将其分开。
在几何空间里,两个点可以定位一条直线,两条直线可以定位一个平面,两个平面可以定位一个三维空间,两个三维空间可以定位更高维的空间……
在线性可分问题上也可以这样扩展,线性可分是在一个平面里,通过一条线来分类,那么同理,如果线所在的平面升级到了三维空间,则需要通过一个平面将问题分类。如图所示,把异或数据集的输入x1、x2当成平面的两个点,输出y当作三维空间里的z轴上的坐标,那么所绘制的图形就是这样的。
文章图片
很明显,这样的数据集是很好分开的。图中,右面的比例尺指示的是纵坐标。0刻度往下,颜色由浅蓝逐渐变为深蓝;0刻度往上,颜色由浅红逐渐变为深红。作一个平行于底平面、高度为0的平面,即可将数据分开,如图中的虚平面。我们前面使用的隐藏层的两个节点,可以理解成定位中间平面的两条直线。其实,一个隐藏层的作用,就是将线性可分问题转化成平面可分问题。更多的隐藏层,就相当于转化成更高维度的空间可分问题。所以理论上通过升级空间可分的结构,是可以将任何问题分开的。
那么,是不是隐藏层越多就越好呢,可以特征划分的更清楚?
理论上是这样的,但实际这样会带来两个问题
- 层数越多参数会爆炸式增多
- 到了一定层数,再往深了加隐藏层,分类效果的增强会越来越不明显。上面那个例子,一层足以划分异或集,再加几层是要得到什么特征呢?这些特征对划分没有什么提升了。
2、卷积神经网络——隐藏层的常见功能层
但随着神经网络发展到以卷积神经网络为基础的阶段,除了输入层与输出层之外,都可以被泛称隐藏层。隐藏层不直接接受外界的信号,也不直接向外界发送信号。
隐藏层在神经网络中的作用,就是中间的黑盒子,可以认为是其他的不同功能层的一个总称。
隐藏层的形式是任意自定义的,我们在此只介绍最基础的几种隐藏层。
卷积层(convolutional layer)
- 卷积核(convolutional kernel)
卷积层的功能是对输入数据进行特征提取,其内部包含多个卷积核,组成卷积核的每个元素都对应一个权重系数W和一个偏差量b(bias vector),类似于一个前馈神经网络的神经元(neuron)。
卷积层内每个神经元都与前一层中位置接近的区域的多个神经元相连,区域的大小取决于卷积核的大小,在文献中被称为“感受野(receptive field)”,卷积核在工作时,会有规律地扫过输入特征,在感受野内对输入特征做矩阵元素乘法求和并叠加偏差量。
- 卷积层参数
卷积层参数包括卷积核大小、步长和填充,三者共同决定了卷积层输出特征图的尺寸,是卷积神经网络的超参数。
其中卷积核大小可以指定为小于输入图像尺寸的任意值,卷积核越大,可提取的输入特征越复杂。
卷积步长定义了卷积核相邻两次扫过特征图时位置的距离,卷积步长为1时,卷积核会逐个扫过特征图的元素,步长为n时会在下一次扫描跳过n-1个像素 。
由卷积核的交叉相关计算可知,随着卷积层的堆叠,特征图的尺寸会逐步减小,例如16×16的输入图像在经过单位步长、无填充的5×5的卷积核后,会输出12×12的特征图。为此,填充是在特征图通过卷积核之前人为增大其尺寸以抵消计算中尺寸收缩影响的方法。常见的填充方法为按0填充和重复边界值填充(replication padding)。
填充(padding)依据其层数和目的可分为四类:
· 有效填充(valid padding):即完全不使用填充,卷积核只允许访问特征图中包含完整感受野的位置。输出的所有像素都是输入中相同数量像素的函数。使用有效填充的卷积被称为“窄卷积(narrow convolution)”,窄卷积输出的特征图尺寸为(L-f)/s+1。
· 相同填充/半填充(same/half padding):只进行足够的填充来保持输出和输入的特征图尺寸相同。相同填充下特征图的尺寸不会缩减但输入像素中靠近边界的部分相比于中间部分对于特征图的影响更小,即存在边界像素的欠表达。使用相同填充的卷积被称为“等长卷积(equal-width convolution)”。
· 全填充(full padding):进行足够多的填充使得每个像素在每个方向上被访问的次数相同。步长为1时,全填充输出的特征图尺寸为L+f-1,大于输入值。使用全填充的卷积被称为“宽卷积(wide convolution)”
· 任意填充(arbitrary padding):介于有效填充和全填充之间,人为设定的填充,较少使用。
带入先前的例子,若16×16的输入图像在经过单位步长的5×5的卷积核之前先进行相同填充,则会在水平和垂直方向填充两层,即两侧各增加2个像素( )变为20×20大小的图像,通过卷积核后,输出的特征图尺寸为16×16,保持了原本的尺寸。
- 激励函数(activation function)
(实现方法同上文神经元的拟合原理)
卷积神经网络通常使用线性整流函数(Rectified Linear Unit, ReLU),其它类似ReLU的变体包括有斜率的ReLU(Leaky ReLU, LReLU)、参数化的ReLU(Parametric ReLU, PReLU)、随机化的ReLU(Randomized ReLU, RReLU)、指数线性单元(Exponential Linear Unit, ELU)等。在ReLU出现以前,Sigmoid函数和双曲正切函数(hyperbolic tangent)也有被使用。
激励函数操作通常在卷积核之后,一些使用预激活(preactivation)技术的算法将激励函数置于卷积核之前。
池化(pooling) 的本质,其实就是降采样。Pooling 对于输入的 Feature Map,选择某种方式对其进行降维压缩,以加快运算速度。
采用较多的一种池化过程叫最大池化(Max Pooling),其具体操作过程如下:
文章图片
池化还有平均池化、随机混合池化、谱池化等类型,具体的实现方法在此不在赘述。
【池化层没有参数、池化层没有参数、池化层没有参数】 (重要的事情说三遍)
池化的作用:
(1)保留主要特征的同时减少参数和计算量,防止过拟合。
(2)invariance(不变性),这种不变性包括translation(平移),rotation(旋转),scale(尺度)。
Pooling 层说到底还是一个特征选择,信息过滤的过程。也就是说我们损失了一部分信息,这是一个和计算性能的一个妥协,随着运算速度的不断提高,我认为这个妥协会越来越小。
现在有些网络都开始少用或者不用pooling层了。
全连接层(convolutional layer) 卷积神经网络中的全连接层等价于,上文所述传统前馈神经网络中的隐藏层。
每一个结点都与上一层的所有结点相连,用来把前边提取到的特征综合起来。由于其全相连的特性,一般全连接层的参数也是最多的。在卷积神经网络的最后,往往会出现一两层全连接层,全连接一般会把卷积输出的二维特征图转化成一维的一个向量。
3、过拟合与欠拟合问题
过拟合(overfitting)与欠拟合(underfitting)是统计学中的一组现象。过拟合是在统计模型中,由于使用的参数过多而导致模型对观测数据(训练数据)过度拟合,以至于用该模型来预测其他测试样本输出的时候与实际输出或者期望值相差很大的现象。欠拟合则刚好相反,是由于统计模型使用的参数过少,以至于得到的模型难以拟合观测数据(训练数据)的现象。
我们总是希望在机器学习训练时,机器学习模型能在新样本上很好的表现。过拟合时,通常是因为模型过于复杂,学习器把训练样本学得“太好了”,很可能把一些训练样本自身的特性当成了所有潜在样本的共性了,这样一来模型的泛化性能就下降了。欠拟合时,模型又过于简单,学习器没有很好地学到训练样本的一般性质,所以不论在训练数据还是测试数据中表现都很差。
过拟合产生的原因与解决方法
- 欠拟合产生的原因:
1. 模型复杂度过低
2. 特征量过少
- 过拟合产生的原因:
1. 模型太复杂,对神经网络来说,参数太多或特征提取能力太强,模型学到了一些偶然的特征。
2. 数据分布太单一,例如训练用的所有鸟类都在笼子里,模型很容易把笼子当成识别鸟的特征。
3. 数据噪声太大或干扰信息太多,如人脸检测,训练图像的分辨率都是几百乘几百,而人脸只占了几十到几百个像素,此时背景太大,背景信息都属于干扰信息或噪声。
4. 训练迭代次数太多,对数据反复地训练也会让模型学到偶然的特征。
- 欠拟合的解决方法:
1. 增加新特征,可以考虑加入进特征组合、高次特征,来增大假设空间
2. 添加多项式特征,这个在机器学习算法里面用的很普遍,例如将线性模型通过添加二次项或者三次项使模型泛化能力更强
3. 减少正则化参数,正则化的目的是用来防止过拟合的,但是模型出现了欠拟合,则需要减少正则化参数
4. 使用非线性模型,比如核SVM 、决策树、深度学习等模型
5. 调整模型的容量(capacity),通俗地,模型的容量是指其拟合各种函数的能力
6. 容量低的模型可能很难拟合训练集;使用集成学习方法,如Bagging ,将多个弱学习器Bagging
- 过拟合的解决方法:
1. 换一个复杂度低一点的模型或正则化,对神经网络来说,使用参数量少一点的网络。或使用正则化,通过引入范数,增强模型的泛化能力。
2. 使用不同分布的数据来训练。如数据增强,预训练等。
3. 使用图像裁剪等方法对图像进行预处理。
4. 及时地停止训练。如何判断什么时候该停止训练?使用K折交叉验证,若训练损失还在减少,而验证损失开始增加,则说明开始出现过拟合。
5. 通过每次训练时舍去一些节点来增强泛化能力(dropout)。
推荐阅读
- python|Real-Time High-Resolution Background Matting翻译
- yolov5|yolov5测试和训练自己的数据集
- 深度学习|YOLOv5训练自数据集(VOC格式)
- 3d|地理实体三维重建技术,只读这一篇就够了
- 论文输出|2021-09-03
- cnn|“看得见的”卷积神经网络(图文并茂+代码解读)(卷积神经网络可视化)
- 计算机视觉|YoloV5建立自己的数据集并进行训练
- 如何在有限算力下实现智能驾驶多任务高精度识别()
- photoshop|Tool(Adobe Photoshop)