TensorFlow 2.0: нетерпеливое выполнение обучения либо дает плохие результаты, либо совсем не учится - PullRequest
1 голос
/ 21 марта 2019

Я экспериментирую с 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+ без усилий). Такая низкая производительность говорит о том, что на тренировке что-то пошло не так.
  • В других случаях точность очень медленно улучшается, в то время как потери остаются постоянными.

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


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

1 Ответ

2 голосов
/ 21 марта 2019

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(), чтобы очистить состояния переменных, обнуляя его в конце каждой эпохи.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...