🧪 MNIST先导课程实验报告
| 课程名称 | 课程4:梯度爆炸,梯度消失,优化器 | 日期 | |
|---|---|---|---|
| 学生姓名 | 班级/学号 |
🎯一、实验目的
- 使用课程2中的参数, 比对各种优化器的收敛速度
- 发生梯度爆炸时,各种优化器是否能收敛?
- 发生梯度震荡时,各种优化器是否能收敛?
- 发生梯度消失时,各种优化器是否能收敛?
🔧 二、实验参数设置
| 参数名 | 符号 | 说明 |
|---|---|---|
| 输入线索 | clue | |
| 目标值 | target | |
| 学习率 | η | |
| 初始权重 | w | |
| 初始偏置 | b | |
| 优化器类型 | optimizer |
- 实验1:使用 课程 2 中的数据 (称为基线数据): clue=2.0, target=5.0,η=0.1,W=1.2, B=0.8, 观察不同优化器对收敛的影响
- 实验2:固定 clue=2.0, target=5.0,η=0.1,调整 W 和 B, 观察不同优化器对收敛的影响. 特别地, 设置1-3组 W 和 B为极端值
- 实验3:固定 clue=2.0, target=5.0,η=0.1,设置1-3组 W 和 B为极端值,观察不同优化器对收敛的影响
- 实验4:固定初始参数(如 w=0.5, b=-0.5),改变学习率(η=0.01, 0.1, 0.2),观察不同优化器对收敛的影响
- 实验5:将输入 clue 调整至 比 target 稍大, 引发 SGD 情况下的梯度爆炸, 切换到其他优化器, 观察是否能消除梯度爆炸
- 实验6:将输入 clue 调整至 比 target 超出很多 (例如50,100,500), 引发 SGD 情况下的梯度爆炸, 切换到其他优化器, 观察是否能消除梯度爆炸
- 实验7:clue 过小 (如 0.0001),引发梯度消失, 观察各种优化器的收敛速度。
四、代码运行结果
⚠️注意:
- 不要用 Early stop 机制, 要反复尝试, 某些情况下, 你能发现损失函数在越过停止点后, 仍能反弹.
- 如果发生上述情况, 请记录到 <五、观察与分析> 部分
- 如果损失函数和梯度未反弹,请把停止轮次设在停止点附近, 以便让曲线更漂亮.
例如, 如果在曲线中, 发现: 轮次为 30 时, Loss<0.0001, 那么把总轮次设置为 35 或 40 - 最大轮次可以设为 500, 如果总轮次超过最大值后, 损失函数仍未降低到 0.0001, 停止迭代, 也记录到 <五、观察与分析> 部分
- 表格按如下方式填写
-
如果不收敛, 第二列填 ❌
-
如果正常收敛, 第二列填 ✅
-
如果快速收敛, 第二列填 ⚡
-
如果收敛但是有反弹, 第二列填 ℹ️
-
如果趋向收敛但是收敛太慢, 第二列填 🐛
-
如果收敛, 第三列写上停止点的轮次, 否则写 Nan
-
第四列填写观察到的现象
优化器 是否收敛 停止点轮次 说明 SGD ❌ Nan Momentum ✅ 20 收敛 Adagrad ℹ️ 30 收敛但有反弹 RMSprop ✅ 40 Adam 🐛 趋向收敛, 但收敛太慢 自定义优化器 1 🐛 趋向收敛, 但收敛太慢 自定义优化器 2 🐛 趋向收敛, 但收敛太慢
-

点击放大显示 梯度震荡

点击放大显示 梯度消失

点击放大显示 损失回弹

点击放大显示 正常收敛
📊 4.1 基线数据
参数:线索clue=\(3\),目标T=\(2\),学习率 \(\eta\)=\(0.01\), 初始值:权重W=\(1.2\), 偏置b=\(0.8\)
各个优化器的损失变化曲线和梯度变化曲线
填写如下对比表格.
| 优化器 | 是否收敛 | 停止点轮次 | 说明 |
|---|---|---|---|
| SGD | ✅ | 29 | |
| Momentum | ✅ | 22 | 损失在22轮后有小幅回升 |
| Adagrad | ✅ | 40 | 收敛较慢 |
| RMSprop | ⚡ | 4 | 下降过快 |
| Adam | ✅ | 7 | 梯度反复震荡 |
📊 4.2 不同的 W 和 B
参数:线索clue=\(3\),目标T=\(2\),学习率 \(\eta\)=\(0.01\), 初始值:权重W=\(12\), 偏置b=\(-8\)
各个优化器的损失变化曲线和梯度变化曲线
填写如下对比表格.
| 优化器 | 是否收敛 | 停止点轮次 | 说明 |
|---|---|---|---|
| SGD | 🐛 | 69 | 收敛过慢 |
| Momentum | ✅ | 59 | 损失有多次回弹 |
| Adagrad | ❌ | Nan | 收敛极慢,停止学习 |
| RMSprop | 🐛🐛 | 200+ | 收敛过慢 |
| Adam | ❌ | 400+ | 收敛超级慢 |
📊 4.3 W 和 B 为极端值
参数:线索clue=\(3\),目标T=\(2\),学习率 \(\eta\)=\(0.01\), 初始值:权重W=\(-120\), 偏置b=\(-800\)
各个优化器的损失变化曲线和梯度变化曲线
填写如下对比表格.
| 优化器 | 是否收敛 | 停止点轮次 | 说明 |
|---|---|---|---|
| SGD | ✅ | 110 | |
| Momentum | ℹ️ | 166 | 收敛但有反弹 |
| Adagrad | ❌ | Nan | 梯度消失 |
| RMSprop | ❌ | Nan | 收敛缓慢 |
| Adam | ❌ | Nan | 收敛缓慢 |
📊 4.4 不同的学习率对比
参数:线索clue=\(3\),目标T=\(2\),学习率 \(\eta\)=\(0.1\), 初始值:权重W=\(1.2\), 偏置b=\(0.8\)
各个优化器的损失变化曲线和梯度变化曲线
填写如下对比表格.
| 优化器 | 是否收敛 | 停止点轮次 | 说明 |
|---|---|---|---|
| SGD | ⚡ | 1 | |
| Momentum | ℹ️ | 5 | 收敛但有反弹 |
| Adagrad | ⚡ | 4 | |
| RMSprop | ⚡ | 3 | |
| Adam | ℹ️ | 4 | 收敛但有反弹 |
📊 4.5 Clue 比 target 略大
参数:线索clue=\(10\),目标T=\(8\),学习率 \(\eta\)=\(0.01\), 初始值:权重W=\(1.2\), 偏置b=\(0.8\)
各个优化器的损失变化曲线和梯度变化曲线
填写如下对比表格.
| 优化器 | 是否收敛 | 停止点轮次 | 说明 |
|---|---|---|---|
| SGD | ❌ | Nan | 梯度震荡 |
| Momentum | ℹ️ | 71 | 收敛但有反弹 |
| Adagrad | ❌ | Nan | 收敛缓慢 |
| RMSprop | ✅ | 6 | |
| Adam | ✅ | 69 |
📊 4.6 Clue 超大
参数:线索clue=\(100\),目标T=\(10\),学习率 \(\eta\)=\(0.01\), 初始值:权重W=\(1.2\), 偏置b=\(0.8\)
各个优化器的损失变化曲线和梯度变化曲线
填写如下对比表格.
| 优化器 | 是否收敛 | 停止点轮次 | 说明 |
|---|---|---|---|
| SGD | ❌ | Nan | 梯度爆炸 |
| Momentum | ❌ | Nan | 梯度爆炸(但是比SGD好一点) |
| Adagrad | ❌ | Nan | 收敛过慢 |
| RMSprop | ✅ | 43 | |
| Adam | ❌ | Nan | 收敛过慢(但是比Adagrad好一点) |
📊 4.7 Clue 过小, 正常学习率 0.1
参数:线索clue=\(0.01\),目标T=\(2\),学习率 \(\eta\)=\(0.01\), 初始值:权重W=\(1.2\), 偏置b=\(0.8\)
各个优化器的损失变化曲线和梯度变化曲线
填写如下对比表格.
| 优化器 | 是否收敛 | 停止点轮次 | 说明 |
|---|---|---|---|
| SGD | 🐛 | 237 | |
| Momentum | 🐛 | 194 | |
| Adagrad | ❌ | Nan | 收敛过慢 |
| RMSprop | ✅ | 25 | |
| Adam | 🐛 | 264 |
📊 4.8 Clue 过小 (例如 0.001), 超小学习率 0.0001
参数:线索clue=\(0.01\),目标T=\(2\),学习率 \(\eta\)=\(0.0001\), 初始值:权重W=\(1.2\), 偏置b=\(0.8\)
各个优化器的损失变化曲线和梯度变化曲线
填写如下对比表格.
| 优化器 | 是否收敛 | 停止点轮次 | 说明 |
|---|---|---|---|
| SGD | ❌ | Nan | 收敛过慢 |
| Momentum | ❌ | Nan | 收敛过慢 |
| Adagrad | ❌ | Nan | 梯度消失 |
| RMSprop | ❌ | Nan | 收敛过慢 |
| Adam | ❌ | Nan | 收敛过慢 |
🎉 五、观察与分析
- 基线数据下, 观察到什么现象? 评估一下各个优化器?RMSprop 较优
- 不同 W 和 B 时, 观察到什么现象? 评估一下各个优化器?Momentum 较优
- 极端的 W 和 B , 观察到什么现象? 评估一下各个优化器?SGD 较优
- 不同的学习率, 观察到什么现象? 评估一下各个优化器?RMSprop 较优
特别是, 如果学习率过小, 哪个优化器能较快收敛? - Clue 比 target 略大时, 观察到什么现象? 评估一下各个优化器?RMSprop 较优
- Clue 为极端值, 观察到什么现象? 评估一下各个优化器?RMSprop 较优
- Clue 过小, 观察到什么现象? 评估一下各个优化器?RSMprop 较优
- 学习率过小,什么优化器都没用
✨ 六、实验结论
优化器可以更快的收敛,但是要根据实际情况选择合适的优化器。
💫 七、思考题
大多数情况下选择Adam优化器
八、附录:实验代码
(可附上本次实验的核心代码片段,或说明代码存放位置)
from datetime import datetime
from pydraw import pydraw
import optimizer
def training_model_4 (nbof_epoch:int, clue:float, target:float, lr:float, w:float, b:float):
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
desc = f"clue={clue}, t={target}, lr={lr}, w={w}, b={b}"
title = ""
title += "| 轮次 "
title += r"| $\boxed{S5}$ 权重W= "
title += r"| $\boxed{S6}$ 偏置B= "
title += r"| $\boxed{S0}$ 预测值pred= "
title += r"| $\boxed{S1}$ 损失Loss= "
title += r"| $\boxed{S2}$ 输出的梯度 $G_{pred}$= "
title += r"| $\boxed{S3}$ 权重的梯度 $G_w$= "
title += r"| $\boxed{S4}$ 偏置的梯度 $G_b$= "
print (title)
#print (f"|{'轮次':^5} | {'权重W=':^8} | {'偏置B':^8} | {'预测值':^7} | {'损失':^10} | {'输出梯度G':^8} | {'梯度w':^10} | {'梯度b':^10} |")
print (f"|{'-'*8}|{'-'*12}|{'-'*12}|{'-'*12}|{'-'*14}|{'-'*14}|{'-'*14}|{'-'*14}|")
hintstr = r"| |$W-\eta \times G_w$|$B-\eta \times G_b$|$W\times clue+B$|$(pred-T)^2$|$2 \times (pred-T)$ |$G_{pred} \times clue$ |$G_{pred}$ |"
print (hintstr)
# opt = optimizer.SGD (lr=lr)
# opt = optimizer.Momentum (lr=lr, beta=0.9)
# opt = optimizer.Adagrad (lr=lr)
# opt = optimizer.RMSprop (lr=lr)
opt = optimizer.Adam (lr=lr)
draw = pydraw ()
draw.xlabel = "Epoch"
draw.ylabel = "Value"
draw.title = "课程 2 (y = W * X + B), 优化器 - " + opt.name
#draw.title = "课程 2 (y = W * X + B) - 正常梯度下降"
#draw.title = "课程 2 (y = W * X + B) - 梯度消失"
# 设置图例显示名称(可选)
draw.set_label("loss", "Loss")
draw.set_label("grad_pred", "Gradient of pred")
draw.set_label("grad_w", "Gradient of w")
found = None
for epoch in range (nbof_epoch):
# 预测
pred = w * clue + b
# 损失和梯度
loss = (pred - target) ** 2
grad_pred = 2 * (pred - target)
grad_w = grad_pred * clue
grad_b = grad_pred
# 显示
#if epoch % 2 == 0 or epoch < 5:
print (f"| {epoch:^6} | {w:^10.4f} | {b:^10.4f} | {pred:^10.4f} "
f"| {loss:^12.4f} | {grad_pred:^12.4f} | {grad_w:^12.4f} | {grad_b:^12.4f} |")
draw.add (loss, name="loss")
draw.add (grad_pred, name="grad_pred")
draw.add (grad_w, name="grad_w")
# 在特定点添加注释
if found is None and loss < 0.0001:
draw.annotate ("Loss<0.0001", xy=(epoch, loss))
found = epoch
# 更新
#w -= lr * grad_w
#b -= lr * grad_b
# 更新
step_w, step_b = opt.compute_step (grad_w, grad_b)
w -= step_w
b -= step_b
# 添加底部描述
draw.description = desc + f", Loss<0.0001 on epoch={found}, final loss={loss:.8f}" + ", " + timestamp
# draw.export ("doc/media-class4/training_curves_cluebig_SGD.png")
draw.draw ()
clue = 0.01 # 线索, 即预测的初始值
#clue = 0.1 # 线索, 即预测的初始值
target = 2 # 我心中的目标值
#learn_rate = 0.027 # 学习率, 神奇的震荡, 固定值
#learn_rate = 0.028 # 学习率, 神奇的震荡, 渐增
#learn_rate = 0.029 # 学习率, 神奇的震荡, 快增
learn_rate = 0.001 # 学习率
w = 1.2 # 权重
#w = -1.3 # 权重
b = 0.8 # 偏置
print (f"权重和偏置的训练表格(线索clue={clue},目标T={target},学习率={learn_rate}, 权重W={w}, 偏置B={b})")
print ("")
training_model_2 (500, clue, target, learn_rate, w, b)
浙公网安备 33010602011771号