xxnithicxx commited on
Commit
89a46dd
·
1 Parent(s): 28d6f49

Add HuggingFace Space files: app.py, README.md with metadata, requirements.txt, and .gitignore

Browse files
Files changed (4) hide show
  1. .gitignore +62 -0
  2. README.md +75 -6
  3. app.py +415 -0
  4. requirements.txt +11 -0
.gitignore ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+ .Python
7
+ build/
8
+ develop-eggs/
9
+ dist/
10
+ downloads/
11
+ eggs/
12
+ .eggs/
13
+ lib/
14
+ lib64/
15
+ parts/
16
+ sdist/
17
+ var/
18
+ wheels/
19
+ *.egg-info/
20
+ .installed.cfg
21
+ *.egg
22
+
23
+ # Virtual Environment
24
+ venv/
25
+ env/
26
+ ENV/
27
+ .venv
28
+
29
+ # Jupyter Notebook
30
+ .ipynb_checkpoints
31
+ *.ipynb
32
+
33
+ # Data directories
34
+ data/
35
+ *.pth
36
+ *.pt
37
+ *.h5
38
+ *.pkl
39
+ *.pickle
40
+
41
+ # IDE
42
+ .vscode/
43
+ .idea/
44
+ *.swp
45
+ *.swo
46
+ *~
47
+
48
+ # OS
49
+ .DS_Store
50
+ Thumbs.db
51
+
52
+ # Logs
53
+ *.log
54
+
55
+ # Temporary files
56
+ *.tmp
57
+ *.bak
58
+ *.cache
59
+
60
+ # HuggingFace Space specific
61
+ flagged/
62
+
README.md CHANGED
@@ -1,12 +1,81 @@
1
  ---
2
- title: SHAP DEMO
3
- emoji: 🌖
4
- colorFrom: yellow
5
- colorTo: gray
6
  sdk: gradio
7
- sdk_version: 5.49.1
8
  app_file: app.py
9
  pinned: false
 
10
  ---
11
 
12
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ title: SHAP Explainability Demo
3
+ emoji: 🔍
4
+ colorFrom: blue
5
+ colorTo: purple
6
  sdk: gradio
7
+ sdk_version: 4.0.0
8
  app_file: app.py
9
  pinned: false
10
+ license: mit
11
  ---
12
 
13
+ # SHAP Explainability Demo 🔍
14
+
15
+ An interactive demonstration of SHAP (SHapley Additive exPlanations) algorithm with three different explanation approaches.
16
+
17
+ ## 🎯 Features
18
+
19
+ This demo showcases three powerful SHAP explanation methods:
20
+
21
+ ### 1. 🖼️ Pixel-level Explanations (MNIST Digits)
22
+ - Uses **DeepExplainer** for deep learning models
23
+ - Explains which pixels contribute to digit classification
24
+ - Interactive digit selection (0-9)
25
+ - Real-time visualization with red/blue attribution maps
26
+
27
+ ### 2. 🎨 Image Segmentation Explanations (ImageNet)
28
+ - Uses **Partition Explainer** with image masking
29
+ - Explains image classification with region-based attributions
30
+ - Upload any image and see which regions matter
31
+ - Shows top 4 predicted classes with real names (e.g., "beagle", "golden_retriever")
32
+ - Uses ResNet50 pre-trained on ImageNet
33
+
34
+ ### 3. 📊 Tabular Data Explanations (Adult Income)
35
+ - Uses **TreeExplainer** for tree-based models
36
+ - Explains income prediction with feature attributions
37
+ - Waterfall plots showing feature contributions
38
+ - Based on Adult Income dataset with Random Forest classifier
39
+
40
+ ## 🚀 How to Use
41
+
42
+ ### Tab 1: Pixel-level (MNIST)
43
+ 1. Use the slider to select a digit index (0-99)
44
+ 2. Click "Generate Explanation"
45
+ 3. See the original digit and SHAP pixel attributions
46
+
47
+ ### Tab 2: Image Segmentation (ImageNet)
48
+ 1. Upload any image (JPG, PNG)
49
+ 2. Click "Generate Explanation"
50
+ 3. Wait 30-60 seconds (image masking is computationally intensive)
51
+ 4. See SHAP region attributions for top 4 classes
52
+
53
+ ### Tab 3: Tabular Data (Adult Income)
54
+ 1. Use the slider to select a sample (0-99)
55
+ 2. Click "Generate Explanation"
56
+ 3. See the waterfall plot showing feature contributions
57
+
58
+ ## 🛠️ Technologies
59
+
60
+ - **Gradio**: Web interface
61
+ - **SHAP**: Explanation framework
62
+ - **PyTorch**: MNIST model
63
+ - **TensorFlow/Keras**: ResNet50 model
64
+ - **scikit-learn**: Random Forest model
65
+ - **OpenCV**: Image inpainting for masking
66
+
67
+ ## 📚 About SHAP
68
+
69
+ SHAP (SHapley Additive exPlanations) is a game-theoretic approach to explain machine learning model predictions.
70
+
71
+ **Learn more:**
72
+ - [SHAP GitHub](https://github.com/slundberg/shap)
73
+ - [SHAP Paper](https://arxiv.org/abs/1705.07874)
74
+
75
+ ## 📄 License
76
+
77
+ MIT License
78
+
79
+ ---
80
+
81
+ **Built with ❤️ using Gradio and SHAP**
app.py ADDED
@@ -0,0 +1,415 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import shap
3
+ import numpy as np
4
+ import pandas as pd
5
+ import matplotlib.pyplot as plt
6
+ import torch
7
+ import torch.nn as nn
8
+ import torch.nn.functional as F
9
+ from torchvision import datasets, transforms
10
+ from sklearn.ensemble import RandomForestClassifier
11
+ from sklearn.model_selection import train_test_split
12
+ import json
13
+ import io
14
+ from PIL import Image
15
+ import warnings
16
+ warnings.filterwarnings("ignore")
17
+
18
+ # Configure TensorFlow to avoid GPU issues
19
+ import os
20
+ os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3' # Suppress TensorFlow warnings
21
+ os.environ['CUDA_VISIBLE_DEVICES'] = '-1' # Force TensorFlow to use CPU only
22
+
23
+ import tensorflow as tf
24
+ # Disable GPU for TensorFlow
25
+ tf.config.set_visible_devices([], 'GPU')
26
+
27
+ from tensorflow.keras.applications.resnet50 import ResNet50, preprocess_input
28
+
29
+ # Set random seeds for reproducibility
30
+ torch.manual_seed(42)
31
+ np.random.seed(42)
32
+
33
+ # ============================================================================
34
+ # MNIST Model Definition (for Pixel-level SHAP)
35
+ # ============================================================================
36
+ class MNISTNet(nn.Module):
37
+ def __init__(self):
38
+ super(MNISTNet, self).__init__()
39
+ self.conv1 = nn.Conv2d(1, 32, 3, 1)
40
+ self.conv2 = nn.Conv2d(32, 64, 3, 1)
41
+ self.dropout1 = nn.Dropout2d(0.25)
42
+ self.dropout2 = nn.Dropout2d(0.5)
43
+ self.fc1 = nn.Linear(9216, 128)
44
+ self.fc2 = nn.Linear(128, 10)
45
+
46
+ def forward(self, x):
47
+ x = self.conv1(x)
48
+ x = F.relu(x)
49
+ x = self.conv2(x)
50
+ x = F.relu(x)
51
+ x = F.max_pool2d(x, 2)
52
+ x = self.dropout1(x)
53
+ x = torch.flatten(x, 1)
54
+ x = self.fc1(x)
55
+ x = F.relu(x)
56
+ x = self.dropout2(x)
57
+ x = self.fc2(x)
58
+ output = F.softmax(x, dim=1)
59
+ return output
60
+
61
+ # ============================================================================
62
+ # Global Variables and Model Loading
63
+ # ============================================================================
64
+ DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")
65
+
66
+ # Load MNIST data
67
+ transform = transforms.Compose([
68
+ transforms.ToTensor(),
69
+ transforms.Normalize((0.1307,), (0.3081,))
70
+ ])
71
+
72
+ # Initialize models (will be loaded on first use)
73
+ mnist_model = None
74
+ mnist_background = None
75
+ resnet_model = None
76
+ resnet_explainer = None
77
+ tabular_model = None
78
+ tabular_explainer = None
79
+ tabular_data = None
80
+
81
+ # ============================================================================
82
+ # Helper Functions
83
+ # ============================================================================
84
+ def initialize_mnist_model():
85
+ """Initialize MNIST model and background data"""
86
+ global mnist_model, mnist_background
87
+
88
+ if mnist_model is None:
89
+ # Load MNIST test data
90
+ test_dataset = datasets.MNIST('./data', train=False, download=True, transform=transform)
91
+ test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=200, shuffle=False)
92
+
93
+ # Get background and test images
94
+ images, targets = next(iter(test_loader))
95
+ mnist_background = images[:100]
96
+
97
+ # Create and train a simple model
98
+ mnist_model = MNISTNet().to(DEVICE)
99
+ mnist_model.eval()
100
+
101
+ return mnist_model, mnist_background
102
+
103
+ def initialize_resnet_model():
104
+ """Initialize ResNet50 model and explainer"""
105
+ global resnet_model, resnet_explainer
106
+
107
+ if resnet_model is None:
108
+ resnet_model = ResNet50(weights="imagenet")
109
+
110
+ # Load ImageNet class names
111
+ class_names = None
112
+ json_path = "imagenet_class_index.json"
113
+
114
+ # Try to load from file
115
+ if os.path.exists(json_path):
116
+ try:
117
+ with open(json_path) as f:
118
+ class_idx = json.load(f)
119
+ class_names = [class_idx[str(i)][1] for i in range(1000)]
120
+ print(f"✓ Loaded {len(class_names)} ImageNet class names")
121
+ except Exception as e:
122
+ print(f"⚠ Error loading class names: {e}")
123
+
124
+ # If not found, try to download
125
+ if class_names is None:
126
+ print("Downloading ImageNet class names...")
127
+ try:
128
+ import urllib.request
129
+ url = "https://storage.googleapis.com/download.tensorflow.org/data/imagenet_class_index.json"
130
+ urllib.request.urlretrieve(url, json_path)
131
+ with open(json_path) as f:
132
+ class_idx = json.load(f)
133
+ class_names = [class_idx[str(i)][1] for i in range(1000)]
134
+ print(f"✓ Downloaded and loaded {len(class_names)} ImageNet class names")
135
+ except Exception as e:
136
+ print(f"⚠ Could not download class names: {e}")
137
+ print("Using placeholder names...")
138
+ class_names = [f"class_{i}" for i in range(1000)]
139
+
140
+ def f(x):
141
+ tmp = x.copy()
142
+ preprocess_input(tmp)
143
+ return resnet_model(tmp)
144
+
145
+ masker = shap.maskers.Image("inpaint_telea", (224, 224, 3))
146
+ resnet_explainer = shap.Explainer(f, masker, output_names=class_names)
147
+
148
+ return resnet_model, resnet_explainer
149
+
150
+ def initialize_tabular_model():
151
+ """Initialize tabular model and explainer"""
152
+ global tabular_model, tabular_explainer, tabular_data
153
+
154
+ if tabular_model is None:
155
+ # Load adult income dataset (returns DataFrame and Series)
156
+ X, y = shap.datasets.adult()
157
+
158
+ # Convert to pandas DataFrame if it's not already
159
+ if not isinstance(X, pd.DataFrame):
160
+ X = pd.DataFrame(X)
161
+ if not isinstance(y, pd.Series):
162
+ y = pd.Series(y)
163
+
164
+ # Keep as DataFrame after split
165
+ X_train, X_test, y_train, y_test = train_test_split(
166
+ X, y, test_size=0.2, random_state=42
167
+ )
168
+
169
+ # Train Random Forest
170
+ tabular_model = RandomForestClassifier(n_estimators=100, random_state=42)
171
+ tabular_model.fit(X_train, y_train)
172
+
173
+ # Create explainer
174
+ tabular_explainer = shap.TreeExplainer(tabular_model)
175
+ tabular_data = (X_test, y_test)
176
+
177
+ return tabular_model, tabular_explainer, tabular_data
178
+
179
+ # ============================================================================
180
+ # SHAP Explanation Functions
181
+ # ============================================================================
182
+ def explain_mnist_digit(digit_index):
183
+ """Generate SHAP explanation for MNIST digit"""
184
+ try:
185
+ model, background = initialize_mnist_model()
186
+
187
+ # Load test data
188
+ test_dataset = datasets.MNIST('./data', train=False, download=True, transform=transform)
189
+ test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=200, shuffle=False)
190
+ images, targets = next(iter(test_loader))
191
+ test_images = images[100:110]
192
+ test_targets = targets[100:110].numpy()
193
+
194
+ # Select image
195
+ idx = min(digit_index, len(test_images) - 1)
196
+ test_image = test_images[[idx]]
197
+
198
+ # Move to same device as model
199
+ test_image = test_image.to(DEVICE)
200
+ background_device = background.to(DEVICE)
201
+
202
+ # Get prediction
203
+ with torch.no_grad():
204
+ output = model(test_image)
205
+ pred = output.max(1, keepdim=True)[1].cpu().numpy()[0][0]
206
+
207
+ # Create explainer and get SHAP values
208
+ explainer = shap.DeepExplainer(model, background_device)
209
+ shap_values = explainer.shap_values(test_image)
210
+
211
+ # Prepare for visualization
212
+ shap_numpy = [np.swapaxes(np.swapaxes(s, 1, -1), 1, 2) for s in shap_values]
213
+ test_numpy = np.swapaxes(np.swapaxes(test_image.cpu().numpy(), 1, -1), 1, 2)
214
+
215
+ # Create plot
216
+ fig = plt.figure(figsize=(15, 3))
217
+ shap.image_plot(shap_numpy, -test_numpy, show=False)
218
+
219
+ # Add title
220
+ plt.suptitle(f'Actual: {test_targets[idx]}, Predicted: {pred}', fontsize=14, y=1.02)
221
+
222
+ # Convert to image
223
+ buf = io.BytesIO()
224
+ plt.savefig(buf, format='png', bbox_inches='tight', dpi=150)
225
+ buf.seek(0)
226
+ img = Image.open(buf)
227
+ plt.close()
228
+
229
+ return img, f"Prediction: {pred} (Actual: {test_targets[idx]})"
230
+
231
+ except Exception as e:
232
+ return None, f"Error: {str(e)}"
233
+
234
+ def explain_imagenet_image(image):
235
+ """Generate SHAP explanation for ImageNet image"""
236
+ try:
237
+ model, explainer = initialize_resnet_model()
238
+
239
+ # Preprocess image
240
+ if image is None:
241
+ return None, "Please upload an image"
242
+
243
+ # Resize and prepare image
244
+ img = Image.fromarray(image).resize((224, 224))
245
+ img_array = np.array(img)
246
+
247
+ if len(img_array.shape) == 2: # Grayscale
248
+ img_array = np.stack([img_array] * 3, axis=-1)
249
+ elif img_array.shape[2] == 4: # RGBA
250
+ img_array = img_array[:, :, :3]
251
+
252
+ img_array = np.clip(img_array, 0, 255).astype(np.uint8)
253
+ img_array = np.expand_dims(img_array, axis=0)
254
+
255
+ # Calculate SHAP values
256
+ shap_values = explainer(img_array, max_evals=100, batch_size=50,
257
+ outputs=shap.Explanation.argsort.flip[:4])
258
+
259
+ # Create plot
260
+ fig = plt.figure(figsize=(15, 5))
261
+ shap.image_plot(shap_values, show=False)
262
+
263
+ # Convert to image
264
+ buf = io.BytesIO()
265
+ plt.savefig(buf, format='png', bbox_inches='tight', dpi=150)
266
+ buf.seek(0)
267
+ result_img = Image.open(buf)
268
+ plt.close()
269
+
270
+ return result_img, "SHAP explanation generated successfully"
271
+
272
+ except Exception as e:
273
+ return None, f"Error: {str(e)}"
274
+
275
+ def explain_tabular_sample(sample_index):
276
+ """Generate SHAP explanation for tabular data sample"""
277
+ try:
278
+ model, explainer, (X_test, y_test) = initialize_tabular_model()
279
+
280
+ # Select sample
281
+ idx = min(sample_index, len(X_test) - 1)
282
+
283
+ # Get first 100 samples for SHAP calculation
284
+ X_subset = X_test.iloc[:100] if hasattr(X_test, 'iloc') else X_test[:100]
285
+ shap_values = explainer(X_subset)
286
+
287
+ # Create waterfall plot
288
+ fig = plt.figure(figsize=(10, 8))
289
+ shap.plots.waterfall(shap_values[idx, :, 1], show=False)
290
+
291
+ # Convert to image
292
+ buf = io.BytesIO()
293
+ plt.savefig(buf, format='png', bbox_inches='tight', dpi=150)
294
+ buf.seek(0)
295
+ img = Image.open(buf)
296
+ plt.close()
297
+
298
+ # Get prediction - handle both DataFrame and numpy array
299
+ if hasattr(X_test, 'iloc'):
300
+ # DataFrame/Series
301
+ X_sample = X_test.iloc[[idx]]
302
+ actual = y_test.iloc[idx]
303
+ else:
304
+ # Numpy array
305
+ X_sample = X_test[idx:idx+1]
306
+ actual = y_test[idx]
307
+
308
+ pred = model.predict(X_sample)[0]
309
+
310
+ return img, f"Prediction: {pred} (Actual: {actual})"
311
+
312
+ except Exception as e:
313
+ import traceback
314
+ error_details = traceback.format_exc()
315
+ return None, f"Error: {str(e)}\n\nDetails:\n{error_details}"
316
+
317
+ # ============================================================================
318
+ # Gradio Interface
319
+ # ============================================================================
320
+ def create_demo():
321
+ """Create Gradio demo interface"""
322
+
323
+ with gr.Blocks(title="SHAP Explanations Demo") as demo:
324
+ gr.Markdown("# SHAP (SHapley Additive exPlanations) Demo")
325
+ gr.Markdown("This demo showcases three different SHAP explanation methods for machine learning models.")
326
+
327
+ with gr.Tabs():
328
+ # Tab 1: MNIST Pixel-level Explanations
329
+ with gr.Tab("1. Pixel-level (MNIST Digits)"):
330
+ gr.Markdown("""
331
+ ### Pixel-level SHAP Explanations
332
+ This method uses **DeepExplainer** to show which pixels contribute to the model's prediction.
333
+ - **Red pixels**: Increase the probability of the predicted class
334
+ - **Blue pixels**: Decrease the probability of the predicted class
335
+ """)
336
+
337
+ with gr.Row():
338
+ with gr.Column():
339
+ mnist_slider = gr.Slider(minimum=0, maximum=9, step=1, value=0,
340
+ label="Select Test Image Index")
341
+ mnist_button = gr.Button("Generate Explanation", variant="primary")
342
+
343
+ with gr.Column():
344
+ mnist_output = gr.Image(label="SHAP Explanation")
345
+ mnist_text = gr.Textbox(label="Prediction Result")
346
+
347
+ mnist_button.click(
348
+ fn=explain_mnist_digit,
349
+ inputs=[mnist_slider],
350
+ outputs=[mnist_output, mnist_text]
351
+ )
352
+
353
+ # Tab 2: ImageNet Image Explanations
354
+ with gr.Tab("2. Image Segmentation (ImageNet)"):
355
+ gr.Markdown("""
356
+ ### Image Segmentation SHAP Explanations
357
+ This method uses **Partition Explainer** with image masking to explain ResNet50 predictions.
358
+ Upload an image to see which regions contribute to the top predicted classes.
359
+ """)
360
+
361
+ with gr.Row():
362
+ with gr.Column():
363
+ image_input = gr.Image(label="Upload Image")
364
+ image_button = gr.Button("Generate Explanation", variant="primary")
365
+
366
+ with gr.Column():
367
+ image_output = gr.Image(label="SHAP Explanation")
368
+ image_text = gr.Textbox(label="Status")
369
+
370
+ image_button.click(
371
+ fn=explain_imagenet_image,
372
+ inputs=[image_input],
373
+ outputs=[image_output, image_text]
374
+ )
375
+
376
+ # Tab 3: Tabular Data Explanations
377
+ with gr.Tab("3. Tabular Data (Adult Income)"):
378
+ gr.Markdown("""
379
+ ### Tabular Data SHAP Explanations
380
+ This method uses **TreeExplainer** to explain Random Forest predictions on the Adult Income dataset.
381
+ The waterfall plot shows how each feature contributes to the prediction.
382
+ """)
383
+
384
+ with gr.Row():
385
+ with gr.Column():
386
+ tabular_slider = gr.Slider(minimum=0, maximum=99, step=1, value=0,
387
+ label="Select Sample Index")
388
+ tabular_button = gr.Button("Generate Explanation", variant="primary")
389
+
390
+ with gr.Column():
391
+ tabular_output = gr.Image(label="SHAP Waterfall Plot")
392
+ tabular_text = gr.Textbox(label="Prediction Result")
393
+
394
+ tabular_button.click(
395
+ fn=explain_tabular_sample,
396
+ inputs=[tabular_slider],
397
+ outputs=[tabular_output, tabular_text]
398
+ )
399
+
400
+ gr.Markdown("""
401
+ ---
402
+ ### About SHAP
403
+ SHAP (SHapley Additive exPlanations) is a unified approach to explain the output of machine learning models.
404
+ It connects game theory with local explanations and provides consistent and locally accurate feature attributions.
405
+ """)
406
+
407
+ return demo
408
+
409
+ # ============================================================================
410
+ # Main
411
+ # ============================================================================
412
+ if __name__ == "__main__":
413
+ demo = create_demo()
414
+ demo.launch(share=False, server_name="0.0.0.0", server_port=7860)
415
+
requirements.txt ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ gradio>=4.0.0
2
+ shap>=0.44.0
3
+ numpy>=1.24.0
4
+ matplotlib>=3.7.0
5
+ torch>=2.0.0
6
+ torchvision>=0.15.0
7
+ scikit-learn>=1.3.0
8
+ tensorflow>=2.13.0
9
+ Pillow>=10.0.0
10
+ pandas>=2.0.0
11
+ opencv-python