простой MLP с нуля с использованием tensorflow

#python #tensorflow #machine-learning #mnist

#python #tensorflow #машинное обучение #mnist

Вопрос:

Я пытаюсь реализовать MLP в tensorflow с нуля и протестировать его на наборе данных MNIST. Это мой код:

 import tensorflow.compat.v1 as tf
from tensorflow.compat.v1.keras.losses import categorical_crossentropy
tf.disable_v2_behavior()

image_tensor = tf.placeholder(tf.float32 , shape=(None , 784))
label_tensor = tf.placeholder(tf.float32 , shape=(None , 10))

# Model architecture
# --> Layer 1
w1 = tf.Variable(tf.random_uniform([784 , 128])) # weights
b1 = tf.Variable(tf.zeros([128])) # bias
a1 = tf.matmul(image_tensor , w1)   b1
h1 = tf.nn.relu(a1)
# --> Layer 2
w2 = tf.Variable(tf.random_uniform([128 , 128]))
b2 = tf.zeros([128])
a2 = tf.matmul(h1 , w2)   b2
h2 = tf.nn.relu(a2)
# --> output layer
w3 = tf.Variable(tf.random_uniform([128 , 10]))
b3 = tf.zeros([10])
a3 = tf.matmul(h2 , w3)   b3
predicted_tensor = tf.nn.softmax(a3) 

loss = tf.reduce_mean(categorical_crossentropy(label_tensor , predicted_tensor))

opt = tf.train.GradientDescentOptimizer(0.01) 
training_step = opt.minimize(loss)

with tf.Session() as sess:
    init_op = tf.global_variables_initializer()
    sess.run(init_op)   
    epochs = 50
    batch  = 100
    iterations = len(training_images) // batch

    for j in range(epochs):
        start = 0
        end = batch
        for i in range(iterations):
            image_batch = np.array(training_images[start : end])
            label_batch = np.array(training_labels[start : end])

            start = batch   1
            end = start   batch
            _ , loss = sess.run(training_step  , feed_dict = {
                image_tensor : image_batch,
                label_tensor : label_batch
                })
  

но когда я пытаюсь запустить этот код, я получаю это сообщение об ошибке:

 File "MNIST3.py", line 97, in <module>
    main()
  File "MNIST3.py", line 88, in main
    label_tensor : label_batch
TypeError: 'NoneType' object is not iterable
  

Хотя, когда я пытаюсь распечатать первые 10 образцов из label_batch:

 print(training_labels[0 : 10])
  

Это будет результат:

 [[1 0 0 0 0 0 0 0 0 0]
 [1 0 0 0 0 0 0 0 0 0]
 [1 0 0 0 0 0 0 0 0 0]
 [1 0 0 0 0 0 0 0 0 0]
 [1 0 0 0 0 0 0 0 0 0]
 [1 0 0 0 0 0 0 0 0 0]
 [1 0 0 0 0 0 0 0 0 0]
 [1 0 0 0 0 0 0 0 0 0]
 [1 0 0 0 0 0 0 0 0 0]
 [1 0 0 0 0 0 0 0 0 0]]
  

И когда я пытаюсь напечатать форму набора данных:

 print(training_images.shape)
print(training_labels.shape)
  

Это вывод:

 (10000, 784)
(10000, 10)
  

Чего мне здесь не хватает?

Комментарии:

1. Кроме того, это субъективная вещь, но подумайте также об изучении реализации TF 2.0. Я долгое время использовал TF 1.0, поэтому написал множество сложных моделей, используя графики и session.run, и работа с TF 2.0 до сих пор облегчала мне жизнь. Кроме того, именно там в конечном итоге будет оказана вся поддержка, так что это более прибыльная технология, на которую стоит тратить свое время. (Однако знание графиков, безусловно, полезно, поскольку вы работаете с графиками, например, при создании пользовательских слоев keras)

Ответ №1:

Вы неправильно поняли сообщение об ошибке (Python может вводить в заблуждение в этом, мы все сталкивались с подобными ошибками чаще, чем хотелось бы признать …). Несмотря на то, что он отображает label_tensor : label_batch строку в вашей ошибке, на самом деле речь идет обо всем session.run() вызове.

И причина, по которой вы видите эту ошибку, заключается в том, что вы ожидаете, что вызов вернет кортеж, но вы предоставляете только один тензор, который будет вычислен TensorFlow.

sess.run(training_step, feed_dict=...) вернется None , потому что op training_step не должен ничего возвращать, вызывая его, вы просто выполняете один шаг оптимизации.

Чтобы получить желаемый результат, измените код на:

 _ , loss_result = sess.run([training_step, loss], 
                           feed_dict={
                               image_tensor : image_batch,
                               label_tensor : label_batch
                           })
  

Таким образом, TensorFlow оценит эти 2 операции, первая вернет None (как вы уже получаете), а вторая вычислит значение вашей функции потерь для данного пакета.

(Обратите внимание, что вам нужно переименовать переменную loss в левой части, потому что, если вы этого не сделаете, вы замените операцию потери, и следующий вызов, вероятно, вызовет исключение или, что еще хуже, просто даст неправильные результаты)