Keras LSTM, чем больше эпох, тем ниже точность и отзыв - PullRequest
0 голосов
/ 02 апреля 2019

Я работаю над проблемой с несколькими метками, с 38 входными переменными и выводом в виде 6 векторов с горячим кодированием. В общей сложности 7 различных временных рядов демонстрируют различные типы поведения, которым я хочу научить свою модель. Данные несбалансированы, так как примерно 20% в начале каждого временного ряда имеют «Ложь» на всех метках, в то время как последние 80% точек данных каждого временного ряда имеют как минимум одну метку «Позитивный» (за исключением все первые серии «ложные»).

Я испробовал множество различных подходов для улучшения своей модели, но основная проблема, с которой я боролся, сохраняется: чем больше эпох я запускаю, тем хуже производительность модели с точки зрения отзыва (она ' чаще всего просто помечаю все точки данных как ложную / нулевую гипотезу). Кроме того, я увижу функцию убывающих потерь для первых двух или трех временных рядов, а затем у последних будут только плоские / неизменные потери во все эпохи, даже если я запусту их в течение 300 эпох.

Кто-нибудь видит серьезные ошибки в моем коде, которые следует улучшить? Я подумал, что это может быть результатом комбинации несбалансированных данных и наборов тренировок и тестов, выбранных статически как соответственно 70% первых точек данных каждого временного ряда, и тестирования последних 30%. Тем не менее, я не уверен, как я могу сделать это иначе, чем перетасовывать временные ряды и, таким образом, вредить временному порядку данных.

Я был бы очень благодарен, если бы кто-нибудь мог подтолкнуть меня в правильном направлении!

class LSTM:

    def __init__(self): 
        self.x_testsets = {}
        self.y_testsets = {} 
        self.variable_split = 0
        self.results_total = pd.DataFrame(columns=['NoRot_P', 'NoThrust_P', 'NoRot_B', 'NoThrust_B','NoRot_S','NoThrust_S','pred_NoRot_P','pred_NoThrust_P', 
                                                   'pred_NoRot_B','pred_NoThrust_B','pred_NoRot_S','pred_NoThrust_S'])



    def model_initialize(self, datasets):
        num_datapoints = 0 
        input_dim = 38
        # One timestep at a time, ensure that statefulness is enabled. 
        timesteps = 1
        batch_size_c = 12
        epochs = 7
        iterate = 1
        total_epochs = epochs * len(datasets)
        epochs_done = 0
        set_names = ['NullHypothesis','behaviour1','behaviour2','behaviour3',
               'behaviour4','behaviour5','behaviour6']
        for k in datasets:
            break_flag = 0
            # Uncomment to shuffle
            #df = df.sample(frac=1).reset_index(drop=True)


            num_datapoints = datasets[k].shape[0] + num_datapoints


            split_num = 0.7
            train_elements = 0
            test_elements = 0 

            # Delete rows until both the test and training sets are divisible with batch size
            if(self.variable_split == 0): 
                if(break_flag):
                    break_flag = 0
                    break
                deletedRows = 0
                split = int(len(datasets[k])*split_num)
                train_elements = split
                test_elements = len(datasets[k])-(split)
                while True: 
                    if ((train_elements%batch_size_c == 0) and (test_elements%batch_size_c == 0)):
                        #print("Sets are now divisble by batch size - deleted " + str(deletedRows) +" rows")
                        break_flag = 1
                        break
                    datasets[k].drop((datasets[k].shape[0]-1),inplace = True)
                    split = int(len(datasets[k])*split_num)
                    train_elements = split
                    test_elements = len(datasets[k])-(split)
                    deletedRows = deletedRows + 1

            x = datasets[k].iloc[:, :-6] # Prediction variables
            y = datasets[k].iloc[:, -6:] # 

            x_train, x_test, y_train, y_test = x[:split], x[split:], y[:split], y[split:]


            # Feature Scaling

            scaler = StandardScaler()
            x_train = scaler.fit_transform(x_train)
            x_test = scaler.transform(x_test)

            # LSTM expect a 3D matrix, so we reshape the training data with an extra
            # singular dimension to satisfy the dimension requirements
            x_train = np.reshape(x_train, (x_train.shape[0],1,x_train.shape[1]))
            x_test = np.reshape(x_test, (x_test.shape[0],1,x_test.shape[1]))

            self.x_testsets[k] = x_test
            self.y_testsets[k] = y_test


            if(hasattr(self,'model')):
                self.model.reset_states()
            else:
                self.model = Sequential()
                self.model.add(LSTM(batch_size_c, return_sequences=False, batch_size = batch_size_c,stateful=True,
                               input_shape=(timesteps, input_dim)))  
                self.model.add(Dense(512, activation='linear'))
                self.model.add(LeakyReLU(alpha=0.3))
                self.model.add(Dense(512, activation='linear'))
                self.model.add(LeakyReLU(alpha=0.3))
                self.model.add(Dense(512, activation='linear'))
                self.model.add(LeakyReLU(alpha=0.3))
                self.model.add(Dense(512, activation='linear'))
                self.model.add(LeakyReLU(alpha=0.3))
                self.model.add(Dense(32, activation='linear'))
                self.model.add(LeakyReLU(alpha=0.3))
                self.model.add(Dense(32, activation='linear'))
                self.model.add(LeakyReLU(alpha=0.3))
                #self.model.add(LeakyReLU(alpha=0.3))
                self.model.add(Dense(6, activation='sigmoid'))
                opt = RMSprop(lr=0.001)
                self.model.compile(loss='binary_crossentropy', optimizer=opt, metrics=['binary_accuracy'])

history = np.zeros(epochs) 
            for i in range(epochs):
                acc = self.model.fit(x_train, y_train, epochs=1, batch_size=batch_size_c, verbose=0, shuffle=False)
                epochs_done = epochs_done + 1
                if(epochs_done/total_epochs > 0.1*iterate):
                    print("Percent done: ",int(100.0*epochs_done/total_epochs))
                    iterate = iterate + 1                
                history[i] = acc.history['loss'][0]
                self.model.reset_states()    
            print("Plot for set: ", set_names[k])
            plt.plot(range(0,epochs),history)
            plt.title('model loss')
            plt.ylabel('loss')
            plt.xlabel('epoch')
            plt.legend(['train'], loc='upper left')
            plt.show()



            y_pred = self.model.predict(x_test,batch_size=batch_size_c)
            y_pred = (y_pred > 0.5)

            data = {'NoRot_P': y_test.iloc[:,0], 'NoThrust_P': y_test.iloc[:,1],'NoRot_B': y_test.iloc[:,2], 'NoThrust_B': y_test.iloc[:,3],
                    'NoRot_S': y_test.iloc[:,4], 'NoThrust_S': y_test.iloc[:,5],'pred_NoRot_P': y_pred[:,0], 'pred_NoThrust_P': y_pred[:,1],
                    'pred_NoRot_B': y_pred[:,2],'pred_NoThrust_B': y_pred[:,3],'pred_NoRot_Star': y_pred[:,4],'pred_NoThrust_S': y_pred[:,5]}
            results = pd.DataFrame(data = data)
            self.results_total = self.results_total.append(results,ignore_index=True)
        self.model.summary()




if (__name__ == '__main__'):
    random.seed(42)
    df_dictionary = {}

    df_dictionary[0] = pd.read_csv('trainingdata_nullhypothesis.csv', encoding = "ISO-8859-1")
    df_dictionary[1] = pd.read_csv('trainingdata1.csv', encoding = "ISO-8859-1")
    df_dictionary[2] = pd.read_csv('trainingdata2.csv', encoding = "ISO-8859-1")
    df_dictionary[3] = pd.read_csv('trainingdata3.csv', encoding = "ISO-8859-1")
    df_dictionary[4] = pd.read_csv('trainingdata4.csv', encoding = "ISO-8859-1")
    df_dictionary[5] = pd.read_csv('trainingdata5.csv', encoding = "ISO-8859-1")
    df_dictionary[6] = pd.read_csv('trainingdata6.csv', encoding = "ISO-8859-1")

    ann = LSTM()
    ann.model_initialize(df_dictionary)

    final = ann.results_total
    wrong_prediction = 0
    right_prediction = 0
    true_negative = 0
    true_positive = 0
    false_negative = 0 
    false_positive = 0
    total_num_predictions = int(final.shape[0]*(final.shape[1]*0.5))
    for i in range(0,len(final)):
        for k in range(0,int(final.shape[1]/2)):
            if(final.iloc[i,k] != final.iloc[i,k+6]):
                wrong_prediction = wrong_prediction + 1
                if(final.iloc[i,k] == 1 and final.iloc[i][k+6] == 0):
                    false_negative = false_negative + 1
                else: 
                    false_positive = false_positive + 1
            else:
                right_prediction = right_prediction + 1
                if(final.iloc[i,k] == 1 and final.iloc[i][k+6] == 1):
                    true_positive = true_positive + 1
                else: 
                    true_negative = true_negative + 1


    accuracy = right_prediction/total_num_predictions
    print("Accuracy: ", accuracy)
    recall = true_positive/(true_positive+false_negative)
    print("False positives: ", false_positive)
    print("Recall: ", recall)`

Редактировать: я экспериментировал со скоростью обучения оптимизатора (RMSprop) и получил немного странное поведение. Иногда я получаю значение отзыва равное нулю, но с очень высокой точностью, то есть система не помечает одну метку как положительную. Возможно ли, что большее количество эпох приведет к застреванию раствора в локальном оптимуме?

Можно ли перетасовать временные ряды в LSTM с хорошими результатами или это ставит под угрозу весь смысл включения временного измерения в машинное обучение?

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

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