Add normalized scoring and MLPerf principles to Module 19

Enhancements to benchmarking module:
- Added calculate_normalized_scores() for fair hardware comparison
- Implemented speedup, compression ratio, accuracy delta metrics
- Added MLPerf principles section to educational content
- Updated module to support competition fairness

These changes enable Module 20 competition to work across different hardware.
This commit is contained in:
Vijay Janapa Reddi
2025-11-07 20:04:46 -05:00
parent f5004807eb
commit 3cefcf192e
2 changed files with 277 additions and 227 deletions
@@ -3,7 +3,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "0f6c62ff",
"id": "e9ff31aa",
"metadata": {},
"outputs": [],
"source": [
@@ -13,7 +13,7 @@
},
{
"cell_type": "markdown",
"id": "40158b0d",
"id": "d49b6d28",
"metadata": {
"cell_marker": "\"\"\""
},
@@ -54,7 +54,7 @@
},
{
"cell_type": "markdown",
"id": "7bb7b96d",
"id": "1dd61735",
"metadata": {
"cell_marker": "\"\"\""
},
@@ -83,7 +83,7 @@
},
{
"cell_type": "markdown",
"id": "39c18e66",
"id": "cdb58292",
"metadata": {
"cell_marker": "\"\"\""
},
@@ -119,7 +119,7 @@
},
{
"cell_type": "markdown",
"id": "ec7d8e69",
"id": "a41ba608",
"metadata": {
"cell_marker": "\"\"\""
},
@@ -172,7 +172,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "0b3993a6",
"id": "3698099e",
"metadata": {},
"outputs": [],
"source": [
@@ -197,7 +197,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "c14f714c",
"id": "1ba1d3dc",
"metadata": {
"lines_to_next_cell": 1
},
@@ -222,7 +222,7 @@
},
{
"cell_type": "markdown",
"id": "9054e08f",
"id": "e4bd5a37",
"metadata": {
"cell_marker": "\"\"\""
},
@@ -251,7 +251,7 @@
},
{
"cell_type": "markdown",
"id": "dc131487",
"id": "17a008af",
"metadata": {
"cell_marker": "\"\"\"",
"lines_to_next_cell": 1
@@ -291,7 +291,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "ad20a4c8",
"id": "58b069fb",
"metadata": {
"nbgrader": {
"grade": false,
@@ -400,7 +400,7 @@
},
{
"cell_type": "markdown",
"id": "c0df7489",
"id": "8205c609",
"metadata": {
"cell_marker": "\"\"\"",
"lines_to_next_cell": 1
@@ -453,7 +453,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "38491cfa",
"id": "ec6dd3bb",
"metadata": {
"nbgrader": {
"grade": false,
@@ -533,7 +533,7 @@
},
{
"cell_type": "markdown",
"id": "149f5f9a",
"id": "e369a7a0",
"metadata": {
"cell_marker": "\"\"\"",
"lines_to_next_cell": 1
@@ -601,7 +601,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "d53f0474",
"id": "e9daff37",
"metadata": {
"nbgrader": {
"grade": false,
@@ -876,7 +876,7 @@
},
{
"cell_type": "markdown",
"id": "2ea120cb",
"id": "1530cb11",
"metadata": {
"cell_marker": "\"\"\"",
"lines_to_next_cell": 1
@@ -940,7 +940,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "f9cfacc6",
"id": "49bc9ee6",
"metadata": {
"nbgrader": {
"grade": false,
@@ -1317,7 +1317,7 @@
},
{
"cell_type": "markdown",
"id": "4239143f",
"id": "8f1ca772",
"metadata": {
"cell_marker": "\"\"\"",
"lines_to_next_cell": 1
@@ -1394,7 +1394,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "93f6691b",
"id": "c48dd641",
"metadata": {
"nbgrader": {
"grade": false,
@@ -1768,7 +1768,7 @@
},
{
"cell_type": "markdown",
"id": "05bec50f",
"id": "bce5e722",
"metadata": {
"cell_marker": "\"\"\""
},
@@ -1800,7 +1800,7 @@
},
{
"cell_type": "markdown",
"id": "8a879de8",
"id": "fceb0478",
"metadata": {
"cell_marker": "\"\"\"",
"lines_to_next_cell": 1
@@ -1853,7 +1853,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "e1fe12aa",
"id": "e0e9d140",
"metadata": {
"nbgrader": {
"grade": false,
@@ -2094,7 +2094,7 @@
},
{
"cell_type": "markdown",
"id": "9cc1cdcb",
"id": "026dcc7d",
"metadata": {
"cell_marker": "\"\"\""
},
@@ -2184,12 +2184,258 @@
},
{
"cell_type": "markdown",
"id": "34d08319",
"id": "20aa0b56",
"metadata": {
"cell_marker": "\"\"\""
},
"source": [
"## 4.5 Combination Strategies - Preparing for TorchPerf Olympics\n",
"## 4.5 Normalized Metrics - Fair Comparison Across Different Hardware\n",
"\n",
"### The Hardware Problem\n",
"\n",
"Imagine two students submit their optimizations:\n",
"- **Alice** (M3 Mac, 16GB RAM): \"My model runs at 50ms latency!\"\n",
"- **Bob** (2015 laptop, 4GB RAM): \"My model runs at 200ms latency!\"\n",
"\n",
"Who optimized better? **You can't tell from raw numbers!**\n",
"\n",
"Alice's hardware is 4x faster. If Bob achieved 200ms on old hardware, he might have optimized MORE aggressively than Alice. Raw metrics are unfair.\n",
"\n",
"### The Solution: Relative Improvement Metrics\n",
"\n",
"Instead of absolute performance, measure **relative improvement** from YOUR baseline:\n",
"\n",
"```\n",
"Speedup = Baseline Latency / Optimized Latency\n",
"Compression Ratio = Baseline Memory / Optimized Memory \n",
"Accuracy Delta = Optimized Accuracy - Baseline Accuracy\n",
"```\n",
"\n",
"**Example:**\n",
"- Alice: 100ms → 50ms = **2.0x speedup** ✓\n",
"- Bob: 400ms → 200ms = **2.0x speedup** ✓\n",
"\n",
"Now they're fairly compared! Both achieved 2x speedup on their hardware.\n",
"\n",
"### Key Normalized Metrics for TorchPerf Olympics\n",
"\n",
"**1. Speedup (for Latency Sprint)**\n",
"```python\n",
"speedup = baseline_latency / optimized_latency\n",
"# Higher is better: 2.5x means 2.5 times faster\n",
"```\n",
"\n",
"**2. Compression Ratio (for Memory Challenge)**\n",
"```python\n",
"compression_ratio = baseline_memory / optimized_memory\n",
"# Higher is better: 4.0x means 4 times smaller\n",
"```\n",
"\n",
"**3. Accuracy Preservation (for All Events)**\n",
"```python\n",
"accuracy_delta = optimized_accuracy - baseline_accuracy\n",
"# Closer to 0 is better: -0.02 means 2% accuracy drop\n",
"```\n",
"\n",
"**4. Efficiency Score (for All-Around)**\n",
"```python\n",
"efficiency = (speedup * compression_ratio) / max(1.0, abs(accuracy_delta))\n",
"# Balances all metrics\n",
"```\n",
"\n",
"### Why This Matters for Your Competition\n",
"\n",
"**Without normalization:**\n",
"- Newest hardware wins unfairly\n",
"- Focus shifts to \"who has the best laptop\"\n",
"- Optimization skill doesn't matter\n",
"\n",
"**With normalization:**\n",
"- Everyone competes on **optimization skill**\n",
"- Hardware differences are eliminated\n",
"- Focus is on relative improvement\n",
"\n",
"**Real MLPerf Example:**\n",
"```\n",
"NVIDIA A100 submission: 2.1ms (absolute) → 3.5x speedup (relative)\n",
"Google TPU submission: 1.8ms (absolute) → 4.2x speedup (relative)\n",
"\n",
"Winner: Google (better speedup despite slower absolute time)\n",
"```\n",
"\n",
"### Implementing Normalized Scoring"
]
},
{
"cell_type": "markdown",
"id": "6c051c23",
"metadata": {
"cell_marker": "\"\"\"",
"lines_to_next_cell": 1
},
"source": [
"Let's implement a helper function to calculate normalized scores for the competition:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "75393e9b",
"metadata": {
"lines_to_next_cell": 1,
"nbgrader": {
"grade": false,
"grade_id": "normalized-scoring",
"locked": false
}
},
"outputs": [],
"source": [
"#| export\n",
"def calculate_normalized_scores(baseline_results: dict, \n",
" optimized_results: dict) -> dict:\n",
" \"\"\"\n",
" Calculate normalized performance metrics for fair competition comparison.\n",
" \n",
" This function converts absolute measurements into relative improvements,\n",
" enabling fair comparison across different hardware platforms.\n",
" \n",
" Args:\n",
" baseline_results: Dict with keys: 'latency', 'memory', 'accuracy'\n",
" optimized_results: Dict with same keys as baseline_results\n",
" \n",
" Returns:\n",
" Dict with normalized metrics:\n",
" - speedup: Relative latency improvement (higher is better)\n",
" - compression_ratio: Relative memory reduction (higher is better)\n",
" - accuracy_delta: Absolute accuracy change (closer to 0 is better)\n",
" - efficiency_score: Combined metric balancing all factors\n",
" \n",
" Example:\n",
" >>> baseline = {'latency': 100.0, 'memory': 12.0, 'accuracy': 0.89}\n",
" >>> optimized = {'latency': 40.0, 'memory': 3.0, 'accuracy': 0.87}\n",
" >>> scores = calculate_normalized_scores(baseline, optimized)\n",
" >>> print(f\"Speedup: {scores['speedup']:.2f}x\")\n",
" Speedup: 2.50x\n",
" \"\"\"\n",
" # Calculate speedup (higher is better)\n",
" speedup = baseline_results['latency'] / optimized_results['latency']\n",
" \n",
" # Calculate compression ratio (higher is better)\n",
" compression_ratio = baseline_results['memory'] / optimized_results['memory']\n",
" \n",
" # Calculate accuracy delta (closer to 0 is better, negative means degradation)\n",
" accuracy_delta = optimized_results['accuracy'] - baseline_results['accuracy']\n",
" \n",
" # Calculate efficiency score (combined metric)\n",
" # Penalize accuracy loss: the more accuracy you lose, the lower your score\n",
" accuracy_penalty = max(1.0, 1.0 - accuracy_delta) if accuracy_delta < 0 else 1.0\n",
" efficiency_score = (speedup * compression_ratio) / accuracy_penalty\n",
" \n",
" return {\n",
" 'speedup': speedup,\n",
" 'compression_ratio': compression_ratio,\n",
" 'accuracy_delta': accuracy_delta,\n",
" 'efficiency_score': efficiency_score,\n",
" 'baseline': baseline_results.copy(),\n",
" 'optimized': optimized_results.copy()\n",
" }"
]
},
{
"cell_type": "markdown",
"id": "16a7dbfe",
"metadata": {
"cell_marker": "\"\"\"",
"lines_to_next_cell": 1
},
"source": [
"### 🧪 Unit Test: Normalized Scoring\n",
"\n",
"**This is a unit test** - it validates that normalized scoring correctly calculates relative improvements."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "a76bb43c",
"metadata": {
"nbgrader": {
"grade": true,
"grade_id": "test-normalized-scoring",
"locked": true,
"points": 1
}
},
"outputs": [],
"source": [
"def test_unit_normalized_scoring():\n",
" \"\"\"Test normalized scoring calculation.\"\"\"\n",
" print(\"🔬 Unit Test: Normalized Scoring Calculation...\")\n",
" \n",
" # Test Case 1: Standard optimization (speedup + compression)\n",
" baseline = {'latency': 100.0, 'memory': 12.0, 'accuracy': 0.89}\n",
" optimized = {'latency': 40.0, 'memory': 3.0, 'accuracy': 0.87}\n",
" \n",
" scores = calculate_normalized_scores(baseline, optimized)\n",
" \n",
" assert abs(scores['speedup'] - 2.5) < 0.01, \"Speedup calculation incorrect\"\n",
" assert abs(scores['compression_ratio'] - 4.0) < 0.01, \"Compression ratio incorrect\"\n",
" assert abs(scores['accuracy_delta'] - (-0.02)) < 0.001, \"Accuracy delta incorrect\"\n",
" print(\" ✅ Standard optimization scoring works\")\n",
" \n",
" # Test Case 2: Extreme optimization (high speedup, accuracy loss)\n",
" optimized_extreme = {'latency': 20.0, 'memory': 1.5, 'accuracy': 0.75}\n",
" scores_extreme = calculate_normalized_scores(baseline, optimized_extreme)\n",
" \n",
" assert scores_extreme['speedup'] > 4.0, \"Extreme speedup not detected\"\n",
" assert scores_extreme['accuracy_delta'] < -0.1, \"Large accuracy loss not detected\"\n",
" print(\" ✅ Extreme optimization scoring works\")\n",
" \n",
" # Test Case 3: Conservative optimization (minimal changes)\n",
" optimized_conservative = {'latency': 90.0, 'memory': 11.0, 'accuracy': 0.89}\n",
" scores_conservative = calculate_normalized_scores(baseline, optimized_conservative)\n",
" \n",
" assert abs(scores_conservative['accuracy_delta']) < 0.01, \"Accuracy preservation not detected\"\n",
" print(\" ✅ Conservative optimization scoring works\")\n",
" \n",
" # Test Case 4: Accuracy improvement (rare but possible)\n",
" optimized_better = {'latency': 80.0, 'memory': 10.0, 'accuracy': 0.91}\n",
" scores_better = calculate_normalized_scores(baseline, optimized_better)\n",
" \n",
" assert scores_better['accuracy_delta'] > 0, \"Accuracy improvement not detected\"\n",
" print(\" ✅ Accuracy improvement scoring works\")\n",
" \n",
" print(\"📈 Progress: Normalized Scoring ✓\\n\")\n",
"\n",
"test_unit_normalized_scoring()"
]
},
{
"cell_type": "markdown",
"id": "c1199666",
"metadata": {
"cell_marker": "\"\"\""
},
"source": [
"### Key Takeaways\n",
"\n",
"1. **Always report relative improvements, not absolute numbers**\n",
"2. **Speedup and compression ratio are the primary metrics**\n",
"3. **Accuracy delta shows the optimization cost**\n",
"4. **Efficiency score balances all factors for All-Around event**\n",
"\n",
"**In Module 20**, you'll use `calculate_normalized_scores()` to generate your competition submission!"
]
},
{
"cell_type": "markdown",
"id": "3dabdb12",
"metadata": {
"cell_marker": "\"\"\""
},
"source": [
"## 4.6 Combination Strategies - Preparing for TorchPerf Olympics\n",
"\n",
"You've learned individual optimizations (M14-18). Now it's time to combine them strategically! The order and parameters matter significantly for final performance.\n",
"\n",
@@ -2281,7 +2527,7 @@
},
{
"cell_type": "markdown",
"id": "bdb56ec9",
"id": "4d21ac76",
"metadata": {
"cell_marker": "\"\"\"",
"lines_to_next_cell": 1
@@ -2297,7 +2543,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "54dd1924",
"id": "73f8dc31",
"metadata": {
"nbgrader": {
"grade": true,
@@ -2329,6 +2575,7 @@
" test_unit_benchmark_suite()\n",
" test_unit_tinymlperf()\n",
" test_unit_optimization_comparison()\n",
" test_unit_normalized_scoring()\n",
"\n",
" print(\"\\nRunning integration scenarios...\")\n",
"\n",
@@ -2467,7 +2714,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "a291734b",
"id": "f526d238",
"metadata": {},
"outputs": [],
"source": [
@@ -2479,7 +2726,7 @@
},
{
"cell_type": "markdown",
"id": "b7f4a27d",
"id": "fea34d89",
"metadata": {
"cell_marker": "\"\"\""
},
@@ -2527,7 +2774,7 @@
},
{
"cell_type": "markdown",
"id": "db353c04",
"id": "aadfb85c",
"metadata": {
"cell_marker": "\"\"\""
},
@@ -2023,203 +2023,7 @@ TinyMLPerf is MLPerf for embedded/edge devices:
# %% [markdown]
"""
## 4.5 Normalized Metrics - Fair Comparison Across Different Hardware
### The Hardware Problem
Imagine two students submit their optimizations:
- **Alice** (M3 Mac, 16GB RAM): "My model runs at 50ms latency!"
- **Bob** (2015 laptop, 4GB RAM): "My model runs at 200ms latency!"
Who optimized better? **You can't tell from raw numbers!**
Alice's hardware is 4x faster. If Bob achieved 200ms on old hardware, he might have optimized MORE aggressively than Alice. Raw metrics are unfair.
### The Solution: Relative Improvement Metrics
Instead of absolute performance, measure **relative improvement** from YOUR baseline:
```
Speedup = Baseline Latency / Optimized Latency
Compression Ratio = Baseline Memory / Optimized Memory
Accuracy Delta = Optimized Accuracy - Baseline Accuracy
```
**Example:**
- Alice: 100ms 50ms = **2.0x speedup**
- Bob: 400ms 200ms = **2.0x speedup**
Now they're fairly compared! Both achieved 2x speedup on their hardware.
### Key Normalized Metrics for TorchPerf Olympics
**1. Speedup (for Latency Sprint)**
```python
speedup = baseline_latency / optimized_latency
# Higher is better: 2.5x means 2.5 times faster
```
**2. Compression Ratio (for Memory Challenge)**
```python
compression_ratio = baseline_memory / optimized_memory
# Higher is better: 4.0x means 4 times smaller
```
**3. Accuracy Preservation (for All Events)**
```python
accuracy_delta = optimized_accuracy - baseline_accuracy
# Closer to 0 is better: -0.02 means 2% accuracy drop
```
**4. Efficiency Score (for All-Around)**
```python
efficiency = (speedup * compression_ratio) / max(1.0, abs(accuracy_delta))
# Balances all metrics
```
### Why This Matters for Your Competition
**Without normalization:**
- Newest hardware wins unfairly
- Focus shifts to "who has the best laptop"
- Optimization skill doesn't matter
**With normalization:**
- Everyone competes on **optimization skill**
- Hardware differences are eliminated
- Focus is on relative improvement
**Real MLPerf Example:**
```
NVIDIA A100 submission: 2.1ms (absolute) 3.5x speedup (relative)
Google TPU submission: 1.8ms (absolute) 4.2x speedup (relative)
Winner: Google (better speedup despite slower absolute time)
```
### Implementing Normalized Scoring
"""
# %% [markdown]
"""
Let's implement a helper function to calculate normalized scores for the competition:
"""
# %% nbgrader={"grade": false, "grade_id": "normalized-scoring", "locked": false}
#| export
def calculate_normalized_scores(baseline_results: dict,
optimized_results: dict) -> dict:
"""
Calculate normalized performance metrics for fair competition comparison.
This function converts absolute measurements into relative improvements,
enabling fair comparison across different hardware platforms.
Args:
baseline_results: Dict with keys: 'latency', 'memory', 'accuracy'
optimized_results: Dict with same keys as baseline_results
Returns:
Dict with normalized metrics:
- speedup: Relative latency improvement (higher is better)
- compression_ratio: Relative memory reduction (higher is better)
- accuracy_delta: Absolute accuracy change (closer to 0 is better)
- efficiency_score: Combined metric balancing all factors
Example:
>>> baseline = {'latency': 100.0, 'memory': 12.0, 'accuracy': 0.89}
>>> optimized = {'latency': 40.0, 'memory': 3.0, 'accuracy': 0.87}
>>> scores = calculate_normalized_scores(baseline, optimized)
>>> print(f"Speedup: {scores['speedup']:.2f}x")
Speedup: 2.50x
"""
# Calculate speedup (higher is better)
speedup = baseline_results['latency'] / optimized_results['latency']
# Calculate compression ratio (higher is better)
compression_ratio = baseline_results['memory'] / optimized_results['memory']
# Calculate accuracy delta (closer to 0 is better, negative means degradation)
accuracy_delta = optimized_results['accuracy'] - baseline_results['accuracy']
# Calculate efficiency score (combined metric)
# Penalize accuracy loss: the more accuracy you lose, the lower your score
accuracy_penalty = max(1.0, 1.0 - accuracy_delta) if accuracy_delta < 0 else 1.0
efficiency_score = (speedup * compression_ratio) / accuracy_penalty
return {
'speedup': speedup,
'compression_ratio': compression_ratio,
'accuracy_delta': accuracy_delta,
'efficiency_score': efficiency_score,
'baseline': baseline_results.copy(),
'optimized': optimized_results.copy()
}
# %% [markdown]
"""
### 🧪 Unit Test: Normalized Scoring
**This is a unit test** - it validates that normalized scoring correctly calculates relative improvements.
"""
# %% nbgrader={"grade": true, "grade_id": "test-normalized-scoring", "locked": true, "points": 1}
def test_unit_normalized_scoring():
"""Test normalized scoring calculation."""
print("🔬 Unit Test: Normalized Scoring Calculation...")
# Test Case 1: Standard optimization (speedup + compression)
baseline = {'latency': 100.0, 'memory': 12.0, 'accuracy': 0.89}
optimized = {'latency': 40.0, 'memory': 3.0, 'accuracy': 0.87}
scores = calculate_normalized_scores(baseline, optimized)
assert abs(scores['speedup'] - 2.5) < 0.01, "Speedup calculation incorrect"
assert abs(scores['compression_ratio'] - 4.0) < 0.01, "Compression ratio incorrect"
assert abs(scores['accuracy_delta'] - (-0.02)) < 0.001, "Accuracy delta incorrect"
print(" ✅ Standard optimization scoring works")
# Test Case 2: Extreme optimization (high speedup, accuracy loss)
optimized_extreme = {'latency': 20.0, 'memory': 1.5, 'accuracy': 0.75}
scores_extreme = calculate_normalized_scores(baseline, optimized_extreme)
assert scores_extreme['speedup'] > 4.0, "Extreme speedup not detected"
assert scores_extreme['accuracy_delta'] < -0.1, "Large accuracy loss not detected"
print(" ✅ Extreme optimization scoring works")
# Test Case 3: Conservative optimization (minimal changes)
optimized_conservative = {'latency': 90.0, 'memory': 11.0, 'accuracy': 0.89}
scores_conservative = calculate_normalized_scores(baseline, optimized_conservative)
assert abs(scores_conservative['accuracy_delta']) < 0.01, "Accuracy preservation not detected"
print(" ✅ Conservative optimization scoring works")
# Test Case 4: Accuracy improvement (rare but possible)
optimized_better = {'latency': 80.0, 'memory': 10.0, 'accuracy': 0.91}
scores_better = calculate_normalized_scores(baseline, optimized_better)
assert scores_better['accuracy_delta'] > 0, "Accuracy improvement not detected"
print(" ✅ Accuracy improvement scoring works")
print("📈 Progress: Normalized Scoring ✓\n")
test_unit_normalized_scoring()
# %% [markdown]
"""
### Key Takeaways
1. **Always report relative improvements, not absolute numbers**
2. **Speedup and compression ratio are the primary metrics**
3. **Accuracy delta shows the optimization cost**
4. **Efficiency score balances all factors for All-Around event**
**In Module 20**, you'll use `calculate_normalized_scores()` to generate your competition submission!
"""
# %% [markdown]
"""
## 4.6 Combination Strategies - Preparing for TorchPerf Olympics
## 4.5 Combination Strategies - Preparing for TorchPerf Olympics
You've learned individual optimizations (M14-18). Now it's time to combine them strategically! The order and parameters matter significantly for final performance.
@@ -2340,7 +2144,6 @@ def test_module():
test_unit_benchmark_suite()
test_unit_tinymlperf()
test_unit_optimization_comparison()
test_unit_normalized_scoring()
print("\nRunning integration scenarios...")