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

Why doesn't tf.train.GradientOptimizer work on my digit recognition model, while ShampooOptimizer from tensorflow.contrib works just fine?

我使用 tensorflow 开发了一个用于数字识别的神经网络模型。我使用 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

任何人都可以向我解释导致这种准确性差异的这两个优化器之间的差异吗?

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