(五)梯度下降法

文章详细介绍了梯度下降法,它是一种用于最优化的搜索方法,主要用于最小化损失函数。文中通过代码示例展示了如何在Python中实现梯度下降法,并讨论了其在解决线性回归问题中的应用。此外,还对比了批量梯度下降和随机梯度下降的优缺点,强调随机梯度下降在处理大规模数据时的效率优势。最后,文章提到了梯度调试技巧以及在机器学习流程中的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • 不是一个机器学习算法,不能解决分类或回归问题

  • 是一种基于搜索的最优化方法

  • 作用:最小化一个损失函数

  • 梯度上升法:最大化一个效用函数

并不是所有的函数都有唯一的极值点

解决方案:

  • 多次运行,随机初始化点

  • 梯度下降法的初始点也是一个超参数

一,梯度下降法模拟实现

线性回归的损失函数具有唯一的最优解

import numpy as np

importmatplotlib.pyplot as plt

plot_x =np.linspace(-1., 6., 141)

plot_y= (plot_x-2.5)**2 - 1. #假设的损失函数曲线

epsilon= 1e-8 #定义容许的误差

eta =0.1 #定义步长

theta= 0.0 #初始化theta

while True:

gradient = dJ(theta)

last_theta = theta

theta = theta - eta * gradient

if(abs(J(theta) - J(last_theta)) <epsilon):

break

eta的影响:

theta = 0.0

theta_history = [theta]#记录theta

while True:

gradient = dJ(theta)

last_theta = theta

theta = theta - eta * gradient

theta_history.append(theta)

if(abs(J(theta) - J(last_theta)) <epsilon):

break

plt.plot(plot_x,J(plot_x))

plt.plot(np.array(theta_history),J(np.array(theta_history)), color="r", marker='+')

plt.show()

eta = 0.8

eta = 1.1

二,线性回归中使用梯度下降算法

J的梯度就是n维空间中,损失函数下降速度最快的方向。

三,在线性回归中实现梯度下降算法

构造数据样本

np.random.seed(666)

x = 2 *np.random.random(size=100)

y = x * 3. + 4. +np.random.normal(size=100)

X =x.reshape(-1, 1) #变成列向量

plt.scatter(x, y)

使用梯度下降法训练

def J(theta, X_b, y):

try:

return np.sum((y - X_b.dot(theta))**2)/ len(X_b)

except: #防止步长太大造成溢出

return float('inf')

def dJ(theta, X_b, y):

res = np.empty(len(theta))

res[0] = np.sum(X_b.dot(theta) - y)

for i in range(1, len(theta)):

res[i] = (X_b.dot(theta) -y).dot(X_b[:,i]) #完全对照上边的公式

return res * 2 / len(X_b)

defgradient_descent(X_b, y, initial_theta, eta, n_iters = 1e4, epsilon=1e-8):

theta = initial_theta

cur_iter = 0

while cur_iter < n_iters:

gradient = dJ(theta, X_b, y)

last_theta = theta

theta = theta - eta * gradient

if(abs(J(theta, X_b, y) - J(last_theta,X_b, y)) < epsilon):

break

cur_iter += 1

return theta

X_b =np.hstack([np.ones((len(x), 1)), x.reshape(-1,1)])

initial_theta =np.zeros(X_b.shape[1])

eta = 0.01

theta =gradient_descent(X_b, y, initial_theta, eta)

一步步纠正自己对机器学习原始的印象,机器学习并不是所有算法都是通过迭代训练参数的,目前为止大多数都是通过数学推导和简单的逻辑实现的。

四,梯度下降法的向量化和数据标准化

梯度下降算法的进一步变形:

最终损失函数的导数化为:

def dJ(theta, X_b, y):

return X_b.T.dot(X_b.dot(theta) - y) *2. / len(y)

预测波士房价

使用梯度下降法之前,最好进行数据的归一化

数据集的特征的数据量级不同,需要对数据进行预处理。如果不进行处理,步长的设定对某些特征的数据可能正好,但是对一些量级非常小的数据可能不合适,使得算法发散。

fromsklearn.preprocessing import StandardScaler

standardScaler =StandardScaler() #实例化这个函数

standardScaler.fit(X_train)

X_train_standard =standardScaler.transform(X_train)

lin_reg3 =LinearRegression()

%timelin_reg3.fit_gd(X_train_standard, y_train)

X_test_standard =standardScaler.transform(X_test)

lin_reg3.score(X_test_standard,y_test)

梯度下降法的优势

m = 1000

n = 5000

big_X =np.random.normal(size=(m, n))

true_theta =np.random.uniform(0.0, 100.0, size=n+1)

big_y =big_X.dot(true_theta[1:]) + true_theta[0] + np.random.normal(0., 10., size=m)

对特别大的矩阵,一般来说梯度下降法的速度更快一些,但当特别大时候,梯度下降法也很慢,因此引入随机梯度下降法。

五,随机梯度下降法StochasticGradient Descent

随机梯度下降就是采取,每次随机取出样本的一行,也就是一个样本的所有属性作为方向作为迭代,寻找损失函数的最小值。图中右侧的式子已经不是损失函数,只是作为一种搜索的方向

从图中可以看出,搜索过程中,每次的搜索方向都是随机的;常规的梯度下降是按照一个方向进行的,这个方向一定是损失函数下降速度最快的方向,但是对于大样本来说这样的算法计算速度太慢。随机梯度下降虽然不一定是按照下降速度最快的方向,但是对于m,也就是样本数量太大的情况可以明显加快计算速度。总之,随机梯度下降法的精度较低一些,但是速度快了很多,而传统的梯度下降算法精度足够,一定可以来到损失函数最低点,但是计算速度不高。

随机梯度下降法的步长是需要不断的改变的,应该随着学习次数的提高,学习率(步长)应该逐渐减少。

eta的分母+b的原因是为了缓解学习次数很小时,相邻学习次数对应的步长差距太大的影响

因此,随机梯度下降算法的超参数是a,b,我们可以取经验值,a=5,b=50

这种步长随着循环次数的增加而递减的思想是用到了模拟退火算法的思想

随机梯度下降算法的实现:

m =1000000 #数据规模非常大

x =np.random.normal(size=m)

X = x.reshape(-1,1)

y = 4.*x + 3. +np.random.normal(0, 3, size=m)

def dJ_sgd(theta,X_b_i, y_i):

return 2 * X_b_i.T.dot(X_b_i.dot(theta) -y_i)

def sgd(X_b, y,initial_theta, n_iters):

t0, t1 = 5, 50

def learning_rate(t):

return t0 / (t + t1)

theta = initial_theta

for cur_iter in range(n_iters):

rand_i = np.random.randint(len(X_b)) #随机

gradient = dJ_sgd(theta, X_b[rand_i],y[rand_i])

theta = theta - learning_rate(cur_iter)* gradient

return theta

X_b =np.hstack([np.ones((len(X), 1)), X])

initial_theta =np.zeros(X_b.shape[1])

theta= sgd(X_b, y, initial_theta, n_iters=m//3) #只需要检查很少的样本量

结果对比:

采取一般梯度下降法:

采取随机梯度下降法:

skikit-learn中的随机梯度下降法

fromsklearn.linear_model import SGDRegressor #在linear包中,只能解决线性问题

sgd_reg =SGDRegressor()

%timesgd_reg.fit(X_train_standard, y_train)

sgd_reg.score(X_test_standard,y_test)

机器学习通用过程:

调包->构建实例对象进行fit->验证训练模型的效果

六:调试梯度下降法

红点切线对应的斜率近似等于它旁边俩个点连线的斜率

问题是时间复杂度太高

因此我们可以采取选用小数据量的样本来使用上述的公式验证,看我们所写的梯度下降法是否有错误。

梯度调试的计算

产生数据:

np.random.seed(666)

X =np.random.random(size=(1000, 10))

true_theta =np.arange(1, 12, dtype=float)

X_b =np.hstack([np.ones((len(X), 1)), X])

y = X_b.dot(true_theta)+ np.random.normal(size=1000)

定义函数公式:

def J(theta, X_b, y):

try:

return np.sum((y - X_b.dot(theta))**2)/ len(X_b)

except:

return float('inf')

def dJ_math(theta, X_b,y):

return X_b.T.dot(X_b.dot(theta) - y) * 2. /len(y)

def dJ_debug(theta, X_b, y, epsilon=0.01):

res = np.empty(len(theta))

for i in range(len(theta)):

theta_1 = theta.copy()

theta_1[i] += epsilon

theta_2 = theta.copy()

theta_2[i] -= epsilon

res[i] = (J(theta_1, X_b, y) -J(theta_2, X_b, y)) / (2 * epsilon)

return res

defgradient_descent(dJ, X_b, y, initial_theta, eta, n_iters = 1e4, epsilon=1e-8):

theta = initial_theta

cur_iter = 0

while cur_iter < n_iters:

gradient = dJ(theta, X_b, y)

last_theta = theta

theta = theta - eta * gradient

if(abs(J(theta, X_b, y) - J(last_theta,X_b, y)) < epsilon):

break

cur_iter += 1

return theta

验证:

X_b =np.hstack([np.ones((len(X), 1)), X])

initial_theta =np.zeros(X_b.shape[1])

eta = 0.01

%time theta =gradient_descent(dJ_debug, X_b, y, initial_theta, eta)

%time theta =gradient_descent(dJ_math, X_b, y, initial_theta, eta)

检查theta即可

七,总结:

  • 批量梯度下降法 Batch Gradient Descent 精确但是慢

  • 随机梯度下降法 Stochastic Gradient Descent 快但是不精确

  • 小批量梯度下降法 Mini-Batch Gradient Descent 较快较精确

随机的优势:

  • 跳出局部最优解

  • 更快的运行速度

  • 机器学习领域很多算法都要使用随机的特点

随即搜索:随机森林

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值