目录
一、多任务计算
共享隐层, 多个任务并行训练并共享不同任务已学到的特征表示
(1)交替训练:不同任务,不同的数据集,一次优化一层,每层都有一个loss,一个optimiser
(2)联合训练:不同任务,相同的数据集,一次优化一层,每层都有一个loss,loss相加,一共一个optimiser
二、归一化、标准化normalize
- 目的
①把特征的各个维度标准化到特定的区间
②把有量纲表达式变为无量纲表达式(去除数据的单位限制) - 好处
①加快梯度下降求最优的速度,各维度取值范围差别越大,椭圆等高线会越狭长。由于梯度方向垂直于等高线方向,此时优化路线会较为曲折,迭代会很慢
②提升模型精度,不归一化会突出数值较高的指标的作用 - 方法
(1)极差变换: (不涉及距离、协方差,数据不符合正态分布时)
y i = x i − m i n ( x ) m a x ( x ) − m i n ( x ) y_i=\frac{x_i-min(x)}{max(x)-min(x)} yi=max(x)−min(x)xi−min(x)
(2)0均值标准化变换: (标准差)(用到距离时,PCA降维时)
y i = x i − m e a n ( x ) σ y_i=\frac{x_i-mean(x)}{\sigma} yi=σxi−mean(x)
三、激活函数:ReLU
- 作用:提高网络的分类能力
(1)sigmoid: y ( z ) = 1 1 + e − z , z = ∑ w i x i + b y(z) = \frac{1}{1+e^{-z}}, z = \sum w_ix_i+b y(z)=1+e−z1,z=∑wixi+b
- 缺点:
①要么接近于0,要么接近于1,会导致BP时出现梯度趋0的问题,发生梯度弥散
②输出不是关于原点中心对称的,收敛速度会变得很慢(如果输入是正的,w的梯度要么全正,要么全负)
③计算很耗时
(2)tanh: t a n h ( x ) tanh(x) tanh(x):(sigmoid图像下移0.5)解决sigmoid不关于原点对称
- 缺点:梯度仍然会发生饱和,引起梯度弥散
(3)ReLU修正线性单元(Rectified linear unit)(常用): m a x ( 0 , x ) max(0,x) max(0,x):
- 优点:
1)前向反向计算都非常快,收敛速度快
2)不容易发生梯度弥散/爆炸问题(梯度>1,爆炸;<1,弥散) - 缺点:
1)输出不是关于原点中心对称的
2)dead ReLU:永远不会被激活,参数不会更新,造成数据多样性的丢失不可逆转
①表现:网络在训练一段时间后,loss依然很大,且持续不变
为什么刚开始loss可以下降一部分,但是后来不行了?
刚开始你的 w e i g h t > 0 weight>0 weight>0,但梯度也 > 0 >0 >0,几次训练后, w e i g h t − 学 习 率 ∗ 梯 度 < 0 weight - 学习率*梯度<0 weight−学习率∗梯度<0。
②通常在两种情况下发生:
1)初始化ReLU时,把权重设置成了不能使神经元激活的数值,导致神经元不会训练
2)通常是学习率太高
(4)Leaky ReLU:
m
a
x
(
α
x
,
x
)
max(αx, x)
max(αx,x):修正dead ReLU
(5)ELU:
f
(
x
)
=
{
x
x
>
0
α
(
e
x
p
(
x
)
−
1
)
x
<
=
0
f(x)= \begin{cases} x& x>0\\ α(exp(x)-1)& x<=0 \end{cases}
f(x)={xα(exp(x)−1)x>0x<=0
继承了ReLU的优点,也不会有输出不是0中心的问题,会得到0均值的输出
(6)Maxout:
m
a
x
(
w
1
T
x
+
b
1
,
w
2
T
x
+
b
2
)
max(w_1^Tx+b_1,w_2^Tx+b_2)
max(w1Tx+b1,w2Tx+b2)
不会出现神经元失活(dead),但参数太多
- 为什么在CNN中将原先的sigmoid、tanh换成ReLU可以取得比较好的效果?
sigmoid、tanh会导致梯度弥散问题,例如sigmoid的导数的取值范围是(0, 0.25],小于1的数乘在一起,越来越小。而ReLU的导数 ∈ 0 , 1 \in{0,1} ∈0,1,这样的话只要一条路径上的导数都是1,无论神经网络是多少层,这一部分的乘积都始终为1,因此深层的梯度也可以传递到浅层中。 - 为什么在RNN中,将tanh换成ReLU不能取得类似的效果?
1)在RNN中直接把激活函数换成ReLU会导致非常大的输出值:
原始RNN表达式: a i = W f i − 1 + U x i + b i , f i = f ( a i ) a_i=Wf_{i-1}+Ux_i+b_i,f_i=f(a_i) ai=Wfi−1+Uxi+bi,fi=f(ai),原始RNN在每个阶段都共享同一个参数W,假设从某一层开始 x i , b i x_i,b_i xi,bi都为0,则最后的输出就是 f ( W f ( W f ( … ) ) ) f(Wf(Wf(…))) f(Wf(Wf(…))),某种程度上相当于W做连乘,那么只要W有一个大于1的特征值,经过若干次连乘后都会导致一个非常大的矩阵;
2)梯度爆炸:
BP时,连乘的W越来越多,ReLU可以让梯度传递,后面就会导致梯度爆炸;而CNN上每一层使用的 W i W_i Wi不同并且是稀疏矩阵,很大程度上能抵消掉梯度爆炸的影响
四、梯度优化
(1)SGD:直接根据梯度校正W:
x
+
=
−
η
∗
d
x
x+= -\eta*dx
x+=−η∗dx
(2)momentum动量更新:
v
=
α
v
−
η
∗
d
x
,
x
+
=
v
v=αv- \eta*dx,x+=v
v=αv−η∗dx,x+=v
解决梯度高度敏感于参数空间某些方向的问题;
更新时在一定程度上保留之前更新的方向,同时利用当前梯度微调最终的更新方向
当前梯度与历史同向则增强,异向则减弱
(3)NAG(Nesterov Accelerated Gradient)(Nesterov momentum):
对我们预测的位置求梯度
v
t
=
α
v
t
−
1
−
η
∗
d
f
(
x
t
−
1
+
α
v
t
−
1
)
,
x
t
=
x
t
−
1
+
v
t
v_t=αv_{t-1}-\eta*df(x_{t-1}+αv_{t-1}),x_t =x_{t-1}+ v_t
vt=αvt−1−η∗df(xt−1+αvt−1),xt=xt−1+vt
(4)AdaGrad:
c
a
c
h
e
+
=
d
x
2
,
x
+
=
−
η
∗
d
x
n
p
.
s
q
r
t
(
c
a
c
h
e
)
+
1
e
−
7
cache += dx^2,x += \frac{-\eta*dx}{np.sqrt(cache)+1e-7}
cache+=dx2,x+=np.sqrt(cache)+1e−7−η∗dx
自适应学习率,每个维度都不一样,梯度大的方向因为除的数越来越大而使步长变得越来越小,梯度小的越来越大;深度太大的时候,分母=0,x不再变化,结束训练
(5)RMSProp:解决提前结束的问题
c
a
c
h
e
=
α
∗
c
a
c
h
e
+
(
1
−
α
)
∗
d
x
2
cache = \alpha * cache + (1- \alpha) * dx^2
cache=α∗cache+(1−α)∗dx2,#
α
\alpha
α衰减率
x
+
=
−
η
∗
d
x
n
p
.
s
q
r
t
(
c
a
c
h
e
)
+
1
e
−
7
x += \frac{-\eta*dx}{np.sqrt(cache)+1e-7}
x+=np.sqrt(cache)+1e−7−η∗dx
(6)adam:RMSProp +momentum(β超参,t时间步长)
m
=
β
1
∗
m
+
(
1
−
β
1
)
∗
d
x
m = β_1 * m + (1-β_1)*dx
m=β1∗m+(1−β1)∗dx #动量,梯度的一阶矩
m
/
=
1
−
β
1
t
m /= 1-β_1^t
m/=1−β1t #偏置校正,一种针对m、v初始为0的补偿措施,在开始时把m、v变大
v
=
β
2
∗
v
+
(
1
−
β
2
)
∗
d
x
2
v = β_2 * v + (1-β_2)*dx^2
v=β2∗v+(1−β2)∗dx2 #二阶矩
v
/
=
1
−
β
2
t
v /= 1-β_2^t
v/=1−β2t
x
+
=
−
η
∗
m
n
p
.
s
q
r
t
(
v
)
+
1
e
−
7
x += \frac{-\eta*m}{np.sqrt(v)+1e-7}
x+=np.sqrt(v)+1e−7−η∗m
哪种更好?哪种都不好。应该开始阶段使用高学习率,后面降低
五、梯度下降法 vs. 牛顿法
常用的两种凸函数求极值的方法
- 梯度下降法:直接求解目标函数极小值
θ j − = α ∂ ∂ θ j J ( θ ) \theta_j -=\alpha\frac{\partial}{\partial\theta_j}J(\theta) θj−=α∂θj∂J(θ)
更新参数的方式为目标函数在当前参数取值下的梯度值,前面再加上一个步长α
α:随着迭代次数不断减小,不能到0 - 牛顿法:由泰勒展开得到,通过求解目标函数一阶导为零的参数值,进而求得最小值
θ = θ − l ′ ( θ ) l ′ ′ ( θ ) = θ − H − 1 ∇ θ l ( θ ) \theta=\theta-\frac{l'(\theta)}{l''(\theta)}=\theta-H^{-1}\nabla_\theta l(\theta) θ=θ−l′′(θ)l′(θ)=θ−H−1∇θl(θ)
牛顿法收敛速度比梯度下降法快,而且由于海森阵的逆在迭代中不断减小,起到逐渐缩小步长的效果。计算海森阵的逆比较困难,消耗时间和计算资源。
六、过拟合、欠拟合的起因,怎么解决
- 过拟合:
- 起因:
1)数据集有问题,太少,噪音多等;或者训练集和测试集特征分布不一致
2)模型对数据的拟合过于自信,非常完美的拟合上了所有数据(包括噪声) - 解决:
1)清洗数据,增大数据的数据集
2)正则化:保留所有的特征变量,但是会减小特征变量的数量级, 值越小,就越光滑,也就越简单
L1更容易产生稀疏解,但不稳定;
L2倾向于让参数趋于0,更小的参数意味着更低的复杂度
3)交叉验证
4)对神经网络:
①dropout:随机失活(把相应权重设为0),训练时让神经元以一定概率dead;在最后的全连接层前加一层Dropout,默认参数是0.5
②数据增强:平移、旋转、加噪、亮度改变、饱和度改变等
③BN:根据BN的论文来看,BN层是可以缓解过拟合问题的,而且还可以减小网络初始化、未归一化的影响。如果在归一化时因图像数量太大,没办法求得准确的标准差,可以尝试在网络的输入加一层BN。
5)对树:剪枝(预剪枝、后剪枝) - 判断:
1)训练准确率升高时测试准确率却在降低,两准确率差的特别多
2)每训练一小段时间就做一次测试,如果多次发生测试精度下降,说明可能过拟合的趋势已经发生,停止训练,或还原测试前的状态,调整参数
3)当训练集和测试集的误差收敛但却很高时,为高偏差;
当训练集和测试集的误差之间有大的差距时,为高方差;
当训练集的准确率比其他独立数据集上的测试结果的准确率要高时,一般都是过拟合;
理想情况是是找到偏差和方差都很小的情况,即收敛且误差较小
- 起因:
- 欠拟合
- 起因:模型没有很好的捕捉到数据特征,不能很好地拟合数据
- 解决:
1)添加其他特征项
2)添加多项式特征
3)减少正则化参数
七、Batch Normalization批数据的规范化
- 随着一层层隐层神经元非线性函数的处理,输入数据逐渐向取值区间内极度饱和的区域靠拢,这样在做BP时这些数据的梯度变化很慢,随着层数的增加还会导致梯度消失问题,BN做的就是把这些数据强制拉回到均值为0方差为1的正态分布中,让他们落入到对输入比较敏感的更线性一点的区域,增大导数值,增强BP信息流动性,加快收敛,也能避免梯度消失问题。
- 在每一个维度执行规范化
x ^ ( k ) = x ( k ) − E [ x ( k ) ] V a r [ x ( k ) ] \hat{x}^{(k)}=\frac{x^{(k)}-E[x^{(k)}]}{\sqrt{Var[x^{(k)}]}} x^(k)=Var[x(k)]x(k)−E[x(k)] - 优点:①加快收敛,提升稳定性(下一层不用再学习输入数据中的偏移)
②对初始化要求就没那么高了,而且支持较大的学习率 - 均值和方差怎么更新的(指数加权滑动平均)
μ = α ∗ 以 前 的 μ + ( 1 − α ) ∗ 当 前 的 μ μ = \alpha *以前的μ + (1-α) * 当前的μ μ=α∗以前的μ+(1−α)∗当前的μ (α指数衰减的参数),var同理
模型训练好之后, predict时, BN 还是要计算 x − μ σ 2 + ϵ \frac{x-μ}{\sqrt{σ^2+ϵ}} σ2+ϵx−μ , 这时的μ 和 ϵ是基于整个训练集的,比较直接的方法是在训练集上重新计算,但数据特别多时,计算量大,BN就是训练时就把μ 和 ϵ计算出来了,是近似值,两个值在训练迭代过程中相当于是在不断的moving
八、梯度弥散/爆炸
- 梯度弥散
- 什么是梯度弥散:BP时链式法则中的累乘效应和极小梯度在传递链上的连续出现,导致梯度更新无法有效到达前面的网络层,前面层的参数也就无法更新,称梯度弥散(消失)
- 解决:
①BN:把逐渐向取值区间内极度饱和区域靠拢的数据强制拉回到均值为0方差为1的正态分布中,让他们落入到对输入比较敏感的更线性一点的区域内,增大梯度,通过这种方法,在前传过程中消除梯度弥散
②shortcut/skip connection:在BP过程中更好地把梯度传到前面的层次中
- 梯度爆炸
- 什么是梯度爆炸:初始化权值过大,累乘后,梯度呈指数级增长
- 解决:
①梯度剪切:设置一个梯度剪切阈值,更新梯度时,如果梯度超过阈值,就将其强制限制在这个范围之内。
②权重正则化
③激活函数
九、dropout (全连接层)
- 随机挑一些神经元失活,置零
- 优点
①能用到更多特征,而不是强依赖于某一个特征,因为你不知道他会不会被失活
②相当于训练一个由很多小模型集成而成的大模型:每次dropout一部分后剩下的就相当于一个新模型 - 训练时用dropout,测试时不再用(不然效率很低),就会出现差异,即测试时得到的更新期望会是训练时的二倍(与失活比例有关),你就需要补偿多出来的那一倍,补偿方式为:
①改变测试:测试时,要让激活函数×失活概率
②改变训练:反向dropout:在激活函数乘随机失活过滤器之前,让过滤器除以失活概率
十、tensorflow:Graph、Operation、Tensor、Session
- 大部分开源代码、论文都支持tensorflow,对Numpy, Pandas,keras的支持,tensorboard方便
- 使用数据流图技术来进行数值计算的开源软件库(不只是一个神经网络工具包,只要能用数据流图来描述的计算过程,就能用TensorFlow)。
- 数据流图
描述有向图中的数值计算过程。节点Ops(operator)代表数学运算、输入、输出或读写等操作;边表示节点之间的联系,负责传输多维数据(Tensors:有固定的类型、级别和大小)。
1)Variables:变量,在图执行时候保持着自己的状态
2)constant是常量
3)Fetches:抓取,输出
4)Feeds:先创建特定数据类型的占位符placeholder,之后再进行数据填充 - 图计算
图的创建类似于一个 [施工阶段:构造好图/演员到位],而在 [执行阶段:Action开拍] 则利用一个session来执行图中的节点。很常见的情况是,在 [施工阶段] 创建一个图来表示神经网络,而 [执行阶段] 在图中执行一系列的训练操作。- 创建图
创建一个图来表示神经网络 - 执行图:Session会话
一个Session可能会拥有一些资源,例如Variable或者Queue,不再需要时,需要释放
图通过Session的运行而执行计算。Session将图的ops放到计算设备上,然后通过方法执行它们;这些方法执行完成后,将返回tensors
with tf.Session() as sess: #自动释放Session资源
result = sess.run([product]) # run之前计算节点都不会被触发执行
- 创建图
- 执行Operation或者求值Tensor有两种方式
1)调用tf.Session.run(fetches, feed_dict=None)
2)调用Operation.run(session)
3)调用Tensor.eval(session)