CS231n实战解析:从零构建全连接网络与优化器调优

张开发
2026/4/17 6:46:23 15 分钟阅读

分享文章

CS231n实战解析:从零构建全连接网络与优化器调优
1. 全连接网络基础与CS231n作业解析第一次接触全连接网络时我被它的全连接特性震撼到了——每个神经元都与前一层的所有神经元相连就像一张密不透风的网。在CS231n作业中构建FullyConnectedNet时这种密集连接既带来了强大的表达能力也埋下了梯度问题的隐患。全连接层的数学本质是矩阵乘法。假设输入是3072维的CIFAR-10图像32x32x3第一个隐藏层有100个神经元那么这个全连接层就需要3072x100307,200个权重参数我在实现时经常犯的一个错误是搞反矩阵维度顺序导致维度不匹配。正确的初始化应该是W1 np.random.normal(0, weight_scale, (input_dim, hidden_dims[0])) b1 np.zeros(hidden_dims[0])CS231n作业中一个精妙的设计是affine_relu_forward和affine_relu_backward的组合。前向传播时affine变换后立即接ReLU激活out, cache affine_forward(x, w, b) out, relu_cache relu_forward(out)反向传播时则需要严格逆序dx relu_backward(dout, relu_cache) dx, dw, db affine_backward(dx, fc_cache)2. 梯度问题实战消失与爆炸的较量在调试五层网络时我遇到了典型的梯度消失问题。当设置weight_scale1e-5时训练准确率卡在16%不动就像汽车陷在泥潭里。通过打印各层梯度范数发现从输出层往回梯度以约0.1的比率衰减Layer5 grad norm: 3.21e-3 Layer4 grad norm: 2.87e-4 Layer3 grad norm: 1.15e-5 Layer2 grad norm: 4.62e-7对比之下当weight_scale1e-2时又出现了梯度爆炸梯度值超过1e30导致NaN。这就像调节音响音量 - 太小听不清太大会爆音。经过多次实验我总结出不同网络深度的黄金初始化区间网络层数推荐weight_scale范围适用激活函数3层[1e-2, 5e-2]ReLU5层[1e-3, 5e-3]ReLU7层[1e-4, 1e-3]ReLU3. 优化器实现细节与性能对比实现SGDMomentum时velocity的初始化容易被忽略。我最初忘记在config中维护velocity状态导致每次更新都从零开始动量效果大打折扣。正确的做法应该是v config.get(velocity, np.zeros_like(w)) # 保留历史速度 v mu * v - learning_rate * dw next_w w v config[velocity] v # 更新状态在CIFAR-10上对比四种优化器时我发现一个有趣现象当使用较大batch_size(1024)时Adam的优势更明显。这是因为大批量训练的梯度估计更准确配合自适应学习率能稳定收敛。实测结果对比如下优化器最高验证准确率收敛所需epochSGD45.2%50SGDMomentum48.7%35RMSProp51.3%25Adam52.6%20Adam的优越性来自其双缓存设计既像Momentum那样跟踪梯度一阶矩均值又像RMSProp那样跟踪二阶矩方差。这就像赛车同时具备强劲引擎一阶动量和智能悬挂二阶自适应在各种地形都能平稳高速行驶。4. 调参实战从网格搜索到模型部署在最终模型调参时我开发了一套分层调参策略初始化阶段用50个样本的小数据集固定learning_rate1e-3扫描weight_scalefor weight_scale in np.logspace(-5, -2, 20): model FullyConnectedNet([100]*5, weight_scaleweight_scale) solver.train()架构验证用完整训练集的10%约5000样本测试不同隐藏层配置architectures [ [100]*3, [200,100,50], [256,128,64,32] ]最终微调全数据集上优化learning_rate和regularization_strengthfor lr in [1e-4, 3e-4, 1e-3]: for reg in [0.01, 0.1, 1.0]: solver Solver(model, data, optim_config{learning_rate: lr}, regreg)部署模型时我养成了保存训练曲线的习惯。用Matplotlib同时绘制loss和accuracy曲线能直观判断是否过拟合plt.subplot(2,1,1) plt.plot(solver.loss_history) plt.subplot(2,1,2) plt.plot(solver.train_acc_history, labeltrain) plt.plot(solver.val_acc_history, labelval)最终我的五层网络在CIFAR-10上达到52.6%的测试准确率。虽然不如卷积神经网络但这个过程让我深刻理解了深度学习的底层机制。记得在调试最困难的时候我几乎要放弃直到某次调整weight_scale后看到验证曲线突然上升——那一刻的喜悦至今难忘。

更多文章