CoolFace
Apppublic

HarshithReddy01/srmamamba-liver-segmentation

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes
model_loader.py359 linesDownload Raw Back to root
1import os2import time3import torch4from monai.inferers import SlidingWindowInferer5from config import BUILD_SRMAMAMBA_AVAILABLE, build_SRMAMamba, SRMA_MAMBA_DIR6 7MODEL_T1 = None8MODEL_T2 = None9DEVICE = torch.device('cpu')10WINDOW_INFER = None11 12def clear_gpu_memory():13    global MODEL_T1, MODEL_T2, WINDOW_INFER14    if torch.cuda.is_available():15        if MODEL_T1 is not None:16            del MODEL_T117            MODEL_T1 = None18        if MODEL_T2 is not None:19            del MODEL_T220            MODEL_T2 = None21        if WINDOW_INFER is not None:22            del WINDOW_INFER23            WINDOW_INFER = None24        torch.cuda.empty_cache()25        torch.cuda.synchronize()26        print("  → GPU memory cleared (models unloaded)")27 28def load_model(modality='T1'):29    global MODEL_T1, MODEL_T2, DEVICE, WINDOW_INFER, BUILD_SRMAMAMBA_AVAILABLE30    31    if torch.cuda.is_available():32        torch.cuda.empty_cache()33        torch.cuda.synchronize()34    35    if not BUILD_SRMAMAMBA_AVAILABLE or build_SRMAMamba is None:36        error_msg = "Model builder (build_SRMAMamba) is not available. Please check the logs for import errors."37        print(f"✗ {error_msg}")38        raise ImportError(error_msg)39    40    print(f"Loading {modality} model...")41    42    if torch.cuda.is_available():43        try:44            max_retries = 345            retry_delay = 246            47            for attempt in range(max_retries):48                try:49                    torch.cuda.empty_cache()50                    test_tensor = torch.zeros(1).cuda()51                    del test_tensor52                    torch.cuda.synchronize()53                    DEVICE = torch.device('cuda')54                    print(f"✓ Using device: {DEVICE}")55                    break56                except RuntimeError as e:57                    if "CUDA" in str(e) and attempt < max_retries - 1:58                        print(f"⚠ GPU wake-up attempt {attempt + 1}/{max_retries}: {e}")59                        print(f"⚠ Waiting {retry_delay}s for GPU to wake up...")60                        time.sleep(retry_delay)61                        retry_delay *= 262                    else:63                        raise64        except Exception as e:65            print(f"⚠ CUDA available but failed to initialize: {e}. Falling back to CPU.")66            DEVICE = torch.device('cpu')67    else:68        DEVICE = torch.device('cpu')69        print(f"ℹ CUDA not available. Using device: {DEVICE}")70    71    if DEVICE.type == 'cuda':72        torch.cuda.empty_cache()73        torch.cuda.synchronize()74        allocated = torch.cuda.memory_allocated(0) / (1024**3)75        reserved = torch.cuda.memory_reserved(0) / (1024**3)76        total = torch.cuda.get_device_properties(0).total_memory / (1024**3)77        free_memory_gb = total - allocated78        print(f"  → GPU memory: {allocated:.2f} GB allocated, {reserved:.2f} GB reserved, {free_memory_gb:.2f} GB free (total: {total:.2f} GB)")79        80        if free_memory_gb < 1.0:81            print(f"  ⚠ CRITICAL: Very low free memory ({free_memory_gb:.2f} GB). Using ultra-minimal settings.")82            size = [192, 192, 32]83            batch_size = 184            overlap = 0.2585        elif free_memory_gb < 2.0:86            print(f"  ⚠ WARNING: Very low free memory ({free_memory_gb:.2f} GB). Using minimal settings.")87            size = [192, 192, 32]88            batch_size = 189            overlap = 0.2590        elif free_memory_gb < 5.0:91            size = [224, 224, 48]92            batch_size = 193            overlap = 0.294        elif free_memory_gb > 40:95            print(f"  Very high VRAM GPU detected ({free_memory_gb:.2f} GB free). Using optimal settings for maximum speed.")96            size = [256, 256, 80]97            batch_size = 298            overlap = 0.199        elif free_memory_gb > 30:100            print(f"  High VRAM GPU detected ({free_memory_gb:.2f} GB free). Using optimal settings for speed.")101            size = [256, 256, 64]102            batch_size = 2103            overlap = 0.1104        elif free_memory_gb > 25:105            print(f"  ✓ Large VRAM GPU detected ({free_memory_gb:.2f} GB free). Using optimal settings.")106            size = [256, 256, 64]107            batch_size = 1108            overlap = 0.1109        elif free_memory_gb > 20:110            size = [256, 256, 64]111            batch_size = 1112            overlap = 0.1113        elif free_memory_gb > 15:114            size = [256, 256, 64]115            batch_size = 1116            overlap = 0.1117        elif free_memory_gb > 10:118            size = [224, 224, 64]119            batch_size = 1120            overlap = 0.1121        elif free_memory_gb > 8:122            size = [224, 224, 48]123            batch_size = 1124            overlap = 0.2125        else:126            size = [192, 192, 48]127            batch_size = 1128            overlap = 0.2129    else:130        size = [224, 224, 64]131        batch_size = 1132        overlap = 0.15133    134    print(f"  → Sliding window config: roi_size={size}, sw_batch_size={batch_size}, overlap={overlap}")135    136    print("Building model architecture...")137    if SRMA_MAMBA_DIR:138        original_cwd = os.getcwd()139        try:140            os.chdir(SRMA_MAMBA_DIR)141            print(f"Changed working directory to: {SRMA_MAMBA_DIR}")142            model = build_SRMAMamba()143            print("✓ Model architecture built")144        finally:145            os.chdir(original_cwd)146    else:147        model = build_SRMAMamba()148        print("✓ Model architecture built")149    150    model = model.to(DEVICE)151    print(f"✓ Model moved to {DEVICE}")152    153    checkpoint_path = f"checkpoint_{modality}.pth"154    possible_paths = [155        checkpoint_path,156        os.path.join(os.path.dirname(__file__), checkpoint_path),157        f"../../Chkpoints/checkpoint_{modality}.pth",158        f"Chkpoints/checkpoint_{modality}.pth",159        f"../Chkpoints/checkpoint_{modality}.pth",160        f"Model/Chkpoints/checkpoint_{modality}.pth",161        os.path.join(os.path.dirname(__file__), f"Chkpoints/checkpoint_{modality}.pth"),162    ]163    164    found = False165    for path in possible_paths:166        abs_path = os.path.abspath(path)167        if os.path.exists(path) or os.path.exists(abs_path):168            checkpoint_path = path if os.path.exists(path) else abs_path169            found = True170            print(f"✓ Found checkpoint at: {checkpoint_path}")171            break172    173    if not found:174        try:175            from huggingface_hub import hf_hub_download176            repo_id = os.environ.get("HF_MODEL_REPO", "HarshithReddy01/srmamamba-liver-segmentation")177            print(f"Attempting to download checkpoint from Hugging Face: {repo_id}")178            checkpoint_path = hf_hub_download(179                repo_id=repo_id,180                filename=f"checkpoint_{modality}.pth",181                cache_dir="."182            )183            found = True184            print(f"✓ Downloaded checkpoint to: {checkpoint_path}")185        except Exception as e:186            error_msg = f"Checkpoint not found. Searched: {possible_paths}. Hugging Face download failed: {str(e)}"187            print(f"✗ {error_msg}")188            raise FileNotFoundError(error_msg)189    190    print(f"Loading checkpoint weights from: {checkpoint_path}")191    try:192        checkpoint = torch.load(checkpoint_path, map_location=DEVICE)193        if isinstance(checkpoint, dict) and 'state_dict' in checkpoint:194            ckpt_sd = checkpoint['state_dict']195        else:196            ckpt_sd = checkpoint197        model_keys = set(model.state_dict().keys())198        ckpt_keys = set(ckpt_sd.keys())199        missing = model_keys - ckpt_keys200        unexpected = ckpt_keys - model_keys201        if missing:202            print(f"  ⚠ WARNING: Checkpoint missing keys for model: {len(missing)} keys")203        if unexpected:204            print(f"  ⚠ WARNING: Checkpoint has unexpected keys: {len(unexpected)} keys")205        if not missing and not unexpected:206            print("  ✓ State dict keys match (no missing/unexpected keys)")207        if isinstance(checkpoint, dict) and 'state_dict' in checkpoint:208            model.load_state_dict(ckpt_sd)209        else:210            model.load_state_dict(ckpt_sd)211        print("✓ Checkpoint loaded successfully")212    except Exception as e:213        print(f"✗ Failed to load checkpoint: {e}")214        raise215    216    model.eval()217    print("✓ Model set to evaluation mode")218    219    if DEVICE.type == 'cuda':220        import config221        from packaging import version222        223        torch_version = version.parse(torch.__version__)224        if torch_version >= version.parse("2.9.0"):225            torch.backends.cuda.matmul.fp32_precision = 'tf32'226            torch.backends.cudnn.conv.fp32_precision = 'tf32'227            tf32_matmul = torch.backends.cuda.matmul.fp32_precision228            tf32_conv = torch.backends.cudnn.conv.fp32_precision229        else:230            torch.backends.cuda.matmul.allow_tf32 = True231            torch.backends.cudnn.allow_tf32 = True232            tf32_matmul = 'tf32' if torch.backends.cuda.matmul.allow_tf32 else 'ieee'233            tf32_conv = 'tf32' if torch.backends.cudnn.allow_tf32 else 'ieee'234        torch.backends.cudnn.benchmark = True235        print(f"TF32 enabled: matmul={tf32_matmul}, conv={tf32_conv}")236        print("cuDNN benchmarking enabled")237        238        if config.ENABLE_TORCH_COMPILE:239            try:240                compile_mode = os.environ.get('TORCH_COMPILE_MODE', 'reduce-overhead')241                if compile_mode == 'max-autotune':242                    print(f"  → Compiling with max-autotune (may take 2-5 min on first run)...")243                    model = torch.compile(model, mode='max-autotune', fullgraph=False)244                    print(f"✓ Model compiled with torch.compile (mode=max-autotune, fullgraph=False)")245                elif compile_mode == 'default':246                    print(f"  → Compiling with default mode (may take 1-3 min on first run)...")247                    model = torch.compile(model, fullgraph=False)248                    print(f"✓ Model compiled with torch.compile (mode=default, fullgraph=False)")249                else:250                    print(f"  → Compiling with reduce-overhead (faster first run, ~30-60s)...")251                    model = torch.compile(model, mode='reduce-overhead', fullgraph=False)252                    print(f"✓ Model compiled with torch.compile (mode=reduce-overhead, fullgraph=False)")253            except Exception as e:254                print(f"  ⚠ torch.compile failed: {e}. Continuing without compilation.")255        else:256            print("  ℹ torch.compile disabled (set ENABLE_TORCH_COMPILE=true to enable)")257    258    torch.cuda.empty_cache()259    torch.cuda.synchronize()260    allocated_after_load = torch.cuda.memory_allocated(0) / (1024**3)261    free_after_load = (torch.cuda.get_device_properties(0).total_memory - torch.cuda.memory_allocated(0)) / (1024**3)262    print(f"  → GPU memory after model load: {allocated_after_load:.2f} GB allocated, {free_after_load:.2f} GB free")263    264    if free_after_load < 1.0:265        print(f"  ⚠ CRITICAL: Only {free_after_load:.2f} GB free after model load. Using ultra-minimal settings.")266        size = [192, 192, 32]267        batch_size = 1268        overlap = 0.25269    elif free_after_load < 2.0:270        print(f"  ⚠ WARNING: Low free memory ({free_after_load:.2f} GB) after model load. Adjusting to minimal settings.")271        size = [192, 192, 32]272        batch_size = 1273        overlap = 0.25274    elif free_after_load > 40:275        print(f"  Excellent free memory ({free_after_load:.2f} GB) after model load. Using optimal settings for maximum speed.")276        size = [256, 256, 80]277        batch_size = 2278        overlap = 0.1279    elif free_after_load > 30:280        print(f"  Excellent free memory ({free_after_load:.2f} GB) after model load. Using optimal settings for speed.")281        size = [256, 256, 64]282        batch_size = 2283        overlap = 0.1284    elif free_after_load > 25:285        print(f"  ✓ Good free memory ({free_after_load:.2f} GB) after model load. Using optimal settings.")286        size = [256, 256, 64]287        batch_size = 1288        overlap = 0.1289    elif free_after_load > 20:290        print(f"  ✓ Good free memory ({free_after_load:.2f} GB) after model load. Using optimal settings.")291        size = [256, 256, 64]292        batch_size = 1293        overlap = 0.1294    elif free_after_load > 15:295        size = [256, 256, 64]296        batch_size = 1297        overlap = 0.1298    elif free_after_load < 5.0 and (size[0] > 224 or batch_size > 1):299        print(f"  ⚠ WARNING: Limited free memory ({free_after_load:.2f} GB). Reducing window size and batch size.")300        size = [224, 224, 48]301        batch_size = 1302        overlap = 0.1303    304    aggregation_device = 'cuda'305    if free_after_load < 2.0:306        aggregation_device = 'cpu'307        print(f"  → Very low VRAM ({free_after_load:.2f} GB), using CPU aggregation to prevent OOM")308    else:309        print(f"  → Using GPU aggregation for maximum speed (VRAM: {free_after_load:.2f} GB free)")310    311    WINDOW_INFER = SlidingWindowInferer(312        roi_size=size, 313        sw_batch_size=batch_size, 314        overlap=overlap,315        sw_device='cuda',316        device=aggregation_device317    )318    print(f"✓ Sliding window inferer created (GPU compute, {aggregation_device.upper()} aggregation)")319    320    if DEVICE.type == 'cuda':321        if config.ENABLE_TORCH_COMPILE:322            print("  Running warm-up inference to trigger compilation and kernel autotuning...")323            print("  This may take 30-60s (reduce-overhead) or 2-5min (max-autotune) on first run...")324        else:325            print("  Running warm-up inference to trigger kernel autotuning...")326        try:327            dummy_input = torch.randn(1, 1, size[0], size[1], size[2], device=DEVICE, dtype=torch.float32)328            dummy_input = dummy_input.contiguous(memory_format=torch.channels_last_3d)329            warmup_start = time.time()330            with torch.no_grad():331                from torch.amp import autocast332                with autocast(device_type='cuda'):333                    _ = model(dummy_input)334            torch.cuda.synchronize()335            warmup_time = time.time() - warmup_start336            del dummy_input, _337            torch.cuda.empty_cache()338            if config.ENABLE_TORCH_COMPILE:339                print(f"  Warm-up completed in {warmup_time:.1f}s (compilation + kernel autotuning)")340            else:341                print(f"  Warm-up completed in {warmup_time:.1f}s (kernels autotuned)")342        except RuntimeError as e:343            if "out of memory" in str(e):344                print(f"  Warm-up OOM (non-critical): {e}")345                print(f"  Will use progressive fallback during inference")346            else:347                print(f"  Warm-up failed (non-critical): {e}")348        except Exception as e:349            print(f"  Warm-up failed (non-critical): {e}")350    351    if modality == 'T1':352        MODEL_T1 = model353    else:354        MODEL_T2 = model355    356    print(f"✓ {modality} model loaded and ready")357    return model358 359