MNIST训练CNN时softmax输出概率均为0.1的问题求助
嘿,我来帮你拆解一下这个问题!你遇到的softmax输出固定为[0.1, 0.1,...,0.1]的情况,核心原因几乎可以确定是模型梯度无法有效更新,导致参数根本没在学习。咱们一步步来梳理问题点和解决办法:
主要问题分析
模型规模严重过载:你搭建的模型实在太庞大了——从128通道一路升到1024通道,还有4层连续的1024通道卷积,这对于MNIST这种简单的手写数字数据集来说完全是“杀鸡用牛刀”。这么深的网络很容易触发梯度消失:ReLU激活函数在深层网络中会让大量神经元输出为0,梯度无法反向传播到前面的层,参数自然不会更新,最后模型只能输出均匀概率。
数据未做归一化:MNIST的原始像素值范围是0-255,你直接把这种大数值喂给模型,会导致卷积和全连接层的输入波动极大,很容易让ReLU进入饱和区(输出为0),进一步加剧梯度消失的问题。
缺少正则化与归一化层:深层网络没有加入Dropout或Batch Normalization,不仅容易过拟合,还会让中间层的激活值分布失衡,影响梯度传递效率。
全连接层维度冗余:虽然你计算的
9216维度是正确的(3×3×1024),但这么大的全连接层在MNIST上完全没必要,只会增加参数数量,加重梯度更新的负担。
具体修改建议
1. 先做数据归一化
在加载数据后立刻加入归一化步骤,把像素值缩放到0-1区间:
data = np.asarray(mnist["data"],dtype=np.float32) / 255.0 # 关键:归一化到0-1
2. 大幅简化模型
把模型缩小到适合MNIST的规模,比如:
# 简化后的模型结构 conv1_1 = get_conv(x,[3,3,1,32]) # 减少通道数到32 conv1_2 = get_conv(conv1_1,[3,3,32,32]) pool1 = get_pool(conv1_2,[1,2,2,1]) conv2_1 = get_conv(pool1,[3,3,32,64]) conv2_2 = get_conv(conv2_1,[3,3,64,64]) pool2 = get_pool(conv2_2,[1,2,2,1]) # 加入Dropout防止过拟合 dropout = tf.nn.dropout(pool2, keep_prob=0.5) # 计算正确的全连接层输入维度:28→14→7,7×7×64=3136 fc1 = get_fc(dropout,[3136,256]) fc1_drop = tf.nn.dropout(fc1, keep_prob=0.5) fc2 = get_fc(fc1_drop,[256,10])
3. 训练过程中监控Loss
在训练循环里加入Loss打印,确认模型是否在学习:
for i in range(15): print(f"Step {i}") indices = np.random.randint(len(tr_data),size=[200]) batch_data = tr_data[indices] batch_labels = tr_labels[indices] _, loss_val = sess.run([train_step, loss], feed_dict={x:batch_data,y:batch_labels}) print(f"Loss: {loss_val:.4f}") # 观察Loss是否下降
额外提示
15步训练确实很少,但如果模型正常的话,Loss应该会有明显下降,softmax输出也会开始出现差异。如果修改后Loss还是不动,那可以检查一下get_fc函数里的偏置初始化是否正确,或者尝试调小Adam的学习率(比如0.0001)。
内容的提问来源于stack exchange,提问作者Pian Pawakapan

