fix(chronos): inference RuntimeError 시 자동 CPU 폴백
ea88597 의 fp32 변경만으로는 sm_86 커널 누락 케이스를 100% 회피한다는
보장이 없음 (에러 메시지가 dtype 과 무관한 dispatch 단계에서 날 수 있어
fp32 도 같은 증상 가능). 그래서 forecast() 안에서 RuntimeError 잡아
'no kernel image' / 'CUDA error' / 'CUBLAS' 신호면 pipeline 을 CPU 로
재로드하고 한 번 더 추론. 폴백 후엔 그 세션 동안 계속 CPU 사용 (재시도
비용 회피).
이로써 사용자는 환경변수 수동 변경 없이도 GPU 비호환 시 자동으로 차트가
뜸. GPU 가 잘 도는 경우는 영향 없음.
This commit is contained in:
@@ -84,6 +84,26 @@ def _load() -> None:
|
|||||||
_state.update({"loaded": True, "pipe": pipe, "device": device})
|
_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(
|
def forecast(
|
||||||
series: list[float],
|
series: list[float],
|
||||||
*,
|
*,
|
||||||
@@ -102,14 +122,31 @@ def forecast(
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
import torch
|
import torch
|
||||||
|
|
||||||
pipe = _state["pipe"]
|
def _do_predict():
|
||||||
context = torch.tensor([float(x) for x in series], dtype=torch.float32)
|
pipe = _state["pipe"]
|
||||||
with torch.no_grad():
|
context = torch.tensor([float(x) for x in series], dtype=torch.float32)
|
||||||
samples = pipe.predict(
|
with torch.no_grad():
|
||||||
context=context,
|
return pipe.predict(
|
||||||
prediction_length=horizon,
|
context=context,
|
||||||
num_samples=num_samples,
|
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)
|
# samples: (1, num_samples, prediction_length)
|
||||||
arr = samples[0].cpu().float().numpy()
|
arr = samples[0].cpu().float().numpy()
|
||||||
q10 = np.quantile(arr, 0.10, axis=0).tolist()
|
q10 = np.quantile(arr, 0.10, axis=0).tolist()
|
||||||
|
|||||||
Reference in New Issue
Block a user