Spark推荐系统,干货,心得
点击上方蓝字关注~
在之前两章讲了线性回归,并定义损失函数使用直接求导法进行求解模型参数θ,这章使用梯度下降法进行求解并进行详细介绍~
往期回顾:
机器学习-线性回归(一)
梯度下降法:
(英文:Gradientdescent)是一个一阶最优化算法,通常也称为最速下降法。
梯度下降算法是一种求局部最优解的方法,对于F(x),在a点的梯度是F(x)增长最快的方向,那么它的相反方向则是该点下降最快的方向则是该点下降最快的方向
原理:将函数比作一座山,站在某个上坡上,往四周看,从哪个方向向下走一小步,能够下降的最快
步骤:
初始化theta
沿着负梯度方向迭代,更新后的theta使得J(theta)更小
其中a表示学习率
梯度下降实现
在线性回归中,目标函数收敛而且为凸函数,是一个极值点,所以局部最小值就是全局最小值
批量梯度下降法BGD
批量梯度下降BatchGradient Descent——BGD
对所有数据点,上述损失函数的偏导(累和)为
在最小化损失函数的过程中,需要不断反复更新weights(也就是下面代码里面的theta)使得误差函数(MSE)减小,更新过程如下:
代码实现1(少量维度实现,易于理解)
# -*- coding: utf-8 -*-
# 5行3列,相当于5条样本,3特征(2个实际特征+1个截距项)
x_train = [(1, 0., 3), (1, 1., 3), (1, 2., 3), (1, 3., 2), (1, 4., 4)]
# 5个lable值
y_train = [95.364, 97.217205, 75.195834, 60.105519, 49.342380]
# 初始化thea(因为是3个特征,所以有3个theta)
theta0, theta1, theta2 = 0, 0, 0
# 设置学习率
alpha = 0.0001
# 样本数
m = len(x_train)
# 存放差值
error1, error2 = 0.0, 0.0
# 设置误差结束的阈值
epsilon = 0.00001
cnt = 0
# 根据更新后的theta 计算每一条样本的预测值y_hat
def hx(x):
return theta0 * x[0] + theta1 * x[1] + theta2 * x[2]
while True:
cnt += 1
# 计算梯度
diff = [0, 0, 0]
for i in range(m):
diff[0] += (y_train[i] - hx(x_train[i])) * 1
diff[1] += float((y_train[i] - hx(x_train[i])) * x_train[i][1])
diff[2] += float((y_train[i] - hx(x_train[i])) * x_train[i][2])
# 更新theta
theta0 = theta0 + alpha * diff[0] / m
theta1 = theta1 + alpha * diff[1] / m
theta2 = theta2 + alpha * diff[2] / m
print("theta0:", theta0, " theta1:", theta1, " theta2:", theta2)
# 计算MSE
for i in range(m):
error1 += (y_train[i] - hx(x_train[i])) ** 2
error1 /= m
# 判断结束条件
if abs(error1 - error2) < epsilon:
break
else:
error2 = error1
error1 = 0.0
求解结果
theta0: 92.56879079366635 theta1: -12.989587163127105 theta2: 2.8807162746286443
代码实现2(矩阵通用形式表达)
import numpy as np
np.random.seed(10)
x = np.random.rand(100, 4) # 随机生成100行4列矩阵(相当于100条样本,4个特征)
x_train = np.c_[np.ones((100, 1)), x] # 添加截距项
y_train = x_train @ np.random.randn(5, 1) # 生成100行1列的label值
print(x_train)
print(y_train)
# 初始化thea
theta = np.zeros((5, 1))
# 设置学习率
alpha = 0.001
# 存放差值
error1, error2 = 0.0, 0.0
# 设置误差结束的阈值
epsilon = 0.00000000001
while True:
# 求梯度
diff = 1 / m * x_train.T @ (x_train @ theta - y_train)
# 更新theta
theta = theta - alpha * diff
print("theta:", theta)
# 计算MSE
error1 = np.sum((x_train @ theta - y_train) ** 2)
error1 /= m
# 判断结束条件
if abs(error1 - error2) < epsilon:
break
else:
error2 = error1
error1 = 0.0
求解结果:
theta: [[ 0.75540004]
[-0.72832989]
[ 1.21532026]
[ 1.00850685]
[ 0.07384045]]
随机梯度下降SGD(实际项目中使用最多)
由于批量梯度下降每更新一个theta参数的时候,要用到所有的样本数据,所有训练速度会随着样本数量的增加而变得非常缓慢。随机梯度下降正是为了解决这个办法而提出的。它是利用每个样本的损失函数对θ求偏导得到对应的梯度,来更新θ:
代码实现
import numpy as np
np.random.seed(10)
x = np.random.rand(100, 4) # 随机生成100行4列矩阵(相当于100条样本,4个特征)
x_train = np.c_[np.ones((100, 1)), x] # 添加截距项
y_train = x_train @ np.random.randn(5, 1) # 生成100行1列的label值
print(x_train)
print(y_train)
# 初始化thea
theta = np.zeros((5, 1))
# 设置学习率
alpha = 0.001
# 存放差值
error1, error2 = 0.0, 0.0
# 设置误差结束的阈值
epsilon = 0.000000001
m = len(x_train)
while True:
# 在x_train,y_train样本中随机选取一条数据
random_index = np.random.randint(m)
xi = x_train[random_index:random_index + 1]
yi = y_train[random_index:random_index + 1]
# 求梯度
diff = xi.T @ (xi @ theta - yi)
# 更新theta
theta = theta - alpha * diff
print("theta:", theta)
# 计算MSE
error1 = np.sum((x_train @ theta - y_train) ** 2)
error1 /= m
# 判断结束条件
if abs(error1 - error2) < epsilon:
break
else:
error2 = error1
error1 = 0.0
theta: [[ 0.75329149]
[-0.7250897 ]
[ 1.21542624]
[ 1.00817401]
[ 0.0749319 ]]
缺点:SGD伴随的一个问题是噪音较BGD要多,使得SGD并不是每次迭代都向着整体最优化方向。
解决方案:
1.动态更改学习速率a的大小,可以增大或者减小
2.随机选样本进行学习
小批量梯度下降MBGD
小批量梯度下降Mini-BathGradient Descent,简称MBGD解决BGD和SGD的缺点,使得算法的训练过程比较快,使得每次迭代也基本朝着整体最优化方向
代码实现
import numpy as np
np.random.seed(10)
x = np.random.rand(100, 4) # 随机生成100行4列矩阵(相当于100条样本,4个特征)
x_train = np.c_[np.ones((100, 1)), x] # 添加截距项
y_train = x_train @ np.random.randn(5, 1) # 生成100行1列的label值
print(x_train)
print(y_train)
# 初始化thea
theta = np.zeros((5, 1))
# 设置学习率
alpha = 0.001
# 存放差值
error1, error2 = 0.0, 0.0
# 设置误差结束的阈值
epsilon = 0.00000000001
m = len(x_train)
while True:
# 在x_train,y_train样本中随机选取一条数据
random_index = np.random.randint(m)
xi = x_train[random_index:random_index + 1]
yi = y_train[random_index:random_index + 1]
# 求梯度
diff = xi.T @ (xi @ theta - yi)
# 更新theta
theta = theta - alpha * diff
print("theta:", theta)
# 计算MSE
error1 = np.sum((x_train @ theta - y_train) ** 2)
error1 /= m
# 判断结束条件
if abs(error1 - error2) < epsilon:
break
else:
error2 = error1
error1 = 0.0
theta: [[ 0.72819422]
[-0.0236637 ]
[ 0.69902268]
[ 0.59513736]
[ 0.26477262]]
总结:本文主要引入求解线性回归的loss函数最优解,来学习了梯度下降法,该方法被广泛使用在机器学习,深度学习求解最优解问题中~
推荐阅读:
spark协同过滤
Spark推荐系统
长按识别二维码关注我们