第三周:超参数调整,批量标准化,编程框架

本文是改善深层神经网络的笔记。

3.1 调试处理

重要性排序

目前我们见到的一些超参数:

  • 学习率 α \alpha α: 重要性1
  • Momentum参数 β \beta β:重要性2
  • Adam参数 β 1 , β 2 , ϵ \beta_1,\beta_2,\epsilon β1,β2,ϵ
  • 隐层数量:重要性3
  • 隐藏神经元数量:重要性2
  • Learning rate decay:重要性3
  • mini-batch size:重要性2

如何选择超参数的值?

  1. 用一个规整的Grid
  2. 随便取一些参数(随机取值、精确搜索):
  3. Coarse to find [在一个大区域里面取随机点找出一个小的区域,然后循环]

在这里插入图片描述
这里说明随机选取要比Grid要好一点,如果Hyperparameters 2是 ϵ \epsilon ϵ,则Grid Search的结果中实际上只起到了测5组Hyperparameters 1的作用,因为 ϵ \epsilon ϵ对结果的影响不大。然而在随机选取中,我们得以测量25组数据对结果的影响。所以更优一点。

3.2 ⚠️ 为超参数选择合适的范围

  • 可以随机取值的例子:
    • 隐层层数
    • 每个隐层的神经元数量
  • 学习率 α \alpha α
  • Momentum β \beta β
  1. 如果直接均匀分布地选取:
# 如果直接均匀分布地选取:
a = np.random.rand(100000)
plt.hist(a,bins=10)
plt.show()

import math
print(f"Total Num = {len(a)}")
for i in range(-4,0):
    print(math.pow(10,i+1),">a>",math.pow(10,i)," Num = ",np.sum((math.pow(10,i)<a)*(a<math.pow(10,i+1))))

输出:
在这里插入图片描述

Total Num = 100000
0.001 >a> 0.0001  Num =  93
0.01 >a> 0.001  Num =  902
0.1 >a> 0.01  Num =  8945
1.0 >a> 0.1  Num =  90052

实际上比较合理的方法:在对数尺寸上选

一般为了在 [ 1 0 a , 1 0 b ] [10^a,10^b] [10a,10b]量级里面,每个量级都拥有较为均衡的数据,我们使用如下的方法:

  1. r = b-(a+b)*np.random.rand()
  2. a=np.array([math.pow(10,i) for in r])
  1. 如果是在对数尺寸里均匀分布地选取:(相当于每个数量级都均匀地取了一点)
# 如果是在对数尺寸里均匀分布地选取:(相当于每个数量级都均匀地取了一点)
r = -4*np.random.rand(10000)
a = np.array([math.pow(10,i) for i in r])

plt.hist(a,bins=10)
plt.show()

import math
print(f"Total Num = {len(a)}")
for i in range(-4,0):
print(math.pow(10,i+1),">a>",math.pow(10,i)," Num = ",np.sum((math.pow(10,i)<a)*(a<math.pow(10,i+1))))

在这里插入图片描述

Total Num = 10000
0.001 >a> 0.0001  Num =  2404
0.01 >a> 0.001  Num =  2544
0.1 >a> 0.01  Num =  2587
1.0 >a> 0.1  Num =  2465

Momentum上 β \beta β的例子

假设我们希望模拟 β \beta β的范围在 [ 0.9 , … , 0.999 ] [0.9,\dots,0.999] [0.9,,0.999]我们可以这样做:

  1. 考虑 1 − β ∈ [ 0.001 , 0.1 ] 1-\beta \in [0.001,0.1] 1β[0.001,0.1]
  2. 利用上面的方法,模拟 r ∈ [ − 3 , − 1 ] r \in [-3,-1] r[3,1]
  3. 因此得到 β = 1 − 1 0 r \beta =1 - 10^r β=110r

3.3 超参数训练的实践

  • 照看一个模型:每天换一次参数,不对了就回到上一次的模型。“Panda”方法
  • 同时训练多个模型:“Caviar”(鱼子酱)方法

3.4 ⚠️正则化网络(Batch Normalization)的激活函数

  • 类似于我们对于输入的操作:减去均值+处以方差

  • 我们对于每一层的 z z z在输入激活层之前进行此操作 = > Batch Normalization

  • 但我们并不希望一直是 N ( 0 , 1 ) N(0,1) N(0,1)这样的分布,因为这样对于一些激活函数,如sigmoid不太友好。因为它没有利用到它的非线性区域。

具体实现

我们引入 β [ l ] \beta^{[l]} β[l], γ [ l ] \gamma^{[l]} γ[l]作为参数。这里的 β \beta β和Momentum之间是不同的。

鉴于我们希望在激活层之前完成Batch Normalization,所以我们看的是 z z z。下面求的是某一层输出神经元的平均值,即计算对m个样本某一层的参数的平均值和方差。

μ = 1 m ∑ i = 1 m z [ l ] ( i ) \mu=\frac{1}{m}\sum_{i=1}^{m}z^{[l](i)} μ=m1i=1mz[l](i)

σ 2 = 1 m ∑ i = 1 m ( z [ l ] ( i ) − μ ) 2 \sigma^2=\frac{1}{m}\sum_{i=1}^{m}(z^{[l](i)}-\mu)^2 σ2=m1i=1m(z[l](i)μ)2

z n o r m [ l ] ( i ) = z [ l ] ( i ) − μ σ 2 + ϵ z^{[l](i)}_{norm}=\frac{z^{[l](i)}-\mu}{\sqrt{\sigma^2+\epsilon}} znorm[l](i)=σ2+ϵ z[l](i)μ

z ~ [ l ] ( i ) = γ [ l ] z n o r m [ l ] ( i ) + β [ l ] \tilde{z}^{[l](i)}=\gamma^{[l]} z_{norm}^{[l](i)}+\beta^{[l]} z~[l](i)=γ[l]znorm[l](i)+β[l]

a [ l ] = g [ l ] ( z ~ [ l ] ) a^{[l]}=g^{[l]}(\tilde{z}^{[l]}) a[l]=g[l](z~[l])

3.5 将Batch Norm拟合进神经网络

  • 此时的 b [ l ] = 0 b^{[l]}=0 b[l]=0因为每次BN过程中都要减去均值,所以均值一定为0。 b [ l ] b^{[l]} b[l]增加偏差的作用不明显。
    在这里插入图片描述

3.6 为什么BN奏效?

  • 解释一:
    • 可以使更深层的网络减少受到第一层的影响。
    • "Covariate Shift":即训练数据和测试数据并不是同一个分布。
    • BN降低了Covariate Shift,从而使得层与层之间的输入更加集中。BN改变了输入值变化太大的问题,换言之它减少了前几层网络的作用。
  • 解释二:
    • ⚠️ BN有一定的正则化作用。因为我们是对于MiniBatch进行作用,它是包含噪音的。所以我们计算出来的 μ \mu μ σ 2 \sigma^2 σ2也是包含噪音的,从而减少了过拟合的风险。也正因为这个想法,如果MiniBatch太大,噪音就相对小一点,从而正则化(Regularization)的效果就差一点。

3.7 ⚠️测试时的BN

  • Recap+Pbm:
    在训练的时候我们是对多个样本求均值,然后再处以方差从而达到BN的作用的。但是,实际上,我们在测试这个训练好的模型的时候是一个一个输入数据的,应该怎么处理?

鉴于我们测试时候每次只输入一个数据,所以我们得想个另外的方法得到每一个 μ \mu μ σ 2 \sigma^2 σ2。从而可以计算 z ~ \tilde{z} z~

  • Sol:
  • 方法一:
    对每个MiniBatch来用指数加权平均来估算:
X { 1 } X^{\{1\}} X{1} X { 2 } X^{\{2\}} X{2} X { 3 } X^{\{3\}} X{3}
μ { 1 } [ 1 ] \mu^{\{1\}[1]} μ{1}[1] μ { 2 } [ 1 ] \mu^{\{2\}[1]} μ{2}[1] μ { 3 } [ 1 ] \mu^{\{3\}[1]} μ{3}[1]
σ { 1 } [ 1 ] \sigma^{\{1\}[1]} σ{1}[1] σ { 2 } [ 1 ] \sigma^{\{2\}[1]} σ{2}[1] σ { 3 } [ 1 ] \sigma^{\{3\}[1]} σ{3}[1]

即在每一个BN层里面加入
μ [ l ] : = β μ [ l ] + ( 1 − β ) μ [ l ] { i } \mu^{[l]}:=\beta \mu^{[l]} + (1-\beta) \mu^{[l]\{i\}} μ[l]:=βμ[l]+(1β)μ[l]{i}
σ [ l ] : = σ μ [ l ] + ( 1 − β ) σ [ l ] { i } \sigma^{[l]}:=\sigma \mu^{[l]} + (1-\beta) \sigma^{[l]\{i\}} σ[l]:=σμ[l]+(1β)σ[l]{i}

  • 方法二:
    对于训练好的网络,将整个训练集的样本全部输入进去,基于整个样本,求出各BN层的平均值和方差。

3.8 SoftMax回归

  • 对于Logistic Regression回归的generalize,用于处理多分类的任务。因为SoftMax的决策边界也是线性的。
  • 记号:
    • C = C l a s s e s C = Classes C=Classes:有多少个类别
  • SoftMax即换一个激活函数(不用平常使用的ReLU)
    • SoftMax激活函数 g : R C × 1 → R C × 1 g: \mathbb{R}^{C\times 1} \to \mathbb{R}^{C\times1} g:RC×1RC×1
      在这里插入图片描述

3.9 训练一个SoftMax分类器

  • HardMax,会找出所有元素中最大的元素。相反的是SoftMax。

  • 如果C=2,SoftMax就会退化为Logistic Regression:
    e z 1 e z 1 + e z 2 = 1 1 + e z 2 − z 1 \frac{e^{z1}}{e^{z1}+e^{z2}}=\frac{1}{1+e^{z_2-z_1}} ez1+ez2ez1=1+ez2z11

例子

y ^ = g [ l ] ( z [ l ] ) = [ 0.842 0.042 0.002 0.114 ] , y = [ 0 1 0 0 ] \hat{y}=g^{[l]}(z^{[l]})=\begin{bmatrix} 0.842 \\ 0.042 \\ 0.002 \\ 0.114 \end{bmatrix},y=\begin{bmatrix} 0 \\ 1 \\ 0 \\ 0 \end{bmatrix} y^=g[l](z[l])=0.8420.0420.0020.114,y=0100
则我们可以通过下面的Cost Function得到当前样本的损失
L ( y ^ , y ) = − 1 ∗ l o g ( y ^ 2 ) = − l o g ( 0.042 ) L(\hat{y},y)=-1*log(\hat{y}_2)=-log(0.042) L(y^,y)=1log(y^2)=log(0.042),此时希望最小化L等价于最大化 l o g ( y ^ 2 ) log(\hat{y}_2) log(y^2),即最大化 y ^ \hat{y} y^中正确项(第二项)的概率(概率最大为1)。

SoftMax 常用的Loss Function和Cost Function

  • 其实是最大似然法的结果,类似于交叉熵的推广:

L ( y ^ , y ) = − ∑ j = 1 C y j l o g ( y ^ j ) L(\hat{y},y)=-\sum_{j=1}^Cy_jlog(\hat{y}_j) L(y^,y)=j=1Cyjlog(y^j)

J ( w [ 1 ] , b [ 1 ] , …   ) = 1 m ∑ i = 1 m L ( y ^ ( i ) , y ( i ) ) J(w^{[1]},b^{[1]},\dots)=\frac{1}{m}\sum_{i=1}^mL(\hat{y}^{(i)},y^{(i)}) J(w[1],b[1],)=m1i=1mL(y^(i),y(i))

J 是m个样本的均值。

  • 引入
    Y = [ y ( 1 ) , y ( 2 ) , … , y ( m ) ] Y = [y^{(1)},y^{(2)},\dots,y^{(m)}] Y=[y(1),y(2),,y(m)]
    其中每一个样本 y ( i ) y^{(i)} y(i)是一个列向量,里面为1的元素表示对应正确类别。

反向传播

d z [ L ] = ∂ J ∂ z [ L ] = y ^ − y dz^{[L]}=\frac{\partial J}{\partial z^{[L]}}=\hat{y}-y dz[L]=z[L]J=y^y【待证明❓❓】

3.10 深度学习框架

  • 选择框架的标准:
    • 易于编程
    • 训练速度快
    • Truly Open

3.11 TensorFlow

  • 例子:
    最小化 J ( w ) = w 2 − 10 w + 25 J(w)=w^2-10w+25 J(w)=w210w+25
  • 关键操作:
    • tf.Variable(0,dtype=tf.float32):创建一个初始值为0的参数w
    • 梯度下降:train = tf.train.GradientDescentOptimizer(0.01).minimize(cost) # 学习率为0.01
    • 开始训练
init = tf.global_variables_initializer()
session = tf.Session()
session.run(init)
session.run(train,feed_dict={x:coefficients}) #执行一步梯度下降,x是placeholders的名字
print(session.run(w)) #打印出更新完之后的参数w
  • 代价函数的定义:
    • (不太常用)cost = tf.add(tf.add(w**2,tf.multiply(-10.,w)),25),利用tensorflow内部的函数
    • 鉴于对于tf.Variable加减乘法已经重载为TensorFlow里面的tf.add这种,所以可以直接用来构造代价函数,如cost = w**2 - 10*w +25
    • 需要传递的参数
x = tf.placeholder(tf.float32,[3,1]) # placeholder 表示到时候由它提供数据,x是一个3*1的数组
coefficients = np.array([[1.],[-20.],[100.]])
cost = x[0][0]*w**2 + x[1][0]*w+x[2][0]
  • 全部代码:
w = tf.Variable(0,dtype=tf.float32) #w是一个初始值为3的tf.float32的变量

# 将训练数据导入
x = tf.placeholder(tf.float32,[3,1]) # placeholder 表示到时候由它提供数据,x是一个3*1的数组
coefficients = np.array([[1.],[-20.],[100.]])

# cost = tf.add(tf.add(w**2,tf.multiply(-10.,w)),25) #定义损失函数 w^2-10w+25,方向传播的方法已经写在这里面了
# cost = w**2 - 10*w +25#如果w是一个tf.Variable,则所有的+-*/已经被重载了,所以上面的代码等价于当前行的代码
cost = x[0][0]*w**2 + x[1][0]*w+x[2][0]


train = tf.train.GradientDescentOptimizer(0.01).minimize(cost) # 学习率为0.01

init = tf.global_variables_initializer()
session = tf.Session()
session.run(init)
print(session.run(w)) #评估一个变量(参数),我们这里目的想寻找最小值对应的w的值。

session.run(train,feed_dict={x:coefficients}) #执行一步梯度下降,x是placeholders的名字
print(session.run(w)) #评估一个变量

for i in range(1000):
    session.run(train,feed_dict={x:coefficients}) #执行一步梯度下降
print(session.run(w)) #评估一个变量
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值