SIENTIAPDE-1231
Enhance MLFlow and MLFlowRepository with improved data handling and logging - Refactored MLFlow class to sort data by 'created_at' and drop duplicates for better input preparation. - Updated MLFlowRepository methods to include detailed logging for artifact downloads and model predictions. - Introduced LzmaPayloadCodec for efficient payload compression in the worker, optimizing data handling for large payloads. - Enhanced timestamp handling in treated data to ensure compatibility with model expectations.
This commit is contained in:
@@ -235,6 +235,9 @@ class MLFlowRepository():
|
||||
if not path.exists(output_dir):
|
||||
makedirs(output_dir)
|
||||
|
||||
self.logger.info(
|
||||
f"Downloading artifacts from {run_id} to {output_dir}")
|
||||
|
||||
return self.client.download_artifacts(
|
||||
run_id,
|
||||
artifact_path,
|
||||
@@ -347,18 +350,13 @@ class MLFlowRepository():
|
||||
Raises:
|
||||
ValueError: If model cannot be loaded with any compression method
|
||||
"""
|
||||
code_path = path.join(
|
||||
artifact_path, "code")
|
||||
|
||||
if type == "transformer":
|
||||
code_path = path.join(
|
||||
artifact_path, "transformer_pyfunc", "code")
|
||||
pickle_path = path.join(
|
||||
artifact_path, "transformer_pyfunc", "artifacts", "training_transformer.pkl")
|
||||
pickle_file = "training_transformer.pkl" if type == "transformer" else "stacking_model.pkl"
|
||||
|
||||
elif type == "prediction":
|
||||
code_path = path.join(
|
||||
artifact_path, "stacking_model", "code")
|
||||
pickle_path = path.join(
|
||||
artifact_path, "stacking_model", "artifacts", "stacking_model.pkl")
|
||||
pickle_path = path.join(
|
||||
artifact_path, "artifacts", pickle_file)
|
||||
|
||||
if code_path not in sys_path:
|
||||
sys_path.insert(0, code_path)
|
||||
@@ -468,6 +466,9 @@ class MLFlowRepository():
|
||||
f"{message}")
|
||||
|
||||
elif index_type == datetime or index_type == pd.Timestamp:
|
||||
if data.index.tz is None:
|
||||
data.index = data.index.tz_localize('UTC')
|
||||
|
||||
data.index = data.index.strftime(DATETIME_FORMAT_WITH_TZ)
|
||||
else:
|
||||
raise ValueError(
|
||||
@@ -690,6 +691,9 @@ class MLFlowRepository():
|
||||
self.logger.custom_debug(
|
||||
f"Fitting transformation model with training data (shape: {data.shape})", metadata)
|
||||
|
||||
data.to_csv(
|
||||
f"tmp/retrain_data_{model_name}.csv", index=True)
|
||||
|
||||
data_model = data_model.fit(data)
|
||||
|
||||
self.logger.custom_debug(
|
||||
@@ -697,6 +701,20 @@ class MLFlowRepository():
|
||||
|
||||
treated_data = data_model.predict(data)
|
||||
|
||||
# Stores current index as timestamp, Courier model expects a timestamp column
|
||||
# with specific format
|
||||
treated_data['timestamp'] = treated_data.index
|
||||
|
||||
# Parses timestamp column to datetime format to align with data
|
||||
treated_data = self.detect_and_parse_datetime_index(
|
||||
treated_data, metadata)
|
||||
|
||||
self.logger.custom_debug(
|
||||
f"Treated data index: {treated_data.index}", metadata)
|
||||
|
||||
treated_data.to_csv(
|
||||
f"tmp/retrain_treated_data_{model_name}.csv", index=True)
|
||||
|
||||
self.logger.custom_debug(
|
||||
f"Transformed data shape: {treated_data.shape}", metadata)
|
||||
|
||||
@@ -708,12 +726,24 @@ class MLFlowRepository():
|
||||
self.logger.custom_debug(
|
||||
f"Using provided target variable: {target_name}", metadata)
|
||||
|
||||
# Check if treated_data contains target variable
|
||||
if target_name not in treated_data.columns:
|
||||
self.logger.custom_debug(
|
||||
f"Target variable {target_name} not found in treated data, aligning data with treated data indexes", metadata)
|
||||
# Aligns data with treated data indexes to get target variable
|
||||
aligned_data = data.loc[treated_data.index]
|
||||
else:
|
||||
# Uses target variable from treated data
|
||||
self.logger.custom_debug(
|
||||
f"Target variable {target_name} found in treated data, using it", metadata)
|
||||
aligned_data = treated_data
|
||||
|
||||
if fit_config.get('y_type', 'series').lower() == 'series':
|
||||
y = data[target_name]
|
||||
y = aligned_data[target_name]
|
||||
self.logger.custom_debug(
|
||||
f"Extracting target as series, shape: {y.shape}", metadata)
|
||||
else:
|
||||
y = data[[target_name]]
|
||||
y = aligned_data[[target_name]]
|
||||
self.logger.custom_debug(
|
||||
f"Extracting target as dataframe, shape: {y.shape}", metadata)
|
||||
|
||||
@@ -726,22 +756,25 @@ class MLFlowRepository():
|
||||
self.logger.custom_debug(
|
||||
f"Combined data shape for prediction model fit: {treated_data.shape}", metadata)
|
||||
|
||||
treated_data.to_csv(
|
||||
f"tmp/retrain_treated_data_combined_{model_name}.csv", index=True)
|
||||
|
||||
prediction_model = prediction_model.fit(treated_data)
|
||||
self.logger.custom_debug(
|
||||
"Prediction model fitted with combined data", metadata)
|
||||
else:
|
||||
# Keep data separated
|
||||
fit_order = fit_config.get('split_fit_first', 'x').lower()
|
||||
|
||||
y.to_csv(
|
||||
f"tmp/retrain_y_{model_name}.csv", index=True)
|
||||
|
||||
self.logger.custom_debug(
|
||||
f"Fitting prediction model with separated data, order: {fit_order}", metadata)
|
||||
f"Fitting prediction model with separated data, first arg: {fit_order}", metadata)
|
||||
if fit_order == 'x':
|
||||
prediction_model = prediction_model.fit(treated_data, y)
|
||||
self.logger.custom_debug(
|
||||
"Prediction model fitted with X, y order", metadata)
|
||||
else:
|
||||
prediction_model = prediction_model.fit(y, treated_data)
|
||||
self.logger.custom_debug(
|
||||
"Prediction model fitted with y, X order", metadata)
|
||||
|
||||
experiment = self.get_experiment_by_run_id(latest_production_id)
|
||||
mlflow.set_experiment(experiment)
|
||||
@@ -1012,30 +1045,32 @@ class MLFlowRepository():
|
||||
data.to_csv(
|
||||
f"tmp/treated_data_{model_name}.csv", index=True)
|
||||
|
||||
data = self.get_cached_predict(
|
||||
predict_data = self.get_cached_predict(
|
||||
model_name, data, model_retention, flavor)
|
||||
|
||||
end_time = datetime.now()
|
||||
|
||||
if isinstance(data, pd.DataFrame):
|
||||
if isinstance(predict_data, pd.DataFrame):
|
||||
self.logger.custom_debug(
|
||||
f"Data received from model prediction: {data.head(5).to_csv()}", metadata)
|
||||
|
||||
data.to_csv(
|
||||
predict_data.to_csv(
|
||||
f"tmp/predicted_data_{model_name}.csv", index=True)
|
||||
data.columns = ['prediction']
|
||||
|
||||
else:
|
||||
data = pd.DataFrame(data, columns=['prediction'])
|
||||
data.to_csv(
|
||||
predict_data = pd.DataFrame(
|
||||
predict_data, columns=['prediction'])
|
||||
predict_data.to_csv(
|
||||
f"tmp/predicted_data_{model_name}.csv", index=True)
|
||||
|
||||
data.index = input_index
|
||||
data['response_time'] = (end_time - start_time).total_seconds()
|
||||
predict_data.index = input_index
|
||||
predict_data['response_time'] = (
|
||||
end_time - start_time).total_seconds()
|
||||
|
||||
return {
|
||||
'success': True,
|
||||
'content': data.to_dict()
|
||||
'content': predict_data.to_dict()
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
|
||||
Reference in New Issue
Block a user