如何在 MNIST 数据上使用 TensorFlow 和 python 创建 2 层神经网络
How to create 2-layers neural network using TensorFlow and python on MNIST data
我是机器学习的新手,我正在按照 tensorflow 的教程创建一些学习 MNIST 数据的简单神经网络。
我已经构建了一个单层网络(按照教程),准确度约为 0.92,这对我来说还可以。但是后来我又加了一层,准确率降到0.113,很糟糕。
下面是2层之间的关系:
import tensorflow as tf
x = tf.placeholder(tf.float32, [None, 784])
#layer 1
W1 = tf.Variable(tf.zeros([784, 100]))
b1 = tf.Variable(tf.zeros([100]))
y1 = tf.nn.softmax(tf.matmul(x, W1) + b1)
#layer 2
W2 = tf.Variable(tf.zeros([100, 10]))
b2 = tf.Variable(tf.zeros([10]))
y2 = tf.nn.softmax(tf.matmul(y1, W2) + b2)
#output
y = y2
y_ = tf.placeholder(tf.float32, [None, 10])
我的结构好吗?是什么原因让它表现如此糟糕?我应该如何修改我的网络?
第二层的输入是第一层输出的softmax
。你不想那样做。
您强制这些值的总和为 1。如果 tf.matmul(x, W1) + b1
的某些值大约为 0(并且肯定是),则 softmax 操作会将此值降低为 0。结果:您正在扼杀梯度,没有任何东西可以流过这些神经元。
如果您删除层之间的 softmax(但如果您想将这些值视为概率,则将其放在输出层上的 softmax)您的网络将正常工作。
Tl;博士:
import tensorflow as tf
x = tf.placeholder(tf.float32, [None, 784])
#layer 1
W1 = tf.Variable(tf.zeros([784, 100]))
b1 = tf.Variable(tf.zeros([100]))
y1 = tf.matmul(x, W1) + b1 #remove softmax
#layer 2
W2 = tf.Variable(tf.zeros([100, 10]))
b2 = tf.Variable(tf.zeros([10]))
y2 = tf.nn.softmax(tf.matmul(y1, W2) + b2)
#output
y = y2
y_ = tf.placeholder(tf.float32, [None, 10])
遇到完全相同的问题,梯度发散并得到一堆 nan
用于预测 y
。实施了 nessuno 的建议,不幸的是,发散梯度仍未修复。
相反,我尝试 sigmoid
作为第 1 层的激活函数,它起作用了!但是对于 relu
如果将 W1
和 W2
初始化为零矩阵则不起作用,精度仅为 0.1135 。为了使 relu
和 sigmoid
都起作用,最好将 W1
和 W2
的初始化随机化。这是修改后的代码
import tensorflow as tf
x = tf.placeholder(tf.float32, [None, 784])
# layer 1
with tf.variable_scope('layer1'):
W1 = tf.get_variable('w1',[784,200],
initializer=tf.random_normal_initializer())
b1 = tf.get_variable('b1',[1,],
initializer=tf.constant_initializer(0.0))
y1 = tf.nn.sigmoid(tf.matmul(x, W1) + b1)
# y1 = tf.nn.relu(tf.matmul(x, W1) + b1) # alternative choice for activation
# layer 2
with tf.variable_scope('layer2'):
W2 = tf.get_variable('w2',[200,10],
initializer= tf.random_normal_nitializer())
b2 = tf.get_variable('b2',[1,],
initializer=tf.constant_initializer(0.0))
y2 = tf.nn.softmax(tf.matmul(y1, W2) + b2)
# output
y = y2
y_ = tf.placeholder(tf.float32, [None, 10])
我发现 this link 很有帮助,请参阅问题 2 (c) 部分,它给出了基本 2 层神经网络的反向传播导数。在我看来,当用户没有指定任何激活函数时,只在第 1 层应用线性流,最终会反向传播一个看起来像 (sth)*W2^T*W1^T
的梯度,并且当我们同时初始化 W1
和 W2
为零,它们的乘积可能非常小接近于零,这导致梯度消失。
更新
这是来自 Quora 的回答 Ofir posted 关于神经网络中好的初始权重。
The most common initializations are random initialization and Xavier
initialization. Random initialization just samples each weight from a
standard distribution (often a normal distribution) with low
deviation. The low deviation allows you to bias the network towards
the 'simple' 0 solution, without the bad repercussions of actually
initializing the weights to 0.
我尝试 运行 上面的代码片段。低于 90% 的结果被丢弃,我从来没有真正确定我做了上面的评论。这是我的完整代码。
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
x = tf.placeholder(tf.float32, [None, 784])
#layer 1
W1 = tf.get_variable('w1', [784, 100], initializer=tf.random_normal_initializer())
b1 = tf.get_variable('b1', [1,], initializer=tf.random_normal_initializer())
y1 = tf.nn.sigmoid(tf.matmul(x, W1) + b1)
#layer 2
W2 = tf.get_variable('w2',[100,10], initializer=
tf.random_normal_initializer())
b2 = tf.get_variable('b2',[1,], initializer=tf.random_normal_initializer())
y2 = tf.nn.softmax(tf.matmul(y1, W2) + b2)
#output
y = y2
y_ = tf.placeholder(tf.float32, [None, 10])
cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y),
reduction_indices=[1]))
train_step = tf.train.GradientDescentOptimizer(0.2).minimize(cross_entropy)
sess = tf.InteractiveSession()
tf.global_variables_initializer().run()
for _ in range(10000):
batch_xs, batch_ys = mnist.train.next_batch(100)
sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})
correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
print(sess.run(accuracy, feed_dict={x: mnist.test.images, y_:
mnist.test.labels}))
通过改变 10000 -> 200000 我达到了 95.5%。
我是机器学习的新手,我正在按照 tensorflow 的教程创建一些学习 MNIST 数据的简单神经网络。
我已经构建了一个单层网络(按照教程),准确度约为 0.92,这对我来说还可以。但是后来我又加了一层,准确率降到0.113,很糟糕。
下面是2层之间的关系:
import tensorflow as tf
x = tf.placeholder(tf.float32, [None, 784])
#layer 1
W1 = tf.Variable(tf.zeros([784, 100]))
b1 = tf.Variable(tf.zeros([100]))
y1 = tf.nn.softmax(tf.matmul(x, W1) + b1)
#layer 2
W2 = tf.Variable(tf.zeros([100, 10]))
b2 = tf.Variable(tf.zeros([10]))
y2 = tf.nn.softmax(tf.matmul(y1, W2) + b2)
#output
y = y2
y_ = tf.placeholder(tf.float32, [None, 10])
我的结构好吗?是什么原因让它表现如此糟糕?我应该如何修改我的网络?
第二层的输入是第一层输出的softmax
。你不想那样做。
您强制这些值的总和为 1。如果 tf.matmul(x, W1) + b1
的某些值大约为 0(并且肯定是),则 softmax 操作会将此值降低为 0。结果:您正在扼杀梯度,没有任何东西可以流过这些神经元。
如果您删除层之间的 softmax(但如果您想将这些值视为概率,则将其放在输出层上的 softmax)您的网络将正常工作。
Tl;博士:
import tensorflow as tf
x = tf.placeholder(tf.float32, [None, 784])
#layer 1
W1 = tf.Variable(tf.zeros([784, 100]))
b1 = tf.Variable(tf.zeros([100]))
y1 = tf.matmul(x, W1) + b1 #remove softmax
#layer 2
W2 = tf.Variable(tf.zeros([100, 10]))
b2 = tf.Variable(tf.zeros([10]))
y2 = tf.nn.softmax(tf.matmul(y1, W2) + b2)
#output
y = y2
y_ = tf.placeholder(tf.float32, [None, 10])
遇到完全相同的问题,梯度发散并得到一堆 nan
用于预测 y
。实施了 nessuno 的建议,不幸的是,发散梯度仍未修复。
相反,我尝试 sigmoid
作为第 1 层的激活函数,它起作用了!但是对于 relu
如果将 W1
和 W2
初始化为零矩阵则不起作用,精度仅为 0.1135 。为了使 relu
和 sigmoid
都起作用,最好将 W1
和 W2
的初始化随机化。这是修改后的代码
import tensorflow as tf
x = tf.placeholder(tf.float32, [None, 784])
# layer 1
with tf.variable_scope('layer1'):
W1 = tf.get_variable('w1',[784,200],
initializer=tf.random_normal_initializer())
b1 = tf.get_variable('b1',[1,],
initializer=tf.constant_initializer(0.0))
y1 = tf.nn.sigmoid(tf.matmul(x, W1) + b1)
# y1 = tf.nn.relu(tf.matmul(x, W1) + b1) # alternative choice for activation
# layer 2
with tf.variable_scope('layer2'):
W2 = tf.get_variable('w2',[200,10],
initializer= tf.random_normal_nitializer())
b2 = tf.get_variable('b2',[1,],
initializer=tf.constant_initializer(0.0))
y2 = tf.nn.softmax(tf.matmul(y1, W2) + b2)
# output
y = y2
y_ = tf.placeholder(tf.float32, [None, 10])
我发现 this link 很有帮助,请参阅问题 2 (c) 部分,它给出了基本 2 层神经网络的反向传播导数。在我看来,当用户没有指定任何激活函数时,只在第 1 层应用线性流,最终会反向传播一个看起来像 (sth)*W2^T*W1^T
的梯度,并且当我们同时初始化 W1
和 W2
为零,它们的乘积可能非常小接近于零,这导致梯度消失。
更新
这是来自 Quora 的回答 Ofir posted 关于神经网络中好的初始权重。
The most common initializations are random initialization and Xavier initialization. Random initialization just samples each weight from a standard distribution (often a normal distribution) with low deviation. The low deviation allows you to bias the network towards the 'simple' 0 solution, without the bad repercussions of actually initializing the weights to 0.
我尝试 运行 上面的代码片段。低于 90% 的结果被丢弃,我从来没有真正确定我做了上面的评论。这是我的完整代码。
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
x = tf.placeholder(tf.float32, [None, 784])
#layer 1
W1 = tf.get_variable('w1', [784, 100], initializer=tf.random_normal_initializer())
b1 = tf.get_variable('b1', [1,], initializer=tf.random_normal_initializer())
y1 = tf.nn.sigmoid(tf.matmul(x, W1) + b1)
#layer 2
W2 = tf.get_variable('w2',[100,10], initializer=
tf.random_normal_initializer())
b2 = tf.get_variable('b2',[1,], initializer=tf.random_normal_initializer())
y2 = tf.nn.softmax(tf.matmul(y1, W2) + b2)
#output
y = y2
y_ = tf.placeholder(tf.float32, [None, 10])
cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y),
reduction_indices=[1]))
train_step = tf.train.GradientDescentOptimizer(0.2).minimize(cross_entropy)
sess = tf.InteractiveSession()
tf.global_variables_initializer().run()
for _ in range(10000):
batch_xs, batch_ys = mnist.train.next_batch(100)
sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})
correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
print(sess.run(accuracy, feed_dict={x: mnist.test.images, y_:
mnist.test.labels}))
通过改变 10000 -> 200000 我达到了 95.5%。