🧪 MNIST先导课程实验报告

课程名称 课程1 单值线性回归(无权重,直接更新预测值) 日期
学生姓名 班级/学号

🎯一、实验目的

  1. 固定初始值, 使用不同的学习率, 观察收敛速度
  2. 固定学习率, 使用不同的初始值, 观察收敛速度
  3. 绘制损失曲线和梯度曲线, 分析两者关系

🔧 二、实验参数设置

参数名 符号 说明
输入线索 clue 8
目标值 target 10
学习率 η 0.1
  • 实验1:固定目标值(如 target=5),改变初始预测值(如 pred=8, pred=12, pred=-3),观察损失下降曲线,分析收敛速度。
  • 实验2:固定初始预测值(如 pred=8),改变学习率(如 η=0.01, 0.1, 0.5),观察损失曲线的震荡或发散现象。
  • 实验3:如果初始值和目标值非常接近(如 pred=5.01, target=5),学习率 η=0.1,观察损失曲线和梯度的情况。
  • 实验4:使用 pydraw 同时绘制损失和预测梯度 grad_pred 的变化曲线,分析两者关系。
  • 手算练习:对前4轮进行手工前向计算,填写表格。

四、代码运行结果

📊 4.1 训练过程中的损失变化曲线和梯度变化曲线

图片

点击放大显示 损失变化曲线

📝 4.2 训练过程生成的数据表格 (前3行+后3行), Early stop 机制

4.2.1 输入线索 clue = 8 , 目标值 target = 10 , 学习率 η = 0.1 , 停止阈值 Threshold = 0.0001

轮次 模型输出 (预测值) 损失 预测梯度
0 8 4 4
1 8.4 2.56 3.2
2 8.72 1.6384 2.56
30 / / /
31 / / /
32 / / /

4.2.2 输入线索 clue = 8 , 目标值 target = 10 , 学习率 η = 0.1 , 停止阈值 Threshold = 0.00001

轮次 模型输出 (预测值) 损失 预测梯度
0 8 4 4
1 8.4 2.56 3.2
2 8.72 1.6384 2.56
30 / / /
31 / / /
32 / / /

4.2.3 输入线索 clue = 120 , 目标值 target = 10 , 学习率 η = 0.1 , 停止阈值 Threshold = 0.00001

轮次 模型输出 (预测值) 损失 预测梯度
0 120 12100 220
1 98 7744 176
2 80 4956 140.8
30 10.1362 0.0185 0.2723
31 10.1089 0.0119 0.2179
32 10.0872 0.0076 0.1743

4.2.4 输入线索 clue = 120 , 目标值 target = 10 , 学习率 η = 0.01 , 停止阈值 Threshold = 0.0001

轮次 模型输出 (预测值) 损失 预测梯度
0 120 12100 220
1 117.8 11620.84 215.6
2 115.644 11160.6547 211.288
30 70.0033 3600.3930 120.0066
31 68.8032 3457.8175 117.6064
32 67.6271 3320.8879 115.2543

4.2.5 输入线索 clue = 120, 目标值 target = 10, 学习率 η = 0.9, 停止阈值 Threshold = 0.0001

轮次 模型输出 (预测值) 损失 预测梯度
0 120 12100 220
1 -78 7744 -176
2 80 4956 140
30 10.1362 0.0185 0.2723
31 9.8911 0.0119 0.2179
32 10.0872 0.0076 0.1743

4.3 最终参数与最终损失

clue target η 轮次 最终输出 最终损失 备注
5 8 0.1 30 0.0001
5 18 0.1 60 0.0001
5 80 0.1 70 0.0001
5 8000 0.1 130 0.0001
5.0.1 5 0.1 270 0.0001

🎉 五、观察与分析

  1. 学习率的影响:当学习率过大/过小时,观察到了什么现象? 当学习率过大时,梯度会发生震荡和不降反增现象;当学习率过小时,损失下降缓慢,最终停止学习
  2. 神经元死亡现象:是否观察到梯度为0、参数不再更新的情况?如何判断?
    是的。当学习率过小时,会发生神经元死亡现象,即参数不再更新

✨ 六、实验结论

(总结本次实验的核心发现,例如:学习率需要适中才能稳定收敛;Leaky ReLU 可以有效避免神经元死亡等)

七、附录:实验代码

(可附上本次实验的核心代码片段,或说明代码存放位置)

from pydraw import pydraw
from datetime import datetime
def trainmodule1(target:int,clue:int,rate:float):
    draw = pydraw()
    pred=clue
    for epoch in range(20):
        
        loss = (pred-target)*(pred-target)
        
        grad = 2*(pred-target)

        print(f"epoch={epoch},pred={pred:.4f},loss={loss:.4f}")
        draw.add(loss,"loss")
        draw.add(grad,"grad")

        pred = pred-(rate*grad)
    draw.draw()

def trainmodule2(target:int,clue:int,rate:float,stop:float):
    draw = pydraw()
    draw.xlabel = "Epoch"
    draw.ylabel = "Value"
    draw.title = "课程1:简单的梯度下降"
    timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    desc = f"clue={clue}, t={target}, lr={rate}"
    pred=clue
    found = None

    for epoch in range(50):
        loss = (pred-target)*(pred-target)
        if found is None and loss < 0.0001:
            draw.annotate ("Loss<0.0001", xy=(epoch, loss))
            found = epoch
        grad = 2*(pred-target)

        print(f"epoch={epoch},pred={pred:.4f},loss={loss:.4f},grad={grad:.4f}")
        draw.add(loss,"loss")
        draw.add(grad,"grad")

        pred = pred-(rate*grad)
    # 添加底部描述
    draw.description = desc + f", Loss<0.0001 on epoch={found}, final loss={loss:.8f}" + ", " + timestamp
    draw.export("trainingcurves-1.png")
    draw.draw()
trainmodule2(10,8,0.1,0.0001)