Оптимизатор градиентного спуска TensorFlow

Я новичок в этом мире глубокого обучения. В эти дни я стараюсь понять, как работает нейронная сеть, поэтому я делаю другой тест. Сейчас я использую базу данных MNIST с номерами от 0 до 9. Я использую полностью подключенную сеть без скрытых слоев. Вот код:

from keras.datasets import mnist # subroutines for fetching the MNIST dataset
import tensorflow as tf
import matplotlib.pyplot as plt
import numpy as np
from keras.utils import np_utils # utilities for one-hot encoding of ground truth values
from tensorflow.examples.tutorials.mnist import input_data

mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)

x_train = mnist.train.images
y_train = mnist.train.labels
x_test = mnist.test.images
y_test = mnist.test.labels

test = np.reshape(x_train,[-1,28,28]) #THRESHOLDING
x_train = np.zeros([55000,28,28])
x_train[test > 0.5] = 1


print(x_train.shape)

x_train = np.reshape(x_train,[55000,784])
y_train = np_utils.to_categorical(y_train, 10) # One-hot encode the labels

print(x_train.shape)
print(y_train.shape)

x_test = np.reshape(x_test,[10000,784])

input = tf.placeholder(tf.float32, name='Input')
output = tf.placeholder(tf.float32, name = 'Output')

syn0 = tf.Variable(2*tf.random_uniform([784,10],seed=1)-1, name= 'syn0')
#syn0 = tf.Variable(tf.zeros([784,10], dtype = tf.float32), name= 'syn0')


b1 = tf.Variable(2*tf.random_uniform([10],seed=1)-1, name= 'b1')
#b1 = tf.Variable(tf.zeros([10],dtype = tf.float32), name= 'syn0')

init = tf.global_variables_initializer()

#model

l1 = tf.nn.softmax((tf.matmul(input,syn0) + b1),name='layer1')

error = tf.square(tf.subtract(l1,output),name='error')
loss = tf.reduce_sum(error, name='cost')

#optimizer
with tf.name_scope('trainning'):
    optimizer = tf.train.GradientDescentOptimizer(0.01)
    train = optimizer.minimize(loss)


#session
sess = tf.Session()
sess.run(init)

syn0_ini = sess.run(syn0)

#trainning
for i in range (10000):
    batch_xs, batch_ys = mnist.train.next_batch(128)
    _,lossNow =  sess.run([train,loss],{input: batch_xs,output: batch_ys})

    if i%10 == 0:
        print("Loss in iteration " , i, " is: ", lossNow )

#print debug 

y_pred = sess.run(l1,{input: x_test,output: y_test})

correct_prediction = tf.equal(tf.argmax(y_pred,1), tf.argmax(y_test,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

print()
print("Final Accuracy: ", sess.run(accuracy))

Я напечатал веса (syn0), и я ничего не вижу. Но если я инициализирую их нулем, я вижу форму чисел. Это логика, потому что поскольку скрытых слоев нет, это похоже на корреляцию.

Так что в первом случае я могу предположить, что я могу видеть что-либо, потому что веса не были изменены, и они были инициализированы в случайные значения.

Что я не понимаю, так это то, что только тренировочные функции изменили только некоторые веса, так как я кормлю их с потерей, которая составляет всего одно число. Так что, по моему мнению, все веса должны быть изменены одинаково.

Здесь есть веса со случайными инициализациями: весы для 0 весов для 1

Теперь я поставил веса с нулевой инициализацией:

весов за 0 весов за 1

Как вы можете видеть, есть некоторые веса, которые остаются как в начале, но есть некоторые, которые меняются. Как это возможно, поскольку функция потерь - это просто скалярное число?

Надеюсь, мой вопрос ясен. Если не просто скажи мне.

Большое спасибо.

1 ответ

Решение

Что я не понимаю, так это то, что только тренировочные функции изменили только некоторые веса, так как я кормлю их с потерей, которая составляет всего одно число. Так что, по моему мнению, все веса должны быть изменены одинаково.

Это не совсем верно.

Рассмотрим линейную активацию в случае одиночной обучающей выборки:

Z = W*X + b    #(tf.matmul(input,syn0) + b1

Здесь вы выполняете скалярное произведение между W и X. В основном вы делаете:

Z = sum(W[j] * X[j]) + b

oss: matmul работает, потому что ваш вес - вектор строки, а особенности - вектор столбца.

После этого вы применяете функцию нелинейной активации, а именно функцию softmax. Это даст вам прогноз, который вы будете использовать для вычисления потерь, которые, как вы сказали, являются скалярами.

Теперь при выполнении шага обратного распространения TF будет вычислять производную потери по каждому компоненту W. Точно:

dW[j] = dL/dZ * dZ/dW[j]

где:

  • dL/dZ является производной убытка по Z
  • dZ/dW[j] является производной от Z по отношению к W

Предыдущая формула вытекает из правила цепочки.

Оказывается, что:

dZ/dW[j] = x[j]

Вот почему вы получаете разные значения для каждого компонента.

Для дальнейшего анализа смотрите этот вопрос. По сути, инициализация всех весов всех нейронов в 0 делает вашу сеть избыточной, так как все нейроны будут иметь одинаковые значения для W. Однако в каждом нейроне компонент W будет отличаться.

Другие вопросы по тегам