TensorFlow手动实现MLP与Layers API实现效果不一致问题排查
解决:手动实现MLP与TensorFlow Layers API准确率差异的问题
你遇到的问题核心在于权重初始化方式!你的初始手动实现把所有权重都设为0,这会让神经网络彻底丧失学习能力,而TensorFlow Layers API默认使用了合理的权重初始化策略,这就是两者效果天差地别的原因。
为什么初始手动实现失效?
在你的初始代码里,所有权重矩阵都是用tf.Variable(tf.zeros([...]))初始化为全0:
def manual_create_mlp_net(input_images=input_images, reuse=False): with tf.variable_scope('mlp', reuse = reuse): W1 = tf.Variable(tf.zeros([784,512])) # 全0初始化 b1 = tf.Variable(tf.zeros([512])) l1 = tf.nn.relu(tf.matmul(input_images,W1) + b1) W2 = tf.Variable(tf.zeros([512,512])) # 全0初始化 b2 = tf.Variable(tf.zeros([512])) l2 = tf.nn.relu(tf.matmul(l1,W2) + b2) W3 = tf.Variable(tf.zeros([512,10])) # 全0初始化 b3 = tf.Variable(tf.zeros([10])) y = tf.nn.softmax(tf.matmul(l2,W3) + b3) return y
全0初始化会导致每一层的所有神经元输出完全相同,反向传播时所有权重的梯度更新也完全一致——相当于整个网络的每个隐藏层都只有“一个神经元”的表达能力,根本无法学习到数据中的特征,最终模型只能随机预测,对应10分类任务的约11%准确率。
贴近Layers API的正确手动实现
TensorFlow的tf.layers.dense默认使用glorot_uniform_initializer(Xavier均匀初始化)来初始化权重,我们可以用tf.get_variable()来复用这种默认初始化逻辑(不指定初始化器时,tf.get_variable()会使用该默认策略)。修正后的代码如下:
def manual_create_mlp_net(input_images=input_images, reuse=False): with tf.variable_scope('mlp', reuse = reuse): W1 = tf.get_variable('w1',shape=[784,512]) # 默认使用Xavier初始化 b1 = tf.Variable(tf.zeros([512])) l1 = tf.nn.relu(tf.matmul(input_images,W1) + b1) W2 = tf.get_variable('w2',shape=[512,512]) # 默认使用Xavier初始化 b2 = tf.Variable(tf.zeros([512])) l2 = tf.nn.relu(tf.matmul(l1,W2) + b2) W3 = tf.get_variable('w3',shape=[512,10]) # 默认使用Xavier初始化 b3 = tf.Variable(tf.zeros([10])) y = tf.nn.softmax(tf.matmul(l2,W3) + b3) return y
这里偏置项初始化为0是没问题的,Layers API的dense层也默认把偏置初始化为0。
完整可运行代码
import numpy as np import tensorflow as tf from tensorflow.examples.tutorials.mnist import input_data mnist = input_data.read_data_sets("MNIST_data/", one_hot=True) input_images = tf.placeholder(tf.float32, [None, 784], name='input_images') input_labels = tf.placeholder(tf.float32, [None, 10], name = 'input_labels') def create_mlp_net(input_images=input_images, reuse=False): with tf.variable_scope('mlp', reuse = reuse): l1 = tf.layers.dense(input_images, 512, activation=tf.nn.relu) l2 = tf.layers.dense(l1, 512, activation=tf.nn.relu) y = tf.layers.dense(l2, 10, activation=tf.nn.softmax) return y def manual_create_mlp_net(input_images=input_images, reuse=False): with tf.variable_scope('mlp', reuse = reuse): W1 = tf.get_variable('w1',shape=[784,512]) b1 = tf.Variable(tf.zeros([512])) l1 = tf.nn.relu(tf.matmul(input_images,W1) + b1) W2 = tf.get_variable('w2',shape=[512,512]) b2 = tf.Variable(tf.zeros([512])) l2 = tf.nn.relu(tf.matmul(l1,W2) + b2) W3 = tf.get_variable('w3',shape=[512,10]) b3 = tf.Variable(tf.zeros([10])) y = tf.nn.softmax(tf.matmul(l2,W3) + b3) return y y_api = create_mlp_net(input_images,reuse=False) y_man = manual_create_mlp_net(input_images,reuse=False) y_use = y_man # 切换为手动实现即可得到和API版接近的准确率 cross_entropy = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits_v2(labels=input_labels, logits=y_use)) train_step = tf.train.RMSPropOptimizer(0.001).minimize(cross_entropy) with tf.Session() as sess: tf.global_variables_initializer().run() for _ in range(1000): batch_xs, batch_ys = mnist.train.next_batch(100) sess.run(train_step, feed_dict={input_images: batch_xs, input_labels: batch_ys}) correct_prediction = tf.equal(tf.argmax(y_use,1), tf.argmax(input_labels,1)) accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32)) print(sess.run(accuracy, feed_dict={input_images: mnist.test.images, input_labels: mnist.test.labels}))
内容的提问来源于stack exchange,提问作者ste_kwr
相关产品推荐
相关产品推荐

