深度学习基础与技巧

举报
竹叶青 发表于 2019/10/13 18:04:37 2019/10/13
【摘要】 虽然我们对人工神经网络ANN有了初步的了解,还实现了一个简单的三层神经 网络来对虚拟医疗数据进行分类。可在中间还忽略了很多细节,例如有没有其他的 激活函数可供选择?损失函数只能使用均方误差吗?如何确定梯度下降算法的参数?除了上述数学问题外,还有如何解决训练时模型预测的准确率不再提升的问题?当隐层神经元设置过多引起过度拟合时,如何通过减少过度拟合的情况来 提高网络模型的预测准确率?不懂机器学习...


top0.97ac691.png虽然我们对人工神经网络ANN有了初步的了解,还实现了一个简单的三层神经 网络来对虚拟医疗数据进行分类。可在中间还忽略了很多细节,例如有没有其他的 激活函数可供选择?损失函数只能使用均方误差吗?

如何确定梯度下降算法的参数?除了上述数学问题外,还有如何解决训练时模型预测的准确率不再提升的问题?当隐层神经元设置过多引起过度拟合时,如何通过减少过度拟合的情况来 提高网络模型的预测准确率?

不懂机器学习数学原理的算法工程师,并不能称为真正的算法工程师。不懂神经 网络数学原理的算法工程师,并不是真正的深度学习拥护者。

可毕竟“条条大路通罗马”,总有方法可以让我们少走弯路。在本文中,我们将会深入了解神经网络中激活函数、损失函数的定义和类型。

此外,在训练阶段使用的梯度下降算法中,常常需要 调节与神经网络相关的众多参数(对网络模型进行参数调整的过程称为“调参过程”), 恰当地定义好参数不仅可以加快网络模型的训练速度,还能够提升训练效果,起到事半功倍的作用。在本文结束前,我们将会讨论深度学习的一些规律和技巧。

如果发现自己训练的神经网络模型效果一般,可以回顾本文,尝试使用深度神 经网络中的一些小技巧来提升网络模型的效果。

激活函数

在正式了解神经网络的激活函数之前,我们首先思考几个问题:为什么需要激活函数?激活函数可以有哪些种类?如何选择激活函数?下面带着这几个问题来深入了解神经网络中的激活函数。

首先来看激活函数在神经网络模型中的位置,如图1-1 所示的激活函数实 际上隐藏在神经网络模型中的连接线上。前文反复强调神经网络模型中的连接是最 重要的,该连接线包括输入矩阵与权值矩阵相乘的过程,还包括激活函数对数据进 行激活的过程。

激活函数的一般性质如下。

(1)单调可微

一般情况下,我们使用梯度下降算法更新神经网络中的参数,因此必须要求激活函数可微。如果函数是单调递增的,求导后函数必大于零(方便计算),因此需要 激活函数具有单调性。



1535100591618015889.jpg

图1-1激活函数作用于/层的神经元到/+1层神经元之间

(2)限制输出值的范围

输入的数据通过神经元上的激活函数来控制输出数值的大小,该输出数值是一 个非线性值。通过激活函数求得的数值,根据极限值来判断是否需要激活该神经元。 也就是说,我们可以通过激活函数确定是否对一个神经元的输出感兴趣。

(3)非线性

因为线性模型的表达能力不够(从数据输入到与权值求和加偏置,都是在线性 函数内执行权重与输入数据进行加权求和的过程,如因此激活函数的出现还为神经网络模型加入非线性因素。

激活函数拥有上述特性,它存在的核心意义在于:一个没有激活函数的神经网络只不过是一个线性回归模型,它不能表达复杂的数据分布。神经网络中 加入了激活函数,相当于引入了非线性因素,从而解决了线性模型不能解决的 问题。

选择不同的激活函数对神经网络的训练和预测都有着不同程度的影响,下面来分析神经网络中常用的激活函数及其优缺点。

1 线性函数

如图3-2所示,线性(Linear)函数是最基本的激活函数,其因变量与自变量之间有直接的比例关系。因此,线性变换类似于线性回归。实际上,在神经网络中线性变换,意味着节点按原样通过数据信号通常与单层神经网络一起使用。线性激活函数如式(1-1)所示,代码见【代码清单1-1】。


1535100591687073843.jpg

【代码清单1-1】线性激活函数


1535100591759067265.jpg



1535100591843026064.jpg

图1-2 线性函数

 2 Sigmoid函数

如图1-3所示,Sigmoid函数是一种在不删除数据的情况下,减少数据的极值或异常值的函数。因此,它能够很好地表达激活的意思,未激活值为0,完全饱和的激活值则为1。在数学上,Sigmoid激活函数为每个类输出提供独立的概率。Sigmoid 激活函数如式(1-2)所示,代码见【代码清单1-2】。


1535100591936033714.jpg

优点:

• Sigmoid函数的输出映射在[0, 1]范围内,函数单调连续,且输出范围有限 制,优化稳定;

• 易于求导;

• 输出值为独立概率,可以用在输出层。

缺点:

• Sigmoid函数容易饱和,导致训练结果不佳;

• 其输出并不是零均值,数据存在偏差,分布不平均。

【代码清单1-2】 Sigmoid激活函数

def sigmoid(x,w = 1):

   return 1 / (1 + np.sum(np.exp(-wx))


1535100591955000650.jpg

图 1-3 Sigmoid 函数

3 双曲正切函数

如图1-4所示,双曲正切函数(Tanh) 与Sigmoid函数类似。不同的是,Tanh的 归一化范围为-1到1,而不是0到1,因此Tanh的优点是可以更容易地处理负数。 同时,因为Tanh是0均值,也就解决了 Sigmoid函数的非0均值的缺点,所以实际中Tanh函数会比Sigmoid函数更常用。 Tanh激活函数如式(1-3)所示,代码见 【代码清单1-3】。


1535100592006068591.jpg

优点:

Tanh函数比Sigmoid函数收敛速度更快,更加易于训练。其输出以0为中心,数据分布平均。

缺点:

没有改变Sigmoid函数由饱和性引起的梯度消失问题。 

【代码清单1-3】双曲正切激活函数

def tanh(x):

   return np.tanh(x)


1535100592076078976.jpg

图1-4 双曲正切函数

4  ReLU 函数

(Lennieetal.,2003)的研究表明,大脑同时被激活的神经元只有1%〜4%,这 表明神经元工作的稀疏性。从信号方面来看,神经元同时只对输入信号的少部分进行选择性响应,大量信号被刻意地屏蔽,这样可以提高神经网络的学习精度,更好地提取稀疏特征。

而ReLU函数(如图1-5所示)则满足仿生学中的稀疏性,只有当输入值高于一定数目时才激活该神经元节点。当输入值低于0时进行限制,当输入上升到某一阈值以上时,函数中的自变量与因变量呈线性关系。ReLU激活函数如式 (1-4)所示,代码见【代码清单1-4】。

relu(x)=max(0, x)


1535100592148044062.jpg

图1-5 ReLU类函数

ReLU函数对比Sigmoid函数主要有如下3点变化:

• 单侧抑制;

• 相对宽阔的兴奋边界;

• 稀疏激活性。

优点:

• 相比Sigmoid函数和Tanh函数,ReLU函数在随机梯度下降算法中能够快速收敛;

•  ReLU函数的梯度为0或常数,因此可以缓解梯度消散问题;

•  ReLU函数引入稀疏激活性,在无监督预训练时也能有较好的表现。

缺点:

•  ReLU神经元在训练中不可逆地死亡;

• 随着训练的进行,可能会出现神经元死亡、权重无法更新的现象,流经神经元的梯度从该点开始将永远是零。

正是因为ReLU函数比其他激活函数更适合在神经网络中作为激活函数,或者说优点更加明显,因此综合速率和效率,神经网络中大部分激活函数都使用了 ReLU 函数。

【代码清单1-4】 ReLU激活函数

def relu(x):

    return x if x > 0 else 0

5 Softmax函数

根据维基百科对Softmax函数的定义:Soflmax函数的本质是将一个K维的任意实数向量,压缩(映射)成另一个K维的实数向量,其中向量中的每个元素取值都介于(0, 1)范围内。

Softmax是对逻辑回归(Logistic Regression, LR)的推广,逻辑回归用于处理二分类问题,其推广Softmax回归则用于处理多分类问题。

如图1-6所示,在数学上, Softmax函数会返回输出类的互斥概率分布,例如,网络的输出为(1,1, 1,1),经过 Softmax函数后输出为(0.25, 0.25, 0.25, 0.25)。我们可以得到分类中唯一所属类别, 因此通常把Softmax作为输出层的激活函数。


1535100592191007644.jpg

图1-6 Softmax函数曲线图

下面进一步说明Softmax函数作为输出层的思路及其使用方法。现假设有一个多 分类问题,但是我们只关心这些类别的最高得分概率,那么将会使用一个带有最大 似然估计函数的Softmax输出层来获得所有类别输出概率的最大值。

例如神经网络的分类有3个,分别为“野马”“河马” “斑马”,使用Softmax作为输出层的激活函数 最后只能得到一个最大的分类概率如:野马(0.6)、河马(0.1)、斑马(0.3),其中 最大值为野马(0.6)。

如果要求每次的输出都可以获得多个分类,例如希望神经网络的预测输出既像 “野马”也像“河马”,那么我们不希望Softmax作为输出层,这里可以使用Sigmoid 函数作为输出层的激活函数更合适,因为Sigmoid函数可以为每个类别的输出提供独 立的概率。

【代码清单1-5】 Softmax激活函数

def Softmax(x):

     return np.exp(x) / np.sum(np.exp(x))

6 激活函数的选择

在选择激活函数时,一般隐层选择Leak ReLU函数会得到较为理想的效果。当 然这不是恒定的规律,我们可以尝试使用Sigmoid函数作为隐层激活函数,但注意 使用时尽量不要超过太多隐层。

另外可以使用Tanh函数来代替Sigmoid函数观察 模型的精确率曲线图。如果直接使用ReLU函数作为激活函数,注意梯度下降算 法的学习率参数7?不能设置得过高,避免神经元的大量“消亡”。

对于输出层,一 般使用Softmax函数获得同分布最高概率作为输出结果。此外,可以加入Batch Normalization (BN)层,让下一层的输入数据具有相同的分布。如果遇到神经网络训 练时收敛速度慢,或梯度爆炸或者梯度消失等无法训练的状况都可以尝试加入BN 层,然后观察其训练结果。

损失函数

在机器学习任务中,大部分监督学习算法都会有一个目标函数, 算法对该目标函数进行优化,称为优化算法的过程。例如在分类或者回归任务中, 使用损失函数作为其目标函数对算法模型进行优化。

之前,简单介绍了均方误差损失函数和交叉熵损失函数,如图1-7所示,可以清晰地观察到不同的损失函数在梯度下降过程中的收敛速度和性能都 是不同的。

特别是针对自定义的深度神经网络,深度神经网络中的输出结果包括分类和回归问题,损失函数的模型会变得更加复杂。因此了解损失函数的类型并掌握 损失函数的使用技巧,有助于加深对深度学习的认知。


1535100592299098109.jpg

图1-7使用了 MSE均方误差损失函数和交叉熵损失函数。MSE损失函数收敛速度慢,可能会陷入 局部最优解;而交叉熵损失函数的收敛速度较MSE快,且较为容易找到函数最优解

1 损失函数的定义

在神经网络中,损失函数用来评价网络模型输出的预测值与真实值Y之间的差异。这里使用来L表示损失函数,它是一个非负实值函数。损失值越小,网络模型的性能就越好,所以优化算法目的就是让损失函数尽可能 的小。

假设网络模型中有N个样本,样本的输入和输出向量为



1535100592395047992.jpg

那么总损失函数为每一个输出预测值与真实值的误差之和:


1535100592443058825.jpg

值得注意的是,机器学习问题分主要为回归和分类问题,对分类模型和回归模型进行评估时会使用不同的损失函数,下面将分别对回归模型和分类模型的损失函数进行介绍。

分类与回归的区别:

分类任务输入的是离散数据,目的是寻找决策边界,对输入的数据进行有效 的分类,如预测明天是雨天还是晴天为一个分类任务。

回归任务输入的是连续数据,目的是找到最优的拟合方法,如预测明天的气 温是多少摄氏度属于一个回归任务。

2 回归损失函数

(1) 均方误差损失函数

运用均方误差的典型回归算法有线性回归。见【代码清单1-6】,均方误差损失函数的定义如下:


1535100592466019359.jpg

【代码清单1-6】均方误差损失函数

def mean_squared_error{y_true, y_pred):

     “均方误差损失函数实现"

      return np.mean(np.square 

      (y_pred - y_true), axis=-l)

实际上,均方误差损失函数的计算公式可以看作欧式距离的计算公式。欧式距离的计算简单方便,而且是一种很好的相似性度量标准,因此通常使用MSE作为标准的衡量指标。

如果想要知道自己的神经网络模型损失函数是否选择正确,那么可以训练两个损失函数不同的网络模型,模型A损失函数使用均方误差,模型B则采用其他。 

训练后对比模型A与B的损失值曲线,如果B的损失值普遍比A小且收敛速度比 A快,那么证明模型B的训练效果比一般的训练效果好,否则就应该选择其他损失 函数。

另外由于均方误差损失函数对异常值非常敏感,平方操作会放大异常值,于是学者们又相继提出了平均绝对误差损失、均方误差对数损失、平均绝对百分比误差 损失等损失函数来避免该问题

(2) 平均绝对误差损失函数

平均绝对误差损失是对数据的绝对误差求平均。见【代码清单1-7】,平均绝对误差损失函数的定义如下:


1535100592570069769.jpg

【代码清单1-7】平均绝对误差损失函数

def mean_absolute_error(y_true, y_pred):

     "平均绝对误差损一失函数实现"

       return np.mean(np.abs (y_pred - y_true), axis=-l)

(3)均方误差对数损失函数

见【代码清单1-8】,均方误差对数损失的定义如下:


1535100592653038798.jpg

【代码清单1-8】均方误差对数损失函数

def mean—squared—logarithmic—error

     (y—true, y_pred):

     “均方误差对数损失实现”

     first—log = np. log (np. clip (y—pred, 10e-6, None) + 1.) 、

     second—log = np.log (np.clip(y—true, 10e-6, None) + 1.) 

     return np.mean  (np. square (first—log - second—log) , axis=-l)

均方误差对数损失函数的实现代码中涉及对数计算,为了避免计算log0没有意 义,因此加入一个很小的常数作为计算补偿。

(4) 平均绝对百分比误差损失函数

见【代码清单1-9】,平均绝对百分比误差损失的定义如下:


1535100592742048782.jpg

【代码清单1-9】平均绝对百分比误差损失函数

def mean—absolute—percentage—error

     (y—true, y_pred):

     “平均绝对百分比误差损失函数实现”

     diff = np.abs((y_pred - y—true) / np.clip (np.abs(y_true), 10e-6, None)) 

     return  100 * np.mean(diff, axis=-l)

(5) 回归损失函数总结

尽管针对回归模型的损失函数有很多种,但是均方误差仍然是使用最广泛的, 并且在大部分情况下,均方误差有着不错的性能,因此被用作损失函数的基本衡量指标。

MAE则会比较有效地惩罚异常值,如果数据异常值较多,需要考虑使用平均 绝对误差损失作为损失函数。一般情况下,为了不让数据出现太多异常值,可以对数据进行预处理操作。

均方误差对数损失与均方误差的计算过程类似,多了对每个输出数据进行对数计算,目的是缩小函数输出的范围值。平均绝对百分比误差损失则计算预测值与真实值的相对误差。均方误差对数损失与平均绝对百分比误差损失实际上是用来处理大范围数据的,但是在神经网络中,我们常把输入数据归一化到一 个合理范围的(如[-1, 1]),然后再使用均方误差或者平均绝对误差损失来计算损失。

为什么神经网络中常把输入数据归一化到合理范围内?

因为小范围的数据方便GPU/CPU进行计算,并能提高浮点运算精度。方便观察数据的变化趋势和变化形式。

3 分类损失函数

(1) Logistic损失函数

神经网络中涉及多分类问题时最常用的是Logistic损失函数。神经网络模型会为每一个分类产生一个有效的概率。为了让某一分类的概率最大,而引入了最大似然 估计函数。

在最大似然估计函数中,定义一个损失函数为loss,公式表示样本X在分类Y的情况下,使概率达到最大值。换句话说,就是利用已知的样本X分布,找到最有可能的参数,使样本A:属于:F的概率最大。

假设二分类有 


1535100592762082665.jpg

因此对于多分类有:


1535100592843074519.jpg

在这里使用最大似然函数,目的是使每个分类都最大化,预测其所属正确分类 的概率:


1535100592885021427.jpg

(2)负对数似然损失函数

为了方便数学运算,在处理概率乘积时通常把最大似然函数转化为概率的对数, 这样可以把最大似然函数中的连乘转化为求和。

在前面加一个负号之后,最大化概率等价于寻找最小化的损失。最后,Logistic损失函数变成了常见的负对数似 然函数:


1535100592903009866.jpg

(3)交叉熵损失函数

见【代码清单1-10】,由于Logistic损失函数和负对数似然损失函数都只能处理二分类问题,从两个类别扩展到M个类别,于是有了交叉熵损失函数:


1535100592925007999.jpg

【代码清单1-10】交叉熵损失函数

def cross一entropy(y_true, y_pred):

     “交叉熵损失实现”

      return -np.sum (y_true * np.log(y_pred + 10e-6))

(4)Hinge损失函数

运用Hinge损失的典型分类器是SVM算法,因为Hinge损失可以用来解决间隔最大化问题。当分类模型需要硬分类结果的,例如分类结果是0或1、-1或1的二分类数据,Hinge损失无疑是最方便的选择。见【代码清单1-11】,Hinge损失函数 的定义如下:


1535100592945039513.jpg

【代码清单1-11】 Hinge损失函数

def hinge(y—true, y—pred):

      “Hinge损失实现”

       return np.mean(np.maximum(1. - y—true * y—pred, 0•), axis=-l)

(5)指数损失函数

【代码清单1-12】指数损失函数

def exponential(y_truef y_pred):

     return np.sum (np.exp(-y_true * y_pred))

4 神经网络中常用的损失函数

神经网络中的损失函数可以自定义,前提是需要考虑数据本身和用于求解的优 化方案。换句话说,自定义损失函数需要考虑输入的数据形式和对损失函数求导的 算法。

自定义损失函数其实是有些难度的,在实际工程项目上,结合激活函数来选 择损失函数是常见的做法,常用组合有以下3种。

(1) ReLU + MSE

均方误差损失函数无法处理梯度消失问题,而使用Leak ReLU激活函数能够减少计算时梯度消失的问题,因此在神经网络中如果需要使用均方误差损失函数,一 般采用Leak ReLU等可以减少梯度消失的激活函数。另外,由于均方误差具有普遍性,一般作为衡量损失值的标准,因此使用均方误差作为损失函数表现既不会太好也不至于太差。

(2)Sigmoid + Logistic

Sigmoid函数会引起梯度消失问题:根据链式求导法,Sigmoid函数求导后由多个[0,1]范围的数进行连乘,如其导数形式为当其中一个数很小时, 连成后会无限趋近于零直至最后消失。而类Logistic损失函数求导时,加上对数后 连乘操作转化为求和操作,在一定程度上避免了梯度消失,所以我们经常可以看到 Sigmoid激活函数+交叉摘损失函数的组合。

(3)Softmax + Logisitc

在数学上,Softmax激活函数会返回输出类的互斥概率分布,也就是能把离散的 输出转换为一个同分布互斥的概率,如(0.2, 0.8)。另外,类Logisitc损失函数是基 于概率的最大似然估计函数而来的,因此输出概率化能够更加方便优化算法进行求 导和计算,所以我们经常可以看到输出层使用Softmax激活函数+交叉熵损失函数 的组合。

1535100592950032066.jpg

《深度学习原理与实践》

陈仲铭,彭凌西 著

本书系统全面、循序渐进地介绍了深度学习的各方面知识,包括技术经验、使用技巧和实践案例。本书详细介绍了目前深度学习相关的常用网络模型,以及不同网络模型的算法原理和核心思想。本书利用大量的实例代码对网络模型进行了分析,这些案例能够加深读者对网络模型的认识。

此外,本书还提供完整的进阶内容和对应案例,让读者全面深入地了解深度学习的知识和技巧,达到学以致用的目的。

本文转载自异步社区

原文链接:

https://www.epubit.com/articleDetails?id=N48a36721-57d2-48fd-90d1-26f16a7d212f


【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。