walidchaib commited on
Commit
8d1f2ed
·
verified ·
1 Parent(s): 68cc43f

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +96 -0
app.py ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # ================================
2
+ # 0. PATCH pour huggingface_hub (contourne l'absence de HfFolder)
3
+ # ================================
4
+ import huggingface_hub
5
+ if not hasattr(huggingface_hub, 'HfFolder'):
6
+ class HfFolder:
7
+ _token = None
8
+ @staticmethod
9
+ def get_token():
10
+ return HfFolder._token
11
+ @staticmethod
12
+ def save_token(token):
13
+ HfFolder._token = token
14
+ huggingface_hub.HfFolder = HfFolder
15
+
16
+ # ================================
17
+ # 1. PATCH pour contourner le bug de Gradio 4.44.0
18
+ # (TypeError: argument of type 'bool' is not iterable)
19
+ # ================================
20
+ import gradio_client.utils
21
+
22
+ original_get_type = gradio_client.utils.get_type
23
+
24
+ def patched_get_type(schema):
25
+ if isinstance(schema, bool):
26
+ return "boolean"
27
+ return original_get_type(schema)
28
+
29
+ gradio_client.utils.get_type = patched_get_type
30
+
31
+ # ================================
32
+ # 2. IMPORTS STANDARDS
33
+ # ================================
34
+ import gradio as gr
35
+ import tensorflow as tf
36
+ import numpy as np
37
+ from PIL import Image
38
+
39
+ # Forcer la précision float32 (évite les warnings de mixed precision sur CPU)
40
+ tf.keras.mixed_precision.set_global_policy('float32')
41
+
42
+ # ================================
43
+ # 3. CHARGEMENT DU MODÈLE (binaire)
44
+ # ================================
45
+ MODEL_PATH = "final_model.keras"
46
+ # Charger le modèle sans compiler pour éviter l'avertissement sur l'optimiseur
47
+ model = tf.keras.models.load_model(MODEL_PATH, compile=False)
48
+
49
+ # Recompiler avec une configuration simple (nécessaire pour faire des prédictions)
50
+ model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
51
+
52
+ # ================================
53
+ # 4. CONSTANTES
54
+ # ================================
55
+ IMG_SIZE = 380 # Taille d'entrée du modèle (EfficientNetB4)
56
+
57
+ # ================================
58
+ # 5. FONCTION DE PRÉDICTION
59
+ # ================================
60
+ def preprocess_image(img):
61
+ """
62
+ Redimensionne et normalise l'image pour le modèle.
63
+ L'entraînement a utilisé : cv2.resize + /255.0
64
+ """
65
+ img = img.resize((IMG_SIZE, IMG_SIZE))
66
+ img_array = np.array(img, dtype=np.float32) / 255.0
67
+ img_array = np.expand_dims(img_array, axis=0)
68
+ return img_array
69
+
70
+ def predict(img):
71
+ """
72
+ Retourne un dictionnaire {classe: probabilité} pour les deux classes.
73
+ La sortie du modèle est la probabilité d'être une mauvaise herbe (weed).
74
+ """
75
+ processed = preprocess_image(img)
76
+ prob_weed = float(model.predict(processed, verbose=0)[0][0])
77
+ prob_crop = 1 - prob_weed
78
+ return {
79
+ "crop": prob_crop,
80
+ "weed": prob_weed
81
+ }
82
+
83
+ # ================================
84
+ # 6. INTERFACE GRADIO
85
+ # ================================
86
+ iface = gr.Interface(
87
+ fn=predict,
88
+ inputs=gr.Image(type="pil", label="Chargez une image de champ (culture ou mauvaise herbe)"),
89
+ outputs=gr.Label(num_top_classes=2, label="Prédiction"),
90
+ title="Classification Culture / Mauvaise Herbe",
91
+ description="Ce modèle (EfficientNetB4) distingue les cultures des mauvaises herbes. \
92
+ Il a été entraîné sur un dataset avec bounding boxes, pour une tâche de classification binaire."
93
+ )
94
+
95
+ if __name__ == "__main__":
96
+ iface.launch(share=True)