Hilft bei der Zeitreihenprognose

Wir alle wissen, wie das geht: Zeitreihendaten sind knifflig.

Herkömmliche Prognosemodelle sind auf Ereignisse wie plötzliche Marktabstürze, Black Swan-Ereignisse oder seltene Wetterereignisse nicht vorbereitet.

Sogar große, schicke Modelle wie Chronos haben manchmal Probleme, weil sie sich noch nie mit solchen Mustern befasst haben.

Wir können dies mit mildern Abruf. Mit Rückruf sind wir in der Lage zu fragen Ist so etwas schon einmal passiert? und dann dieses vergangene Beispiel als Leitfaden für die Prognose verwenden.

Wie wir vielleicht alle wissen, wird diese Idee in der Verarbeitung natürlicher Sprache (NLP) genannt Retrieval-Augmented Era (RAG). Es wird auch in der Welt der Zeitreihenprognosen immer beliebter.

Das Modell berücksichtigt dann vergangene Situationen die dem aktuellen ähnlich sehen, und von da an kann man daraus noch mehr machen zuverlässig Vorhersagen.

Wie unterscheidet sich diese RAF von herkömmlichen Zeitreihen? Die Abrufprognose fügt eine hinzu expliziter Speicherzugriffsschritt.

Anstatt:

Vergangenheit -> Parameter -> Prognose

Mit Abruf wir haben:

Aktuelle State of affairs -> Ähnlichkeitssuche -> konkrete vergangene Episoden-> Vorhersage

Abruf-erweiterter Prognosezyklus. Bild vom Autor | Servietten-KI.
Abruf-erweiterter Prognosezyklus. Bild vom Autor | Servietten-KI.

Anstatt nur das zu nutzen, was das Modell dabei gelernt hat AusbildungDie Idee besteht darin, ihm Zugriff auf eine Reihe von zu gewähren ähnlich Situationen.

Es ist, als würde man ein Wettermodell prüfen lassen: „Wie sahen vergangene Winter wie dieser aus?“ vor?“.


Hallo, das bin ich Sara Nóbregaein KI-Ingenieur. Wenn Sie an ähnlichen Problemen arbeiten oder Suggestions zur Umsetzung dieser Ideen wünschen, sammle ich meine Texte, Ressourcen und Mentoring-Hyperlinks Hier.


In diesem Artikel erkunde ich Abruferweiterte Prognose von Grund auf und zeigen anhand konkreter Beispiele und Codebeispiele, wie Retrieval in realen Prognosepipelines eingesetzt werden kann.

Was ist Retrieval-Augmented Forecasting (RAF)?

Was ist RAF? Auf einer sehr übergeordneten Ebene stützt sich RAF nicht nur auf das, was ein Modell im Coaching gelernt hat, sondern lässt das Modell aktiv nachschlagen konkrete vergangene Situationen ähnlich dem aktuellen und nutzen ihre Ergebnisse dazu Führung seine Vorhersage.

Sehen wir uns das genauer an:

  • Sie konvertieren die aktuelle State of affairs (z. B. die letzten Wochen eines Zeitreihen-Bestandsdatensatzes) in eine Abfrage.
  • Das Abfrage ist dann gewohnt suchen A Datenbank der historischen Zeitreihensegmente am meisten zu finden ähnlich Muster.
  • Diese Streichhölzer müssen nicht aus demselben Bestand stammen; Das System sollte auch ähnliche Bewegungen bei anderen Aktien oder Finanzprodukten anzeigen.

Es ruft diese ab Muster und was passiert ist nachher.

Im Anschluss sind diese Informationen eingenommen zum Prognose Modell, um bessere Vorhersagen zu treffen.

Diese Technik ist wirkungsvoll bei:

  • Zero-Shot-Szenarien: Wenn das Modell etwas sieht, auf das es nicht trainiert wurde.
  • Seltene oder ungewöhnliche Ereignisse: Wie COVID, plötzliche Finanzcrashs usw.
  • Sich entwickelnde saisonale Tendencies: Wo frühere Daten hilfreiche Muster enthalten, diese sich jedoch im Laufe der Zeit ändern.

RAF ersetzt nicht Ihr Prognose Modell, sondern stattdessen erweitert es, indem du es gibst Further Hinweise und die Untermauerung anhand relevanter historischer Beispiele.

Ein weiteres Beispiel: Nehmen wir an, Sie möchten den Energieverbrauch während einer ungewöhnlich heißen Woche vorhersagen.

Anstatt zu hoffen, dass Ihr Modell sich daran erinnert, wie sich Hitzewellen auf die Nutzung auswirken, findet Retrieval heraus ähnlich vergangene Hitzewellen und lässt das Modell berücksichtigen, was in dieser Zeit passiert ist.

Was rufen diese Modelle tatsächlich ab?

Bei dem abgerufenen „Wissen“ handelt es sich nicht nur um Rohdaten. Es ist der Kontext, der dem Modell Hinweise gibt.

Hier sind einige gängige Beispiele:

Beispiele für den Datenabruf. Bild vom Autor | Servietten-KI.
Beispiele für den Datenabruf. Bild vom Autor | Servietten-KI.

Wie Sie sehen, konzentriert sich der Abruf auf bedeutsame historische Situationen, wie seltene Schocks, saisonale Effekte und Muster mit ähnlichen Strukturen. Diese liefern einen umsetzbaren Kontext für die aktuelle Prognose.

Wie rufen diese Modelle ab?

Related finden Muster Aus der Vergangenheit nutzen diese Modelle strukturierte Mechanismen, die die aktuelle State of affairs so darstellen, dass sie sie darstellt einfach um große Datenbanken zu durchsuchen und die ähnlichsten Übereinstimmungen zu finden.

Bei den Codeausschnitten in diesem Abschnitt handelt es sich um eine vereinfachte Veranschaulichung, die der Anschauung dienen soll, sie stellen keinen Produktionscode dar.

Abrufmethoden für die Zeitreihenvorhersage. Bild vom Autor | Servietten-KI.
Abrufmethoden für die Zeitreihenvorhersage. Bild vom Autor | Servietten-KI.

Einige dieser Methoden sind:

Einbettungsbasierte Ähnlichkeit

Dieser wandelt Zeitreihen (oder Patches/Fenster einer Reihe) in kompakt um Vektorenund vergleichen Sie sie dann mit Distanzmetriken wie Euklidischer oder Kosinusähnlichkeit.

In einfach Worte: Das Modell wandelt Teile von Zeitreihendaten in kurze um Zusammenfassungen und prüft dann welche Vergangenheit Zusammenfassungen ähneln am ehesten dem, was jetzt passiert.

Einige abrufgestützte Prognostiker (z. B. FLOSS) die ähnlichsten historischen Daten abrufen Patches aus den Trainingsdaten / der gesamten Serie und dann Aggregat abgerufene Werte mit aufmerksamkeitsähnlichen Gewichten.

Mit einfachen Worten: Es findet ähnlich Situationen aus der Vergangenheit und Durchschnittswerte sie zahlen mehr Aufmerksamkeit zum am besten Streichhölzer.

import numpy as np

# Instance: embedding-based retrieval for time-series patches
# This can be a toy instance to point out the *thought* behind retrieval.
# In observe:
# - embeddings are discovered by neural networks
# - similarity search runs over hundreds of thousands of vectors
# - this logic lives inside a bigger forecasting pipeline


def embed_patch(patch: np.ndarray) -> np.ndarray:
    """
    Convert a brief time-series window ("patch") right into a compact vector.

    Right here we use easy statistics (imply, std, min, max) purely for illustration.
    Actual-world methods would possibly use:
      - a educated encoder community
      - shape-based representations
      - frequency-domain options
      - latent vectors from a forecasting spine
    """
    return np.array((
        patch.imply(),   # common degree
        patch.std(),    # volatility
        patch.min(),    # lowest level
        patch.max()     # highest level
    ))


def cosine_similarity(a: np.ndarray, b: np.ndarray) -> float:
    """
    Measure how comparable two vectors are.
    Cosine similarity focuses on *route* quite than magnitude,
    which is commonly helpful for evaluating patterns or shapes.
    """
    return float(a @ b) / (np.linalg.norm(a) * np.linalg.norm(b) + 1e-9)


# Step 1: Symbolize the present state of affairs

# A brief window representing the present time-series habits
query_patch = np.array((10, 12, 18, 25, 14, 11))

# Flip it into an embedding
query_embedding = embed_patch(query_patch)


# Step 2: Symbolize historic conditions

# Previous home windows extracted from historic information
historical_patches = (
    np.array((9, 11, 17, 24, 13, 10)),   # seems comparable
    np.array((2, 2, 2, 2, 2, 2)),        # flat, unrelated
    np.array((10, 13, 19, 26, 15, 12))   # very comparable
)

# Convert all historic patches into embeddings
historical_embeddings = (
    embed_patch(patch) for patch in historical_patches
)

# Step 3: Evaluate and retrieve essentially the most comparable previous instances

# Compute similarity scores between the present state of affairs
# and every historic instance
similarities = (
    cosine_similarity(query_embedding, hist_emb)
    for hist_emb in historical_embeddings
)

# Rank historic patches by similarity
top_k_indices = np.argsort(similarities)(::-1)(:2)

print("Most comparable historic patches:", top_k_indices)

# Step 4 (conceptual):
# In a retrieval-augmented forecaster, the mannequin would now:
# - retrieve the *future outcomes* of those comparable patches
# - weight them by similarity (attention-like weighting)
# - use them to information the ultimate forecast
# This integration step is model-specific and never proven right here.

Retrieval-Instruments und Bibliotheken

1. FAISS
FAISS ist ein tremendous schnelles und GPU-freundliche Bibliothek für die Ähnlichkeitssuche über dichte Vektoren. Der am besten Datensätze für diese Bibliothek sind diejenigen, die es sind groß und in-Erinnerungobwohl seine Struktur die Implementierung von Echtzeitaktualisierungen erschwert.

import faiss
import numpy as np

# Suppose we have already got embeddings for historic home windows
d = 128  # embedding dimension
xb = np.random.randn(100_000, d).astype("float32")  # historic embeddings
xq = np.random.randn(1, d).astype("float32")        # question embedding

index = faiss.IndexFlatIP(d)   # inside product (usually used with normalized vectors for cosine-like habits)
index.add(xb)

ok = 5
scores, ids = index.search(xq, ok)
print("Nearest neighbors (ids):", ids)
print("Similarity scores:", scores)

# Some FAISS indexes/algorithms can run on GPU.

Suche nach dem nächsten Nachbarn (Annoy)
Die Annoy-Bibliothek ist relativ leicht und einfach zu verarbeiten.

Die besten Datensätze für diese Bibliothek sind historische Datensätze, die größtenteils statisch bleiben, da jede Änderung des Datensatzes eine Neuerstellung des Index erfordert.

from annoy import AnnoyIndex
import numpy as np

# Variety of values in every embedding vector.
# The "size" of every fingerprint.
f = 64

# Create an Annoy index.
# This object will retailer many previous embeddings and assist us rapidly discover essentially the most comparable ones.
ann = AnnoyIndex(f, "angular")
# "angular" distance is often used to check patterns
# and behaves equally to cosine similarity.

# Add historic embeddings (previous conditions).
# Every merchandise represents a compressed model of a previous time-series window.
# Right here we use random numbers simply for example.
for i in vary(10000):
    ann.add_item(i, np.random.randn(f).tolist())

# Construct the search construction.
# This step organizes the info so similarity searches are quick.
# After this, the index turns into read-only.
ann.construct(10)

# Save the index to disk.
# This permits us to load it later with out rebuilding every little thing.
ann.save("hist.ann")

# Create a question embedding.
# This represents the present state of affairs we wish to evaluate
# towards previous conditions.
q = np.random.randn(f).tolist()

# Discover the 5 most comparable previous embeddings.
# Annoy returns the IDs of the closest matches.
neighbors = ann.get_nns_by_vector(q, 5)

print("Nearest neighbors:", neighbors)

# Necessary observe:
# As soon as the index is constructed, you can not add new objects.
# If new historic information seems, the index have to be rebuilt.

Qdrant / Tannenzapfen

Qdrant und Pinecone sind ähnlich Google für Einbettungen.

Sie speichern viele Vektor-„Fingerabdrücke“ (plus zusätzliche Tags wie Stadt/Jahreszeit) und wenn Sie einen neuen Fingerabdruck haben, fragen Sie:

Zeigen Sie mir die ähnlichsten, aber nur aus dieser Stadt/Saison/Geschäftsart.“
Das macht sie einfacher als das eigene Einholen: Sie lassen sich schnell handhaben suchen Und Filterung!

Qdrant ruft Metadaten auf Nutzlastund Sie können Suchergebnisse mithilfe von Bedingungen filtern.

# Instance solely (for instinct). Actual code wants a operating Qdrant occasion + actual embeddings.

from qdrant_client import QdrantClient, fashions

consumer = QdrantClient(url="http://localhost:6333")

assortment = "time_series_windows"

# Fake that is the embedding of the *present* time-series window
query_vector = (0.12, -0.03, 0.98, 0.44)  # shortened for readability

# Filter = "solely contemplate previous home windows from New York in summer time"
# Qdrant documentation exhibits filters constructed from FieldCondition + MatchValue. :contentReference(oaicite:3){index=3}
query_filter = fashions.Filter(
    should=(
        fashions.FieldCondition(
            key="metropolis",
            match=fashions.MatchValue(worth="New York"),
        ),
        fashions.FieldCondition(
            key="season",
            match=fashions.MatchValue(worth="summer time"),
        ),
    )
)

# In actual utilization, you’d name search/question and get again the closest matches
# plus their payload (metadata) when you request it.
outcomes = consumer.search(
    collection_name=assortment,
    query_vector=query_vector,
    query_filter=query_filter,
    restrict=5,
    with_payload=True,   # return metadata so you'll be able to examine what you retrieved
)

print(outcomes)

# What you'd do subsequent (conceptually):
# - take the matched IDs
# - load the precise historic home windows behind them
# - feed these home windows (or their outcomes) into your forecasting mannequin

Pinecone-Läden Metadaten-Schlüssel-Wert-Paare neben Vektoren und ermöglicht das Filtern zum Zeitpunkt der Abfrage (einschließlich $eq) und Metadaten zurückgeben.

# Instance solely (for instinct). Actual code wants an API key + an index host.

from pinecone import Pinecone

laptop = Pinecone(api_key="YOUR_API_KEY")
index = laptop.Index(host="INDEX_HOST")

# Fake that is the embedding of the present time-series window
query_vector = (0.12, -0.03, 0.98, 0.44)  # shortened for readability

# Ask for essentially the most comparable previous home windows, however solely the place:
# metropolis == "New York" AND season == "summer time"
# Pinecone docs present query-time filtering and `$eq`. :contentReference(oaicite:5){index=5}
res = index.question(
    namespace="home windows",
    vector=query_vector,
    top_k=5,
    filter={
        "metropolis": {"$eq": "New York"},
        "season": {"$eq": "summer time"},
    },
    include_metadata=True,  # return tags so you'll be able to sanity-check matches
    include_values=False
)

print(res)

# Conceptually subsequent:
# - use the returned IDs to fetch the underlying historic home windows/outcomes
# - situation your forecast on these retrieved examples

Warum helfen Vektor-DBs? Sie lassen dich machen Ähnlichkeitssuche + „SQL-ähnliche WHERE-Filter“ in einem Schritt, was mit einem DIY-Setup schwer sauber zu bewerkstelligen ist (sowohl die Qdrant-Nutzlastfilterung als auch die Pinecone-Metadatenfilterung sind erstklassige Funktionen in ihren Dokumenten).

Jedes Device hat seine Kompromisse. Zum Beispiel, FAISS ist großartig für die Leistung, aber nicht geeignet für häufig Aktualisierungen. Qdrant gibt Flexibilität und Echtzeitfilterung. Pinecone ist einfach einzurichten, aber nur SaaS.

Retrieval + Prognose: Wie man sie kombiniert

Nachdem Sie wissen, was abgerufen werden soll, besteht der nächste Schritt darin, diese Informationen mit der aktuellen Eingabe zu kombinieren.

Sie kann je nach Architektur und Aufgabenstellung variieren. Dafür gibt es mehrere Strategien (siehe Bild unten).

Strategien zur Kombination von Abruf und Prognose
Strategien zur Kombination von Abruf und Prognose. Bild vom Autor | Servietten-KI.

A. Verkettung
Idee:
Behandeln Sie den abgerufenen Kontext als „mehr Eingabe“, indem Sie ihn an die vorhandene Sequenz anhängen (sehr häufig bei Setups mit erweiterter Generierung beim Abrufen).

Funktioniert intestine mit transformatorbasierten Modellen wie Chronos und erfordert keine Änderungen an der Architektur.

import torch

# x_current: the mannequin's typical enter sequence (e.g., final N timesteps or tokens)
# form: (batch, time, d_model)   (or (batch, time) when you suppose in tokens)
x_current = torch.randn(8, 128, 256)

# x_retrieved: retrieved context encoded within the SAME illustration area
# e.g., embeddings for comparable previous home windows (or their summaries)
# form: (batch, retrieved_time, d_model)
x_retrieved = torch.randn(8, 32, 256)

# Easy fusion: simply append retrieved context to the top of the enter sequence
# Now the mannequin sees: (present historical past ... + retrieved context ...)
x_fused = torch.cat((x_current, x_retrieved), dim=1)

# In observe, you'd additionally add:
# - an consideration masks (so the mannequin is aware of what’s actual vs padded)
# - section/kind embeddings (so the mannequin is aware of which half is retrieved context)
# Then feed x_fused to your transformer.

B. Cross-Consideration-Fusion
Idee:
Halten Sie die „aktuelle Eingabe“ und den „abgerufenen Kontext“ getrennt und lassen Sie das Modell Sich um den abgerufenen Kontext kümmern wenn es es braucht. Dies ist das Kernmuster „Fusion im Decoder durch gegenseitige Aufmerksamkeit“, das von abrufgestützten Architekturen wie FiD verwendet wird.

import torch

# current_repr: illustration of the present time-series window
# form: (batch, time, d_model)
current_repr = torch.randn(8, 128, 256)

# retrieved_repr: illustration of retrieved home windows (could possibly be concatenated)
# form: (batch, retrieved_time, d_model)
retrieved_repr = torch.randn(8, 64, 256)

# Consider cross-attention like:
# - Question (Q) comes from the present sequence
# - Keys/Values (Okay/V) come from retrieved context
Q = current_repr
Okay = retrieved_repr
V = retrieved_repr

# Consideration scores: "How a lot ought to every present timestep take a look at every retrieved timestep?"
scores = torch.matmul(Q, Okay.transpose(-1, -2)) / (Q.dimension(-1) ** 0.5)

# Flip scores into weights (so that they sum to 1 throughout retrieved positions)
weights = torch.softmax(scores, dim=-1)

# Weighted sum of retrieved info (that is the “fused” retrieved sign)
retrieval_signal = torch.matmul(weights, V)

# Ultimate fused illustration: present data + retrieved data
# (Some fashions add, some concatenate, some use a discovered projection)
fused = current_repr + retrieval_signal

# Then the forecasting head reads from `fused` to foretell the longer term.

C. Combination-of-Specialists (MoE)
Idee: Kombinieren Sie zwei „Experten“:

  • Die Abrufbasierter Prognostiker (nicht parametrisch, fallbasiert)
  • Die Basisprognostiker (parametrisches Wissen)

Ein „Gate“ entscheidet bei jedem Zeitschritt, welchem ​​Tor mehr vertraut werden soll.

import torch

# base_pred: forecast from the primary mannequin (what it "discovered in weights")
# form: (batch, horizon)
base_pred = torch.randn(8, 24)

# retrieval_pred: forecast urged by retrieved comparable instances
# form: (batch, horizon)
retrieval_pred = torch.randn(8, 24)

# context_for_gate: abstract of the present state of affairs (could possibly be final hidden state)
# form: (batch, d_model)
context_for_gate = torch.randn(8, 256)

# gate: a quantity between 0 and 1 saying "how a lot to belief retrieval"
# (In actual fashions, it is a tiny neural web.)
gate = torch.sigmoid(torch.randn(8, 1))

# Combination: convex mixture
# - if gate ~ 1 -> belief retrieval extra
# - if gate ~ 0 -> belief the bottom mannequin extra
final_pred = gate * retrieval_pred + (1 - gate) * base_pred

# In observe:
# - gate may be timestep-dependent: form (batch, horizon, 1)
# - you may also add coaching losses to stabilize routing/utilization (frequent in MoE)

D. Kanalaufforderung
Idee:
Abgerufene Serien behandeln als zusätzliche Eingangskanäle/Funktionen (besonders natürlich in multivariaten Zeitreihen, in denen jede Variable ein „Kanal“ ist).

import torch

# x: multivariate time sequence enter
# form: (batch, time, channels)
# Instance: channels could possibly be (gross sales, worth, promo_flag, temperature, ...)
x = torch.randn(8, 128, 5)

# retrieved_series_aligned: retrieved sign aligned to the identical time grid
# Instance: common of the top-k comparable previous home windows (or one consultant neighbor)
# form: (batch, time, retrieved_channels)
retrieved_series_aligned = torch.randn(8, 128, 2)

# Channel prompting = append retrieved channels as further options
# Now the mannequin will get "regular channels + retrieved channels"
x_prompted = torch.cat((x, retrieved_series_aligned), dim=-1)

# In observe you’d seemingly additionally embrace:
# - a masks or confidence rating for retrieved channels
# - normalization so retrieved indicators are on a comparable scale
# Then feed x_prompted into the forecaster.

Einige Modelle lassen sich sogar kombinieren mehrere Methoden.

Ein gängiger Ansatz ist das Abrufen mehrere Erstellen Sie ähnliche Serien, führen Sie sie mit Aufmerksamkeit zusammen, damit sich das Modell auf die relevantesten Teile konzentrieren kann, und geben Sie sie dann an einen Experten weiter.

Zusammenfassung

Retrieval-Augmented Forecasting (RAF) lässt Ihr Modell auf eine Weise aus der Vergangenheit lernen, die mit der herkömmlichen Zeitreihenmodellierung nicht möglich ist.

Es wirkt wie ein externer Speicher Dies hilft dem Modell, unbekannte Situationen sicherer zu meistern.

Es ist einfach zu experimentieren und liefert bedeutende Verbesserungen bei Prognoseaufgaben.

Retrieval ist kein akademischer Hype mehr, sondern liefert bereits Ergebnisse in realen Systemen.

Vielen Dank fürs Lesen!

Ich heiße Sara Nóbrega. Ich bin ein KI-Ingenieur, der sich auf MLOps und die Bereitstellung maschineller Lernsysteme in der Produktion konzentriert.


Referenzen

(1) J. Liu, Y. Zhang, Z. Wang et al., Abrufgestützte Zeitreihenprognose (2025), arXiv-Vorabdruck
Quelle: https://arxiv.org/html/2505.04163v1

(2) UConn DSIS, TS-RAG: Time-Sequence Retrieval-Augmented Era (nd), GitHub-Repository
Quelle: https://github.com/UConn-DSIS/TS-RAG

(3) Y. Zhang, H. Xu, X. Chen et al., Speichererweiterte Prognose für Zeitreihen mit seltenen Ereignissen (2024), arXiv-Vorabdruck
Quelle: https://arxiv.org/abs/2412.20810

Von admin

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert