TensorFlow四层字母识别神经网络精度异常及loss为nan问题求助
问题排查与修复方案
嘿,我帮你揪出了几个核心问题,这就是你的四层神经网络精度只有10%还时不时出现NaN的根源:
1. 网络结构“缩水”+ 验证/测试路径完全错误
你明明定义了hidden_neurons = [inputs, 1024, 512, 256,]打算做四层网络,但实际代码里只实现了两层隐藏层+输出层,完全没用到256神经元的那一层。更要命的是,验证和测试的预测逻辑直接跑偏了:
- 训练时的路径是:输入→relu1→relu2→logits→softmax
- 但验证/测试时居然是:输入→relu1→softmax(跳过了relu2之后的所有计算,直接对中间层结果做分类)
这就相当于你训练了一个模型,测试时却用了另一个完全不同的网络,精度能上去才怪!
2. Loss出现NaN的三大元凶
(1)初始学习率高到离谱
你给GradientDescentOptimizer设了0.3的初始学习率,这值太大了,梯度更新时权重会突变,直接导致softmax交叉熵计算时出现数值溢出(比如logits变得无穷大),最后loss就成了NaN。
(2)权重初始化太“激进”
tf.truncated_normal默认标准差是1.0,对于大尺寸的权重矩阵(比如输入层到1024的矩阵),这种初始化会让神经元的激活值爆炸,经过relu后要么大量神经元饱和,要么引发梯度爆炸,最终搞出NaN。
(3)正则化计算画蛇添足
你已经对交叉熵loss做了tf.reduce_mean,结果加上正则化项后又做了一次tf.reduce_mean,这不仅让正则化项被不必要地缩小,还可能放大数值计算的不稳定性。
3. 修复后的完整代码
我帮你把所有问题都修正了,你可以直接用:
batch_size = 128 beta = 0.01 inputs = image_size*image_size hidden_neurons = [inputs, 1024, 512, 256,] graph = tf.Graph() with graph.as_default(): global_step = tf.Variable(0) # 输入数据定义保持不变 tf_train_dataset = tf.placeholder(tf.float32, shape=(batch_size, image_size * image_size)) tf_train_labels = tf.placeholder(tf.float32, shape=(batch_size, num_labels)) tf_valid_dataset = tf.constant(valid_dataset) tf_test_dataset = tf.constant(test_dataset) # 改用普通变量定义神经元数量,避免不必要的张量计算 hidden_1_size = 1024 hidden_2_size = 512 hidden_3_size = 256 # 补上你原本计划的第三层隐藏层 # 修正权重初始化:用小标准差0.01,避免激活值过大 weights_1 = tf.Variable(tf.truncated_normal([image_size * image_size, hidden_1_size], stddev=0.01)) biases_1 = tf.Variable(tf.zeros([hidden_1_size])) weights_2 = tf.Variable(tf.truncated_normal([hidden_1_size, hidden_2_size], stddev=0.01)) biases_2 = tf.Variable(tf.zeros([hidden_2_size])) # 新增第三层隐藏层的权重和偏置 weights_3 = tf.Variable(tf.truncated_normal([hidden_2_size, hidden_3_size], stddev=0.01)) biases_3 = tf.Variable(tf.zeros([hidden_3_size])) # 输出层权重:从第三层隐藏层映射到分类标签数 weights_out = tf.Variable(tf.truncated_normal([hidden_3_size, num_labels], stddev=0.01)) biases_out = tf.Variable(tf.zeros([num_labels])) # 完整的四层网络训练路径 relu_1 = tf.nn.relu(tf.matmul(tf_train_dataset, weights_1) + biases_1) relu_2 = tf.nn.relu(tf.matmul(relu_1, weights_2) + biases_2) relu_3 = tf.nn.relu(tf.matmul(relu_2, weights_3) + biases_3) # 补上第三层relu激活 logits = tf.matmul(relu_3, weights_out) + biases_out # 修正loss计算:只做一次均值计算,正则化项直接相加 cross_entropy = tf.nn.softmax_cross_entropy_with_logits(labels=tf_train_labels, logits=logits) loss = tf.reduce_mean(cross_entropy) + beta * ( tf.nn.l2_loss(weights_1) + tf.nn.l2_loss(weights_2) + tf.nn.l2_loss(weights_3) + tf.nn.l2_loss(weights_out) ) # 修正学习率:初始值降到0.05,避免梯度爆炸 learning_rate = tf.train.exponential_decay(0.05, global_step, 100000, 0.7, staircase=True) optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss, global_step=global_step) # 统一预测逻辑:训练/验证/测试走完全相同的网络路径 def predict(dataset): relu_1 = tf.nn.relu(tf.matmul(dataset, weights_1) + biases_1) relu_2 = tf.nn.relu(tf.matmul(relu_1, weights_2) + biases_2) relu_3 = tf.nn.relu(tf.matmul(relu_2, weights_3) + biases_3) logits = tf.matmul(relu_3, weights_out) + biases_out return tf.nn.softmax(logits) train_prediction = predict(tf_train_dataset) valid_prediction = predict(tf_valid_dataset) test_prediction = predict(tf_test_dataset)
4. 额外小 tips
- 可以给隐藏层加上Dropout(
tf.nn.dropout),防止四层网络过拟合,比如在每个relu之后加tf.nn.dropout(relu_x, keep_prob=0.5)(注意训练时用0.5,验证/测试时用1.0)。 - 如果还是出现NaN,试试把初始学习率再调低一点,或者改用AdamOptimizer(自适应学习率,对参数没那么敏感)。
- 记得对输入图像做归一化(比如像素值除以255,缩到0-1区间),能让训练稳定很多。
内容的提问来源于stack exchange,提问作者Untimely Answers
相关产品推荐
相关产品推荐

