Keras:将验证数据与fit_generator结合使用

时间:2019-02-17 18:54:52

标签: keras

在Keras中使用fit_generator时,我将验证集分为多个小批,并且每个小批都会随着训练的进行进行评估。我希望验证数据在每个时期结束时仅使用一次。也就是说,我的代码当前为:

def model_fit_generator(self):
    #This does the actual training of the model

    earlystop = EarlyStopping(monitor='val_acc', patience=5, verbose=2, mode='auto')

    self.__model.fit_generator(generator=self.train_generator, 
            validation_data=self.valid_generator, 
            steps_per_epoch=self.s_per_e, 
            epochs=self.epochs,
            validation_steps = self.v_per_e, 
            shuffle=False, 
            verbose=2,
            callbacks=[earlystop])
    model_filename = '_'.join([str(x) for x in now_list]) + '_model.h5'
    self.__model.save(model_filename)

def model_evaluate(self):
    self.model_fit_generator()
    evaluation = self.__model.evaluate_generator(self.valid_generator, self.v_per_e, verbose=0)
    return evaluation

如何更改此设置,以便在每个时期结束时使用一次验证数据来确定提前停止是否有用?

编辑:响应评论,这是一个完整的MWE,显示验证数据与训练数据同时使用。请注意,此代码将产生错误,但同时也会打印出批号,以表明同时使用了验证和训练集。要运行此代码,您将需要10个CSV数据文件,我可以提供这些数据,但我只想在此代码后立即为您提供输出。

from __future__ import division
from __future__ import print_function

from pandas import concat
from pandas import DataFrame
import sys, keras, GPy, GPyOpt
import numpy as np
import pandas as pd
from keras import backend as K
from keras.models import Model
from keras.metrics import binary_crossentropy
from keras.layers import Dense, Input, LSTM, Lambda
from keras.optimizers import Adam
from keras.callbacks import EarlyStopping

class my_model():

    def __init__(self, n_lags=2, hid_dim_1=5, epochs=2, batch_size=1):
        self.n_lags = n_lags
        self.hid_dim_1 = hid_dim_1
        self.epochs = epochs
        self.batch_size = batch_size
        self.train_generator, self.s_per_e, self.valid_generator, self.v_per_e, self.n_vars = self.read_data()
        self.__model = self.model()

    def read_data(self):

        n_vars = 2
        num_sample_minibatches = 6
        num_valid_minibatches = 4
        sample_IDs = range(1, self.batch_size+num_sample_minibatches)
        valid_IDs = range(num_sample_minibatches+1, max(sample_IDs)+num_valid_minibatches+1)
        params = {'batch_size': self.batch_size, 'n_lags': self.n_lags, 'n_vars': n_vars}
        train_generator = DataGenerator(sample_IDs, **params)
        valid_generator = DataGenerator(valid_IDs, **params)
        s_per_e = int(len(sample_IDs) - self.batch_size + 1) #e.g. if you have 1,2,3,4,5,6 then you can create 4 sequences of length 3 (batch_size)
        v_per_e = int(len(valid_IDs) - self.batch_size + 1)

        return train_generator, s_per_e, valid_generator, v_per_e, n_vars

    def model(self):
        #https://github.com/twairball/keras_lstm_vae/blob/master/lstm_vae/vae.py
        a_input = Input(shape=(self.n_lags, self.n_vars,), name='a_input')
        cond_on_this = Input(shape=(self.n_vars,), name="cond_on_this")
        b_lstm = LSTM(self.hid_dim_1)(a_input)
        outputs = Dense(self.hid_dim_1, activation='sigmoid')(b_lstm)
        my_model1 = Model([a_input, cond_on_this], outputs)
        my_model1.compile(optimizer=Adam(lr=0.001), loss=binary_crossentropy)
        return my_model1

    def my_model_fit_generator(self):
        earlystop = EarlyStopping(monitor='val_acc', patience=5, verbose=2, mode='auto')
        self.__model.fit_generator(generator=self.train_generator,
            validation_data=self.valid_generator,
            steps_per_epoch=self.s_per_e,
            epochs=self.epochs,
            validation_steps = self.v_per_e,
            shuffle=False,
            verbose=2,
            callbacks=[earlystop])

    def my_model_evaluate(self):
        self.my_model_fit_generator()
        evaluation = self.__model.evaluate_generator(self.valid_generator, self.v_per_e, verbose=0)
        return evaluation

class DataGenerator(keras.utils.Sequence):

    'Generates data for Keras'
    def __init__(self, list_IDs, batch_size, n_lags, n_vars, shuffle=False):
        'Initialization'
        self.list_IDs = list_IDs
        self.batch_size = batch_size
        self.n_lags = n_lags
        self.n_vars = n_vars
        self.shuffle = shuffle
        self.on_epoch_end()

    def __len__(self):
        'Denotes the number of batches per epoch'
        batches_per_epoch = int(np.floor(len(self.list_IDs) - self.batch_size + 1))
        return batches_per_epoch

    def __getitem__(self, index):
        'Generate one batch of data'
        #Here's my evidence that the validation minibatches are being used during training!
        print('batch number: ', index+1, 'of: ', int(np.floor(len(self.list_IDs) - self.batch_size + 1)))
        indexes = self.indexes[index:(index+self.batch_size)]

        # Find list of IDs
        list_IDs_temp = [self.list_IDs[k] for k in indexes]

        # Generate data
        data, cond_on_this = self.__data_generation(list_IDs_temp)

        return [np.asarray(data), np.asarray(cond_on_this)], np.asarray(cond_on_this)

    def on_epoch_end(self):
        'Updates indexes after each epoch'
        self.indexes = np.arange(len(self.list_IDs))
        if self.shuffle == True:
            np.random.shuffle(self.indexes)

    #From MachineLearningMastery
    def series_to_supervised(self, data, n_out=1, dropnan=True):
        n_vars = 1 if type(data) is list else data.shape[1]
        df = DataFrame(data)
        cols, names = list(), list()

        #input sequence t-n, ..., t-1
        for i in range(self.n_lags, 0, -1): #for i in 3 to 0 not including 0
            cols.append(df.shift(i))
            names += [('var%d(t-%d)' % (j+1, i)) for j in range (self.n_vars)]

        #forecast sequence t, t+1, ..., t+n
        for i in range(0, n_out):
            cols.append(df.shift(-i))
            if i==0:
                names += [('var%d(t)' % (j+1)) for j in range(self.n_vars)]
            else:
                names += [('var%d(t+%d)' % (j+1, i)) for j in range(self.n_vars)]

        agg = concat(cols, axis=1)
        agg.columns = names
        if dropnan:
            agg.dropna(inplace=True)
        return agg

    def __data_generation(self, list_IDs_temp):
        'Generates data containing batch_size samples'
        data_np_array = np.empty((self.batch_size, self.n_vars), dtype=float)

        for i, ID in enumerate(list_IDs_temp):
            #Read in a data file corresponding to this ID; put it into the numpy array.
            data_file = './pollution_' + str(i) + '.csv'
            df_data = pd.read_csv(data_file, sep=",", header=0)
            df_data.columns = ['date','pollution','dew','temp','press','wnd_dir','wnd_spd','snow','rain']
            df_data_vals = df_data[['pollution', 'temp']] #this is shape (24, 2)
            data_np_array[i,] = np.asarray(df_data_vals)

        data_s2s = np.asarray(self.series_to_supervised(data_np_array))

        data_data = data_s2s[:, :int(self.n_vars*self.n_lags)]
        data_cond = data_s2s[:, int(self.n_vars*self.n_lags):]
        data_data = data_data.reshape((data_data.shape[0], self.n_lags, self.n_vars))

        return data_data, data_cond

def run_my_model(n_lags=2, hid_dim_1=5, epochs=2, batch_size=1):

    _my_model = my_model(n_lags=n_lags, hid_dim_1=hid_dim_1, epochs=epochs, batch_size=batch_size)
    mymodel_evaluation = _my_model.my_model_evaluate()
    return mymodel_evaluation

#Bounds for hyperparameters
bounds = [{'name': 'hid_dim_1', 'type': 'discrete', 'domain': (5, 10)}]

#Bayesian Optimization
def f(x):
    evaluation = run_my_model(hid_dim_1 = int(x[:,0]), epochs = 2, batch_size = 1)
    print("binary crossentropy:\t{0}".format(evaluation[0]))
    print(evaluation)
    return evaluation

#Optimizer instance
opt_mymodel = GPyOpt.methods.BayesianOptimization(f=f, domain=bounds, initial_design_numdata=1)

#Run optimizer
opt_mymodel.run_optimization(max_iter=2)
opt_mymodel.x_opt

相关输出:

Using TensorFlow backend.
Epoch 1/2
batch number:  1 of:  4
batch number:  1 of:  6
batch number:  2 of:  4
batch number:  2 of:  6
batch number:  3 of:  4
batch number:  3 of:  6
batch number:  4batch number:  4 of:   4
of:  6
batch number:  5 of:  6
batch number:  6 of:  6
Traceback (most recent call last):
  ...Error after this...

0 个答案:

没有答案