agh123 commited on
Commit
157b914
·
1 Parent(s): 915fcba

chore: filter out anomalies (z_threshold=9.0)

Browse files
Files changed (2) hide show
  1. src/services/firebase.py +9 -1
  2. src/utils/anomaly.py +146 -0
src/services/firebase.py CHANGED
@@ -5,6 +5,8 @@ import pandas as pd
5
  import streamlit as st
6
  import json
7
 
 
 
8
  # Import the device lookup function
9
  from ..utils.device_lookup import get_device_name
10
 
@@ -91,6 +93,7 @@ def format_leaderboard_data(submissions: List[dict]) -> pd.DataFrame:
91
 
92
  formatted_data.append(
93
  {
 
94
  "Device": device_name, # Use normalized device name
95
  "Device ID": device_id,
96
  "Platform": device_info.get("systemName", "Unknown"),
@@ -157,7 +160,12 @@ def format_leaderboard_data(submissions: List[dict]) -> pd.DataFrame:
157
  st.warning(f"Error processing submission: {str(e)}")
158
  continue
159
 
160
- return pd.DataFrame(formatted_data)
 
 
 
 
 
161
 
162
 
163
  async def fetch_leaderboard_data(
 
5
  import streamlit as st
6
  import json
7
 
8
+ from src.utils.anomaly import filter_anomalies
9
+
10
  # Import the device lookup function
11
  from ..utils.device_lookup import get_device_name
12
 
 
93
 
94
  formatted_data.append(
95
  {
96
+ "Submission ID": benchmark_result.get("uuid", "Unknown"),
97
  "Device": device_name, # Use normalized device name
98
  "Device ID": device_id,
99
  "Platform": device_info.get("systemName", "Unknown"),
 
160
  st.warning(f"Error processing submission: {str(e)}")
161
  continue
162
 
163
+ formatted_df = pd.DataFrame(formatted_data)
164
+ filtered_df, anomalies = filter_anomalies(
165
+ formatted_df, z_threshold=9.0, min_samples=5
166
+ )
167
+ print("Anomalies: ", anomalies)
168
+ return filtered_df
169
 
170
 
171
  async def fetch_leaderboard_data(
src/utils/anomaly.py ADDED
@@ -0,0 +1,146 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pandas as pd
2
+
3
+
4
+ def add_model_size_groups(df, group_size=0.5, max_size=15):
5
+ """
6
+ Add a column to the DataFrame categorizing model file sizes into size groups.
7
+
8
+ Args:
9
+ df (pandas.DataFrame): DataFrame containing model benchmark data
10
+ group_size (float): Size of each group in GB (default: 0.5)
11
+ max_size (int): Maximum size in GB to consider (default: 15)
12
+
13
+ Returns:
14
+ pandas.DataFrame: Original DataFrame with an additional 'Size Group' column
15
+ """
16
+ if df is None or df.empty:
17
+ return df
18
+
19
+ result_df = df.copy()
20
+
21
+ if "Model Size GB" not in result_df.columns:
22
+ # Check if 'Model File Size' exists in the DataFrame
23
+ if "Model File Size" not in result_df.columns:
24
+ raise ValueError("DataFrame must contain 'Model File Size' column")
25
+ result_df["Model Size GB"] = result_df["Model File Size"] / 1024**3
26
+
27
+ # Define a function to assign size groups
28
+ def assign_size_group(size):
29
+ if size is None or pd.isna(size):
30
+ return "Unknown"
31
+
32
+ if size >= max_size:
33
+ return f">{max_size} GB"
34
+
35
+ import math
36
+
37
+ group_index = math.floor(size / group_size)
38
+ lower_bound = group_index * group_size
39
+ upper_bound = lower_bound + group_size
40
+
41
+ # Round to 1 decimal place to avoid floating point issues
42
+ lower_bound = round(lower_bound, 1)
43
+ upper_bound = round(upper_bound, 1)
44
+
45
+ return f"{lower_bound}-{upper_bound} GB"
46
+
47
+ result_df["Size Group"] = result_df["Model Size GB"].apply(assign_size_group)
48
+
49
+ return result_df
50
+
51
+
52
+ def detect_anomalies(df, z_threshold=6.0, min_samples=5):
53
+ """
54
+ Detect anomalies in benchmark data.
55
+
56
+ Args:
57
+ df (pd.DataFrame): DataFrame containing benchmark data
58
+ z_threshold (float): Z-score threshold for anomaly detection (default: 6.0)
59
+ min_samples (int): Minimum number of samples needed for a group to calculate statistics
60
+
61
+ Returns:
62
+ pd.DataFrame: DataFrame containing detected anomalies with relevant information
63
+ """
64
+ if df is None or df.empty:
65
+ return pd.DataFrame()
66
+
67
+ # Ensure we have Size Group column
68
+ if "Size Group" not in df.columns:
69
+ df = add_model_size_groups(df)
70
+
71
+ anomalies = []
72
+
73
+ for metric in ["Prompt Processing", "Token Generation"]:
74
+ size_groups = df.groupby("Size Group")
75
+
76
+ for size_group, group_df in size_groups:
77
+ # Only process groups with enough samples
78
+ if len(group_df) < min_samples:
79
+ continue
80
+
81
+ mean_value = group_df[metric].mean()
82
+ std_value = group_df[metric].std()
83
+
84
+ # Skip if standard deviation is zero or very small
85
+ if std_value < 0.001:
86
+ continue
87
+
88
+ # Calculate z-scores for each entry
89
+ for _, row in group_df.iterrows():
90
+ value = row[metric]
91
+ if pd.isna(value):
92
+ continue
93
+
94
+ z_score = abs((value - mean_value) / std_value)
95
+
96
+ # Flag as anomaly if z-score exceeds threshold
97
+ if z_score > z_threshold:
98
+ anomaly_data = {
99
+ "Size Group": size_group,
100
+ "Model": row["Model"],
101
+ "Device": row["Device"],
102
+ "Device ID": row["Device ID"],
103
+ "Platform": row["Platform"],
104
+ "Metric": metric,
105
+ "Value": value,
106
+ "Mean": mean_value,
107
+ "Std": std_value,
108
+ "Z-Score": z_score,
109
+ "Times Faster/Slower": value / mean_value,
110
+ "Benchmark": row["Benchmark"],
111
+ "Submission ID": row["Submission ID"],
112
+ }
113
+
114
+ anomalies.append(anomaly_data)
115
+
116
+ anomaly_df = pd.DataFrame(anomalies)
117
+ if not anomaly_df.empty:
118
+ anomaly_df = anomaly_df.sort_values(by="Z-Score", ascending=False)
119
+
120
+ return anomaly_df
121
+
122
+
123
+ def filter_anomalies(df, z_threshold=9.0, min_samples=5):
124
+ """
125
+ Filter out anomalies from a DataFrame.
126
+
127
+ Args:
128
+ df (pd.DataFrame): DataFrame containing benchmark data
129
+ z_threshold (float): Z-score threshold for anomaly detection (default: 9.0)
130
+ min_samples (int): Minimum number of samples needed for a group to calculate statistics
131
+
132
+ Returns:
133
+ tuple: (filtered_df, anomalies_df) - the filtered DataFrame without anomalies and the anomalies DataFrame
134
+ """
135
+ if df is None or df.empty:
136
+ return df, pd.DataFrame()
137
+
138
+ # Find anomalies
139
+ anomalies = detect_anomalies(df, z_threshold, min_samples)
140
+
141
+ if anomalies.empty:
142
+ return df, anomalies
143
+
144
+ anomaly_ids = set(anomalies["Submission ID"].dropna().unique())
145
+ filtered_df = df[~df["Submission ID"].isin(anomaly_ids)]
146
+ return filtered_df, anomalies