Spaces:
Sleeping
Sleeping
Update
Browse files
app.py
CHANGED
@@ -19,14 +19,14 @@ def compute_iou(row):
|
|
19 |
yA = max(row["ymin_gt"], row["ymin_pred"])
|
20 |
xB = min(row["xmax_gt"], row["xmax_pred"])
|
21 |
yB = min(row["ymax_gt"], row["ymax_pred"])
|
22 |
-
|
23 |
inter_width = max(0, xB - xA)
|
24 |
inter_height = max(0, yB - yA)
|
25 |
inter_area = inter_width * inter_height
|
26 |
-
|
27 |
boxA_area = (row["xmax_gt"] - row["xmin_gt"]) * (row["ymax_gt"] - row["ymin_gt"])
|
28 |
boxB_area = (row["xmax_pred"] - row["xmin_pred"]) * (row["ymax_pred"] - row["ymin_pred"])
|
29 |
-
|
30 |
union_area = boxA_area + boxB_area - inter_area
|
31 |
iou = inter_area / union_area if union_area > 0 else 0
|
32 |
return iou
|
@@ -34,8 +34,8 @@ def compute_iou(row):
|
|
34 |
def evaluate_submission(file, submission_name, model_description):
|
35 |
"""
|
36 |
Evaluate the submitted CSV file by comparing predicted bounding box coordinates and food weight
|
37 |
-
against the ground truth.
|
38 |
-
|
39 |
"""
|
40 |
if file is None:
|
41 |
return "β Please upload a file."
|
@@ -46,8 +46,8 @@ def evaluate_submission(file, submission_name, model_description):
|
|
46 |
print("Submitted columns:", submission_df.columns.tolist())
|
47 |
except Exception as e:
|
48 |
return f"β File read failed: {e}"
|
49 |
-
|
50 |
-
# Load hidden ground truth CSV from a private dataset.
|
51 |
try:
|
52 |
gt_path = hf_hub_download(
|
53 |
repo_id="issai/ground-truth-food-eval",
|
@@ -58,74 +58,61 @@ def evaluate_submission(file, submission_name, model_description):
|
|
58 |
gt_df = pd.read_csv(gt_path)
|
59 |
except Exception as e:
|
60 |
return "Error loading ground truth file: " + str(e)
|
61 |
-
|
62 |
-
#
|
63 |
print("Ground truth shape:", gt_df.shape)
|
64 |
print("Ground truth sample:")
|
65 |
print(gt_df.head())
|
66 |
-
|
67 |
print("Submission shape:", submission_df.shape)
|
68 |
print("Submission sample:")
|
69 |
print(submission_df.head())
|
70 |
-
|
71 |
-
|
72 |
-
# Merge on 'image_id'
|
73 |
try:
|
74 |
-
df = pd.merge(
|
|
|
|
|
|
|
|
|
75 |
except Exception as e:
|
76 |
return f"β Error during merge: {e}"
|
77 |
-
|
78 |
print(f"β
Received {len(submission_df)} predictions for evaluation!")
|
79 |
print("Merged shape:", df.shape)
|
80 |
-
|
81 |
if df.empty:
|
82 |
-
return "No matching
|
83 |
-
|
84 |
print("Merged columns:", df.columns.tolist())
|
85 |
print("Merged sample data:")
|
86 |
-
print(df[["
|
87 |
-
|
88 |
-
#
|
89 |
df["diff_xmin"] = abs(df["xmin_gt"] - df["xmin_pred"])
|
90 |
df["diff_weight"] = abs(df["weight_gt"] - df["weight_pred"])
|
91 |
print("Differences in 'xmin' (head):", df["diff_xmin"].head())
|
92 |
print("Differences in 'weight' (head):", df["diff_weight"].head())
|
93 |
|
94 |
-
#
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
else:
|
100 |
-
print("No nonzero differences found.")
|
101 |
-
|
102 |
-
# Convert coordinate and weight columns to numeric.
|
103 |
-
coord_cols = ["xmin_gt", "ymin_gt", "xmax_gt", "ymax_gt",
|
104 |
-
"xmin_pred", "ymin_pred", "xmax_pred", "ymax_pred"]
|
105 |
for col in coord_cols:
|
106 |
df[col] = pd.to_numeric(df[col], errors="coerce")
|
|
|
107 |
df["weight_gt"] = pd.to_numeric(df["weight_gt"], errors="coerce")
|
108 |
df["weight_pred"] = pd.to_numeric(df["weight_pred"], errors="coerce")
|
109 |
-
|
110 |
-
#
|
111 |
-
num_before = df.shape[0]
|
112 |
-
df = df[(df["weight_gt"] != -1) & (df["weight_pred"] != -1)]
|
113 |
-
num_filtered = num_before - df.shape[0]
|
114 |
-
print(f"Filtered out {num_filtered} rows due to weight == -1")
|
115 |
-
|
116 |
-
if df.empty:
|
117 |
-
return "No evaluable rows remain after filtering rows with weight == -1."
|
118 |
-
|
119 |
-
# Compute IoU for each row.
|
120 |
df["iou"] = df.apply(compute_iou, axis=1)
|
121 |
-
|
122 |
-
# Compute mean absolute error for
|
123 |
mean_weight_error = mean_absolute_error(df["weight_gt"], df["weight_pred"])
|
124 |
-
|
125 |
-
# Calculate mean IoU.
|
126 |
mean_iou = df["iou"].mean()
|
127 |
-
|
128 |
-
# Save the evaluation result to the leaderboard
|
129 |
result = {
|
130 |
"submission_name": submission_name,
|
131 |
"model_description": model_description,
|
@@ -133,7 +120,7 @@ def evaluate_submission(file, submission_name, model_description):
|
|
133 |
"mean_weight_error": mean_weight_error,
|
134 |
}
|
135 |
save_submission_result(result)
|
136 |
-
|
137 |
result_text = (
|
138 |
f"**Evaluation Results for '{submission_name}'**\n\n"
|
139 |
f"- Model: {model_description}\n"
|
@@ -148,9 +135,6 @@ LEADERBOARD_FILE = "evaluation_results.csv"
|
|
148 |
LEADERBOARD_COLUMNS = ["submission_name", "model_description", "mean_iou", "mean_weight_error"]
|
149 |
|
150 |
def save_submission_result(result):
|
151 |
-
"""
|
152 |
-
Save a new submission result into the leaderboard CSV.
|
153 |
-
"""
|
154 |
if os.path.exists(LEADERBOARD_FILE):
|
155 |
df = pd.read_csv(LEADERBOARD_FILE)
|
156 |
df = pd.concat([df, pd.DataFrame([result])], ignore_index=True)
|
@@ -159,9 +143,6 @@ def save_submission_result(result):
|
|
159 |
df.to_csv(LEADERBOARD_FILE, index=False)
|
160 |
|
161 |
def load_leaderboard():
|
162 |
-
"""
|
163 |
-
Load and sort the leaderboard dataframe.
|
164 |
-
"""
|
165 |
if os.path.exists(LEADERBOARD_FILE):
|
166 |
df = pd.read_csv(LEADERBOARD_FILE)
|
167 |
df = df.sort_values(by="mean_weight_error", ascending=True)
|
@@ -178,27 +159,36 @@ def evaluate_and_refresh(file, submission_name, model_description):
|
|
178 |
|
179 |
with gr.Blocks() as demo:
|
180 |
gr.Markdown("# Benchmark Leaderboard: Food Object Detection & Food Weight Prediction")
|
181 |
-
gr.Markdown(
|
182 |
-
|
|
|
|
|
|
|
183 |
with gr.Tabs():
|
184 |
with gr.TabItem("π
Leaderboard"):
|
185 |
leaderboard_output = gr.Dataframe(label="Leaderboard")
|
186 |
demo.load(load_leaderboard, outputs=leaderboard_output)
|
187 |
refresh_button = gr.Button("Refresh Leaderboard")
|
|
|
188 |
def refresh_leaderboard():
|
189 |
return load_leaderboard()
|
|
|
190 |
refresh_button.click(refresh_leaderboard, outputs=leaderboard_output)
|
191 |
-
|
192 |
with gr.TabItem("π Submit CSV"):
|
193 |
-
gr.Markdown(
|
194 |
-
|
195 |
-
|
196 |
-
|
|
|
|
|
|
|
|
|
197 |
submission_name_textbox = gr.Textbox(label="Submission Name / Your Name")
|
198 |
model_description_textbox = gr.Textbox(label="Model Description / Model Name")
|
199 |
submit_button = gr.Button("Evaluate Submission")
|
200 |
evaluation_output = gr.Markdown()
|
201 |
-
|
202 |
submit_button.click(
|
203 |
evaluate_and_refresh,
|
204 |
inputs=[submission_file, submission_name_textbox, model_description_textbox],
|
|
|
19 |
yA = max(row["ymin_gt"], row["ymin_pred"])
|
20 |
xB = min(row["xmax_gt"], row["xmax_pred"])
|
21 |
yB = min(row["ymax_gt"], row["ymax_pred"])
|
22 |
+
|
23 |
inter_width = max(0, xB - xA)
|
24 |
inter_height = max(0, yB - yA)
|
25 |
inter_area = inter_width * inter_height
|
26 |
+
|
27 |
boxA_area = (row["xmax_gt"] - row["xmin_gt"]) * (row["ymax_gt"] - row["ymin_gt"])
|
28 |
boxB_area = (row["xmax_pred"] - row["xmin_pred"]) * (row["ymax_pred"] - row["ymin_pred"])
|
29 |
+
|
30 |
union_area = boxA_area + boxB_area - inter_area
|
31 |
iou = inter_area / union_area if union_area > 0 else 0
|
32 |
return iou
|
|
|
34 |
def evaluate_submission(file, submission_name, model_description):
|
35 |
"""
|
36 |
Evaluate the submitted CSV file by comparing predicted bounding box coordinates and food weight
|
37 |
+
against the ground truth. We merge on both 'image_name' and 'class_id', because there can be
|
38 |
+
multiple items (classes) in the same image.
|
39 |
"""
|
40 |
if file is None:
|
41 |
return "β Please upload a file."
|
|
|
46 |
print("Submitted columns:", submission_df.columns.tolist())
|
47 |
except Exception as e:
|
48 |
return f"β File read failed: {e}"
|
49 |
+
|
50 |
+
# Load hidden ground truth CSV from a private dataset (adjust repo_id as needed).
|
51 |
try:
|
52 |
gt_path = hf_hub_download(
|
53 |
repo_id="issai/ground-truth-food-eval",
|
|
|
58 |
gt_df = pd.read_csv(gt_path)
|
59 |
except Exception as e:
|
60 |
return "Error loading ground truth file: " + str(e)
|
61 |
+
|
62 |
+
# Debug: Print shapes and first few rows.
|
63 |
print("Ground truth shape:", gt_df.shape)
|
64 |
print("Ground truth sample:")
|
65 |
print(gt_df.head())
|
66 |
+
|
67 |
print("Submission shape:", submission_df.shape)
|
68 |
print("Submission sample:")
|
69 |
print(submission_df.head())
|
70 |
+
|
71 |
+
# Merge on 'image_name' and 'class_id' so that multiple classes per image match up correctly.
|
|
|
72 |
try:
|
73 |
+
df = pd.merge(
|
74 |
+
gt_df, submission_df,
|
75 |
+
on=["image_name", "class_id"],
|
76 |
+
suffixes=("_gt", "_pred")
|
77 |
+
)
|
78 |
except Exception as e:
|
79 |
return f"β Error during merge: {e}"
|
80 |
+
|
81 |
print(f"β
Received {len(submission_df)} predictions for evaluation!")
|
82 |
print("Merged shape:", df.shape)
|
83 |
+
|
84 |
if df.empty:
|
85 |
+
return "No matching rows found between ground truth and submission (image_name/class_id)."
|
86 |
+
|
87 |
print("Merged columns:", df.columns.tolist())
|
88 |
print("Merged sample data:")
|
89 |
+
print(df[["image_name", "class_id", "xmin_gt", "xmin_pred", "weight_gt", "weight_pred"]].head())
|
90 |
+
|
91 |
+
# Debug differences in xmin and weight
|
92 |
df["diff_xmin"] = abs(df["xmin_gt"] - df["xmin_pred"])
|
93 |
df["diff_weight"] = abs(df["weight_gt"] - df["weight_pred"])
|
94 |
print("Differences in 'xmin' (head):", df["diff_xmin"].head())
|
95 |
print("Differences in 'weight' (head):", df["diff_weight"].head())
|
96 |
|
97 |
+
# Convert columns to numeric
|
98 |
+
coord_cols = [
|
99 |
+
"xmin_gt", "ymin_gt", "xmax_gt", "ymax_gt",
|
100 |
+
"xmin_pred", "ymin_pred", "xmax_pred", "ymax_pred"
|
101 |
+
]
|
|
|
|
|
|
|
|
|
|
|
|
|
102 |
for col in coord_cols:
|
103 |
df[col] = pd.to_numeric(df[col], errors="coerce")
|
104 |
+
|
105 |
df["weight_gt"] = pd.to_numeric(df["weight_gt"], errors="coerce")
|
106 |
df["weight_pred"] = pd.to_numeric(df["weight_pred"], errors="coerce")
|
107 |
+
|
108 |
+
# Compute IoU for each row
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
109 |
df["iou"] = df.apply(compute_iou, axis=1)
|
110 |
+
|
111 |
+
# Compute mean absolute error for weight
|
112 |
mean_weight_error = mean_absolute_error(df["weight_gt"], df["weight_pred"])
|
|
|
|
|
113 |
mean_iou = df["iou"].mean()
|
114 |
+
|
115 |
+
# Save the evaluation result to the leaderboard
|
116 |
result = {
|
117 |
"submission_name": submission_name,
|
118 |
"model_description": model_description,
|
|
|
120 |
"mean_weight_error": mean_weight_error,
|
121 |
}
|
122 |
save_submission_result(result)
|
123 |
+
|
124 |
result_text = (
|
125 |
f"**Evaluation Results for '{submission_name}'**\n\n"
|
126 |
f"- Model: {model_description}\n"
|
|
|
135 |
LEADERBOARD_COLUMNS = ["submission_name", "model_description", "mean_iou", "mean_weight_error"]
|
136 |
|
137 |
def save_submission_result(result):
|
|
|
|
|
|
|
138 |
if os.path.exists(LEADERBOARD_FILE):
|
139 |
df = pd.read_csv(LEADERBOARD_FILE)
|
140 |
df = pd.concat([df, pd.DataFrame([result])], ignore_index=True)
|
|
|
143 |
df.to_csv(LEADERBOARD_FILE, index=False)
|
144 |
|
145 |
def load_leaderboard():
|
|
|
|
|
|
|
146 |
if os.path.exists(LEADERBOARD_FILE):
|
147 |
df = pd.read_csv(LEADERBOARD_FILE)
|
148 |
df = df.sort_values(by="mean_weight_error", ascending=True)
|
|
|
159 |
|
160 |
with gr.Blocks() as demo:
|
161 |
gr.Markdown("# Benchmark Leaderboard: Food Object Detection & Food Weight Prediction")
|
162 |
+
gr.Markdown(
|
163 |
+
"This leaderboard evaluates CSV submissions based on bounding boxes (IoU) "
|
164 |
+
"and food weight (grams). **Now merging on image_name + class_id** to handle multiple items."
|
165 |
+
)
|
166 |
+
|
167 |
with gr.Tabs():
|
168 |
with gr.TabItem("π
Leaderboard"):
|
169 |
leaderboard_output = gr.Dataframe(label="Leaderboard")
|
170 |
demo.load(load_leaderboard, outputs=leaderboard_output)
|
171 |
refresh_button = gr.Button("Refresh Leaderboard")
|
172 |
+
|
173 |
def refresh_leaderboard():
|
174 |
return load_leaderboard()
|
175 |
+
|
176 |
refresh_button.click(refresh_leaderboard, outputs=leaderboard_output)
|
177 |
+
|
178 |
with gr.TabItem("π Submit CSV"):
|
179 |
+
gr.Markdown(
|
180 |
+
"**Submit your predictions CSV file.** Required columns:\n\n"
|
181 |
+
"`image_name, class_id, xmin, ymin, xmax, ymax, weight`"
|
182 |
+
)
|
183 |
+
|
184 |
+
submission_file = gr.File(
|
185 |
+
label="Upload Submission CSV", file_types=[".csv"]
|
186 |
+
)
|
187 |
submission_name_textbox = gr.Textbox(label="Submission Name / Your Name")
|
188 |
model_description_textbox = gr.Textbox(label="Model Description / Model Name")
|
189 |
submit_button = gr.Button("Evaluate Submission")
|
190 |
evaluation_output = gr.Markdown()
|
191 |
+
|
192 |
submit_button.click(
|
193 |
evaluate_and_refresh,
|
194 |
inputs=[submission_file, submission_name_textbox, model_description_textbox],
|