# Cargar datos de octubre-noviembre-diciembre s3 = boto3.client("s3") fecha = datetime.strptime(fecha, "%Y-%m-%d") # Cargar los últimos 45 días del ads ads_nuevo = load_ads(s3, fecha, dias_ads, "indicadores/ads") ads_nuevo.drop_duplicates(subset=["date", "equipo"], inplace=True) ads_nuevo = ads_nuevo.sort_values(by=['date']).reset_index() ads_nuevo.drop(columns=['index'], inplace=True) # Leer el ads viejo filename = "ads_s3.pkl" path_data = "sagemaker_cosmos/" + filename ads_viejo = read_pkl_s3(os.environ["buckettrain"], path_data) # Concatenar con los nuevos ads ads = pd.concat([ads_nuevo, ads_viejo], axis=0) ads.drop_duplicates(subset=["equipo", "date"], inplace=True) ads.to_pickle(filename) s3.upload_file(Filename=f"{filename}", Bucket=os.environ["buckettrain"], Key=path_data) space = "==============================================" space = space + space msg = f"({mine}) La concatenacion de ADS historicos acaba de finalizar" +\ " enviando" + '\n' + f"{filename} a S3 en la ruta {path_data}" texto = space + '\n' + msg + '\n' + space post_message_to_slack(texto)
def train_nn( filename, columns, model, hyperparameters={ "penalization": True, "batch_size": 4096, "epochs": 800, "patience": 70, "min_delta": 400, "optimizer": "adam", "lr_factor": 0.5, "lr_patience": 25, "lr_min": 5E-4, "validation_size": 0.2 }): """ Entrenar con red neuronal en función de las columnas que se le entregan para poder entrenear modularizadamente los distintos modelos Parameters ---------- filename : string nombre del modelo. columns : string DESCRIPTION. model : object arquitectura definida en el main.py de este archivo. Ej: model = Sequential() model.add(Dense(2048, input_dim=X_train.shape[1], activation='relu')) model.add(BatchNormalization()) model.add(Dropout(0.3)) model.add(Dense(1024, activation='relu')) model.add(BatchNormalization()) model.add(Dropout(0.3)) model.add(Dense(1024, activation='relu')) model.add(BatchNormalization()) model.add(Dropout(0.3)) model.add(Dense(1024, activation='relu')) model.add(BatchNormalization()) model.add(Dropout(0.3)) model.add(Dense(512, activation='relu')) model.add(BatchNormalization()) model.add(Dropout(0.3)) model.add(Dense(512, activation='relu')) model.add(BatchNormalization()) model.add(Dense(1, activation='linear')) model.summary() hyperparameters : Dict DESCRIPTION. The default is: hyperparameters = { "penalization": True, "batch_size": 4096, "epochs": 800, "patience": 70, "min_delta": 400, "optimizer": "adam", "lr_factor": 0.5, "lr_patience": 25, "lr_min": 5E-4, "validation_size": 0.2 } """ # hiperpametros para el entrenamiento del modelo # si es True, ejecutará con una función de costos personalizada penalization = hyperparameters["penalization"] # tamaño del lote de entrenamiento batch_size = hyperparameters["penalization"] # épocas de entrenamiento epochs = hyperparameters["penalization"] # paciencia del earlystopping patience = hyperparameters["penalization"] # lo mínimo que tiene que bajar el earlystopping para terminar el train min_delta = hyperparameters["penalization"] # optimizador optimizer = hyperparameters["optimizer"] # factor de división learining rate lr_factor = hyperparameters["lr_factor"] # paciencia del learning rate lr_patience = hyperparameters["lr_patience"] # mínima tasas de aprendizaje que puede llegar a tener lr_min = hyperparameters["lr_min"] # porcentaje de los datos a validación validation_size = hyperparameters["validation_size"] # llamar a s3 s3 = boto3.client("s3") # Nombre del modelo en la nube bucket_train = os.environ["buckettrain"] num_classes = 0 print(filename) # Data eqtiquetada path_labelled = "sagemaker_cosmos/preprocessed_ads_window.pkl" data_oversampling = read_pkl_s3(bucket_train, path_labelled) data_oversampling = data_oversampling[columns].reset_index(drop=True) # Data original path_original = "sagemaker_cosmos/preprocessed_ads.pkl" data_original = read_pkl_s3(bucket_train, path_original) data_original = data_original[columns].reset_index(drop=True) # ADS con la data generada por los snapshots y # la original de final de ciclo ads = pd.concat([data_original, data_oversampling], axis=0) ads.reset_index(drop=True, inplace=True) # features que se utilizan en el entrenamiento features = ads.columns.to_list() X = ads[features] # Separar variable target, de las features y = X[["cantidad"]] y_original = data_original[["cantidad"]] del X["cantidad"], data_original["cantidad"] columns_dataset = X.columns.to_list() # scaler para normalizar los datos scaler = MinMaxScaler(feature_range=(0, 1)) # normalizar X = scaler.fit_transform(X) X_original = scaler.transform(data_original) # guardar el objeto en el bucket de train con key pruebas de entrenamiento scaler_filename = f"{filename}.save" joblib.dump(scaler, scaler_filename) # Dividir los conjuntos de datos X = pd.DataFrame(X, columns=columns_dataset).reset_index(drop=True) X_original = pd.DataFrame(X_original, columns=columns_dataset).reset_index(drop=True) y_original = y_original.reset_index(drop=True) y = y.reset_index(drop=True) # Semilla de alatoredad alpha = 20 # Dividir los conjuntos de datos X_train, X_test, y_train, y_test =\ train_test_split(X, y, test_size=0.1, random_state=alpha) original = pd.concat([y_original, X_original], axis=1) test = pd.concat([y_test, X_test], axis=1) alpha = original.merge(test, how="inner") # Pasar los datos a numpy array X_test = X_test.to_numpy(dtype="float64") y_test = y_test.to_numpy(dtype="float64") X_train = X_train.to_numpy(dtype="float64") y_train = y_train.to_numpy(dtype="float64") # definir el nombre del modelo model_name = f"{filename}" # empezar el proceso de entrenamiento del modelo model.summary() # Agregar las función de costo a keras keras.losses.handler_loss_function = handler_loss_function # Compile optimizer model.compile(loss=handler_loss_function(batch_size, penalization), optimizer=optimizer) keras.callbacks.Callback() stop_condition = keras.callbacks.EarlyStopping(monitor='val_loss', mode='min', patience=patience, verbose=1, min_delta=min_delta, restore_best_weights=True) learning_rate_schedule = ReduceLROnPlateau(monitor="val_loss", factor=lr_factor, patience=lr_patience, verbose=1, mode="auto", cooldown=0, min_lr=lr_min) callbacks = [stop_condition, learning_rate_schedule] # sacar el historial de entrenamiento history = model.fit(X_train, y_train, validation_split=validation_size, batch_size=batch_size, epochs=epochs, shuffle=False, verbose=1, callbacks=callbacks) # Plotear los resultados del entrenamiento plot_historial_entrenamiento(history, model_name, filename) # Guardar el modelo actualmente reentrenado en la otra ruta model.save(f"{filename}.h5") s3.upload_file(Filename=f"{filename}.h5", Bucket=bucket_train, Key=f"sagemaker_cosmos/modelos/{filename}.h5") # Score del modelo entrenado scores = model.evaluate(X_test, y_test, batch_size=batch_size) print('Mean squared error, Test:', scores) # Solo sacar las columnas originales y_test_original = alpha[["cantidad"]].to_numpy() x_test_original = alpha[columns_dataset] # Predicciones en conjunto de testeo y_pred = model.predict(X_test) # Predictions on y_test y_pred_original = model.predict(x_test_original) # Metricas de evaluación mae_acum = abs(y_pred_original - y_test_original) mae = round(mae_acum.mean(), 3) std = round(mae_acum.std(), 3) q95 = round(pd.DataFrame(mae_acum).quantile(0.95)[0], 3) aa, dd = distribucion_errores(y_pred_original, y_test_original) print(f"Los errores por abajo son: {dd} %") print(f"Los errores por arriba son: {aa} %") max_original = max(y_original.max()) print(max_original) fig, ax = plt.subplots(1, figsize=(22, 12)) plt.scatter(y_test, y_pred, color='blue') plt.scatter(y_test_original, y_pred_original, color='green') plt.scatter(y_test_original, y_test_original, color='red') titulo = 'NN oversampling + originales' +\ f'| Data original: {alpha.shape[0]} filas' + '\n' +\ f'MAE: {str(mae)} [lts]' +\ f'--- STD: {str(std)} [lts] --- Q95: {str(q95)} [lts]' + '\n' +\ f'errores por arriba/errores por abajo : {aa}' + '/' + f'{dd}' plt.title(titulo, fontsize=30) plt.xlabel('Cantidades reales de combustible', fontsize=30) plt.ylabel('Predicción NN de combustible', fontsize=30) ax.tick_params(axis='both', which='major', labelsize=22) plt.legend([ "Predicciones oversampling", "Predicciones que estan en el conjunto de test y data original", "Cantidades reales", "" ], fontsize=22, loc="lower right") plt.ylim(0, 4600) plt.xlim(0, 4600) plt.show() # resultados del modelo resultados_name = "resultados_" + filename fig.savefig(f"{resultados_name}.png") s3.upload_file(Filename=f"{resultados_name}.png", Bucket=bucket_train, Key=f"sagemaker_cosmos/resultados/{resultados_name}.png") y_test_original = pd.DataFrame(y_test_original, columns=["Cantidad"]) y_pred_original = pd.DataFrame(y_pred_original, columns=["predicciones"]) mae_acum = pd.DataFrame(mae_acum, columns=["error"]) data = pd.concat([y_test_original, y_pred_original, mae_acum], axis=1) df_count =\ data['error'].value_counts(bins=15).reset_index(drop=False) df_count.columns = ["rango", "frecuencia errores"] df_count['Porcentaje'] =\ df_count['frecuencia errores'] / \ df_count['frecuencia errores'].sum() * 100 print("===========================================================") print("Errores en el conjunto de testeo original:") print("MAE -----> " + str(mae)) print("DEVEST --> " + str(std)) print("QUANTILE 0.95--> " + str(q95)) print("El número de clases utilizado fue:", num_classes) print("Rangos cantidad de puntos en los que los errores sobre 500 lts:") print(df_count) print("===========================================================") # Cargar el modelo actual en productivo path_modelo_actual =\ f"sagemaker_cosmos/productivo/modelos_productivos/{filename}.h5" path_scaler_actual =\ f"sagemaker_cosmos/productivo/scalers_productivos/{filename}.save" # Cargar el scaler del que esta productivo actualmente scaler_productivo = scaler_s3(bucket_train, filename, path_scaler_actual) # Normalizar con los scalers del modelo actual x_test_original = scaler.inverse_transform(x_test_original) x_test = scaler_productivo.transform(x_test_original) # Cargar modelo actual en predictivo modelo_antiguio = modelos_s3(bucket_train, filename, path_modelo_actual) y_pred_antiguo = modelo_antiguio.predict(x_test) # en esta parte deberia leer el archivo csv ruta = 'sagemaker_cosmos/mae_modelos/mae_modelos.pkl' df_mae = read_pkl_s3(bucket_train, ruta) mae_antiguo = df_mae[filename].iloc[0] # Condiciones de deploy if filename == "modelo_global": limite = 250 elif filename == "modelo_gps_loads_specto": limite = 280 elif filename == "modelo_gps_mems_specto": limite = 300 elif filename == "modelo_loads_mems_specto": limite = 300 elif filename == "modelo_gps_loads_mems": limite = 300 elif filename == "modelo_gps_specto": limite = 300 elif filename == "modelo_mems_specto": limite = 300 elif filename == "modelo_loads_mems": limite = 300 elif filename == "modelo_gps_mems": limite = 300 elif filename == "modelo_gps_loads": limite = 350 elif filename == "modelo_gps": limite = 350 elif filename == "modelo_loads": limite = 350 elif filename == "modelo_mems": limite = 350 elif filename == "modelo_specto": limite = 350 if mae >= limite: space = "==============================================" space = space + space msg = f"({mine}) El proceso de re-entrenamiento del {filename} finalizó. " + '\n' +\ f"El modelo {filename} no superó la condición límite de {limite}" + '\n' +\ " litros de error, No habrá deploy de un nuevo modelo"+'\n' +\ f" modelo en actual: {mae_antiguo} litros de error"+'\n' +\ f" modelo recien entrenado: {mae} litros de error" texto = space + '\n' + msg + '\n' + space post_message_to_slack(texto) pass elif mae < limite: # Condiciones de subir o no un modelo if mae >= mae_antiguo: print("==========================================") print(f"Es mejor el modelo antiguo: {filename}") print("==========================================") space = "==============================================" space = space + space msg = f"({mine}) El proceso de re-entrenamiento del {filename} finalizó. " + '\n' +\ f"El mae del modelo anterior fue de: mae = {mae_antiguo}" + '\n' +\ f"El mae del modelo actual es de: mae ={mae}" + '\n' + \ f" El modelo anterior es mejor que el actual, " + \ "no hay cambio de modelo" texto = space + '\n' + msg + '\n' + space post_message_to_slack(texto) elif mae < mae_antiguo: print("==========================================") print(f"Es mejor el modelo nuevo: {filename}") print("==========================================") # Guardar el modelo nuevo en productivo model.save(f"{filename}.h5") s3.upload_file(Filename=f"{filename}.h5", Bucket=bucket_train, Key=path_modelo_actual) # Guardar el scaler en productivo scaler_filename = f"{filename}.save" joblib.dump(scaler, scaler_filename) s3.upload_file(Filename=f"{filename}.save", Bucket=bucket_train, Key=path_scaler_actual) # guardar mae en data frame df_mae.at[0, filename] = mae space = "==============================================" space = space + space msg = f"({mine}) El proceso de re-entrenamiento del {filename} finalizó. " + '\n' +\ f"El mae del modelo anterior fue de: mae = {mae_antiguo}" + '\n' +\ f"El mae del modelo actual es de: mae ={mae}" + '\n' + \ f" El modelo actual es mejor que el anterior, " + \ "se cambia el modelo a producción" + '\n' +\ f" dejandolo en la ruta {path_modelo_actual} " + '\n' +\ f"y el scaler en {path_scaler_actual}" texto = space + '\n' + msg + '\n' + space post_message_to_slack(texto) # subir mae a archivo pkl df_mae.to_pickle('mae_modelos.pkl') s3.upload_file(Filename="mae_modelos.pkl", Bucket=bucket_train, Key=ruta)