Spaces:
Sleeping
Retirer ZeroGPU : le Space passe en CPU
Browse filesLe quota GPU journalier par visiteur (2 a 5 min selon le compte) restait
un probleme structurel pour l'usage en classe, meme apres avoir calibre
les durees demandees sur des mesures reelles. Les mesures elles-memes
montraient que le temps d'entrainement sur ce jeu de donnees minuscule
est domine par un overhead fixe (chargement, tiny batches) plutot que
par le calcul GPU : multiplier les parametres du CNN par ~128x n'avait
fait varier le temps par epoque que de ~40%. Le CPU ne devrait donc pas
etre dramatiquement plus lent, et supprime completement le systeme de
quota par utilisateur.
Suppression des decorateurs @spaces.GPU et des fonctions de duree
dynamique associees (devenues inutiles), et de la dependance spaces.
Le changement de materiel du Space (ZeroGPU -> CPU basic) se fait cote
Settings HF, pas dans ce commit.
- app.py +12 -55
- requirements.txt +0 -1
|
@@ -1,7 +1,6 @@
|
|
| 1 |
import json
|
| 2 |
|
| 3 |
import gradio as gr
|
| 4 |
-
import spaces
|
| 5 |
|
| 6 |
from backbone_utils import extract_all_features, get_cached_features
|
| 7 |
from classical_ml_utils import train_classical_model
|
|
@@ -40,27 +39,6 @@ def refresh_gallery_callback(split_name, class_name, max_images):
|
|
| 40 |
# Tab 2 — MLP (baseline)
|
| 41 |
# ---------------------------------------------------------------------------
|
| 42 |
|
| 43 |
-
def mlp_gpu_duration(
|
| 44 |
-
num_layers, hidden_dim, dropout,
|
| 45 |
-
learning_rate, weight_decay, batch_size, epochs,
|
| 46 |
-
model_tag,
|
| 47 |
-
request: gr.Request,
|
| 48 |
-
):
|
| 49 |
-
# Calibré sur deux exécutions réelles :
|
| 50 |
-
# 2 couches, hidden_dim=256, epochs=30 -> 66.6s (2.22 s/époque)
|
| 51 |
-
# 5 couches, hidden_dim=1024, epochs=50 -> 140.8s (2.82 s/époque)
|
| 52 |
-
# Le jeu de données est minuscule (peu de pas par époque) : le temps est
|
| 53 |
-
# dominé par un overhead fixe, hidden_dim ne le fait varier que doucement
|
| 54 |
-
# (x4 sur hidden_dim -> seulement +27% par époque). On plafonne à 180s :
|
| 55 |
-
# nettement sous le quota journalier d'un compte gratuit (300s), pour
|
| 56 |
-
# qu'un seul entraînement au pire réglage ne consomme pas tout le quota
|
| 57 |
-
# du jour d'un·e étudiant·e.
|
| 58 |
-
per_epoch = 2.22 + 0.0008 * max(0, int(hidden_dim) - 256)
|
| 59 |
-
estimated = 15 + per_epoch * int(epochs)
|
| 60 |
-
return min(180, max(45, int(estimated * 1.4)))
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
@spaces.GPU(duration=mlp_gpu_duration)
|
| 64 |
def train_mlp_callback(
|
| 65 |
num_layers, hidden_dim, dropout,
|
| 66 |
learning_rate, weight_decay, batch_size, epochs,
|
|
@@ -100,31 +78,6 @@ def train_mlp_callback(
|
|
| 100 |
# Tab 3 — SimpleCNN
|
| 101 |
# ---------------------------------------------------------------------------
|
| 102 |
|
| 103 |
-
def cnn_gpu_duration(
|
| 104 |
-
num_conv_blocks, base_filters, kernel_size, use_batchnorm,
|
| 105 |
-
dropout, fc_dim,
|
| 106 |
-
learning_rate, weight_decay, batch_size, epochs,
|
| 107 |
-
model_tag,
|
| 108 |
-
request: gr.Request,
|
| 109 |
-
):
|
| 110 |
-
# Calibré sur deux exécutions réelles :
|
| 111 |
-
# 3 blocs, filtres=32, noyau=3, epochs=30 -> 65.3s (2.18 s/époque)
|
| 112 |
-
# 5 blocs, filtres=128, noyau=5, epochs=50 -> 153.9s (3.08 s/époque)
|
| 113 |
-
# Le nombre de paramètres varie de ~130x entre ces deux essais mais le temps
|
| 114 |
-
# par époque seulement de 40% : sur ce jeu de données minuscule, le coût est
|
| 115 |
-
# dominé par un overhead fixe (chargement/augmentation), pas par les FLOPs
|
| 116 |
-
# du réseau — le nombre de paramètres surestimerait donc très largement.
|
| 117 |
-
# On interpole plutôt sur un score d'architecture simple. Plafond 180s :
|
| 118 |
-
# nettement sous le quota journalier d'un compte gratuit (300s).
|
| 119 |
-
score = int(num_conv_blocks) * int(base_filters) * (int(kernel_size) / 3)
|
| 120 |
-
baseline_score, worst_score = 96.0, 1066.7
|
| 121 |
-
frac = max(0.0, min(1.0, (score - baseline_score) / (worst_score - baseline_score)))
|
| 122 |
-
per_epoch = 2.18 + 0.9 * frac
|
| 123 |
-
estimated = 15 + per_epoch * int(epochs)
|
| 124 |
-
return min(180, max(45, int(estimated * 1.4)))
|
| 125 |
-
|
| 126 |
-
|
| 127 |
-
@spaces.GPU(duration=cnn_gpu_duration)
|
| 128 |
def train_cnn_callback(
|
| 129 |
num_conv_blocks, base_filters, kernel_size, use_batchnorm,
|
| 130 |
dropout, fc_dim,
|
|
@@ -168,7 +121,6 @@ def train_cnn_callback(
|
|
| 168 |
# Tab 4 — Backbone + ML classique
|
| 169 |
# ---------------------------------------------------------------------------
|
| 170 |
|
| 171 |
-
@spaces.GPU(duration=60)
|
| 172 |
def extract_features_callback():
|
| 173 |
try:
|
| 174 |
_, class_names, counts = extract_all_features()
|
|
@@ -254,14 +206,13 @@ def get_model_info_callback(model_name, request: gr.Request):
|
|
| 254 |
|
| 255 |
def download_model_callback(model_name, request: gr.Request):
|
| 256 |
if not model_name:
|
| 257 |
-
return
|
| 258 |
try:
|
| 259 |
-
return
|
| 260 |
except FileNotFoundError:
|
| 261 |
-
return
|
| 262 |
|
| 263 |
|
| 264 |
-
@spaces.GPU(duration=120)
|
| 265 |
def evaluate_callback(model_name, request: gr.Request):
|
| 266 |
try:
|
| 267 |
summary, report_df, cm_df, cm_path = evaluate_saved_model(model_name, request.session_hash)
|
|
@@ -270,7 +221,6 @@ def evaluate_callback(model_name, request: gr.Request):
|
|
| 270 |
return {"Erreur": str(e)}, None, None, None
|
| 271 |
|
| 272 |
|
| 273 |
-
@spaces.GPU(duration=60)
|
| 274 |
def predict_callback(model_name, image, request: gr.Request):
|
| 275 |
try:
|
| 276 |
return predict_uploaded_image(model_name, image, request.session_hash)
|
|
@@ -278,7 +228,6 @@ def predict_callback(model_name, image, request: gr.Request):
|
|
| 278 |
return f"Échec :\n{e}", None
|
| 279 |
|
| 280 |
|
| 281 |
-
@spaces.GPU(duration=60)
|
| 282 |
def random_test_callback(model_name, request: gr.Request):
|
| 283 |
try:
|
| 284 |
return test_random_sample(model_name, request.session_hash)
|
|
@@ -600,7 +549,11 @@ with gr.Blocks(title="Classification d'images microscopiques") as demo:
|
|
| 600 |
refresh_btn = gr.Button("Actualiser la liste")
|
| 601 |
load_info_btn = gr.Button("Afficher les informations du modèle")
|
| 602 |
model_info = gr.JSON(label="Métadonnées du modèle")
|
| 603 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 604 |
|
| 605 |
with gr.Column():
|
| 606 |
evaluate_btn = gr.Button("Évaluer sur le jeu de test", variant="primary")
|
|
@@ -711,6 +664,10 @@ with gr.Blocks(title="Classification d'images microscopiques") as demo:
|
|
| 711 |
fn=download_model_callback, inputs=model_selector, outputs=model_download
|
| 712 |
)
|
| 713 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 714 |
evaluate_btn.click(
|
| 715 |
fn=evaluate_callback,
|
| 716 |
inputs=model_selector,
|
|
|
|
| 1 |
import json
|
| 2 |
|
| 3 |
import gradio as gr
|
|
|
|
| 4 |
|
| 5 |
from backbone_utils import extract_all_features, get_cached_features
|
| 6 |
from classical_ml_utils import train_classical_model
|
|
|
|
| 39 |
# Tab 2 — MLP (baseline)
|
| 40 |
# ---------------------------------------------------------------------------
|
| 41 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 42 |
def train_mlp_callback(
|
| 43 |
num_layers, hidden_dim, dropout,
|
| 44 |
learning_rate, weight_decay, batch_size, epochs,
|
|
|
|
| 78 |
# Tab 3 — SimpleCNN
|
| 79 |
# ---------------------------------------------------------------------------
|
| 80 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 81 |
def train_cnn_callback(
|
| 82 |
num_conv_blocks, base_filters, kernel_size, use_batchnorm,
|
| 83 |
dropout, fc_dim,
|
|
|
|
| 121 |
# Tab 4 — Backbone + ML classique
|
| 122 |
# ---------------------------------------------------------------------------
|
| 123 |
|
|
|
|
| 124 |
def extract_features_callback():
|
| 125 |
try:
|
| 126 |
_, class_names, counts = extract_all_features()
|
|
|
|
| 206 |
|
| 207 |
def download_model_callback(model_name, request: gr.Request):
|
| 208 |
if not model_name:
|
| 209 |
+
return None
|
| 210 |
try:
|
| 211 |
+
return saved_model_file_path(model_name, request.session_hash)
|
| 212 |
except FileNotFoundError:
|
| 213 |
+
return None
|
| 214 |
|
| 215 |
|
|
|
|
| 216 |
def evaluate_callback(model_name, request: gr.Request):
|
| 217 |
try:
|
| 218 |
summary, report_df, cm_df, cm_path = evaluate_saved_model(model_name, request.session_hash)
|
|
|
|
| 221 |
return {"Erreur": str(e)}, None, None, None
|
| 222 |
|
| 223 |
|
|
|
|
| 224 |
def predict_callback(model_name, image, request: gr.Request):
|
| 225 |
try:
|
| 226 |
return predict_uploaded_image(model_name, image, request.session_hash)
|
|
|
|
| 228 |
return f"Échec :\n{e}", None
|
| 229 |
|
| 230 |
|
|
|
|
| 231 |
def random_test_callback(model_name, request: gr.Request):
|
| 232 |
try:
|
| 233 |
return test_random_sample(model_name, request.session_hash)
|
|
|
|
| 549 |
refresh_btn = gr.Button("Actualiser la liste")
|
| 550 |
load_info_btn = gr.Button("Afficher les informations du modèle")
|
| 551 |
model_info = gr.JSON(label="Métadonnées du modèle")
|
| 552 |
+
download_btn = gr.Button("Préparer le fichier à télécharger")
|
| 553 |
+
model_download = gr.File(
|
| 554 |
+
label="Fichier du modèle (poids .pt ou pipeline .joblib) — cliquez sur "
|
| 555 |
+
"« Préparer le fichier à télécharger » puis sur la flèche de téléchargement ci-dessous",
|
| 556 |
+
)
|
| 557 |
|
| 558 |
with gr.Column():
|
| 559 |
evaluate_btn = gr.Button("Évaluer sur le jeu de test", variant="primary")
|
|
|
|
| 664 |
fn=download_model_callback, inputs=model_selector, outputs=model_download
|
| 665 |
)
|
| 666 |
|
| 667 |
+
download_btn.click(
|
| 668 |
+
fn=download_model_callback, inputs=model_selector, outputs=model_download
|
| 669 |
+
)
|
| 670 |
+
|
| 671 |
evaluate_btn.click(
|
| 672 |
fn=evaluate_callback,
|
| 673 |
inputs=model_selector,
|
|
@@ -2,7 +2,6 @@ torchvision
|
|
| 2 |
datasets
|
| 3 |
huggingface_hub
|
| 4 |
pillow
|
| 5 |
-
spaces
|
| 6 |
scikit-learn
|
| 7 |
pandas
|
| 8 |
matplotlib
|
|
|
|
| 2 |
datasets
|
| 3 |
huggingface_hub
|
| 4 |
pillow
|
|
|
|
| 5 |
scikit-learn
|
| 6 |
pandas
|
| 7 |
matplotlib
|