随机梯度下降法,批量梯度下降法和小批量梯度下降法以及代码实现

前言

梯度下降法是深度学习领域用于最优化的常见方法,根据使用的batch大小,可分为随机梯度下降法(SGD)和批量梯度下降法(BGD)和小批量梯度下降法(MBGD),这里简单介绍下并且提供Python代码演示。
如有谬误,请联系指正。转载请注明出处。
联系方式:
e-mail: FesianXu@163.com
QQ: 973926198
github: https://github.com/FesianXu
代码开源:click

梯度下降法

  其基本思想就是使得网络的各个参数朝着优化函数的梯度的反方向更新,因为梯度的方向是增长最速方向,所以梯度的反方向就是减少的最速方向,因此只要设定一个步进η ,然后朝着梯度的反方向下降减小即可将优化函数最小化。公式表达如:

w l ij :=w l ij ηCw l ij   

以下讨论都假设使用的损失函数是MSE损失函数,模型为线性回归模型。

L=12m  i=1 m (yh(x (i) )) 2 m 

h(x i )=θ T x (i) +bx (i) ix (i) R n  

批量梯度下降法(BGD)

  批量梯度下降法(Batch Gradient Descent, BGD)是梯度下降法的最原始的形式,其特点就是每一次训练迭代都需要利用所有的训练样本,其表达式为:

Lθ j  =1m  i=1 m [(yh(x (i) ))x (i) j ]x (i) j ij 

θ j :=θ j +η1m  i=1 m [(yh(x (i) ))x (i) j ] 

  可以发现,对于每一个参数的更新都需要利用到所有的m个样本,这样会导致训练速度随着训练样本的增大产生极大地减慢,不适合于大规模训练样本的场景,但是,其解是全局最优解,精度高。

随机梯度下降法(SGD)

  随机梯度下降法(Stochastic Gradient Descent, SGD)是梯度下降法的改进形式之一,其特点就是每一次训练迭代只需要训练样本集中的一个样本,其表达式为:

Lθ j  =(yh(x))x j x j j 

θ j :=θ j +η(yh(x))x j  

  和BGD进行对比可以发现,其参数更新过程中,只需要选取训练集中的一个训练样本,因此训练速度快,但是因为其只是利用了训练集的一部分知识,因此其解为局部最优解,精度较低。

小批量梯度下降法(MBGD)

  小批量梯度下降法(Mini-Batch Gradient Descent, MBGD)是结合了SGD和BGD的一种改进版本,既有训练速度快,也有精度较高的特点,其基本特点就是每一次训练迭代在训练集中随机采样batch_size个样本,其表达式为:

Lθ j  =1M  i=1 M [(yh(x (i) ))x (i) j ]Mbatch_size 

θ j :=θ j +η1M  i=1 M [(yh(x (i) ))x (i) j ] 

  这个改进版本在深度学习的网络训练中有着广泛地应用,因为其既有较高的精度,也有较快的训练速度。

代码实现

这里以线性回归模型作为演示,实现梯度下降。代码实现基于python和numpy,matplotlib绘图,matlab生成数据集。代码由github托管。

数据描述

目标直线为y=2.5x+3.5 ,加上了一个高斯噪声,代码如:

x = -20:0.01:20;
line = 2.5*x+3.5;
x_rand = randn(1, length(line))*10;
line = line+x_rand;
x = x';
line = line';
samples = [x, line];

图像如:
dataset
主要代码如:

import numpy as np
import scipy.io as sio
import random
import matplotlib.pyplot as plt

path = u'./samples.mat'
mat = sio.loadmat(path)
dataset = mat['samples']
batch_size = 1

def random_get_samples(mat, batch_size):
    batch_id = random.sample(range(mat.shape[0]), batch_size)
    ret_batch = mat[batch_id, 0]
    ret_line = mat[batch_id, 1]
    return ret_batch, ret_line


params = {
    'w1': np.random.normal(size=(1)),
    'b': np.random.normal(size=(1))
}

def predict(x):
    return params['w1']*x+params['b']

learning_rate = 0.001
for i in range(3000):
    batch, line = random_get_samples(dataset, batch_size)
    y_pred = predict(batch)
    y_pred = np.reshape(y_pred, (batch_size, 1))
    line = np.reshape(line, (batch_size, 1))
    batch = np.reshape(batch, (batch_size, 1))
    delta = line-y_pred
    params['w1'] = params['w1']+learning_rate*np.sum(delta*batch)/batch_size
    params['b'] = params['b']+learning_rate*np.sum(delta)/batch_size
    if i % 100 == 0:
        print(np.sum(np.abs(line-y_pred))/batch_size)

print(params['w1'])
print(params['b'])
x = dataset[:, 0]
line = dataset[:, 1]
y = params['w1']*x+params['b']
plt.figure(1)
plt.plot(x, line, 'b--')
plt.plot(x, y, 'r--')
plt.show()

其中调整batch_size可以分别实现SGD,BGD和MBGD,当其为1时为SGD,当其为dataset.shape[0]时为BGD,当其为其他固定常数时如128,为MBGD。通过实验可以明显发现,当batch_size为1时,训练速度最快,但是精度欠佳,当batch_size=dataset.shape[0]时,训练速度最慢,但是精度较高,当batch_size=128或其他常数时,速度和精度兼有顾及。最后的结果图像如:
regression
可见红线成功拟合了原数据。

posted @ 2017-10-15 19:36  FesianXu  阅读(152)  评论(0编辑  收藏  举报