x1 x2 y
1 4 19
2 5 26
5 1 19
4 2 29
x1和x2是样本值,y是预测目标,我们需要以一条直线来拟合上面的数据,待拟合的函数如下:
我们的目的就是要求出θ1和θ2的值,让h(θ)尽量逼近目标值y。
这是一个线性回归问题,若对线性回归有所了解的同学就知道:利用最小二乘法则和梯度下降法可以求出两个参数,而深度学习也同样可以利用这两种方法求得所有的网络参数,因此,在这里用这个数学模型来解释BGD、SGD、MSGD这几个概念。
梯度下降法原理
我们首先确定损失函数:
其中,J(θ)是损失函数,m代表每次取多少样本进行训练,如果采用SGD进行训练,那每次随机取一组样本,m=1;如果是批处理,则m等于每次抽取作为训练样本的数量。θ是参数,对应(1式)的θ1和θ2。求出了θ1和θ2,h(x)的表达式就出来了:
我们的目标是让损失函数J(θ)的值最小,根据梯度下降法,首先要用J(θ)对θ求偏导:
由于是要最小化损失函数,所以参数θ按其负梯度方向来更新:
示例:
BGD(Batch gradient descent)批量梯度下降法:每次迭代使用所有的样本
-
#-*- coding: utf-8 -*-
-
import random
-
#用y = Θ1*x1 + Θ2*x2来拟合下面的输入和输出
-
#input1 1 2 5 4
-
#input2 4 5 1 2
-
#output 19 26 19 20
-
input_x = [[
1,
4], [
2,
5], [
5,
1], [
4,
2]]
#输入
-
y = [
19,
26,
19,
20]
#输出
-
theta = [
1,
1]
#θ参数初始化
-
loss =
10
#loss先定义一个数,为了进入循环迭代
-
step_size =
0.01
#步长
-
eps =
0.0001
#精度要求
-
max_iters =
10000
#最大迭代次数
-
error =
0
#损失值
-
iter_count =
0
#当前迭代次数
-
-
err1=[
0,
0,
0,
0]
#求Θ1梯度的中间变量1
-
err2=[
0,
0,
0,
0]
#求Θ2梯度的中间变量2
-
-
while( loss > eps
and iter_count < max_iters):
#迭代条件
-
loss =
0
-
err1sum =
0
-
err2sum =
0
-
for i
in range (
4):
#每次迭代所有的样本都进行训练
-
pred_y = theta[
0]*input_x[i][
0]+theta[
1]*input_x[i][
1]
#预测值
-
err1[i]=(pred_y-y[i])*input_x[i][
0]
-
err1sum=err1sum+err1[i]
-
err2[i]=(pred_y-y[i])*input_x[i][
1]
-
err2sum=err2sum+err2[i]
-
theta[
0] = theta[
0] - step_size * err1sum/
4
#对应5式
-
theta[
1] = theta[
1] - step_size * err2sum/
4
#对应5式
-
for i
in range (
4):
-
pred_y = theta[
0]*input_x[i][
0]+theta[
1]*input_x[i][
1]
#预测值
-
error = (
1/(
2*
4))*(pred_y - y[i])**
2
#损失值
-
loss = loss + error
#总损失值
-
iter_count +=
1
-
print (
"iters_count", iter_count)
-
print (
'theta: ',theta )
-
print (
'final loss: ', loss)
-
print (
'iters: ', iter_count)
theta: [3.0044552563214433, 3.9955447274498894] final loss: 9.428456066652548e-05 iters: 97
SGD(Stochastic gradientdescent)随机梯度下降法:每次迭代使用一组样本
针对BGD算法训练速度过慢的缺点,提出了SGD算法,普通的BGD算法是每次迭代把所有样本都过一遍,每训练一组样本就把梯度更新一次。而SGD算法是从样本中随机抽出一组,训练后按梯度更新一次,然后再抽取一组,再更新一次,在样本量及其大的情况下,可能不用训练完所有的样本就可以获得一个损失值在可接受范围之内的模型了。
-
#-*- coding: utf-8 -*-
-
import random
-
#用y = Θ1*x1 + Θ2*x2来拟合下面的输入和输出
-
#input1 1 2 5 4
-
#input2 4 5 1 2
-
#output 19 26 19 20
-
input_x = [[
1,
4], [
2,
5], [
5,
1], [
4,
2]]
#输入
-
y = [
19,
26,
19,
20]
#输出
-
theta = [
1,
1]
#θ参数初始化
-
loss =
10
#loss先定义一个数,为了进入循环迭代
-
step_size =
0.01
#步长
-
eps =
0.0001
#精度要求
-
max_iters =
10000
#最大迭代次数
-
error =
0
#损失值
-
iter_count =
0
#当前迭代次数
-
-
while( loss > eps
and iter_count < max_iters):
#迭代条件
-
loss =
0
-
i = random.randint(
0,
3)
#每次迭代在input_x中随机选取一组样本进行权重的更新
-
pred_y = theta[
0]*input_x[i][
0]+theta[
1]*input_x[i][
1]
#预测值
-
theta[
0] = theta[
0] - step_size * (pred_y - y[i]) * input_x[i][
0]
-
theta[
1] = theta[
1] - step_size * (pred_y - y[i]) * input_x[i][
1]
-
for i
in range (
3):
-
pred_y = theta[
0]*input_x[i][
0]+theta[
1]*input_x[i][
1]
#预测值
-
error =
0.5*(pred_y - y[i])**
2
-
loss = loss + error
-
iter_count +=
1
-
print (
'iters_count', iter_count)
-
print (
'theta: ',theta )
-
print (
'final loss: ', loss)
-
print (
'iters: ', iter_count)
MBGD(Mini-batch gradient descent)小批量梯度下降:每次迭代使用b组样本
SGD相对来说要快很多,但是也有存在问题,由于单个样本的训练可能会带来很多噪声,使得SGD并不是每次迭代都向着整体最优化方向,因此在刚开始训练时可能收敛得很快,但是训练一段时间后就会变得很慢。在此基础上又提出了小批量梯度下降法,它是每次从样本中随机抽取一小批进行训练,而不是一组。
-
#-*- coding: utf-8 -*-
-
import random
-
#用y = Θ1*x1 + Θ2*x2来拟合下面的输入和输出
-
#input1 1 2 5 4
-
#input2 4 5 1 2
-
#output 19 26 19 20
-
input_x = [[
1,
4], [
2,
5], [
5,
1], [
4,
2]]
#输入
-
y = [
19,
26,
19,
20]
#输出
-
theta = [
1,
1]
#θ参数初始化
-
loss =
10
#loss先定义一个数,为了进入循环迭代
-
step_size =
0.01
#步长
-
eps =
0.0001
#精度要求
-
max_iters =
10000
#最大迭代次数
-
error =
0
#损失值
-
iter_count =
0
#当前迭代次数
-
-
-
while( loss > eps
and iter_count < max_iters):
#迭代条件
-
loss =
0
-
#这里每次批量选取的是2组样本进行更新,另一个点是随机点+1的相邻点
-
i = random.randint(
0,
3)
#随机抽取一组样本
-
j = (i+
1)%
4
#抽取另一组样本,j=i+1
-
pred_y0 = theta[
0]*input_x[i][
0]+theta[
1]*input_x[i][
1]
#预测值1
-
pred_y1 = theta[
0]*input_x[j][
0]+theta[
1]*input_x[j][
1]
#预测值2
-
theta[
0] = theta[
0] - step_size * (
1/
2) * ((pred_y0 - y[i]) * input_x[i][
0]+(pred_y1 - y[j]) * input_x[j][
0])
#对应5式
-
theta[
1] = theta[
1] - step_size * (
1/
2) * ((pred_y0 - y[i]) * input_x[i][
1]+(pred_y1 - y[j]) * input_x[j][
1])
#对应5式
-
for i
in range (
3):
-
pred_y = theta[
0]*input_x[i][
0]+theta[
1]*input_x[i][
1]
#总预测值
-
error = (
1/(
2*
2))*(pred_y - y[i])**
2
#损失值
-
loss = loss + error
#总损失值
-
iter_count +=
1
-
print (
'iters_count', iter_count)
-
-
print (
'theta: ',theta )
-
print (
'final loss: ', loss)
-
print (
'iters: ', iter_count)