CV

深度神经网络-中

梯度下降、反向传播、动量算法、Adam、Dropout、BN

Posted by 新宇 on July 17, 2020

一、深度学习的优化方法

1. 梯度下降算法

梯度下降法简单来说就是一种寻找使损失函数最小化的方法;

1.1 梯度下降法的分类

1.2 方法实现

  • tf.keras.optimizers.SGD(learning_rate=0.01, momentum=0.0, nesterov=False, name=’SGD’, **kwargs)
# 导入相应的工具包

import tensorflow as tf
# 实例化优化方法:SGD 

opt = tf.keras.optimizers.SGD(learning_rate=0.1)
# 定义要调整的参数

var = tf.Variable(1.0)
# 定义损失函数:无参但有返回值

loss = lambda: (var ** 2)/2.0  
# 计算梯度,并对参数进行更新,步长为 `- learning_rate * grad`

opt.minimize(loss, [var]).numpy()
# 展示参数更新结果

var.numpy()

1.3 三个基础概念

2. 反向传播算法(BP算法)

2.1 前向传播

  • 前向传播指的是数据输入的神经网络中,逐层向前传输,一直到运算到输出层为止;

2.2 链式法则

  • 反向传播算法是利用链式法则进行梯度求解及权重更新的。
  • 对于复杂的复合函数,我们将其拆分为一系列的加减乘除或指数,对数,三角函数等初等函数,通过链式法则完成复合函数的求导。

2.3 反向传播算法

  • 反向传播算法利用链式法则对神经网络中的各个节点的权重进行更新

3. 梯度下降算法的优化方法

3.1 动量算法

动量算法主要解决鞍点问题。

# 导入相应的工具包

import tensorflow as tf
# 实例化优化方法:SGD 指定参数beta=0.9

opt = tf.keras.optimizers.SGD(learning_rate=0.1, momentum=0.9)
# 定义要调整的参数,初始值

var = tf.Variable(1.0)
val0 = var.value()
# 定义损失函数

loss = lambda: (var ** 2)/2.0         
#第一次更新:计算梯度,并对参数进行更新,步长为 `- learning_rate * grad`

opt.minimize(loss, [var]).numpy()
val1 = var.value()
# 第二次更新:计算梯度,并对参数进行更新,因为加入了momentum,步长会增加

opt.minimize(loss, [var]).numpy()
val2 = var.value()
# 打印两次更新的步长

print("第一次更新步长={}".format((val0 - val1).numpy()))
print("第二次更新步长={}".format((val1 - val2).numpy()))

3.2 AdaGrad

自适应学习率算法

AdaGrad算法会使用一个小批量随机梯度g_t,g_t按元素平方的累加变量st。在首次迭代时,AdaGrad将s0中每个元素初始化为0。在t次迭代,首先将小批量随机梯度gt按元素平方后累加到变量st:

其中α是学习率,ϵ是为了维持数值稳定性而添加的常数,如10^-6,。这里开方、除法和乘法的运算都是按元素运算的。这些按元素运算使得目标函数自变量中每个元素都分别拥有自己的学习率;

# 导入相应的工具包

import tensorflow as tf
# 实例化优化方法:SGD

opt = tf.keras.optimizers.Adagrad(
    learning_rate=0.1, initial_accumulator_value=0.1, epsilon=1e-07
)
# 定义要调整的参数

var = tf.Variable(1.0)
# 定义损失函数:无参但有返回值

def loss(): return (var ** 2)/2.0

# 计算梯度,并对参数进行更新,

opt.minimize(loss, [var]).numpy()
# 展示参数更新结果

var.numpy()

3.3 RMSprop

梯度按元素平方做指数加权移动平均

# 导入相应的工具包

import tensorflow as tf
# 实例化优化方法RMSprop

opt = tf.keras.optimizers.RMSprop(learning_rate=0.1)
# 定义要调整的参数

var = tf.Variable(1.0)
# 定义损失函数:无参但有返回值

def loss(): return (var ** 2)/2.0

# 计算梯度,并对参数进行更新,

opt.minimize(loss, [var]).numpy()
# 展示参数更新结果

var.numpy()

3.4 Adam

动量和RMS Prop算法结合在一起,同时对梯度和学习率做了优化

# 导入相应的工具包

import tensorflow as tf
# 实例化优化方法Adam

opt = tf.keras.optimizers.Adam(learning_rate=0.1)
# 定义要调整的参数

var = tf.Variable(1.0)
# 定义损失函数:无参但有返回值

def loss(): return (var ** 2)/2.0

# 计算梯度,并对参数进行更新,

opt.minimize(loss, [var]).numpy()
# 展示参数更新结果

var.numpy()

4. 学习率退火

4.1 分段常数衰减

# 设置的分段的step值

boundaries = [100000, 110000]
# 不同的step对应的学习率

values = [1.0, 0.5, 0.1]
# 实例化进行学习的更新

learning_rate_fn = keras.optimizers.schedules.PiecewiseConstantDecay(
    boundaries, values)

4.2 指数衰减

def decayed_learning_rate(step):
      return initial_learning_rate * decay_rate ^ (step / decay_steps)

4.3 1/t衰减

def decayed_learning_rate(step):
  return initial_learning_rate / (1 + decay_rate * step / decay_step)

二、深度学习的正则化

1. L1、L2正则化

# 导入相应的工具包

import tensorflow as tf
from tensorflow.keras import regularizers
# 创建模型

model = tf.keras.models.Sequential()
# L2正则化,lambda为0.01

model.add(tf.keras.layers.Dense(16, kernel_regularizer=regularizers.l2(0.001),
                       activation='relu', input_shape=(10,)))
# L1正则化,lambda为0.01

model.add(tf.keras.layers.Dense(16, kernel_regularizer=regularizers.l1(0.001),
                       activation='relu'))
# L1L2正则化,lambda1为0.01,lambda2为0.01

model.add(tf.keras.layers.Dense(16, kernel_regularizer=regularizers.L1L2(0.001, 0.01),
                       activation='relu'))

2. Dropout

# 导入相应的库

import numpy as np
import tensorflow as tf
# 定义dropout层,每一个神经元有0.2的概率被失活,未被失活的输入将按1 /(1-rate)放大

layer = tf.keras.layers.Dropout(0.2,input_shape=(2,))
# 定义五个批次的数据

data = np.arange(1,11).reshape(5, 2).astype(np.float32)
# 原始数据进行打印

print(data)
# 进行随机失活:在training模式中,返回应用dropout后的输出;或者在非training模式下,正常返回输出(没有dropout)

outputs = layer(data,training=True)
# 打印失活后的结果

print(outputs)

3. 提前停止

# 导入相应的工具包

import tensorflow as tf
import numpy as np
# 当连续3个epoch loss不下降则停止训练

callback = tf.keras.callbacks.EarlyStopping(monitor='loss', patience=3)
# 定义只有一层的神经网络

model = tf.keras.models.Sequential([tf.keras.layers.Dense(10)])
# 设置损失函数和梯度下降算法

model.compile(tf.keras.optimizers.SGD(), loss='mse')
# 模型训练

history = model.fit(np.arange(100).reshape(5, 20), np.array([0,1,2,1,2]),
                    epochs=10, batch_size=1, callbacks=[callback],
                    verbose=1)
# 打印运行的epoch

len(history.history['loss']) 

4. 批量标准化

  • 批标准化(BN层,Batch Normalization)是2015年提出的一种方法,在进行深度网络训练时,大多会采取这种算法,与全连接层一样,BN层也是属于网络中的一层。
  • BN层是针对单个神经元进行,利用网络训练时一个 mini-batch 的数据来计算该神经元xi 的均值和方差,归一化后并重构,因而称为 Batch Normalization。在每一层输入之前,将数据进行BN,然后再送入后续网络中进行学习;

# 直接将其放入构建神经网络的结构中即可

tf.keras.layers.BatchNormalization(
    epsilon=0.001, center=True, scale=True,
    beta_initializer='zeros', gamma_initializer='ones',
)