TensorFlow 2.0: усердное выполнение обучения либо возвращает плохие результаты, либо вообще не учится

Я экспериментирую с TensorFlow 2.0 (альфа). Я хочу реализовать простую сеть прямой связи с двумя выходными узлами для двоичной классификации (это версия 2.0 этой модели).

Это упрощенная версия скрипта. После того, как я определил простую модель Sequential(), я установил:

# import layers + dropout & activation
from tensorflow.keras.layers import Dense, Dropout
from tensorflow.keras.activations import elu, softmax

# Neural Network Architecture
n_input = X_train.shape[1]
n_hidden1 = 15
n_hidden2 = 10
n_output = y_train.shape[1]


model = tf.keras.models.Sequential([
    Dense(n_input, input_shape = (n_input,), activation = elu),   # Input layer
    Dropout(0.2), 
    Dense(n_hidden1, activation = elu), # hidden layer 1
    Dropout(0.2),     
    Dense(n_hidden2, activation = elu), # hidden layer 2
    Dropout(0.2), 
    Dense(n_output, activation = softmax)  # Output layer
])


# define loss and accuracy
bce_loss = tf.keras.losses.BinaryCrossentropy()
accuracy = tf.keras.metrics.BinaryAccuracy()

# define optimizer
optimizer = tf.optimizers.Adam(learning_rate = 0.001)

# save training progress in lists
loss_history = []
accuracy_history = []


# loop over 1000 epochs
for epoch in range(1000):

    with tf.GradientTape() as tape:

        # take binary cross-entropy (bce_loss)
        current_loss = bce_loss(model(X_train), y_train)

    # Update weights based on the gradient of the loss function
    gradients = tape.gradient(current_loss, model.trainable_variables)
    optimizer.apply_gradients(zip(gradients, model.trainable_variables))

    # save in history vectors
    current_loss = current_loss.numpy()
    loss_history.append(current_loss)

    accuracy.update_state(model(X_train), y_train)
    current_accuracy = accuracy.result().numpy()
    accuracy_history.append(current_accuracy)

    # print loss and accuracy scores each 100 epochs
    if (epoch+1) % 100 == 0:
        print(str(epoch+1) + '.\tTrain Loss: ' + str(current_loss) + ',\tAccuracy: ' + str(current_accuracy))

    accuracy.reset_states()

print('\nTraining complete.')

Обучение проходит без ошибок, однако случаются странности:

  • Иногда Сеть ничему не учится. Все оценки потерь и точности постоянны на протяжении всех эпох.
  • В других случаях сеть учится, но очень-очень плохо. Точность никогда не превышала 0,4 (в то время как в TensorFlow 1.x я без особых усилий получил 0,95+). Такой низкий показатель говорит мне о том, что что-то пошло не так на тренировке.
  • В других случаях точность улучшается очень медленно, а потери все время остаются постоянными.

Что может вызвать эти проблемы? Пожалуйста, помогите мне понять мои ошибки.


ОБНОВЛЕНИЕ: После некоторых исправлений я могу заставить Сеть учиться. Однако его производительность крайне низка. После 1000 эпох точность достигает около 40%, что явно означает, что что-то все еще не так. Любая помощь приветствуется.


person Leevo    schedule 21.03.2019    source источник


Ответы (1)


tf.GradientTape записывает каждую операцию, которая происходит внутри его области.

Вы не хотите записывать на ленту расчет градиента, вы хотите только вычислить потери вперед.

with tf.GradientTape() as tape:
    # take binary cross-entropy (bce_loss)
    current_loss = bce_loss(model(df), classification)
# End of tape scope

# Update weights based on the gradient of the loss function
gradients = tape.gradient(current_loss, model.trainable_variables)
# The tape is now consumed
optimizer.apply_gradients(zip(gradients, model.trainable_variables))

Что еще более важно, я не вижу цикла на тренировочном наборе, поэтому я полагаю, что полный код выглядит так:

for epoch in range(n_epochs):
    for df, classification in dataset:
        # your code that computes loss and trains

Кроме того, использование метрик является неправильным.

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

Таким образом, вы должны:

# Measure the accuracy inside the training loop
accuracy.update_state(model(df), classification)

И вызывать accuracy.result() только в конце эпохи, когда все значения точности сохранены в метрике. Не забудьте вызвать метод .reset_states(), чтобы очистить состояния переменных, сбрасывая их на ноль в конце каждой эпохи.

person nessuno    schedule 21.03.2019
comment
1) Извините, я все еще не понимаю строку for df, classification in dataset: что такое объект dataset? (В моем скрипте df — это мой набор данных, а classification — зависимая переменная с горячим кодированием). 2) Должен ли я написать current_accuracy = accuracy.update_state(model(df), classification), а затем добавить это к accuracy_history? Кстати, спасибо за всю информацию. - person Leevo; 21.03.2019
comment
1) Таким образом, вы не зацикливаете средние партии, а используете весь тренировочный набор одновременно. Чистый градиентный спуск, а не мини-пакетный градиентный спуск - тогда все в порядке! Вы можете удалить часть цикла, которую я добавил, так как вам не нужно зацикливаться на наборе данных. 2) accuracy.update_state(model(df), classification), затем accuracy_history.append(accuracy.result()) и закончить на accuracy_history.clear_states() - person nessuno; 21.03.2019
comment
Возможно, Вы имели в виду: accuracy.reset_states() в конце? Сделать то же самое для loss ? - person Leevo; 21.03.2019
comment
Привет, я следовал всем твоим советам, но проблема все еще существует. Выходные потери и точность всегда постоянны, за исключением случаев, когда он учится, но так плохо, что не может быть прав. Что еще я могу попробовать? - person Leevo; 25.03.2019
comment
Привет, пожалуйста, обновите пост с обновленной версией кода - это может помочь - person nessuno; 25.03.2019
comment
Я обновил код. Теперь он включает в себя предложенные вами исправления, а также спецификацию MLP. - person Leevo; 25.03.2019
comment
Выглядит нормально — единственная отсутствующая часть — это параметр обучения последовательного метода __call__. Когда вы пробуете модель, вы должны использовать ее как model(X_train, True) во время измерения точности, вместо этого вы должны установить ti в режим вывода, таким образом, model(X_train, False) - вероятно, низкая точность связана с применением отсева при ее измерении. - person nessuno; 25.03.2019
comment
Понятно. Что-то не так в вычислении точности: я только что визуализировал матрицу путаницы на тестовом наборе и получил точность около 98%. Подскажите, в чем проблема с точностью? - person Leevo; 26.03.2019
comment
Кажется, я нашел причину! ` precision.update_state(model(X_train), y_train)` должно быть ` precision.update_state(y_train, model(X_train))`, поскольку tensorflow.org/api_docs/python/tf/keras/metrics/Accuracy — это точность (y_true, y_pred) - person nessuno; 26.03.2019
comment
Да, теперь это работает. Почему на такую ​​операцию, как Binary Accuracy, может повлиять переключение с (a, b) на (b, a)? Однако спасибо. Я успешно провел свой первый MLP в TF 2.0 благодаря вашей помощи. - person Leevo; 26.03.2019
comment
Потому что считать прогнозы и метки одним и тем же — неправильно! (а,б) != (б,а). Однако я рад помочь - отметьте этот ответ как принятый сейчас: D - person nessuno; 26.03.2019