Spaces:
Sleeping
Sleeping
| # --- imports --- | |
| import os, time, hashlib | |
| import numpy as np | |
| import cv2 | |
| import tensorflow as tf | |
| import matplotlib.pyplot as plt | |
| from PIL import Image | |
| from IPython.display import clear_output, display | |
| from deepface import DeepFace | |
| # --- config --- | |
| IMG_PATH = "data/test_images/5_images_baby_cute_face/5.jpg" | |
| TFLITE_PATH = "models/age_model_single_batch.tflite" | |
| DETECTOR_BACKEND = "opencv" # try "retinaface" for better alignment, slower [page:0] | |
| ALIGN = True | |
| ENFORCE_DETECTION = True | |
| def md5_file(path): | |
| with open(path, "rb") as f: | |
| return hashlib.md5(f.read()).hexdigest() | |
| def softmax(x): | |
| x = x - np.max(x) | |
| e = np.exp(x) | |
| return e / np.sum(e) | |
| def show_inline(title, img_rgb): | |
| # img_rgb: HxWx3 RGB uint8/float | |
| clear_output(wait=True) | |
| plt.figure(figsize=(4, 4)) | |
| plt.title(title) | |
| plt.imshow(np.clip(img_rgb, 0, 255).astype(np.uint8)) | |
| plt.axis("off") | |
| plt.show() | |
| plt.close() | |
| # --- sanity: confirm image really changes between runs --- | |
| print("IMG_PATH:", IMG_PATH) | |
| print("mtime:", os.path.getmtime(IMG_PATH)) | |
| print("md5:", md5_file(IMG_PATH)) | |
| # --- 1) detect/extract face crop with DeepFace --- | |
| faces = DeepFace.extract_faces( | |
| img_path=IMG_PATH, | |
| detector_backend=DETECTOR_BACKEND, | |
| align=ALIGN, | |
| enforce_detection=ENFORCE_DETECTION, | |
| ) | |
| print("faces found:", len(faces)) | |
| face_rgb = faces[0]["face"] # RGB numpy array from DeepFace.extract_faces [page:0] | |
| # display the face crop so you can verify it's correct | |
| show_inline("Extracted face (RGB)", face_rgb) | |
| # --- 2) load TFLite interpreter --- | |
| interpreter = tf.lite.Interpreter(model_path=TFLITE_PATH) # TFLite interpreter API [web:74] | |
| interpreter.allocate_tensors() | |
| inp = interpreter.get_input_details()[0] | |
| out = interpreter.get_output_details()[0] | |
| print("\nINPUT details:", {k: inp.get(k) for k in ["shape", "dtype", "quantization", "quantization_parameters"]}) | |
| print("OUTPUT details:", {k: out.get(k) for k in ["shape", "dtype", "quantization", "quantization_parameters"]}) | |
| # --- 3) preprocess to the model’s expected input --- | |
| h, w = int(inp["shape"][1]), int(inp["shape"][2]) | |
| x = cv2.resize(face_rgb, (w, h), interpolation=cv2.INTER_AREA) | |
| # common float model input: [0,1] | |
| x = x.astype(np.float32) / 255.0 | |
| x = np.expand_dims(x, axis=0) # [1,H,W,3] | |
| # if model is quantized, quantize using scale/zero_point | |
| if inp["dtype"] in (np.uint8, np.int8): | |
| scale, zero_point = inp["quantization"] | |
| if scale == 0: | |
| raise ValueError("Input scale is 0; quantization info looks invalid.") | |
| x = (x / scale + zero_point).round().astype(inp["dtype"]) | |
| interpreter.set_tensor(inp["index"], x) | |
| # --- 4) run inference --- | |
| interpreter.invoke() | |
| y = interpreter.get_tensor(out["index"]) | |
| print("\nraw output shape:", y.shape, "dtype:", y.dtype) | |
| y1 = y.reshape(-1) | |
| print("raw output (first 10):", y1[:10]) | |
| print("raw output sum:", float(np.sum(y1))) | |
| # --- 5) decode output into an age --- | |
| # Case A: 101-bin classifier (ages 0..100). If output isn't normalized, softmax it. | |
| if y1.size == 101: | |
| probs = y1 | |
| if not (0.99 <= probs.sum() <= 1.01): | |
| probs = softmax(probs) | |
| age = float(np.sum(probs * np.arange(101))) | |
| print("\npredicted age (expected value over 0..100 bins):", age) | |
| # Case B: regression scalar output | |
| elif y1.size == 1: | |
| print("\npredicted age (scalar regression):", float(y1[0])) | |
| else: | |
| print("\nUnhandled output size:", y1.size, "— tell me the model’s output meaning and I’ll adapt decoding.") | |