Почему модель LSTM не выдает одинаковые конечные веса при каждом прогоне, тогда как начальные веса всегда одинаковы? - PullRequest
0 голосов
/ 09 апреля 2019

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

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

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

Epoch 00000: val_loss did not improve
3s - loss: 0.0251 - val_loss: 0.0276
1994
--
Epoch 00000: val_loss did not improve
3s - loss: 0.0251 - val_loss: 0.0276
1995
--
Epoch 00000: val_loss did not improve
3s - loss: 0.0251 - val_loss: 0.0276
1996
--
Epoch 00000: val_loss did not improve
3s - loss: 0.0251 - val_loss: 0.0276
1997
--
Epoch 00000: val_loss did not improve
3s - loss: 0.0251 - val_loss: 0.0276
1998
--
Epoch 00000: val_loss did not improve
3s - loss: 0.0251 - val_loss: 0.0276
1999
--
Epoch 00000: val_loss did not improve
3s - loss: 0.0251 - val_loss: 0.0276
[2019-04-07 18:28:17,495 - - DEBUG -my_project_model.py:317 -             fit_lstm() ] Time taken: 126.07314221905544 min

И для того же набора данных и того же фрагмента кода выходные данные различны.Журналы примеров показаны ниже.И val_loss намного меньше, чем предыдущий всего за 285 эпох.Мы не понимаем, что именно происходит на заднем плане.

3s - loss: 0.0044 - val_loss: 0.0011
271
--
Epoch 1/1
Epoch 00000: val_loss did not improve
3s - loss: 0.0043 - val_loss: 0.0011
272
--
Epoch 1/1
Epoch 00000: val_loss did not improve
3s - loss: 0.0043 - val_loss: 0.0011
273
--
Epoch 1/1
Epoch 00000: val_loss did not improve
3s - loss: 0.0043 - val_loss: 9.5030e-04
274
--
Epoch 1/1
Epoch 00000: val_loss did not improve
3s - loss: 0.0042 - val_loss: 9.7404e-04
275
--
Epoch 1/1
Epoch 00000: val_loss did not improve
3s - loss: 0.0042 - val_loss: 0.0010
276
--
Epoch 1/1
Epoch 00000: val_loss did not improve
3s - loss: 0.0044 - val_loss: 9.6836e-04
277
--
Epoch 1/1
Epoch 00000: val_loss did not improve
3s - loss: 0.0042 - val_loss: 0.0011
278
--
Epoch 1/1
Epoch 00000: val_loss did not improve
3s - loss: 0.0042 - val_loss: 0.0010
279
--
Epoch 1/1
Epoch 00000: val_loss did not improve
3s - loss: 0.0042 - val_loss: 0.0010
280
--
Epoch 1/1
Epoch 00000: val_loss did not improve
3s - loss: 0.0042 - val_loss: 0.0011
281
--
Epoch 1/1
Epoch 00000: val_loss did not improve
3s - loss: 0.0042 - val_loss: 8.9629e-04
282
--
Epoch 1/1
Epoch 00000: val_loss did not improve
3s - loss: 0.0041 - val_loss: 9.8693e-04
283
--
Epoch 1/1
Epoch 00000: val_loss did not improve
3s - loss: 0.0041 - val_loss: 9.4584e-04
284
--
Epoch 1/1
Epoch 00000: val_loss did not improve
3s - loss: 0.0041 - val_loss: 0.0011
285
--
Epoch 1/1
Epoch 00000: val_loss did not improve
3s - loss: 0.0041 - val_loss: 9.8990e-04

Понятно, что он выбирает случайные пути;но выход может совпадать когда-нибудь.Но это никогда не совпало.Мы подозревали, что выпадение может привести к большей случайности, и мы удалили его из фрагмента кода.Приведенные выше результаты взяты из примера в реальном времени, и фрагмент кода, используемый для того же самого, приведен ниже.

Информация о библиотеках

[id@ip~]$ source activate projectcondaenv

(projectcondaenv) [id@ip~]$ conda list | grep -i keras
dist-keras                0.2.1                     <pip>
keras                     2.0.5                    py36_0  

(projectcondaenv) [id@ip~]$ conda list | grep -i tensor
tensorflow                1.3.0                         0  
tensorflow-base           1.3.0            py36h5293eaa_1  
tensorflow-tensorboard    0.1.5                    py36_0 

Переменные считываются из файла конфигурации, и оникак показано ниже:

nb_epoch=2000
batch_size=1
neurons=15

Код такой, как показано ниже:

from numpy.random import seed
from keras.layers import Dense, LSTM, TimeDistributed, Dropout
from keras.callbacks import ModelCheckpoint, EarlyStopping, ReduceLROnPlateau
#from keras.callbacks import TensorBoard
from keras.models import Sequential
from keras.models import load_model
#from keras.constraints import NonNeg
from sklearn.metrics import mean_squared_error
from sklearn.preprocessing import MinMaxScaler
from pathlib import Path
from datetime import timedelta
#from time import time

from exceptions.model_file_not_found_exception import  ModelFileNotFoundException
from exceptions.data_not_found_exception import  DataNotFoundException


logger = logging.getLogger(__name__)

tf.set_random_seed(1234)
seed(1)


class MyProject(object):
    def fit_lstm(self, train, batch_size, nb_epoch, neurons, test=None, load_model=False):
        import timeit
        try:
            start = timeit.default_timer()
            X, y = train[:, 0:-1], train[:, -1]
            X = X.reshape(X.shape[0], 1, X.shape[1])

            if test.any():
                X_test, y_test = test[:, 0:-1], test[:, -1]
                X_test = X_test.reshape(X_test.shape[0], 1, X_test.shape[1])

            model = Sequential()
            model.add(LSTM(neurons, batch_input_shape=(batch_size, X.shape[1], X.shape[2]), stateful=True,
                           return_sequences=True))
            #model.add(Dropout(self.dropout_1)) #commented
            model.add(LSTM(neurons, stateful=True))
            #model.add(Dropout(self.dropout_2)) #commented
            model.add(Dense(1))
            model.compile(loss=self.loss, optimizer=self.optimizer)

            if load_model:
                pass

                # callbacks
            c = [
                ModelCheckpoint(self.checkpoint_dir+self.model_filename, save_best_only=True,
                                                monitor='val_loss', mode='min', verbose=1, period=1),
                EarlyStopping(monitor='val_loss', min_delta=0, patience=10, verbose=1),
                ReduceLROnPlateau(monitor='val_loss', factor=0.2, patience=5, min_lr=self.min_lr)
            ]

            for i in range(nb_epoch):
                print(i)
                model.fit(X, y, epochs=1, batch_size=batch_size, verbose=2, shuffle=False, validation_data=(X_test, y_test),
                          callbacks=c)
                model.reset_states()
            time_taken = timeit.default_timer() - start
            logger.debug('Time taken: ' + str(time_taken/60) + ' min')
            model = self.get_latest_model()
            return model, round(time_taken/60, 2)
        except Exception as err:
            logger.error('Fit LSTM Method failed with Errors .. '+str(err))
            logger.exception('=== Failed to fit the LSTM Model  === ')
            raise err

Кто-нибудь может подсказать, в чем может быть проблема?

Почему на выходе огромная случайность?

Разве он не может найти глобальные минимумы и застревать на локальных минимумах?Пожалуйста, включите свет, чтобы помочь нам двигаться дальше.

Я уже ссылался на несколько статей и проблем с Keras (как показано ниже).Но ни один из этих ответов не отвечает на вопросы.

Ссылка:

https://stats.stackexchange.com/questions/255105/why-is-the-validation-accuracy-fluctuating

Существует несколько проблем, связанных с Keras:

https://github.com/keras-team/keras/issues/1597

https://github.com/keras-team/keras/issues/2711

https://github.com/keras-team/keras/issues/11371

1 Ответ

1 голос
/ 09 апреля 2019

В последнее время я пытался получить воспроизводимые результаты, используя Tensorflow 2.0 и его высокоуровневый keras API, и позвольте мне начать с того, что это не простая задача.

Я думаю, что вы на неправильном путиздесь (хотя я не могу проверить это напрямую), и проблема заключается в наследовании источника случайности в Tensorflow.

Прежде всего, вы должны попытаться установить все как можно более детерминированным, чтобыДля этого следуйте разделу часто задаваемых вопросов Keras по воспроизводимости .По сути, вы должны настроить что-то вроде этого:

import numpy as np
import tensorflow as tf
import random as rn

SEED=0

# Numpy fixed random seed
np.random.seed(SEED)

# Python's random generator
rn.seed(SEED)

# Tensorflow has to use one thread (multiple threads might give you different results)
session_conf = tf.ConfigProto(intra_op_parallelism_threads=1,
                              inter_op_parallelism_threads=1)

from keras import backend as K

# Set Tensorflow random seed
tf.set_random_seed(1234)

# Create default graph without parallelism
K.set_session(tf.Session(graph=tf.get_default_graph(), config=session_conf))

Кроме того, вам необходимо установить переменную окружения PYTHONHASHSEED=0 перед запуском скрипта Python из CLI следующим образом:

$ PYTHONHASHSEED=0 python my_script.py

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

$ CUDA_VISIBLE_DEVICES="" PYTHONHASHSEED=0 python my_script.py

Вы можете вводить каждое изменение шаг за шагом, чтобы максимально удалить недетерминированные факторы.Я бы сказал так:

  • Установите все начальные числа и PYTHONHASHSEED и проверьте, отличаются ли результаты
  • Используйте session_conf для удаления параллелизма между операциями
  • Наконец отключитеCUDA (если предыдущие действия не помогли)

Кроме этого (если вы работаете с моделью с одинаковыми начальными весами и разделение проверки всегда одинаково), это может быть присущей конструктивной ошибкойэти рамки см. эту проблему .

...