学习笔记三:深度学习DNN"/>
学习笔记三:深度学习DNN
文章目录
- 一、BP神经网络(MLP)
- 1.1 感知机模型及其局限性
- 1.2 BP神经网络基本原理
- 1.3 softmax多分类、求导
- 1.4 二分类使用softmax还是sigmoid好?
- 1.5 为什么要用激活函数?
- 1.6 梯度下降和链式求导
- 1.7度量学习
- 二、矩阵求导术
- 2.1 标量对向量求导
- 2.2 向量对向量求导
- 2.3 标量对矩阵的矩阵
- 2.4 向量求导及链式法则
- 2.5 BP反向传播
- 2.5 激活函数及其导数
- 三、神经网络调优
- 3.1 激活函数得选型
- 3.2 Relu激活函数及其变体
- 3.3 高斯误差线性单元激活函数gelu
- 3.3.1 GELU概述
- 3.3.2 GELU数学表示
- 3.4 Xavier权重初始化
一、BP神经网络(MLP)
1.1 感知机模型及其局限性
感知机是一个有若干输入和一个输出的模型:
z = ∑ i = 1 m w i x i + b z=\sum\limits_{i=1}^mw_ix_i + b z=i=1∑mwixi+b
接着是一个神经元激活函数:
s i g n ( z ) = { − 1 z < 0 1 z ≥ 0 sign(z)= \begin{cases} -1& {z<0}\\ 1& {z\geq 0} \end{cases} sign(z)={−11z<0z≥0
从而得到我们想要的输出结果1或者-1。
所以MLP模型只能用于二元分类,且无法学习比较复杂的非线性模型,因此在工业界无法使用。而神经网络则在感知机的模型上做了扩展来解决这个问题。
- 加入了隐藏层,隐藏层可以有多层,增强模型的表达能力
- 输出层的神经元可以有多个输出,这样模型可以灵活的应用于分类回归
- 对激活函数做扩展,感知机的激活函数是 s i g n ( z ) sign(z) sign(z),虽然简单但是处理能力有限,因此神经网络中一般使用的其他的激活函数
为什么要使用神经网络模型?
-
逻辑回归对于如今越来越复杂的任务效果越来越差,主要是难以处理线性不可分的数据,LR处理线性不可分,一般是特征变换和特征组合,将低维空间线性不可分的数据在高维空间中线性可分
-
改良方式有几种,本质上都是对原始输入特征做文章。但都是针对特定场景设计。如果实际场景中特征组合在设计之外,模型无能为力
- 人工组合高维特征,将特征升维至高维空间。但是会耗费较多人力,而且需要对业务理解很深
- 自动交叉二阶特征,例如FM模型。缺点是只能进行二阶交叉
- SVM+核方法:可以将特征投影到高维空间。缺点是核函数种类有限,升维具有局限性,运算量巨大。
-
构建BP神经网络(也叫MLP多层感知器),用线性变换+非线性函数激活的方式进行特征变换。以分类为目的进行学习的时候,网络中的参数会以分类正确为目的自行调整,也就是自动提取合适的特征。(回归问题,去掉最后一层的激活函数就行。输出层激活函数只是为了结果有概率意义)神经网络最大的惊喜就是自动组合特征。
1.2 BP神经网络基本原理
- MLP网络中,每个节点都接收前一层所有节点的信号的加权和,累加后进行激活,再传入下一层的节点。这个过程和动物神经元细胞传递信号的过程类似,所以叫神经网络,各节点称为神经元。
- 每层神经元个数称为神经网络的宽度,层数称为神经网络的深度。所以多层神经网络称为深度神经网络DNN。
- 神经元数据过多会造成过拟合和运算量过大。层中神经元过多,相当于该层转换后的特征维度过高,会造成维数灾难。
- DNN仍然使用交叉熵损失函数。
1.3 softmax多分类、求导
- 机器学习模型相对简单,参数较少。可以通过训练N个二分类模型来完成多分类。而深度学习中,模型参数较多,训练多个模型不实际。而且多分类任务的前层特征变换是一致的,没必要训练多个模型。一般是输出层采用softmax函数来完成。
- softmax做多分类只适用于类别互斥且和为1的情况。如果和不为1,可以加一个其它类。不互斥时不能保证分母能归一化。
- 如果多个标签有交集不互斥,比如歌曲分类:流行、摇滚、抒情、怀旧的时候,类别不互斥,且还存在其它类。此时不能用softmax,而应该用sigmoid进行多个二分类,文本分类要注意。
- 为什么叫softmax。如果是max做分类结果,那就是直接输出one-hot向量[0,0,1],非连续函数不好求导。而softmax就要软一点,softmax(np.array([0.2,0.1,0.8]))=array([0.2683, 0.2428, 0.4889]),可求导。
1.4 二分类使用softmax还是sigmoid好?
参考《速通8-DNN神经网络学习笔记》
a、b两类二分类时:
s o f t m a x ( x = a ) = e a e a + e b = 1 1 + e b − a = 1 1 + e − d softmax(x=a)=\frac{e^{a}}{e^{a}+e^{b}}=\frac{1}{1+e^{b-a}}=\frac{1}{1+e^{-d}} softmax(x=a)=ea+ebea=1+eb−a1=1+e−d1
- softmax等于分别学习w1和w2,而sigmoid等于学这两个的差值就行了。sigmoid是softmax在二分类上的特例。二分类时sigmoid更好。因为我们只关注w1和w2的差值,但是不关心其具体的值。
- softmax的运算量很大,因为要考虑别的概率值。一般只在神经网络最后一层用(多分类时)。中间层神经元各算各的,不需要考虑别的w数值,所以中间层不需要softmax函数。
- softmax函数分子:通过指数函数,将实数输出映射到零到正无穷。softmax函数分母:将所有结果相加,进行归一化。
- softmax和sigmoid一样有饱和区,x变化几乎不会引起softmax输出的变化,而且饱和区导数几乎为0,无法有效学习。所以需要合适的初始化,控制前层输出的值域。
- 两个函数的代码实现如下图
import numpy as np
import matplotlib.pyplot as plt
def sigmoid(x):return 1.0/(1+np.exp(-x))sigmoid_inputs = np.arange(-10,10)
sigmoid_outputs=sigmoid(sigmoid_inputs)
print("Sigmoid Function Input :: {}".format(sigmoid_inputs))
print("Sigmoid Function Output :: {}".format(sigmoid_outputs))plt.plot(sigmoid_inputs,sigmoid_outputs)
plt.xlabel("Sigmoid Inputs")
plt.ylabel("Sigmoid Outputs")
plt.show()
def softmax(x):orig_shape=x.shapeif len(x.shape)>1:#Matrix#shift max whithin each rowconstant_shift=np.max(x,axis=1).reshape(1,-1)x-=constant_shiftx=np.exp(x)normlize=np.sum(x,axis=1).reshape(1,-1)x/=normlizeelse:#vectorconstant_shift=np.max(x)x-=constant_shiftx=np.exp(x)normlize=np.sum(x)x/=normlizeassert x.shape==orig_shapereturn xsoftmax_inputs = np.arange(-10,10)
softmax_outputs=softmax(softmax_inputs)
print("Sigmoid Function Input :: {}".format(softmax_inputs))
print("Sigmoid Function Output :: {}".format(softmax_outputs))
# 画图像
plt.plot(softmax_inputs,softmax_outputs)
plt.xlabel("Softmax Inputs")
plt.ylabel("Softmax Outputs")
plt.show()
1.5 为什么要用激活函数?
- 没有非线性函数,多层线性变换等于一层,丧失了深度的意义。
- 非线性变换才能够解决线性不可分的问题,组合更丰富的高阶特征。
第二点从泰勒公式来说明:
泰勒公式:
任意函数可以写成多项式的和。 x 0 x_0 x0是函数定义域上的任意一点,x在a的附近。 R n R_n Rn是补偿,n越大 R n R_n Rn越小。n→∞, R n → 0 R_n→0 Rn→0。
- y=kx+b, f ′ = k f{}'=k f′=k, f ′ ′ = 0 f{}'{}'=0 f′′=0,往后导数都是0 。
- y= e x e^x ex, f ′ = e x f{}'=e^x f′=ex, f ′ ′ = e x f{}'{}'=e^x f′′=ex…各阶导数都是 e x e^x ex。
- 线性变换:二阶导数以后都是0
- 合适的非线性变换(常见激活函数):高阶导数都不为0,尽量保留高阶项。
- 如果神经网络不加激活函数,f(d)=d(二阶导往后都为0)
- 如果神经网络加了sigmoid函数,其n阶导数为nf(1-f),则: f ( d ) = s i g m o i d ( d ) = f ( x 0 ) + f ( x 0 ) ′ d + 2 f ( x 0 ) ′ ′ d 2 + 6 f ( x 0 ) ′ ′ ′ d 3 . . . f(d)=sigmoid(d)=f({x_0})+f({x_0})'d+2f({x_0})'{}'d^{2}+6f({x_0})'{}'{}'d^{3}... f(d)=sigmoid(d)=f(x0)+f(x0)′d+2f(x0)′′d2+6f(x0)′′′d3...
d = ∑ i = 1 n w i x i d=\sum_{i=1}^{n} w_ix_i d=∑i=1nwixi,第三项就有 d = ∑ i = 1 n ( w i x i ) 2 d=\sum_{i=1}^{n} (w_ix_i)^2 d=∑i=1n(wixi)2,等于FM模型二阶特征组合。第四项是三阶特征组合…。所以加入激活函数等于做了高阶特征组合。
为什么不用 e x e^x ex做激活函数,因为其各阶导数都一样。即各阶特征组合权重都很大,没有衰减过程。而好的特征我们希望组合特征的越高阶,对应权重越低,否则过拟合。不衰减,模型会认为必须满足所有高阶特征才预测出正确结果,泛化能力很弱。所以希望模型可以捕获高阶特征,但是不能过于依赖高阶特征。
没有激活函数的两层线性变换的意义:
1. Self-Attention模型的作用是提取语义级别的信息(不存在长距离依赖),而FFNN是在各个时序上对特征进行非线性变换,提高网络表达能力。
FFNN有两层,是将attention层输出先扩维4倍再降维。为什么这么做?神经网络中线性连接可以写成 d l = W l ⋅ x d^l=W^{l}\cdot x dl=Wl⋅x。其中三者维度分别是m×1、m×n、n×1。
- m>n:升维,将特征进行各种类型的特征组合,提高模型分辨能力
- m<n:降维,去除区分度低的组合特征
所以一般神经网络都是先做宽再做窄。
- 有的时候不加激活函数可以节省大量参数。
例如:向量x是100×1维,向量y是1000×1维。直接变换,则W是1000×100=10万维。 y = W x y=Wx y=Wx
如果经过一个10×1的中间向量z进行变换有:
z = M x z=Mx z=Mx
y = N z y=Nz y=Nz
也可以达到y=NMx变换的目的,但是M是10×100维,N是1000×10维,总共11000维,大大减少参数量。
1.6 梯度下降和链式求导
1.7度量学习
二、矩阵求导术
线性代数参考《线性代数一(基本概念)》
2.1 标量对向量求导
例如标量z对向量X求导,就是看X各元素变化对z的影响。所以结果是z对X各元素求导,结果也是一个同尺寸向量。
2.2 向量对向量求导
列向量对行向量求导,结果是一个矩阵,方便后面进行链式求导中的导数连乘。(向量既可以写成列的形式,也可以写成行的形式。列向量可以直接对列向量求导,但是维数太多不便于操作,而且没法进行连乘,一般没人这么干。)
- m×1维列向量 y y y对n×1维列向量 x x x求导,等于 y y y的每个元素 y i y_{i} yi分别对 x x x求导,得到m×1维导数。而导数每个元素都是标量对向量求导,结果是n×1维列向量。所以最终结果是mn×1维的列向量。行向量亦然。
- 神经网络中一般都用列向量。,如果列向量 y y y对列向量 x x x求导,结果太长不便于计算。一般是 y y y对 x x x的转置求导,即 ∂ y ∂ x T \frac{\partial y}{\partial x^{T}}
更多推荐
学习笔记三:深度学习DNN
发布评论