写在前面
之前写线性回归那一块内容的时候,发过手写二元线性回归梯度下降的博,由于基于方程的写法过于复杂,于是有了这一篇基于矩阵的梯度下降实现~
梯度下降回顾
首先,我们一起回顾一下梯度下降的算法原理:
梯度下降是一种最优化算法的常见求解方法,广泛应用于:线性回归、逻辑回归、神经网络、支持向量机等算法中。
我们之前都有说过梯度下降的白话解说:详情戳☞机器学习入门——线性回归剖析☜
梯度下降就是用以解决最小二乘算法解决不了的问题,当损失函数非凸时,常规的最小二乘无法求解(容易陷入局部最优)见下图:
上图即是损失函数非凸函数的情况,这时直接使用最小二乘求全局最优解是非常不切实际的。(全局最优解无法得到,往往陷入局部坑中)
这个时候,灵活的梯度下降就出现了。
梯度下降分为:批量梯度下降(Batch Gradient Descent)、随机梯度下降(Stochastic Gradient Descent)和小批量梯度下降(Mini Batch Gradient Descent)。
我们常说的梯度下降就是批量梯度下降,用大白话来理解这三个算法就是:
批量梯度下降BGD:使用全部样本构建了损失函数(在线性回归中为SSE),再根据损失函数梯度下降求得系数(权值);
随机梯度下降SGD:每次只使用一个样本点得到损失函数的公式,根据梯度下降求解参数,再随机选择样本进行系数更新;
小批量梯度下降MBGD:每次使用部分样本计算得到损失函数,根据梯度下降算法求解参数,再不断更新。
根据理解,我们可以总结得出其三个算法的优缺点见下表:
算法 | 优点 | 缺点 |
---|---|---|
BGD | 容易理解,得到稳定的参数值 | 每次迭代需要计算所有的样本,计算复杂;容易收敛到局部最优 |
SGD | 用随机性对抗数据集可能存在的不确定性,解决容易收敛到局部最优解的问题;大大加快了收敛速率 | 每次计算得到的系数值都不同,对关注于参数的算法不适用 |
MBGD | 结合上述两算法 | 不同batch_size的选择可能带来一些问题 |
算法过程
设样本量为m,回归方程为:
h
θ
(
x
1
,
x
2
,
.
.
.
x
n
)
=
θ
0
+
θ
1
x
1
+
.
.
.
+
θ
n
x
n
h
θ
(
x
1
,
x
2
,
.
.
.
x
n
)
=
θ
0
+
θ
1
x
1
+
.
.
.
+
θ
n
x
n
h_θ(x1,x2,...x_n)=θ_0+θ_1x_1+...+θ_nx_nh_θ(x_1,x_2,...x_n)=θ_0+θ_1x_1+...+θ_nx_n
hθ(x1,x2,...xn)=θ0+θ1x1+...+θnxnhθ(x1,x2,...xn)=θ0+θ1x1+...+θnxn 损失函数为:
J
(
θ
0
,
θ
1
.
.
.
,
θ
n
)
=
1
2
m
∑
j
m
(
h
θ
(
x
j
)
−
y
j
)
2
=
1
2
m
(
X
θ
−
Y
)
T
(
X
θ
−
Y
)
J(θ_0,θ_1...,θ_n)=\frac{1}{2m}∑_j^m(h_θ(x^j)−y^j)^2=\frac{1}{2m}(X\theta-Y)^T(X\theta-Y)
J(θ0,θ1...,θn)=2m1j∑m(hθ(xj)−yj)2=2m1(Xθ−Y)T(Xθ−Y)
g
r
a
d
θ
=
∇
J
(
θ
)
=
∂
J
(
θ
)
∂
θ
=
1
m
X
T
(
X
θ
−
Y
)
grad_\theta = \nabla J(\theta)=\frac{\partial J(\theta)}{\partial \theta}=\frac{1}{m}X^T(X\theta-Y)
gradθ=∇J(θ)=∂θ∂J(θ)=m1XT(Xθ−Y)PS.上述具体推导过程详见:☞之前博客-正规方程法☜
系数更新:
θ
:
=
θ
−
α
∗
g
r
a
d
θ
=
θ
−
α
∗
1
m
X
T
(
X
θ
−
Y
)
\theta:=\theta-\alpha*grad_\theta=\theta-\alpha*\frac{1}{m}X^T(X\theta-Y)
θ:=θ−α∗gradθ=θ−α∗m1XT(Xθ−Y)
Note.在介绍下述算法实现之前,首先应该明了,使用梯度下降的算法应该对数据进行标准化以消除量纲对梯度下降的影响。(对特征进行缩放(归一化、标准化)可以更快进行收敛。)
我们以吴恩达老师所说的例子(仍然是房价),对于房屋数量和房屋面积,其量纲差别较大,此时不标准化,直接进行梯度下降的结果如上图左,收敛速度慢;而对数据进行标准化后再进行梯度下降,得到的结果如上右图更快的收敛到全局最小值。
定义标准化函数:
def regulization(X):
xmat = X.copy()
x_mean = np.mean(xmat,axis = 0)
x_std = np.std(xmat,axis = 0)
x_norm = (xmat-x_mean)/x_std
return x_norm
批量梯度下降的python实现
def bgd(data,alp=0.01,numit=5000):
# 将数据转化为矩阵形式(分特征矩阵和标签矩阵)
xMat = np.mat(data.iloc[:,:-1].values)
yMat = np.mat(data.iloc[:,-1].values).T
# 将数据标准化
xMat = regulization(xMat)
yMat = regulization(yMat)
m,n = xMat.shape
# 存储系数
w = np.zeros((n,1))
for k in range(numit):
grad = xMat.T*(xMat*w-yMat)/m
w -= alp*grad
return w
随机梯度下降的python实现
注意:此处更换数据集,尽量不要在线性回归中使用随机梯度下降(线性回归关注参数,随机梯度下降每次运行的参数都不同!)
以逻辑回归为例(损失函数非凸)详情可见☞“机器学习入门——10分钟走进逻辑回归(Logistic Regression)”☜
def sgd(data,alp=0.01,numit=5000):
# 设置“随机性”:数据打乱
data = data.sample(numit,replace=True)
data.index = range(data.shape[0])
xMat = np.mat(data.iloc[:,:-1].values)
yMat = np.mat(data.iloc[:,-1].values).T
xMat = regulization(xMat)
m,n = xMat.shape
w = np.zeros((n,1))
# 对打乱的数据依次求解梯度下降
for i in range(m):
grad = xMat[i].T*(xMat[i]*w-yMat[i])
w -= alp*grad
return w
小批量梯度下降的python实现
def sbgd(data,alp=0.01,numit=5000,batch_size=10):
data = data.sample(numit,replace=True)
data.index = range(data.shape[0])
xMat = np.mat(data.iloc[:,:-1].values)
yMat = np.mat(data.iloc[:,-1].values).T
xMat = regulization(xMat)
m,n = xMat.shape
w = np.zeros((n,1))
k = m/batch_size
for i in range(batch_size):
if i < (batch_size-1):
grad = xMat[range(int(k)*i,(i+1)*int(k))].T*(xMat[range(int(k)*i,(i+1)*int(k))]*w-yMat[range(int(k)*i,(i+1)*int(k))])
else:
grad = xMat[range(int(k)*i,m)].T*(xMat[range(int(k)*i,m)]*w-yMat[range(int(k)*i,m)])
w -= alp*grad
return w
sbgd(abalone,alp=0.01,numit=5000,batch_size=10)
写在最后
以上是本人对梯度下降三个方法的浅要理解,如果哪里有问题,欢迎大家批评指正~希望和大家共同进步!