Legend + FAQ
Browse files- README.md +21 -1
- app.py +5 -2
- styles.css +6 -2
- summary_page.py +40 -7
README.md
CHANGED
|
@@ -10,4 +10,24 @@ pinned: false
|
|
| 10 |
short_description: A dashboard
|
| 11 |
---
|
| 12 |
|
| 13 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
short_description: A dashboard
|
| 11 |
---
|
| 12 |
|
| 13 |
+
# TCID
|
| 14 |
+
|
| 15 |
+
This space displays the state of the `transformers` CI on two hardwares, for a subset of models. The CI is run daily, on both AMD MI325 and Nvidia A10. The CI runs a different number of tests for each model. When a test finishes, it is assigned a status depending on its outcome:
|
| 16 |
+
|
| 17 |
+
- passed: the test finsihed and the expected output (or outputs) were retrieved;
|
| 18 |
+
- failed: the test either did not finish or the output was different from the expected output;
|
| 19 |
+
- skipped: the test was not run, which usually happens when a test is incompatible with a model. For instance, some models skip `flash-attention`-related tests because they are incompatible with `flash-attention`;
|
| 20 |
+
- error: the test did not finish and python crashed;
|
| 21 |
+
|
| 22 |
+
The dashboard is divided in two main parts:
|
| 23 |
+
|
| 24 |
+
## Summary page
|
| 25 |
+
|
| 26 |
+
On the summary page, you can see a snapshot of the mix of test passed, failed and skipped for each model. The summary page also features an "Overall failures rate" for AMD and NVIDIA, which is computed this way:
|
| 27 |
+
```overall_failure_rate = (failed + error) / (passed + failed + error)```
|
| 28 |
+
|
| 29 |
+
We do not account for the test skipped in this overall failure rate, because skipped test have no chance to neither pass nor fail.
|
| 30 |
+
|
| 31 |
+
## Models page
|
| 32 |
+
|
| 33 |
+
From the sidebar, you can access a detailled view of each model. In it, you will find the breakdown of test statuses and the names of the test that failed for single and multi-gpu runs.
|
app.py
CHANGED
|
@@ -229,7 +229,10 @@ with gr.Blocks(title="Model Test Results Dashboard", css=load_css()) as demo:
|
|
| 229 |
if amd_multi_link and amd_single_link and nvidia_multi_link and nvidia_single_link:
|
| 230 |
break
|
| 231 |
|
| 232 |
-
|
|
|
|
|
|
|
|
|
|
| 233 |
|
| 234 |
# AMD links
|
| 235 |
if amd_multi_link or amd_single_link:
|
|
@@ -254,7 +257,7 @@ with gr.Blocks(title="Model Test Results Dashboard", css=load_css()) as demo:
|
|
| 254 |
return links_md
|
| 255 |
except Exception as e:
|
| 256 |
logger.error(f"getting CI links: {e}")
|
| 257 |
-
return "π **CI Jobs:** *Error loading links
|
| 258 |
|
| 259 |
|
| 260 |
# Auto-update CI links when the interface loads
|
|
|
|
| 229 |
if amd_multi_link and amd_single_link and nvidia_multi_link and nvidia_single_link:
|
| 230 |
break
|
| 231 |
|
| 232 |
+
|
| 233 |
+
# Add FAQ link at the bottom
|
| 234 |
+
links_md = "β [**FAQ**](https://huggingface.co/spaces/ror/tcid/blob/main/README.md)\n\n"
|
| 235 |
+
links_md += "π **CI Jobs:**\n\n"
|
| 236 |
|
| 237 |
# AMD links
|
| 238 |
if amd_multi_link or amd_single_link:
|
|
|
|
| 257 |
return links_md
|
| 258 |
except Exception as e:
|
| 259 |
logger.error(f"getting CI links: {e}")
|
| 260 |
+
return "π **CI Jobs:** *Error loading links*\n\nβ **[FAQ](README.md)**"
|
| 261 |
|
| 262 |
|
| 263 |
# Auto-update CI links when the interface loads
|
styles.css
CHANGED
|
@@ -1,4 +1,8 @@
|
|
| 1 |
-
/* Global dark theme */
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2 |
.gradio-container {
|
| 3 |
background-color: #000000 !important;
|
| 4 |
color: white !important;
|
|
@@ -500,7 +504,7 @@ h1, h2, h3, p, .markdown {
|
|
| 500 |
/* Main content area */
|
| 501 |
.main-content {
|
| 502 |
background-color: #000000 !important;
|
| 503 |
-
padding: 0px 20px
|
| 504 |
margin-left: 300px !important;
|
| 505 |
height: 100vh !important;
|
| 506 |
overflow-y: auto !important;
|
|
|
|
| 1 |
+
/* Global dark theme with configurable bottom margin */
|
| 2 |
+
:root {
|
| 3 |
+
--main-content-bottom-margin: 10px; /* Configurable bottom margin for main content */
|
| 4 |
+
}
|
| 5 |
+
|
| 6 |
.gradio-container {
|
| 7 |
background-color: #000000 !important;
|
| 8 |
color: white !important;
|
|
|
|
| 504 |
/* Main content area */
|
| 505 |
.main-content {
|
| 506 |
background-color: #000000 !important;
|
| 507 |
+
padding: 0px 20px var(--main-content-bottom-margin, 10px) 20px !important;
|
| 508 |
margin-left: 300px !important;
|
| 509 |
height: 100vh !important;
|
| 510 |
overflow-y: auto !important;
|
summary_page.py
CHANGED
|
@@ -11,10 +11,10 @@ BAR_WIDTH = COLUMN_WIDTH * 0.8 # 80% of column width for bars
|
|
| 11 |
BAR_MARGIN = COLUMN_WIDTH * 0.1 # 10% margin on each side
|
| 12 |
|
| 13 |
# Figure dimensions
|
| 14 |
-
FIGURE_WIDTH =
|
| 15 |
-
MAX_HEIGHT =
|
| 16 |
-
MIN_HEIGHT_PER_ROW = 2.
|
| 17 |
-
FIGURE_PADDING =
|
| 18 |
|
| 19 |
# Bar styling
|
| 20 |
BAR_HEIGHT_RATIO = 0.22 # Bar height as ratio of vertical spacing
|
|
@@ -56,13 +56,13 @@ def calculate_overall_failure_rates(df: pd.DataFrame, available_models: list[str
|
|
| 56 |
amd_stats, nvidia_stats = extract_model_data(row)[:2]
|
| 57 |
|
| 58 |
# AMD totals
|
| 59 |
-
amd_total =
|
| 60 |
if amd_total > 0:
|
| 61 |
total_amd_tests += amd_total
|
| 62 |
total_amd_failures += amd_stats['failed'] + amd_stats['error']
|
| 63 |
|
| 64 |
# NVIDIA totals
|
| 65 |
-
nvidia_total =
|
| 66 |
if nvidia_total > 0:
|
| 67 |
total_nvidia_tests += nvidia_total
|
| 68 |
total_nvidia_failures += nvidia_stats['failed'] + nvidia_stats['error']
|
|
@@ -180,9 +180,42 @@ def create_summary_page(df: pd.DataFrame, available_models: list[str]) -> plt.Fi
|
|
| 180 |
# Increment counter for next visible model
|
| 181 |
visible_model_count += 1
|
| 182 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 183 |
# Style the axes to be completely invisible and span full width
|
| 184 |
ax.set_xlim(-5, 105) # Slightly wider to accommodate labels
|
| 185 |
-
ax.set_ylim(0, max_y)
|
| 186 |
ax.set_xlabel('')
|
| 187 |
ax.set_ylabel('')
|
| 188 |
ax.spines['bottom'].set_visible(False)
|
|
|
|
| 11 |
BAR_MARGIN = COLUMN_WIDTH * 0.1 # 10% margin on each side
|
| 12 |
|
| 13 |
# Figure dimensions
|
| 14 |
+
FIGURE_WIDTH = 22 # Wider to accommodate columns and legend
|
| 15 |
+
MAX_HEIGHT = 14 # Maximum height in inches
|
| 16 |
+
MIN_HEIGHT_PER_ROW = 2.8
|
| 17 |
+
FIGURE_PADDING = 1
|
| 18 |
|
| 19 |
# Bar styling
|
| 20 |
BAR_HEIGHT_RATIO = 0.22 # Bar height as ratio of vertical spacing
|
|
|
|
| 56 |
amd_stats, nvidia_stats = extract_model_data(row)[:2]
|
| 57 |
|
| 58 |
# AMD totals
|
| 59 |
+
amd_total = amd_stats['passed'] + amd_stats['failed'] + amd_stats['error']
|
| 60 |
if amd_total > 0:
|
| 61 |
total_amd_tests += amd_total
|
| 62 |
total_amd_failures += amd_stats['failed'] + amd_stats['error']
|
| 63 |
|
| 64 |
# NVIDIA totals
|
| 65 |
+
nvidia_total = nvidia_stats['passed'] + nvidia_stats['failed'] + nvidia_stats['error']
|
| 66 |
if nvidia_total > 0:
|
| 67 |
total_nvidia_tests += nvidia_total
|
| 68 |
total_nvidia_failures += nvidia_stats['failed'] + nvidia_stats['error']
|
|
|
|
| 180 |
# Increment counter for next visible model
|
| 181 |
visible_model_count += 1
|
| 182 |
|
| 183 |
+
|
| 184 |
+
# Add legend horizontally in bottom right corner
|
| 185 |
+
patch_height = 0.3
|
| 186 |
+
patch_width = 3
|
| 187 |
+
|
| 188 |
+
legend_start_x = 68.7
|
| 189 |
+
legend_y = max_y + 1
|
| 190 |
+
legend_spacing = 10
|
| 191 |
+
legend_font_size = 15
|
| 192 |
+
|
| 193 |
+
# Add failure rate explanation text on the left
|
| 194 |
+
# explanation_text = "Failure rate = failed / (passed + failed)"
|
| 195 |
+
# ax.text(0, legend_y, explanation_text,
|
| 196 |
+
# ha='left', va='bottom', color='#CCCCCC',
|
| 197 |
+
# fontsize=legend_font_size, fontfamily='monospace', style='italic')
|
| 198 |
+
|
| 199 |
+
# Legend entries
|
| 200 |
+
legend_items = [
|
| 201 |
+
('passed', 'Passed'),
|
| 202 |
+
('failed', 'Failed'),
|
| 203 |
+
('skipped', 'Skipped'),
|
| 204 |
+
]
|
| 205 |
+
|
| 206 |
+
for i, (status, label) in enumerate(legend_items):
|
| 207 |
+
x_pos = legend_start_x + i * legend_spacing
|
| 208 |
+
# Small colored square
|
| 209 |
+
ax.add_patch(plt.Rectangle((x_pos - 0.6, legend_y), patch_width, -patch_height,
|
| 210 |
+
facecolor=COLORS[status], alpha=0.9))
|
| 211 |
+
# Status label
|
| 212 |
+
ax.text(x_pos + patch_width, legend_y, label,
|
| 213 |
+
ha='left', va='bottom', color='#CCCCCC',
|
| 214 |
+
fontsize=legend_font_size, fontfamily='monospace')
|
| 215 |
+
|
| 216 |
# Style the axes to be completely invisible and span full width
|
| 217 |
ax.set_xlim(-5, 105) # Slightly wider to accommodate labels
|
| 218 |
+
ax.set_ylim(0, max_y + 1) # Add some padding at the top for title
|
| 219 |
ax.set_xlabel('')
|
| 220 |
ax.set_ylabel('')
|
| 221 |
ax.spines['bottom'].set_visible(False)
|