为什么tf.train.GradientOptimizer不能在我的数字识别模型上工作,而tensorflow.contrib的ShampooOptimizer却能正常工作?

时间:2019-01-10 18:13:08

标签: tensorflow optimization deep-learning gradient-descent

我开发了一个神经网络模型,用于使用张量流进行数字识别。我使用tf.train.GradientDescent作为优化器,但预测精度很低(大约11%)。但是,如果仅将我的优化器从tensorflow.contrib更改为ShampooOptimizer,它对验证数据的准确性就很高(约92%)。

我实际上只是更改了我的代码的一行:     来自opt = tf.train.GradientDescentOptimizer(0.001)     到opt = ShampooOptimizer()     而且有效

我试图在训练中停下来,但发现了一些区别。 对于GradientDescentOptimizer:     经过60次迭代,最佳W在维度上具有相同的编号(我为第一层设置了87个维度),最佳b在维度上具有相同的编号。 对于洗发水:     经过60次迭代,最佳W在维度上具有不同的数字,最佳b也是如此。 我注意到了这种差异,但我不知道为什么。

import tensorflow as tf
import numpy as np
from mnist import MNIST
from tensorflow.contrib.opt.python.training.shampoo import *

mndata = MNIST()
data, labels = mndata.load_training()
data = np.array(data)
nb_classes = 10
labels = np.eye(nb_classes)[labels]

test_data, test_labels = mndata.load_testing()
test_data = np.array(test_data)
nb_classes = 10
test_labels = np.eye(nb_classes)[test_labels]

X = tf.placeholder(dtype='float32',shape = (None,784))          
y = tf.placeholder(dtype='float32',shape = (None, 10))

W = tf.Variable(initial_value=np.ones((784,87)),dtype='float32',name='W',trainable=True) 
b = tf.Variable(initial_value=np.ones((1,87)),dtype='float32',name='b', trainable=True)
preds_t1= tf.matmul(X,W) + b
preds_a1 = tf.nn.relu(preds_t1)                          

W2 = tf.Variable(initial_value=np.ones((87,10)),dtype='float32',name = 'W2')    
b2 = tf.Variable(initial_value=np.ones((1,10)),dtype='float32', name = 'b2')
logits = tf.matmul(preds_a1,W2) + b2
preds = tf.nn.softmax(logits, axis=1)

loss = tf.losses.softmax_cross_entropy(onehot_labels=y, logits=logits)
opt = tf.train.GradientDescentOptimizer(0.001)
opt_op = opt.minimize(loss = loss, var_list = [W, b, W2, b2])

s_preds = tf.argmax(preds, axis = 1)
s_labels = tf.argmax(y, axis = 1)
sacc, sacc_op = tf.metrics.accuracy(s_labels, s_preds)

saver = tf.train.Saver()

with tf.Session() as sess:
    sess.run(tf.initializers.global_variables())
    sess.run(tf.local_variables_initializer())

    best_W, best_b, best_W2, best_b2 = sess.run((W, b, W2, b2))
    stop_count = 0
    patience = 40
    best_loss = np.inf
    train_data, train_labels, valid_data, valid_labels = 
train_valid_split(data, labels, split = 0.2)
    for i in range(300):
        batch_X, batch_y = random_sampling(train_data, train_labels, 12000)
        sess.run((opt_op), feed_dict={X: batch_X, y: batch_y})
        s_loss, s_accuracy = sess.run((loss, sacc_op), feed_dict={X: valid_data, y: valid_labels})       # validation
        print('epoch: ' + str(i) + '; loss is: ' + str(s_loss) + '; slack_accuracy is :' + str(s_accuracy))
        # early stopping thing
        if s_loss < best_loss:
            best_loss = s_loss
            best_W, best_b, best_W2, best_b2 = sess.run((W, b, W2, b2))
        else:
            stop_count += 1
            if (stop_count >=  patience):
                print('Stopped at iteration: ' + str(i))
                break

有人能向我解释导致精度差异的这两个优化器之间的差异吗?

1 个答案:

答案 0 :(得分:0)

您正在将所有权重初始化为相同的值(使用np.ones)。这会破坏您的模型,因为所有隐藏单元都将计算相同的事物(并接收相同的错误),因此它们也将学习相同的事物,这意味着您实际上只有一个隐藏单元。我不知道洗发水优化器的作用,但我想它具有某种对称性。
如果您将权重初始值替换为随机数(例如,隐藏层为tf.random_uniform([784,87], minval=-0.1, maxval=0.1)),则您的模型应该使用默认的梯度下降。这样可以防止所有单位都相同。