Skip to main content

Python SDK for FAIM time-series forecasting with foundation AI models

Project description

FAIM SDK

PyPI version Python 3.11+ License: Apache 2.0

Production-ready Python SDK for FAIM (Foundation AI Models) - a high-performance time-series forecasting platform powered by foundation models.

Features

  • 🚀 Multiple Foundation Models: FlowState, Amazon Chronos 2.0, TiRex
  • 🔒 Type-Safe API: Full type hints with Pydantic validation
  • ⚡ High Performance: Optimized Apache Arrow serialization with zero-copy operations
  • 🎯 Probabilistic & Deterministic: Point forecasts, quantiles, and samples
  • 🔄 Async Support: Built-in async/await support for concurrent requests
  • 📊 Rich Error Handling: Machine-readable error codes with detailed diagnostics
  • 🧪 Battle-Tested: Production-ready with comprehensive error handling
  • 📈 Evaluation Tools: Built-in metrics (MSE, MASE, CRPS) and visualization utilities

Installation

pip install faim-sdk

For visualization support:

pip install faim-sdk[viz]

Authentication

Get your free API key at https://faim.it.com/

from faim_sdk import ForecastClient

# Initialize client with your API key
client = ForecastClient(api_key="your-api-key")

Quick Start

import numpy as np
from faim_sdk import ForecastClient, Chronos2ForecastRequest

# Initialize client
client = ForecastClient(api_key="your-api-key")

# Prepare your time-series data
# Shape: (batch_size, sequence_length, features)
data = np.random.randn(32, 100, 1).astype(np.float32)

# Create probabilistic forecast request
request = Chronos2ForecastRequest(
    x=data,
    horizon=24,  # Forecast 24 steps ahead
    output_type="quantiles",
    quantiles=[0.1, 0.5, 0.9]  # 10th, 50th (median), 90th percentiles
)

# Generate forecast - model inferred automatically from request type
response = client.forecast(request)

# Access predictions
print(response.quantiles.shape)  # (32, 24, 3, 1)
print(response.metadata)  # Model version, inference time, etc.

Input/Output Format

Input Data Format

All models require 3D input arrays:

# Shape: (batch_size, sequence_length, features)
x = np.array([
    [[1.0], [2.0], [3.0]],  # Series 1
    [[4.0], [5.0], [6.0]]   # Series 2
])  # Shape: (2, 3, 1)
  • batch_size: Number of independent time series
  • sequence_length: Historical data points (context window)
  • features: Number of variables per time step (use 1 for univariate)

Important: 2D input will raise a validation error. Always provide 3D arrays.

Output Data Format

Point Forecasts (3D):

response.point  # Shape: (batch_size, horizon, features)

Quantile Forecasts (4D):

response.quantiles  # Shape: (batch_size, horizon, num_quantiles, features)
# Example: (32, 24, 5, 1) = 32 series, 24 steps ahead, 5 quantiles, 1 feature

Univariate vs Multivariate

  • Chronos2: ✅ Supports multivariate forecasting (multiple features)
  • FlowState: ⚠️ Univariate only - automatically transforms multivariate input
  • TiRex: ⚠️ Univariate only - automatically transforms multivariate input

When you provide multivariate input (features > 1) to FlowState or TiRex, the SDK automatically:

  1. Issues a warning
  2. Forecasts each feature independently
  3. Reshapes the output back to your original structure
# Multivariate input to FlowState
data = np.random.randn(2, 100, 3)  # 2 series, 3 features
request = FlowStateForecastRequest(x=data, horizon=24, prediction_type="mean")

# Warning: "FlowState model only supports univariate forecasting..."
response = client.forecast(request)

# Output is automatically reshaped
print(response.point.shape)  # (2, 24, 3) - original structure preserved

Available Models

FlowState

Optimized for deterministic point forecasts with optional scaling and normalization.

from faim_sdk import FlowStateForecastRequest

request = FlowStateForecastRequest(
    x=data,
    horizon=24,
    model_version="latest",
    output_type="point",
    scale_factor=1.0,  # Optional: normalization factor, for details check: https://huggingface.co/ibm-granite/granite-timeseries-flowstate-r1
    prediction_type="mean"  # Options: "mean", "median"
)

response = client.forecast(request)
print(response.point.shape)  # (batch_size, 24, features)

Chronos 2.0

Amazon's large language model for time series - ideal for probabilistic forecasting with quantiles.

from faim_sdk import Chronos2ForecastRequest

# Quantile-based probabilistic forecast
request = Chronos2ForecastRequest(
    x=data,
    horizon=24,
    output_type="quantiles",
    quantiles=[0.05, 0.25, 0.5, 0.75, 0.95]  # Full distribution
)

response = client.forecast(request)
print(response.quantiles.shape)  # (batch_size, 24, 5)

TiRex

Transformer-based forecasting model for efficient and accurate predictions.

from faim_sdk import TiRexForecastRequest

request = TiRexForecastRequest(
    x=data,
    horizon=24,
    output_type="point"
)

response = client.forecast(request)
print(response.point.shape)  # (batch_size, 24, features)

Response Format

All forecasts return a ForecastResponse object with predictions and metadata:

response = client.forecast(request)

# Access predictions based on output_type
if response.point is not None:
    predictions = response.point  # Shape: (batch_size, horizon, features)

if response.quantiles is not None:
    quantiles = response.quantiles  # Shape: (batch_size, horizon, num_quantiles)
    # Lower quantiles for uncertainty bounds
    lower_bound = quantiles[:, :, 0]  # 10th percentile
    median = quantiles[:, :, 1]       # 50th percentile (median)
    upper_bound = quantiles[:, :, 2]  # 90th percentile

if response.samples is not None:
    samples = response.samples  # Shape: (batch_size, horizon, num_samples)

# Access metadata
print(response.metadata)
# {'model_name': 'chronos2', 'model_version': '1.0', 'inference_time_ms': 123}

Evaluation & Metrics

The SDK includes a comprehensive evaluation toolkit (faim_sdk.eval) for measuring forecast quality with standard metrics and visualizations.

Installation

For visualization support, install with the viz extra:

pip install faim-sdk[viz]

Available Metrics

Mean Squared Error (MSE)

Measures average squared difference between predictions and ground truth.

from faim_sdk.eval import mse

# Evaluate point forecast
mse_score = mse(test_data, response.point, reduction='mean')
print(f"MSE: {mse_score:.4f}")

# Per-sample MSE
mse_per_sample = mse(test_data, response.point, reduction='none')
print(f"MSE per sample shape: {mse_per_sample.shape}")  # (batch_size,)

Mean Absolute Scaled Error (MASE)

Scale-independent metric comparing forecast to naive baseline (better than MAPE for series with zeros).

from faim_sdk.eval import mase

# MASE requires training data for baseline
mase_score = mase(test_data, response.point, train_data, reduction='mean')
print(f"MASE: {mase_score:.4f}")

# Interpretation:
# MASE < 1: Better than naive baseline
# MASE = 1: Equivalent to naive baseline
# MASE > 1: Worse than naive baseline

Continuous Ranked Probability Score (CRPS)

Proper scoring rule for probabilistic forecasts - generalizes MAE to distributions.

from faim_sdk.eval import crps_from_quantiles

# Evaluate probabilistic forecast with quantiles
crps_score = crps_from_quantiles(
    test_data,
    response.quantiles,
    quantile_levels=[0.1, 0.5, 0.9],
    reduction='mean'
)
print(f"CRPS: {crps_score:.4f}")

Visualization

Plot forecasts with training context and ground truth:

from faim_sdk.eval import plot_forecast

# Plot single sample (remember to index batch dimension!)
fig, ax = plot_forecast(
    train_data=train_data[0],  # (seq_len, features) - 2D array
    forecast=response.point[0],  # (horizon, features) - 2D array
    test_data=test_data[0],  # (horizon, features) - optional
    title="Time Series Forecast"
)

# Save to file
fig.savefig("forecast.png", dpi=300, bbox_inches="tight")

Multi-Feature Visualization

# Option 1: All features on same plot
fig, ax = plot_forecast(
    train_data[0],
    response.point[0],
    test_data[0],
    features_on_same_plot=True,
    feature_names=["Temperature", "Humidity", "Pressure"]
)

# Option 2: Separate subplots per feature
fig, axes = plot_forecast(
    train_data[0],
    response.point[0],
    test_data[0],
    features_on_same_plot=False,
    feature_names=["Temperature", "Humidity", "Pressure"]
)

Complete Evaluation Example

import numpy as np
from faim_sdk import ForecastClient, Chronos2ForecastRequest
from faim_sdk.eval import mse, mase, crps_from_quantiles, plot_forecast

# Initialize client
client = ForecastClient()

# Prepare data splits
train_data = np.random.randn(32, 100, 1)
test_data = np.random.randn(32, 24, 1)

# Generate forecast
request = Chronos2ForecastRequest(
    x=train_data,
    horizon=24,
    output_type="quantiles",
    quantiles=[0.1, 0.5, 0.9]
)
response = client.forecast(request)

# Evaluate point forecast (use median)
point_pred = response.quantiles[:, :, 1:2]  # Extract median, keep 3D shape
mse_score = mse(test_data, point_pred)
mase_score = mase(test_data, point_pred, train_data)

# Evaluate probabilistic forecast
crps_score = crps_from_quantiles(
    test_data,
    response.quantiles,
    quantile_levels=[0.1, 0.5, 0.9]
)

print(f"MSE: {mse_score:.4f}")
print(f"MASE: {mase_score:.4f}")
print(f"CRPS: {crps_score:.4f}")

# Visualize best and worst predictions
mse_per_sample = mse(test_data, point_pred, reduction='none')
best_idx = np.argmin(mse_per_sample)
worst_idx = np.argmax(mse_per_sample)

fig1, ax1 = plot_forecast(
    train_data[best_idx],
    point_pred[best_idx],
    test_data[best_idx],
    title=f"Best Forecast (MSE: {mse_per_sample[best_idx]:.4f})"
)
fig1.savefig("best_forecast.png")

fig2, ax2 = plot_forecast(
    train_data[worst_idx],
    point_pred[worst_idx],
    test_data[worst_idx],
    title=f"Worst Forecast (MSE: {mse_per_sample[worst_idx]:.4f})"
)
fig2.savefig("worst_forecast.png")

Error Handling

The SDK provides machine-readable error codes for robust error handling:

from faim_sdk import (
    ForecastClient,
    Chronos2ForecastRequest,
    ValidationError,
    AuthenticationError,
    RateLimitError,
    ModelNotFoundError,
    ErrorCode
)

try:
    request = Chronos2ForecastRequest(x=data, horizon=24, quantiles=[0.1, 0.5, 0.9])
    response = client.forecast(request)

except AuthenticationError as e:
    # Handle authentication failures (401, 403)
    print(f"Authentication failed: {e.message}")
    print(f"Request ID: {e.error_response.request_id}")

except ValidationError as e:
    # Handle invalid request parameters (422)
    if e.error_code == ErrorCode.INVALID_SHAPE:
        print(f"Shape error: {e.error_response.detail}")
        # Fix shape and retry
    elif e.error_code == ErrorCode.MISSING_REQUIRED_FIELD:
        print(f"Missing field: {e.error_response.detail}")

except RateLimitError as e:
    # Handle rate limiting (429)
    print("Rate limit exceeded - implementing exponential backoff")
    retry_after = e.error_response.metadata.get('retry_after', 60)
    time.sleep(retry_after)

except ModelNotFoundError as e:
    # Handle model/version not found (404)
    print(f"Model not found: {e.message}")

Exception Hierarchy

FAIMError (base)
├── APIError
│   ├── AuthenticationError (401, 403)
│   ├── InsufficientFundsError (402)
│   ├── ModelNotFoundError (404)
│   ├── PayloadTooLargeError (413)
│   ├── ValidationError (422)
│   ├── RateLimitError (429)
│   ├── InternalServerError (500)
│   └── ServiceUnavailableError (503, 504)
├── NetworkError
├── SerializationError
├── TimeoutError
└── ConfigurationError

Async Support

The SDK supports async operations for concurrent requests:

import asyncio
from faim_sdk import ForecastClient, Chronos2ForecastRequest

async def forecast_multiple_series():
    client = ForecastClient(
        api_key="your-api-key"
    )

    # Create multiple requests
    requests = [
        Chronos2ForecastRequest(x=data1, horizon=24),
        Chronos2ForecastRequest(x=data2, horizon=24),
        Chronos2ForecastRequest(x=data3, horizon=24),
    ]

    # Execute concurrently
    async with client:
        tasks = [
            client.forecast_async(req)
            for req in requests
        ]
        responses = await asyncio.gather(*tasks)

    return responses

# Run async forecasts
responses = asyncio.run(forecast_multiple_series())

Configuration

Client Options

from faim_sdk import ForecastClient

# Basic configuration
client = ForecastClient(
    timeout=120.0,  # Request timeout in seconds (default: 120)
    verify_ssl=True,  # SSL certificate verification (default: True)
)

# With API key authentication
client = ForecastClient(
    api_key="your-secret-api-key",
    timeout=120.0
)

# Advanced configuration with custom httpx settings
import httpx

client = ForecastClient(
    api_key="your-api-key",
    timeout=120.0,
    limits=httpx.Limits(max_connections=10),  # Connection pooling
    headers={"X-Custom-Header": "value"}  # Custom headers
)

Request Options

# Compression options for large payloads
request = Chronos2ForecastRequest(
    x=data,
    horizon=24,
    compression="zstd"  # Options: "zstd", "lz4", None (default: "zstd")
)

# Model version pinning
request = FlowStateForecastRequest(
    x=data,
    horizon=24,
    model_version="1.2.3"  # Pin to specific version (default: "latest")
)

Context Managers

Use context managers for automatic resource cleanup:

# Sync context manager
with ForecastClient() as client:
    request = Chronos2ForecastRequest(x=data, horizon=24, quantiles=[0.1, 0.5, 0.9])
    response = client.forecast(request)
    print(response.quantiles)
# Client automatically closed

# Async context manager
async with ForecastClient() as client:
    request = Chronos2ForecastRequest(x=data, horizon=24, quantiles=[0.1, 0.9])
    response = await client.forecast_async(request)
    print(response.quantiles)
# Client automatically closed

Examples

See the examples/ directory for complete Jupyter notebook examples:

  • flowstate_simple_example.ipynb - Point forecasting with FlowState on AirPassengers dataset
  • chronos2_probabilistic.ipynb - Probabilistic forecasting with quantiles (coming soon)
  • batch_processing.ipynb - Efficient batch processing patterns (coming soon)

Requirements

  • Python >= 3.11
  • numpy >= 1.26.0
  • pyarrow >= 11.0.0
  • httpx >= 0.23.0
  • pydantic >= 2.0.0

Performance Tips

  1. Batch Processing: Process multiple time series in a single request for optimal throughput

    # Good: Single request with 32 series
    data = np.random.randn(32, 100, 1)
    
    # Less efficient: 32 separate requests
    # for series in data: client.forecast(...)
    
  2. Compression: Use compression="zstd" for large payloads (default, recommended)

  3. Async for Concurrent Requests: Use forecast_async() with asyncio.gather() for parallel processing

  4. Connection Pooling: Reuse client instances across requests instead of creating new ones

Support

License

Apache License 2.0 - See LICENSE file for details.

Citation

If you use FAIM in your research, please cite:

@software{faim_sdk,
  title = {FAIM SDK: Foundation AI Models for Time Series Forecasting},
  author = {FAIM Team},
  year = {2024},
  url = {https://github.com/your-org/faim-sdk}
}

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

faim_sdk-0.4.0.tar.gz (39.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

faim_sdk-0.4.0-py3-none-any.whl (45.6 kB view details)

Uploaded Python 3

File details

Details for the file faim_sdk-0.4.0.tar.gz.

File metadata

  • Download URL: faim_sdk-0.4.0.tar.gz
  • Upload date:
  • Size: 39.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.1.3 CPython/3.11.13 Darwin/24.6.0

File hashes

Hashes for faim_sdk-0.4.0.tar.gz
Algorithm Hash digest
SHA256 428f03df36857f4fcf29f198861c127e38a79778363f6b96c6f96c1721ab0586
MD5 4886bf89fcf049e9a0d367034becfcdc
BLAKE2b-256 987de4dec9dc36b7096f6a5f2ef351dc6c43867817057ceec615301f7fee8776

See more details on using hashes here.

File details

Details for the file faim_sdk-0.4.0-py3-none-any.whl.

File metadata

  • Download URL: faim_sdk-0.4.0-py3-none-any.whl
  • Upload date:
  • Size: 45.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.1.3 CPython/3.11.13 Darwin/24.6.0

File hashes

Hashes for faim_sdk-0.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 5718a1dca663e530436dc1688f8a515056fa27dae6ad3b26e4a03f6c7901b5b2
MD5 01f0bfe45ffa98d77d4aedd937028659
BLAKE2b-256 9a03dc85a3745c2aa482d887303e5f0db416b781ff1a27e1d40c581202c7a725

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page