quantumbit commited on
Commit
3f54158
·
verified ·
1 Parent(s): aa76ac6

Delete app.py

Browse files
Files changed (1) hide show
  1. app.py +0 -232
app.py DELETED
@@ -1,232 +0,0 @@
1
- from flask import Flask, request, jsonify
2
- import numpy as np
3
- import tensorflow as tf
4
- from PIL import Image
5
- import io
6
- import base64
7
- import re
8
- import joblib
9
- import os
10
-
11
- app = Flask(__name__)
12
-
13
- # Ensure the "images" directory exists
14
- IMAGE_DIR = "images"
15
- if not os.path.exists(IMAGE_DIR):
16
- os.makedirs(IMAGE_DIR)
17
-
18
- # Load all models - use absolute paths for Hugging Face
19
- MODEL_DIR = os.path.join(os.getcwd(), "models")
20
- models = {
21
- "cnn": tf.keras.models.load_model(os.path.join(MODEL_DIR, "mnist_cnn_model.h5")),
22
- "svm": joblib.load(os.path.join(MODEL_DIR, "mnist_svm.pkl")),
23
- "logistic": joblib.load(os.path.join(MODEL_DIR, "mnist_logistic_regression.pkl")),
24
- "random_forest": joblib.load(os.path.join(MODEL_DIR, "mnist_random_forest.pkl"))
25
- }
26
-
27
- # [Keep your existing classification_reports, preprocess_image,
28
- # and create_simulated_scores functions exactly as they are]
29
- # Classification reports for each model
30
- classification_reports = {
31
- "cnn": """
32
- precision recall f1-score support
33
- 0 0.99 1.00 0.99 980
34
- 1 1.00 1.00 1.00 1135
35
- 2 0.99 0.99 0.99 1032
36
- 3 0.99 1.00 0.99 1010
37
- 4 1.00 0.99 0.99 982
38
- 5 0.98 0.99 0.99 892
39
- 6 1.00 0.98 0.99 958
40
- 7 0.99 0.99 0.99 1028
41
- 8 1.00 0.99 0.99 974
42
- 9 0.99 0.99 0.99 1009
43
- accuracy 0.99 10000
44
- macro avg 0.99 0.99 0.99 10000
45
- weighted avg 0.99 0.99 0.99 10000
46
- """,
47
- "svm": """
48
- precision recall f1-score support
49
- 0 0.9874 0.9896 0.9885 1343
50
- 1 0.9882 0.9925 0.9903 1600
51
- 2 0.9706 0.9819 0.9762 1380
52
- 3 0.9783 0.9749 0.9766 1433
53
- 4 0.9777 0.9822 0.9800 1295
54
- 5 0.9827 0.9796 0.9811 1273
55
- 6 0.9858 0.9921 0.9889 1396
56
- 7 0.9768 0.9807 0.9788 1503
57
- 8 0.9813 0.9683 0.9748 1357
58
- 9 0.9807 0.9669 0.9738 1420
59
- accuracy 0.9810 14000
60
- macro avg 0.9809 0.9809 0.9809 14000
61
- weighted avg 0.9810 0.9810 0.9810 14000
62
- """,
63
- "random_forest": """
64
- precision recall f1-score support
65
- 0 0.9844 0.9866 0.9855 1343
66
- 1 0.9831 0.9831 0.9831 1600
67
- 2 0.9522 0.9674 0.9597 1380
68
- 3 0.9579 0.9532 0.9556 1433
69
- 4 0.9617 0.9699 0.9658 1295
70
- 5 0.9707 0.9631 0.9669 1273
71
- 6 0.9800 0.9828 0.9814 1396
72
- 7 0.9668 0.9681 0.9674 1503
73
- 8 0.9599 0.9528 0.9564 1357
74
- 9 0.9566 0.9465 0.9515 1420
75
- accuracy 0.9675 14000
76
- macro avg 0.9673 0.9674 0.9673 14000
77
- weighted avg 0.9675 0.9675 0.9675 14000
78
- """,
79
- "logistic": """
80
- precision recall f1-score support
81
- 0 0.9636 0.9650 0.9643 1343
82
- 1 0.9433 0.9675 0.9553 1600
83
- 2 0.9113 0.8935 0.9023 1380
84
- 3 0.9021 0.8939 0.8980 1433
85
- 4 0.9225 0.9290 0.9257 1295
86
- 5 0.8846 0.8790 0.8818 1273
87
- 6 0.9420 0.9534 0.9477 1396
88
- 7 0.9273 0.9421 0.9347 1503
89
- 8 0.8973 0.8696 0.8832 1357
90
- 9 0.9019 0.9000 0.9010 1420
91
- accuracy 0.9204 14000
92
- macro avg 0.9196 0.9193 0.9194 14000
93
- weighted avg 0.9201 0.9204 0.9202 14000
94
- """
95
- }
96
-
97
- # Preprocess image before prediction
98
- def preprocess_image(image, model_type):
99
- image = image.resize((28, 28)).convert('L') # Convert to grayscale
100
- img_array = np.array(image) / 255.0 # Normalize
101
-
102
- if model_type == "cnn":
103
- # CNN expects 4D tensor with channel dimension
104
- return np.expand_dims(np.expand_dims(img_array, axis=0), axis=-1)
105
- else:
106
- # Other models expect flattened 1D array
107
- return img_array.flatten().reshape(1, -1)
108
-
109
- @app.route('/')
110
- def home():
111
- return jsonify({
112
- "message": "MNIST Classifier API",
113
- "available_models": list(models.keys()),
114
- "endpoints": {
115
- "/predict": "POST - Send image and model_type",
116
- "/get_classification_report": "POST - Get model metrics"
117
- }
118
- })
119
-
120
- # [Keep your existing /get_classification_report and /predict routes exactly as they are]
121
- @app.route('/get_classification_report', methods=['POST'])
122
- def get_classification_report():
123
- model_type = request.json['model_type']
124
- if model_type in classification_reports:
125
- return jsonify({
126
- 'report': classification_reports[model_type]
127
- })
128
- return jsonify({'error': 'Model not found'})
129
-
130
- @app.route('/predict', methods=['POST'])
131
- def predict():
132
- if request.method == 'POST':
133
- data = request.json['image']
134
- model_type = request.json['model_type']
135
-
136
- img_data = re.sub('^data:image/png;base64,', '', data)
137
- img = Image.open(io.BytesIO(base64.b64decode(img_data)))
138
-
139
- # Save the image to "images" folder
140
- image_path = os.path.join(IMAGE_DIR, "digit.png")
141
- img.save(image_path)
142
-
143
- # Preprocess image and predict
144
- processed_image = preprocess_image(img, model_type)
145
-
146
- if model_type in models:
147
- model = models[model_type]
148
-
149
- # Model-specific prediction logic
150
- if model_type == "cnn":
151
- # For CNN, use softmax probabilities
152
- prediction = model.predict(processed_image)
153
- predicted_digit = np.argmax(prediction)
154
- confidence_scores = prediction[0].tolist()
155
- score_type = "probability"
156
-
157
- elif model_type == "svm":
158
- # For SVM, use decision function distances
159
- predicted_digit = model.predict(processed_image)[0]
160
-
161
- # Try to get decision function scores
162
- if hasattr(model, "decision_function") and callable(getattr(model, "decision_function")):
163
- try:
164
- # Get raw decision scores
165
- decision_scores = model.decision_function(processed_image)
166
-
167
- # One-vs-One SVMs have a different shape for decision_function output
168
- if len(decision_scores.shape) == 2:
169
- # This is a standard one-vs-rest SVM, shape should be (1, n_classes)
170
- confidence_scores = decision_scores[0].tolist()
171
- else:
172
- # One-vs-One SVM returns pairwise comparisons
173
- # Convert to a simplified score per class (this is an approximation)
174
- confidence_scores = [0] * 10
175
- for i in range(10):
176
- # Count how many times class i wins in pairwise comparisons
177
- confidence_scores[i] = sum(1 for score in decision_scores[0] if score > 0)
178
-
179
- # Normalize scores to positive values for visualization
180
- min_score = min(confidence_scores)
181
- if min_score < 0:
182
- confidence_scores = [score - min_score for score in confidence_scores]
183
-
184
- score_type = "decision_distance"
185
- except (AttributeError, NotImplementedError) as e:
186
- print(f"Error getting decision function: {e}")
187
- confidence_scores = create_simulated_scores(int(predicted_digit))
188
- score_type = "simulated"
189
- else:
190
- # Fallback if decision_function is not available
191
- confidence_scores = create_simulated_scores(int(predicted_digit))
192
- score_type = "simulated"
193
-
194
- else:
195
- # For other models (Random Forest, Logistic Regression)
196
- predicted_digit = model.predict(processed_image)[0]
197
-
198
- # Try to get probability estimates
199
- if hasattr(model, "predict_proba") and callable(getattr(model, "predict_proba")):
200
- try:
201
- confidence_scores = model.predict_proba(processed_image)[0].tolist()
202
- score_type = "probability"
203
- except (AttributeError, NotImplementedError):
204
- confidence_scores = create_simulated_scores(int(predicted_digit))
205
- score_type = "simulated"
206
- else:
207
- confidence_scores = create_simulated_scores(int(predicted_digit))
208
- score_type = "simulated"
209
-
210
- return jsonify({
211
- 'digit': int(predicted_digit),
212
- 'confidence_scores': confidence_scores,
213
- 'score_type': score_type
214
- })
215
-
216
- return jsonify({'error': 'Model not found'})
217
-
218
- def create_simulated_scores(predicted_digit):
219
- """Create simulated confidence scores that sum to 1.0 with highest probability for the predicted digit."""
220
- # Assign base probabilities
221
- scores = [0.01] * 10 # Give each digit a small base probability
222
-
223
- # Calculate remaining probability (should be around 0.9)
224
- remaining = 1.0 - sum(scores)
225
-
226
- # Assign the remaining probability to the predicted digit
227
- scores[predicted_digit] += remaining
228
-
229
- return scores
230
-
231
- if __name__ == '__main__':
232
- app.run(host='0.0.0.0', port=7860) # Hugging Face uses port 7860