عنوان

معرفی، بررسی و فلسفهٔ Foundation Modelها در سری‌های زمانی؛ بررسی TimesFM، مدلی دنیا‌دیده در سری‌های زمانی

در مقالهٔ اول فهمیدیم یک شبکهٔ عصبی چطور از اشتباه‌هایش یاد می‌گیره. در مقالهٔ دوم دیدیم وقتی داده ترتیب دارد، مسیر معماری‌ها از MLP و RNN به LSTM، Attention و Transformer می‌رسد.

حالا یک سؤال تازه داریم.

فرض کن برای پیش‌بینی مصرف برق یک مدل ساخته‌ایم. برای پیش‌بینی ترافیک، فروش فروشگاه، دمای هوا و قیمت یک دارایی هم مدل‌های جداگانه‌ای می‌سازیم. هر بار باید داده جمع کنیم، معماری انتخاب کنیم، مدل را از اول آموزش بدهیم و امیدوار باشیم دادهٔ همان مسئله برای یادگیری کافی باشد.

اما آیا می‌شود یک مدل قبل از رسیدن به مسئلهٔ ما، تعداد بسیار زیادی سری زمانی از دنیا دیده باشد؟ مدلی که مفهوم روند، فصل، شوک، نوسان، بازگشت و تکرار را فقط از یک سهم یا یک فروشگاه یاد نگرفته باشد؛ بلکه از مجموعه‌ای بزرگ و متنوع از سری‌ها تجربه گرفته باشد و بعد، با دیدن سری تازهٔ ما، بدون آموزش دوباره یک پیش‌بینی قابل‌قبول تولید کند؟

ایدهٔ Foundation Model برای سری زمانی از همین‌جا شروع می‌شود.

TimesFM یکی از جدی‌ترین پاسخ‌های اولیه به این سؤال است: یک Transformer از نوع decoder-only که گوگل آن را روی حجم بزرگی از سری‌های زمانی پیش‌آموزش داده تا بتواند روی داده‌ای که قبلاً ندیده، به‌صورت zero-shot پیش‌بینی انجام دهد.

من به چنین مدلی می‌گویم «مدل دنیا‌دیده». نه چون همه‌چیز را می‌داند؛ چون پیش از ملاقات با مسئلهٔ ما، شکل‌های بسیار متنوعی از رفتار زمان را دیده است.

قبل از Foundation Modelها چه کار می‌کردیم؟

برای فهم Foundation Model، اول باید فرق سه نوع نگاه به مسئله را ببینیم.

مدل محلی؛ برای هر سری یک مدل

در مدل‌های محلی، برای هر سری زمانی یک مدل جدا می‌سازیم:

فروشگاه A → مدل A
فروشگاه B → مدل B
فروشگاه C → مدل C

ARIMA و Exponential Smoothing معمولاً در چنین قالبی استفاده می‌شوند. مدلِ فروشگاه A فقط تاریخچهٔ همان فروشگاه را می‌بیند.

این روش می‌تواند روی یک سری مشخص خوب باشد، اما دانشی که مدل A پیدا کرده خودبه‌خود به مدل B منتقل نمی‌شود. اگر هر سری کوتاه یا پرنویز باشد، دادهٔ زیادی هم برای یادگیری نداریم.

مدل Global؛ یک مدل برای چند سری مرتبط

قدم بعدی این بود که یک مدل را روی چند سری با هم آموزش بدهیم:

فروشگاه‌های A, B, C, ...
↓
یک مدل مشترک

مدل global می‌تواند الگوهای مشترک میان سری‌ها را یاد بگیرد. مثلاً فروش پایان هفته شاید در بسیاری از شعب دیده شود.

اما این مدل هنوز معمولاً برای همان مجموعه‌داده و همان مسئله ساخته شده است. یک مدل فروش فروشگاه‌ها الزاماً قرار نیست بدون آموزش روی ترافیک شهری یا مصرف برق خوب عمل کند.

Foundation Model؛ پیش‌آموزش روی جهان بزرگ‌تری از سری‌ها

Foundation Model تلاش می‌کند مرحلهٔ آموزش عمومی را از مسئلهٔ نهایی جدا کند:

سری‌های فراوان از دامنه‌ها و فرکانس‌های مختلف
↓
Pretraining
↓
یک مدل عمومی
↓
استفاده روی مسئله‌های جدید

مدل قرار نیست نام تک‌تک سری‌هایی را که دیده حفظ کند. هدف این است که ساختارهای قابل‌انتقال را یاد بگیرد؛ چیزهایی مثل:

  • روندهای آرام و سریع
  • چرخه‌ها و فصل‌ها
  • تغییر سطح
  • شوک و بازیابی
  • نوسان‌های کوتاه و بلند
  • وابستگی میان گذشتهٔ نزدیک و دور

Foundation Model دقیقاً به چه مدلی می‌گوییم؟

بزرگ‌بودن به‌تنهایی یک مدل را Foundation Model نمی‌کند.

سه ویژگی کنار هم مهم‌اند:

  1. مدل روی داده‌ای بزرگ و متنوع پیش‌آموزش دیده باشد.
  2. دانشی که یاد گرفته روی مسئله‌ها یا داده‌های جدید قابل‌استفاده باشد.
  3. بتوان آن را مستقیماً یا با مقدار کمی adaptation برای کارهای پایین‌دستی به کار برد.

پس یک Transformer بسیار بزرگ که فقط روی تاریخچهٔ یک سهم آموزش دیده، Foundation Model نیست. در مقابل، مدلی کوچک‌تر که روی دامنه‌های بسیار متنوع آموزش دیده و روی سری‌های ندیده انتقال پیدا می‌کند، به فلسفهٔ Foundation Model نزدیک‌تر است.

Pretraining چه فرقی با آموزش عادی دارد؟

در آموزش عادی می‌گوییم:

این دادهٔ مشخص را بگیر
برای همین مسئله یک مدل بساز

در pretraining می‌گوییم:

این جهان بزرگ از داده‌ها را ببین
یک دانش عمومی یاد بگیر
بعداً آن دانش را روی مسئله‌های مختلف مصرف می‌کنیم

پیش‌آموزش یک هدف جادویی جدا ندارد. در TimesFM، مدل بارها گذشتهٔ یک سری را می‌بیند و باید آیندهٔ آن را پیش‌بینی کند. تفاوت اصلی در مقیاس و تنوع داده‌هاست.

مسئلهٔ عمومی پیش‌بینی

context y₁:C
target yC+1:C+H
forecast f(context)

C طول گذشته‌ای است که مدل می‌بیند و H طول آینده‌ای است که باید پیش‌بینی کند.

این تمرین روی تعداد زیادی سری تکرار می‌شود. اگر مدل در این مسیر فقط یک الگوی خاص را حفظ کند، روی سری‌های دیگر شکست می‌خورد. برای کم‌کردن loss در یک مجموعهٔ بسیار متنوع، مجبور می‌شود الگوهای عمومی‌تری پیدا کند.

Zero-shot، Few-shot و Fine-tuning

این سه اصطلاح را باید از هم جدا کنیم.

Zero-shot

مدل وزن‌هایش را تغییر نمی‌دهد. فقط گذشتهٔ سری جدید را می‌گیرد و آینده را پیش‌بینی می‌کند:

سری جدید → مدل ازپیش‌آموزش‌دیده → پیش‌بینی

مدل ممکن است هرگز همین dataset یا همین دارایی را در pretraining ندیده باشد.

Few-shot

این اصطلاح در سری زمانی گاهی به این معنی استفاده می‌شود که مقدار کمی context یا دادهٔ مسئلهٔ جدید در اختیار مدل است. بسته به مقاله، ممکن است وزن‌ها تغییر کنند یا نکنند؛ پس باید تعریف هر پژوهش را جدا خواند.

Fine-tuning

در fine-tuning، وزن‌های مدل یا بخشی از آن‌ها با دادهٔ مسئلهٔ جدید به‌روزرسانی می‌شوند:

مدل عمومی + دادهٔ مالی
↓
آموزش تکمیلی
↓
مدل سازگارشده با امور مالی

چرا ساخت Foundation Model برای سری زمانی سخت‌تر از چیزی است که به نظر می‌رسد؟

در زبان، با وجود پیچیدگی، واحدهایی مثل کلمه و subword داریم. مدل می‌تواند یک vocabulary بسازد. اما سری زمانی vocabulary مشخصی ندارد.

عدد 100 در دو سری ممکن است معنای کاملاً متفاوتی داشته باشد:

دمای 100 درجه
قیمت 100 دلار
فروش 100 واحد
ضربان 100 بار در دقیقه

چالش‌های مهم‌تر:

  • مقیاس سری‌ها متفاوت است.
  • فرکانس‌ها از ثانیه‌ای تا ماهانه فرق می‌کنند.
  • طول context و horizon ثابت نیست.
  • بعضی سری‌ها فصلی‌اند و بعضی تقریباً بی‌فصل.
  • داده‌های واقعی missing value، outlier و تغییر رژیم دارند.
  • برخلاف متن عمومی، corpus عظیم و آزاد سری زمانی به‌سادگی پیدا نمی‌شود.
  • در بسیاری از کاربردها فقط پیش‌بینی نقطه‌ای کافی نیست و عدم‌قطعیت هم مهم است.

پس کپی‌کردن مستقیم یک LLM و ریختن عددها داخل آن، مسئله را حل نمی‌کند. باید تعریف کنیم «توکن» در سری زمانی چیست، سری‌ها چطور هم‌مقیاس می‌شوند و مدل با horizonهای مختلف چگونه کار می‌کند.

TimesFM چیست؟

TimesFM مخفف Time Series Foundation Model و محصول Google Research است. مقالهٔ اصلی آن با عنوان A Decoder-Only Foundation Model for Time-Series Forecasting در ICML 2024 منتشر شد.

ایدهٔ اصلی‌اش آشناست:

همان‌طور که یک مدل زبانی با دیدن توکن‌های قبلی توکن بعدی را می‌سازد، یک مدل سری زمانی هم می‌تواند با دیدن patchهای گذشته patch آینده را پیش‌بینی کند.

اما کلمه‌ای در کار نیست. ورودی مجموعه‌ای از عددهاست و باید آن‌ها را به چیزی شبیه token تبدیل کنیم.

یک نکتهٔ مهم دربارهٔ نسخه‌ای که بررسی می‌کنیم

تا زمان نوشتن این مقاله، نسل‌های جدیدتری از TimesFM منتشر شده‌اند. بااین‌حال برای اینکه بحث معماری دقیق و قابل‌بازتولید بماند، تمرکز این نوشته روی نخستین checkpoint عمومی مدل است:

google/timesfm-1.0-200m-pytorch

بنابراین هرجا در این مقاله از TimesFM حرف می‌زنیم، منظور اصلی نسخهٔ 1.0 با حدود ۲۰۰ میلیون پارامتر است؛ مگر اینکه صریحاً نسخهٔ دیگری نام برده شود.

نسخهٔ مقالهٔ پژوهشی و checkpoint نهایی عمومی در بعضی عددهای گزارش‌شده تفاوت دارند. نسخه‌های اولیهٔ متن پژوهشی آزمایش مدلی حدود ۲۲۵ میلیون پارامتر روی حدود یک میلیارد time point را شرح می‌دهند؛ انتشار عمومی و گزارش نهایی Google Research از checkpoint حدود ۲۰۰ میلیون پارامتری و corpus گسترش‌یافتهٔ ۱۰۰ میلیارد time point حرف می‌زنند. در این نوشته، مشخصات checkpoint عمومی معیار عملی ماست.

چرا به TimesFM می‌گوییم Decoder-only؟

در Transformer اصلی ترجمه، Encoder ابتدا کل ورودی را پردازش می‌کرد و Decoder با کمک Cross-Attention از آن برای ساخت خروجی استفاده می‌کرد. TimesFM این دو مسیر جدا را ندارد؛ همه‌چیز داخل یک stack از blockهای decoder-style اتفاق می‌افتد.

هر patch فقط خودش و patchهای قبل از خودش را می‌بیند:

patch 1 → می‌تواند patch 1 را ببیند
patch 2 → می‌تواند patchهای 1 و 2 را ببیند
patch 3 → می‌تواند patchهای 1 تا 3 را ببیند

این محدودیت با یک causal mask ساخته می‌شود. اگر patch اول هنگام آموزش patchهای بعدی را می‌دید، جواب آینده را از قبل در اختیار داشت و عملاً تقلب می‌کرد.

اما این به معنی ازدست‌رفتن گذشته نیست. نمایش patch سوم، هر سه patch را دیده و برای پیش‌بینی بخش بعدی استفاده می‌شود. فقط اجازه نداده‌ایم اطلاعات از آینده به گذشته نشت کند.

مزیت این انتخاب این است که معماری یکپارچه‌تر می‌شود، جهت حرکت اطلاعات با جهت زمان هماهنگ می‌ماند و می‌توان از چند جایگاه یک سری برای ساخت هدف‌های آموزشی استفاده کرد. مدل همچنین می‌تواند contextهایی با طول‌های متفاوت دریافت کند.

در مقابل، پیش‌بینی افق‌های بلند معمولاً مرحله‌به‌مرحله انجام می‌شود. بنابراین خطای یک forecast patch می‌تواند وارد مرحلهٔ بعد شود و روی خطاهای بعدی اثر بگذارد. همچنین Encoder–Decoder برای بعضی مسئله‌های چندورودی یا اطلاعات جانبیِ آینده ساختار طبیعی‌تری دارد.

پس Decoder-only همیشه از Encoder–Decoder بهتر نیست؛ برای مسئلهٔ TimesFM، یعنی «گذشتهٔ یک سری را ببین و ادامه‌اش را بساز»، انتخاب ساده و طبیعی‌تری است.

Patch؛ وقتی ۳۲ عدد تبدیل به یک توکن می‌شوند

اگر هر time point را یک token بگیریم، توالی خیلی طولانی می‌شود. TimesFM سری را به تکه‌های پیوسته و بدون overlap تقسیم می‌کند.

در نسخهٔ 1.0:

input_patch_len = 32

فرض کن ۹۶ روز داده داریم:

روزهای 1 تا 32   → patch₁
روزهای 33 تا 64  → patch₂
روزهای 65 تا 96  → patch₃

پس ۹۶ عدد به سه token تبدیل می‌شوند.

تعداد patchها

context_length C
input_patch_length P
number_of_patches N = C ÷ P

مثلاً اگر context برابر ۶۴ نقطه و P = 32 باشد، ورودی فقط دو patch دارد:

مثال یک context با ۶۴ نقطه

context_length 64
patch_length 32
number_of_patches 64 ÷ 32 = 2

پس حتی یک مدل بزرگ هم در این تنظیم خاص، از ۶۴ مقدار خام فقط دو token زمانی می‌سازد. اندازهٔ patch مستقیماً تعیین می‌کند Attention با چه دقت زمانی‌ای روابط را ببیند.

آیا خودِ ۳۲ عدد مستقیم وارد Transformer می‌شوند؟

نه. Transformer انتظار دارد هر token یک بردار با اندازهٔ ثابت D باشد. پس هر patch ابتدا وارد یک Residual Block می‌شود.

32 raw values
↓
Input Residual Block
↓
1280-dimensional token

این Residual Block در اصل یک MLP با skip connection است؛ همان چیزی که در دو مقالهٔ قبلی یاد گرفتیم.

تبدیل patch به token

patchⱼ yP(j−1)+1:Pj
tokenⱼ InputResidualBlock(patchⱼ) + PEⱼ

PEⱼ اطلاعات موقعیت patch است. بدون آن، مدل نمی‌فهمد کدام patch قدیمی‌تر و کدام تازه‌تر است.

در checkpoint عمومی TimesFM 1.0:

model_dimension = D = 1280
number_of_layers = 20
number_of_attention_heads = 16

پس هر patch بعد از ورودی، به یک بردار ۱۲۸۰بعدی تبدیل می‌شود و از ۲۰ Transformer block می‌گذرد.

داخل backbone چه اتفاقی می‌افتد؟

هر block اصلی دو بخش آشنا دارد:

Multi-Head Causal Self-Attention
↓
Feed-Forward Network

به‌اضافهٔ residual connection و normalization.

Attention تعیین می‌کند هر patch برای ساختن نمایش خودش، از کدام patchهای قبلی اطلاعات بگیرد. Feed-Forward Network بعد از آن، نمایش هر patch را جداگانه پردازش می‌کند.

خروجی causal در جایگاه j

outputⱼ Transformer(token₁, token₂, …, tokenⱼ)

به‌دلیل causal mask، outputⱼ نمی‌تواند از patchهای بعد از j اطلاعات بگیرد. پس می‌توانیم از آن برای پیش‌بینی آیندهٔ همان نقطه استفاده کنیم، بدون اینکه leakage رخ دهد.

خروجی مدل؛ یک token چند عدد آینده می‌سازد؟

در یک LLM، هر token معمولاً توکن بعدی را پیش‌بینی می‌کند. اما اگر TimesFM هر بار فقط یک عدد آینده بسازد، پیش‌بینی افق بلند به گام‌های autoregressive بسیار زیادی نیاز دارد و خطاها روی هم جمع می‌شوند.

TimesFM به‌جای یک نقطه، یک output patch می‌سازد:

output_patch_len = 128

خروجی Transformer وارد Output Residual Block می‌شود و به ۱۲۸ مقدار آینده نگاشت می‌شود:

تبدیل نمایش پنهان به پیش‌بینی

hidden_state outputⱼ
forecast_patch OutputResidualBlock(hidden_state)
forecast_patch_length 128

این یعنی input patch می‌تواند ۳۲ نقطه باشد، اما output patch برابر ۱۲۸ نقطه باشد. برابرنبودن این دو یک انتخاب عمدی معماری است.

مدل هنگام آموزش دقیقاً چه تمرینی می‌کند؟

فرض کن یک سری ۵۱۲نقطه‌ای داریم و patch ورودی ۳۲ و خروجی ۱۲۸ است.

مدل در یک توالی آموزشی چند سؤال می‌گیرد:

نقاط 1 تا 32   → نقاط 33 تا 160 را پیش‌بینی کن
نقاط 1 تا 64   → نقاط 65 تا 192 را پیش‌بینی کن
نقاط 1 تا 96   → نقاط 97 تا 224 را پیش‌بینی کن
...

به‌خاطر causal attention، خروجی هر patch فقط گذشتهٔ مجاز خودش را دیده است. بنابراین از یک سری، چند هدف آموزشی به‌طور هم‌زمان ساخته می‌شود.

Loss پیش‌آموزش به‌شکل ساده

predictionⱼ forecast after patchⱼ
targetⱼ true next output patch
loss average(MSE(predictionⱼ, targetⱼ) across patches)

Backpropagation از تمام این lossها عبور می‌کند و Input Residual Block، Transformerها و Output Residual Block را با هم آموزش می‌دهد.

اگر horizon بیشتر از ۱۲۸ باشد چه می‌شود؟

مدل اولین patch آینده را می‌سازد. سپس پیش‌بینی تولیدشده به انتهای context اضافه می‌شود و مدل patch بعدی را تولید می‌کند:

context واقعی
↓
forecast 1
↓
context واقعی + forecast 1
↓
forecast 2

Autoregressive patch decoding

first_forecast ŷC+1:C+128
extended_context [y₁:C ; first_forecast]
second_forecast ŷC+129:C+256

این هنوز autoregressive است، اما به‌جای تولید یک نقطه در هر گام، یک بلوک بزرگ تولید می‌شود. در نتیجه برای افق ۵۱۲، با output patch برابر ۱۲۸ فقط چهار مرحله لازم داریم.

TimesFM روی چه چیزی «دنیا‌دیده» شد؟

طبق گزارش انتشار عمومی Google Research، corpus نهایی حدود ۱۰۰ میلیارد time point واقعی داشته است. بخش مهمی از داده از Google Trends و Wikipedia Pageviews آمده و مجموعه‌های عمومی دیگر هم به آن اضافه شده‌اند. نسخهٔ پژوهشی اولیه همچنین استفاده از M4، Traffic و Electricity را شرح می‌دهد.

این تنوع از دو جهت مهم است:

  1. مدل شکل‌های متفاوت رفتار زمانی را می‌بیند.
  2. مدل با granularities متفاوت، از ساعتی تا ماهانه، مواجه می‌شود.

دادهٔ مصنوعی هم می‌تواند الگوهای پایه‌ای مثل روند و فصل را با کنترل بیشتر به مدل نشان بدهد؛ دادهٔ واقعی بی‌نظمی و پیچیدگی دنیای واقعی را اضافه می‌کند.

اما «۱۰۰ میلیارد نقطه» را نباید با «۱۰۰ میلیارد مثال مستقل و باکیفیت» یکی گرفت. نقاط مجاور یک سری به هم وابسته‌اند، بعضی دامنه‌ها سهم بیشتری دارند و حجم زیاد همیشه به معنی پوشش متوازن همهٔ دنیا نیست.

مدل با مقیاس‌های متفاوت چه می‌کند؟

یک سری ممکن است اطراف 0.01 و دیگری اطراف 100000 حرکت کند. اگر مقدار خام را بدون ملاحظه وارد مدل کنیم، مقیاس می‌تواند بر یادگیری غلبه کند.

TimesFM در مسیر inference داده را بر اساس context هر سری نرمال می‌کند و پس از پیش‌بینی، خروجی را به مقیاس اصلی برمی‌گرداند. فلسفهٔ این کار مهم است:

مدل به‌جای حفظ سطح عددی هر سری،
روی شکل تغییرات و ساختار زمانی تمرکز کند.

این نرمال‌سازی به انتقال میان دامنه‌ها کمک می‌کند، ولی اطلاعات وابسته به سطح مطلق را هم ممکن است کم‌رنگ کند. هیچ preprocessing خنثی نیست؛ هرکدام یک فرض وارد مدل می‌کند.

Frequency indicator چیست؟

نسخهٔ عمومی TimesFM یک نشانگر دسته‌ای فرکانس هم می‌پذیرد. این ورودی به مدل سرنخ می‌دهد که سری تقریباً در چه مقیاس زمانی قرار دارد.

در API نسخهٔ 1.0 معمولاً سه گروه دیده می‌شود:

0 → فرکانس بالا، تا حدود روزانه
1 → فرکانس متوسط، مانند هفتگی یا ماهانه
2 → فرکانس پایین‌تر

این indicator خودِ timestamp کامل نیست. فقط یک دسته‌بندی کلی از granularity است. در نوت‌بوک بیت‌کوین روزانه از freq = 0 استفاده می‌کنیم.

Zero-shot بودن TimesFM دقیقاً یعنی چه؟

وقتی TimesFM را روی بیت‌کوین اجرا می‌کنیم و وزن‌هایش را تغییر نمی‌دهیم، کار zero-shot انجام داده‌ایم:

آخرین 512 قیمت بیت‌کوین
↓
TimesFM frozen
↓
پیش‌بینی 64 روز آینده

مدل از خود context بیت‌کوین استفاده می‌کند، اما روی آن training انجام نمی‌دهد. این با «بدون اطلاعات» فرق دارد. مدل دادهٔ گذشتهٔ همان سری را می‌بیند؛ چیزی که نمی‌گیرد gradient و به‌روزرسانی وزن روی dataset جدید است.

چرا این ایده جذاب است؟

Foundation Model می‌تواند هزینهٔ شروع یک پروژه را کم کند:

  • قبل از ساخت مدل اختصاصی یک baseline قوی داریم.
  • برای datasetهای کوچک الزاماً از صفر آموزش نمی‌دهیم.
  • یک مدل می‌تواند context و horizonهای مختلف را بپذیرد.
  • دانش میان دامنه‌ها منتقل می‌شود.
  • می‌توانیم بعداً با fine-tuning یا adapter آن را تخصصی کنیم.

TimesFM در ارزیابی‌های مقالهٔ اصلی توانست در تعدادی از benchmarkهای ندیده به مدل‌های supervised نزدیک شود یا از بعضی آن‌ها جلو بزند؛ درحالی‌که آن مدل‌های supervised برای dataset هدف جداگانه آموزش دیده بودند.

این نتیجه مهم است، اما معنایش این نیست که TimesFM در همهٔ datasetها بهترین مدل است. ادعای درست‌تر این است:

یک مدل واحد و ازپیش‌آموزش‌دیده می‌تواند بدون آموزش روی dataset هدف، در دامنه‌های متنوع baseline رقابتی تولید کند.

«مدل دنیا‌دیده» چه چیزی را تضمین نمی‌کند؟

دنیا‌دیدگی با دانای کل بودن فرق دارد.

TimesFM نمی‌تواند:

  • شوک سیاسی یا خبری دیده‌نشده را از هیچ پیش‌بینی کند.
  • رابطهٔ علّی را صرفاً از همبستگی زمانی تضمین کند.
  • تغییر رژیم بازار را همیشه به‌موقع تشخیص دهد.
  • عدم‌قطعیت واقعی را در نسخهٔ 1.0 به‌طور کامل و کالیبره‌شده ارائه کند.
  • جایگزین backtest، baseline ساده و ارزیابی خارج از نمونه شود.
  • تضمین کند الگوی آموخته‌شده از Google Trends برای بازار مالی بهترین الگوست.

در مالی، نسبت signal به noise پایین است، توزیع داده تغییر می‌کند و رقابت باعث محوشدن الگوهای قابل‌سوءاستفاده می‌شود. مدلی که روی ترافیک، فروش و جست‌وجو عالی است، لزوماً رفتار قیمت دارایی را بدون adaptation کامل نمی‌فهمد.

چرا TimesFM خام ممکن است در امور مالی مشکل داشته باشد؟

سه مسئله مهم داریم.

شکاف دامنه

ترکیب corpus عمومی با دادهٔ مالی یکی نیست. الگوی بازدید صفحه یا مصرف برق می‌تواند فصل‌پذیر و نسبتاً پایدار باشد؛ قیمت بازار تحت شوک، انتظارات و تغییر رژیم است.

کمبود دادهٔ مخصوص هر دارایی

اگر کل مدل ۲۰۰میلیونی را روی دادهٔ محدود چند سهم fine-tune کنیم، خطر overfitting بالاست.

تعارض تخصص و تعمیم

اگر مدل را خیلی به S&P100 تخصصی کنیم، شاید روی همان سهام بهتر شود اما روی سهم ندیده از S&P500 بدتر عمل کند. یعنی چیزی به دست آورده‌ایم و چیزی از دست داده‌ایم.

اجرای واقعی TimesFM 1.0 روی لپ‌تاپ

برای اجرای دقیق نسخهٔ 1.0 باید package قدیمی را عمداً pin کنیم، چون package فعلی TimesFM نسل‌های جدیدتری دارد.

%pip install -q "timesfm==1.3.0" torch huggingface_hub

بعد checkpoint رسمی PyTorch را بارگذاری می‌کنیم:

import timesfm

model = timesfm.TimesFm(
    context_len=512,
    horizon_len=64,
    input_patch_len=32,
    output_patch_len=128,
    num_layers=20,
    model_dims=1280,
    backend="cpu",
)

model.load_from_checkpoint(
    repo_id="google/timesfm-1.0-200m-pytorch"
)

و برای یک سری روزانه:

point_forecast, quantile_forecast = model.forecast(
    inputs=[context_values],
    freq=[0],
)

forecast = point_forecast[0][:64]

مدل روی CPU هم قابل اجراست، اما بارگذاری آن سبک نیست. checkpoint PyTorch حدود ۸۱۴ مگابایت است و مستندات رسمی نسخهٔ قدیمی برای dependencyها حافظهٔ زیادی توصیه می‌کنند. GPU سرعت را بهتر می‌کند، ولی برای یک آزمایش zero-shot کوچک الزام معماری نیست.

نوت‌بوک کامل تست بیت‌کوین کنار همین مقاله قرار دارد. در آن، دادهٔ روزانهٔ BTC-USD دانلود می‌شود، آخرین ۵۱۲ روز به مدل داده می‌شود، ۶۴ روز آینده پیش‌بینی و سپس MAE و RMSE همراه نمودار محاسبه می‌شوند.

چطور TimesFM را منصفانه ارزیابی کنیم؟

یک نمودار زیبا کافی نیست. حداقل باید این اصول را رعایت کنیم:

  1. داده را زمانی split کنیم؛ آینده نباید وارد train یا انتخاب hyperparameter شود.
  2. TimesFM را با baselineهای ساده مثل آخرین مقدار، میانگین متحرک و مدل آماری مقایسه کنیم.
  3. فقط یک پنجرهٔ تست نداشته باشیم؛ rolling backtest انجام دهیم.
  4. چند metric مثل MAE، RMSE و خطای نسبی را کنار هم ببینیم.
  5. در دادهٔ مالی، بازده و جهت حرکت را هم جدا از خطای قیمت بررسی کنیم.
  6. هزینهٔ معامله و اثر تصمیم عملی را از دقت عددی جدا نکنیم.

ممکن است مدلی RMSE بهتری داشته باشد ولی هیچ مزیت معاملاتی پایدار ایجاد نکند. forecasting خوب و strategy سودآور یک چیز نیستند.

نقد معماری TimesFM

نقطهٔ قوت اول: یک زبان مشترک برای سری‌ها

Patching و نرمال‌سازی باعث می‌شوند سری‌های متفاوت به نمایش مشترک‌تری تبدیل شوند. مدل به‌جای وابستگی کامل به واحد اندازه‌گیری، روی شکل رفتار تمرکز می‌کند.

نقطهٔ قوت دوم: Decoder-only و context متغیر

مدل causal به‌طور طبیعی از گذشته برای آینده استفاده می‌کند و می‌تواند با history lengthهای مختلف کار کند.

نقطهٔ قوت سوم: خروجی patch بزرگ

پیش‌بینی ۱۲۸ نقطه در هر مرحله تعداد گام‌های autoregressive را کم می‌کند و برای horizon بلند مفید است.

محدودیت اول: patch می‌تواند جزئیات را فشرده کند

وقتی ۳۲ نقطه یک token می‌شوند، Attention دیگر مستقیماً میان تک‌تک time pointها عمل نمی‌کند. MLP ورودی باید اطلاعات مهم داخل patch را در بردار ۱۲۸۰بعدی حفظ کند.

محدودیت دوم: univariate بودن نسخهٔ 1.0

نسخهٔ 1.0 اساساً گذشتهٔ یک سری را برای پیش‌بینی آیندهٔ همان سری استفاده می‌کند. رابطهٔ هم‌زمان چند سری، حجم، نرخ بهره یا متغیرهای بیرونی مستقیماً در backbone اصلی آن مدل نمی‌شود.

محدودیت سوم: point forecast

نسخهٔ 1.0 عمدتاً برای point forecasting عرضه شد. در کاربردهای حساس، دانستن دامنهٔ عدم‌قطعیت گاهی از یک عدد مرکزی مهم‌تر است.

محدودیت چهارم: corpus عمومی الزاماً نمایندهٔ مالی نیست

مدل عمومی biasهای corpus خودش را دارد. دیدن دادهٔ زیاد، شکاف دامنه را حذف نمی‌کند؛ فقط نقطهٔ شروع را بهتر می‌کند.

آیا Foundation Model همان مدل نهایی ماست؟

بهتر است Foundation Model را «پایه» ببینیم، نه جواب نهایی.

سه حالت منطقی داریم:

اگر zero-shot کافی است:
مدل frozen را مستقیم استفاده کن

اگر دادهٔ مناسب و سخت‌افزار زیاد داری:
full fine-tuning را بررسی کن

اگر داده یا منابع محدود است:
PEFT، LoRA یا Adapter را بررسی کن

جمع‌بندی

Foundation Model در سری زمانی یعنی مدلی که قبل از مسئلهٔ ما، روی مجموعه‌ای بزرگ و متنوع از توالی‌ها پیش‌آموزش دیده و قرار است دانش زمانی‌اش را به دادهٔ تازه منتقل کند.

TimesFM این فلسفه را با چند تصمیم معماری پیاده می‌کند:

سری خام
↓
تقسیم به patchهای 32 نقطه‌ای
↓
تبدیل هر patch به token با MLP residual
↓
20 لایهٔ Transformer با causal self-attention
↓
Output Residual Block
↓
پیش‌بینی patch آینده

دلیل جذابیتش فقط بزرگی مدل نیست. ارزش اصلی در این است که یک مدل واحد، بعد از پیش‌آموزش گسترده، می‌تواند روی سری ندیده بدون آموزش دوباره پیش‌بینی تولید کند.

اما دنیا‌دیده‌بودن به معنی همه‌چیزدان‌بودن نیست. TimesFM یک prior قدرتمند و یک baseline عمومی به ما می‌دهد، ولی کیفیت نهایی همچنان باید روی دادهٔ واقعی، با split زمانی، rolling backtest و baselineهای ساده سنجیده شود.

منابع

این مقاله با روایت و مثال‌های تألیفی نوشته شده و مشخصات فنی آن بر منابع اولیهٔ زیر تکیه دارد:

  1. Abhimanyu Das، Weihao Kong، Rajat Sen و Yichen Zhou، A Decoder-Only Foundation Model for Time-Series Forecasting، ICML 2024.
  2. Google Research، A Decoder-Only Foundation Model for Time-Series Forecasting، معرفی رسمی TimesFM و corpus انتشار عمومی.
  3. Google Research، مخزن رسمی TimesFM، کد، checkpointها و مستندات نسخه‌ها.
  4. Google، TimesFM 1.0 200M PyTorch checkpoint، وزن رسمی استفاده‌شده برای اجرای محلی.
  5. Yuqi Nie و همکاران، A Time Series Is Worth 64 Words: Long-term Forecasting with Transformers، ICLR 2023؛ منبع ایدهٔ patching در مدل‌های Transformer سری زمانی.
  6. Rishi Bommasani و همکاران، On the Opportunities and Risks of Foundation Models، ۲۰۲۱؛ برای تعریف و فلسفهٔ Foundation Model.