From b52b7625452ca8096bc79ef5f6f40424ccea716a Mon Sep 17 00:00:00 2001 From: Vijay Janapa Reddi Date: Sun, 9 Nov 2025 09:15:13 -0500 Subject: [PATCH] feat(profiler): Add helper functions for optimization modules - Add quick_profile() for simplified profiling interface - Add analyze_weight_distribution() for compression module - Both functions will be used by modules 15-18 --- modules/source/15_profiling/profiling_dev.py | 100 +++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/modules/source/15_profiling/profiling_dev.py b/modules/source/15_profiling/profiling_dev.py index ea3cb481..8cb97d5d 100644 --- a/modules/source/15_profiling/profiling_dev.py +++ b/modules/source/15_profiling/profiling_dev.py @@ -736,6 +736,106 @@ class Profiler: } ### END SOLUTION +# %% [markdown] +""" +## Helper Functions - Quick Profiling Utilities + +These helper functions provide simplified interfaces for common profiling tasks. +They make it easy to quickly profile models and analyze characteristics. +""" + +# %% +#| export +def quick_profile(model, input_tensor, profiler=None): + """ + Quick profiling function for immediate insights. + + Provides a simplified interface for profiling that displays key metrics + in a student-friendly format. + + Args: + model: Model to profile + input_tensor: Input data for profiling + profiler: Optional Profiler instance (creates new one if None) + + Returns: + dict: Profile results with key metrics + + Example: + >>> model = Linear(128, 64) + >>> input_data = Tensor(np.random.randn(16, 128)) + >>> results = quick_profile(model, input_data) + >>> # Displays formatted output automatically + """ + if profiler is None: + profiler = Profiler() + + profile = profiler.profile_forward_pass(model, input_tensor) + + # Display formatted results + print("🔬 Quick Profile Results:") + print(f" Parameters: {profile['parameters']:,}") + print(f" FLOPs: {profile['flops']:,}") + print(f" Latency: {profile['latency_ms']:.2f} ms") + print(f" Memory: {profile['peak_memory_mb']:.2f} MB") + print(f" Bottleneck: {profile['bottleneck']}") + print(f" Efficiency: {profile['computational_efficiency']*100:.1f}%") + + return profile + +#| export +def analyze_weight_distribution(model, percentiles=[10, 25, 50, 75, 90]): + """ + Analyze weight distribution for compression insights. + + Helps understand which weights are small and might be prunable. + Used by Module 17 (Compression) to motivate pruning. + + Args: + model: Model to analyze + percentiles: List of percentiles to compute + + Returns: + dict: Weight distribution statistics + + Example: + >>> model = Linear(512, 512) + >>> stats = analyze_weight_distribution(model) + >>> print(f"Weights < 0.01: {stats['below_threshold_001']:.1f}%") + """ + # Collect all weights + weights = [] + if hasattr(model, 'parameters'): + for param in model.parameters(): + weights.extend(param.data.flatten().tolist()) + elif hasattr(model, 'weight'): + weights.extend(model.weight.data.flatten().tolist()) + else: + return {'error': 'No weights found'} + + weights = np.array(weights) + abs_weights = np.abs(weights) + + # Calculate statistics + stats = { + 'total_weights': len(weights), + 'mean': float(np.mean(abs_weights)), + 'std': float(np.std(abs_weights)), + 'min': float(np.min(abs_weights)), + 'max': float(np.max(abs_weights)), + } + + # Percentile analysis + for p in percentiles: + stats[f'percentile_{p}'] = float(np.percentile(abs_weights, p)) + + # Threshold analysis (useful for pruning) + for threshold in [0.001, 0.01, 0.1]: + below = np.sum(abs_weights < threshold) / len(weights) * 100 + stats[f'below_threshold_{str(threshold).replace(".", "")}'] = below + + return stats + # %% [markdown] """ ## Parameter Counting - Model Size Analysis