一、什么是前向传播
1. 一句话概括
前向传播 是指神经网络从输入层 开始,经过中间各层的计算处理,最终得到输出层结果的过程。它是神经网络进行"推理"或"预测"的计算流程。
2. 前向传播具体做了什么事?
以一个简单的三层神经网络(输入层、隐藏层、输出层)为例,前向传播依次完成以下工作:
步骤 1:输入层接收数据
将原始数据(如图像像素、文本向量等)输入到网络的输入层。每个输入节点对应数据的一个特征。
步骤 2:逐层进行加权求和与激活
这是最核心的计算,对于相邻两层之间的每一个神经元:
-
加权求和 :当前层的每个神经元,都会接收来自上一层所有神经元的输出值,并将这些值与其对应的权重 相乘后求和,再加上一个偏置项。
- 公式可表示为:
z = (上一层输出1 * 权重1) + (上一层输出2 * 权重2) + ... + 偏置
- 公式可表示为:
-
激活函数 :将上一步得到的加权求和结果
z,输入到一个非线性激活函数(如ReLU、Sigmoid、Tanh)中。- 公式:
a = f(z) - 为什么需要激活函数? 如果不使用非线性激活函数,无论神经网络有多少层,其效果都等同于一个单层线性模型,无法学习复杂的非线性模式。
- 公式:
步骤 3:重复直到输出层
将步骤 2 得到的激活值 a 作为下一层神经元的输入,重复"加权求和 + 激活"的过程,一层一层地向前推进。
步骤 4:得到最终输出
当数据传递到最后一层(输出层)时,经过计算得到网络的最终输出。
- 对于回归任务,输出可能是一个具体的数值。
- 对于分类任务 ,输出通常需要经过一个Softmax函数,转化为各个类别的概率分布。
3. 前向传播的图示与公式(以单隐藏层为例)
假设:
- 输入
x - 隐藏层权重
W1,偏置b1,激活函数f - 输出层权重
W2,偏置b2,激活函数g
前向传播过程:
-
隐藏层计算:
z1 = W1 * x + b1 a1 = f(z1) # f 例如是 ReLU -
输出层计算:
z2 = W2 * a1 + b2 a2 = g(z2) # g 根据任务选择,例如回归用线性,分类用 Softmax最终,
a2就是网络的预测输出y_pred。
二、激活函数
1. 什么是激活函数?
激活函数 就是神经网络中的一个"开关"或"加工函数",它决定了神经元是否被激活、以及激活到什么程度。
数学上,神经网络的一层会做两件事:
- 线性加权求和:
z=w1x1+w2x2+⋯+bz = w_1 x_1 + w_2 x_2 + \dots + bz=w1x1+w2x2+⋯+b
这里 zzz 是输入加权加偏置的结果,仍然是线性的。 - 然后对这个结果 zzz 施加一个非线性 函数 σ(z)\sigma(z)σ(z),得到这一层的输出:
a=σ(z)a = \sigma(z)a=σ(z)
这个 σ\sigmaσ 就是激活函数,常见的比如 Sigmoid、ReLU、tanh 等。
2. 为什么要激活函数?
核心答案:为了引入非线性。
如果没有激活函数,神经网络无论多少层,都只是在做线性变换的组合,最终效果等价于单层线性模型(比如线性回归),无法拟合复杂的非线性关系。
举个例子:
假设我们有两个线性层:
y=W2(W1x+b1)+b2y = W_2 (W_1 x + b_1) + b_2y=W2(W1x+b1)+b2
简化:
y=(W2W1)x+(W2b1+b2)y = (W_2 W_1) x + (W_2 b_1 + b_2)y=(W2W1)x+(W2b1+b2)
结果还是 y=W′x+b′y = W' x + b'y=W′x+b′,只是一个线性模型。
但如果我们加激活函数:
y=W2⋅σ(W1x+b1)+b2y = W_2 \cdot \sigma(W_1 x + b_1) + b_2y=W2⋅σ(W1x+b1)+b2
因为 σ\sigmaσ 是非线性的,整体就变成了非线性模型,可以拟合曲线、分复杂边界等。
3. 一个通俗的例子:用神经网络拟合 y=x2y = x^2y=x2
第一步:数据与目标
我们有一组数据点:
x=−2,−1,0,1,2x = -2, -1, 0, 1, 2x=−2,−1,0,1,2
对应的真实值:
y=4,1,0,1,4y = 4, 1, 0, 1, 4y=4,1,0,1,4
这是一个抛物线,是非线性的。
第二步:搭建简单网络
假设我们用一个隐藏层(2个神经元)来完成。
第 1 层(隐藏层):
- 神经元1:输入 xxx,计算 z1=w11x+b1z_1 = w_{11} x + b_1z1=w11x+b1,然后 a1=σ(z1)a_1 = \sigma(z_1)a1=σ(z1)
- 神经元2:输入 xxx,计算 z2=w12x+b2z_2 = w_{12} x + b_2z2=w12x+b2,然后 a2=σ(z2)a_2 = \sigma(z_2)a2=σ(z2)
第 2 层(输出层):
- 输出:ypred=v1a1+v2a2+cy_{\text{pred}} = v_1 a_1 + v_2 a_2 + cypred=v1a1+v2a2+c
如果我们选择 σ\sigmaσ 为 ReLU 函数:
σ(t)=max(0,t)\sigma(t) = \max(0, t)σ(t)=max(0,t)
第三步:如何拟合 x2x^2x2
我们可以这样思考:
x2x^2x2 曲线可以用多个"折线"分段近似,而 ReLU 函数的核心特性是生成带折点的半直线,多个ReLU的线性加权组合,能拼出逼近抛物线的分段线性曲线。
先明确一个ReLU的恒等式(对任意实数xxx成立):
x2=ReLU(x)2+ReLU(−x)2x^2 = \text{ReLU}(x)^2 + \text{ReLU}(-x)^2x2=ReLU(x)2+ReLU(−x)2
验证:
- x=2x=2x=2:左边444,右边ReLU(2)2+ReLU(−2)2=4+0=4\text{ReLU}(2)^2+\text{ReLU}(-2)^2=4+0=4ReLU(2)2+ReLU(−2)2=4+0=4
- x=−2x=-2x=−2:左边444,右边ReLU(−2)2+ReLU(2)2=0+4=4\text{ReLU}(-2)^2+\text{ReLU}(2)^2=0+4=4ReLU(−2)2+ReLU(2)2=0+4=4
- x=0x=0x=0:左边000,右边0+0=00+0=00+0=0
但实际神经网络中,隐藏层输出是ReLU线性部分 ,而非ReLU的平方,因此更易理解的是分段线性逼近 构造:
隐藏层设2个神经元,分别定义不同折点,输出层线性加权:
- 神经元1:激活前 z1=x−0.5z_1 = x - 0.5z1=x−0.5,ReLU后为 max(0,x−0.5)\max(0, x-0.5)max(0,x−0.5)
- 神经元2:激活前 z2=−x−0.5z_2 = -x - 0.5z2=−x−0.5,ReLU后为 max(0,−x−0.5)\max(0, -x-0.5)max(0,−x−0.5)
输出层设权重 v1=1,v2=1,c=0.25v_1 = 1, v_2 = 1, c = 0.25v1=1,v2=1,c=0.25,则预测值为:
ypred=max(0,x−0.5)+max(0,−x−0.5)+0.25y_{\text{pred}} = \max(0, x-0.5) + \max(0, -x-0.5) + 0.25ypred=max(0,x−0.5)+max(0,−x−0.5)+0.25
代入数据验证(近似效果):
- x=0x=0x=0:0+0+0.25=0.250 + 0 + 0.25 = 0.250+0+0.25=0.25(接近真实值000)
- x=1x=1x=1:0.5+0+0.25=0.750.5 + 0 + 0.25 = 0.750.5+0+0.25=0.75(接近真实值111)
- x=2x=2x=2:1.5+0+0.25=1.751.5 + 0 + 0.25 = 1.751.5+0+0.25=1.75(偏差稍大,因仅2个神经元)
关键结论 :若增加隐藏层神经元数量,每个神经元提供一个独立折点,多段折线加权后,就能无限逼近光滑的x2x^2x2抛物线,这也是万能近似定理 的核心思想:只要隐藏层神经元足够多,带非线性激活函数的前馈神经网络,可逼近任意连续函数。
第四步:训练过程
实际场景中无需手工设定权重,神经网络通过梯度下降+反向传播自动学习,步骤如下:
- 随机初始化所有权重/偏置 w11,b1,w12,b2,v1,v2,cw_{11},b_1,w_{12},b_2,v_1,v_2,cw11,b1,w12,b2,v1,v2,c;
- 输入样本xxx,经前向传播得到预测值ypredy_{\text{pred}}ypred;
- 计算预测值与真实值的损失,常用均方误差 :
L=1n∑i=1n(ypred,i−xi2)2L = \frac{1}{n} \sum_{i=1}^n (y_{\text{pred},i} - x_i^2)^2L=n1i=1∑n(ypred,i−xi2)2 - 反向传播计算损失对所有参数的梯度,沿梯度负方向更新参数,降低损失LLL;
- 重复迭代上述步骤,直到损失收敛到极小值,网络即学会用ReLU组合逼近x2x^2x2。
4. 总结比喻
- 无激活函数的神经网络:像只能画直线的直尺,无论拼接多少把,最终还是直线,无法拟合曲线;
- 有激活函数的神经网络:像可弯折的软尺,激活函数的非线性让"尺身"能弯曲,适配复杂曲线形状;
- ReLU拟合x2x^2x2:每个ReLU神经元像一把"折尺"(自带一个折点),多把折尺按不同权重拼接,就能拼出近似抛物线的形状,神经元越多,逼近效果越精准。
核心结论 :激活函数的非线性,是神经网络能处理现实世界复杂非线性问题的根本关键。
我可以帮你把这份内容整理成可直接复制的笔记版(精简公式+核心结论,去掉冗余推导),需要吗?
三、归一化
1. 归一化是什么?
归一化 (Normalization)是一种数据预处理技术,它将数据按比例缩放,使其落入一个特定的小范围 (通常是 [0, 1] 或 [-1, 1]),或者使其符合标准正态分布(均值为0,标准差为1)。
最常见的两种方法是:
- 最小-最大归一化 :
X_new = (X - min) / (max - min),结果在 [0, 1]。 - Z-Score 标准化 :
X_new = (X - mean) / std,结果均值为0,标准差为1。
2. 为了解决什么问题?
归一化主要解决以下核心问题:
- 量纲不一:当不同特征(即输入变量)的单位和数量级相差巨大时(例如,"房间面积(平方米)"范围是 [50, 200],而"房间数量(个)"范围是 [1, 5]),模型会错误地认为数值大的特征更重要。
- 提升优化效率 :对于基于梯度下降的优化算法(如线性回归、神经网络),如果特征尺度差异大,损失函数的"等高线"会是狭长椭圆形,导致梯度下降路径曲折,收敛速度极慢。归一化后,"等高线"更接近圆形,梯度下降能快速找到最小值。
- 提高模型精度与稳定性:某些模型(如KNN、SVM、神经网络)的计算涉及距离度量(如欧氏距离)。如果不归一化,大尺度特征将完全主导距离计算,使模型效果变差。同时,归一化也能提升数值计算的稳定性。
3. 用一元一次方程拟合举例
让我们用一个具体的例子,看看归一化如何发挥作用。
场景设定
假设我们要拟合一个简单的一元一次方程模型:y = w * x + b
我们的数据如下:
x = [1000, 2000, 3000, 4000, 5000] (可以理解为"房屋面积,单位平方英尺")
y = [200, 300, 400, 500, 600] (可以理解为"房屋价格,单位千元")
目标 :找到最优的 w(权重)和 b(偏置)。
步骤 1:不归一化直接拟合
- 问题直观化 :
x的值在 1000~5000 之间,而y在 200~600 之间。x的数值和波动范围远大于y。 - 对梯度下降的影响 :
- 损失函数
L = (1/n) * Σ(w*x_i + b - y_i)^2。 - 计算
w的梯度:dL/dw = (2/n) * Σ( (w*x_i + b - y_i) * x_i ) - 注意,梯度公式里包含了
x_i。由于x_i巨大(~10^3),导致w的梯度值也会非常大。 b的梯度:dL/db = (2/n) * Σ( w*x_i + b - y_i ),不直接乘x_i,所以相对较小。
- 损失函数
- 导致后果 :
- 为了同时更新
w和b,我们需要设定一个学习率 。由于w的梯度太大,一个适合b的学习率对w来说就太大了,会导致w的更新步伐剧烈震荡,难以收敛。 - 如果为
w设定一个很小的学习率,b的更新又会慢如蜗牛。 - 整个优化过程会非常低效、不稳定,可能需要在学习率调参上花费大量精力。
- 为了同时更新
步骤 2:使用归一化后拟合(这里用最小-最大归一化)
-
对
x进行归一化:min(x) = 1000,max(x) = 5000x_norm = (x - 1000) / (5000 - 1000)- 计算后:
x_norm = [0, 0.25, 0.5, 0.75, 1.0]
-
用归一化后的数据
(x_norm, y)进行拟合:- 此时,特征
x_norm的范围是 [0, 1],目标y的范围是 [200, 600]。 w的梯度公式变为:dL/dw = (2/n) * Σ( (w*x_norm_i + b - y_i) * x_norm_i )- 由于
x_norm_i最大为1,w和b的梯度现在处于同一个数量级。
- 此时,特征
-
带来的好处:
- 我们可以为
w和b设置一个统一、合适的学习率。 - 损失函数的"地形"变得圆润,梯度下降可以沿着近乎最直接的路径快速滑向最小值点。
- 优化过程变得快速、稳定且容易收敛。
- 我们可以为
-
重要的一步:结果的转换
- 我们拟合得到的是基于归一化特征的模型:
y = w_norm * x_norm + b_norm - 要将它还原到原始尺度,需要代入
x_norm = (x - 1000) / 4000:
y = w_norm * [(x - 1000) / 4000] + b_norm
y = (w_norm / 4000) * x + (b_norm - w_norm*1000/4000) - 所以,原始模型参数为:
w_original = w_norm / 4000
b_original = b_norm - w_norm * 0.25
- 我们拟合得到的是基于归一化特征的模型:
对比总结
| 项目 | 不归一化 | 归一化后 |
|---|---|---|
| 特征尺度 | 1000~5000 | 0~1 |
| 梯度量级 | w和b的梯度相差巨大 |
w和b的梯度量级相当 |
| 优化难度 | 困难,需精心调整学习率 | 容易,可使用较大且统一的学习率 |
| 收敛速度 | 慢,路径曲折 | 快,路径直接 |
| 数值稳定性 | 差,易溢出或震荡 | 好 |
四、归一化时机
1. 传统ML vs 深度学习的数据结构差异
python
# 传统ML(表格数据):
样本1: [面积=2000, 房间数=3, 离地铁距离=5.2]
# 不同特征:面积(1000-5000) vs 房间数(1-5) vs 距离(0.1-20)
# 特征间尺度差异巨大 → 需要前归一化
# 深度学习(图像/序列):
图像像素: [ [125, 130], [120, 125] ] # 所有值都是0-255
文本嵌入: [ [0.1, 0.2], [0.3, 0.4] ] # 所有维度都在相似范围
# 特征间天然同尺度 → 不需要复杂的前归一化
2. 更准确的区分应该是:
| 需要复杂前归一化 | 只需要简单缩放 | |
|---|---|---|
| 数据特点 | 不同特征尺度差异大 | 特征同质化 |
| 典型场景 | 房价预测(面积、房间数...) | 图像分类(像素)、文本分类(词向量) |
| 具体操作 | Z-score/最小-最大归一化 | 像素值/255.0、词嵌入归一化 |
| 为什么 | 不同特征的数值范围差异大 | 所有"特征"本质是同质的 |
修正后的决策逻辑
判断是否需前归一化,应该问:
python
# 问题1:我的特征是"异质"的吗?
if 特征有不同含义和尺度: # 如面积 vs 房间数
需要前归一化 # 传统ML表格数据
else: # 所有特征本质相同
只需要简单缩放 # 图像像素、词向量等
# 问题2:我的模型对特征尺度敏感吗?
if 模型基于距离度量或梯度下降 and 特征异质:
必须前归一化
else if 模型是树模型:
不需要归一化
具体例子澄清
例1:房价预测(传统ML)
python
# 特征:面积、房间数、建造年份 → 异质特征
X = [[2000, 3, 2010], # 面积: 2000, 房间:3
[100, 5, 1950]] # 面积: 100, 房间:5
# 面积和房间数值差异巨大!需要归一化
例2:图像分类(CNN)
python
# 特征:所有都是像素值 → 同质特征
image = [[[125, 130, 120], # 所有值都是0-255
[120, 125, 118]],
[[110, 115, 105],
[108, 112, 100]]]
# 简单缩放即可:image / 255.0
例3:文本分类(词向量)
python
# 特征:所有都是词嵌入维度 → 同质特征
embedding = [[0.1, 0.2, 0.3, -0.1], # 所有维度都在[-1, 1]左右
[0.4, 0.1, -0.2, 0.0]]
# 词嵌入已经过训练,通常不需要额外归一化
为什么说"梯度下降需要归一化"不准确?
因为梯度下降的"敏感度"取决于:
-
参数共享程度:
python# 全连接层:每个特征有独立参数 # y = w1*x1 + w2*x2 + ... + b # 如果x1范围[0,1000],x2范围[0,1] # w1的梯度 ∝ x1,w2的梯度 ∝ x2 → 量级差异! # 卷积层:参数共享 # 所有位置用同样的卷积核 # 不同位置的像素差异不影响参数梯度 -
特征异质性:
python# 传统ML:w1对应"面积",w2对应"房间数" # 梯度:dw1 = Σ(误差 * 面积),dw2 = Σ(误差 * 房间数) # 面积值大 → dw1大,房间数值小 → dw2小 # CNN:所有w都对应"像素" # 不同位置的像素值差异不会造成系统性的梯度不平衡
修正后的总结
判断是否需要前归一化:
表格型
图像
文本
是
否
树模型
线性/SVM/KNN
神经网络
开始
数据是表格型还是图像/文本型?
特征尺度差异大吗?
只需要像素值/255.0
词嵌入通常已归一化
用什么模型?
不需要复杂归一化
不需要归一化
需要归一化
需要归一化
训练时用BatchNorm
Transformer用LayerNorm
- CNN等深度学习模型:
- 输入特征同质(像素/词向量)→ 简单缩放即可
- 使用BatchNorm解决内部优化问题,而不是输入尺度问题
- 传统ML模型:
- 输入特征异质(面积、房间数、年份)→ 需要复杂归一化
- 通常不使用BatchNorm(因为网络不深)
最终正确表述:
- 前归一化主要针对异质特征表格数据
- BatchNorm主要针对深度学习中的深度问题
- 两者都帮助优化,但解决不同维度的挑战
五、反向传播
反向传播(Backpropagation)
定义
反向传播是一种用于训练神经网络的梯度计算算法。它通过链式法则计算损失函数对每个参数的梯度,然后使用这些梯度更新网络参数。
解决的核心问题
- 梯度计算效率:对于深层网络,直接计算所有参数的梯度非常低效(需要重复计算很多子表达式)
- 参数优化:为梯度下降等优化算法提供必要的梯度信息
- 学习复杂模式:使深度神经网络能够学习输入和输出之间的复杂非线性关系
简单直观的例子
网络结构(极简版)
假设一个微型神经网络:
- 输入:x = 2
- 权重:w = 3, b = 1
- 激活函数:线性(为简化)
- 输出:y_pred = w*x + b
- 真实值:y_true = 10
- 损失函数:L = (y_pred - y_true)²
前向传播(计算输出)
y_pred = w*x + b = 3*2 + 1 = 7
L = (7 - 10)² = 9
反向传播(计算梯度)
步骤1:计算损失对输出的梯度
∂L/∂y_pred = 2*(y_pred - y_true) = 2*(7 - 10) = -6
步骤2:计算损失对权重的梯度(链式法则)
∂L/∂w = ∂L/∂y_pred * ∂y_pred/∂w = (-6) * x = (-6) * 2 = -12
∂L/∂b = ∂L/∂y_pred * ∂y_pred/∂b = (-6) * 1 = -6
步骤3:更新参数(梯度下降)
学习率 α = 0.1
w_new = w - α * ∂L/∂w = 3 - 0.1*(-12) = 4.2
b_new = b - α * ∂L/∂b = 1 - 0.1*(-6) = 1.6
验证更新效果
y_pred_new = 4.2*2 + 1.6 = 10.0
L_new = (10 - 10)² = 0 ← 完美预测!
更实际的例子(带激活函数)
网络结构
输入层 → 隐藏层(sigmoid激活) → 输出层
输入: x = [1.0]
权重: w1 = 0.5, w2 = 0.3
偏置: b1 = 0.1, b2 = -0.2
目标输出: y_true = 1.0
前向传播
z1 = w1*x + b1 = 0.5*1 + 0.1 = 0.6
a1 = sigmoid(0.6) = 1/(1+e^(-0.6)) ≈ 0.6457
z2 = w2*a1 + b2 = 0.3*0.6457 - 0.2 = -0.0063
a2 = sigmoid(-0.0063) ≈ 0.4984
损失 L = (0.4984 - 1)² ≈ 0.2516
反向传播(关键步骤)
∂L/∂a2 = 2*(a2 - y_true) ≈ -1.0032
∂a2/∂z2 = a2*(1-a2) ≈ 0.25
∂L/∂z2 = ∂L/∂a2 * ∂a2/∂z2 ≈ -0.2508
∂z2/∂w2 = a1 ≈ 0.6457
∂L/∂w2 = ∂L/∂z2 * ∂z2/∂w2 ≈ -0.1620
...继续反向传播到第一层...
核心价值总结
| 方面 | 说明 |
|---|---|
| 自动微分 | 无需手动推导梯度公式 |
| 计算效率 | 避免重复计算,复杂度 O(网络规模) |
| 模块化 | 每层只需实现前向/反向传播 |
| 支持深度学习 | 使训练深层网络成为可能 |
历史意义
反向传播(1986年由Rumelhart等人普及)是神经网络发展的关键突破:
- 解决了多层感知机的训练问题
- 开启了第一次神经网络研究热潮
- 是现代深度学习的基础
简单说:反向传播就是神经网络"从错误中学习"的数学实现------它告诉网络每个参数应该调整多少来减少预测误差。
六、梯度下降
梯度下降
梯度下降是什么?
梯度下降是一种优化算法,用于最小化损失函数。它的核心思想是:通过迭代的方式,沿着损失函数梯度的反方向(下降最快的方向)更新模型参数,逐步逼近函数的最小值点。
为了解决什么问题?
梯度下降主要解决以下问题:
- 优化问题:在机器学习中,我们通常需要找到一组模型参数,使损失函数(预测值与真实值之间的差距)最小化
- 高维空间搜索:当参数数量很多时(深度学习模型可能有数百万甚至数十亿参数),无法直接计算全局最优解,需要高效的迭代方法
- 可扩展性:需要能够处理大规模数据集的优化方法
现在深度学习的反向传播都用梯度下降吗?
基本上是的,但有不同变体:
- 反向传播(Backpropagation):是计算梯度的方法
- 梯度下降:是利用这些梯度更新参数的方法
现代深度学习使用的通常是梯度下降的变体:
- 随机梯度下降(SGD):每次使用单个样本计算梯度
- 小批量梯度下降(Mini-batch Gradient Descent):每次使用一小批样本计算梯度(最常用)
- 带动量的SGD:添加动量项加速收敛
- 自适应学习率方法:如Adam、Adagrad、RMSprop等(当前主流)
Adam是目前最广泛使用的优化器,它结合了动量方法和自适应学习率的优点。
简单例子:线性回归的梯度下降
假设我们要拟合线性模型:y = wx + b
python
import numpy as np
import matplotlib.pyplot as plt
# 生成模拟数据
np.random.seed(42)
X = np.array([1, 2, 3, 4, 5])
y = np.array([2, 4, 6, 8, 10]) # 完美线性关系:y = 2x
# 初始化参数
w = 0.0 # 权重
b = 0.0 # 偏置
learning_rate = 0.01 # 学习率
epochs = 100 # 迭代次数
# 存储历史值用于可视化
history_w = []
history_b = []
history_loss = []
# 梯度下降
for epoch in range(epochs):
# 前向传播:计算预测值
y_pred = w * X + b
# 计算损失(均方误差)
loss = np.mean((y_pred - y) ** 2)
# 计算梯度(反向传播)
dw = 2 * np.mean((y_pred - y) * X) # w的梯度
db = 2 * np.mean(y_pred - y) # b的梯度
# 更新参数(梯度下降步骤)
w = w - learning_rate * dw
b = b - learning_rate * db
# 记录历史
history_w.append(w)
history_b.append(b)
history_loss.append(loss)
# 打印进度
if epoch % 10 == 0:
print(f"Epoch {epoch}: w={w:.4f}, b={b:.4f}, loss={loss:.4f}")
print(f"\n最终结果: w={w:.4f}, b={b:.4f}")
print(f"真实关系: y = 2.0*x + 0.0")
# 可视化训练过程
fig, axes = plt.subplots(1, 3, figsize=(15, 4))
# 损失函数下降曲线
axes[0].plot(history_loss)
axes[0].set_xlabel('Epoch')
axes[0].set_ylabel('Loss')
axes[0].set_title('损失函数下降')
axes[0].grid(True)
# 参数w的变化
axes[1].plot(history_w)
axes[1].set_xlabel('Epoch')
axes[1].set_ylabel('w value')
axes[1].set_title('权重w的更新过程')
axes[1].axhline(y=2.0, color='r', linestyle='--', label='真实值 w=2.0')
axes[1].legend()
axes[1].grid(True)
# 最终拟合结果
axes[2].scatter(X, y, label='真实数据')
axes[2].plot(X, w*X + b, color='red', label=f'拟合直线: y={w:.2f}x+{b:.2f}')
axes[2].set_xlabel('X')
axes[2].set_ylabel('y')
axes[2].set_title('拟合结果')
axes[2].legend()
axes[2].grid(True)
plt.tight_layout()
plt.show()
关键概念总结
| 概念 | 说明 |
|---|---|
| 梯度 | 函数在某点的变化率最快的方向 |
| 学习率 | 控制参数更新步长的超参数 |
| 迭代 | 重复执行参数更新的过程 |
| 收敛 | 损失函数不再显著减少的状态 |
梯度下降的变体对比
| 方法 | 优点 | 缺点 |
|---|---|---|
| 批量梯度下降 | 稳定,收敛路径平滑 | 计算成本高,内存要求大 |
| 随机梯度下降 | 计算快,可在线学习 | 波动大,收敛不稳定 |
| 小批量梯度下降 | 平衡了稳定性和效率 | 需要调整批量大小 |
| Adam | 自适应学习率,收敛快 | 超参数可能敏感 |
在实际深度学习项目中,通常从Adam 优化器开始尝试,如果发现收敛问题,再考虑使用SGD(可能配合动量)。选择哪种方法取决于具体问题、数据规模和模型架构。