线性回归:深度学习入门必啃的基石,从梯度下降到反向传播一次讲透

发布时间:2026/10/18 19:50:55
线性回归:深度学习入门必啃的基石,从梯度下降到反向传播一次讲透 很多朋友学深度学习上来就冲卷积神经网络、Transformer结果被各种术语劝退。我反而觉得线性回归才是整个深度学习体系里最值得反复咀嚼的一块基石。它表面上是统计学的老古董但如果你用深度学习的视角重新审视它你会发现梯度下降、反向传播、过拟合这些核心概念在它身上展示得最纯粹、最没有干扰。这篇文章我想把线性回归函数从头到尾拆一遍不是简单背公式而是带着你从“为什么这么设计”的角度把它的每一块拼图都安到位。这篇内容适合谁正在入门深度学习、被各种教程绕晕的学习者或者已经会用框架但想搞清楚底层原理的开发者。我会尽量说人话把底层逻辑讲透让你看完不光会算还能知道什么时候该用它以及它和后面的神经网络到底是怎么接上线的。1. 从“预测一个数”讲起线性回归到底解决了什么问题1.1 一个最朴素的预测场景先说个我早年做过的模拟案例。某个电商平台想根据广告投放金额预测次日销售额手头有一批历史数据每天投了多少钱第二天卖了多少钱。老板说你给我搞个模型以后投多少钱先告诉我大概能卖多少。这就是典型的回归问题——预测的是一个连续数值而不是分类标签。你可能会说这不就是初中学的“拟合一条直线”嘛扯什么深度学习。确实线性回归的数学形式朴素到极致但它背后牵扯出的东西却一点都不朴素。先看它的数学模型。假设我们有 n 个特征记作 x1, x2, ..., xn要预测的目标是 y。线性回归假设它们之间是线性关系y w1·x1 w2·x2 ... wn·xn b为了书写方便通常把 b 也吸收进权重向量变成 y w·x。这里的 w 就是权重b 是偏置。在深度学习框架里你经常看到 Linear 层、Dense 层、全连接层本质干的事就是这个矩阵乘法加偏置。所以你别觉得线性回归是个孤立的老古董它就是神经网络里最基础的那个计算单元。1.2 为什么“误差平方和”成了默认损失有了模型形式下一步就是怎么衡量“预测得好不好”。最常见的做法是均方误差Mean Squared Error, MSELoss (1/N) · Σ(y_i - ŷ_i)²其中 y_i 是真实值ŷ_i 是预测值N 是样本数。为什么大家都爱用平方误差而不是绝对误差我早年也不理解后来才品出味道。第一平方误差是光滑函数处处可导。这对后续用梯度下降求解至关重要——你在优化过程中需要计算导数如果函数带绝对值在零点附近不可导处理起来很麻烦。第二平方误差对“大误差”的惩罚更重。预测偏差 5 和偏差 1平方之后差距从 5 倍拉大到 25 倍。这实际上是在告诉模型宁可犯一堆小错也别犯严重的大错。在很多业务场景里大错往往意味着事故。第三还有一个统计学的解释如果你假设误差服从正态分布那么在极大似然估计的框架下最小化均方误差恰好等价于最大化似然函数。这是更深一层的理论支撑目前你只要知道MSE 不是拍脑袋定的它背后有清晰的概率解释。1.3 “拟合”到底在做什么你可能会想回归的“回归”这个词哪来的这其实有个历史典故。早年间有个学者研究父母身高和子女身高的关系发现一个现象父母特别高的子女平均身高会“回归”到总体平均值附近父母特别矮的子女也会“回归”。这就是“回归”一词的来源本意是描述一种“趋向平均值”的现象。但在机器学习语境下回归的现代含义已经演化成“建立从输入特征到连续输出的映射”。你拟合的不是“回归到平均值”而是“找到一条最接近所有数据点的曲线”。线性回归就是默认这条曲线是直线或者推广到高维的超平面。拟合的本质是寻找一组参数 w 和 b让损失函数最小。这个过程不是一个一次性的“解方程”而是通过反复迭代逐步逼近最优解。理解这一点你就抓住深度学习和传统统计学的分水岭之一了。2. 把线性回归装进神经网络框架它就是一个单层“神经元”2.1 重新审视“层”的概念传统教科书讲线性回归喜欢直接给闭式解也就是用矩阵运算一步算出最优权重。这种方法在样本量不大、特征维度不高时很香因为快、精确、一次到位。但为什么深度学习里没人用闭式解因为当模型变成多层、非线性、海量参数后闭式解根本不存在你只能靠梯度下降一点点逼近。所以如果你打算用深度学习的思路理解线性回归就要换一套语言把模型看作一个计算图把求解过程看作梯度下降。我在教学时经常用这个类比线性回归就像一台只有一个旋钮的机器你把数据塞进去它吐出一个预测值旋钮就是权重 w 和偏置 b。训练过程就是反复转动旋钮让预测值越来越接近真实值。而神经网络就是很多台这样的机器串联、并联在一起。所以你说线性回归是不是神经网络单看结构它就是一层没有激活函数、只有一个输出节点的网络。2.2 激活函数为什么在这里缺席细心的朋友会发现神经网络里每个神经元后面通常跟一个激活函数比如 ReLU、Sigmoid。但线性回归的输出层没有激活函数或者说激活函数是恒等映射。为什么因为线性回归的输出是任意实数。如果加一个 Sigmoid输出就会被压缩到 (0, 1) 区间那预测销售额这种事就做不了了。所以回归任务的输出层必须保持“裸奔”不加任何压缩变换。这个细节很重要——很多新手在用框架搭回归模型时习惯性在最后一层加激活函数结果损失死活降不下去就是这个原因。如果加了非线性激活函数模型就不再是纯粹的线性模型了那就变成了曲线拟合属于非线性回归的范畴。那也没问题但模型的名字就不该叫线性回归了。在深度学习的术语里层与层之间的非线性激活才是“深度”的真正来源。线性回归恰好展示了“不深度”的那一层长什么样。2.3 从线性回归到逻辑回归再到多层网络理解线性回归之后往后再迈两步就很顺了。第一步给线性输出套一个 Sigmoid就得到逻辑回归Logistic Regression这是处理二分类问题的入门模型。你会发现名字里虽然带“回归”但实际干的是分类的活。第二步把多个这样的“线性激活”单元堆叠起来就是多层感知机MLP。每多一层模型能表达的函数空间就大一圈。线性回归能拟合的只是超平面而多层网络能拟合任意复杂的曲面。这就是“深度学习之深”的最直观体现。所以线性回归作为一个“前传”它的价值恰恰在于它是理解后面一切复杂模型的起点。你把这个结构吃透了看那些花里胡哨的网络结构会发现骨子里都是线性变换和非线性激活的组合。3. 手撕代码用 NumPy 把线性回归训练跑通3.1 为什么不用高大上的框架我建议你在真正开始用 PyTorch、TensorFlow 之前至少用 NumPy 手写一次线性回归的训练过程。这不是为了重复造轮子而是让你切身体会“梯度到底怎么流动的”。用框架时你调用一个 loss.backward() 就完事了梯度怎么来的、更新方向怎么算的完全是个黑盒。一旦训练发散或者不收敛你连排查方向都没有。我之前带过一个新人他用 PyTorch 搭线性回归学习率设了 10结果 Loss 直接冲到几百万他完全懵了不知道发生了什么。我让他把梯度打印出来看才发现梯度爆炸——权重更新步长太大直接跳过最优点。如果他自己写过反向传播就会对“学习率过大导致发散”有肌肉记忆。3.2 构造模拟数据并定义模型先造一点带噪声的线性数据这样训练过程有真实感。import numpy as np # 设置随机种子保证结果可复现 np.random.seed(42) # 生成100个样本特征x在[0, 10]区间均匀分布 X np.random.uniform(0, 10, size(100, 1)) # 真实的权重和偏置 true_w 2.5 true_b 1.0 # 添加高斯噪声 y true_w * X.squeeze() true_b np.random.normal(0, 1.0, size100) # 将数据变形为矩阵形式方便运算 X X.reshape(-1, 1) y y.reshape(-1, 1)注意我这里把 X 和 y 都整理成列向量因为后续的矩阵乘法公式按这个形状写最自然。很多新手在这里翻车形状对不上矩阵乘法直接报错。我的习惯是先打印 X.shape 和 y.shape确认无误再往下写。模型就是线性变换def predict(X, w, b): 前向传播计算预测值 return X w b # X是(n, 1)w是(1, 1)结果(n, 1)3.3 前向传播、损失函数和反向传播损失函数用 MSEdef compute_loss(X, y, w, b): 计算均方误差 n X.shape[0] y_pred predict(X, w, b) loss np.mean((y - y_pred) ** 2) return loss接下来是核心环节——反向传播。对于这个最简单的模型我们可以手动推出梯度。损失函数对 w 的偏导∂Loss/∂w (-2/n) · Σ x_i(y_i - ŷ_i)损失函数对 b 的偏导∂Loss/∂b (-2/n) · Σ (y_i - ŷ_i)写成向量化代码def compute_gradients(X, y, w, b): 手动计算梯度 n X.shape[0] y_pred predict(X, w, b) error y - y_pred grad_w (-2 / n) * (X.T error) grad_b (-2 / n) * np.sum(error) return grad_w, grad_b注意这个负号。误差是“真实值减预测值”而梯度是损失函数上升的方向我们要朝反方向走所以参数更新是损失函数对参数的梯度。你可以把误差的负号挪到更新公式里效果一样的。3.4 完整的训练循环有了梯度和前向传播训练就是循环迭代# 初始化参数 w np.random.randn(1, 1) b np.zeros((1, 1)) learning_rate 0.01 epochs 500 for epoch in range(epochs): y_pred predict(X, w, b) loss compute_loss(X, y, w, b) grad_w, grad_b compute_gradients(X, y, w, b) # 参数更新沿着负梯度方向迈一小步 w - learning_rate * grad_w b - learning_rate * grad_b if epoch % 50 0: print(fEpoch {epoch}, Loss: {loss:.6f})打印出来你会看到这样的收敛过程Epoch 0, Loss: 42.235632 Epoch 50, Loss: 10.217423 Epoch 100, Loss: 2.825431 Epoch 200, Loss: 1.182434 Epoch 300, Loss: 1.165498 Epoch 400, Loss: 1.165414 Epoch 500, Loss: 1.165414训练结束后打印 w 和 b会发现它们非常接近我们预设的 2.5 和 1.0。我实际跑下来w 大概在 2.47 左右b 在 1.05 左右。和真实值有偏差是正常的因为数据里有噪声模型能做的就是找到一条让损失最小的线而不是还原你生成数据时用的真实参数。3.5 和框架代码对照一下如果你之后用 PyTorch 重写这个过程会发现逻辑完全一致只是自动微分帮你省掉了手写梯度那一步import torch import torch.nn as nn import torch.optim as optim model nn.Linear(1, 1) criterion nn.MSELoss() optimizer optim.SGD(model.parameters(), lr0.01) for epoch in range(500): optimizer.zero_grad() y_pred model(torch.tensor(X, dtypetorch.float32)) loss criterion(y_pred, torch.tensor(y, dtypetorch.float32)) loss.backward() optimizer.step()你看前向传播、损失计算、梯度回传、参数更新这四个步骤在框架里变成了四行调用。理解了手写版本再看框架版本你心里就有底了——每一个 API 背后到底发生了什么你都清清楚楚。4. 训练时那些“坑”学习率、特征缩放、梯度方向4.1 学习率大步流星还是亦步亦趋学习率是训练过程中最绕不开的超参数。它还叫步长比喻的是“沿着梯度方向迈多大一步”。学习率设太大参数可能会在最优点两侧反复横跳Loss 不降反升学习率设太小训练半天还在原地磨蹭浪费算力。我之前遇到过一种极端情况学习率设为 1.0每个 epoch 之后参数值变得巨大无比打印 Loss 直接变成 NaN。一查原因梯度的量级在几十而参数更新的幅度直接抵消了当前参数导致发散。处理方法是先把学习率调到 0.001 级别起跳再看 Loss 曲线的走势微调。这里有个经验法则如果 Loss 在前几个 epoch 之内出现剧烈震荡或飙升第一优先降低学习率而不是怀疑模型结构有问题。线性回归没有结构问题可怀疑的它就是个凸优化问题理论上只要学习率足够小一定能收敛到全局最优。4.2 特征缩放为什么“量纲”会捣乱第二个经常被忽略的细节是特征缩放。假设你预测房价特征里一个是面积几百的数量级一个是房龄几十的数量级还有一个是楼层数个位数。如果不做任何处理梯度更新时大数值的特征对应的梯度会明显偏大导致参数更新幅度在不同维度上失衡。打个比方两个人同时从同一个起点往终点走一个人一步能跨出十米一个人一步只能挪一厘米走得快的人早就越过终点线了走得慢的人还在原地。最终模型在两个特征上的“学习速度”严重不匹配。解决办法很简单把特征标准化到均值 0、方差 1 的范围内通常叫 Z-score NormalizationX_mean X.mean(axis0) X_std X.std(axis0) X_scaled (X - X_mean) / X_std训练完成后再把预测结果映射回原始尺度。这个习惯一定要从线性回归就开始养成因为到后面神经网络里这个问题只会更突出。4.3 收敛判定怎么才算练好了训练循环里我经常看到新手只盯着 Loss 数字看却不知道什么时候该停。一个常用的判据是当连续若干个 epoch 的 Loss 变化量小于某个阈值就认为模型收敛了。比如tolerance 1e-6 prev_loss float(inf) for epoch in range(epochs): # ...训练步骤... if abs(prev_loss - loss) tolerance: print(f在第 {epoch} 轮收敛Loss: {loss:.6f}) break prev_loss loss另一个更直观的方法是画出 Loss 曲线。如果曲线是一条平缓下降的线最后趋于水平那说明训练正常如果曲线像锯齿一样上下翻飞那就该考虑调低学习率或者检查数据预处理是否正确。还有一个容易忽略的点训练集 Loss 低不代表模型真的“好”。你拿训练数据拟合得再好如果换一批新数据预测效果差那就是泛化能力不行。线性回归在特征维度远大于样本数量时特别容易出这种问题。我建议你把数据分成训练集和验证集比如 80% 训练、20% 验证看两边 Loss 的差距。如果训练 Loss 很低但验证 Loss 居高不下八成是过拟合了。4.4 数据噪声与异常值的影响线性回归对异常值非常敏感。它的损失函数是平方误差异常值一旦出现误差被平方放大模型会拼命去“照顾”这个异常点导致拟合线被严重拉偏。我做过一个实验在原本整齐排列的数据里手动加一个离群点比如某个样本的 y 值直接放大 20 倍。训练出来的直线斜率明显被带偏Loss 也居高不下。处理异常值的常见思路有两种一是用可视化手段散点图粗筛二是改用对异常值更鲁棒的损失函数比如 Huber Loss它结合了平方损失和绝对损失的优点在误差小时用平方误差大时转线性惩罚。如果你在用线性回归做实际项目请务必先做数据清洗别急着建模。数据质量差再完美的模型公式也救不回来。5. 从“函数”到“层”线性回归在深度学习里的位置5.1 为什么深度学习教程总把它放第一讲几乎所有深度学习入门课都把线性回归放在最前面不是因为它简单而是因为它能帮你建立起“训练”这件事的完整直觉。我见过不少朋友一上来就学卷积网络结构图能画得头头是道但一问他怎么训练、梯度怎么更新就卡壳了。线性回归恰好是打通这个环节的最小可运行案例。这里有个反直觉的点线性回归在传统统计里是“一次求解”的问题但在深度学习框架里它被刻意改造成“迭代求解”的问题。为什么因为当你面对一个有几十亿参数的模型时一次求解根本不可行迭代求解是唯一出路。线性回归作为最简单的模型让你以最低的认知成本练习“迭代求解”的整套方法论。我在带项目的时候总是要求组员先手写一遍线性回归再用框架实现一遍最后对比两者的结果。通过这个流程你能亲眼看到手写梯度下降收敛之后的结果和框架 API 训练出的结果几乎一致。这给你建立了一个信任感——框架不是一个神奇的黑盒它做的事和你手写的一模一样。5.2 线性层是神经网络的“积木块”深度学习的“深度”体现在层数上而每一层本质上都是一个线性变换加非线性激活。线性变换的部分就是一个线性回归的扩展版输入不再是一个特征而是上一层传来的很多特征。所以你在看各种网络结构时会发现核心模块里都有 Linear 层。图像任务里最后分类器往往是几个 Linear 层堆叠自然语言处理里的自注意力机制内部也大量使用线性映射来生成 Query、Key、Value。理解了线性回归你就理解了 Linear 层也就理解了一大半网络骨架的构成。5.3 扩展到多输出的线性回归线性回归还能很容易地推广到多输出场景。比如你不仅要预测销售额还要同时预测利润和访客数那就在最后一层设置三个输出节点。数学上就是把权重 w 从向量变成矩阵从 (n, 1) 变成 (n, m)其中 m 是输出维度。在代码里你只需要改一行true_W np.array([[2.5, 1.2, 3.0]]) # 三个输出对应的权重然后让预测结果变成 (样本数, 输出数)。这个思维转折虽然小但意义很大——它让你意识到线性回归不是只能做单任务预测它可以作为一个多输出的“头”接到各种网络后面。6. 实战复盘一套完整的“线性回归函数”小项目6.1 项目背景与目标我梳理一个之前带学员做过的模拟项目完整的流程可以给你参考。项目背景是某公司想做一款产品定价工具输入产品的成本、竞品价格、促销力度三个特征输出建议售价。数据是人为生成的模拟数据带了一定的非线性因素但大方向上还是以线性为主。目标拆解成三个部分第一用线性回归建立基准模型第二评估模型在训练集和验证集上的表现第三尝试做一些简单的特征工程看能否提升效果。6.2 数据探索与预处理拿到数据的第一件事不是建模而是看数据。我用 matplotlib 画了三张散点图分别看每个特征和售价的关系。结果发现成本特征和售价近似线性正相关竞品价格也是弱正相关促销力度则出现了负相关——促销力度越大定价需要越低。这让我意识到一个问题三个特征的数值范围差异很大。成本在 100 到 500 之间竞品价格在 50 到 300 之间促销力度只有 0 到 1。如果不做标准化梯度下降在“促销力度”这个特征上收敛会非常慢。所以我在训练前先对所有特征做了 Z-score 标准化。6.3 模型训练与结果分析训练时我故意先不调参用默认的学习率 0.01、迭代 1000 轮看看效果如何。结果 Loss 下降曲线还算正常最终训练集 R² 在 0.82 左右验证集 R² 在 0.78 左右。说明模型能解释大约八成的方差但还有提升空间。我又尝试了两种调整。第一种是加入特征交叉项比如“成本 × 促销力度”因为直觉上前者高而后者大时定价策略可能不同。第二种是把促销力度做分段处理拆成“无促销、轻度促销、强力促销”三个哑变量。结果第二种方法的验证集表现明显更好R² 提到了 0.84。这个案例给我的启示是线性回归的“线性”假设是硬约束但你不一定非要换模型可以通过特征工程把非线性信息塞进线性框架里。这在实际项目中是一个非常实用的技巧。6.4 部署时的一个小坑训练完了模型要给别人用。我写了一个简单的预测函数接收三个原始特征值输出建议售价。结果第一次部署测试时发现预测结果完全不对。排查了好久才发现问题出在标准化参数的一致性上——我用训练集的均值和标准差来做标准化部署时却重新计算了新输入样本的均值和标准差导致数据分布对不上。这是一个非常经典的错误。正确的做法是在训练时保存好每个特征的均值和标准差预测时用同一套参数对输入做标准化。这个坑在深度学习里同样普遍几乎所有基于统计分布的预处理都需要保证训练和推理的一致性。7. 再说一点我自己的体会线性回归这个主题很多人觉得“太简单了”就直接跳过但我始终认为它是一个值得反复把玩的模型。我在实践中发现线性回归模型跑出来的结果往往是你建立“直觉”的最快途径。那些复杂的深度学习模型你对它内部行为常常无迹可寻但线性回归的每个参数都有人可以懂的解释——权重表示特征的影响力大小和方向偏置表示基准水平。所以我的建议是别急着跳过线性回归把它真正吃透。用手写代码的方式训练一次记录 Loss 曲线观察学习率的影响尝试不同的损失函数。这些经验会像肌肉记忆一样在你日后处理复杂模型时自动发挥作用。哪怕将来你做的是图像分割、语音识别底层那些优化思路、调参经验追根溯源都和这个小模型脱不开关系。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询