From 323061df02f27af19b2294deade61b6eae52b7d7 Mon Sep 17 00:00:00 2001 From: claude-owner Date: Sat, 23 May 2026 16:09:09 +0900 Subject: [PATCH] =?UTF-8?q?fix(chronos):=20inference=20RuntimeError=20?= =?UTF-8?q?=EC=8B=9C=20=EC=9E=90=EB=8F=99=20CPU=20=ED=8F=B4=EB=B0=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ea88597 의 fp32 변경만으로는 sm_86 커널 누락 케이스를 100% 회피한다는 보장이 없음 (에러 메시지가 dtype 과 무관한 dispatch 단계에서 날 수 있어 fp32 도 같은 증상 가능). 그래서 forecast() 안에서 RuntimeError 잡아 'no kernel image' / 'CUDA error' / 'CUBLAS' 신호면 pipeline 을 CPU 로 재로드하고 한 번 더 추론. 폴백 후엔 그 세션 동안 계속 CPU 사용 (재시도 비용 회피). 이로써 사용자는 환경변수 수동 변경 없이도 GPU 비호환 시 자동으로 차트가 뜸. GPU 가 잘 도는 경우는 영향 없음. --- backend/app/models/chronos.py | 53 +++++++++++++++++++++++++++++------ 1 file changed, 45 insertions(+), 8 deletions(-) diff --git a/backend/app/models/chronos.py b/backend/app/models/chronos.py index 328dacc..5ae1621 100644 --- a/backend/app/models/chronos.py +++ b/backend/app/models/chronos.py @@ -84,6 +84,26 @@ def _load() -> None: _state.update({"loaded": True, "pipe": pipe, "device": device}) +def _reload_cpu() -> None: + """현재 pipeline 을 폐기하고 CPU 로 강제 재로드. + + cuda 환경에서 'no kernel image is available for execution on the device' 같이 + 런타임에야 드러나는 GPU 비호환 에러가 났을 때 자동 폴백용. 한 번 폴백하면 + 다음 호출부터는 CPU 그대로 사용 (재시도 비용 회피).""" + global _state + import torch + from chronos import ChronosPipeline + with _lock: + logger.warning("falling back to CPU for Chronos (GPU inference failed)") + _state.update({"loaded": False, "pipe": None, "device": None}) + pipe = ChronosPipeline.from_pretrained( + MODEL_NAME, + device_map="cpu", + torch_dtype=torch.float32, + ) + _state.update({"loaded": True, "pipe": pipe, "device": "cpu"}) + + def forecast( series: list[float], *, @@ -102,14 +122,31 @@ def forecast( import numpy as np import torch - pipe = _state["pipe"] - context = torch.tensor([float(x) for x in series], dtype=torch.float32) - with torch.no_grad(): - samples = pipe.predict( - context=context, - prediction_length=horizon, - num_samples=num_samples, - ) + def _do_predict(): + pipe = _state["pipe"] + context = torch.tensor([float(x) for x in series], dtype=torch.float32) + with torch.no_grad(): + return pipe.predict( + context=context, + prediction_length=horizon, + num_samples=num_samples, + ) + + try: + samples = _do_predict() + except RuntimeError as exc: + # cuda 빌드/드라이버 미스매치는 inference 시점에야 드러나는 경우가 많음. + # 'no kernel image is available' / 'CUDA error' 같은 신호 잡아서 CPU 로 폴백. + msg = str(exc) + if _state.get("device") == "cuda" and ( + "no kernel image" in msg + or "CUDA error" in msg + or "CUBLAS" in msg + ): + _reload_cpu() + samples = _do_predict() + else: + raise # samples: (1, num_samples, prediction_length) arr = samples[0].cpu().float().numpy() q10 = np.quantile(arr, 0.10, axis=0).tolist()