Spaces:
Sleeping
Sleeping
Upload 5 files
Browse files- app2.py +92 -0
- requirements.txt +6 -0
- scaler_X_DS.joblib +3 -0
- scaler_y_DS.joblib +3 -0
- scripted_model_DS.pt +3 -0
app2.py
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import streamlit as st
|
| 2 |
+
import numpy as np
|
| 3 |
+
import torch
|
| 4 |
+
import shap
|
| 5 |
+
import matplotlib.pyplot as plt
|
| 6 |
+
import joblib
|
| 7 |
+
import pandas as pd
|
| 8 |
+
# Load scalers and model
|
| 9 |
+
@st.cache_resource
|
| 10 |
+
def load_resources():
|
| 11 |
+
scaler_X = joblib.load("scaler_X_DS.joblib")
|
| 12 |
+
scaler_y = joblib.load("scaler_y_DS.joblib")
|
| 13 |
+
|
| 14 |
+
model = torch.jit.load("scripted_model_DS.pt")
|
| 15 |
+
model.eval()
|
| 16 |
+
|
| 17 |
+
return scaler_X, scaler_y, model
|
| 18 |
+
|
| 19 |
+
# Create a wrapper function for SHAP
|
| 20 |
+
def model_wrapper(X):
|
| 21 |
+
with torch.no_grad():
|
| 22 |
+
X_tensor = torch.tensor(X, dtype=torch.float32)
|
| 23 |
+
output = model(X_tensor).numpy()
|
| 24 |
+
return scaler_y.inverse_transform(output)
|
| 25 |
+
|
| 26 |
+
# Streamlit app
|
| 27 |
+
st.title("Dynamic Stability Predictor")
|
| 28 |
+
|
| 29 |
+
# Load resources
|
| 30 |
+
scaler_X, scaler_y, model = load_resources()
|
| 31 |
+
|
| 32 |
+
# Define feature names and default values
|
| 33 |
+
feature_names = [
|
| 34 |
+
"25", "19", "12.5", "9.5", "4.75", "2.36", "1.18", "0.6", "0.3", "0.15", "0.075", "CA", "FA", "type"
|
| 35 |
+
]
|
| 36 |
+
default_values = [100, 100, 81.593, 68.395, 49.318, 29.283, 17.261, 14.257, 6.041, 3.000, 2.115, 0.600, 0.350, 1.0]
|
| 37 |
+
|
| 38 |
+
# Input features
|
| 39 |
+
st.sidebar.header("Input Features")
|
| 40 |
+
input_features = {}
|
| 41 |
+
for feature, default_value in zip(feature_names, default_values):
|
| 42 |
+
if feature == "type":
|
| 43 |
+
type_option = st.sidebar.selectbox(f"Enter {feature}", options=["1 - Limestone", "2 - Basalt"], index=0)
|
| 44 |
+
input_features[feature] = 1.0 if type_option == "1 - Limestone" else 2.0
|
| 45 |
+
else:
|
| 46 |
+
input_features[feature] = st.sidebar.number_input(f"Enter {feature}", value=default_value)
|
| 47 |
+
|
| 48 |
+
# Create input array
|
| 49 |
+
input_array = np.array([input_features[feature] for feature in feature_names]).reshape(1, -1)
|
| 50 |
+
input_scaled = scaler_X.transform(input_array)
|
| 51 |
+
|
| 52 |
+
# Make prediction
|
| 53 |
+
with torch.no_grad():
|
| 54 |
+
prediction = model(torch.tensor(input_scaled, dtype=torch.float32)).numpy()
|
| 55 |
+
prediction_unscaled = scaler_y.inverse_transform(prediction)
|
| 56 |
+
|
| 57 |
+
st.write(f"Predicted Dynamic Stability: {prediction_unscaled[0][0]:.2f} pass/mm")
|
| 58 |
+
|
| 59 |
+
# SHAP explanation
|
| 60 |
+
if st.button("Explain Prediction"):
|
| 61 |
+
# Generate some random background data for SHAP
|
| 62 |
+
background_data = np.random.randn(100, 14) # 100 samples, 14 features
|
| 63 |
+
background_data_scaled = scaler_X.transform(background_data)
|
| 64 |
+
|
| 65 |
+
explainer = shap.KernelExplainer(model_wrapper, background_data_scaled)
|
| 66 |
+
shap_values = explainer.shap_values(input_scaled)
|
| 67 |
+
|
| 68 |
+
shap_values_single = shap_values[0].flatten()
|
| 69 |
+
expected_value = explainer.expected_value[0]
|
| 70 |
+
|
| 71 |
+
feature_values = [f"{x:.1f}" for x in input_array[0]]
|
| 72 |
+
|
| 73 |
+
explanation = shap.Explanation(
|
| 74 |
+
values=shap_values_single,
|
| 75 |
+
base_values=expected_value,
|
| 76 |
+
data=feature_values,
|
| 77 |
+
feature_names=feature_names
|
| 78 |
+
)
|
| 79 |
+
|
| 80 |
+
fig, ax = plt.subplots(figsize=(10, 6))
|
| 81 |
+
shap.plots.waterfall(explanation, show=False)
|
| 82 |
+
st.pyplot(fig)
|
| 83 |
+
|
| 84 |
+
st.write(f"Base value (unscaled): {([[expected_value]])[0][0]:.2f} pass/mm")
|
| 85 |
+
st.write(f"Output value (unscaled): {prediction_unscaled[0][0]:.2f} pass/mm")
|
| 86 |
+
|
| 87 |
+
st.write("\nFeature contributions (unscaled):")
|
| 88 |
+
feature_contributions = pd.DataFrame({
|
| 89 |
+
'Contribution': shap_values_single
|
| 90 |
+
}, index=feature_names)
|
| 91 |
+
feature_contributions['Contribution'] = feature_contributions['Contribution'].round(4)
|
| 92 |
+
st.table(feature_contributions)
|
requirements.txt
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
streamlit
|
| 2 |
+
numpy
|
| 3 |
+
torch
|
| 4 |
+
shap
|
| 5 |
+
matplotlib
|
| 6 |
+
joblib
|
scaler_X_DS.joblib
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:6835ccf71cbd062cc20230e43eb0166f6a8a7bd2f7cd65fc37e657873e778edb
|
| 3 |
+
size 951
|
scaler_y_DS.joblib
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:1dd90832e71904d2eab0440e1f0ff044fbf6329b098215b024febf47c7596e92
|
| 3 |
+
size 623
|
scripted_model_DS.pt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:fa630b0d18893474bfadbe48873d929fbc464aaa7be2b34d1254e266196ea526
|
| 3 |
+
size 1651715
|