본문 바로가기
파이썬/파이썬 개발환경

윈도우 11 업데이트 후 Cuda 먹통 .. Pytorch 오류 해결한 후기

by Think_JUNG 2025. 11. 25.

최근에 윈도우 11을 업데이트한 뒤, 기존에 잘 돌아가던 PyTorch 코드가 갑자기 에러를 뿜기 시작했다.
GPU도 잘 잡히던 환경이었는데, 어느 순간부터 PyTorch에서 torch.cuda.is_available()가 False를 찍어버리는 상황 발생…

처음엔 “아 드라이버 문제인가?” 싶어서 NVIDIA 드라이버만 다시 깔아봤는데 역시나 그대로.
로그를 보니 CUDA 관련 라이브러리 로딩 자체가 실패하고 있었다.

GPT에게 물어봐도.... 다시 설치하라는 말 밖에...

1. 추정 원인

조사해보니 Windows 11 업데이트하면서
기존 CUDA 실행에 필요한 dll이나 경로가 꼬이거나 구버전 CUDA가 정상적으로 인식되지 않는 경우가 많다고 한다.

특히 PyTorch는 본인이 빌드된 CUDA 버전에 매우 민감한데,
나는 CUDA 12.9 기반 PyTorch를 쓰고 있었고, 윈도우 업데이트 이후 어디가 꼬여버린 것인지 인지를 못했던 것으로 추정됨.

2. 해결 방법

혹시나 나중에 다른 PC 업데이트 하다가 또 삽질할까 싶어 이렇게 글을 남긴다.

CUDA , CUDNN은 최신 버전 업그레이드, -> 이에 맞춰 Pytorch는 재설치(--force 옵션 추가하여 재설치)

어쩌다 보니.. Cuda는 13 버전.. 처음 접했을 때가 8.0이였던거 같은데.....

혹시 모르니 GPT가 작성해 준 Cuda Test 코드 추가

# cuda_check_and_burn.py
# PyTorch CUDA 점검 + 더미 연산으로 GPU 점유율 상승
import argparse
import time
import threading
import sys

import torch

def print_cuda_info():
    print("==== CUDA / cuDNN / PyTorch Info ====")
    print(f"PyTorch: {torch.__version__}")
    print(f"CUDA available: {torch.cuda.is_available()}")
    print(f"torch.version.cuda: {torch.version.cuda}")
    try:
        print(f"cuDNN enabled: {torch.backends.cudnn.enabled}")
        print(f"cuDNN version: {torch.backends.cudnn.version()}")
    except Exception as e:
        print(f"cuDNN info unavailable: {e}")

    if torch.cuda.is_available():
        device_count = torch.cuda.device_count()
        print(f"Device count: {device_count}")
        for i in range(device_count):
            name = torch.cuda.get_device_name(i)
            cc = torch.cuda.get_device_capability(i)  # (major, minor)
            props = torch.cuda.get_device_properties(i)
            torch.cuda.set_device(i)
            free, total = torch.cuda.mem_get_info()
            print(f"- [{i}] {name} | CC {cc[0]}.{cc[1]} | VRAM total={total/1e9:.2f} GB, free={free/1e9:.2f} GB")
    print("=====================================")

def try_import_pynvml():
    try:
        import pynvml
        pynvml.nvmlInit()
        return pynvml
    except Exception as e:
        return None

def monitor_gpu(pynvml, device_index: int, interval: float = 1.0, stop_event: threading.Event = None):
    if pynvml is None:
        return
    handle = pynvml.nvmlDeviceGetHandleByIndex(device_index)
    while stop_event is None or not stop_event.is_set():
        util = pynvml.nvmlDeviceGetUtilizationRates(handle)
        mem = pynvml.nvmlDeviceGetMemoryInfo(handle)
        print(f"[Monitor] GPU {device_index} util={util.gpu}% | mem={mem.used/1e9:.2f}/{mem.total/1e9:.2f} GB")
        time.sleep(interval)

def allocate_memory(device, mem_gb: float):
    if mem_gb <= 0:
        return []
    # FP16로 메모리 효율을 높일 수도 있으나, 메모리 점유 목적이면 uint8로 대량 할당
    bytes_to_alloc = int(mem_gb * (1024**3))
    # 큰 한 덩어리 대신 여러 청크로 할당하여 OOM 위험 완화
    chunk_size = 256 * 1024 * 1024  # 256MB
    tensors = []
    allocated = 0
    while allocated < bytes_to_alloc:
        remaining = bytes_to_alloc - allocated
        this_chunk = min(chunk_size, remaining)
        # uint8 텐서는 1 byte/elem
        num_elems = this_chunk
        try:
            t = torch.empty(num_elems, dtype=torch.uint8, device=device)
            tensors.append(t)
            allocated += this_chunk
        except RuntimeError as e:
            print(f"[Memory] Allocation failed at ~{allocated/1e9:.2f} GB: {e}")
            break
    print(f"[Memory] Allocated ~{allocated/1e9:.2f} GB on GPU {device.index}")
    return tensors

def burn_matmul(device, size: int, dtype: str, duration: int, streams: int, report_every: float = 5.0):
    # dtype 설정
    if dtype.lower() == "fp16":
        dt = torch.float16
    elif dtype.lower() == "bf16":
        dt = torch.bfloat16
    else:
        dt = torch.float32

    torch.cuda.set_device(device.index)
    # 여러 스트림 준비
    stream_list = [torch.cuda.Stream(device=device) for _ in range(max(1, streams))]

    # 큰 행렬 준비 (A: [size, size], B: [size, size])
    # 메모리 부담을 줄이려면 size를 조정하세요.
    A_list, B_list = [], []
    for s in stream_list:
        with torch.cuda.stream(s):
            A = torch.randn(size, size, device=device, dtype=dt)
            B = torch.randn(size, size, device=device, dtype=dt)
            A_list.append(A)
            B_list.append(B)
    torch.cuda.synchronize()

    t0 = time.time()
    t_last_report = t0
    iters = 0
    while time.time() - t0 < duration:
        for s, A, B in zip(stream_list, A_list, B_list):
            with torch.cuda.stream(s):
                # 행렬곱 연산
                C = torch.matmul(A, B)
                # 연산 결과를 사용해 최적화 방지
                A.add_(C.mean())
                B.add_(C.mean())
        iters += 1
        # 주기적으로 동기화 및 리포트
        if time.time() - t_last_report >= report_every:
            torch.cuda.synchronize()
            print(f"[Compute] matmul iterations: {iters}, elapsed: {time.time() - t0:.1f}s")
            t_last_report = time.time()

    torch.cuda.synchronize()
    print("[Compute] matmul burn completed.")

def main():
    parser = argparse.ArgumentParser(description="PyTorch CUDA check and GPU burn dummy.")
    parser.add_argument("--device", type=int, default=0, help="사용할 GPU index")
    parser.add_argument("--duration", type=int, default=30, help="연산 지속 시간(초)")
    parser.add_argument("--size", type=int, default=4096, help="행렬곱 크기 (size x size)")
    parser.add_argument("--dtype", type=str, default="fp16", choices=["fp16", "fp32", "bf16"], help="연산 dtype")
    parser.add_argument("--streams", type=int, default=2, help="동시성 스트림 수")
    parser.add_argument("--mem_gb", type=float, default=0.0, help="메모리 점유(dummy) GB")
    parser.add_argument("--monitor", action="store_true", help="pynvml로 GPU 사용률 모니터링")
    args = parser.parse_args()

    print_cuda_info()

    if not torch.cuda.is_available():
        print("CUDA가 사용 불가합니다. NVIDIA 드라이버/Toolkit/환경변수를 확인하세요.")
        sys.exit(1)

    device = torch.device(f"cuda:{args.device}")
    torch.cuda.set_device(device)

    # 성능 최적화 옵션
    try:
        torch.backends.cudnn.benchmark = True
    except Exception:
        pass
    try:
        torch.set_float32_matmul_precision("high")
    except Exception:
        pass

    # 모니터 스레드
    stop_event = threading.Event()
    pynvml = try_import_pynvml() if args.monitor else None
    monitor_thread = None
    if args.monitor and pynvml is not None:
        monitor_thread = threading.Thread(target=monitor_gpu, args=(pynvml, args.device, 1.0, stop_event), daemon=True)
        monitor_thread.start()
    elif args.monitor:
        print("[Monitor] pynvml이 설치되어 있지 않습니다. 설치: pip install nvidia-ml-py")

    # 메모리 점유
    mem_tensors = allocate_memory(device, args.mem_gb) if args.mem_gb > 0 else []

    # 더미 연산 (행렬곱)
    try:
        burn_matmul(device, args.size, args.dtype, args.duration, args.streams)
    except RuntimeError as e:
        print(f"[Error] Compute failed: {e}")

    # 정리
    stop_event.set()
    torch.cuda.synchronize()
    del mem_tensors
    torch.cuda.empty_cache()
    print("Done.")

if __name__ == "__main__":
    main()

 

 

 

댓글