psnc commited on
Commit
fa094e7
ยท
verified ยท
1 Parent(s): cb45c14

Sync from GitHub Actions

Browse files
Files changed (5) hide show
  1. .claude/skills/verify/SKILL.md +0 -47
  2. AGENTS.md +0 -227
  3. CLAUDE.md +0 -297
  4. README_N-BEATS.md +0 -122
  5. requirements.txt +1 -1
.claude/skills/verify/SKILL.md DELETED
@@ -1,47 +0,0 @@
1
- ---
2
- name: verify
3
- description: ์ด ์ €์žฅ์†Œ์˜ ๋ณ€๊ฒฝ์„ ์‹ค์ œ ๊ตฌ๋™์œผ๋กœ ๊ฒ€์ฆํ•˜๋Š” ๋ ˆ์‹œํ”ผ โ€” ๋กœ์ปฌ ์„œ๋ฒ„ ๊ธฐ๋™, UI ๊ตฌ๋™, API ํ˜ธ์ถœ ๋ฐฉ๋ฒ•
4
- ---
5
-
6
- # nbeats ๊ฒ€์ฆ ๋ ˆ์‹œํ”ผ
7
-
8
- ## ๋กœ์ปฌ ์„œ๋ฒ„ ๊ธฐ๋™
9
-
10
- ๋ฐ˜๋“œ์‹œ `venv`๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค (`.venv`๋Š” ์˜์กด์„ฑ ๋ถˆ์™„์ „ โ€” slowapi ์—†์Œ, ์‹œ์Šคํ…œ anaconda python๋„ ๋งˆ์ฐฌ๊ฐ€์ง€):
11
-
12
- ```bash
13
- ./venv/bin/python -m uvicorn main:app --port 8077 # ๋ถ€ํŒ… 20~40์ดˆ (torch/darts ์ž„ํฌํŠธ)
14
- curl http://127.0.0.1:8077/health # {"status":"ok"} ๋Œ€๊ธฐ
15
- ```
16
-
17
- macOS Apple Silicon์—์„œ PyTorch+LightGBM OpenMP ์ถฉ๋Œ ๋ฐฉ์–ด ์ฝ”๋“œ๊ฐ€ main.py์— ์ด๋ฏธ ์žˆ์œผ๋ฏ€๋กœ ๋ณ„๋„ env ๋ถˆํ•„์š”.
18
-
19
- ## ํ‘œ๋ฉด ๊ตฌ๋™
20
-
21
- - ํŽ˜์ด์ง€: `/`, `/prophet`, `/arima`, `/xgboost`, `/ets`, `/lightgbm`, `/theta`, `/hybrid`, `/timesfm`
22
- - ์•™์ƒ๋ธ” API (ํŒŒ์ผ ์—…๋กœ๋“œ + horizon๋งŒ ๋ฐ›์Œ):
23
- ```bash
24
- curl -X POST http://127.0.0.1:8077/api/hybrid/predict \
25
- -F "file=@test_data/stable_trend.csv" -F "forecast_horizon=12"
26
- ```
27
- - ํ…Œ์ŠคํŠธ ๋ฐ์ดํ„ฐ: `test_data/stable_trend.csv` (์›”๋ณ„ 120ํ–‰, ๋น ๋ฆ„), `daily_high_freq.csv` (์ผ๋ณ„ 400ํ–‰, ์ŠคํŠธ๋ ˆ์Šค), `small_dataset.csv` (31ํ–‰ โ€” 50ํ–‰ ๋ฏธ๋งŒ ๊ฒ€์ฆ ์—๋Ÿฌ ํ™•์ธ์šฉ)
28
- - ์•™์ƒ๋ธ” ์†Œ์š”: ์›”๋ณ„ 120ํ–‰ ๊ธฐ์ค€ ๋กœ์ปฌ ์ˆ˜์‹ญ ์ดˆ, HF Space 26์ดˆ / ์ผ๋ณ„ 400ํ–‰์€ HF Space 103์ดˆ
29
-
30
- ## ๋ธŒ๋ผ์šฐ์ € ํŒŒ์ผ ์—…๋กœ๋“œ (claude-in-chrome)
31
-
32
- file_upload ๋„๊ตฌ๊ฐ€ ํ˜ธ์ŠคํŠธ ๊ฒฝ๋กœ๋ฅผ ๊ฑฐ๋ถ€ํ•˜๋ฏ€๋กœ javascript_tool๋กœ ์ฃผ์ž…:
33
-
34
- ```js
35
- const f = new File([csvText], 'x.csv', {type:'text/csv'});
36
- const dt = new DataTransfer(); dt.items.add(f);
37
- const input = document.getElementById('fileInput');
38
- input.files = dt.files;
39
- input.dispatchEvent(new Event('change', {bubbles:true}));
40
- ```
41
-
42
- ## ๋ผ์ด๋ธŒ Space ํ™•์ธ
43
-
44
- ```bash
45
- curl https://psnc-time-series-prediction.hf.space/health # {"status":"ok"}
46
- curl https://psnc-time-series-prediction.hf.space/api/timesfm/status # {"status":"loaded"}
47
- ```
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
AGENTS.md DELETED
@@ -1,227 +0,0 @@
1
- # AGENTS.md โ€” N-BEATS Time Series Forecasting Service
2
-
3
- ## ํ”„๋กœ์ ํŠธ ๊ฐœ์š”
4
-
5
- FastAPI ๊ธฐ๋ฐ˜ ์‹œ๊ณ„์—ด ์˜ˆ์ธก ์„œ๋น„์Šค. 7๊ฐ€์ง€ ์˜ˆ์ธก ๋ชจ๋ธ์„ ์›น UI์™€ REST API๋กœ ์ œ๊ณตํ•˜๋ฉฐ, Hugging Face Spaces์— Docker ์ปจํ…Œ์ด๋„ˆ๋กœ ๋ฐฐํฌ๋œ๋‹ค.
6
-
7
- - **์„œ๋น„์Šค URL:** https://huggingface.co/spaces/psnc/time-series-prediction
8
- - **๋ผ์ด์„ ์Šค:** MIT License
9
-
10
- ---
11
-
12
- ## ๊ธฐ์ˆ  ์Šคํƒ
13
-
14
- | ๋ ˆ์ด์–ด | ๊ธฐ์ˆ  |
15
- |--------|------|
16
- | Web Framework | FastAPI + Uvicorn (ASGI) |
17
- | Deep Learning | Darts (N-BEATS), PyTorch, PyTorch Lightning |
18
- | Statistical | statsmodels (ARIMA, ETS, Theta), Prophet |
19
- | ML | XGBoost, LightGBM |
20
- | Data | pandas, numpy |
21
- | Frontend | Vanilla JS, Chart.js, XLSX.js (๋‹คํฌ ํ…Œ๋งˆ) |
22
- | Deploy | Docker โ†’ Hugging Face Spaces via GitHub Actions |
23
-
24
- ---
25
-
26
- ## ๋””๋ ‰ํ„ฐ๋ฆฌ ๊ตฌ์กฐ
27
-
28
- ```
29
- nbeats/
30
- โ”œโ”€โ”€ main.py # FastAPI ์•ฑ, ๋ชจ๋“  ๋ผ์šฐํŠธ ์ •์˜ (782์ค„)
31
- โ”œโ”€โ”€ requirements.txt
32
- โ”œโ”€โ”€ Dockerfile # HF Spaces ๋ฐฐํฌ์šฉ (port 7860)
33
- โ”œโ”€โ”€ run.sh # ๊ฐœ๋ฐœ ์„œ๋ฒ„ (--reload)
34
- โ”œโ”€โ”€ start.sh # ํ”„๋กœ๋•์…˜ ์„œ๋ฒ„
35
- โ”œโ”€โ”€ run_test.py # ์„œ๋น„์Šค ์ง์ ‘ ํ…Œ์ŠคํŠธ
36
- โ”œโ”€โ”€ .github/workflows/deploy.yml # main push โ†’ HF ์ž๋™ ๋ฐฐํฌ
37
- โ”œโ”€โ”€ src/domains/time_series_prediction/
38
- โ”‚ โ”œโ”€โ”€ data_service.py # ํŒŒ์ผ ํŒŒ์‹ฑ ๋ฐ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ
39
- โ”‚ โ”œโ”€โ”€ data_profile.py # ๊ณตํ†ต ๋ฐ์ดํ„ฐ ๋ถ„์„ (DataProfile ๋ฐ์ดํ„ฐํด๋ž˜์Šค)
40
- โ”‚ โ”œโ”€โ”€ model_parameters.py # N-BEATS ํŒŒ๋ผ๋ฏธํ„ฐ ์Šคํ‚ค๋งˆ
41
- โ”‚ โ”œโ”€โ”€ nbeats_service.py # N-BEATS ๊ตฌํ˜„ (575์ค„)
42
- โ”‚ โ”œโ”€โ”€ prophet_service.py # Prophet ๊ตฌํ˜„ (412์ค„)
43
- โ”‚ โ”œโ”€โ”€ arima_service.py # ARIMA/SARIMA ๊ตฌํ˜„ (516์ค„)
44
- โ”‚ โ”œโ”€โ”€ xgboost_service.py # XGBoost ๊ตฌํ˜„ (557์ค„)
45
- โ”‚ โ”œโ”€โ”€ ets_service.py # ETS/Holt-Winters ๊ตฌํ˜„ (315์ค„)
46
- โ”‚ โ”œโ”€โ”€ lightgbm_service.py # LightGBM ๊ตฌํ˜„ (506์ค„)
47
- โ”‚ โ””โ”€โ”€ theta_service.py # Theta Method ๊ตฌํ˜„ (302์ค„)
48
- โ”œโ”€โ”€ static/
49
- โ”‚ โ”œโ”€โ”€ index.html # N-BEATS UI
50
- โ”‚ โ”œโ”€โ”€ prophet.html
51
- โ”‚ โ”œโ”€โ”€ arima.html
52
- โ”‚ โ”œโ”€โ”€ xgboost.html
53
- โ”‚ โ”œโ”€โ”€ ets.html
54
- โ”‚ โ”œโ”€โ”€ lightgbm.html
55
- โ”‚ โ””โ”€โ”€ theta.html
56
- โ”œโ”€โ”€ test_data/ # ํ…Œ์ŠคํŠธ์šฉ CSV ๋ฐ์ดํ„ฐ์…‹
57
- โ”œโ”€โ”€ tests/
58
- โ”‚ โ”œโ”€โ”€ test_nbeats.py
59
- โ”‚ โ”œโ”€โ”€ test_auto_scaling.py
60
- โ”‚ โ””โ”€โ”€ generate_test_datasets.py
61
- โ””โ”€โ”€ backend/ # ๋ ˆ๊ฑฐ์‹œ ์ฝ”๋“œ (๋ณด๊ด€์šฉ)
62
- ```
63
-
64
- ---
65
-
66
- ## ๊ตฌํ˜„๋œ ๋ชจ๋ธ
67
-
68
- | ๋ชจ๋ธ | ์œ ํ˜• | ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ | ํŠน์ง• |
69
- |------|------|-----------|------|
70
- | **N-BEATS** | ๋”ฅ๋Ÿฌ๋‹ | Darts + PyTorch | ์Šคํƒ ๊ธฐ๋ฐ˜ ์‹ ๊ฒฝ๋ง, ์•™์ƒ๋ธ” |
71
- | **Prophet** | ๋ฒ ์ด์ง€์•ˆ | Meta/Facebook | ์ถ”์„ธ ๋ณ€ํ™”์  ์ž๋™ ๊ฐ์ง€, ์‹ ๋ขฐ๊ตฌ๊ฐ„ |
72
- | **ARIMA/SARIMA** | ํ†ต๊ณ„ | statsmodels | AIC ๊ธฐ๋ฐ˜ ์ž๋™ ์ฐจ์ˆ˜ ์„ ํƒ |
73
- | **XGBoost** | ๊ทธ๋ž˜๋””์–ธํŠธ ๋ถ€์ŠคํŒ… | xgboost | ๋ž˜๊ทธ ํ”ผ์ฒ˜, ๋กค๋ง ํ†ต๊ณ„ |
74
- | **LightGBM** | ๊ทธ๋ž˜๋””์–ธํŠธ ๋ถ€์ŠคํŒ… | lightgbm | Leaf-wise ๋ถ„ํ• , XGBoost ๋Œ€๋น„ 2-5๋ฐฐ ๋น ๋ฆ„ |
75
- | **ETS** | ์ง€์ˆ˜ํ‰ํ™œ | statsmodels | Holt-Winters, ๊ฐ์‡  ์ถ”์„ธ |
76
- | **Theta** | ๊ณ ์ „ ํ†ต๊ณ„ | statsmodels | M3 ๋Œ€ํšŒ ์šฐ์Šน ์•Œ๊ณ ๋ฆฌ์ฆ˜ |
77
-
78
- ---
79
-
80
- ## API ๊ตฌ์กฐ
81
-
82
- ### ๊ณตํ†ต ํŒจํ„ด
83
-
84
- - **Page Routes:** `GET /`, `/prophet`, `/arima`, `/xgboost`, `/ets`, `/lightgbm`, `/theta`
85
- - **Health:** `GET /health`, `GET /api/status`
86
- - **Template:** `GET /download_template?file_format=csv|xlsx|json`
87
-
88
- ### ๋ชจ๋ธ๋ณ„ ์—”๋“œํฌ์ธํŠธ
89
-
90
- ```
91
- POST /nbeats โ†’ N-BEATS ์˜ˆ์ธก (๋ฐฑํ…Œ์ŠคํŠธ ์˜ต์…˜)
92
- GET /nbeats/parameters โ†’ ํŒŒ๋ผ๋ฏธํ„ฐ ์Šคํ‚ค๋งˆ
93
- POST /nbeats/evaluate โ†’ ํ›ˆ๋ จ/ํ…Œ์ŠคํŠธ ๋ถ„๋ฆฌ ํ‰๊ฐ€
94
-
95
- POST /api/{prophet,arima,xgboost,ets,lightgbm,theta}/predict
96
- ```
97
-
98
- ### ๊ณตํ†ต ์‘๋‹ต ํ˜•์‹
99
-
100
- ```json
101
- {
102
- "success": true,
103
- "data": [{"ds": "2024-01-01", "y": 100.0, "yhat": 102.5}],
104
- "metrics": {"mae": 2.1, "rmse": 3.4, "mape": 0.021, "r2": 0.95},
105
- "test_size": 30
106
- }
107
- ```
108
-
109
- ---
110
-
111
- ## ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ํŒŒ์ดํ”„๋ผ์ธ
112
-
113
- ### ์ž…๋ ฅ ํฌ๋งท
114
- - **์ง€์›:** CSV, Excel (.xlsx), JSON
115
- - **ํ•„์ˆ˜ ์ปฌ๋Ÿผ:** `date`(๋˜๋Š” `ds`) + `value`/`target`(๋˜๋Š” `y`)
116
- - **์ตœ์†Œ ๋ฐ์ดํ„ฐ ํฌ์ธํŠธ:** 50๊ฐœ
117
-
118
- ### DataProfile (data_profile.py)
119
- ์ž๋™ ๋ถ„์„ ๊ฒฐ๊ณผ๋ฅผ ๋‹ด๋Š” ๋ฐ์ดํ„ฐํด๋ž˜์Šค. ๋ชจ๋“  ๋ชจ๋ธ์˜ ํŒŒ๋ผ๋ฏธํ„ฐ ์ž๋™ ์กฐ์ •์— ์‚ฌ์šฉ๋œ๋‹ค.
120
-
121
- ```python
122
- @dataclass
123
- class DataProfile:
124
- n_samples: int
125
- freq: str # 'D', 'W', 'MS', 'QS', 'YS' ๋“ฑ
126
- seasonal_period: int
127
- break_index: int # ๊ตฌ์กฐ์  ๋ณ€ํ™”์  ์ธ๋ฑ์Šค (-1์ด๋ฉด ์—†์Œ)
128
- volatility: float # ๋ณ€๋™์„ฑ ์ง€์ˆ˜
129
- trend_type: str # 'stable', 'gradual', 'sudden'
130
- seasonality_mode: str # 'additive', 'multiplicative'
131
- ```
132
-
133
- ### ์ž๋™ ํŒŒ๋ผ๋ฏธํ„ฐ ์กฐ์ • (Auto-Tuning)
134
- ๋ชจ๋“  ๋ชจ๋ธ์€ `DataProfile`์— ๊ธฐ๋ฐ˜ํ•˜์—ฌ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ž๋™ ์กฐ์ •ํ•œ๋‹ค:
135
- - **์ฃผํŒŒ์ˆ˜ ๊ฐ์ง€** โ†’ ๊ณ„์ ˆ ์ฃผ๊ธฐ ์ž๋™ ์„ค์ •
136
- - **๊ตฌ์กฐ์  ๋ณ€ํ™”์  ๊ฐ์ง€** (CUSUM) โ†’ ์ตœ๊ทผ ๋ฐ์ดํ„ฐ๋งŒ ํ•™์Šต ์˜ต์…˜
137
- - **์ด์ƒ๊ฐ’ ๊ฐ์ง€** (IQR 2.5๋ฐฐ) โ†’ ์ „์ฒ˜๋ฆฌ ์ ์šฉ
138
- - **๊ณ„์ ˆ์„ฑ ๋ชจ๋“œ** (๋ณ€๋™๊ณ„์ˆ˜ ๋น„๊ต) โ†’ additive/multiplicative ์„ ํƒ
139
-
140
- ---
141
-
142
- ## ์„œ๋น„์Šค ๋ ˆ์ด์–ด ๊ทœ์น™
143
-
144
- ์ƒˆ ๋ชจ๋ธ ์ถ”๊ฐ€ ์‹œ `{model}_service.py`์— ๋‹ค์Œ 4๊ฐœ ํ•จ์ˆ˜๋ฅผ ๊ตฌํ˜„ํ•œ๋‹ค:
145
-
146
- ```python
147
- def apply_defaults(params: dict) -> dict:
148
- """ํŒŒ๋ผ๋ฏธํ„ฐ ๊ธฐ๋ณธ๊ฐ’ ๋ณ‘ํ•ฉ"""
149
-
150
- def get_parameters() -> dict:
151
- """ํŒŒ๋ผ๋ฏธํ„ฐ ์Šคํ‚ค๋งˆ ๋ฐ˜ํ™˜ (UI ๋ Œ๋”๋ง์šฉ)"""
152
-
153
- def predict_with_{model}(df: pd.DataFrame, params: dict) -> dict:
154
- """์˜ˆ์ธก ์‹คํ–‰ โ†’ {"success", "data", "metrics"} ๋ฐ˜ํ™˜"""
155
-
156
- def evaluate_with_{model}(df: pd.DataFrame, params: dict) -> dict:
157
- """๋ฐฑํ…Œ์ŠคํŠธ ํ‰๊ฐ€"""
158
- ```
159
-
160
- ---
161
-
162
- ## ๋ฐฐํฌ
163
-
164
- ### ๋กœ์ปฌ ์‹คํ–‰
165
-
166
- ```bash
167
- # ๊ฐœ๋ฐœ (์ž๋™ ๋ฆฌ๋กœ๋“œ)
168
- bash run.sh
169
- # ๋˜๋Š”
170
- uvicorn main:app --reload --port 8000
171
-
172
- # ํ”„๋กœ๋•์…˜ ํ…Œ์ŠคํŠธ
173
- bash start.sh
174
- ```
175
-
176
- ### GitHub Actions โ†’ Hugging Face ์ž๋™ ๋ฐฐํฌ
177
-
178
- `main` ๋ธŒ๋žœ์น˜์— pushํ•˜๋ฉด `.github/workflows/deploy.yml`์ด ์‹คํ–‰๋˜์–ด HF Spaces๋กœ force pushํ•œ๋‹ค.
179
-
180
- - **ํ•„์š” Secret:** `HF_TOKEN` (GitHub Settings์— ๋“ฑ๋ก)
181
- - **HF Port:** 7860 (Dockerfile์— ๋ช…์‹œ๋จ)
182
- - **HF User:** psnc
183
-
184
- ### Docker
185
-
186
- ```dockerfile
187
- FROM python:3.10-slim
188
- # ๋นŒ๋“œ ๋„๊ตฌ ํ•„์š”: gcc, g++, build-essential (Prophet, statsmodels ์ปดํŒŒ์ผ)
189
- # ๋น„root ์‹คํ–‰: appuser (UID 1000)
190
- CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "7860"]
191
- ```
192
-
193
- ---
194
-
195
- ## ํ…Œ์ŠคํŠธ
196
-
197
- ```bash
198
- # ๋‹จ์œ„ ํ…Œ์ŠคํŠธ
199
- python -m pytest tests/
200
-
201
- # ์„œ๋น„์Šค ์ง์ ‘ ํ…Œ์ŠคํŠธ (API ์—†์ด)
202
- python run_test.py
203
- ```
204
-
205
- **์ฃผ์š” ํ…Œ์ŠคํŠธ ํŒŒ์ผ:**
206
- - `tests/test_nbeats.py` โ€” N-BEATS ์˜ˆ์ธก ์ •ํ™•๋„
207
- - `tests/test_auto_scaling.py` โ€” ์ž๋™ ํŒŒ๋ผ๋ฏธํ„ฐ ์กฐ์ • ๊ฒ€์ฆ (MASE < 2.0 ๊ธฐ๋Œ€๊ฐ’)
208
-
209
- ---
210
-
211
- ## ์ฝ”๋”ฉ ์ปจ๋ฒค์…˜
212
-
213
- - **์–ธ์–ด:** Python 3.10+
214
- - **๋„ค์ด๋ฐ:** ํด๋ž˜์Šค CamelCase, ํ•จ์ˆ˜/๋ณ€์ˆ˜ snake_case
215
- - **์ฃผ์„/๋…์ŠคํŠธ๋ง:** ํ•œ๊ตญ์–ด
216
- - **์—๋Ÿฌ ์ฒ˜๋ฆฌ:** `HTTPException` + `logging` (INFO ๋ ˆ๋ฒจ)
217
- - **ํƒ€์ž… ํžŒํŠธ:** ์ผ๋ถ€ ํ•จ์ˆ˜๋Š” ๋ˆ„๋ฝ (๊ธฐ์กด ์ฝ”๋“œ ์ˆ˜์ • ์‹œ ๊ฐ•์ œ ์ถ”๊ฐ€ ๋ถˆํ•„์š”)
218
- - **๋ฐฐ์น˜ ํฌ๊ธฐ:** N-BEATS๋Š” ๋ฉ”๋ชจ๋ฆฌ ์•ˆ์ „์„ ์œ„ํ•ด ์ตœ๋Œ€ 32๋กœ ์ œํ•œ
219
-
220
- ---
221
-
222
- ## ์ฃผ์˜์‚ฌํ•ญ
223
-
224
- - N-BEATS๋Š” ํฌ์ธํŠธ ์˜ˆ์ธก๋งŒ ์ œ๊ณต (์‹ ๋ขฐ๊ตฌ๊ฐ„ ์—†์Œ). ๊ตฌ๊ฐ„ ์˜ˆ์ธก์ด ํ•„์š”ํ•˜๋ฉด Prophet ๋˜๋Š” ARIMA ์‚ฌ์šฉ ๊ถŒ์žฅ.
225
- - XGBoost/LightGBM์€ Direct Multi-Step ๋ฐฉ์‹ ์‚ฌ์šฉ (๊ฐ ์˜ˆ์ธก ์Šคํ…๋ณ„ ๋ณ„๋„ ๋ชจ๋ธ๋กœ ์˜ค์ฐจ ๋ˆ„์  ๋ฐฉ์ง€).
226
- - HF Spaces ์žฌ๋ฐฐํฌ๋Š” Docker ๋นŒ๋“œ๋ฅผ ํฌํ•จํ•˜๋ฏ€๋กœ ์‹œ๊ฐ„์ด ๊ฑธ๋ฆด ์ˆ˜ ์žˆ๋‹ค.
227
- - `backend/` ๋””๋ ‰ํ„ฐ๋ฆฌ๋Š” ๋ ˆ๊ฑฐ์‹œ ์ฝ”๋“œ๋กœ ์‹ค์ œ ์„œ๋น„์Šค์— ์‚ฌ์šฉ๋˜์ง€ ์•Š๋Š”๋‹ค.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
CLAUDE.md DELETED
@@ -1,297 +0,0 @@
1
- # CLAUDE.md โ€” N-BEATS Time Series Forecasting Service
2
-
3
- ## ํ”„๋กœ์ ํŠธ ๊ฐœ์š”
4
-
5
- FastAPI ๊ธฐ๋ฐ˜ ์‹œ๊ณ„์—ด ์˜ˆ์ธก ์„œ๋น„์Šค. 7๊ฐœ ๋‹จ์ผ ๋ชจ๋ธ + TimesFM ํŒŒ์šด๋ฐ์ด์…˜ ๋ชจ๋ธ + ํ•˜์ด๋ธŒ๋ฆฌ๋“œ ์•™์ƒ๋ธ”์„ ์›น UI์™€ REST API๋กœ ์ œ๊ณตํ•˜๋ฉฐ, Hugging Face Spaces์— Docker ์ปจํ…Œ์ด๋„ˆ๋กœ ๋ฐฐํฌ๋œ๋‹ค. TimesFM ์ „์šฉ Next.js ํ”„๋ก ํŠธ์—”๋“œ๋Š” Vercel์— ๋ณ„๋„ ๋ฐฐํฌ๋œ๋‹ค.
6
-
7
- - **์„œ๋น„์Šค URL:** https://huggingface.co/spaces/psnc/time-series-prediction
8
- - **์ง์ ‘ ์ ‘๊ทผ:** https://psnc-time-series-prediction.hf.space
9
- - **๋ผ์ด์„ ์Šค:** MIT License
10
-
11
- ---
12
-
13
- ## ๊ธฐ์ˆ  ์Šคํƒ
14
-
15
- | ๋ ˆ์ด์–ด | ๊ธฐ์ˆ  |
16
- |--------|------|
17
- | Web Framework | FastAPI + Uvicorn (ASGI) |
18
- | Deep Learning | Darts (N-BEATS), PyTorch (CPU ์ „์šฉ ํœ ), PyTorch Lightning |
19
- | Foundation Model | TimesFM 2.5 200M (Google, GitHub ์†Œ์Šค ํ•€ ์„ค์น˜) |
20
- | Statistical | statsmodels (ARIMA, ETS, Theta), Prophet |
21
- | ML | XGBoost, LightGBM |
22
- | Data | pandas, numpy |
23
- | Frontend | Vanilla JS, Chart.js, XLSX.js (๋‹คํฌ ํ…Œ๋งˆ) / TimesFM ์ „์šฉ: Next.js |
24
- | Deploy | Docker โ†’ HF Spaces + Next.js โ†’ Vercel (GitHub Actions) |
25
-
26
- ---
27
-
28
- ## ๋””๋ ‰ํ„ฐ๋ฆฌ ๊ตฌ์กฐ
29
-
30
- ```
31
- nbeats/
32
- โ”œโ”€โ”€ main.py # FastAPI ์•ฑ, ๋ชจ๋“  ๋ผ์šฐํŠธ ์ •์˜ (638์ค„)
33
- โ”œโ”€โ”€ requirements.txt # ์ „ ์˜์กด์„ฑ ๋ฒ„์ „ ๊ณ ์ • (+cpu torch)
34
- โ”œโ”€โ”€ Dockerfile # HF Spaces ๋ฐฐํฌ์šฉ (port 7860)
35
- โ”œโ”€โ”€ run.sh # ๊ฐœ๋ฐœ ์„œ๋ฒ„ (--reload, port 8000)
36
- โ”œโ”€โ”€ start.sh # ํ”„๋กœ๋•์…˜ ์„œ๋ฒ„
37
- โ”œโ”€โ”€ run_test.py # ์„œ๋น„์Šค ์ง์ ‘ ํ…Œ์ŠคํŠธ
38
- โ”œโ”€โ”€ .github/workflows/deploy.yml # main push โ†’ HF + Vercel ์ž๋™ ๋ฐฐํฌ
39
- โ”œโ”€โ”€ .claude/skills/verify/ # ๊ฒ€์ฆ ๋ ˆ์‹œํ”ผ (๋กœ์ปฌ ๊ธฐ๋™ยทUI ๊ตฌ๋™ ๋ฐฉ๋ฒ•)
40
- โ”œโ”€โ”€ src/domains/time_series_prediction/
41
- โ”‚ โ”œโ”€โ”€ data_service.py # ํŒŒ์ผ ํŒŒ์‹ฑ ๋ฐ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ
42
- โ”‚ โ”œโ”€โ”€ data_profile.py # ๊ณตํ†ต ๋ฐ์ดํ„ฐ ๋ถ„์„ (DataProfile ๋ฐ์ดํ„ฐํด๋ž˜์Šค)
43
- โ”‚ โ”œโ”€โ”€ model_parameters.py # N-BEATS ํŒŒ๋ผ๋ฏธํ„ฐ ์Šคํ‚ค๋งˆ
44
- โ”‚ โ”œโ”€โ”€ nbeats_service.py # N-BEATS ๊ตฌํ˜„
45
- โ”‚ โ”œโ”€โ”€ prophet_service.py # Prophet ๊ตฌํ˜„
46
- โ”‚ โ”œโ”€โ”€ arima_service.py # ARIMA/SARIMA ๊ตฌํ˜„
47
- โ”‚ โ”œโ”€โ”€ xgboost_service.py # XGBoost ๊ตฌํ˜„
48
- โ”‚ โ”œโ”€โ”€ ets_service.py # ETS/Holt-Winters ๊ตฌํ˜„
49
- โ”‚ โ”œโ”€โ”€ lightgbm_service.py # LightGBM ๊ตฌํ˜„
50
- โ”‚ โ”œโ”€โ”€ theta_service.py # Theta Method ๊ตฌํ˜„
51
- โ”‚ โ”œโ”€โ”€ ensemble_service.py # 7๋ชจ๋ธ ๋น„๋™๊ธฐ ์•™์ƒ๋ธ” ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ดํ„ฐ
52
- โ”‚ โ””โ”€โ”€ timesfm_service.py # TimesFM 2.5 (์‹ฑ๊ธ€ํ†ค ๋กœ๋“œ)
53
- โ”œโ”€โ”€ static/ # ๋ชจ๋ธ๋ณ„ UI (index=N-BEATS, prophet, arima,
54
- โ”‚ โ”‚ # xgboost, ets, lightgbm, theta,
55
- โ”‚ โ”œโ”€โ”€ hybrid.html # ํ•˜์ด๋ธŒ๋ฆฌ๋“œ ์•™์ƒ๋ธ”, timesfm)
56
- โ”‚ โ”œโ”€โ”€ nav.js # ๊ณต์œ  ๋ชจ๋ธ ๋“œ๋กญ๋‹ค์šด ๋‚ด๋น„ (๋ชจ๋ธ ์ถ”๊ฐ€ ์‹œ MODELS ๋ฐฐ์—ด๋งŒ ์ˆ˜์ •)
57
- โ”‚ โ””โ”€โ”€ ...
58
- โ”œโ”€โ”€ timesfm-frontend/ # TimesFM ์ „์šฉ Next.js ์•ฑ (Vercel ๋ฐฐํฌ)
59
- โ”œโ”€โ”€ test_data/ # ํ…Œ์ŠคํŠธ์šฉ CSV ๋ฐ์ดํ„ฐ์…‹
60
- โ”œโ”€โ”€ tests/ # ์ „์ฒด pytest ํ˜ธํ™˜ (92๊ฐœ, CI ๋ฐฐํฌ ๊ฒŒ์ดํŠธ๋กœ ์‹คํ–‰)
61
- โ”‚ โ”œโ”€โ”€ test_nbeats.py
62
- โ”‚ โ”œโ”€โ”€ test_auto_scaling.py
63
- โ”‚ โ”œโ”€โ”€ test_hybrid.py # ์•™์ƒ๋ธ” ๊ฐ€์ค‘์น˜ยท์ง‘๊ณ„ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ
64
- โ”‚ โ”œโ”€โ”€ test_api_contract.py # API ์‘๋‹ต ํ˜•์‹ยท์—๋Ÿฌ ์ฝ”๋“œ ๊ณ„์•ฝ
65
- โ”‚ โ”œโ”€โ”€ test_nonblocking_endpoints.py
66
- โ”‚ โ”œโ”€โ”€ test_timesfm_horizon.py
67
- โ”‚ โ”œโ”€โ”€ test_ensemble_concurrency.py
68
- โ”‚ โ”œโ”€โ”€ test_data_service.py
69
- โ”‚ โ”œโ”€โ”€ test_supply_chain_hardening.py
70
- โ”‚ โ””โ”€โ”€ generate_test_datasets.py
71
- โ””โ”€โ”€ backend/ # ๋ ˆ๊ฑฐ์‹œ ์ฝ”๋“œ (๋ณด๊ด€์šฉ)
72
- ```
73
-
74
- ---
75
-
76
- ## ๊ตฌํ˜„๋œ ๋ชจ๋ธ
77
-
78
- | ๋ชจ๋ธ | ์œ ํ˜• | ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ | ํŠน์ง• |
79
- |------|------|-----------|------|
80
- | **N-BEATS** | ๋”ฅ๋Ÿฌ๋‹ | Darts + PyTorch | ์Šคํƒ ๊ธฐ๋ฐ˜ ์‹ ๊ฒฝ๋ง, ์•™์ƒ๋ธ” |
81
- | **Prophet** | ๋ฒ ์ด์ง€์•ˆ | Meta/Facebook | ์ถ”์„ธ ๋ณ€ํ™”์  ์ž๋™ ๊ฐ์ง€, ์‹ ๋ขฐ๊ตฌ๊ฐ„ |
82
- | **ARIMA/SARIMA** | ํ†ต๊ณ„ | statsmodels | AIC ๊ธฐ๋ฐ˜ ์ž๋™ ์ฐจ์ˆ˜ ์„ ํƒ |
83
- | **XGBoost** | ๊ทธ๋ž˜๋””์–ธํŠธ ๋ถ€์ŠคํŒ… | xgboost | ๋ž˜๊ทธ ํ”ผ์ฒ˜, ๋กค๋ง ํ†ต๊ณ„ |
84
- | **LightGBM** | ๊ทธ๋ž˜๋””์–ธํŠธ ๋ถ€์ŠคํŒ… | lightgbm | Leaf-wise ๋ถ„ํ• , XGBoost ๋Œ€๋น„ 2-5๋ฐฐ ๋น ๋ฆ„ |
85
- | **ETS** | ์ง€์ˆ˜ํ‰ํ™œ | statsmodels | Holt-Winters, ๊ฐ์‡  ์ถ”์„ธ |
86
- | **Theta** | ๊ณ ์ „ ํ†ต๊ณ„ | statsmodels | M3 ๋Œ€ํšŒ ์šฐ์Šน ์•Œ๊ณ ๋ฆฌ์ฆ˜ |
87
- | **TimesFM 2.5** | ํŒŒ์šด๋ฐ์ด์…˜ ๋ชจ๋ธ | Google (200M) | ์ œ๋กœ์ƒท ์˜ˆ์ธก, ๋ถ„์œ„์ˆ˜ ์‹ ๋ขฐ๊ตฌ๊ฐ„, ์š”์ฒญ๋ณ„ ํ•™์Šต ๋ถˆํ•„์š” |
88
- | **ํ•˜์ด๋ธŒ๋ฆฌ๋“œ ์•™์ƒ๋ธ”** | ๋ฉ”ํƒ€ | ensemble_service | ์œ„ 7๊ฐœ ๋‹จ์ผ ๋ชจ๋ธ์˜ DataProfile ๊ธฐ๋ฐ˜ ๊ฐ€์ค‘ ํ‰๊ท  |
89
-
90
- ---
91
-
92
- ## API ๊ตฌ์กฐ
93
-
94
- ### ๊ณตํ†ต ํŒจํ„ด
95
-
96
- - **Page Routes:** `GET /`, `/prophet`, `/arima`, `/xgboost`, `/ets`, `/lightgbm`, `/theta`, `/hybrid`, `/timesfm`
97
- - **Health:** `GET /health`, `GET /api/status`
98
- - **Template:** `GET /download_template?file_format=csv|xlsx|json`
99
-
100
- ### ๋ชจ๋ธ๋ณ„ ์—”๋“œํฌ์ธํŠธ
101
-
102
- ```
103
- POST /nbeats โ†’ N-BEATS ์˜ˆ์ธก (๋ฐฑํ…Œ์ŠคํŠธ ์˜ต์…˜)
104
- GET /nbeats/parameters โ†’ ํŒŒ๋ผ๋ฏธํ„ฐ ์Šคํ‚ค๋งˆ
105
- POST /nbeats/evaluate โ†’ ํ›ˆ๋ จ/ํ…Œ์ŠคํŠธ ๋ถ„๋ฆฌ ํ‰๊ฐ€
106
-
107
- POST /api/{prophet,arima,xgboost,ets,lightgbm,theta}/predict
108
- GET /api/{prophet,arima,xgboost,ets,lightgbm,theta}/parameters
109
-
110
- POST /api/hybrid/predict โ†’ 7๋ชจ๋ธ ์•™์ƒ๋ธ” (file + forecast_horizon(1~500) + model_weights(JSON, ์„ ํƒ))
111
- GET /api/timesfm/status โ†’ TimesFM ๋กœ๋”ฉ ์ƒํƒœ (not_loaded|loading|loaded|error)
112
- POST /api/timesfm/predict โ†’ TimesFM ์ œ๋กœ์ƒท ์˜ˆ์ธก
113
- ```
114
-
115
- ### ๊ณตํ†ต ์‘๋‹ต ํ˜•์‹ (๋‹จ์ผ ๋ชจ๋ธ)
116
-
117
- ```json
118
- {
119
- "success": true,
120
- "data": [{"ds": "2024-01-01", "y": 100.0, "yhat": 102.5}],
121
- "metrics": {"mae": 2.1, "rmse": 3.4, "mape": 0.021, "r2": 0.95},
122
- "test_size": 30
123
- }
124
- ```
125
-
126
- ### ํ•˜์ด๋ธŒ๋ฆฌ๋“œ ์•™์ƒ๋ธ” ์‘๋‹ต
127
-
128
- ```json
129
- {
130
- "success": true,
131
- "baseline": {
132
- "data": [{"ds": "...", "y": null, "yhat": 0.0, "yhat_upper": 0.0, "yhat_lower": 0.0}],
133
- "model_weights": {"nbeats": 0.2},
134
- "uncertainty": 0.07
135
- },
136
- "models_used": ["nbeats", "..."],
137
- "models_failed": []
138
- }
139
- ```
140
-
141
- - ์—ญ์‚ฌ ๊ตฌ๊ฐ„ ํ–‰์€ `yhat=null`, ์˜ˆ์ธก ๊ตฌ๊ฐ„ ํ–‰์€ `y=null` โ€” ํ•˜์œ„ ์ฒ˜๋ฆฌ ์‹œ None ์ฒดํฌ ํ•„์ˆ˜.
142
- - `yhat_upper/lower`๋Š” ๋ชจ๋ธ ๊ฐ„ ์˜ˆ์ธก ํ‘œ์ค€ํŽธ์ฐจ ยฑ1.96ฯƒ. ๋ฐฑํ…Œ์ŠคํŠธ๊ฐ€ ์—†์–ด `metrics`๋Š” ๋นˆ dict.
143
- - LLM ๋ณด์ • ๋ ˆ์ด์–ด๋Š” 2026-07-10 ์ œ๊ฑฐ๋จ (์นจ๋ฌต ํด๋ฐฑ ๋ฌธ์ œ + ๊ฒ€์ฆ ๋ถˆ๊ฐ€). ์ˆœ์ˆ˜ ์•™์ƒ๋ธ”๋งŒ ์ œ๊ณต.
144
-
145
- ---
146
-
147
- ## ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ํŒŒ์ดํ”„๋ผ์ธ
148
-
149
- ### ์ž…๋ ฅ ํฌ๋งท
150
- - **์ง€์›:** CSV, Excel (.xlsx), JSON
151
- - **ํ•„์ˆ˜ ์ปฌ๋Ÿผ:** `date`(๋˜๋Š” `ds`) + `value`/`target`(๋˜๋Š” `y`)
152
- - **์ตœ์†Œ ๋ฐ์ดํ„ฐ ํฌ์ธํŠธ:** 50๊ฐœ
153
- - **์ตœ๋Œ€ ํŒŒ์ผ ํฌ๊ธฐ:** 10MB (์ดˆ๊ณผ ์‹œ 413)
154
-
155
- ### DataProfile (data_profile.py)
156
- ์ž๋™ ๋ถ„์„ ๊ฒฐ๊ณผ๋ฅผ ๋‹ด๋Š” ๋ฐ์ดํ„ฐํด๋ž˜์Šค. ๋ชจ๋“  ๋ชจ๋ธ์˜ ํŒŒ๋ผ๋ฏธํ„ฐ ์ž๋™ ์กฐ์ •์— ์‚ฌ์šฉ๋œ๋‹ค.
157
-
158
- ```python
159
- @dataclass
160
- class DataProfile:
161
- n_samples: int
162
- freq: str # 'D', 'W', 'MS', 'QS', 'YS' ๋“ฑ
163
- seasonal_period: int
164
- break_index: int # ๊ตฌ์กฐ์  ๋ณ€ํ™”์  ์ธ๋ฑ์Šค (-1์ด๋ฉด ์—†์Œ)
165
- volatility: float # ๋ณ€๋™์„ฑ ์ง€์ˆ˜
166
- trend_type: str # 'stable', 'gradual', 'sudden'
167
- seasonality_mode: str # 'additive', 'multiplicative'
168
- ```
169
-
170
- ### ์ž๋™ ํŒŒ๋ผ๋ฏธํ„ฐ ์กฐ์ • (Auto-Tuning)
171
- ๋ชจ๋“  ๋ชจ๋ธ์€ `DataProfile`์— ๊ธฐ๋ฐ˜ํ•˜์—ฌ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ž๋™ ์กฐ์ •ํ•œ๋‹ค:
172
- - **์ฃผํŒŒ์ˆ˜ ๊ฐ์ง€** โ†’ ๊ณ„์ ˆ ์ฃผ๊ธฐ ์ž๋™ ์„ค์ •
173
- - **๊ตฌ์กฐ์  ๋ณ€ํ™”์  ๊ฐ์ง€** (CUSUM) โ†’ ์ตœ๊ทผ ๋ฐ์ดํ„ฐ๋งŒ ํ•™์Šต ์˜ต์…˜
174
- - **์ด์ƒ๊ฐ’ ๊ฐ์ง€** (IQR 2.5๋ฐฐ) โ†’ ์ „์ฒ˜๋ฆฌ ์ ์šฉ
175
- - **๊ณ„์ ˆ์„ฑ ๋ชจ๋“œ** (๋ณ€๋™๊ณ„์ˆ˜ ๋น„๊ต) โ†’ additive/multiplicative ์„ ํƒ
176
-
177
- ์•™์ƒ๋ธ” ๊ฐ€์ค‘์น˜๋„ DataProfile๋กœ ์กฐ์ •๋œ๋‹ค (ensemble_service.py):
178
- volatility > 0.3 โ†’ nbeatsยทprophet +0.05, trend stable โ†’ etsยทtheta +0.05,
179
- ๊ตฌ์กฐ ๋ณ€ํ™”์  ์กด์žฌ โ†’ xgboostยทlightgbm +0.05, ํ•ฉ๊ณ„ 1.0 ์ •๊ทœํ™”.
180
- `model_weights`(JSON, ์„ ํƒ)๋กœ ์ˆ˜๋™ ๊ฐ€์ค‘์น˜๋ฅผ ๋„˜๊ธฐ๋ฉด ์ž๋™ ์กฐ์ • ๋Œ€์‹  ์‚ฌ์šฉ๋˜๋ฉฐ,
181
- ๊ฐ€์ค‘์น˜ 0์ธ ๋ชจ๋ธ์€ ์‹คํ–‰ ์ž์ฒด๋ฅผ ๊ฑด๋„ˆ๋›ด๋‹ค (์–‘์ˆ˜ ๋ชจ๋ธ 2๊ฐœ ๋ฏธ๋งŒ์ด๋ฉด 422).
182
-
183
- ---
184
-
185
- ## ์„œ๋น„์Šค ๋ ˆ์ด์–ด ๊ทœ์น™
186
-
187
- ์ƒˆ ๋ชจ๋ธ ์ถ”๊ฐ€ ์‹œ `{model}_service.py`์— ๋‹ค์Œ 4๊ฐœ ํ•จ์ˆ˜๋ฅผ ๊ตฌํ˜„ํ•œ๋‹ค:
188
-
189
- ```python
190
- def apply_defaults(params: dict) -> dict:
191
- """ํŒŒ๋ผ๋ฏธํ„ฐ ๊ธฐ๋ณธ๊ฐ’ ๋ณ‘ํ•ฉ"""
192
-
193
- def get_parameters() -> dict:
194
- """ํŒŒ๋ผ๋ฏธํ„ฐ ์Šคํ‚ค๋งˆ ๋ฐ˜ํ™˜ (UI ๋ Œ๋”๋ง์šฉ)"""
195
-
196
- def predict_with_{model}(df: pd.DataFrame, params: dict) -> dict:
197
- """์˜ˆ์ธก ์‹คํ–‰ โ†’ {"success", "data", "metrics"} ๋ฐ˜ํ™˜"""
198
-
199
- def evaluate_with_{model}(df: pd.DataFrame, params: dict) -> dict:
200
- """๋ฐฑํ…Œ์ŠคํŠธ ํ‰๊ฐ€"""
201
- ```
202
-
203
- ์•™์ƒ๋ธ”์— ํŽธ์ž…ํ•˜๋ ค๋ฉด `ensemble_service.py`์˜ `model_configs`์™€ `_DEFAULT_WEIGHTS`์— ๋“ฑ๋กํ•œ๋‹ค.
204
-
205
- ---
206
-
207
- ## ๋ฐฐํฌ
208
-
209
- ### ๋กœ์ปฌ ์‹คํ–‰
210
-
211
- ```bash
212
- # ๊ฐœ๋ฐœ (์ž๋™ ๋ฆฌ๋กœ๋“œ) โ€” ๋ฐ˜๋“œ์‹œ venv ์‚ฌ์šฉ (.venv๋Š” ์˜์กด์„ฑ ๋ถˆ์™„์ „)
213
- bash run.sh
214
- # ๋˜๋Š”
215
- ./venv/bin/python -m uvicorn main:app --reload --port 8000
216
- ```
217
-
218
- ๋ถ€ํŒ…์— 20~40์ดˆ ๊ฑธ๋ฆฐ๋‹ค (torch/darts ์ž„ํฌํŠธ + TimesFM ๋ฐ๋ชฌ ์Šค๋ ˆ๋“œ ๋กœ๋“œ).
219
-
220
- ### GitHub Actions โ†’ HF + Vercel ์ž๋™ ๋ฐฐํฌ
221
-
222
- `main` ๋ธŒ๋žœ์น˜์— pushํ•˜๋ฉด `.github/workflows/deploy.yml`์ด ๋ณ€๊ฒฝ ๊ฒฝ๋กœ์— ๋”ฐ๋ผ job์„ ์„ ๋ณ„ ์‹คํ–‰ํ•œ๋‹ค:
223
-
224
- - **changes:** git diff๋กœ ๋ณ€๊ฒฝ ํŒŒ์ผ์„ backend/frontend/tests๋กœ ๋ถ„๋ฅ˜ (force-pushยทworkflow_dispatch๋Š” ์ „์ฒด ๋ฐฐํฌ๋กœ ํด๋ฐฑ)
225
- - **test:** backend ๋˜๋Š” tests ๋ณ€๊ฒฝ ์‹œ Python 3.10(ํ”„๋กœ๋•์…˜ Docker์™€ ๋™์ผ)์—์„œ ์ „์ฒด pytest ์‹คํ–‰ โ€” deploy-hf์˜ ํ•„์ˆ˜ ๊ฒŒ์ดํŠธ. timesfm git ์†Œ์Šค ์„ค์น˜๋ฅผ ์œ„ํ•ด GIT_CONFIG_* ํ™˜๊ฒฝ๋ณ€์ˆ˜๋กœ ๋Ÿฌ๋„ˆ์˜ git-lfs ํ•„ํ„ฐ๋ฅผ ๋ฌด๋ ฅํ™”ํ•œ๋‹ค
226
- - **deploy-hf:** backend ๋ณ€๊ฒฝ + ํ…Œ์ŠคํŠธ ํ†ต๊ณผ ์‹œ์—๋งŒ `HfApi.upload_folder`๋กœ ๊ธฐ์กด Space์— ์ง์ ‘ ์ปค๋ฐ‹ (free-tier Docker Space์˜ create_repo 402 ํŽ˜์ด์›”์„ ์šฐํšŒํ•˜๊ธฐ ์œ„ํ•ด hf CLI ๋Œ€์‹  ์‚ฌ์šฉ). `tests/`๋Š” ์—…๋กœ๋“œ ์ œ์™ธ
227
- - **deploy-vercel:** `timesfm-frontend/**` ๋ณ€๊ฒฝ ์‹œ์—๋งŒ Vercel prebuilt ๋ฐฉ์‹์œผ๋กœ ํ”„๋กœ๋•์…˜ ๋ฐฐํฌ
228
-
229
- **ํ•„์š” Secret:** `HF_TOKEN`, `VERCEL_TOKEN`, `VERCEL_ORG_ID`, `VERCEL_PROJECT_ID`
230
-
231
- ### Docker
232
-
233
- ```dockerfile
234
- FROM python:3.10-slim
235
- # ๋นŒ๋“œ ๋„๊ตฌ ํ•„์š”: gcc, g++, build-essential (Prophet, statsmodels ์ปดํŒŒ์ผ)
236
- # ๋น„root ์‹คํ–‰: appuser (UID 1000)
237
- CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "7860"]
238
- ```
239
-
240
- FastAPI ์•ฑ์€ ๋ณ„๋„ ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์—†์ด ๋™์ž‘ํ•œ๋‹ค. Claude API๋ฅผ ์“ฐ๋Š” ๊ณณ์€ timesfm-frontend์˜
241
- `/api/interpret` ๋ผ์šฐํŠธ๋ฟ์ด๋ฉฐ, ํ‚ค๋Š” Vercel ํ™˜๊ฒฝ๋ณ€์ˆ˜ `ANTHROPIC_API_KEY`๋กœ ๊ด€๋ฆฌ๋œ๋‹ค.
242
-
243
- ---
244
-
245
- ## ํ…Œ์ŠคํŠธ
246
-
247
- ```bash
248
- # ๋‹จ์œ„ ํ…Œ์ŠคํŠธ
249
- python -m pytest tests/
250
-
251
- # ์„œ๋น„์Šค ์ง์ ‘ ํ…Œ์ŠคํŠธ (API ์—†์ด)
252
- python run_test.py
253
- ```
254
-
255
- **์ฃผ์š” ํ…Œ์ŠคํŠธ ํŒŒ์ผ:**
256
- - `tests/test_nbeats.py` โ€” N-BEATS ํ•™์Šตยท์˜ˆ์ธก (์†Œํ˜• ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์‹ค์ œ ํ•™์Šต)
257
- - `tests/test_auto_scaling.py` โ€” ์ž๋™ ํŒŒ๋ผ๋ฏธํ„ฐ ์กฐ์ • ๊ฒ€์ฆ (MASE < 2.0 ๊ธฐ๋Œ€๊ฐ’)
258
- - `tests/test_hybrid.py` โ€” ์•™์ƒ๋ธ” ๊ฐ€์ค‘์น˜ ์‚ฐ์ •ยท์ง‘๊ณ„ยท์ˆ˜๋™ ๊ฐ€์ค‘์น˜ ๊ฒ€์ฆ ๋กœ์ง
259
- - `tests/test_api_contract.py` โ€” API ์‘๋‹ต ํ˜•์‹ยท์—๋Ÿฌ ์ฝ”๋“œ ๊ณ„์•ฝ (๋ชจ๋ธ ํ•™์Šต ์—†์ด ๋น ๋ฆ„)
260
- - `tests/test_nonblocking_endpoints.py` โ€” ์˜ˆ์ธก ์‹คํ–‰ ์ค‘ ์ด๋ฒคํŠธ ๋ฃจํ”„ ๋…ผ๋ธ”๋กœํ‚น ๊ฒ€์ฆ
261
- - `tests/test_timesfm_horizon.py` โ€” TimesFM horizon ํ•œ๋„(256) ์ฒ˜๋ฆฌ
262
- - `tests/test_ensemble_concurrency.py` โ€” ์„œ๋ฒ„ ์ „์—ญ Semaphore(3) ๋™์‹œ ์‹คํ–‰ ์ œํ•œ
263
- - `tests/test_data_service.py` โ€” ํŒŒ์ผ ํŒŒ์‹ฑ (์ธ์ฝ”๋”ฉ ํด๋ฐฑยท์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€ ๊ตฌ๋ถ„)
264
- - `tests/test_supply_chain_hardening.py` โ€” ๋ฐฐํฌ ๊ณต๊ธ‰๋ง ๋ฐฉ์–ด + ๋ฐฐํฌ ๊ฒฝ๋กœ ๊ฒŒ์ดํŠธ ๊ฒ€์ฆ
265
-
266
- **ํ…Œ์ŠคํŠธ ์ž‘์„ฑ ์ฃผ์˜:** `ensemble_service._MODEL_SEMAPHORE`๋Š” ๋ชจ๋“ˆ ์ „์—ญ์ด๋ผ ์ตœ์ดˆ
267
- ๊ฒฝํ•ฉ ์‹œ ํ•ด๋‹น ์ด๋ฒคํŠธ ๋ฃจํ”„์— ๋ฐ”์ธ๋”ฉ๋œ๋‹ค. `asyncio.run`(์ƒˆ ๋ฃจํ”„)์œผ๋กœ
268
- `run_ensemble_async`๋ฅผ ์ง์ ‘ ํ˜ธ์ถœํ•˜๋Š” ํ…Œ์ŠคํŠธ๋Š” monkeypatch๋กœ ์ƒˆ Semaphore๋ฅผ
269
- ์ฃผ์ž…ํ•ด์•ผ ๋‹ค๋ฅธ ํ…Œ์ŠคํŠธ์™€ ์ˆœ์„œ ์˜์กด ์ถฉ๋Œ์ด ์—†๋‹ค (test_hybrid.py `_isolate_semaphore` ์ฐธ๊ณ ).
270
-
271
- ๋ณ€๊ฒฝ ๊ฒ€์ฆ(๋กœ์ปฌ ๊ธฐ๋™ยทUI ๊ตฌ๋™ ๋ ˆ์‹œํ”ผ)์€ `.claude/skills/verify/SKILL.md` ์ฐธ๊ณ .
272
-
273
- ---
274
-
275
- ## ์ฝ”๋”ฉ ์ปจ๋ฒค์…˜
276
-
277
- - **์–ธ์–ด:** Python 3.10+
278
- - **๋„ค์ด๋ฐ:** ํด๋ž˜์Šค CamelCase, ํ•จ์ˆ˜/๋ณ€์ˆ˜ snake_case
279
- - **์ฃผ์„/๋…์ŠคํŠธ๋ง:** ํ•œ๊ตญ์–ด
280
- - **์—๋Ÿฌ ์ฒ˜๋ฆฌ:** `HTTPException` + `logging` (INFO ๋ ˆ๋ฒจ)
281
- - **ํƒ€์ž… ํžŒํŠธ:** ์ผ๋ถ€ ํ•จ์ˆ˜๋Š” ๋ˆ„๋ฝ (๊ธฐ์กด ์ฝ”๋“œ ์ˆ˜์ • ์‹œ ๊ฐ•์ œ ์ถ”๊ฐ€ ๋ถˆํ•„์š”)
282
- - **๋ฐฐ์น˜ ํฌ๊ธฐ:** N-BEATS๋Š” ๋ฉ”๋ชจ๋ฆฌ ์•ˆ์ „์„ ์œ„ํ•ด ์ตœ๋Œ€ 32๋กœ ์ œํ•œ
283
-
284
- ---
285
-
286
- ## ์ฃผ์˜์‚ฌํ•ญ
287
-
288
- - **requirements.txt๋Š” ์ „ ์˜์กด์„ฑ ๋ฒ„์ „ ๊ณ ์ •.** torch๋Š” ๋ฐ˜๋“œ์‹œ CPU ์ „์šฉ ํœ (`+cpu`, extra-index-url) โ€” ๊ธฐ๋ณธ PyPI ํœ ์€ CUDA ์Šคํƒ ~3GB๋ฅผ ๋Œ์–ด์™€ HF CPU Space ๋ถ€ํŒ…์„ ๋ง๊ฐ€๋œจ๋ฆฐ๋‹ค.
289
- - **TimesFM์€ GitHub ์ปค๋ฐ‹ ํ•€ ์„ค์น˜** (`timesfm[torch] @ git+...@d720daa`). PyPI ๋ฒ„์ „๊ณผ API๊ฐ€ ๋‹ค๋ฅด๋ฏ€๋กœ ์ž„์˜ ์—…๊ทธ๋ ˆ์ด๋“œ ๊ธˆ์ง€. ์•ฑ ์‹œ์ž‘ ์‹œ ๋ฐ๋ชฌ ์Šค๋ ˆ๋“œ๋กœ ๋กœ๋“œํ•ด์•ผ SIGTERM ์ข…๋ฃŒ๊ฐ€ ๋งค๋‹ฌ๋ฆฌ์ง€ ์•Š๋Š”๋‹ค (main.py lifespan ์ฐธ๊ณ ).
290
- - **macOS Apple Silicon ๋กœ์ปฌ ์‹คํ–‰ ์‹œ** PyTorch+LightGBM OpenMP ์ถฉ๋Œ ๋ฐฉ์–ด๊ฐ€ main.py ์ƒ๋‹จ์— ์žˆ๋‹ค (`KMP_DUPLICATE_LIB_OK`, ML ์ž„ํฌํŠธ ์ „ ์„ค์ • ํ•„์ˆ˜). ์•™์ƒ๋ธ”์€ ์„œ๋ฒ„ ์ „์—ญ Semaphore(3)๋กœ ๋™์‹œ ์‹คํ–‰ ๋ชจ๋ธ ์ˆ˜๋ฅผ ์ œํ•œํ•œ๋‹ค.
291
- - **Claude API ์‘๋‹ต์„ JSON ํŒŒ์‹ฑํ•  ๋•Œ๋Š” ๋งˆํฌ๋‹ค์šด ์ฝ”๋“œ๋ธ”๋ก ์ œ๊ฑฐ ํ•„์ˆ˜** (timesfm-frontend์˜ interpret ๋ผ์šฐํŠธ ์ฐธ๊ณ ). FastAPI ์•ฑ์€ 2026-07-10๋ถ€ํ„ฐ Claude API๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค (hybrid LLM ๋ณด์ •ยทTimesFM ํ•ด์„ค ๋ชจ๋‘ ์ œ๊ฑฐ).
292
- - N-BEATS๋Š” ํฌ์ธํŠธ ์˜ˆ์ธก๋งŒ ์ œ๊ณต (์‹ ๋ขฐ๊ตฌ๊ฐ„ ์—†์Œ). ๊ตฌ๊ฐ„ ์˜ˆ์ธก์ด ํ•„์š”ํ•˜๋ฉด Prophet, ARIMA, Theta, TimesFM ๋˜๋Š” ํ•˜์ด๋ธŒ๋ฆฌ๋“œ ์•™์ƒ๋ธ” ์‚ฌ์šฉ ๊ถŒ์žฅ. (ETS, XGBoost, LightGBM๋„ ํฌ์ธํŠธ ์˜ˆ์ธก๋งŒ.)
293
- - TimesFM์€ test ๊ตฌ๊ฐ„ ํฌํ•จ ์ตœ๋Œ€ 256 ์Šคํ…(max_horizon)๊นŒ์ง€๋งŒ ์˜ˆ์ธก โ€” ์ดˆ๊ณผ ์š”์ฒญ์€ ํ•œ๋„ ๋‚ด๋กœ ์ž˜๋ฆฌ๊ณ  ๊ฒฝ๊ณ  ๋กœ๊ทธ๋ฅผ ๋‚จ๊ธด๋‹ค.
294
- - XGBoost/LightGBM์€ Direct Multi-Step ๋ฐฉ์‹ ์‚ฌ์šฉ (๊ฐ ์˜ˆ์ธก ์Šคํ…๋ณ„ ๋ณ„๋„ ๋ชจ๋ธ๋กœ ์˜ค์ฐจ ๋ˆ„์  ๋ฐฉ์ง€).
295
- - ์•™์ƒ๋ธ”์€ ์š”์ฒญ๋งˆ๋‹ค 7๊ฐœ ๋ชจ๋ธ์„ ํ•™์Šตํ•˜๋ฏ€๋กœ ๋А๋ฆฌ๋‹ค (HF Space ์‹ค์ธก: ์›”๋ณ„ 120ํ–‰ 26์ดˆ, ์ผ๋ณ„ 400ํ–‰ 103์ดˆ). ๋ชจ๋ธ๋ณ„ ํƒ€์ž„์•„์›ƒ 180์ดˆ, ์„ฑ๊ณต ๋ชจ๋ธ 2๊ฐœ ๋ฏธ๋งŒ์ด๋ฉด 422.
296
- - HF Spaces ์žฌ๋ฐฐํฌ๋Š” Docker ๋นŒ๋“œ๋ฅผ ํฌํ•จํ•˜๋ฏ€๋กœ ์‹œ๊ฐ„์ด ๊ฑธ๋ฆด ์ˆ˜ ์žˆ๋‹ค.
297
- - `backend/` ๋””๋ ‰ํ„ฐ๋ฆฌ๋Š” ๋ ˆ๊ฑฐ์‹œ ์ฝ”๋“œ๋กœ ์‹ค์ œ ์„œ๋น„์Šค์— ์‚ฌ์šฉ๋˜์ง€ ์•Š๋Š”๋‹ค.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
README_N-BEATS.md DELETED
@@ -1,122 +0,0 @@
1
- # N-BEATS ์‹œ๊ณ„์—ด ์˜ˆ์ธก ๋ชจ๋ธ ์‚ฌ์šฉ ๊ฐ€์ด๋“œ
2
-
3
- ## ์ž…๋ ฅ ๋ฐ์ดํ„ฐ ํ˜•์‹
4
-
5
- N-BEATS ๋ฐ ๋‹ค๋ฅธ ๋ชจ๋“  ์‹œ๊ณ„์—ด ์˜ˆ์ธก ๋ชจ๋ธ(Prophet, XGBoost, ARIMA, SARIMA ๋“ฑ)์€ ๊ณตํ†ต๋œ ํ‘œ์ค€ ๋ฐ์ดํ„ฐ ํ˜•์‹์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค:
6
-
7
- ### ํ•„์ˆ˜ ์ปฌ๋Ÿผ
8
- - `ds`: ๋‚ ์งœ/์‹œ๊ฐ„ ์ปฌ๋Ÿผ (ํ•„์ˆ˜)
9
- - `y`: ์˜ˆ์ธกํ•˜๋ ค๋Š” ๋Œ€์ƒ ๊ฐ’ ์ปฌ๋Ÿผ (ํ•„์ˆ˜)
10
-
11
- ### ๋ฐ์ดํ„ฐ ์š”๊ตฌ์‚ฌํ•ญ
12
- - ์ตœ์†Œ 50๊ฐœ ์ด์ƒ์˜ ๋ฐ์ดํ„ฐ ํฌ์ธํŠธ ํ•„์š” (๋” ๋งŽ์„์ˆ˜๋ก ์ข‹์Œ)
13
- - ๋‚ ์งœ๋Š” ์ผ๊ด€๋œ ๊ฐ„๊ฒฉ์„ ๊ฐ€์ ธ์•ผ ํ•จ (์ผ๋ณ„, ์ฃผ๋ณ„, ์›”๋ณ„ ๋“ฑ)
14
- - ๊ฒฐ์ธก์น˜๋‚˜ ์ด์ƒ์น˜๋Š” ๋ชจ๋ธ ์„ฑ๋Šฅ์— ์˜ํ–ฅ์„ ์ค„ ์ˆ˜ ์žˆ์Œ
15
-
16
- ### ์ง€์›๋˜๋Š” ๋‚ ์งœ ํ˜•์‹
17
- ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋‹ค์–‘ํ•œ ๋‚ ์งœ ํ˜•์‹์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค:
18
- - ISO ํ˜•์‹: `2023-01-01`
19
- - ์Šฌ๋ž˜์‹œ ํ˜•์‹: `01/01/2023` ๋˜๋Š” `2023/01/01`
20
- - ์ปดํŒฉํŠธ ํ˜•์‹: `20230101`
21
- - ํ…์ŠคํŠธ ํ˜•์‹: `01-Jan-2023`, `Jan-01-2023`
22
-
23
- ### ์ง€์›๋˜๋Š” ํŒŒ์ผ ํ˜•์‹
24
- ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํŒŒ์ผ ํ˜•์‹์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค:
25
- - CSV (`.csv`)
26
- - Excel (`.xlsx`, `.xls`)
27
- - JSON (`.json`)
28
-
29
- ### ์˜ˆ์‹œ CSV ํ˜•์‹
30
- ```
31
- ds,y
32
- 2023-01-01,100
33
- 2023-01-02,105
34
- 2023-01-03,98
35
- ...
36
- ```
37
-
38
- ### ์˜ˆ์‹œ JSON ํ˜•์‹
39
- ```json
40
- [
41
- {"ds": "2023-01-01", "y": 100},
42
- {"ds": "2023-01-02", "y": 105},
43
- {"ds": "2023-01-03", "y": 98},
44
- ...
45
- ]
46
- ```
47
- ๋˜๋Š”
48
- ```json
49
- {
50
- "data": [
51
- {"ds": "2023-01-01", "y": 100},
52
- {"ds": "2023-01-02", "y": 105},
53
- {"ds": "2023-01-03", "y": 98},
54
- ...
55
- ]
56
- }
57
- ```
58
-
59
- ## API ์š”์ฒญ ์˜ˆ์‹œ
60
-
61
- ```json
62
- {
63
- "model_type": "nbeats",
64
- "forecast_periods": 30,
65
- "params": {
66
- "input_chunk_length": 24,
67
- "output_chunk_length": 12,
68
- "generic_architecture": true,
69
- "num_stacks": 10,
70
- "num_blocks": 1,
71
- "num_layers": 4,
72
- "layer_widths": 256,
73
- "expansion_coefficient_dim": 5,
74
- "dropout": 0.1,
75
- "n_epochs": 100,
76
- "batch_size": 32,
77
- "learning_rate": 0.001
78
- }
79
- }
80
- ```
81
-
82
- ## ์ฃผ์š” ํŒŒ๋ผ๋ฏธํ„ฐ ์„ค๋ช…
83
-
84
- ### ๊ธฐ๋ณธ ํŒŒ๋ผ๋ฏธํ„ฐ
85
- - `model_type`: 'nbeats' (๊ณ ์ •๊ฐ’)
86
- - `forecast_periods`: ์˜ˆ์ธกํ•  ๊ธฐ๊ฐ„ ์ˆ˜
87
- - `input_chunk_length`: ์ž…๋ ฅ ์‹œํ€€์Šค ๊ธธ์ด (๊ณผ๊ฑฐ ๋ฐ์ดํ„ฐ ํฌ์ธํŠธ ์ˆ˜)
88
- - `output_chunk_length`: ์ถœ๋ ฅ ์‹œํ€€์Šค ๊ธธ์ด (ํ•œ ๋ฒˆ์— ์˜ˆ์ธกํ•  ๋ฏธ๋ž˜ ๋ฐ์ดํ„ฐ ํฌ์ธํŠธ ์ˆ˜)
89
-
90
- ### ๊ณ ๊ธ‰ ํŒŒ๋ผ๋ฏธํ„ฐ
91
- - `generic_architecture`: ์ผ๋ฐ˜ ์•„ํ‚คํ…์ฒ˜ ์‚ฌ์šฉ ์—ฌ๋ถ€ (true/false)
92
- - `num_stacks`: ์Šคํƒ ์ˆ˜
93
- - `num_blocks`: ๋ธ”๋ก ์ˆ˜
94
- - `num_layers`: ๋ ˆ์ด์–ด ์ˆ˜
95
- - `layer_widths`: ๋ ˆ์ด์–ด ๋„ˆ๋น„
96
- - `expansion_coefficient_dim`: ํ™•์žฅ ๊ณ„์ˆ˜ ์ฐจ์›
97
- - `dropout`: ๋“œ๋กญ์•„์›ƒ ๋น„์œจ
98
- - `n_epochs`: ํ•™์Šต ์—ํฌํฌ
99
-
100
- ## ์ค‘์š” ์ฐธ๊ณ ์‚ฌํ•ญ
101
-
102
- 1. N-BEATS ๋ชจ๋ธ์€ ๋‹ค๋ฅธ ์‹œ๊ณ„์—ด ์˜ˆ์ธก ๋ชจ๋ธ์— ๋น„ํ•ด ๋งŽ์€ ๋ฐ์ดํ„ฐ ํฌ์ธํŠธ๋ฅผ ํ•„์š”๋กœ ํ•ฉ๋‹ˆ๋‹ค. ์ตœ์†Œ 50๊ฐœ ์ด์ƒ์˜ ๋ฐ์ดํ„ฐ ํฌ์ธํŠธ๋ฅผ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.
103
-
104
- 2. ๋‚ ์งœ ๋ฐ์ดํ„ฐ๋Š” ์ผ๊ด€๋œ ๊ฐ„๊ฒฉ์„ ๊ฐ€์ ธ์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋ถˆ๊ทœ์น™ํ•œ ๊ฐ„๊ฒฉ์˜ ๋ฐ์ดํ„ฐ๋Š” ๋ชจ๋ธ ์„ฑ๋Šฅ์„ ์ €ํ•˜์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
105
-
106
- 3. ๋ชจ๋“  ์˜ˆ์ธก ๋ชจ๋ธ(N-BEATS, Prophet, XGBoost, ARIMA, SARIMA)์€ ๋™์ผํ•œ 'ds'์™€ 'y' ์ปฌ๋Ÿผ ํ˜•์‹์„ ์‚ฌ์šฉํ•˜๋ฏ€๋กœ, ๋ฐ์ดํ„ฐ๋ฅผ ํ‘œ์ค€ํ™”ํ•˜๋ฉด ์—ฌ๋Ÿฌ ๋ชจ๋ธ์„ ์‰ฝ๊ฒŒ ๋น„๊ตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
107
-
108
- 4. ๋Œ€๊ทœ๋ชจ ๋ฐ์ดํ„ฐ์…‹์˜ ๊ฒฝ์šฐ ํ•™์Šต ์‹œ๊ฐ„์ด ๊ธธ์–ด์งˆ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ `n_epochs`์™€ `batch_size` ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ ์ ˆํžˆ ์กฐ์ •ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.
109
-
110
- 5. **์‹ ๋ขฐ ๊ตฌ๊ฐ„ ์—†์Œ**: N-BEATS๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ์‹ ๋ขฐ ๊ตฌ๊ฐ„(์ƒํ•œ/ํ•˜ํ•œ ๊ฒฝ๊ณ„)์„ ์ œ๊ณตํ•˜์ง€ ์•Š๊ณ  ๋‹จ์ผ ์˜ˆ์ธก๊ฐ’๋งŒ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” Prophet์ด๋‚˜ ARIMA์™€ ๊ฐ™์€ ํ†ต๊ณ„์  ๋ชจ๋ธ๊ณผ์˜ ์ฃผ์š” ์ฐจ์ด์ ์ž…๋‹ˆ๋‹ค. ์‹ ๋ขฐ ๊ตฌ๊ฐ„์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ Prophet ๋˜๋Š” ARIMA ๋ชจ๋ธ ์‚ฌ์šฉ์„ ๊ณ ๋ คํ•˜์„ธ์š”.
111
-
112
- 6. **๋ฐฐ์น˜ ํฌ๊ธฐ ์ œํ•œ**: ๋ฉ”๋ชจ๋ฆฌ ๋ฌธ์ œ๋ฅผ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฐฐ์น˜ ํฌ๊ธฐ ๊ฐ€์ด๋“œ๋ผ์ธ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค:
113
- - ๊ธฐ๋ณธ ์„ค์ •: 8 (์•ˆ์ „ํ•œ ๊ธฐ๋ณธ๊ฐ’)
114
- - ์ผ๋ฐ˜์ ์ธ ์‚ฌ์šฉ: 16-32 (๋Œ€๋ถ€๋ถ„์˜ ์‹œ์Šคํ…œ์—์„œ ์•ˆ์ •์ )
115
- - ์ตœ๋Œ€ ๊ถŒ์žฅ: 32 (32๋ฅผ ์ดˆ๊ณผํ•˜๋Š” ๊ฐ’์€ ๋ฉ”๋ชจ๋ฆฌ ์˜ค๋ฅ˜ ์œ„ํ—˜์ด ๋†’์•„์ง‘๋‹ˆ๋‹ค)
116
- - ์‹œ์Šคํ…œ ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ์ถฉ๋ถ„ํ•˜๋ฉด ์ตœ๋Œ€ 64๊นŒ์ง€ ์‚ฌ์šฉ ๊ฐ€๋Šฅ
117
-
118
- ์‹œ์Šคํ…œ์—์„œ ์ž๋™์œผ๋กœ ๋ฐฐ์น˜ ํฌ๊ธฐ๋ฅผ 32๋กœ ์ œํ•œํ•˜์—ฌ ๋ฉ”๋ชจ๋ฆฌ ์˜ค๋ฅ˜๋ฅผ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค.
119
-
120
- 7. **๋ชจ๋ธ ๋ณต์žก์„ฑ๊ณผ ํ•™์Šต ์‹œ๊ฐ„**: ๋ณต์žกํ•œ ๋ชจ๋ธ(์Šคํƒ, ๋ธ”๋ก, ๋ ˆ์ด์–ด ์ˆ˜๊ฐ€ ๋งŽ์€ ๋ชจ๋ธ)์€ ๋” ๋งŽ์€ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ฏ€๋กœ ๋ฐฐ์น˜ ํฌ๊ธฐ๋ฅผ ์ค„์—ฌ์•ผ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ํ•™์Šต ์‹œ๊ฐ„์ด ๊ธธ์–ด์ง€๋ฏ€๋กœ ์‹œ๊ฐ„๊ณผ ์„ฑ๋Šฅ ์‚ฌ์ด์˜ ๊ท ํ˜•์„ ๊ณ ๋ คํ•˜์„ธ์š”.
121
-
122
- 8. **์„ฑ๋Šฅ ํ‰๊ฐ€ (๋ฐฑํ…Œ์ŠคํŠธ)**: N-BEATS๋Š” ์‹ ๋ขฐ ๊ตฌ๊ฐ„์„ ์ œ๊ณตํ•˜์ง€ ์•Š์ง€๋งŒ, ๋ฐฑํ…Œ์ŠคํŠธ๋กœ ๋ชจ๋ธ ์„ฑ๋Šฅ์„ ํ‰๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฐ์ดํ„ฐ์˜ ๋งˆ์ง€๋ง‰ 20%๋ฅผ ๊ฒ€์ฆ์šฉ์œผ๋กœ ๋ถ„ํ• ํ•˜์—ฌ ํ•™์Šต ํ›„ ์˜ˆ์ธก๊ฐ’๊ณผ ์‹ค์ œ๊ฐ’์„ ๋น„๊ตํ•˜๊ณ , **MAE**, **RMSE**, **MAPE**, **Rยฒ** ์ง€ํ‘œ๋ฅผ ๊ณ„์‚ฐํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ์ธก API์— `include_evaluation=true`๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ `/nbeats/evaluate` ์—”๋“œํฌ์ธํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”. (์ตœ์†Œ 60๊ฐœ ๋ฐ์ดํ„ฐ ํ•„์š”)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
requirements.txt CHANGED
@@ -20,7 +20,7 @@ openpyxl==3.1.5
20
 
21
  # N-BEATS (Darts)
22
  darts==0.45.0
23
- torch==2.12.1+cpu
24
  pytorch-lightning==2.6.5
25
 
26
  # Prophet
 
20
 
21
  # N-BEATS (Darts)
22
  darts==0.45.0
23
+ torch==2.13.0+cpu
24
  pytorch-lightning==2.6.5
25
 
26
  # Prophet