|
|
|
|
|
|
|
|
import os |
|
|
import joblib |
|
|
import gradio as gr |
|
|
import matplotlib.pyplot as plt |
|
|
import numpy as np |
|
|
import pandas as pd |
|
|
import shap |
|
|
from sklearn.pipeline import Pipeline |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
MODEL_FILE = "machine_failure_prediction_model.joblib" |
|
|
|
|
|
|
|
|
|
|
|
try: |
|
|
loaded_model = joblib.load(MODEL_FILE) |
|
|
print(f"Successfully loaded model from {MODEL_FILE}") |
|
|
except FileNotFoundError: |
|
|
print(f"Error: Model file not found at {MODEL_FILE}. Make sure the file is uploaded to the repository.") |
|
|
|
|
|
loaded_model = None |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def predict_failure(Type, air_temperature, process_temperature, rotational_speed, torque, tool_wear): |
|
|
"""Predicts machine failure and calculates SHAP values using the loaded model.""" |
|
|
if loaded_model is None: |
|
|
return "Error: Model not loaded.", None |
|
|
|
|
|
input_data = pd.DataFrame({ |
|
|
'Type': [Type], 'Air temperature [K]': [air_temperature], |
|
|
'Process temperature [K]': [process_temperature], 'Rotational speed [rpm]': [rotational_speed], |
|
|
'Torque [Nm]': [torque], 'Tool wear [min]': [tool_wear] |
|
|
}) |
|
|
|
|
|
preprocessor = loaded_model.named_steps['preprocessor'] |
|
|
classifier = loaded_model.named_steps['classifier'] |
|
|
input_processed = preprocessor.transform(input_data) |
|
|
probability = classifier.predict_proba(input_processed)[:, 1] |
|
|
|
|
|
explainer = shap.TreeExplainer(classifier) |
|
|
shap_values = explainer.shap_values(input_processed) |
|
|
feature_names = preprocessor.get_feature_names_out() |
|
|
|
|
|
|
|
|
shap_val_failure = shap_values[1][0] |
|
|
base_val_failure = explainer.expected_value[1] |
|
|
|
|
|
return probability[0], shap_val_failure, feature_names, base_val_failure |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def generate_shap_plot(shap_values, feature_names, base_value): |
|
|
"""Generates a SHAP waterfall plot for the Gradio interface.""" |
|
|
plt.close('all') |
|
|
explanation = shap.Explanation( |
|
|
values=shap_values, base_values=base_value, feature_names=feature_names |
|
|
) |
|
|
fig, _ = plt.subplots() |
|
|
shap.waterfall_plot(explanation, max_display=10, show=False) |
|
|
plt.tight_layout() |
|
|
return fig |
|
|
|
|
|
def predict_and_generate_plot(Type, air_temperature, process_temperature, rotational_speed, torque, tool_wear): |
|
|
"""Wrapper function that connects the backend prediction to the frontend plot.""" |
|
|
result = predict_failure( |
|
|
Type, air_temperature, process_temperature, rotational_speed, torque, tool_wear |
|
|
) |
|
|
|
|
|
if isinstance(result, tuple): |
|
|
probability, shap_values, feature_names, base_value = result |
|
|
shap_plot = generate_shap_plot(shap_values, feature_names, base_value) |
|
|
return f"{probability:.2%}", shap_plot |
|
|
else: |
|
|
|
|
|
error_message = result |
|
|
empty_plot = plt.figure() |
|
|
plt.text(0.5, 0.5, 'Error: Model could not be loaded.', horizontalalignment='center', verticalalignment='center') |
|
|
return error_message, empty_plot |
|
|
|
|
|
|
|
|
|
|
|
with gr.Blocks(theme=gr.themes.Soft()) as iface_with_shap: |
|
|
gr.Markdown("# Machine Failure Prediction with Live SHAP Analysis") |
|
|
gr.Markdown("Adjust the sliders to see the real-time probability of machine failure and how each feature's value contributes to the prediction.") |
|
|
with gr.Row(): |
|
|
with gr.Column(scale=1): |
|
|
gr.Markdown("### Input Features") |
|
|
type_input = gr.Dropdown(label="Type", choices=['L', 'M', 'H'], value='L') |
|
|
air_temp_input = gr.Slider(minimum=295, maximum=305, value=300, label="Air temperature [K]") |
|
|
proc_temp_input = gr.Slider(minimum=305, maximum=315, value=310, label="Process temperature [K]") |
|
|
rpm_input = gr.Slider(minimum=1000, maximum=3000, value=1500, label="Rotational speed [rpm]") |
|
|
torque_input = gr.Slider(minimum=5, maximum=80, value=40, label="Torque [Nm]") |
|
|
wear_input = gr.Slider(minimum=0, maximum=250, value=100, label="Tool wear [min]") |
|
|
inputs = [type_input, air_temp_input, proc_temp_input, rpm_input, torque_input, wear_input] |
|
|
|
|
|
with gr.Column(scale=2): |
|
|
gr.Markdown("### Prediction Outputs") |
|
|
probability_output = gr.Textbox(label="Probability of Machine Failure") |
|
|
plot_output = gr.Plot(label="Feature Contribution to Failure (SHAP Waterfall Plot)") |
|
|
|
|
|
|
|
|
iface_with_shap.load( |
|
|
fn=predict_and_generate_plot, |
|
|
inputs=inputs, |
|
|
outputs=[probability_output, plot_output] |
|
|
) |
|
|
|
|
|
|
|
|
for input_comp in inputs: |
|
|
input_comp.change( |
|
|
fn=predict_and_generate_plot, |
|
|
inputs=inputs, |
|
|
outputs=[probability_output, plot_output] |
|
|
) |
|
|
|
|
|
|
|
|
if __name__ == "__main__": |
|
|
iface_with_shap.launch() |