Spaces:
Paused
Paused
Tonic commited on
Commit ·
2384e68
1
Parent(s): 248f443
adds improved predictions for chronos model
Browse files
app.py
CHANGED
|
@@ -63,9 +63,14 @@ def load_pipeline():
|
|
| 63 |
"amazon/chronos-t5-large",
|
| 64 |
device_map="auto", # Let the machine choose the best device
|
| 65 |
torch_dtype=torch.float16, # Use float16 for better memory efficiency
|
| 66 |
-
low_cpu_mem_usage=True
|
|
|
|
| 67 |
)
|
|
|
|
| 68 |
pipeline.model = pipeline.model.eval()
|
|
|
|
|
|
|
|
|
|
| 69 |
print("Chronos model loaded successfully")
|
| 70 |
return pipeline
|
| 71 |
except Exception as e:
|
|
@@ -293,8 +298,13 @@ def make_prediction(symbol: str, timeframe: str = "1d", prediction_days: int = 5
|
|
| 293 |
# Use Close prices instead of returns for better prediction
|
| 294 |
prices = df['Close'].values
|
| 295 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 296 |
# Normalize the data using MinMaxScaler
|
| 297 |
normalized_prices = scaler.fit_transform(prices.reshape(-1, 1)).flatten()
|
|
|
|
| 298 |
|
| 299 |
# Ensure we have enough data points and pad if necessary
|
| 300 |
min_data_points = 64 # Minimum required by Chronos
|
|
@@ -302,12 +312,18 @@ def make_prediction(symbol: str, timeframe: str = "1d", prediction_days: int = 5
|
|
| 302 |
# Pad the data with the last value
|
| 303 |
padding = np.full(min_data_points - len(normalized_prices), normalized_prices[-1])
|
| 304 |
normalized_prices = np.concatenate([padding, normalized_prices])
|
|
|
|
|
|
|
| 305 |
elif len(normalized_prices) > min_data_points:
|
| 306 |
# Take the most recent data points
|
| 307 |
normalized_prices = normalized_prices[-min_data_points:]
|
|
|
|
|
|
|
|
|
|
|
|
|
| 308 |
|
| 309 |
-
# Reshape for Chronos (batch_size=1, sequence_length, features=
|
| 310 |
-
context = torch.tensor(
|
| 311 |
|
| 312 |
# Make prediction with GPU acceleration
|
| 313 |
pipe = load_pipeline()
|
|
@@ -333,18 +349,39 @@ def make_prediction(symbol: str, timeframe: str = "1d", prediction_days: int = 5
|
|
| 333 |
|
| 334 |
with torch.inference_mode():
|
| 335 |
try:
|
| 336 |
-
|
| 337 |
-
|
| 338 |
-
|
| 339 |
-
num_samples=100
|
| 340 |
-
).detach().cpu().numpy()
|
| 341 |
|
| 342 |
-
|
| 343 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 344 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 345 |
# Denormalize predictions
|
| 346 |
-
mean_pred = scaler.inverse_transform(
|
| 347 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 348 |
|
| 349 |
# If we had to limit the prediction length, extend the prediction
|
| 350 |
if actual_prediction_length < prediction_days:
|
|
|
|
| 63 |
"amazon/chronos-t5-large",
|
| 64 |
device_map="auto", # Let the machine choose the best device
|
| 65 |
torch_dtype=torch.float16, # Use float16 for better memory efficiency
|
| 66 |
+
low_cpu_mem_usage=True,
|
| 67 |
+
trust_remote_code=True # Required for Chronos models
|
| 68 |
)
|
| 69 |
+
# Set model to evaluation mode
|
| 70 |
pipeline.model = pipeline.model.eval()
|
| 71 |
+
# Disable gradient computation
|
| 72 |
+
for param in pipeline.model.parameters():
|
| 73 |
+
param.requires_grad = False
|
| 74 |
print("Chronos model loaded successfully")
|
| 75 |
return pipeline
|
| 76 |
except Exception as e:
|
|
|
|
| 298 |
# Use Close prices instead of returns for better prediction
|
| 299 |
prices = df['Close'].values
|
| 300 |
|
| 301 |
+
# Calculate returns for additional context
|
| 302 |
+
returns = np.diff(prices) / prices[:-1]
|
| 303 |
+
returns = np.insert(returns, 0, 0) # Add 0 for first day
|
| 304 |
+
|
| 305 |
# Normalize the data using MinMaxScaler
|
| 306 |
normalized_prices = scaler.fit_transform(prices.reshape(-1, 1)).flatten()
|
| 307 |
+
normalized_returns = scaler.fit_transform(returns.reshape(-1, 1)).flatten()
|
| 308 |
|
| 309 |
# Ensure we have enough data points and pad if necessary
|
| 310 |
min_data_points = 64 # Minimum required by Chronos
|
|
|
|
| 312 |
# Pad the data with the last value
|
| 313 |
padding = np.full(min_data_points - len(normalized_prices), normalized_prices[-1])
|
| 314 |
normalized_prices = np.concatenate([padding, normalized_prices])
|
| 315 |
+
padding_returns = np.full(min_data_points - len(normalized_returns), normalized_returns[-1])
|
| 316 |
+
normalized_returns = np.concatenate([padding_returns, normalized_returns])
|
| 317 |
elif len(normalized_prices) > min_data_points:
|
| 318 |
# Take the most recent data points
|
| 319 |
normalized_prices = normalized_prices[-min_data_points:]
|
| 320 |
+
normalized_returns = normalized_returns[-min_data_points:]
|
| 321 |
+
|
| 322 |
+
# Combine price and returns data
|
| 323 |
+
combined_data = np.column_stack((normalized_prices, normalized_returns))
|
| 324 |
|
| 325 |
+
# Reshape for Chronos (batch_size=1, sequence_length, features=2)
|
| 326 |
+
context = torch.tensor(combined_data.reshape(1, -1, 2), dtype=torch.float32)
|
| 327 |
|
| 328 |
# Make prediction with GPU acceleration
|
| 329 |
pipe = load_pipeline()
|
|
|
|
| 349 |
|
| 350 |
with torch.inference_mode():
|
| 351 |
try:
|
| 352 |
+
# Generate multiple predictions for ensemble
|
| 353 |
+
num_ensemble = 5
|
| 354 |
+
all_predictions = []
|
|
|
|
|
|
|
| 355 |
|
| 356 |
+
for _ in range(num_ensemble):
|
| 357 |
+
# Use predict_quantiles for probabilistic forecasts
|
| 358 |
+
quantiles, mean = pipe.predict_quantiles(
|
| 359 |
+
context=context,
|
| 360 |
+
prediction_length=actual_prediction_length,
|
| 361 |
+
quantile_levels=[0.1, 0.5, 0.9] # 10th, 50th, and 90th percentiles
|
| 362 |
+
)
|
| 363 |
+
|
| 364 |
+
if quantiles is None or mean is None:
|
| 365 |
+
raise ValueError("Chronos returned empty prediction")
|
| 366 |
+
|
| 367 |
+
# Convert to numpy arrays
|
| 368 |
+
quantiles = quantiles.detach().cpu().numpy()
|
| 369 |
+
mean = mean.detach().cpu().numpy()
|
| 370 |
|
| 371 |
+
# Store predictions
|
| 372 |
+
all_predictions.append((quantiles, mean))
|
| 373 |
+
|
| 374 |
+
# Ensemble the predictions
|
| 375 |
+
ensemble_quantiles = np.mean([p[0] for p in all_predictions], axis=0)
|
| 376 |
+
ensemble_mean = np.mean([p[1] for p in all_predictions], axis=0)
|
| 377 |
+
|
| 378 |
# Denormalize predictions
|
| 379 |
+
mean_pred = scaler.inverse_transform(ensemble_mean.reshape(-1, 1)).flatten()
|
| 380 |
+
lower_bound = scaler.inverse_transform(ensemble_quantiles[0, :, 0].reshape(-1, 1)).flatten()
|
| 381 |
+
upper_bound = scaler.inverse_transform(ensemble_quantiles[0, :, 2].reshape(-1, 1)).flatten()
|
| 382 |
+
|
| 383 |
+
# Calculate standard deviation from quantiles
|
| 384 |
+
std_pred = (upper_bound - lower_bound) / (2 * 1.645) # 90% confidence interval
|
| 385 |
|
| 386 |
# If we had to limit the prediction length, extend the prediction
|
| 387 |
if actual_prediction_length < prediction_days:
|