-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.py
More file actions
340 lines (296 loc) · 14.5 KB
/
Copy pathmain.py
File metadata and controls
340 lines (296 loc) · 14.5 KB
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
#!/usr/bin/env python3
"""
ML Inference Optimizer
A framework for optimizing and benchmarking ML inference with various optimization techniques.
"""
import os
import sys
import logging
import argparse
from pathlib import Path
from typing import Dict, Any, Optional
from config.config_loader import load_config, save_config, get_optimized_config
from config.config_schema import OptimizerConfig
# Initialize components dynamically based on configuration
def init_components(config: OptimizerConfig):
"""
Initialize all components based on the configuration.
Args:
config: OptimizerConfig object with configuration
Returns:
Dictionary of initialized components
"""
components = {}
# Configure logging
logging.basicConfig(
level=getattr(logging, config.log_level),
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[
logging.StreamHandler(sys.stdout),
logging.FileHandler(os.path.join(config.output_dir, "optimizer.log"), mode='w')
]
)
logger = logging.getLogger(__name__)
logger.info(f"ML Inference Optimizer starting with {config.hardware.gpu_count} GPUs")
# Create output directory
os.makedirs(config.output_dir, exist_ok=True)
# Initialize model
if config.model.model_name_or_path:
try:
from baseline.model_loader import load_model
logger.info(f"Loading model: {config.model.model_name_or_path}")
model_info = load_model(
model_name_or_path=config.model.model_name_or_path,
model_type=config.model.model_type,
precision=config.model.precision,
trust_remote_code=config.model.trust_remote_code
)
components["model"] = model_info["model"]
components["tokenizer"] = model_info.get("tokenizer")
components["processor"] = model_info.get("processor")
logger.info(f"Model loaded successfully: {type(components['model']).__name__}")
except Exception as e:
logger.error(f"Failed to load model: {str(e)}")
raise
# Initialize parallelism if enabled
if any([config.parallelism.tensor_parallel_size > 1,
config.parallelism.sequence_parallel,
config.parallelism.pipeline_parallel_size > 1]):
try:
from parallelism.orchestrator import ParallelizationOrchestrator
logger.info("Initializing parallelization orchestrator")
orchestrator = ParallelizationOrchestrator(
model=components.get("model"),
tensor_parallel_size=config.parallelism.tensor_parallel_size,
sequence_parallel=config.parallelism.sequence_parallel,
pipeline_parallel_size=config.parallelism.pipeline_parallel_size,
data_parallel_size=config.parallelism.data_parallel_size,
communication_dtype=config.parallelism.communication_dtype
)
components["orchestrator"] = orchestrator
# Update model with parallelized version if model was loaded
if "model" in components:
components["model"] = orchestrator.parallelize_model()
logger.info("Model parallelized successfully")
except Exception as e:
logger.error(f"Failed to initialize parallelism: {str(e)}")
raise
# Initialize optimized kernels if enabled
if any([config.kernels.use_flash_attention,
config.kernels.use_fused_mlp,
config.kernels.use_triton_kernels]):
try:
logger.info("Initializing optimized kernels")
if config.kernels.use_flash_attention:
from kernels.attention.flash_attention import apply_flash_attention
if "model" in components:
components["model"] = apply_flash_attention(components["model"])
logger.info("Flash Attention applied to model")
if config.kernels.use_fused_mlp:
from kernels.mlp.fused_mlp import apply_fused_mlp
if "model" in components:
components["model"] = apply_fused_mlp(components["model"])
logger.info("Fused MLP applied to model")
if config.kernels.use_triton_kernels:
# Initialize Triton kernels if available
try:
import triton
from kernels.triton.flash_attention_kernels import compile_flash_attention_kernels
from kernels.triton.mlp_kernels import compile_mlp_kernels
from kernels.triton.layernorm_kernels import compile_layernorm_kernels
logger.info("Initializing Triton kernels")
compile_flash_attention_kernels()
compile_mlp_kernels()
compile_layernorm_kernels()
logger.info("Triton kernels initialized successfully")
components["triton_initialized"] = True
except ImportError:
logger.warning("Triton not available. Skipping Triton kernel initialization.")
components["triton_initialized"] = False
except Exception as e:
logger.error(f"Failed to initialize optimized kernels: {str(e)}")
raise
# Initialize inference runner
try:
from baseline.inference import InferenceRunner
logger.info("Initializing inference runner")
components["inference_runner"] = InferenceRunner(
model=components.get("model"),
tokenizer=components.get("tokenizer"),
processor=components.get("processor"),
batch_size=config.model.max_batch_size,
sequence_length=config.model.max_sequence_length,
use_cache=config.model.use_cache
)
logger.info("Inference runner initialized")
except Exception as e:
logger.error(f"Failed to initialize inference runner: {str(e)}")
raise
# Initialize profiler if enabled
if config.profiling.enable_profiling:
try:
from profiling.torch_profiler import TorchProfilerWrapper
from profiling.bottleneck_analyzer import BottleneckAnalyzer
logger.info("Initializing profiler")
profiler = TorchProfilerWrapper(
save_dir=os.path.join(config.profiling.profiler_output_dir, "torch_profile"),
num_iterations=config.profiling.profile_iterations,
save_timeline=config.profiling.save_timeline
)
components["profiler"] = profiler
if config.profiling.bottleneck_analysis:
analyzer = BottleneckAnalyzer(
model=components.get("model"),
profiler=profiler,
output_dir=os.path.join(config.profiling.profiler_output_dir, "bottleneck_analysis")
)
components["bottleneck_analyzer"] = analyzer
logger.info("Bottleneck analyzer initialized")
except Exception as e:
logger.error(f"Failed to initialize profiler: {str(e)}")
raise
# Initialize benchmarker
try:
from benchmarks.runners import BenchmarkRunner
logger.info("Initializing benchmark runner")
components["benchmark_runner"] = BenchmarkRunner(
inference_runner=components.get("inference_runner"),
batch_sizes=config.benchmark.batch_sizes,
sequence_lengths=config.benchmark.sequence_lengths,
num_iterations=config.benchmark.num_iterations,
warmup_iterations=config.benchmark.warmup_iterations,
metrics=config.benchmark.metrics,
output_dir=os.path.join(config.output_dir, config.benchmark.report_path)
)
logger.info("Benchmark runner initialized")
except Exception as e:
logger.error(f"Failed to initialize benchmark runner: {str(e)}")
raise
# Initialize dashboard if enabled
if config.dashboard.enable_dashboard:
try:
from dashboard.app import create_dashboard
logger.info("Initializing dashboard")
components["dashboard"] = create_dashboard(
config=config,
host=config.dashboard.host,
port=config.dashboard.port,
update_interval=config.dashboard.update_interval_seconds
)
logger.info(f"Dashboard initialized at http://{config.dashboard.host}:{config.dashboard.port}")
except Exception as e:
logger.error(f"Failed to initialize dashboard: {str(e)}")
# Non-critical component, continue without dashboard
return components
def run_optimizer(config: OptimizerConfig, components: Dict[str, Any],
profiling_only: bool = False, benchmark_only: bool = False):
"""
Run the ML inference optimizer with the given configuration and components.
Args:
config: OptimizerConfig object with configuration
components: Dictionary of initialized components
profiling_only: If True, only run profiling without optimization
benchmark_only: If True, only run benchmarking without optimization
"""
logger = logging.getLogger(__name__)
# Save the current configuration
save_config(config, os.path.join(config.output_dir, "used_config.yaml"))
# Run profiling if enabled
if config.profiling.enable_profiling or profiling_only:
logger.info("Running profiling")
if "profiler" in components and "inference_runner" in components:
profiler = components["profiler"]
inference_runner = components["inference_runner"]
# Profile model inference
with profiler:
for _ in range(config.profiling.profile_iterations):
inference_runner.run_inference(
batch_size=config.model.max_batch_size,
sequence_length=config.model.max_sequence_length
)
# Run bottleneck analysis if enabled
if config.profiling.bottleneck_analysis and "bottleneck_analyzer" in components:
analyzer = components["bottleneck_analyzer"]
bottlenecks = analyzer.analyze()
logger.info(f"Bottlenecks identified: {bottlenecks}")
# Output recommendations based on bottleneck analysis
from dashboard.recommendation import generate_optimization_recommendations
recommendations = generate_optimization_recommendations(bottlenecks, config)
# Save recommendations
recommendations_path = os.path.join(config.output_dir, "optimization_recommendations.txt")
with open(recommendations_path, "w") as f:
f.write("\n".join(recommendations))
logger.info(f"Optimization recommendations saved to {recommendations_path}")
# Stop here if only profiling
if profiling_only:
return
# Run benchmarking
if "benchmark_runner" in components:
logger.info("Running benchmarks")
benchmark_runner = components["benchmark_runner"]
results = benchmark_runner.run_benchmarks()
# Generate report
from benchmarks.reporting import generate_report
report_path = os.path.join(config.output_dir, "benchmark_report.html")
generate_report(results, report_path)
logger.info(f"Benchmark report generated: {report_path}")
# Start dashboard if enabled
if config.dashboard.enable_dashboard and "dashboard" in components:
logger.info(f"Starting dashboard at http://{config.dashboard.host}:{config.dashboard.port}")
dashboard = components["dashboard"]
dashboard.run_server(
debug=False,
host=config.dashboard.host,
port=config.dashboard.port
)
def main():
"""Main entry point for the ML inference optimizer."""
parser = argparse.ArgumentParser(description="ML Inference Optimizer")
parser.add_argument("--config", type=str, help="Path to configuration file")
parser.add_argument("--model", type=str, help="Model name or path")
parser.add_argument("--output-dir", type=str, help="Output directory")
parser.add_argument("--profiling-only", action="store_true", help="Run only profiling without optimization")
parser.add_argument("--benchmark-only", action="store_true", help="Run only benchmarking without optimization")
parser.add_argument("--gpus", type=int, help="Number of GPUs to use")
parser.add_argument("--batch-size", type=int, help="Maximum batch size")
parser.add_argument("--sequence-length", type=int, help="Maximum sequence length")
parser.add_argument("--precision", choices=["fp32", "fp16", "bf16"], help="Model precision")
parser.add_argument("--dashboard", action="store_true", help="Enable dashboard")
parser.add_argument("--dashboard-port", type=int, default=8050, help="Dashboard port")
args = parser.parse_args()
# Load configuration
if args.model:
# Generate optimized config for the specified model
hardware_config = {"gpu_count": args.gpus} if args.gpus else None
config = get_optimized_config(args.model, hardware_config)
else:
# Load from config file or use default
config = load_config(args.config)
# Override config with command line arguments
if args.output_dir:
config.output_dir = args.output_dir
if args.gpus:
config.hardware.gpu_count = args.gpus
if args.batch_size:
config.model.max_batch_size = args.batch_size
if args.sequence_length:
config.model.max_sequence_length = args.sequence_length
if args.precision:
config.model.precision = args.precision
if args.dashboard:
config.dashboard.enable_dashboard = True
if args.dashboard_port:
config.dashboard.port = args.dashboard_port
# Create output directory
os.makedirs(config.output_dir, exist_ok=True)
# Initialize components
components = init_components(config)
# Run optimizer
run_optimizer(
config=config,
components=components,
profiling_only=args.profiling_only,
benchmark_only=args.benchmark_only
)
if __name__ == "__main__":
main()