Tensorflow 无法将手动创建的模型与使用图层的模型协调一致 api
Tensorflow can't reconcile manually created model with the one using layers api
我在手动重新创建使用图层 API 创建的模型时遇到问题。这是我认为应该相等但在我 运行 它们时不知何故无法解决的两个公式。
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.Variable(tf.zeros([784,512]))
b1 = tf.Variable(tf.zeros([512]))
l1 = tf.nn.relu(tf.matmul(input_images,W1) + b1)
W2 = tf.Variable(tf.zeros([512,512]))
b2 = tf.Variable(tf.zeros([512]))
l2 = tf.nn.relu(tf.matmul(l1,W2) + b2)
W3 = tf.Variable(tf.zeros([512,10]))
b3 = tf.Variable(tf.zeros([10]))
y = tf.nn.softmax(tf.matmul(l2,W3) + b3)
return y
第一个的准确率为 97%,而手动的准确率为 11%。我似乎无法弄清楚为什么它们应该是相同的。下面是我用来 运行 这个的最小工作代码。
正确实施
根据 NPE 的以下回答,初始化是问题所在。下面的手动实现最接近于使用层 API:
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
最少的工作代码
import numpy as np
import tensorflow as tf
# Load training and eval data
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')
y_api = create_mlp_net(input_images,reuse=False)
y_man = manual_create_mlp_net(input_images,reuse=False)
y_use = y_api ## Changing this to y_man does not yield the same result
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}))
根本原因是你把三个权重矩阵初始化为零
这是行不通的,因为一层中的神经元之间没有不对称性,因此它们无法学习不同的东西。
非线性模型的推荐做法是使用较小的随机初始权重。这是在 tf.layers.dense
中通过委托给 get_variable()
完成的,后者又默认为 glorot_uniform_initializer
.
请注意,这仅针对权重进行;偏差被初始化为零,就像在您的代码中所做的那样。
有关 Xavier 初始化程序的讨论,请参阅
Why should the initialization of weights and bias be chosen around 0?
我在手动重新创建使用图层 API 创建的模型时遇到问题。这是我认为应该相等但在我 运行 它们时不知何故无法解决的两个公式。
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.Variable(tf.zeros([784,512]))
b1 = tf.Variable(tf.zeros([512]))
l1 = tf.nn.relu(tf.matmul(input_images,W1) + b1)
W2 = tf.Variable(tf.zeros([512,512]))
b2 = tf.Variable(tf.zeros([512]))
l2 = tf.nn.relu(tf.matmul(l1,W2) + b2)
W3 = tf.Variable(tf.zeros([512,10]))
b3 = tf.Variable(tf.zeros([10]))
y = tf.nn.softmax(tf.matmul(l2,W3) + b3)
return y
第一个的准确率为 97%,而手动的准确率为 11%。我似乎无法弄清楚为什么它们应该是相同的。下面是我用来 运行 这个的最小工作代码。
正确实施
根据 NPE 的以下回答,初始化是问题所在。下面的手动实现最接近于使用层 API:
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
最少的工作代码
import numpy as np
import tensorflow as tf
# Load training and eval data
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')
y_api = create_mlp_net(input_images,reuse=False)
y_man = manual_create_mlp_net(input_images,reuse=False)
y_use = y_api ## Changing this to y_man does not yield the same result
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}))
根本原因是你把三个权重矩阵初始化为零
这是行不通的,因为一层中的神经元之间没有不对称性,因此它们无法学习不同的东西。
非线性模型的推荐做法是使用较小的随机初始权重。这是在 tf.layers.dense
中通过委托给 get_variable()
完成的,后者又默认为 glorot_uniform_initializer
.
请注意,这仅针对权重进行;偏差被初始化为零,就像在您的代码中所做的那样。
有关 Xavier 初始化程序的讨论,请参阅 Why should the initialization of weights and bias be chosen around 0?