[tensorflow2笔记四] 神经网络优化

本讲目标

学会神经网络的 优化过程,使用 正则化 减少过拟合,使用 优化器 更新网络参数。

1.预备知识

认识几个函数:

函数说明
tf.where(条件语句,真返回A,假返回B)条件语句,真返回A,假返回B
np.random.RandomState().rand(维度)返回[0,1)之间的随机数
np.vstack((a,b))将a,b两个数组按垂直方向叠加,一维变二维
np.mgrid[]、.ravel()、np.c_[]三个函数常一起使用,生成网格坐标点

(1)tf.where(条件语句,真返回A,假返回B)

例子:

a = tf.constant([1,2,3])
b = tf.constant([0,3,1])
c = tf.where(tf.greater(a,b), a, b)  # 若a大于b,返回a对应位置元素;否则返回b中的元素
print(c)

输出:
tf.Tensor([1 3 3], shape=(3,), dtype=int32)

其中,tf.greater(a,b)函数,判别a是否大于b,大于返回True,不大于返回False。

(2)np.random.RandomState().rand(维度):返回[0,1)之间的随机数。

维度为空,则返回标量。

例子:

import numpy as np
a = np.random.RandomState().rand()
b = np.random.RandomState().rand(2,3)

输出:
0.19051479222973633
[[0.47288409 0.45516564 0.50699265]
 [0.64240615 0.96283958 0.92144825]]

(3) np.vstack((a,b))

将a,b两个数组按垂直方向叠加,一维变二维。

例子:

a = np.array([1,2,3])
b = np.array([3,2,1])
c = np.vstack((a,b))
print(c)

输出:
[[1 2 3]
 [3 2 1]]

(4)np.mgrid[]、.ravel()、np.c_[]三个函数常一起使用,生成网格坐标点。

np.mgrid[起始值:结束值:步长,起始值:结束值:步长,…]
注意:[起始值,结束值)

x.ravel():将多维数组x变为一位数组,拉长x。

np.c_[数组1,数组2,…]:使返回的数组1和数组2的对应点配对。

例子:

x, y = np.mgrid[1:3:1,2:4:0.5]  # x为1 2,y为2 2.5 3 3.5。可生成8个点的网格坐标。
print(x)
print(y)
grid = np.c_[x.ravel(),y.ravel()]
print(grid)

输出:
[[1. 1. 1. 1.]
 [2. 2. 2. 2.]]
 
[[2.  2.5 3.  3.5]
 [2.  2.5 3.  3.5]]
 
[[1.  2. ]
 [1.  2.5]
 [1.  3. ]
 [1.  3.5]
 [2.  2. ]
 [2.  2.5]
 [2.  3. ]
 [2.  3.5]]

2.复杂度、学习率

(1)神经网络(NN)复杂度:可用NN层数和NN参数的个数表示。分为空间复杂度,时间复杂度。

例子:
输入层(3个神经元)、1个隐藏层(4个神经元)、输出层(2个神经元)

空间复杂度

层数 = 隐藏层的层数 + 1个输出层(不计算输入层)= 2
总参数 = 总w + 总b = 3X4+4 + 4X2+2 = 26

时间复杂度:乘加运算次数 = 3X4 + 4X2 = 20

(2)学习率

更新后的参数 = 当前参数 - 学习率 * 偏导数

可以先使用较大的学习率,快速得到较优解;然后逐步减小学习率,使得模型在训练后期稳定。比如,指数衰减学习率。

指数衰减学习率 = 初始学习率 * [学习率衰减率 ** (当前轮数 / 多少轮衰减一次)]

epoch = 40       # 遍历数据集次数
LR_BASE = 0.2    # 初始学习率
LR_DECAY = 0.99  # 学习率衰减率
LR_STEP = 1      # 多少轮衰减一次

for epoch in range(epoch):
    lr = LR_BASE * LR_DECAY ** (epoch / LR_STEP)   # 指数衰减学习率
    with tf.GradientTape() as tape:
        loss = tf.square(w + 1)
    grads = tape.gradient(loss, w)
    w.assign_sub(lr * grads)
    print("Epoch: %s,lr: %f" % (epoch, lr))

3.激活函数

(1)MP模型:线性求和,再通过一个非线性函数,输出结果。

y = f(x * w + b)     # f为激活函数

意义:非线性激活函数的引入,使得多层神经网络不再是输入x的线性组合,大大提升了模型的表达力。

(2)优秀的激活函数

·非线性:多层神经网络可以逼近所有函数,不会被单层神经网络所替代。
·可微性:因为优化器大多使用梯度下降更新参数。
·单调性:能保证单层网络的损失函数是凸函数,更容易收敛。
·近似恒等性:f(x)近似x,当参数初始化为随机小时,神经网络更稳定。

(3)输出值的范围

·激活函数输出为有限值,基于梯度的优化方法更稳定。
·激活函数输出为无限值,建议调小学习率。

(4)常用激活函数

Sigmoid函数

·表达式:f(x) = 1 / (1 + e^(-x))

·输出:把输入值变到0-1之间输出,相当于对输入做了归一化。

·神经网络兴起的时候,使用Sigmoid函数的比较多,近年来比较少了,因为深层神经网络更新参数时,需要从输出层到输入层逐层链式求导,而该函数的导数输出在0-0.25之间,链式求导多层导数连续相乘时,结果将趋近于0,产生梯度消失,使得参数无法继续更新。

·我们希望输入每层神经网络的特征是以0为均值的小数,Sigmoid函数输出非0正数均值,收敛慢

·存在幂运算,计算复杂度大

Tanh函数

·表达式:f(x) = (1 - e ^ (-2x)) / (1 + e^(-2x))

·输出为0均值,但依旧存在梯度消失和幂运算复杂度问题。

Relu函数

·表达式:f(x) = max(x, 0)

·优点:在正区间内解决了梯度消失问题;收敛速度比Tanh和Sigmoid快;只需判断是否大于0计算速度快。

·缺点:Dead Relu问题,即送入激活函数的值为负数时,激活函数输出为0,反向传播得到的梯度是0,导致参数无法更新,造成神经元死亡。

·解决:改进随机初始化,避免过多的负数特征送入relu函数;通过设置更小的学习率,减少参数分布的巨大变化,避免训练中产生过多负数特征进入Relu函数。

Leaky Relu函数

·表达式:f(x) = max(αx, x)

·为解决relu负区间为0,引起神经元死亡问题设计的。虽然效果更好,但在实际应用中,选择relu的更多。

(5)激活函数总结

·首选relu激活函数

·学习率设置一个比较小的值

·输入特征标准化,即让输入特征满足以0为均值,1为标准差的正态分布

·初始参数中心化,即让随机生成的参数满足以0为均值,sqrt(2 / 当前输入特征个数)为标准差的正态分布。

4.损失函数

(1)损失函数(loss):预测值与已知答案的差距。NN优化目标:loss最小

(2)主流的loss有三种计算方法:mse(均方误差)、自定 义、ce(交叉熵)

·均方差mse

loss_mse = tf.reduce_mean(tf.square(y_ - y))

·自定义损失函数:预测少了,损失利润;预测多了,损失成本。

loss_zdy = tf.reduce_sum(tf.where(tf.greater(y, y_), COSE*(y-y_), PROFIT(y – y_)))

·交叉熵损失函数CE:表示两个概率分布之间的距离。可用来计算两种结果哪个更接近真实答案。

tf.losses.categorical_crossentropy(y_, y)

通常先通过softmax函数,让输出结果符合概率分布,再计算交叉熵损失函数。同时实现以上功能,tensorflow提供了函数:

tf.nn.softmax_cross_entropy_with_logits(y_, y)  

相等于

y_pro = tf.nn.softmax(y)
tf.losses.categorical_crossentropy(y_, y_pro)

5.欠拟合与过拟合

(1)概念
• 欠拟合:是模型不能有效拟合数据集,学习的不够彻底。

·过拟合:模型对当前数据集拟合得太好了,但对从未见过的新数据难以做出正确的判断,缺乏泛化力。

(2)解决方法
欠拟合的解决方法:
• 增加输入特征项,给网络更高维度的输入特征。
• 增加网络参数,扩展网络规模,增加网络深度。
• 减少正则化参数。

缓解过拟合方法:
• 数据清洗,减少数据集中的噪声,使得数据集更纯净。
• 增大数据集,让模型见到更多的数据。
• 采用正则化。
• 增大正则化参数。

(3)正则化缓解过拟合

正则化就是在损失函数中引入模型复杂度指标,给每个参数w加上权重,抑制训练数据集中的噪声。通常只对w进行加权,不正则化偏置b。

loss = loss(y与y_) + REGULARIZER*loss(w)

用REGULARIZER给出参数w在总loss中的比重。

loss(w)的计算可以使用两种方法:

lossL1(w) = Σ|wi|

lossL2(w) = Σ|wi2|

L1正则化大概率会使得很多参数变为0,因此该方法可通过稀疏参数(即减少参数数量),降低复杂度。
L2正则化会使参数很接近0但不是0,因此该方法可通过减小参数的数值,降低复杂度。

在前向传播中,计算损失函数:

loss_regularization = []
loss_regularization.append(tf.nn.l2_loss(w1))
loss_regularization.append(tf.nn.l2_loss(w2))
loss_regularization = tf.reduce_sum(loss_regularization)
loss = loss_mse + REGULARIZATION * loss_regularization

6.优化器

(1)概念

优化器就是引导神经网络更新参数的工具。

参数:待优化参数w,损失函数loss,学习率lr,每次迭代一个batch(通常包含2的n次方个数据),t表示当前batch迭代的总次数。

(2)步骤
更新参数分为4步完成:

• 计算t时刻损失函数关于当前参数的梯度gt:loss对每一个wt求偏导数。
• 计算t时刻一阶动量mt和二阶动量Vt。一阶动量是与梯度相关的函数;二阶动量是与梯度平方相关的函数。
• 计算t时刻的下降梯度:yt = lr ·mt/√Vt
• 计算t+1时刻的参数:wt+1 = wt – yt

不同的优化器实质上只定义了不同的一阶动量和二阶动量公式。

(3)常用的优化器:
随机梯度下降法SGD:当不含动量时,mt = gt Vt = 1
yt = lr·gt
wt+1 = wt – lr·gt。

代码:对于单层网络
w1 = assign_sub(lr*grads[0])
b1 = assign_sub(lr*grads[1])

SGDM(含动量的SGD):在SGD基础上增加一阶动量。
mt = β·mt-1 + (1-β)·gt
Vt = 1
yt = lr·mt wt+1 = wt – lr·mt

其中β是超参数,是一个接近于1的数值,0.9。

代码:
m_w ,m_b = 0, 0    # w和b的初始一阶动量
beta = 0.9
m_w = beta*m_w + (1-beta) * grads[0]
m_b = beta*m_b + (1-beta) * grads[1]
w1 = assign_sub(lr*m_w)
b1 = assign_sub(lr*m_b)

Adagrad:
在SGD基础上增加二阶动量。可以对模型中的每一个参数分配自适应学习率了。
mt = gt Vt = ∑gtao2
yt = lr ·mt/√Vt wt+1 = wt – yt

二阶动量是从开始到现在梯度平法的累计和。

代码:
v_w,v_b = 0, 0
v_w += tf.square(grads[0])
v_b = tf.square(grads[1])
w1.assign_sub(lr * grads[0] / tf.sqrt(v_w))
b1.assign_sub(lr * grads[1] / tf.sqrt(v_b))

RMSProp:
SGD基础上增加了二阶动量。V使用指数滑动平均值计算,表征的是过去一段时间的平均值。
mt = gt Vt = β·Vt-1 + (1-β)·gt2

代码:
v_w,v_b = 0, 0
v_w += beta*v_w +(1-beta) * tf.square(grads[0])
v_b += beta*v_b +(1-beta) * tf.square(grads[1])
w1.assign_sub(lr * grads[0] / tf.sqrt(v_w))
b1.assign_sub(lr * grads[1] / tf.sqrt(v_b))

Adam:同时结合SGDM一阶动量和 RMSProp二阶动量。并进行了参数修正。

mt = β1·mt-1 + (1-β1)·gt
mt = mt / (1-β1t)
Vt = β2·Vt-1 + (1-β2)·gt2
Vt = Vt / (1-β2t)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值