Spaces:
Running
on
Zero
Running
on
Zero
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:
|