File size: 14,984 Bytes
e10a4c7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21635bb
 
 
 
 
 
 
 
e10a4c7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21635bb
 
 
 
 
e10a4c7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
bc70d3d
e10a4c7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
bc70d3d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e10a4c7
 
 
 
 
 
bc70d3d
e10a4c7
bc70d3d
 
 
 
 
 
 
 
 
 
e10a4c7
bc70d3d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
import numpy as np
import pandas as pd

def estimate_inference_cost(model_size_gb, quantization="FP32"):
    """
    Estimate inference cost per 1M requests based on model size and quantization.

    Args:
        model_size_gb: Model size in GB
        quantization: Quantization type (FP32, FP16, INT8, INT4, Mixed)

    Returns:
        dict with cost metrics
    """
    # Step 1: Determine GPU tier based on model size
    if model_size_gb <= 4:
        gpu_name = "T4"
        gpu_cost_per_hour = 0.35
        throughput_base = 200
    elif model_size_gb <= 10:
        gpu_name = "V100"
        gpu_cost_per_hour = 2.50
        throughput_base = 120
    elif model_size_gb <= 20:
        gpu_name = "A100"
        gpu_cost_per_hour = 4.10
        throughput_base = 80
    else:
        num_gpus = int(np.ceil(model_size_gb / 20))
        gpu_name = f"A100x{num_gpus}"
        gpu_cost_per_hour = 4.10 * num_gpus
        throughput_base = 80

    # Step 2: Adjust throughput for quantization (quantized models are faster)
    quantization_speedup = {
        "FP32": 1.0,
        "FP16": 1.8,
        "INT8": 2.5,
        "INT4": 3.5,
        "Mixed": 2.0
    }
    throughput_qps = throughput_base * quantization_speedup.get(quantization, 1.0)

    # Step 3: Calculate cost per 1M requests
    cost_per_second = gpu_cost_per_hour / 3600
    cost_per_inference = cost_per_second / throughput_qps
    cost_per_1M = cost_per_inference * 1_000_000

    return {
        "cost_per_1M": cost_per_1M,
        "gpu_tier": gpu_name,
        "throughput_qps": throughput_qps,
        "gpu_cost_per_hour": gpu_cost_per_hour
    }

def estimate_latency(model_size_gb, quantization="FP32"):
    """
    Estimate inference latency in milliseconds.
    Latency inversely proportional to throughput.
    """
    cost_info = estimate_inference_cost(model_size_gb, quantization)
    # Latency approximation: 1000ms / QPS (for single request)
    latency_ms = 1000.0 / cost_info["throughput_qps"]
    return latency_ms

def estimate_memory_footprint(model_size_gb, quantization="FP32"):
    """
    Estimate peak memory footprint during inference.
    Memory = model size + activation overhead
    """
    # Activation overhead typically 20-40% of model size
    overhead_factor = 1.3
    memory_gb = model_size_gb * overhead_factor
    return memory_gb

def estimate_energy_consumption(model_size_gb, quantization="FP32"):
    """
    Estimate energy consumption in Watts.
    Based on GPU tier and utilization.
    """
    cost_info = estimate_inference_cost(model_size_gb, quantization)

    # GPU power consumption (TDP)
    gpu_power = {
        "T4": 70,      # 70W
        "V100": 250,   # 250W
        "A100": 400    # 400W
    }

    # Extract base GPU type
    gpu_type = cost_info["gpu_tier"]
    if "x" in gpu_type:
        # Multiple GPUs
        base_type = gpu_type.split("x")[0]
        num_gpus = int(gpu_type.split("x")[1])
        power = gpu_power.get(base_type, 400) * num_gpus
    else:
        power = gpu_power.get(gpu_type, 400)

    # Assume 70% utilization during inference
    power_watts = power * 0.7
    return power_watts

def generate_pareto_front_data():
    """Generate mock Pareto front data with all objectives."""
    np.random.seed(42)

    # Generate many model configurations (100+ points)
    num_models = 150

    # Create models with various sizes and accuracies
    model_sizes = []
    accuracies = []

    # Generate diverse model configurations
    for i in range(num_models):
        size = np.random.uniform(2, 35)

        # Base accuracy trend: larger models tend to be more accurate
        # But with significant variance to create interesting Pareto front
        base_acc = 70 + (size / 35) * 20  # 70-90% range
        noise = np.random.normal(0, 3)  # More variance
        acc = np.clip(base_acc + noise, 68, 92)

        model_sizes.append(size)
        accuracies.append(acc)

    # Calculate other objectives for each model
    # Use mixed quantization types for diversity
    quantization_types = np.random.choice(['FP32', 'FP16', 'INT8', 'INT4'], num_models)

    costs = []
    throughputs = []
    latencies = []
    memories = []
    energies = []

    for i in range(num_models):
        quant = quantization_types[i]
        size = model_sizes[i]

        cost_info = estimate_inference_cost(size, quant)
        costs.append(cost_info['cost_per_1M'])
        throughputs.append(cost_info['throughput_qps'])

        latencies.append(estimate_latency(size, quant))
        memories.append(estimate_memory_footprint(size, quant))
        energies.append(estimate_energy_consumption(size, quant))

    df = pd.DataFrame({
        'accuracy': accuracies,
        'size': model_sizes,
        'cost': costs,
        'throughput': throughputs,
        'latency': latencies,
        'memory': memories,
        'energy': energies
    })

    # Calculate Pareto front for accuracy vs size (default)
    # A point is on the Pareto front if no other point dominates it
    # (dominates = higher accuracy AND smaller size)
    df['is_pareto_accuracy_size'] = False

    for i in range(len(df)):
        is_dominated = False
        for j in range(len(df)):
            if i != j:
                # Check if point j dominates point i
                if (df.iloc[j]['accuracy'] >= df.iloc[i]['accuracy'] and
                    df.iloc[j]['size'] <= df.iloc[i]['size'] and
                    (df.iloc[j]['accuracy'] > df.iloc[i]['accuracy'] or
                     df.iloc[j]['size'] < df.iloc[i]['size'])):
                    is_dominated = True
                    break
        if not is_dominated:
            df.at[i, 'is_pareto_accuracy_size'] = True

    return df

def calculate_pareto_front(df, obj1, obj2, obj1_maximize=True, obj2_maximize=False):
    """
    Calculate Pareto front for any two objectives.

    Args:
        df: DataFrame with objective columns
        obj1: First objective column name
        obj2: Second objective column name
        obj1_maximize: True if obj1 should be maximized, False if minimized
        obj2_maximize: True if obj2 should be maximized, False if minimized

    Returns:
        DataFrame with is_pareto column added
    """
    df = df.copy()
    df['is_pareto'] = False

    for i in range(len(df)):
        is_dominated = False
        for j in range(len(df)):
            if i != j:
                # Check if point j dominates point i
                obj1_better = (df.iloc[j][obj1] >= df.iloc[i][obj1]) if obj1_maximize else (df.iloc[j][obj1] <= df.iloc[i][obj1])
                obj2_better = (df.iloc[j][obj2] >= df.iloc[i][obj2]) if obj2_maximize else (df.iloc[j][obj2] <= df.iloc[i][obj2])
                obj1_strictly_better = (df.iloc[j][obj1] > df.iloc[i][obj1]) if obj1_maximize else (df.iloc[j][obj1] < df.iloc[i][obj1])
                obj2_strictly_better = (df.iloc[j][obj2] > df.iloc[i][obj2]) if obj2_maximize else (df.iloc[j][obj2] < df.iloc[i][obj2])

                if obj1_better and obj2_better and (obj1_strictly_better or obj2_strictly_better):
                    is_dominated = True
                    break
        if not is_dominated:
            df.at[i, 'is_pareto'] = True

    return df

def generate_optimization_progress(budget_hours=2):
    """Generate mock optimization progress data over time."""
    np.random.seed(42)

    # Generate time points
    num_points = 20
    time_points = np.linspace(0, budget_hours, num_points)

    # Accuracy starts lower for LLMs and gradually improves
    base_accuracy = 75
    accuracy_trend = base_accuracy + np.log1p(time_points) * 4
    accuracy = [min(acc + np.random.uniform(-0.3, 0.3), 89) for acc in accuracy_trend]

    # Model size starts large and decreases (GB for LLMs)
    initial_size = 35
    size_reduction = initial_size * (1 - 0.70 * (time_points / budget_hours))
    model_size = [max(s + np.random.uniform(-0.5, 0.5), 2) for s in size_reduction]

    return pd.DataFrame({
        'search_time': time_points,
        'accuracy': accuracy,
        'model_size_gb': model_size
    })

def generate_all_objectives_progress(budget_hours=2):
    """Generate progress data for all optimization objectives over time."""
    np.random.seed(42)

    num_points = 20
    time_points = np.linspace(0, budget_hours, num_points)

    # Accuracy: starts at 72%, improves to ~85%
    base_accuracy = 72
    accuracy_trend = base_accuracy + np.log1p(time_points) * 5.5
    accuracy = [min(acc + np.random.uniform(-0.3, 0.3), 85.2) for acc in accuracy_trend]

    # Model size: starts at 32.5 GB, decreases to ~6.2 GB
    initial_size = 32.5
    size_reduction = initial_size * (1 - 0.81 * (time_points / budget_hours))
    size = [max(s + np.random.uniform(-0.5, 0.5), 6.2) for s in size_reduction]

    # Calculate other metrics based on size and quantization progression
    # Quantization improves gradually from FP32 -> FP16 -> INT8 -> INT4 over time
    # Use a mix to create smoother transitions
    quantizations = (
        ['FP32', 'FP32', 'Mixed', 'Mixed', 'FP16'] +
        ['FP16', 'FP16', 'Mixed', 'INT8', 'INT8'] +
        ['INT8', 'INT8', 'Mixed', 'INT4', 'INT4'] +
        ['INT4', 'INT4', 'INT4', 'INT4', 'INT4']
    )

    cost = []
    throughput = []
    latency = []
    memory = []
    energy = []

    for i in range(num_points):
        quant = quantizations[i]
        model_size = size[i]

        cost_info = estimate_inference_cost(model_size, quant)
        cost.append(cost_info['cost_per_1M'])
        throughput.append(cost_info['throughput_qps'])

        # Add slight variation to latency for smoother visualization
        base_latency = estimate_latency(model_size, quant)
        latency_variation = np.random.uniform(-0.1, 0.1)
        latency.append(max(0.1, base_latency * (1 + latency_variation)))

        memory.append(estimate_memory_footprint(model_size, quant))
        energy.append(estimate_energy_consumption(model_size, quant))

    return pd.DataFrame({
        'time': time_points,
        'accuracy': accuracy,
        'size': size,
        'cost': cost,
        'throughput': throughput,
        'latency': latency,
        'memory': memory,
        'energy': energy
    })

def generate_discovered_models():
    """Generate mock discovered models with their specifications (6 Pareto-optimal configs)."""
    models = [
        {
            'name': 'Optimized-7B-Q8',
            'params': '7.2B',
            'accuracy': 85.2,
            'size_gb': 10.2,
            'quantization': 'INT8'
        },
        {
            'name': 'Optimized-7B-Q4',
            'params': '7.2B',
            'accuracy': 83.8,
            'size_gb': 6.2,
            'quantization': 'INT4'
        },
        {
            'name': 'Optimized-3B-Q8',
            'params': '3.5B',
            'accuracy': 79.2,
            'size_gb': 4.8,
            'quantization': 'INT8'
        },
        {
            'name': 'Optimized-7B-FP16',
            'params': '7.2B',
            'accuracy': 86.5,
            'size_gb': 14.4,
            'quantization': 'FP16'
        },
        {
            'name': 'Optimized-3B-Q4',
            'params': '3.5B',
            'accuracy': 77.8,
            'size_gb': 2.4,
            'quantization': 'INT4'
        },
        {
            'name': 'Optimized-7B-Mixed',
            'params': '7.2B',
            'accuracy': 84.6,
            'size_gb': 8.5,
            'quantization': 'Mixed'
        }
    ]

    return models

def get_base_models():
    """Get list of available base LLM models (recent, single-GPU optimizable)."""
    return [
        "Llama 3.2 3B Instruct",
        "Llama 3.1 8B Instruct",
        "Mistral 7B v0.3",
        "Phi-3.5 Mini (3.8B)",
        "Qwen2.5 3B Instruct",
        "Qwen2.5 7B Instruct",
        "Gemma 2 2B",
        "Gemma 2 9B",
        "Yi 1.5 9B",
        "StableLM 2 1.6B"
    ]

def get_target_hardware():
    """Get list of target hardware platforms for LLM deployment."""
    return {
        "NVIDIA Datacenter": [
            "H100 (80GB)",
            "A100 (80GB)",
            "A100 (40GB)",
            "L40S (48GB)",
            "A10 (24GB)"
        ],
        "NVIDIA Workstation/Consumer": [
            "RTX 4090 (24GB)",
            "RTX 4080 (16GB)",
            "RTX 3090 (24GB)",
            "RTX 3080 Ti (12GB)"
        ],
        "AMD Datacenter": [
            "MI300X (192GB)",
            "MI250X (128GB)",
            "MI210 (64GB)"
        ],
        "AMD Consumer": [
            "RX 7900 XTX (24GB)",
            "RX 7900 XT (20GB)"
        ],
        "Edge Hardware": [
            "Jetson AGX Orin (64GB)",
            "Jetson Orin NX (16GB)",
            "Jetson Orin Nano (8GB)",
            "Apple M2 Ultra (192GB)"
        ]
    }

def get_hardware_specs(hardware_name):
    """Get specifications for a given hardware platform."""
    # Parse hardware name to extract key info
    hardware_specs = {
        # NVIDIA Datacenter
        "H100 (80GB)": {"vram": 80, "compute": "Hopper", "tflops": 1979, "category": "datacenter"},
        "A100 (80GB)": {"vram": 80, "compute": "Ampere", "tflops": 312, "category": "datacenter"},
        "A100 (40GB)": {"vram": 40, "compute": "Ampere", "tflops": 312, "category": "datacenter"},
        "L40S (48GB)": {"vram": 48, "compute": "Ada Lovelace", "tflops": 362, "category": "datacenter"},
        "A10 (24GB)": {"vram": 24, "compute": "Ampere", "tflops": 125, "category": "datacenter"},

        # NVIDIA Workstation/Consumer
        "RTX 4090 (24GB)": {"vram": 24, "compute": "Ada Lovelace", "tflops": 83, "category": "consumer"},
        "RTX 4080 (16GB)": {"vram": 16, "compute": "Ada Lovelace", "tflops": 49, "category": "consumer"},
        "RTX 3090 (24GB)": {"vram": 24, "compute": "Ampere", "tflops": 36, "category": "consumer"},
        "RTX 3080 Ti (12GB)": {"vram": 12, "compute": "Ampere", "tflops": 34, "category": "consumer"},

        # AMD
        "MI300X (192GB)": {"vram": 192, "compute": "CDNA 3", "tflops": 1307, "category": "datacenter"},
        "MI250X (128GB)": {"vram": 128, "compute": "CDNA 2", "tflops": 383, "category": "datacenter"},
        "MI210 (64GB)": {"vram": 64, "compute": "CDNA 2", "tflops": 181, "category": "datacenter"},
        "RX 7900 XTX (24GB)": {"vram": 24, "compute": "RDNA 3", "tflops": 61, "category": "consumer"},
        "RX 7900 XT (20GB)": {"vram": 20, "compute": "RDNA 3", "tflops": 51, "category": "consumer"},

        # Edge
        "Jetson AGX Orin (64GB)": {"vram": 64, "compute": "Ampere", "tops": 275, "category": "edge"},
        "Jetson Orin NX (16GB)": {"vram": 16, "compute": "Ampere", "tops": 100, "category": "edge"},
        "Jetson Orin Nano (8GB)": {"vram": 8, "compute": "Ampere", "tops": 40, "category": "edge"},
        "Apple M2 Ultra (192GB)": {"vram": 192, "compute": "ARM", "tflops": 28, "category": "edge"}
    }

    return hardware_specs.get(hardware_name, {"vram": 24, "compute": "Unknown", "category": "unknown"})