深度学习之参数优化算法

1、GD:Gradient Descent, 梯度下降法

1.1 原理

  • 梯度下降学习的目标通常是最小化机器学习问题的损失函数,寻找全局最优值。

  • 基本的梯度下降算法遵循的思想是,梯度的相反方向指向较低的区域。所以它在梯度的相反方向迭代。对于参数 θ \theta θ,它做如下操作( ∇ θ \nabla_{\theta} θ表示损失函数对 θ \theta θ的导数, ∇ θ = 1 m ∑ i = 1 m ∂ L ( y i , f ( x i , θ ) ) ∂ θ \nabla_{\theta}=\frac{1}{m}\sum_{i=1}^m\frac{\partial L(y_i, f(x_i, \theta))}{\partial \theta} θ=m1i=1mθL(yi,f(xi,θ)),即梯度, α \alpha α表示学习率):

Δ ( t ) = − α ∗ ∇ θ ( t ) θ ( t ) = θ ( t − 1 ) + Δ θ ( t ) \Delta^{(t)} = - \alpha * \nabla_{\theta}^{(t)} \\ \theta^{(t)} =\theta^{(t-1)}+ \Delta^{(t)}_{\theta} Δ(t)=αθ(t)θ(t)=θ(t1)+Δθ(t)

  • θ \theta θ是一些需要优化的参数(例如,神经网络中神经元与神经元之间连接的权重,线性回归特征的系数,等等),上标表示迭代轮次 t t t

1.2 梯度下降法的几种形式

  1. 批量梯度下降(Batch Gradient Descent,BGD)
    批量梯度下降法是指在每一次迭代时使用所有样本来进行梯度的更新。
    优点:
      (1)一次迭代是对所有样本进行计算,此时利用矩阵进行操作,实现了并行。
      (2)由于全部数据集确定的方向能够更好地代表样本总体,从而更准确地朝向极值所在的方向。当目标函数为凸函数时,BGD一定能够得到全局最优。
      
    缺点:
      (1)当样本数目很大时,每迭代一步都需要对所有样本计算,训练过程会很慢。

  2. 随机梯度下降(Stochastic Gradient Descent,SGD)
    随机梯度下降是每次迭代使用一个样本来对参数进行更新。使得训练速度加快。
    优点:
      (1)由于不是在全部训练数据上的损失函数,而是在每轮迭代中,随机优化某一条训练数据上的损失函数,这样每一轮参数的更新速度大大加快。
    缺点:
      (1)准确度下降。由于即使在目标函数为强凸函数的情况下,SGD仍旧无法做到线性收敛。
      (2)可能会收敛到局部最优,由于单个样本并不能代表全体样本的趋势。
      (3)不易于并行实现。

  3. 小批量梯度下降(Mini-Batch Gradient Descent, MBGD)

  4. 小批量梯度下降,是对批量梯度下降以及随机梯度下降的一个折中办法。其思想是:每次迭代 使用 batch_size个样本来对参数进行更新。
    优点:
      (1)通过矩阵运算,每次在一个batch上优化神经网络参数并不会比单个数据慢太多。
      (2)每次使用一个batch可以大大减小收敛所需要的迭代次数,同时可以使收敛到的结果更加接近梯度下降的效果。(比如上例中的30W,设置batch_size=100时,需要迭代3000次,远小于SGD的30W次)
      (3)可实现并行化。
    缺点:
      (1)batch_size的不当选择可能会带来一些问题。

1.3 代码实现

1.3.1 TensorFlow实现

tf.train.GradientDescentOptimizer 优化器

import tensorflow as tf
tf.train.GradientDescentOptimizer(learning_rate, use_locking=False,name=’GradientDescent’)
'''
参数:
learning_rate: A Tensor or a floating point value. 要使用的学习率
use_locking: 要是True的话,就对于更新操作(update operations.)使用锁
name: 名字,可选,默认是”GradientDescent”
函数:
minimize() 函数处理了梯度计算和参数更新两个操作
compute_gradients() 函数用于获取梯度
apply_gradients() 用于更新参数
'''
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data

#one_hot=True表示将预测变量y_true转换为one hot模式
mnist=input_data.read_data_sets(r'./TensorFlow+Keras深度学习人工智能实践应用/MNIST_data', one_hot=True)
x=tf.placeholder(tf.float32, [None, 784]) #采用占位符,不传入具体的样本数量
w=tf.Variable(tf.zeros([784, 10]))
b=tf.Variable(tf.zeros([10]))

#多分类采用softmax作为输出函数
y_pred=tf.nn.softmax(tf.matmul(x, w)+b) #matmul是矩阵相乘,+是逐元素相加
y_true=tf.placeholder(tf.float32, [None, 10])

#交叉熵损失函数
cross_entropy=tf.reduce_mean(-tf.reduce_sum(y_true*tf.log(y_pred)))

#梯度下降算法,最小化交叉熵
train_step=tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)

#创建会话
with tf.Session() as sess:
    #初始化所有变量
    init=tf.initialize_all_variables()
    sess.run(init)
    for i in range(50):
        batch_x, batch_y=mnist.train.next_batch(100)
        train_step.run({x:batch_x, y_true:batch_y})
    #tf.argmax在行中寻找最大的索引
    correct_prediction=tf.equal(tf.argmax(y_true ,1), tf.argmax(y_pred ,1))
    #tf.cast先将数据转换成float,防止求平均不准确。
    acc=tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
    print(sess.run(acc, feed_dict={x: mnist.test.images, y_true: mnist.test.labels}))

#结果
0.8598

1.3.2 pytorch 实现

#数据记载
batch_size=100
train_data=Data.MNIST(root='./MNIST',train=True,transform=transforms.ToTensor().,download=True)
test_data=Data.MNIST(root='./MNIST',train=False,transform=transforms.ToTensor().,download=False)
train_loader=DataLoader(dataset=train_data, batch_size=batch_size, shuffle=True)
test_loader=DataLoader(dataset=test_data, batch_size=batch_size, shuffle=True)

#定义神经网络
input_size=28*28
hiddle_size=500
output_size=10
class Net(nn.Module):
    def __init__(self, input_size, hiddle_size, output_size):
        super(self, Net).__init__()
        self.layer1=nn.Linear(input_size, hiddle_size)
        self.layer2=nn.Linear(hiddle_size, output_size)
    def forward(self, x):
        out=self.layer1(x)
        out=torch.nn.ReLU(out)
        out=self.layer2(out)
        return out
model=Net(input_size ,hiddle_size, output_size)

#训练
lr=1e-1
epochs=5
criterion=nn.CrossEntropyLoss()
optimizer=torch.optim.SGD(model.parameters(), lr=lr)
for epoch in range(epochs):
    for i (image, label) in enumerate(train_loader):
        image=Variable(image.view(-1, 28*28))
        label=Variable(label)
        output=net(image)
        loss=criterion(output, label)
        optimizer.zero_grad() #梯度清零
        loss.backward() #计算梯度
        optimizer.step() #更新梯度
        if i % 100==0:
            print('current loss=%0.5f'%loss.item())

#预测
total=0
correct=0
for image, label in test_loader:
    image=Variable(image.view(-1, 28*28))
    output=net(image)
    pred=torch.argmax(output, 1)
    total+=label.size(0)
    correct+=torch.sum(pred==label)
    
print('Accuracy=%0.2f'%(100*correct/total))

2、Momentum:动量法

2.1 原理

  • 借鉴物理学的思想,我们将动量的概念应用到原版梯度下降法中。在每一步参数更新中,除了常规的梯度之外,还增加了前一步中的移动,对于参数 θ \theta θ的更新公式如下:
    Δ t = − α ∗ ∇ θ + β Δ t − 1 \Delta_t=-\alpha*\nabla_{\theta} +\beta\Delta_{t-1} Δt=αθ+βΔt1
    θ t = θ t − 1 + Δ t \theta_t=\theta_{t-1}+\Delta_t θt=θt1+Δt
    公式中引入动量系数 β \beta β,取值范围为[0, 1],用于调节先前梯度的衰减效果。动量系数一般初始化为0.5,并在多个时期后逐渐初始化为0.9。
  • 当我们使用动量优化算法的时候,可以解决小批量SGD优化算法更新幅度摆动大的问题,同时可以使得网络的收敛速度更快。

2.2 代码实现

2.2.1 TensorFlow实现

optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.001).minimize(loss)

2.2.2 pytorch 实现

model = Net()# 定义模型
CrossEntropy_loss = torch.nn.CrossEntropyLoss()#定义损失函数
LR=0.001 #学习率
optimizer = torch.optim.SGD(model.parameters(),lr=LR,  momentum=0.9)#定义优化器, momentum通常取0.5,0.9,0.99

3、AdaGrad:Adaptive Gradient,自适应梯度法

3.1 原理

  • AdaGrad,不是像动量一样跟踪梯度之和,而是跟踪梯度平方之和,并使用这种方法在不同的方向上调整梯度。
    Δ ( t ) = − α ∑ i = 1 t − 1 ( ∇ θ ( i ) ) 2 + ( ∇ θ ( t ) ) 2 + δ ∇ θ ( t ) \Delta^{(t)}=-\frac{\alpha}{\sqrt{\sum_{i=1}^{t-1}(\nabla_{\theta}^{(i)})^2+(\nabla^{(t)}_{\theta})^2}+\delta}\nabla^{(t)}_{\theta} Δ(t)=i=1t1(θ(i))2+(θ(t))2 +δαθ(t)
    θ ( t ) = θ ( t − 1 ) + Δ ( t ) \theta^{(t)}=\theta^{(t-1)}+\Delta^{(t)} θ(t)=θ(t1)+Δ(t)
    为了避免分母为0,添加一个因子 δ \delta δ,取值为 1 0 − 7 10^{-7} 107
  • 从上式可以看出,AdaGrad使的参数在累积的梯度较小时(分母较小)就会放大学习率,使网络训练更加快速。在梯度的累积量较大时(分母较大)就会缩小学习率,延缓网络的训练,简单的来说,网络刚开始时学习率很大,当走完一段距离后小心翼翼,这正是我们需要的。
  • 但是这里存在一个致命的问题就是AdaGrad容易受到过去梯度的影响,陷入“过去“无法自拔,因为梯度很容易就会累积到一个很大的值,此时学习率就会被降低的很厉害,因此AdaGrad很容易过分的降低学习率率使其提前停止,怎么解决这个问题呢?RMSProp算法可以很好的解决该问题。

3.2 代码实现

3.2.1 TensorFlow实现

tf.train.AdagradOptimizer(learning_rate=0.001).minimize(loss)

3.2.2 pytorch 实现

model = Net()# 定义模型
CrossEntropy_loss = torch.nn.CrossEntropyLoss()#定义损失函数
LR=0.001 #学习率
optimizer = torch.optim.Adagrad(model.parameters(),lr=LR)#定义优化器

4、RMSProp:Root Mean Square Propagation,均方根传播法

4.1 原理

  • AdaGrad在理论上有较好的性质,但在实践中表现不是很好,其根本原因在于随着训练周期的增长,梯度平方积累的很大,学习率就会降低的很快。为了避免该现象的发生,RMSProp引入衰减因子,实现对“过去”和“现在”的平衡,常用的衰减因子取值为0.9或者0.5。公式如下所示:
    Δ ( t ) = − α β ∑ i = 1 t − 1 ( ∇ θ ( i ) ) 2 + ( 1 − β ) ( ∇ θ ( t ) ) 2 + δ ∇ θ ( t ) \Delta^{(t)}=-\frac{\alpha}{\sqrt{\beta\sum_{i=1}^{t-1}(\nabla_{\theta}^{(i)})^2+(1-\beta)(\nabla^{(t)}_{\theta})^2}+\delta}\nabla_{\theta}^{(t)} Δ(t)=βi=1t1(θ(i))2+(1β)(θ(t))2 +δαθ(t)
    θ ( t ) = θ ( t − 1 ) + Δ ( t ) \theta^{(t)}=\theta^{(t-1)}+\Delta^{(t)} θ(t)=θ(t1)+Δ(t)
  • 为了避免分母为0,添加一个因子 δ \delta δ,取值为 1 0 − 10 10^{-10} 1010,衰减因子 β \beta β一般取0.9。
  • RMSProp更新方式对深度学习网络十分有效,是深度学习的最有效的更新方式之一

4.2 代码实现

4.2.1 TensorFlow实现

tf.train.RMSPropOptimizer(learning_rate=0.001,momentum=0.9, decay=0.9, epsilon=1e-10).minimize(loss)

4.2.2 pytorch 实现

model = Net()# 定义模型
CrossEntropy_loss = torch.nn.CrossEntropyLoss()#定义损失函数
LR=0.001 #学习率
torch.optim.RMSprop(model.parameters(), lr=LR, alpha=0.9) #alpha就是衰减因子,0.9或者0.5

5、Adam:Adaptive Moment Estimation,自适应动量优化法

5.1 原理

  • 虽然动量法加速了我们对最小值方向的搜索,但RMSProp法阻碍了我们在振荡方向上的搜索。因此Adam方法是基于动量和RMSProp的微调版本,该方法是目前深度学习中最流行的优化方法 。公式如下所示:
  • Momentum:
    M = β 1 ∑ i = 1 t − 1 ∇ θ ( i ) + ( 1 − β 1 ) ∇ θ ( t ) M=\beta_1\sum_{i=1}^{t-1}\nabla_{\theta}^{(i)}+(1-\beta_1)\nabla_{\theta}^{(t)} M=β1i=1t1θ(i)+(1β1)θ(t)
  • RMSProp:
    R = β 2 ∑ i = 1 t − 1 ( ∇ θ ( i ) ) 2 + ( 1 − β 2 ) ( ∇ θ ( t ) ) 2 R=\beta_2\sum_{i=1}^{t-1}(\nabla_{\theta}^{(i)})^2+(1-\beta_2)(\nabla^{(t)}_{\theta})^2 R=β2i=1t1(θ(i))2+(1β2)(θ(t))2
  • 整合
    Δ ( t ) = − α M R + δ \Delta^{(t)}=-\alpha\frac{M}{\sqrt{R}+\delta} Δ(t)=αR +δM
    θ ( t ) = θ ( t − 1 ) + Δ ( t ) \theta^{(t)}=\theta^{(t-1)}+\Delta^{(t)} θ(t)=θ(t1)+Δ(t)
  • 为了避免分母为0,添加一个因子 δ \delta δ,取值为 1 0 − 10 10^{-10} 1010,动量参数 β 1 \beta_1 β1一般取0.9,衰减参数 β 2 \beta_2 β2一般取0.999。

5.2 代码实现

5.2.1 TensorFlow实现

tf.train.AdamOptimizer(learning_rate=0.001,beta1=0.9, beta2=0.999, epsilon=1e-10).minimize(loss)

5.2.2 pytorch 实现

model = Net()# 定义模型
CrossEntropy_loss = torch.nn.CrossEntropyLoss()#定义损失函数
LR=0.001 #学习率
optimizer = torch.optim.Adam(model.parameters(),lr=LR, betas=(0.9, 0.999), eps=1e-08)#定义优化器

引用的文章:
原理:

代码:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值