시간 기반 파운데이션 모델에 1년치 시간별 데이터를 입력하면 그럴듯해 보이는 예측치를 얻습니다. 그리고 이를 배포했을 때 모든 급증(spike)을 놓칩니다. 모델이 데이터가 나빠서 실패한 것이 아닙니다. 컨텍스트 창(context window)이 잘못되었기 때문에 실패한 것입니다.
이 글의 끝에 이르면, 시계열 모델이 입력 데이터를 조용히 잘라내고 있는지(truncating) 알아차릴 수 있게 되며, 예측 지평(horizon)과 일치하는 컨텍스트 길이를 선택하고, 호출을 래핑하여 실패가 숨겨지는 대신 노출되도록 할 수 있을 것입니다.
조용한 잘림 함정 (The silent truncation trap)
Mistral의 Timestral 같은 시계열 파운데이션 모델은 고정된 컨텍스트 창으로 입력을 처리합니다. 이 창이란 모델이 한 번에 어텐션(attend)할 수 있는 토큰의 개수입니다. 만약 사용자의 시리즈 길이가 이 창보다 길면, 모델은 가장 오래된 토큰들을 버립니다.
오류가 발생하지 않습니다. 경고도 기록되지 않습니다. 예측은 여전히 실행됩니다. 이는 데이터의 끝 부분(tail)을 기반으로 실행되며, 이러한 모델들은 어떤 입력이든 그럴듯한 모양의 곡선을 생성하는 데 능숙하기 때문에 결과가 합리적으로 보입니다.
이는 모델 자체의 버그가 아닙니다. 사용자의 데이터 길이와 모델의 컨텍스트 크기 간의 불일치(mismatch) 문제입니다. 모델은 사용자가 시리즈의 어느 부분을 가장 중요하게 생각하는지 알 방법이 없습니다. 오직 사용자 코드만이 이를 강제할 수 있습니다.
위험한 점은 이 잘림 현상이 양쪽 끝에서 모두 보이지 않는다는 것입니다. 요청은 성공합니다. 응답도 파싱됩니다. 예측 곡선은 부드러워 보입니다. 무언가 잘못되었다는 유일한 징후는 프로덕션 지표(production metrics)의 드리프트이며, 그때쯤이면 나쁜 예측치가 이미 배포된 후입니다.
모델링 전에 측정하기 (Measure before you model)
어떤 시계열 모델을 호출하기 전에, 사용자의 시리즈가 몇 개의 토큰을 생성하는지 확인해야 합니다. 대부분의 시계열 모델은 각 타임스텝(timestep)을 하나의 또는 그 이상의 토큰으로 토큰화하며, 이는 피처 수와 값의 정밀도에 따라 달라집니다. 단변량 시간별 시리즈와 동일한 행 개수를 가진 다변량 분 단위 시리즈는 매우 다른 토큰 수를 생성할 수 있습니다.
모델을 만지기 전에 예상치부터 시작하세요.
import numpy as np
def estimate_tokens(series, features_per_step=1, bytes_per_value=4):
...
이것은 추정치일 뿐 보장이 아닙니다. 토큰화 방식은 모델과 제공업체마다 다릅니다. 이 숫자는 대략적인 크기(order-of-magnitude)를 확인하는 용도로만 사용하십시오. 한계에 가까워지면, 정확한 토큰화 규칙을 확인하기 위해 제공업체의 문서를 참조하거나 작은 탐색(probe) 시퀀스를 보내 응답에서 보고된 토큰 사용량을 읽으십시오.
만약 추정치가 모델의 컨텍스트 창(context window)을 초과한다면, 반드시 다운샘플링(downsample)하거나 청크(chunk)로 나누어야 합니다. 이 단계를 건너뛰지 마십시오.
청킹 또는 압축하기
실제로는 두 가지 전략이 작동합니다. 신호가 정상 상태(stationary)인지, 즉 통계적 속성이 시간이 지나도 대략적으로 일정하게 유지되는지에 따라 선택하십시오.
| 접근 방식 | 사용 시점 | 트레이드오프 (단점) |
|---|
| 슬라이딩 윈도우 (Sliding window) | 신호에 반복 패턴이 있는 경우 | 장기 추세(long-term trends) 손실 |
| 다운샘플링 (Downsampling) | 신호가 노이즈가 많거나 고주파수인 경우 | 세밀한 디테일(fine-grained detail) 손실 |
시간당 데이터에 일별 주기가 있다면, 24단계 슬라이딩 윈도우가 충분한 컨텍스트를 보존하는 경우가 많습니다. 연간 추세의 경우, 일별 평균으로 다운샘플링하면 형태는 유지되지만 일중 급등(intraday spikes)은 숨겨집니다.
선택이 보이는 것보다 더 중요합니다. 만약 스파이크가 중요한 데이터 시리즈를 다운샘플링한다면, 원하는 신호를 평균화하여 사라지게 합니다. 느린 추세(slow trend)를 가진 시리즈를 청크로 나눈다면, 각 청크는 다른 기준선(baseline)에서 예측을 수행하므로 출력 결과가 청크 간에 일관되지 않게 됩니다.
슬라이딩 윈도우는 가장 최근의 N단계만 유지하고 그보다 오래된 모든 것은 버립니다.
def sliding_window(series, window_size):
if len(series) <= window_size:
return series
...
이 윈도우는 모델이 포착하기를 원하는 계절 주기(seasonal cycle)만큼 최소한 길어야 합니다. 시간당 데이터에 24단계 윈도우를 적용하면 하루를 커버합니다. 하지만 주간 패턴은 포착하지 못할 것입니다. 예측 기간(forecast horizon)이 아니라 주기에 맞춰 윈도우 크기를 조정해야 합니다.
호출을 가드(Guard)로 감싸기
절대로 프로덕션 환경에서 시계열 모델을 직접 호출해서는 안 됩니다. 잘림 현상(truncation)이 눈에 보이도록 코드를 감싸야 합니다.
import requests
def forecast_with_context_check(series, max_context=8192):
...
max_context 값은 메모리가 아닌 제공업체의 최신 문서를 참고해야 합니다. 컨텍스트 제한은 모델 릴리스마다 변경되기 때문에, 하드코딩된 오래된 값은 유효한 요청을 차단하거나 다시 조용히 잘리도록 허용할 것입니다.
이 가드는 조용한 자르기(silent truncation)를 큰 오류(loud failure)로 만듭니다. 이는 프로덕션 환경이 아닌 스테이징 환경에서 수정해야 합니다. 예외는 의도적입니다: 부분적인 데이터로 구축된 예측은 아무런 예측이 없는 것보다 더 나쁜데, 그 이유는 신뢰할 수 있게 보이기 때문입니다.
여전히 잘못되는 점들
올바른 컨텍스트 길이에도 불구하고, 파운데이션 모델(foundation models)은 분포 변화(distribution shift)에 어려움을 겪습니다. 만약 학습 데이터가 1월에 끝나고 7월을 예측한다면, 모델은 해당 체제(regime)를 본 적이 없습니다. 모델은 자신감 있게 보간(interpolate)할 것이며 틀릴 것입니다.
컨텍스트 길이가 이를 막아주지 못합니다. 더 긴 창(window)은 모델에 더 많은 이력을 제공하지만, 미래가 과거와 다르게 행동한다면 그 이력은 도움이 되지 않습니다.
항상 실제 데이터의 가장 최근 창으로 검증해야 합니다. 시계열의 마지막 부분을 따로 빼내어 예측하고, 새로운 것에 대해 모델을 신뢰하기 전에 실제 값과 비교하세요. 현재 상황을 본 적이 없는 모델은 신뢰하지 마십시오.
핵심 요약
- 시계열 모델은 입력이 컨텍스트 창을 초과할 때 조용히 잘리며(truncate silently), 예측 결과는 여전히 그럴듯해 보입니다.
- 모델 호출 전에 항상 토큰 수를 추정하고 문서화된 컨텍스트 제한과 비교해야 합니다.
- 반복되는 패턴에는 슬라이딩 윈도우(sliding windows)를, 노이즈가 많은 고주파 데이터에는 다운샘플링(downsampling)을 사용하세요.
- 슬라이딩 윈도우는 예측 기간(forecast horizon)에 맞추지 말고 필요한 계절 주기(seasonal cycle)에 맞춰야 합니다.
- 모델 호출은 명시적인 가드(guard)로 감싸서 자르기가 큰 오류가 되도록 하고, 분포 변화를 포착하기 위해 최근 데이터로 검증해야 합니다.
출처
Timestral: Mistral의 시계열 기반 모델(time-series foundation models)에 대해 알아보세요. (https://mistral.ai/news/timestral/) -- 토큰 추정 및 슬라이딩 윈도우를 위한 작동 코드를 추가했으며, 청킹 전략 테이블과 트렁케이션을 조용한 실패가 아닌 큰 오류로 표시하는 프로덕션 가드 패턴을 구현했습니다.
이 작업 지원하기
이 글들은 유료 장벽, 스폰서 또는 추적 없이 연구되어 게시되었습니다. 만약 이 글 하나가 당신의 오후 시간을 절약해 주었다면, 작은 팁이 계속해서 좋은 콘텐츠를 만드는 데 도움이 됩니다.
USDT, USDC 또는 USDD · TRC-20 (Tron)
TFTNsfyomKrnUutRjBTGVULp19ByW29KbY