吴恩达机器学习课程 笔记2 第一个模型 线性回归梯度下降
线性回归模型
在机器学习中,线性回归模型是一种用于预测连续数值型目标变量的监督学习算法。它假设目标变量与一个或多个自变量之间存在线性关系,并尝试通过拟合最佳线性函数来预测未知数据的输出。下面是机器学习中线性回归模型的详细讲解:
模型定义
线性回归模型可以分为简单线性回归和多元线性回归。
简单线性回归
简单线性回归只涉及一个自变量 ( x ) 和一个因变量 ( y ),模型的形式为:
其中:
- ( y ) 是因变量(目标)。
- ( x ) 是自变量(特征)。
- ( \beta_0 ) 是截距项。
- ( \beta_1 ) 是斜率(权重)。
- ( \epsilon ) 是误差项,代表了模型无法解释的随机噪声。
多元线性回归
当存在多个自变量时,可以扩展模型来包括所有这些变量。多元线性回归模型的一般形式为:
损失函数与优化
为了找到最优的参数 ( \beta ),我们需要定义一个损失函数来量化预测值与实际值之间的差异。最常见的损失函数是最小二乘误差(Mean Squared Error, MSE):
我们的目标是最小化 MSE,以找到最优的 ( \beta ) 参数。
参数估计方法
解析解法(普通最小二乘法,OLS)
对于较小的数据集,可以直接求解参数的解析解。使用矩阵形式,可以写成:
其中:
- ( X ) 是特征矩阵(每一行是一个观测值,每一列是一个特征)。
- ( y ) 是目标向量。
- ( X^T ) 是 ( X ) 的转置。
- ( (X^T X)^{-1} ) 是 ( X^T X ) 的逆矩阵。
数值优化法(梯度下降等)
对于大规模数据集,解析解可能计算成本过高,此时可以使用数值优化方法,如梯度下降法。梯度下降法通过迭代更新参数 ( \beta ),以最小化损失函数。
梯度下降的更新公式为:
其中:
- ( \alpha ) 是学习率,决定了每次更新的步长。
正则化
为了避免过拟合(模型在训练数据上表现很好但在新数据上表现不佳),可以引入正则化项来惩罚参数的过大值。常见的正则化方法有岭回归(Ridge Regression)和LASSO回归(Least Absolute Shrinkage and Selection Operator)。
岭回归
在损失函数中加入L2正则化项:
LASSO回归
在损失函数中加入L1正则化项:
应用场景
线性回归适用于预测连续数值型变量,如房价预测、销售预测等。尽管它的假设条件较为严格,但在实际应用中仍然非常广泛,尤其是在数据量较大且关系较为线性的情况下。
注意事项
尽管线性回归简单有效,但在使用时需要注意以下几点:
- 确保数据满足线性假设。
- 检查数据是否有异常值。
- 使用交叉验证等技术来评估模型的泛化能力。
- 考虑特征缩放(标准化或归一化)以提高模型性能。
- 考虑使用正则化来防止过拟合。
通过以上介绍,可以看出线性回归在机器学习中是一个非常基础但又极其重要的模型,它为理解和应用更复杂的机器学习算法提供了坚实的基础。
代价函数
在机器学习中,特别是监督学习中,代价函数(或损失函数、成本函数)是用来衡量模型预测值与实际值之间的差异。不同的模型可能使用不同的代价函数,具体取决于问题的类型(如回归问题或分类问题)以及模型的设计目标。
对于线性回归来说,一个常见的代价函数是均方误差(Mean Squared Error, MSE),其公式如下:
其中:
- ( m ) 是训练样本的数量;
- ( x^{(i)} ) 是第 ( i ) 个训练样本的特征向量;
- ( y^{(i)} ) 是第 ( i ) 个训练样本的真实值;
- ( h_\theta(x^{(i)}) ) 是模型根据参数 ( \theta ) 对第 ( i ) 个训练样本 ( x^{(i)} ) 的预测值;
- 1/2的因子是为了简化梯度下降法中的数学运算(使得导数更简洁)。
线性回归的目标找到合适的参数w、b,使得minimize J(w,b)
对于逻辑回归等分类问题,通常会使用交叉熵损失(Cross-Entropy Loss)。二分类问题中,交叉熵损失可以表示为:
这里:
- ( h_\theta(x^{(i)}) ) 表示模型预测的概率,即样本 ( x^{(i)} ) 属于正类(通常是类别1)的概率;
- ( \log ) 是自然对数;
- 这个公式衡量了模型预测的概率分布与真实标签之间的差异。
这些代价函数的目标是在给定的数据集上最小化误差,从而优化模型的参数 ( \theta ),使得模型能够更好地拟合数据。在实际应用中,可能会根据具体情况调整代价函数的形式以适应特定的需求。
可视化代价函数
import numpy as np import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D # 定义一个简单的线性回归的代价函数 def cost_function(params): theta1, theta2 = params # 假设我们的数据是固定的,这里创建一些示例数据 X = np.array([1, 2, 3, 4, 5]) y = np.array([2, 3, 5, 7, 11]) # 添加偏置项 X = np.column_stack((np.ones(X.shape), X)) # 计算预测值 predictions = X @ params # 计算均方误差 error = predictions - y return (1/(2 * len(X))) * np.sum(error**2) # 创建参数网格 theta1 = np.linspace(-10, 10, 100) theta2 = np.linspace(-10, 10, 100) Theta1, Theta2 = np.meshgrid(theta1, theta2) # 初始化J_values数组 J_values = np.zeros(Theta1.shape) # 计算代价函数的值 for i in range(len(theta1)): for j in range(len(theta2)): J_values[i, j] = cost_function(np.array([Theta1[i, j], Theta2[i, j]])) # 创建三维图形 fig = plt.figure() ax = fig.add_subplot(111, projection='3d') ax.plot_surface(Theta1, Theta2, J_values, cmap='viridis') # 设置标签 ax.set_xlabel('theta1') ax.set_ylabel('theta2') ax.set_zlabel('Cost') # 显示图形 plt.show()
梯度下降
机器学习中的梯度下降是一种用于求解最小化问题(如最小化损失函数)的优化算法。它通常用于训练模型参数,使得预测误差尽可能小。梯度下降的基本思想是通过迭代更新参数来逐渐逼近损失函数的最小值点。
梯度下降的概念
在最简单的形式中,假设有一个需要最小化的损失函数 ( J(\theta) ),其中 ( \theta ) 是模型的参数向量。梯度下降的目标是找到一组参数 ( \theta ),使得 ( J(\theta) ) 达到最小值。
梯度是一个向量,表示了损失函数在某一点上的变化方向和速率。对于单个参数 ( \theta_i ),其梯度就是损失函数在该参数上的偏导数 ( \frac{\partial J}{\partial \theta_i} )。
梯度下降的过程
- 初始化参数:选择一个初始参数值 ( \theta^{(0)} )。
- 计算梯度:计算损失函数在当前参数下的梯度。
- 更新参数:使用下面的公式更新参数:
其中 ( \alpha ) 是学习率(learning rate),决定了每次更新的步长大小。 - 重复步骤:重复步骤 2 和 3 直到满足某个停止条件(比如达到最大迭代次数或梯度接近零)。
梯度下降的类型
- 批量梯度下降(Batch Gradient Descent):每次更新参数时使用所有训练样本计算梯度。
- 随机梯度下降(Stochastic Gradient Descent, SGD):每次只用一个训练样本来估计梯度并更新参数。
- 小批量梯度下降(Mini-batch Gradient Descent):每次使用一个小批量的样本来估计梯度,这是实际中最常用的变体。
实现梯度下降
以 Python 和 NumPy 为例,这里展示一个简单的批量梯度下降的实现流程:
import numpy as np def compute_cost(X, y, theta): # 计算损失函数 m = len(y) predictions = X.dot(theta) cost = (1. / (2 * m)) * np.sum(np.square(predictions - y)) return cost def gradient_descent(X, y, theta, alpha, num_iters): m = len(y) J_history = np.zeros(num_iters) for i in range(num_iters): predictions = X.dot(theta) error = np.dot(X.transpose(), (predictions - y)) theta = theta - (alpha / len(X)) * error J_history[i] = compute_cost(X, y, theta) return theta, J_history # 初始化数据 X = np.random.rand(100, 1) # 假设有100个样本,每个样本有1个特征 y = np.random.rand(100, 1) # 假设输出也是1维的 theta = np.zeros((1, 1)) # 初始参数 alpha = 0.01 # 学习率 num_iters = 1500 # 迭代次数 # 调用梯度下降函数 theta, J_history = gradient_descent(X, y, theta, alpha, num_iters)
以上代码定义了一个计算损失函数的方法 compute_cost
和一个执行梯度下降的函数 gradient_descent
。在实际应用中,需要根据具体的问题调整学习率、迭代次数等超参数,并且可能还需要考虑正则化项等复杂情况。
学习率
学习率(Learning Rate)是在机器学习和深度学习中非常重要的一个超参数。它控制着模型参数更新的速度,具体来说,在训练过程中,当模型计算出预测结果与实际结果之间的差距(即损失函数的值)后,会根据这个差距调整模型参数,以便下次能够更好地预测。学习率决定了这种调整的幅度。
学习率的作用
学习率决定了在每次迭代时,模型参数向损失函数最小值方向移动的步长。较高的学习率意味着更大的步长,较低的学习率意味着较小的步长。学习率的选择对模型训练的效果至关重要:
- 学习率过高:可能导致模型在寻找损失函数最小值的过程中跨越最低点,从而导致训练不稳定,甚至不能收敛。
- 学习率过低:虽然可以保证模型逐渐靠近最小值,但也会导致训练过程非常缓慢,需要更多的迭代次数才能收敛,增加了训练时间和计算成本。
如何选择学习率
由于学习率对训练的影响如此重要,所以在实践中通常需要进行一些实验来找到合适的值。常用的方法包括:
- 手动调整:基于经验,尝试几个不同的学习率值,观察模型的表现。
- 网格搜索:系统地尝试一系列预定义的学习率值。
- 随机搜索:随机选择学习率值,以减少搜索空间。
- 自适应学习率算法:使用像 AdaGrad、RMSProp 或 Adam 这样的算法,它们能够在训练过程中自动调整学习率。
自适应学习率调整
自适应学习率算法试图解决固定学习率带来的问题。这些算法会根据梯度的历史信息来动态调整学习率,从而在训练初期快速收敛,同时在接近最小值时减小步长,防止过冲。
- AdaGrad:根据每个参数的历史梯度累积平方和来调整学习率。
- RMSProp:改进了 AdaGrad,通过使用滑动窗口平均来限制历史梯度累积的影响。
- Adam:结合了 AdaGrad 和 RMSProp 的优点,并加入了动量(Momentum)的思想来加速收敛。
总结
学习率的选择对模型训练的成功至关重要。一个好的学习率可以帮助模型快速且稳定地收敛到一个最小损失值。然而,没有一种“万能”的学习率适用于所有情况,通常需要根据具体问题和数据集进行调整。此外,使用自适应学习率算法可以简化这一过程,并提高模型训练的质量。
用于线性回归的梯度下降
代码实现示例
import numpy as np # 定义损失函数 def compute_cost(X, y, theta): """ 计算损失函数值(均方误差)。 :param X: 特征矩阵 :param y: 目标向量 :param theta: 参数向量 :return: 损失函数值 """ m = len(y) predictions = X @ theta cost = (1. / (2 * m)) * np.sum(np.square(predictions - y)) return cost # 定义梯度计算函数 def compute_gradient(X, y, theta): """ 计算损失函数关于参数的梯度。 :param X: 特征矩阵 :param y: 目标向量 :param theta: 参数向量 :return: 梯度向量 """ m = len(y) predictions = X @ theta error = predictions - y grad = (1. / m) * (X.T @ error) return grad # 梯度下降算法实现 def gradient_descent(X, y, theta, alpha, num_iters): """ 使用梯度下降法优化参数。 :param X: 特征矩阵 :param y: 目标向量 :param theta: 初始参数向量 :param alpha: 学习率 :param num_iters: 最大迭代次数 :return: 优化后的参数向量和每轮迭代的成本记录 """ m = len(y) J_history = np.zeros(num_iters) for i in range(num_iters): grad = compute_gradient(X, y, theta) theta -= alpha * grad J_history[i] = compute_cost(X, y, theta) return theta, J_history # 示例数据 X = np.array([[1, 2], [1, 3], [1, 4]]) # 添加一列1作为偏置项 y = np.array([3, 5, 7]).reshape(-1, 1) # 输出向量 # 初始化参数 theta = np.zeros((X.shape[1], 1)) # 设置学习率和迭代次数 alpha = 0.01 num_iters = 1500 # 运行梯度下降 theta_opt, J_history = gradient_descent(X, y, theta, alpha, num_iters) print("Optimal theta:", theta_opt) print("Final cost:", J_history[-1])
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix