class LSTMClassifier(BaseEstimator, ClassifierMixin):
    def __init__(self, epochs, num_features=features_n):
        self.epochs = epochs
        self.model = Sequential([
            Reshape((1, num_features), batch_input_shape=(1, num_features)),
            LSTM(units=50, stateful=True),
            Dropout(0.4),
            Dense(units=1, activation='sigmoid')
        ])
        self.model.compile(optimizer='adam',
                           loss='binary_crossentropy',
                           metrics=['accuracy'])

    def fit(self, X, y):
        for e in range(self.epochs):
            self.model.fit(X,
                           y,
                           epochs=1,
                           batch_size=1,
                           verbose=1,
                           shuffle=False)
            self.model.reset_states()

    def predict(self, X):
        proba = self.model.predict(X, batch_size=1)
        return (proba > 0.5).astype('int32')
from tensorflow.keras.layers import Dense
from tensorflow.keras.layers import LSTM

model = Sequential()
model.add(LSTM(50, batch_input_shape=(1, 3, 1),
               stateful=True))  #dimensions of every single sample
model.add(Dense(1))
model.compile(loss='mean_squared_error', optimizer='adam')

model.fit(X_train,
          y_train,
          epochs=3000,
          batch_size=1,
          verbose=2,
          shuffle=False)
model.reset_states()

X_test = X_test.reshape(24, 3, 1)
y_test = y_test.reshape(24, 1, 1)
print(X_test.shape, y_test.shape)

#make a one-step forecast
yhat = model.predict(X_test, verbose=2, batch_size=1)
#without batch_size the model only accepts one input at a time
yhat

#invert preprocessing on predicted data
#remove stationary
y_test = y_test.reshape(24, 1)
var1 = y_test_  #original values
var2 = yhat  #gaps
Esempio n. 3
0
class NNmodel():
    def __init__(self,
                 Num_classes=3,
                 learning_rate=0.001,
                 batch_size=32,
                 decay=0,
                 epochs=100,
                 stateful_mode=False,
                 model=None,
                 regression=False,
                 **kwargs):

        self.Num_classes = Num_classes
        self.learning_rate = learning_rate
        self.batch_size = batch_size
        self.decay = decay
        self.epochs = epochs
        self.stateful_mode = stateful_mode
        self.regression = regression
        if model is None:
            self.model = Sequential()
        else:
            self.init_model(model)

    def init_model(self, model):
        # compile the model and init some attr of the object by extracting info from the model
        self.model = model
        self.Num_classes = int(self.model.layers[-1].output_shape[-1])
        if self.Num_classes == 1:
            self.regression = True
        self.model_compile()

    def validate_model_shape(self, x):

        if x.ndim == 2:
            x = np.expand_dims(x, axis=0)

        self._validate_input_shape(x)
        self._validate_output_shape()

    def reset_session(self):
        # try to clear training session to speed up
        session.close()
        k.clear_session()

    def model_compile(self):
        # give model different compile methods
        if self.regression:
            self.model.compile(loss="mean_squared_error",
                               optimizer=optimizers.Adam(lr=self.learning_rate,
                                                         decay=self.decay),
                               metrics=['mae'])
        else:
            if self.Num_classes == 2:
                self.model.compile(
                    loss='binary_crossentropy',
                    optimizer=optimizers.Adam(lr=self.learning_rate,
                                              decay=self.decay),
                    metrics=['accuracy'])
            else:
                self.model.compile(
                    loss='categorical_crossentropy',
                    optimizer=optimizers.Adam(lr=self.learning_rate,
                                              decay=self.decay),
                    metrics=['accuracy'])

    def evaluate(self, data_list):
        '''
        Main evaluation function
        '''
        def _metric_compute(set_key,
                            display_name,
                            data=None,
                            data_generator=None):
            if self.regression:
                self._compute_metric_regression(data, data_generator, set_key,
                                                display_name, metric_dict)
            else:
                self._compute_metric_classification(data, data_generator,
                                                    set_key, display_name,
                                                    metric_dict)

        output_dict = {}
        output_dict['parameters'] = self.model.count_params()

        metric_dict = {}

        for da in data_list:

            # compute for training set
            _metric_compute(**da)

        output_dict['metric'] = metric_dict

        return output_dict

    def _compute_metric_classification(self, data, data_generator, set_key,
                                       display_name, metric_dict):
        '''
        Main evaluation function for classification task
        :return: metrics_tr, metrics_val, metrics_te, where metrics includes accuracy, micro-F1 score, and confusion matrix
        '''

        if self.stateful_mode:
            self.model.reset_states()

        if data:
            X, y = data
            if X is None:
                return
            y_pred = np.argmax(self.model.predict(X,
                                                  batch_size=self.batch_size),
                               axis=-1)

        else:
            data_generator.__reset_index__()
            y_pred = np.argmax(self.model.predict(x=data_generator), axis=-1)
            with h5py.File(data_generator.data, "r") as f:
                y = f["y_{}".format(data_generator.dataset)][:]
            data_generator.on_epoch_end()

        if y.ndim > 1:
            if y.shape[1] > 1:
                # y has been one hot encoded, decode it
                y = np.argmax(y, axis=-1)
            else:
                y = np.squeeze(y)

        accuracy = accuracy_score(y, y_pred)
        f1 = f1_score(y, y_pred, average='weighted')
        cm = self._compute_confusion_matrix(y, y_pred)

        metric_key = ['accuracy', 'f1_score', 'confusion_matrix']

        metric = {}
        metric["display_name"] = display_name
        metric[metric_key[0]] = accuracy
        metric[metric_key[1]] = f1
        metric[metric_key[2]] = cm.tolist()

        metric_dict[set_key] = metric

    def _compute_confusion_matrix(self, y, y_pred):
        # compute the confusion matrix by hand
        cm = np.zeros((self.Num_classes, self.Num_classes))
        for i in range(len(y)):
            cm[int(y[i]), int(y_pred[i])] += 1
        return cm

    def _compute_metric_regression(self, data, data_generator, set_key,
                                   display_name, metric_dict):
        '''
        Main evaluation function for classification task
        :return: metrics_tr, metrics_val, metrics_te, where metrics includes accuracy, micro-F1 score, and confusion matrix
        '''

        if self.stateful_mode:
            self.model.reset_states()

        if data:
            X, y = data
            y_pred = np.argmax(self.model.predict(X,
                                                  batch_size=self.batch_size),
                               axis=-1)

        else:
            data_generator.__reset_index__()
            y_pred = np.argmax(self.model.predict(x=data_generator), axis=-1)
            with h5py.File(data_generator.data, "r") as f:
                y = f["y_{}".format(data_generator.dataset)][:]
            data_generator.on_epoch_end()

        metric_key = [
            'mean_squared_error', 'mean_abs_error', 'variance', 'r2_score'
        ]

        mse = mean_squared_error(y, y_pred)
        mae = mean_absolute_error(y, y_pred)
        evs = explained_variance_score(y, y_pred)
        r2 = r2_score(y, y_pred)

        metric = {}
        metric["display_name"] = display_name
        metric[metric_key[0]] = mse
        metric[metric_key[1]] = mae
        metric[metric_key[2]] = evs
        metric[metric_key[3]] = r2

        metric_dict[set_key] = metric

    def predict(self, x):
        '''
        :param x: a numpy testing array
        :return: a numpy array of probability in shape [m, n], m: the number of testing samples; n: the number of classes
        '''

        return self.model.predict(x, batch_size=self.batch.size)

    def predict_class(self, x):
        '''
        :param x: a numpy testing array
        :return: a numpy array of labels in shape [m, 1], m is the number of testing samples
        '''

        return self.model.predict_classes(x, batch_size=self.batch.size)

    def get_config(self):
        '''
        :return: summary of the model
        '''

        return self.model.summary()

    def initialize(self):
        '''
        re-initialize a trained model

        :param model: given a model
        :return: a new model which has replaced the original CuDNNLSTM with LSTM
        '''
        session = K.get_session()

        new_model = Sequential()

        for i in range(len(self.model.layers)):
            if not self.model.layers[i].get_config()['name'].find(
                    'batch_normalization') != -1:
                for v in self.model.layers[i].__dict__:
                    v_arg = getattr(self.model.layers[i], v)
                    if hasattr(v_arg, 'initializer'):
                        initializer_method = getattr(v_arg, 'initializer')
                        initializer_method.run(session=session)
                        print('reinitializing layer {}.{}'.format(
                            self.model.layers[i].name, v))

        print(new_model.summary())

        new_model.compile(loss=self.model.loss, optimizer=self.model.optimizer)

        return new_model
def train(epochs: int):
    # loading dataset
    df = pd.read_csv('data/trans_per_month.csv', index_col='customer_id')

    # calculating product frequency  per months
    X = []
    y = []
    for i in range(len(df.columns) - 24):
        start = datetime.date(2017, 1, 1) + relativedelta(months=i)
        end = start + relativedelta(months=24)
        new_x, new_y = product_frequency_between(df, start, end)
        X.append(new_x)
        y.append(new_y)

    X = np.concatenate(X)
    y = np.concatenate(y)

    # normalizing data
    x_scaler = MinMaxScaler()
    y_scaler = MinMaxScaler()
    X = x_scaler.fit_transform(X)
    y = y_scaler.fit_transform(y.reshape(-1, 1))[:, 0]

    # saving scalers
    joblib.dump(x_scaler, 'models/serialized/x_scaler.mod')
    joblib.dump(y_scaler, 'models/serialized/y_scaler.mod')

    # spliting data
    X_train, X_test, y_train, y_test = train_test_split(X,
                                                        y,
                                                        test_size=0.2,
                                                        random_state=41)

    # reshaping for lstm
    X_train = X_train.reshape(X_train.shape[0], X_train.shape[1], 1)
    X_test = X_test.reshape(X_test.shape[0], X_test.shape[1], 1)

    # create model
    model = Sequential()
    model.add(
        LSTM(16,
             input_shape=(X_train.shape[1], X_train.shape[2]),
             return_sequences=True))
    model.add(LSTM(8, input_shape=(X_train.shape[1], X_train.shape[2])))
    model.add(Dense(1, activation='relu'))

    model.compile(loss='mean_squared_error', optimizer='adam')
    model.summary()

    # training model
    history = model.fit(X_train,
                        y_train,
                        validation_data=(X_test, y_test),
                        epochs=epochs,
                        verbose=1)

    # saveing model
    model.save('models/serialized/lstm_model')

    # predicting data
    trainPredict = model.predict(X_train)
    model.reset_states()
    testPredict = model.predict(X_test)

    # invert predictions
    trainPredict = y_scaler.inverse_transform(trainPredict)
    trainY = y_scaler.inverse_transform([y_train])
    testPredict = y_scaler.inverse_transform(testPredict)
    testY = y_scaler.inverse_transform([y_test])

    # calculate root mean squared error
    trainScore = math.sqrt(mean_squared_error(trainY[0], trainPredict[:, 0]))
    typer.secho(f'🍻 Train Score: {trainScore:.2f} RMSE',
                fg=typer.colors.BRIGHT_GREEN)
    testScore = math.sqrt(mean_squared_error(testY[0], testPredict[:, 0]))
    typer.secho(f'🍻 Test Score: {testScore:.2f} RMSE',
                fg=typer.colors.BRIGHT_GREEN)

    # ploting
    plt.plot(history.history['loss'], label='train')
    plt.plot(history.history['val_loss'], label='validation')
    plt.title(f'Model loss with {epochs} epoch')
    plt.legend()
    plt.show()