apsora commited on
Commit
f4cd01c
Β·
verified Β·
1 Parent(s): f14f9cd

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +29 -98
app.py CHANGED
@@ -1,38 +1,20 @@
1
- import os, shutil, zipfile, pathlib, traceback, math
2
  import numpy as np
3
  import pandas as pd
4
-
5
- import gradio as gr
6
  from PIL import Image, ImageOps
7
-
8
- from datasets import load_dataset
9
  from huggingface_hub import hf_hub_download
10
-
11
- # AutoGluon (multimodal)
12
  from autogluon.multimodal import MultiModalPredictor
 
13
 
14
- # ---------------- Settings ----------------
15
- TITLE = "πŸ’„ Lipstick Detection (EfficientNet-B0 via AutoGluon)"
16
- DESC = (
17
- "- Upload a face image; the model predicts **Lipstick** vs **No Lipstick**.\n"
18
- "- Left: original; Right: the **preprocessed** 224Γ—224 view used by the model.\n"
19
- "- Teaching demo only."
20
- )
21
-
22
- # =========================
23
- # CONFIG
24
- # =========================
25
  MODEL_REPO_ID = "Iris314/nn_automl_model"
26
  CANDIDATE_FILES = ["best_model.zip", "best_model.pkl"]
27
- DATASET_REPO = "keerthikoganti/lipstick-image-dataset"
28
 
29
- CACHE_DIR = pathlib.Path("hf_cache")
30
- MODEL_DIR = CACHE_DIR / "model"
31
  CACHE_DIR.mkdir(exist_ok=True, parents=True)
32
 
33
- # =========================
34
- # Load trained predictor
35
- # =========================
36
  def load_mm_predictor():
37
  downloaded = None
38
  for fname in CANDIDATE_FILES:
@@ -49,9 +31,8 @@ def load_mm_predictor():
49
  except Exception:
50
  pass
51
  if downloaded is None:
52
- raise FileNotFoundError(f"Could not find any of {CANDIDATE_FILES} in {MODEL_REPO_ID} ")
53
 
54
- # Prepare folder for MultiModalPredictor.load
55
  if MODEL_DIR.exists():
56
  shutil.rmtree(MODEL_DIR)
57
  MODEL_DIR.mkdir(parents=True, exist_ok=True)
@@ -60,98 +41,51 @@ def load_mm_predictor():
60
  with zipfile.ZipFile(downloaded, "r") as zf:
61
  zf.extractall(MODEL_DIR)
62
  kids = [p for p in MODEL_DIR.iterdir()]
63
- load_path = MODEL_DIR
64
- if len(kids) == 1 and kids[0].is_dir():
65
- load_path = kids[0]
66
  else:
67
  load_path = downloaded
68
 
69
  predictor = MultiModalPredictor.load(str(load_path))
70
  return predictor
71
 
72
- try:
73
- PREDICTOR = load_mm_predictor()
74
- except Exception as e:
75
- PREDICTOR = None
76
- print("Failed to load predictor:", e)
77
 
78
- # =========================
79
- # Preprocess (for visualization)
80
- # EfficientNet-B0 typical viz: Resize(shorter side=256) β†’ CenterCrop(224)
81
- # =========================
82
  TARGET_SIZE = 224
83
  RESIZE_SHORT = 256
84
 
85
  def preprocess_for_viz(pil_img: Image.Image) -> Image.Image:
86
  img = pil_img.convert("RGB")
87
- img = ImageOps.exif_transpose(img) # respect orientation EXIF
88
  w, h = img.size
89
- if w <= 0 or h <= 0:
90
- raise ValueError("Invalid image dimensions.")
91
  scale = RESIZE_SHORT / min(w, h)
92
  new_w, new_h = int(round(w * scale)), int(round(h * scale))
93
  img = img.resize((new_w, new_h), Image.BICUBIC)
94
  left = (new_w - TARGET_SIZE) // 2
95
- top = (new_h - TARGET_SIZE) // 2
96
  img = img.crop((left, top, left + TARGET_SIZE, top + TARGET_SIZE))
97
  return img
98
 
99
- # =========================
100
- # File validation
101
- # =========================
102
- ALLOWED_EXT = {".jpg", ".jpeg", ".png"}
103
- MAX_BYTES = 8 * 1024 * 1024 # 8 MB
104
- MAX_SIDE = 4096
105
-
106
- def validate_image(fileobj) -> str:
107
- if fileobj is None:
108
- raise ValueError("Please upload an image.")
109
- # gr.Image with type="filepath" returns a str path in Spaces
110
- path = getattr(fileobj, "name", fileobj)
111
- if not isinstance(path, str):
112
- path = str(path)
113
-
114
- ext = pathlib.Path(path).suffix.lower()
115
- if ext not in ALLOWED_EXT:
116
- raise ValueError("Unsupported file type. Please upload a PNG or JPG/JPEG.")
117
- if os.path.getsize(path) > MAX_BYTES:
118
- raise ValueError("File too large. Please upload an image ≀ 8 MB.")
119
- with Image.open(path) as im:
120
- w, h = im.size
121
- if w > MAX_SIDE or h > MAX_SIDE:
122
- raise ValueError("Image too large (dimensions). Please keep ≀ 4096Γ—4096.")
123
- return path
124
-
125
- # =========================
126
- # Inference (with optional simple TTA)
127
- # =========================
128
  def infer(image_file, threshold=0.5, tta=False):
129
  try:
130
- if PREDICTOR is None:
131
- raise RuntimeError("Model failed to load. Check model artifacts and environment.")
132
-
133
- # 1) Validate & open
134
- path = validate_image(image_file)
135
  orig = Image.open(path).convert("RGB")
136
  vis = preprocess_for_viz(orig.copy())
137
 
138
- # 2) Build test dataframe for predictor
139
  df = pd.DataFrame([{"image": path}])
140
-
141
- # 3) Predict proba for lipstick=1 (binary)
142
  proba_main = PREDICTOR.predict_proba(df)
143
  row = proba_main.iloc[0]
 
144
  p1 = None
145
  for k in [1, "1", "lipstick", "Lipstick", "positive", "True"]:
146
  if k in row.index:
147
- p1 = float(row[k]); break
 
148
  if p1 is None:
149
  if len(row.index) == 2:
150
  p1 = float(max(row.values))
151
  else:
152
  p1 = float(row.values[0])
153
 
154
- # 4) Optional simple TTA: average with horizontally flipped image prediction
155
  if tta:
156
  flipped = orig.transpose(Image.FLIP_LEFT_RIGHT)
157
  flip_tmp = pathlib.Path(path).with_suffix(".flip_tmp.jpg")
@@ -161,14 +95,15 @@ def infer(image_file, threshold=0.5, tta=False):
161
  p1_flip = None
162
  for k in [1, "1", "lipstick", "Lipstick", "positive", "True"]:
163
  if k in row_flip.index:
164
- p1_flip = float(row_flip[k]); break
 
165
  if p1_flip is None:
166
- p1_flip = float(max(row_flip.values)) if len(row_flip.index)==2 else float(row_flip.values[0])
 
 
 
167
  p1 = float((p1 + p1_flip) / 2.0)
168
- try:
169
- os.remove(flip_tmp)
170
- except Exception:
171
- pass
172
 
173
  p1 = float(np.clip(p1, 0.0, 1.0))
174
  p0 = float(1.0 - p1)
@@ -180,9 +115,6 @@ def infer(image_file, threshold=0.5, tta=False):
180
  tb = traceback.format_exc(limit=1)
181
  return None, None, {"error": f"{type(e).__name__}: {e}"}, f"Failed: {type(e).__name__}: {e}\n{tb}"
182
 
183
- # =========================
184
- # Build examples from dataset (if available)
185
- # =========================
186
  def get_examples(n=3):
187
  try:
188
  ds = load_dataset(DATASET_REPO, split="validation")
@@ -211,12 +143,13 @@ def get_examples(n=3):
211
 
212
  EXAMPLES = get_examples(3)
213
 
214
- # =========================
215
- # Gradio UI
216
- # =========================
217
  with gr.Blocks() as demo:
218
- gr.Markdown(f"# {TITLE}")
219
- gr.Markdown(DESC)
 
 
 
 
220
 
221
  with gr.Row():
222
  with gr.Column():
@@ -239,6 +172,4 @@ with gr.Blocks() as demo:
239
  cache_examples=False
240
  )
241
 
242
- # In Spaces, share=True is not required; leaving default.
243
- if __name__ == "__main__":
244
- demo.launch()
 
1
+ import os, zipfile, pathlib, shutil, traceback
2
  import numpy as np
3
  import pandas as pd
 
 
4
  from PIL import Image, ImageOps
5
+ import gradio as gr
 
6
  from huggingface_hub import hf_hub_download
 
 
7
  from autogluon.multimodal import MultiModalPredictor
8
+ from datasets import load_dataset
9
 
 
 
 
 
 
 
 
 
 
 
 
10
  MODEL_REPO_ID = "Iris314/nn_automl_model"
11
  CANDIDATE_FILES = ["best_model.zip", "best_model.pkl"]
12
+ DATASET_REPO = "keerthikoganti/lipstick-image-dataset"
13
 
14
+ CACHE_DIR = pathlib.Path("hf_cache")
15
+ MODEL_DIR = CACHE_DIR / "model"
16
  CACHE_DIR.mkdir(exist_ok=True, parents=True)
17
 
 
 
 
18
  def load_mm_predictor():
19
  downloaded = None
20
  for fname in CANDIDATE_FILES:
 
31
  except Exception:
32
  pass
33
  if downloaded is None:
34
+ raise FileNotFoundError(f"Could not find any of {CANDIDATE_FILES} in {MODEL_REPO_ID}")
35
 
 
36
  if MODEL_DIR.exists():
37
  shutil.rmtree(MODEL_DIR)
38
  MODEL_DIR.mkdir(parents=True, exist_ok=True)
 
41
  with zipfile.ZipFile(downloaded, "r") as zf:
42
  zf.extractall(MODEL_DIR)
43
  kids = [p for p in MODEL_DIR.iterdir()]
44
+ load_path = kids[0] if len(kids) == 1 and kids[0].is_dir() else MODEL_DIR
 
 
45
  else:
46
  load_path = downloaded
47
 
48
  predictor = MultiModalPredictor.load(str(load_path))
49
  return predictor
50
 
51
+ PREDICTOR = load_mm_predictor()
 
 
 
 
52
 
 
 
 
 
53
  TARGET_SIZE = 224
54
  RESIZE_SHORT = 256
55
 
56
  def preprocess_for_viz(pil_img: Image.Image) -> Image.Image:
57
  img = pil_img.convert("RGB")
58
+ img = ImageOps.exif_transpose(img)
59
  w, h = img.size
 
 
60
  scale = RESIZE_SHORT / min(w, h)
61
  new_w, new_h = int(round(w * scale)), int(round(h * scale))
62
  img = img.resize((new_w, new_h), Image.BICUBIC)
63
  left = (new_w - TARGET_SIZE) // 2
64
+ top = (new_h - TARGET_SIZE) // 2
65
  img = img.crop((left, top, left + TARGET_SIZE, top + TARGET_SIZE))
66
  return img
67
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
  def infer(image_file, threshold=0.5, tta=False):
69
  try:
70
+ path = image_file.name if hasattr(image_file, "name") else str(image_file)
 
 
 
 
71
  orig = Image.open(path).convert("RGB")
72
  vis = preprocess_for_viz(orig.copy())
73
 
 
74
  df = pd.DataFrame([{"image": path}])
 
 
75
  proba_main = PREDICTOR.predict_proba(df)
76
  row = proba_main.iloc[0]
77
+
78
  p1 = None
79
  for k in [1, "1", "lipstick", "Lipstick", "positive", "True"]:
80
  if k in row.index:
81
+ p1 = float(row[k])
82
+ break
83
  if p1 is None:
84
  if len(row.index) == 2:
85
  p1 = float(max(row.values))
86
  else:
87
  p1 = float(row.values[0])
88
 
 
89
  if tta:
90
  flipped = orig.transpose(Image.FLIP_LEFT_RIGHT)
91
  flip_tmp = pathlib.Path(path).with_suffix(".flip_tmp.jpg")
 
95
  p1_flip = None
96
  for k in [1, "1", "lipstick", "Lipstick", "positive", "True"]:
97
  if k in row_flip.index:
98
+ p1_flip = float(row_flip[k])
99
+ break
100
  if p1_flip is None:
101
+ if len(row_flip.index) == 2:
102
+ p1_flip = float(max(row_flip.values))
103
+ else:
104
+ p1_flip = float(row_flip.values[0])
105
  p1 = float((p1 + p1_flip) / 2.0)
106
+ os.remove(flip_tmp)
 
 
 
107
 
108
  p1 = float(np.clip(p1, 0.0, 1.0))
109
  p0 = float(1.0 - p1)
 
115
  tb = traceback.format_exc(limit=1)
116
  return None, None, {"error": f"{type(e).__name__}: {e}"}, f"Failed: {type(e).__name__}: {e}\n{tb}"
117
 
 
 
 
118
  def get_examples(n=3):
119
  try:
120
  ds = load_dataset(DATASET_REPO, split="validation")
 
143
 
144
  EXAMPLES = get_examples(3)
145
 
 
 
 
146
  with gr.Blocks() as demo:
147
+ gr.Markdown("# πŸ’„ Lipstick Detection (AutoGluon β€” EfficientNet-B0)")
148
+ gr.Markdown(
149
+ "- Upload a face image; the model predicts **Lipstick** vs **No Lipstick**. \n"
150
+ "- Left: original; Right: the **preprocessed** 224Γ—224 view seen by the model. \n"
151
+ "- This is a **teaching demo**; don’t use for real decisions."
152
+ )
153
 
154
  with gr.Row():
155
  with gr.Column():
 
172
  cache_examples=False
173
  )
174
 
175
+ demo.launch()