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
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()