CoolFace
Apppublic

ASesYusuf1/SESA_Audio_Separation

sourceHugging Facemitupdated 6mo agoView on Hugging Face
14likes
pytorch_backend.py622 linesDownload Raw Back to root
1# coding: utf-82__author__ = 'PyTorch Backend Implementation'3 4import os5import pickle6import numpy as np7import torch8import torch.nn as nn9from typing import Dict, Tuple, Optional, Any10import warnings11import hashlib12import time13 14# Suppress channels_last warnings for 3D audio tensors15warnings.filterwarnings("ignore", message=".*channels_last.*")16warnings.filterwarnings("ignore", message=".*rank 3.*")17 18 19class PyTorchBackend:20    """21    ULTRA-OPTIMIZED PyTorch backend for model inference.22    Provides various optimization techniques for maximum speed.23    """24    25    def __init__(self, device='cuda:0', optimize_mode='channels_last'):26        """27        Initialize ULTRA-OPTIMIZED PyTorch backend.28        29        Parameters:30        ----------31        device : str32            Device to use for inference (cuda:0, cpu, mps, etc.)33        optimize_mode : str34            Optimization mode: 'channels_last' (recommended), 'compile', 'jit', or 'default'35        """36        self.device = device37        self.optimize_mode = optimize_mode38        self.model = None39        self.compiled_model = None40        41        # Check device availability42        if device.startswith('cuda') and not torch.cuda.is_available():43            warnings.warn("CUDA not available, falling back to CPU")44            self.device = 'cpu'45        elif device == 'mps' and not torch.backends.mps.is_available():46            warnings.warn("MPS not available, falling back to CPU")47            self.device = 'cpu'48        49        # Apply ultra optimization settings50        self._apply_ultra_optimizations()51    52    def _apply_ultra_optimizations(self):53        """Apply ultra-speed optimizations globally."""54        if self.device.startswith('cuda'):55            # Enable all CUDA optimizations56            torch.backends.cudnn.benchmark = True57            torch.backends.cuda.matmul.allow_tf32 = True58            torch.backends.cudnn.allow_tf32 = True59            60            # Set optimal CUDA settings61            torch.backends.cudnn.deterministic = False62            torch.backends.cudnn.enabled = True63            64            # Enable cuBLAS optimizations65            os.environ['CUBLAS_WORKSPACE_CONFIG'] = ':4096:8'66        67        # Optimize CPU inference68        if self.device == 'cpu':69            import multiprocessing70            num_threads = multiprocessing.cpu_count()71            torch.set_num_threads(num_threads)72            torch.set_num_interop_threads(num_threads)73            print(f"CPU threads set to {num_threads}")74    75    def optimize_model(76        self,77        model: nn.Module,78        example_input: Optional[torch.Tensor] = None,79        use_amp: bool = True,80        use_channels_last: bool = True81    ) -> nn.Module:82        """83        Optimize PyTorch model for inference.84        85        Parameters:86        ----------87        model : nn.Module88            PyTorch model to optimize89        example_input : Optional[torch.Tensor]90            Example input for optimization (required for some modes)91        use_amp : bool92            Use automatic mixed precision (AMP)93        use_channels_last : bool94            Use channels-last memory format95            96        Returns:97        -------98        nn.Module99            Optimized model100        """101        print(f"Optimizing model with mode: {self.optimize_mode}")102        103        self.model = model.eval().to(self.device)104        self.use_amp = use_amp105        106        # Disable gradients for all parameters (inference only)107        for param in self.model.parameters():108            param.requires_grad = False109        110        # Apply memory format optimization (default: channels_last for CUDA)111        # Note: Audio models use 3D tensors, so channels_last is applied only where beneficial112        if use_channels_last and self.device.startswith('cuda'):113            print("  Using channels-last optimization")114            # Only apply to model if it has 4D conv layers, otherwise skip silently115            try:116                with warnings.catch_warnings():117                    warnings.simplefilter("ignore")118                    self.model = self.model.to(memory_format=torch.channels_last)119            except Exception:120                pass  # Silently skip for models that don't support channels_last121        122        # Set model to inference mode123        torch.set_grad_enabled(False)124        125        # Apply optimization based on mode126        if self.optimize_mode == 'compile':127            self.compiled_model = self._compile_model(self.model)128        elif self.optimize_mode == 'jit':129            if example_input is None:130                raise ValueError("example_input required for JIT optimization")131            self.compiled_model = self._jit_trace_model(self.model, example_input)132        elif self.optimize_mode == 'channels_last':133            self.compiled_model = self.model134        else:135            print("  Using default optimization")136            self.compiled_model = self.model137        138        # Apply fusion optimizations if possible139        try:140            if hasattr(torch.nn.utils, 'fusion'):141                self.compiled_model = torch.nn.utils.fusion.fuse_conv_bn_eval(self.compiled_model)142                print("  Conv-BN fusion applied")143        except:144            pass145        146        print("Optimization complete")147        return self.compiled_model148    149    def _compile_model(self, model: nn.Module) -> nn.Module:150        """151        Compile model using torch.compile (PyTorch 2.0+) with ULTRA optimization.152        153        Parameters:154        ----------155        model : nn.Module156            Model to compile157            158        Returns:159        -------160        nn.Module161            Compiled model162        """163        try:164            if hasattr(torch, 'compile'):165                print("  Compiling model with torch.compile")166                # Try max-autotune for best performance167                try:168                    compiled = torch.compile(model, mode='max-autotune', fullgraph=True)169                    print("  Using max-autotune mode")170                    return compiled171                except:172                    # Fallback to reduce-overhead173                    compiled = torch.compile(model, mode='reduce-overhead')174                    print("  Using reduce-overhead mode")175                    return compiled176            else:177                print("  torch.compile not available (requires PyTorch 2.0+)")178                return model179        except Exception as e:180            print(f"  Compilation failed: {e}")181            return model182    183    def _jit_trace_model(self, model: nn.Module, example_input: torch.Tensor) -> nn.Module:184        """185        Trace model using TorchScript JIT.186        187        Parameters:188        ----------189        model : nn.Module190            Model to trace191        example_input : torch.Tensor192            Example input for tracing193            194        Returns:195        -------196        nn.Module197            Traced model198        """199        try:200            print("  → Tracing model with TorchScript JIT")201            with torch.no_grad():202                traced = torch.jit.trace(model, example_input)203            traced = torch.jit.optimize_for_inference(traced)204            return traced205        except Exception as e:206            print(f"  JIT tracing failed: {e}")207            return model208    209    def save_optimized_model(self, save_path: str):210        """211        Save optimized model to file.212        213        Parameters:214        ----------215        save_path : str216            Path to save the model217        """218        if self.compiled_model is None:219            raise RuntimeError("No model has been optimized yet")220        221        try:222            # Save based on optimization mode223            if self.optimize_mode == 'jit':224                torch.jit.save(self.compiled_model, save_path)225            else:226                torch.save(self.compiled_model.state_dict(), save_path)227            print(f"✓ Model saved to: {save_path}")228        except Exception as e:229            print(f"✗ Failed to save model: {e}")230    231    def load_optimized_model(self, load_path: str, model_template: nn.Module) -> nn.Module:232        """233        Load optimized model from file.234        235        Parameters:236        ----------237        load_path : str238            Path to the saved model239        model_template : nn.Module240            Model template for loading state dict241            242        Returns:243        -------244        nn.Module245            Loaded model246        """247        try:248            if self.optimize_mode == 'jit':249                self.compiled_model = torch.jit.load(load_path, map_location=self.device)250            else:251                model_template.load_state_dict(torch.load(load_path, map_location=self.device, weights_only=False))252                self.compiled_model = model_template.eval()253            254            print(f"✓ Model loaded from: {load_path}")255            return self.compiled_model256        except (pickle.UnpicklingError, RuntimeError, EOFError) as e:257            error_details = f"""258CHECKPOINT FILE CORRUPTED259 260Error: {str(e)}261 262The checkpoint file appears to be corrupted or was not downloaded correctly.263File: {load_path}264 265Common causes:266  - File is an HTML page (wrong download URL, e.g., HuggingFace /blob/ instead of /resolve/)267  - Incomplete or interrupted download268  - Network issues during download269  - File system corruption270 271Solution:272  1. Delete the corrupted checkpoint file:273     {load_path}274  2. Re-run the application - it will automatically re-download the model275  3. If the problem persists, check that your model URL uses /resolve/ not /blob/276     Example: https://huggingface.co/user/repo/resolve/main/model.ckpt277"""278            print(error_details)279            raise280        except Exception as e:281            print(f"✗ Failed to load model: {e}")282            raise283    284    def __call__(self, x: torch.Tensor) -> torch.Tensor:285        """286        Run inference with optimized model.287        288        Parameters:289        ----------290        x : torch.Tensor291            Input tensor292            293        Returns:294        -------295        torch.Tensor296            Model output297        """298        if self.compiled_model is None:299            raise RuntimeError("No model has been optimized yet")300        301        # Apply memory format if needed (only for 4D tensors - images)302        # Audio models typically use 3D tensors, so we silently skip channels_last for them303        if self.optimize_mode == 'channels_last' and x.dim() == 4:304            x = x.to(memory_format=torch.channels_last)305        306        # Run inference with AMP if enabled307        try:308            if self.use_amp and self.device.startswith('cuda'):309                with torch.cuda.amp.autocast():310                    with torch.no_grad():311                        return self.compiled_model(x)312            else:313                with torch.no_grad():314                    return self.compiled_model(x)315        except Exception as e:316            # Fallback to non-compiled model if torch.compile fails at runtime317            # This can happen with rotary embeddings that mutate class variables318            if self.optimize_mode == 'compile' and self.model is not None:319                print(f"  ⚠️ torch.compile runtime error: {type(e).__name__}")320                print(f"  🔄 Falling back to non-compiled model...")321                self.compiled_model = self.model322                self.optimize_mode = 'fallback'323                # Retry with non-compiled model324                if self.use_amp and self.device.startswith('cuda'):325                    with torch.cuda.amp.autocast():326                        with torch.no_grad():327                            return self.compiled_model(x)328                else:329                    with torch.no_grad():330                        return self.compiled_model(x)331            else:332                raise333 334 335class PyTorchOptimizer:336    """337    Helper class for various PyTorch optimization techniques.338    """339    340    @staticmethod341    def enable_cudnn_benchmark():342        """Enable cuDNN benchmark mode."""343        if torch.cuda.is_available():344            torch.backends.cudnn.benchmark = True345            torch.backends.cudnn.deterministic = False346            print("cuDNN benchmark enabled")347    348    @staticmethod349    def enable_cudnn_deterministic():350        """Enable cuDNN deterministic mode for reproducible results."""351        if torch.cuda.is_available():352            torch.backends.cudnn.deterministic = True353            torch.backends.cudnn.benchmark = False354            print("✓ cuDNN deterministic mode enabled")355    356    @staticmethod357    def enable_tf32():358        """Enable TF32 for Ampere GPUs (RTX 30xx+)."""359        if torch.cuda.is_available():360            torch.backends.cuda.matmul.allow_tf32 = True361            torch.backends.cudnn.allow_tf32 = True362            # Also enable for float32 matmul precision363            torch.set_float32_matmul_precision('high')  # or 'highest' for max speed364            print("TF32 enabled")365    366    @staticmethod367    def set_num_threads(num_threads: int):368        """Set number of threads for CPU inference."""369        torch.set_num_threads(num_threads)370        print(f"✓ Number of threads set to: {num_threads}")371    372    @staticmethod373    def optimize_for_inference(model: nn.Module) -> nn.Module:374        """375        Apply ULTRA optimization for inference.376        377        Parameters:378        ----------379        model : nn.Module380            Model to optimize381            382        Returns:383        -------384        nn.Module385            ULTRA-optimized model386        """387        model.eval()388        torch.set_grad_enabled(False)389        390        # Disable gradient computation for all parameters391        for param in model.parameters():392            param.requires_grad = False393        394        # Fuse operations if possible395        try:396            # Try to fuse batch norm397            model = torch.quantization.fuse_modules(model, inplace=True)398            print("Batch norm fused")399        except:400            pass401        402        try:403            # Try to fuse conv-bn if available404            if hasattr(torch.nn.utils, 'fusion'):405                model = torch.nn.utils.fusion.fuse_conv_bn_eval(model)406                print("Conv-BN fused")407        except:408            pass409        410        return model411 412 413def benchmark_pytorch_optimizations(414    model: nn.Module,415    input_shape: Tuple[int, ...],416    device: str = 'cuda:0',417    num_iterations: int = 100,418    warmup_iterations: int = 10419) -> Dict[str, float]:420    """421    Benchmark different PyTorch optimization techniques.422    423    Parameters:424    ----------425    model : nn.Module426        Model to benchmark427    input_shape : Tuple[int, ...]428        Input tensor shape429    device : str430        Device to use431    num_iterations : int432        Number of benchmark iterations433    warmup_iterations : int434        Number of warmup iterations435        436    Returns:437    -------438    Dict[str, float]439        Benchmark results with average inference times440    """441    results = {}442    dummy_input = torch.randn(*input_shape).to(device)443    444    optimization_modes = ['default', 'compile', 'channels_last']445    446    for mode in optimization_modes:447        print(f"\n{'='*60}")448        print(f"Benchmarking: {mode}")449        print('='*60)450        451        try:452            backend = PyTorchBackend(device=device, optimize_mode=mode)453            454            # Optimize model455            if mode == 'compile':456                optimized_model = backend.optimize_model(model, use_amp=True)457            else:458                optimized_model = backend.optimize_model(459                    model, 460                    example_input=dummy_input,461                    use_amp=True,462                    use_channels_last=(mode == 'channels_last')463                )464            465            # Warmup466            for _ in range(warmup_iterations):467                _ = backend(dummy_input)468            469            # Benchmark470            if device.startswith('cuda'):471                torch.cuda.synchronize()472            473            start = time.time()474            for _ in range(num_iterations):475                _ = backend(dummy_input)476            477            if device.startswith('cuda'):478                torch.cuda.synchronize()479            480            elapsed = (time.time() - start) / num_iterations481            results[mode] = elapsed * 1000  # Convert to ms482            483            print(f"  Average time: {results[mode]:.2f} ms")484            485        except Exception as e:486            print(f"  Failed: {e}")487            results[mode] = None488    489    return results490 491 492def create_inference_session(493    model: nn.Module,494    device: str = 'cuda:0',495    optimize_mode: str = 'default',496    enable_amp: bool = True,497    enable_tf32: bool = True,498    enable_cudnn_benchmark: bool = True499) -> PyTorchBackend:500    """501    Create an optimized inference session.502    503    Parameters:504    ----------505    model : nn.Module506        Model to use for inference507    device : str508        Device to use509    optimize_mode : str510        Optimization mode511    enable_amp : bool512        Enable automatic mixed precision513    enable_tf32 : bool514        Enable TF32 (for Ampere GPUs)515    enable_cudnn_benchmark : bool516        Enable cuDNN benchmark517        518    Returns:519    -------520    PyTorchBackend521        Configured inference session522    """523    # Apply global optimizations524    optimizer = PyTorchOptimizer()525    526    if enable_cudnn_benchmark:527        optimizer.enable_cudnn_benchmark()528    529    if enable_tf32 and device.startswith('cuda'):530        optimizer.enable_tf32()531    532    # Create backend533    backend = PyTorchBackend(device=device, optimize_mode=optimize_mode)534    backend.optimize_model(model, use_amp=enable_amp)535    536    return backend537 538 539def convert_model_to_onnx(540    model: nn.Module,541    input_shape: Tuple[int, ...],542    output_path: str,543    opset_version: int = 14544):545    """546    Convert PyTorch model to ONNX format.547    548    Parameters:549    ----------550    model : nn.Module551        Model to convert552    input_shape : Tuple[int, ...]553        Input tensor shape554    output_path : str555        Path to save ONNX model556    opset_version : int557        ONNX opset version558    """559    try:560        import onnx561        562        model.eval()563        dummy_input = torch.randn(*input_shape)564        565        print(f"Converting model to ONNX (opset {opset_version})...")566        torch.onnx.export(567            model,568            dummy_input,569            output_path,570            export_params=True,571            opset_version=opset_version,572            do_constant_folding=True,573            input_names=['input'],574            output_names=['output'],575            dynamic_axes={576                'input': {0: 'batch_size'},577                'output': {0: 'batch_size'}578            }579        )580        581        # Verify ONNX model582        onnx_model = onnx.load(output_path)583        onnx.checker.check_model(onnx_model)584        585        print(f"✓ ONNX model saved to: {output_path}")586        587    except ImportError:588        print("✗ ONNX not available. Install with: pip install onnx")589    except Exception as e:590        print(f"✗ ONNX conversion failed: {e}")591 592 593def get_model_info(model: nn.Module) -> Dict[str, Any]:594    """595    Get information about a PyTorch model.596    597    Parameters:598    ----------599    model : nn.Module600        Model to analyze601        602    Returns:603    -------604    Dict[str, Any]605        Model information606    """607    total_params = sum(p.numel() for p in model.parameters())608    trainable_params = sum(p.numel() for p in model.parameters() if p.requires_grad)609    610    # Estimate model size611    param_size = sum(p.nelement() * p.element_size() for p in model.parameters())612    buffer_size = sum(b.nelement() * b.element_size() for b in model.buffers())613    size_mb = (param_size + buffer_size) / (1024 ** 2)614    615    return {616        'total_parameters': total_params,617        'trainable_parameters': trainable_params,618        'model_size_mb': size_mb,619        'device': next(model.parameters()).device,620        'dtype': next(model.parameters()).dtype621    }622