Fatimasane26 commited on
Commit
73de08b
·
verified ·
1 Parent(s): 425a442

Upload 3 files

Browse files
Files changed (3) hide show
  1. Dockerfile +16 -0
  2. README_UPLOAD.md +14 -0
  3. app.py +216 -0
Dockerfile ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.10-slim
2
+
3
+ ENV PYTHONDONTWRITEBYTECODE=1
4
+ ENV PYTHONUNBUFFERED=1
5
+ ENV PIP_NO_CACHE_DIR=1
6
+
7
+ WORKDIR /app
8
+
9
+ COPY requirements.txt .
10
+ RUN pip install --upgrade pip && pip install -r requirements.txt
11
+
12
+ COPY . .
13
+
14
+ EXPOSE 7860
15
+
16
+ CMD ["python", "app.py"]
README_UPLOAD.md ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Upload these files to your Hugging Face Docker Space root:
2
+
3
+ 1) app.py
4
+ 2) requirements.txt
5
+ 3) Dockerfile
6
+ 4) fatima_model.pth
7
+ 5) fatima_model.keras
8
+ 6) fatima_meta.json (optional but recommended)
9
+
10
+ Notes:
11
+ - If your model filenames differ, update PT_MODEL_PATH / TF_MODEL_PATH in app.py.
12
+ - If you do not have fatima_meta.json, the app uses default class names and ImageNet normalization.
13
+ - For Docker Space, keep app.py launch as:
14
+ demo.launch(server_name="0.0.0.0", server_port=7860)
app.py ADDED
@@ -0,0 +1,216 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import os
3
+
4
+ import gradio as gr
5
+ import numpy as np
6
+ import tensorflow as tf
7
+ import torch
8
+ import torch.nn as nn
9
+ from PIL import Image
10
+ from torchvision import transforms
11
+
12
+
13
+ # -----------------------------
14
+ # Config
15
+ # -----------------------------
16
+ PT_MODEL_PATH = "fatima_model.pth"
17
+ TF_MODEL_PATH = "fatima_model.keras"
18
+ META_PATH = "fatima_meta.json"
19
+
20
+ DEFAULT_CLASS_NAMES = ["buildings", "forest", "glacier", "mountain", "sea", "street"]
21
+ DEFAULT_IMAGE_SIZE = 150
22
+ DEFAULT_MEAN = [0.485, 0.456, 0.406]
23
+ DEFAULT_STD = [0.229, 0.224, 0.225]
24
+
25
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
26
+
27
+
28
+ def load_meta():
29
+ if os.path.exists(META_PATH):
30
+ with open(META_PATH, "r", encoding="utf-8") as f:
31
+ meta = json.load(f)
32
+ class_names = meta.get("class_names", DEFAULT_CLASS_NAMES)
33
+ image_size = int(meta.get("image_size", DEFAULT_IMAGE_SIZE))
34
+ mean = meta.get("imagenet_mean", DEFAULT_MEAN)
35
+ std = meta.get("imagenet_std", DEFAULT_STD)
36
+ return class_names, image_size, mean, std
37
+ return DEFAULT_CLASS_NAMES, DEFAULT_IMAGE_SIZE, DEFAULT_MEAN, DEFAULT_STD
38
+
39
+
40
+ CLASS_NAMES, IMAGE_SIZE, IMAGENET_MEAN, IMAGENET_STD = load_meta()
41
+
42
+
43
+ class TorchCNN(nn.Module):
44
+ def __init__(self, num_classes=6):
45
+ super().__init__()
46
+ self.features = nn.Sequential(
47
+ nn.Conv2d(3, 32, 3, padding=1),
48
+ nn.BatchNorm2d(32),
49
+ nn.ReLU(),
50
+ nn.MaxPool2d(2),
51
+ nn.Conv2d(32, 64, 3, padding=1),
52
+ nn.BatchNorm2d(64),
53
+ nn.ReLU(),
54
+ nn.MaxPool2d(2),
55
+ nn.Conv2d(64, 128, 3, padding=1),
56
+ nn.BatchNorm2d(128),
57
+ nn.ReLU(),
58
+ nn.MaxPool2d(2),
59
+ )
60
+ self.classifier = nn.Sequential(
61
+ nn.Flatten(),
62
+ nn.Linear(128 * 18 * 18, 256),
63
+ nn.ReLU(),
64
+ nn.Dropout(0.4),
65
+ nn.Linear(256, num_classes),
66
+ )
67
+
68
+ def forward(self, x):
69
+ return self.classifier(self.features(x))
70
+
71
+
72
+ def load_pytorch_model():
73
+ ckpt = torch.load(PT_MODEL_PATH, map_location=device)
74
+ class_names = ckpt.get("class_names", CLASS_NAMES)
75
+ image_size = int(ckpt.get("image_size", IMAGE_SIZE))
76
+ model = TorchCNN(num_classes=len(class_names))
77
+ model.load_state_dict(ckpt["model_state"])
78
+ model.to(device).eval()
79
+ return model, class_names, image_size
80
+
81
+
82
+ def preprocess_pytorch(image: Image.Image, image_size: int):
83
+ tfm = transforms.Compose(
84
+ [
85
+ transforms.Resize((image_size, image_size)),
86
+ transforms.ToTensor(),
87
+ transforms.Normalize(mean=IMAGENET_MEAN, std=IMAGENET_STD),
88
+ ]
89
+ )
90
+ x = tfm(image.convert("RGB")).unsqueeze(0)
91
+ return x.to(device)
92
+
93
+
94
+ def load_tensorflow_model():
95
+ return tf.keras.models.load_model(TF_MODEL_PATH)
96
+
97
+
98
+ def preprocess_tensorflow(image: Image.Image, image_size: int):
99
+ image = image.convert("RGB").resize((image_size, image_size))
100
+ x = np.asarray(image, dtype=np.float32) / 255.0
101
+ mean = np.array(IMAGENET_MEAN, dtype=np.float32)
102
+ std = np.array(IMAGENET_STD, dtype=np.float32)
103
+ x = (x - mean) / std
104
+ return np.expand_dims(x, axis=0)
105
+
106
+
107
+ pt_model = None
108
+ pt_class_names = None
109
+ pt_image_size = None
110
+ tf_model = None
111
+
112
+
113
+ def predict(model_choice, image):
114
+ global pt_model, pt_class_names, pt_image_size, tf_model
115
+
116
+ if image is None:
117
+ return "Please upload an image.", "", {}
118
+
119
+ try:
120
+ pil_img = image if isinstance(image, Image.Image) else Image.fromarray(image)
121
+
122
+ if model_choice == "PyTorch":
123
+ if pt_model is None:
124
+ pt_model, pt_class_names, pt_image_size = load_pytorch_model()
125
+
126
+ x = preprocess_pytorch(pil_img, pt_image_size)
127
+ with torch.no_grad():
128
+ logits = pt_model(x)
129
+ probs = torch.softmax(logits, dim=1).cpu().numpy()[0]
130
+ pred_idx = int(np.argmax(probs))
131
+ label = pt_class_names[pred_idx]
132
+ confidence = float(probs[pred_idx])
133
+ details = {pt_class_names[i]: float(probs[i]) for i in range(len(pt_class_names))}
134
+ return f"Prediction: {label}", f"Confidence: {confidence:.2%}", details
135
+
136
+ if tf_model is None:
137
+ tf_model = load_tensorflow_model()
138
+ x = preprocess_tensorflow(pil_img, IMAGE_SIZE)
139
+ probs = tf_model.predict(x, verbose=0)[0]
140
+ pred_idx = int(np.argmax(probs))
141
+ label = CLASS_NAMES[pred_idx]
142
+ confidence = float(probs[pred_idx])
143
+ details = {CLASS_NAMES[i]: float(probs[i]) for i in range(len(CLASS_NAMES))}
144
+ return f"Prediction: {label}", f"Confidence: {confidence:.2%}", details
145
+
146
+ except Exception as exc:
147
+ return f"Inference error: {exc}", "", {}
148
+
149
+
150
+ CUSTOM_CSS = """
151
+ .gradio-container { max-width: 1050px !important; }
152
+ .main-card {
153
+ border-radius: 20px;
154
+ padding: 18px;
155
+ background: linear-gradient(135deg, #0f172a 0%, #1e3a8a 45%, #1d4ed8 100%);
156
+ color: white;
157
+ }
158
+ .main-title { font-size: 30px; font-weight: 800; margin-bottom: 6px; }
159
+ .subtitle { color: #dbeafe; font-size: 14px; }
160
+ .badge {
161
+ display: inline-block;
162
+ padding: 6px 10px;
163
+ margin-right: 8px;
164
+ border-radius: 999px;
165
+ background: rgba(255,255,255,0.18);
166
+ font-size: 12px;
167
+ }
168
+ """
169
+
170
+
171
+ with gr.Blocks(theme=gr.themes.Soft(), css=CUSTOM_CSS, title="Intel Classifier") as demo:
172
+ gr.HTML(
173
+ """
174
+ <div class="main-card">
175
+ <div class="main-title">Intel Image Classification</div>
176
+ <div class="subtitle">Choose a model, upload an image, and get the predicted class.</div>
177
+ <div style="margin-top:10px;">
178
+ <span class="badge">PyTorch + TensorFlow</span>
179
+ <span class="badge">6 Classes</span>
180
+ <span class="badge">Image Size: 150x150</span>
181
+ </div>
182
+ </div>
183
+ """
184
+ )
185
+
186
+ with gr.Row():
187
+ with gr.Column(scale=1):
188
+ model_choice = gr.Dropdown(
189
+ choices=["PyTorch", "TensorFlow"],
190
+ value="PyTorch",
191
+ label="Model",
192
+ )
193
+ image_input = gr.Image(type="pil", label="Upload image")
194
+ with gr.Row():
195
+ predict_btn = gr.Button("Predict", variant="primary")
196
+ clear_btn = gr.Button("Clear")
197
+
198
+ with gr.Column(scale=1):
199
+ pred_text = gr.Textbox(label="Predicted class")
200
+ conf_text = gr.Textbox(label="Confidence")
201
+ probs = gr.Label(label="Class probabilities", num_top_classes=6)
202
+
203
+ predict_btn.click(
204
+ fn=predict,
205
+ inputs=[model_choice, image_input],
206
+ outputs=[pred_text, conf_text, probs],
207
+ )
208
+ clear_btn.click(
209
+ fn=lambda: ("", "", None, None),
210
+ inputs=[],
211
+ outputs=[pred_text, conf_text, probs, image_input],
212
+ )
213
+
214
+
215
+ if __name__ == "__main__":
216
+ demo.launch(server_name="0.0.0.0", server_port=7860)