RATFM:検索拡張で時系列基盤モデルに「正常事例」を覚えさせる異常検知を徹底解説

新しい現場に異常検知を導入したいのに、その現場のデータでモデルを学習させる余裕がない——これは実務で頻繁にぶつかる壁です。心電図、呼吸、歩行、電力需要、生体信号。それぞれ波形のクセはまるで違うのに、「正常から外れた点」を見つけたいという目的は共通しています。ところが従来の深層異常検知は、対象ドメインのデータで一から学習するのが前提でした。ドメインが変わるたびに再学習が要るのでは、コストが見合いません。

近年は、大量の時系列で事前学習した時系列基盤モデル(Time Series Foundation Model)が登場し、ゼロショットでもそこそこ動くようになりました。しかし論文が口を揃えて報告するのは「ドメインによって性能がばらつく」「対象ドメインで微調整(fine-tuning)するとさらに伸びる」という事実です。つまり、性能を出そうとすると結局ドメイン依存の微調整に逆戻りしてしまう。大規模モデルをドメインごとに微調整するのは現実的ではありません。

この袋小路を、自然言語処理(NLP)の発想で抜けようとするのが RATFM (Retrieval-augmented Time Series Foundation Model) です。Maru と Sato が 2025 年に発表しました(arXiv:2506.02081, CC-BY 4.0)。アイデアは明快で、大規模言語モデルが「お手本(例)をプロンプトに入れると新しいタスクをこなせる」のと同じように、テスト時に対象ドメインの“正常なお手本”を検索して基盤モデルに与える。微調整の代わりに、検索した事例を文脈(in-context)として注入することで、ドメイン依存の学習なしに異常検知を成立させます。

RATFM を理解すると、次のような場面で武器になります。

  • 学習データを貯められない新規ライン・新規機器の監視: その場の正常データを少し集めて「参照プール」にするだけで動かせる
  • 多ドメインを横断する監視基盤: ドメインごとにモデルを持たず、1つの基盤モデル+検索で済ませる

本記事の内容

  • RATFM の直感 — なぜ「お手本を検索して入れる」と微調整なしで効くのか
  • 予測ベース異常検知の枠組みと、RATFM の検索・注入・スコア計算の数式
  • 検索の中身(相互相関係数による正常参照の選び方)と in-context 注入の仕組み
  • 異常スコアの定義と、論文の目玉である SMA(単純移動平均)後処理
  • 評価(UCR Anomaly Archive の9ドメイン、Time-MoE/Moment、VUS-ROC/VUS-PR)と、point-adjust の水増し問題
  • 動く機構デモ: 合成時系列で「検索した正常参照との比較で異常スコアを出す」仕組みを実装し、純距離ベース/参照なし予測と比較(※論文SOTAの再現ではなく仕組みの実証)

前提知識

この記事を読む前に、以下を読んでおくと理解が深まります。

時系列の異常検知手法を体系的に解説
点異常・文脈異常・集合異常の分類、予測ベース/再構成ベースの考え方。RATFMは予測ベースの発展形です。
時系列異常検知の深掘りサーベイ
8パラダイム分類、基盤モデル/ゼロショット、評価の落とし穴。RATFMの位置づけが俯瞰できます。
USAD:敵対的オートエンコーダによる異常検知
再構成ベースの代表手法。RATFMの予測ベース・検索拡張という発想と対比すると理解が深まります。

RATFM とは — 「微調整」の代わりに「検索したお手本」を渡す

RATFMの概念図:テスト窓から正常参照を検索し、その未来を基盤モデルに注入して予測、ずれを異常スコアにする

まずイメージから入りましょう。あなたの手元に、心電図の波形を「いつも通りか」判定したい1区間(テスト窓)があるとします。その先がどう続くべきかを当てたい。普通の予測モデルなら、過去だけを見て未来を外挿します。ところが新しいドメインだと、基盤モデルは「この波形が次にどう動くか」を確信できず、しばしば外します。

RATFM の発想はこうです。手元に過去の正常な波形をたくさん集めたプールがあるなら、その中から「いまのテスト窓に一番よく似た区間」を検索してくる。似た区間の「その後の続き」は、いまのテスト窓の続きとしても良いお手本になるはずです。そこで、検索した参照(入力+その未来)とテスト窓を連結して基盤モデルに入れ、未来を予測させる。正常な入力なら、お手本のおかげで予測はよく当たります。逆に異常な入力では、似た正常事例の続きを当てはめても合わないので、予測が大きく外れ、その誤差が異常スコアになる

ここが肝心です。RATFM は GPT のように「お手本をプロンプトに入れる」発想を時系列に持ち込んだ手法で、対象ドメインでモデルを学習し直しません。代わりに、検索したお手本を文脈として使う能力を、多様なドメインのデータであらかじめ身につけさせておきます。「微調整の代わりに検索」——これが RATFM の正体です。

では、そもそも予測ベースの異常検知とは何か、そしてなぜゼロショットでは足りないのか。土台から見ていきましょう。

予測ベース異常検知の枠組み

異常検知の深層手法は、大きく予測ベース再構成ベースに分かれます。再構成ベースは入力をいったん潜在表現に圧縮してから復元し、復元の誤差を異常スコアにします(オートエンコーダや Anomaly Transformer がこの系統です)。一方の予測ベースは、過去から未来を当てに行き、当たらなさを異常とみなします。RATFM は予測ベースで、しかも「未来を当てる手がかりとして検索したお手本を使う」点が新しいところです。

予測ベースの考え方はシンプルです。過去 $T$ ステップの入力時系列 $X_{1:T}$ から、未来の $H$ ステップ $\hat{X}_{T+1:T+H}$ を予測します。

$$ \begin{equation} \hat{X}_{T+1:T+H} = f_{\text{forecast}}(X_{1:T}) \end{equation} $$

ここで $T$ は入力長、$H$ は予測ホライズン(先読みの長さ)です。学習は「正常データで未来を正確に当てられるように」進めます。すると推論時には、正常なら当たり、異常なら外れるという非対称性が生まれます。各時刻 $t$ の異常スコアは、予測値と実測値のずれで定義します。

$$ \begin{equation} \mathrm{AS}(x_t) = \left| \hat{x}_t – x_t \right| \end{equation} $$

このスコアがしきい値を超えた点を異常とみなします。考え方は「正常モデルからの逸脱度」であり、時系列異常検知で扱う逸脱ベースの王道です。重要なのは、スコアを計算するのは予測区間 $X_{T+1:T+H}$ だけという点です。入力 $X_{1:T}$ はモデルが「見た」区間なので異常判定の対象にせず、見ていない未来をどれだけ当て外したかだけを評価します。

ここに予測ベースと再構成ベースの本質的な差が出ます。再構成ベースは入力に未来区間 $X_{T+1:T+H}$ まで含めて、それを復元します。すると異常が入力に入っているぶん、モデルは異常もそのまま上手に復元してしまい、誤差が出ず検出を逃すことがあります(論文 Appendix E は、再構成ベースの Moment で RATFM が伸びなかった原因をこれだと分析しています)。予測ベースは未来を入力に含めないので、この落とし穴を構造的に避けられます。RATFM が予測ベースを主役に据えるのは、この検出可能性の差を意識してのことです。

問題は、未知ドメインではこの非対称性が崩れることです。基盤モデルは見たことのないドメインに対し、正常データに対してすら予測を外しがちです。すると正常区間でもスコアが高くなり、適合率(precision)が落ちます。さらに厄介なのは、しきい値がスコア全体の分布から決まるため、正常区間の偽の高スコアがしきい値を押し上げ、微妙な異常を埋もれさせることです。

この「未知ドメインでの予測失敗」をどう潰すか。RATFM の答えが、検索したお手本の注入でした。次の節で、その検索と注入の中身を数式で押さえます。

RATFM のアーキテクチャ — 検索・連結・予測

何を検索するのか

ドメイン $d$ のターゲット入力 $X^{(d)}_{1:T}$ が与えられたとき、RATFM は同じドメインの別の時系列から、入力がよく似た事例 $X^{\text{example}(d)}_{1:T}$ を探します。さらに、その事例の続き(未来) $X^{\text{example}(d)}_{T+1:T+H}$ もセットで取り出します。つまり検索で手に入るのは「似た入力+その入力の正しい未来」のペアです。

似ているかどうかの尺度には、相互相関係数(cross-correlation coefficient)を使います。2つの時系列 $X_{1:T}$ と $\tilde{X}_{1:T}$ に対し、

$$ \begin{equation} \frac{\mathrm{CC}(X_{1:T}, \tilde{X}_{1:T})}{\| X_{1:T} \| \cdot \| \tilde{X}_{1:T} \|} \end{equation} $$

ここで $\mathrm{CC}$ は相互相関の系列(ラグをずらしながら取った相関)、$\|\cdot\|$ はユークリッドノルムです。分母で正規化することで、振幅の大小によらず「形が似ているか」を測れます。相互相関は計算が軽く、位相ずれにも頑健なので、検索の類似度尺度として実務的に有効です(論文は k-Shape 等の時系列クラスタリングで実績のある尺度として引用しています)。

具体的な動きはこうです。クエリ窓 $X_{1:T}$ と候補窓 $\tilde{X}_{1:T}$ を、ラグ $\tau$ を $-(T-1)$ から $T-1$ まで動かしながら内積を取り、その最大値を類似度とします。

$$ \mathrm{sim}(X, \tilde{X}) = \max_{\tau} \frac{\sum_t x_t\, \tilde{x}_{t-\tau}}{\|X\| \cdot \|\tilde{X}\|} $$

ラグを走査して最大を取るのが肝心で、これにより多少の位相ずれがあっても「重ねれば一致する形」を同じ形と判定できます。プール内の全候補窓についてこの類似度を計算し、最大の1件を正常参照として選びます。ユークリッド距離だと位相が1点ずれただけで大きな距離になりますが、ラグ最大の相互相関なら位相ずれに頑健——前節 Fig.6 の (b) が −0.015(位相未整合)、(a) が 0.974(検索で位相整合)だったのは、まさにこのラグ走査の有無の差です。

相互相関係数による検索:クエリに最も似た候補が選ばれる。係数1.00/0.93/0.55の3候補

上図は、1つのクエリ(青)に対して3つの候補との相互相関係数を計算した様子です。形がそっくりな候補は係数 1.00、振幅や位相が少しずれた候補は 0.93、まったく別の波形は 0.55 と、見た目の類似度に応じて係数が下がります。RATFM はプールの中でこの係数が最大の候補を「正常参照」として選びます

どう注入するのか — 連結による in-context 注入

検索した事例を、ターゲット入力と連結(concatenate)して基盤モデルに入れます。記号 $\oplus$ を連結として、入力は次の形になります。

$$ X^{\text{example}(d)}_{1:T} \oplus X^{\text{example}(d)}_{T+1:T+H} \oplus X^{(d)}_{1:T} $$

モデルはこの連結列を受け取り、ターゲットの未来 $H$ ステップを予測します。

$$ \begin{equation} \hat{X}^{(d)}_{T+1:T+H} = f_{\text{forecast}}\!\left( X^{\text{example}(d)}_{1:T} \oplus X^{\text{example}(d)}_{T+1:T+H} \oplus X^{(d)}_{1:T} \right) \end{equation} $$

ここが NLP の in-context learning(文脈内学習)とまったく同じ構造です。LLM が「入力→出力」の例をプロンプトに並べてから本番の入力を置くのと同様に、RATFM は「事例の入力→事例の未来」を前に置いてから、ターゲットの入力を置く。モデルは前半の事例ペアを見て「この形のときはこう続くのか」を読み取り、後半のターゲットに当てはめます。デコーダ専用の Time-MoE のような基盤モデルでは、この連結列をそのまま1本の系列として左から右へ流せるので、注意機構が自然に前半のお手本を参照しながら後半を予測する形になり、実装も素直です。

なお RATFM は検索した事例を確率的に重み付けして混ぜるのではなく、最も似た1件をそのまま文脈として置くだけです。RAG(検索拡張生成)が外部知識をプロンプトに差し込むのと同じく、追加の専用ネットワークもクロスアテンション機構も要りません。注入は連結という最も軽い操作で済み、ここが「微調整より安価」という主張の実装上の裏づけになっています。

入力長の割り当て — 1本の系列に「お手本」をどう詰めるか

連結が軽いとはいえ、基盤モデルが受け取れる系列長には上限があります。RATFM はこの上限を、お手本とターゲットで配分します。論文 Table 1 によれば、デコーダ専用の Time-MoE では最大入力長 1120 を「事例の入力 512+事例の未来 96+ターゲット入力 512」に割り当てます(予測ホライズン $H$ は全設定で 96 に固定)。一方ゼロショットは事例を使わないので、1120 すべてをターゲット入力に使えます。

$$ \underbrace{512}_{\text{事例入力}} + \underbrace{96}_{\text{事例の未来}} + \underbrace{512}_{\text{ターゲット入力}} = 1120 $$

ここに重要なトレードオフが潜んでいます。事例を入れるぶん、ターゲット自身に使える長さは 1120→512 へと半分に減るのです。それでも RATFM がゼロショットを上回るということは、「ターゲットの過去を長く見る」よりも「短くてよいから良いお手本を1つ持つ」ほうが予測に効く、という主張の裏返しになっています。なお再構成ベースの Moment では未来区間 $X_{T+1:T+H}$ も入力に含めるため割り当てが変わり(512 = (160+96)+(160+96))、この違いが後述の「Moment では RATFM が伸びにくい」現象につながります。

基盤モデル本体は学習済みパラメータをそのまま使います。Time-MoE は 12 層・12 ヘッド・専門家 8(うち活性化 2)・$d_{\text{model}}=768$ の Mixture-of-Experts デコーダで、453M パラメータ。Moment は 24 層・$d_{\text{model}}=1024$ の 385M パラメータです。比較対象の Anomaly Transformer はわずか 4.75M で、基盤モデルとは2桁スケールが違います。RATFM の主張は「この巨大モデルをドメインごとに作り直さず、検索だけで適応させる」点にあります。

検索したお手本が予測を実際にどう安定させるかは、論文 Fig.5 が雄弁です。

出典: RATFM, arXiv:2506.02081 (CC-BY 4.0), Fig.5。同じ時系列に対する3設定の予測。上段が検索した事例、下段がターゲット(青帯=偽陽性)。

出典: Maru & Sato, RATFM (arXiv:2506.02081, CC-BY 4.0), Fig.5。各パネルの下段がターゲット、上段が検索した事例。青帯は偽陽性として誤検出された区間。

(a) ドメイン外微調整(Out-domain FT)では、ターゲットの未来予測(赤点線)が実測から外れ、末尾に偽陽性の青帯が出ています。(b) ドメイン内微調整(In-domain FT)はそのドメインを直接学習しているので安定しますが、これはコストの高い上限設定です。(c) RATFM は、上段に検索した似た事例を持ち、その続きを手がかりにすることで、ドメイン内微調整に学習なしで迫る安定した予測を出しています。同じ out-domain データを使いながら、単に微調整した (a) は外し、お手本として検索・注入した (c) は当てる——これが「性能の源は out-domain 学習ではなく検索の活用」という主張を視覚的に裏づけます。

どう学習するのか — 多ドメインでお手本の使い方を覚えさせる

ただし、基盤モデルは事前学習の段階で「お手本を使う」能力を自然には身につけていません。時系列の事前学習は次の値を当てるだけで、例を解釈する動機がないからです。そこで RATFM は、多様なドメインのデータで、検索した事例つきの入力から未来を当てるという微調整を一度だけ行います。損失は全ドメインにわたる平均二乗誤差です。

$$ \begin{equation} L = \sum_d \left( \hat{X}^{(d)}_{T+1:T+H} – X^{(d)}_{T+1:T+H} \right)^2 \end{equation} $$

重要なのは、この学習が特定ドメインに依存しない点です。多ドメインの事例で「お手本を参照して予測する作法」そのものを覚えさせるので、テスト時には学習で一度も見ていない未知ドメインに対しても、そのドメインの正常プールから事例を検索すれば同じ作法が効きます。論文ではこの「お手本の使い方」を学ぶ訓練を、各ターゲットドメインを除いた8ドメインのデータで行い(out-domain な状況をシミュレート)、残り1ドメインで評価しています。つまり「対象ドメインの微調整は不要」という主張を、out-domain 学習で裏づけています。

ここまでで RATFM の中核が見えました。では、本当に「検索したお手本」は「入力自身」より役に立つのでしょうか。次に、その理由を確かめます。

なぜ「入力自身」ではなく「検索した事例」が効くのか

ここで自然な疑問が湧きます。異常検知の時系列はたいてい周期的です。それなら、入力自身の過去の1周期をそのまま未来として外挿すれば、検索なんて要らないのでは?

論文はこの問いに、相似度の実測で答えています(論文 Table 4)。予測ターゲット(真の未来)に対する類似度を3つの区間で測ると、

  • 検索した事例の未来: 0.974
  • 入力時系列のうち、事例の未来に対応する後半区間: 0.768
  • 入力時系列のうち、事例の入力に対応する区間: −0.015

つまり、検索した事例の未来のほうが、入力自身の後半よりも予測ターゲットに似ている(0.974 vs 0.768)。さらに、入力が周期的でも、予測ターゲットに似た区間が入力内の「ちょうど都合のよい位置」に現れるとは限らない(−0.015)。周期がわずかにドリフトするだけで、入力末尾の1周期は未来と位相がずれてしまうのです。

この3つの区間が系列のどこを指すかは、論文 Fig.6 が明快に示しています。

出典: RATFM, arXiv:2506.02081 (CC-BY 4.0), Fig.6。予測ターゲットとの類似度を測る3区間(a)(b)(c)の図解。

出典: Maru & Sato, RATFM (arXiv:2506.02081, CC-BY 4.0), Fig.6。上段 RATFM は「事例の入力⊕事例の未来⊕ターゲット入力」を連結し、予測ターゲット(右の赤帯)と (a) 事例の未来を比較。下段 Zero-shot は事例を持たず、ターゲット入力の中から (b) 末尾 96 点 / (c) 全 608 点を切り出して予測ターゲットと比較する。

図の右端の赤帯が「当てたい未来(予測ターゲット)」です。RATFM(上段)はその直前に事例ペアを置き、(a) として検索した事例の未来 96 点を予測ターゲットと比べます。これが平均類似度 0.974。一方ゼロショット(下段)は事例を持てないので、ターゲット入力の中で代用するしかありません。(b) 入力末尾の 96 点だけを切り出すと −0.015、(c) 入力全体の 608 点まで広げてようやく 0.768 です。注目すべきは (b) の −0.015——位相をぴったり合わせて切り出さない限り、周期的な入力でも未来とは無相関になりうるのです。検索は「プール全体からラグをずらしながら最も似た窓」を選ぶので、この位相合わせを自動でやってくれる。だから (a) が圧勝します。論文 Table 9 のドメイン別内訳でも、(a) は全9ドメインで 0.88〜0.996 と一貫して高く、検索の優位はドメインを問わないことが示されています。

この現象を、合成データで実際に確かめてみましょう。

import numpy as np

def quasi_series(n, base_period=70.0, drift=0.0008, amp=1.0, noise=0.04, seed=0, shape=0.0):
    """周期がゆっくりドリフトする準周期系列。入力末尾の1周期は未来と位相がずれる。"""
    r = np.random.default_rng(seed)
    t = np.arange(n)
    phase = 2*np.pi*np.cumsum(1.0/(base_period*(1+drift*t)))
    x = amp*(np.sin(phase) + 0.35*np.sin(2*phase + shape))
    return x + noise*r.standard_normal(n)

def xcorr_coef(a, b):                      # 相互相関係数(式3): 正規化内積のラグ最大
    a = a - a.mean(); b = b - b.mean()
    na = np.linalg.norm(a)+1e-8; nb = np.linalg.norm(b)+1e-8
    return float((np.correlate(a, b, mode="full")/(na*nb)).max())

# 参照プール(同種の準周期系列を多数)とターゲット
pool = np.concatenate([quasi_series(1800, seed=100+i, shape=0.3*i) for i in range(8)])
target = quasi_series(3000, seed=999, shape=0.6)
T, H = 210, 60
qs = 900
q, fut = target[qs:qs+T], target[qs+T:qs+T+H]

# 検索: プールから q に最も似た窓を探し、その直後 H をコピー
best, bj = -9, 0
for j in range(0, len(pool)-T-H, 6):
    c = xcorr_coef(q, pool[j:j+T])
    if c > best: best, bj = c, j
ref_in, ref_fut = pool[bj:bj+T], pool[bj+T:bj+T+H]
sc = (q.std()+1e-8)/(ref_in.std()+1e-8)
fc_ref = ref_fut*sc + (q.mean() - ref_in.mean()*sc)   # 振幅・水準を整合してコピー予測

# ゼロショット近似: 入力末尾の1周期(約70)をそのまま未来へ外挿
fc_zs = target[qs+T-70:qs+T-70+H]

print("ゼロショット 平均絶対誤差:", round(np.mean(np.abs(fc_zs-fut)), 3))
print("RATFM       平均絶対誤差:", round(np.mean(np.abs(fc_ref-fut)), 3))
print("対未来 相関 ゼロショット:", round(np.corrcoef(fc_zs, fut)[0,1], 3))
print("対未来 相関 RATFM:      ", round(np.corrcoef(fc_ref, fut)[0,1], 3))

実行すると、ゼロショットの平均絶対誤差は約 1.28、RATFM は約 0.04。予測ターゲットとの相関は、ゼロショットが −0.84(位相が反転して逆向きに外す)に対し、RATFM は 0.996 とほぼ完全に一致します。周期ドリフトのせいで「入力末尾をそのまま伸ばす」戦略が破綻し、検索で位相の合った事例を引いてくる戦略が圧勝するわけです。

参照なし予測と参照あり予測の比較:ゼロショットは位相がずれて未来を外し、RATFMは事例の未来で正確に当てる

左図(参照なし)では、赤い予測線が真の未来(灰色破線)から大きく逸れています。周期ドリフトで入力末尾の位相が未来とずれているためです。一方、右図(参照あり)では、検索した事例の未来をコピーした緑の予測線が真の未来にぴったり重なっています。同じ入力でも、「お手本があるかないか」で予測精度がこれほど変わる——これが RATFM の効きどころです。

加えて論文は、基盤モデルが事前学習で非周期データも見ているため、「周期的な入力を例として使う」能力をそもそも獲得していないと指摘します。実際、検索した事例を学習なしのゼロショットモデルにそのまま渡す設定(RATFM w/o training)は性能が伸びません。事例を活かす能力は、RATFM の後付け学習で明示的に身につける必要があるのです。

ここまでで「検索が効く理由」が腹落ちしました。次は、もう一つの目玉である異常スコアの後処理を見ます。

SMA 後処理 — スコアの「とげ」をならして真の異常を浮かせる

予測誤差をそのまま異常スコアにすると、困った現象が起きます。周期的なピーク(山や谷の頂点)では、真の異常がなくても誤差が跳ねやすいのです。頂点は値の変化が急なので、ほんの少しの予測ずれが大きな絶対誤差になります。結果、スコアの波形がとげとげになり、異常以外の場所でしきい値を超えたり、しきい値そのものを押し上げたりします。

論文の対策はシンプルです。生のスコアに単純移動平均(SMA: Simple Moving Average)をかけてならします。データ点 $x_t$ に対する $n$ 点移動平均は、

$$ \begin{equation} \overline{\mathrm{AS}}(x_t) = \frac{1}{n} \sum_{i=0}^{n-1} \mathrm{AS}(x_{t-i}) \end{equation} $$

窓幅 $n$ は、フーリエ変換で推定したその系列の周期に設定します。移動平均は短い「とげ」を平らにする一方、集合異常のように一定区間続く逸脱はならしても残るので、真の異常だけが滑らかな山として浮かび上がります。

機構デモで、検索ベース予測のスコアに SMA をかけた前後を見てみましょう。

def standardize(x, ref): m, s = ref.mean(), ref.std()+1e-8; return (x-m)/s
def sma(z, n): return np.convolve(z, np.ones(n)/n, mode="same")

def inject_anomaly(x, starts, dur=24):       # レベルシフト型の集合異常
    x = x.copy(); lab = np.zeros(len(x), dtype=int)
    for s in starts:
        x[s:s+dur] += 1.6; lab[s:s+dur] = 1
    return x, lab

# 正常系列+異常注入、別系列の参照プール
base = quasi_series(2400, seed=77, shape=0.5)
x, lab = inject_anomaly(base, [700, 1300, 1900], dur=24)
pool = np.concatenate([quasi_series(2000, seed=200+i, shape=0.3*i) for i in range(6)])
xs, pools = standardize(x, base), standardize(pool, base)

# スライドしながら検索ベース予測→誤差スコア
T, H = 160, 40
pj = list(range(0, len(pools)-T-H, 8))
pw = np.stack([pools[j:j+T] for j in pj]); pwn = pw - pw.mean(1, keepdims=True)
pnn = np.linalg.norm(pwn, axis=1)+1e-8
s_ref = np.zeros(len(xs)); cov = np.zeros(len(xs))
for s in range(0, len(xs)-T-H, H):
    q, fut = xs[s:s+T], xs[s+T:s+T+H]
    qn = q - q.mean(); qn = qn/(np.linalg.norm(qn)+1e-8)
    j = pj[int(np.argmax((pwn@qn)/pnn))]            # 相関最大の参照
    ref_in, ref_fut = pools[j:j+T], pools[j+T:j+T+H]
    scn = (q.std()+1e-8)/(ref_in.std()+1e-8)
    fc = ref_fut*scn + (q.mean() - ref_in.mean()*scn)
    s_ref[s+T:s+T+H] = np.abs(fc - fut); cov[s+T:s+T+H] = 1
s_sma = sma(s_ref, 60)

from sklearn.metrics import roc_auc_score
m = cov > 0
print("SMA前 ROC-AUC:", round(roc_auc_score(lab[m], s_ref[m]), 3))
print("SMA後 ROC-AUC:", round(roc_auc_score(lab[m], s_sma[m]), 3))

実行すると、SMA 前の ROC-AUC が約 0.954、SMA 後が約 0.962 と改善します。論文でも全設定で VUS-ROC が改善し、特に RATFM では Time-MoE で 68.9% → 76.1%、Moment で 68.8% → 74.3% と効果が大きいと報告されています。

窓幅 $n$ を「フーリエ変換で推定した系列の周期」に取る理由も、ここで腑に落ちます。とげの正体は周期的なピークでの予測ずれでした。ならば、ならす窓を1周期ぶんに取れば、ピークごとに散る偽の山がちょうど1周期分平均化されて消える一方、1周期より長く続く真の集合異常は平均化しても山として残ります。周期に同期した平滑化が、偽陽性だけを選択的に潰す鍵なのです。

論文 Fig.4 は、これを実データ(Fig.2 と同じ系列)で示しています。

出典: RATFM, arXiv:2506.02081 (CC-BY 4.0), Fig.4。SMA適用後の予測(上)と異常スコア(下)。(a)Zero-shot (b)RATFM。赤帯=真の異常。

出典: Maru & Sato, RATFM (arXiv:2506.02081, CC-BY 4.0), Fig.4。Time-MoE に SMA を適用した結果。各パネル上段が予測、下段が異常スコアとしきい値。赤帯が真の異常区間。

SMA をかける前(論文 Fig.2)はほぼすべての周期ピークでスコアが跳ね、しきい値を何度も超えていました。SMA 後の Fig.4 では、その偽陽性が抑えられ、赤帯の真の異常だけが滑らかな山として残ってしきい値を超えています。(a) ゼロショットと (b) RATFM を比べると、RATFM のほうがスコアのベースラインが低く平坦で、異常の山がよりくっきり浮いています。これは検索したお手本のおかげで正常区間の予測が安定し、誤差のベースノイズ自体が下がっていることの表れです。後処理(SMA)と検索(RATFM)は別々の工夫ですが、両者が噛み合って初めて「異常だけが際立つ」スコアになるわけです。

SMA前の生スコア:レベルシフト異常で大きく跳ねるが、異常以外でも小ピークが出てしきい値を押し上げる

上の2段の図は、標準化系列(上段、赤帯が真の異常)と生の異常スコア(下段)です。3つの異常区間でスコアがしっかり跳ねていますが、異常以外の場所にも細かいピークが散在し、しきい値(平均+3σ)が押し上げられているのが分かります。これがスコアの「とげ」の正体です。

SMA後のスコア:細かい揺れがならされ、3つの異常区間が滑らかな山として残りしきい値を超える

SMA をかけると、細かい揺れが平らになり、3つの異常区間が滑らかな山として残ります。しきい値を超える山が真の異常とよく対応するようになりました。後処理を一つ挟むだけで、検出のクリアさが目に見えて上がるわけです。

論文はこの結果から、「逸脱の大きさをそのまま使う標準的なスコアリングには限界があり、スコアの設計が性能を左右する」という教訓を引き出しています。次は、これらの仕組みが実データでどれだけ効くのか、評価の中身を見ていきます。

評価 — データセット・指標・主結果

データセットと比較対象

評価には UCR Anomaly Archive を使います。9 ドメイン・250 本の単変量時系列からなる多ドメインデータセットで、各時系列はちょうど1つの異常を含みます。内訳(論文 Table 5)は、心電図 ECG 91本・動脈血圧 42本・歩行 33本・昆虫生体信号 25本・呼吸 17本・電力需要 11本・観測機器信号 11本・温度 13本・加速度 7本。系列長は中央値で訓練 9,406 点・テスト 25,001 点、異常区間長は中央値 101 点と、ドメインによって波形のクセも異常の規模も大きく異なります。だからこそ「ドメイン非依存」を検証する題材として適しています。このデータセットは、従来ベンチマークの欠陥(タスク難易度の偏り、非現実的な異常密度、ラベル誤り、異常位置の偏り)を是正するために作られた点でも信頼できます。前処理として、各点は訓練データの平均・標準偏差で標準化します。

ベースとなる基盤モデルは2つ。Time-MoE(デコーダ専用・Mixture-of-Experts の予測モデル、453M パラメータ)と Moment(再構成タスクで学習した基盤モデル、軽量な線形ヘッドを付け替えて各タスクに適応、385M パラメータ)です。比較対象として、再構成ベースの Anomaly Transformer、統計的手法の Sub-PCA、テキストベースの GPT-4o(時系列を文字列でプロンプト入力)も評価しています。

訓練設定は、ゼロショット、out-domain FT(対象以外の8ドメインで微調整)、in-domain FT(対象ドメインで微調整=コストの高い上限の目安)、そして RATFM、RATFM w/o training の5つです。

評価指標 — なぜ VUS を使い、なぜ adjusted-F1 を避けるのか

指標は、点ごとの F1 スコア、VUS-ROCVUS-PR を使います。点ごと F1 はしきい値(テストスコアの平均+3σ)で二値化して計算しますが、検出タイミングのわずかなずれに敏感という弱点があります。VUS-ROC と VUS-PR はしきい値非依存で、真の異常ラベルを連続値として扱う指標です。詳しくは下記の評価指標の記事を参照してください。

VUS:時系列異常検知のしきい値非依存な評価指標
point-adjustの水増しを避け、バッファ付き連続ラベルで体積として評価するVUS-ROC/VUS-PRを解説。

ここで論文がはっきり避けているのが adjusted-F1(point-adjust)です。これは「異常区間内で1点でも当てれば区間全体を検出成功とみなす」修正版 F1 で、広く使われてきました。しかし非現実的に高い recall を生み、公平な比較を妨げるため、RATFM では採用していません。これは時系列異常検知の評価で繰り返し指摘されてきた落とし穴です。どれくらい危ういのか、機構デモで確かめます。

from sklearn.metrics import precision_recall_curve, auc
rng = np.random.default_rng(1)
N = 2000; lab = np.zeros(N, dtype=int)
for s in [300, 900, 1500]: lab[s:s+30] = 1
good = rng.random(N)*0.3; good[lab==1] += 0.6     # まともなスコア
rand = rng.random(N)                               # ランダムスコア

def point_adjust_f1(score, lab, thr):
    pred = (score > thr).astype(int); padj = pred.copy(); i = 0
    while i < len(lab):                             # 異常区間に1点でも当たれば区間全体を検出扱い
        if lab[i] == 1:
            j = i
            while j < len(lab) and lab[j] == 1: j += 1
            if pred[i:j].any(): padj[i:j] = 1
            i = j
        else: i += 1
    tp = ((padj==1)&(lab==1)).sum(); fp = ((padj==1)&(lab==0)).sum(); fn = ((padj==0)&(lab==1)).sum()
    p, r = tp/(tp+fp+1e-9), tp/(tp+fn+1e-9)
    return 2*p*r/(p+r+1e-9)

def best_pa(sc):                                   # しきい値を振ってpoint-adjust F1の最大
    return max(point_adjust_f1(sc, lab, t) for t in np.linspace(0, 1, 50))
def ap(sc):                                        # PR曲線下面積(VUS-PRの素朴版)
    p, r, _ = precision_recall_curve(lab, sc); return auc(r, p)
print("point-adjust F1  まとも:", round(best_pa(good),3), " ランダム:", round(best_pa(rand),3))
print("AP(しきい値非依存) まとも:", round(ap(good),3), " ランダム:", round(ap(rand),3))

実行すると、point-adjust F1 はまともな検出器で 1.000、ランダム検出器でも 0.635と高く出ます。良い検出器と区別がつきません。一方、AP(VUS-PR の素朴版)はまともな検出器で 1.000、ランダムで 0.055 と、ランダムを正しく低く評価します。

point-adjust F1とAPの比較:point-adjustはランダム検出器でも0.635と高く出るが、APは0.055と正しく低評価

左がpoint-adjust F1、右がAP です。point-adjust はランダムでも 0.635 と高い値を返してしまい(水増し)、まともな検出器との差がほとんど出ません。AP はランダムを 0.055 と正しく低く評価し、性能差をきちんと映します。RATFM が point-adjust を避けて VUS を採るのは、こうした水増しを避けて誠実に比較するためです。

主結果 — RATFM は out-domain FT を超え in-domain FT に迫る

SMA 適用後の主結果(論文 Table 3 の VUS-ROC)を可視化します。

論文Table3の可視化:RATFMはゼロショット・ドメイン外FTを上回り、コスト上限のドメイン内FTに迫る

Time-MoE では、ゼロショット 68.7% → out-domain FT 70.5% → RATFM 76.1% → in-domain FT 79.1%(上限)。Moment でも、ゼロショット 70.6% → out-domain FT 70.7% → RATFM 74.3% → in-domain FT 77.4%。注目すべきは、RATFM と同じ out-domain データで微調整しただけの out-domain FT がほとんど伸びないのに対し、RATFM は大きく伸び、コストの高い in-domain FT(上限)に迫っている点です。つまり性能の源は「out-domain データで学習したこと」ではなく「検索したお手本を使えること」だと分かります。

SMA の効果も論文 Table 2 で確認できます。

論文Table2の可視化:SMA後処理は全設定でVUS-ROCを改善し、RATFMで特に効果が大きい

SMA なし/ありを比べると、全設定で VUS-ROC が改善し、特に RATFM では Time-MoE で 68.9% → 76.1%、Moment で 68.8% → 74.3% と効果が顕著です。後処理一つが大きな差を生むことが見て取れます。

なお論文では、ゼロショットの基盤モデルでも Anomaly Transformer や Sub-PCA といった既存手法を上回り、基盤モデルの汎化力の高さも示されています。一方、再構成ベースの Moment では RATFM が伸びにくいなど、課題も正直に報告されています。

機構デモ — 検索ベース予測が誤差ベースで最良

ここで、本記事の機構デモをまとめます。論文の SOTA を再現するものではなく、「検索した正常参照との比較で異常スコアを出す」という仕組みが、純距離ベースや参照なし予測よりも有利になることを、合成データで示すものです。先ほどの準周期系列(周期ドリフトあり)にレベルシフト異常を注入し、6本の系列で平均した結果を比べます。

results = {"距離ベース": [], "ゼロショット": [], "RATFM(検索)": []}
aps = {k: [] for k in results}
for trial in range(6):
    base = quasi_series(2400, seed=300+trial, shape=0.4*trial)
    x, lab = inject_anomaly(base, [640+trial*20, 1300, 1900], dur=24)
    pool = np.concatenate([quasi_series(2000, seed=400+trial*10+i, shape=0.3*i) for i in range(6)])
    xs, pools = standardize(x, base), standardize(pool, base)
    T, H = 160, 40
    pj = list(range(0, len(pools)-T-H, 8))
    pw = np.stack([pools[j:j+T] for j in pj]); pwn = pw - pw.mean(1, keepdims=True)
    pnn = np.linalg.norm(pwn, axis=1)+1e-8
    s_ref = np.zeros(len(xs)); s_zs = np.zeros(len(xs)); cov = np.zeros(len(xs))
    for s in range(0, len(xs)-T-H, H):
        q, fut = xs[s:s+T], xs[s+T:s+T+H]
        qn = q - q.mean(); qn = qn/(np.linalg.norm(qn)+1e-8)
        j = pj[int(np.argmax((pwn@qn)/pnn))]
        ref_in, ref_fut = pools[j:j+T], pools[j+T:j+T+H]
        scn = (q.std()+1e-8)/(ref_in.std()+1e-8)
        fc = ref_fut*scn + (q.mean() - ref_in.mean()*scn)
        s_ref[s+T:s+T+H] = np.abs(fc - fut)                  # 検索ベース予測誤差
        s_zs[s+T:s+T+H] = np.abs(xs[s+T-70:s+T-70+H] - fut)  # 参照なし(末尾外挿)
        cov[s+T:s+T+H] = 1
    s_dist = np.abs(xs - np.median(pools))*cov               # 距離ベース(予測なし)
    m = cov > 0; y = lab[m]
    for name, sc in [("距離ベース", s_dist), ("ゼロショット", s_zs), ("RATFM(検索)", s_ref)]:
        results[name].append(roc_auc_score(y, sc[m]))
        p, r, _ = precision_recall_curve(y, sc[m]); aps[name].append(auc(r, p))
for k in results:
    print(f"{k}: ROC-AUC={np.mean(results[k]):.3f}  AP={np.mean(aps[k]):.3f}")

実行すると、RATFM(検索)が ROC-AUC 0.955 / AP 0.399 で最良。距離ベースは 0.661 / 0.279、参照なし予測(ゼロショット)は 0.350 / 0.137 にとどまります(下のバー図は図生成スクリプト側のラベル付き値 0.953 / 0.398 等で、ほぼ同値です)。

手法比較:検索ベース予測がROC-AUC・APとも最良、距離ベース・参照なし予測を大きく上回る

ROC-AUC・AP のどちらでも、検索ベース予測(RATFM 相当)が圧勝しています。注目すべきは、参照なし予測のスコアが ROC-AUC 0.350 と 0.5 を下回っている点です。これは偶然ではありません。周期ドリフトのせいで参照なし予測は正常区間でも常に大きく外すため、誤差信号が周期構造に支配され、肝心のレベルシフト異常がそこに埋もれてしまうからです。これはまさに論文が指摘した「未知ドメインでは正常データの予測も失敗し、適合率が落ちる」現象の縮図です。検索でお手本を与えると正常区間の予測が安定し、異常だけが誤差として際立つ——機構レベルでその効果が確認できました。

ここまでで RATFM の効きが見えました。次に、参照プールが小さくても使えるのか、という実務的な問いを見ます。

参照プールが小さくても効くのか

実務では、対象ドメインの正常事例をたくさん集められるとは限りません。論文は、参照候補のプールサイズを 100% / 75% / 50% / 25% と減らして VUS-ROC を測り、性能の落ち方を調べています(論文 Fig.7、心電図 ECG と歩行 Gait の2ドメイン)。結果は「プールを減らすと緩やかに性能は下がるが、25% でもゼロショットや out-domain FT を上回る」というもので、少ない事例でも実用に耐えることを示しました。

出典: RATFM, arXiv:2506.02081 (CC-BY 4.0), Fig.7。参照プールを25/50/75/100%に減らしたときのVUS-ROC(ECG/Gait)。

出典: Maru & Sato, RATFM (arXiv:2506.02081, CC-BY 4.0), Fig.7。左2本がゼロショットとドメイン外FT、右4本がプールサイズを変えた RATFM。緑=ECG、橙=Gait。

具体的な数値を見ると、ECG ではゼロショット 67.7% に対し、RATFM はプール 25% でも 71.2% とすでに上回り、100% で 81.3% まで伸びます。歩行(Gait)も同様に、ゼロショット 60.8% → RATFM 25% で 66.3% → 100% で 80.9%。プールを 1/4 に絞ってもゼロショットとドメイン外微調整(緑橙の左2本)を超える——この「少数事例でも下限を割らない」頑健さが、検索拡張の実務的な強みです。プールが大きいほど「もっと似た事例」が見つかりやすく単調に伸びるので、運用では正常データを貯めるほど精度が上がる、という素直な性質も読み取れます。

機構デモでも、プールサイズに対する ROC-AUC の傾向を再現してみます。

fracs = [0.25, 0.5, 0.75, 1.0]; res = []
for fr in fracs:
    accs = []
    for trial in range(5):
        base = quasi_series(2400, seed=500+trial, shape=0.4*trial)
        x, lab = inject_anomaly(base, [640, 1300, 1900], dur=24)
        allpool = [quasi_series(2000, seed=600+trial*10+i, shape=0.3*i) for i in range(8)]
        k = max(1, round(len(allpool)*fr))
        pool = np.concatenate(allpool[:k])
        xs, pools = standardize(x, base), standardize(pool, base)
        T, H = 160, 40
        pj = list(range(0, len(pools)-T-H, 8))
        pw = np.stack([pools[j:j+T] for j in pj]); pwn = pw - pw.mean(1, keepdims=True)
        pnn = np.linalg.norm(pwn, axis=1)+1e-8
        s_ref = np.zeros(len(xs)); cov = np.zeros(len(xs))
        for s in range(0, len(xs)-T-H, H):
            q, fut = xs[s:s+T], xs[s+T:s+T+H]
            qn = q - q.mean(); qn = qn/(np.linalg.norm(qn)+1e-8)
            j = pj[int(np.argmax((pwn@qn)/pnn))]
            ref_in, ref_fut = pools[j:j+T], pools[j+T:j+T+H]
            scn = (q.std()+1e-8)/(ref_in.std()+1e-8)
            fc = ref_fut*scn + (q.mean() - ref_in.mean()*scn)
            s_ref[s+T:s+T+H] = np.abs(fc - fut); cov[s+T:s+T+H] = 1
        m = cov > 0; accs.append(roc_auc_score(lab[m], s_ref[m]))
    res.append(np.mean(accs))
print(dict(zip([f"{int(f*100)}%" for f in fracs], [round(v,3) for v in res])))

実行すると、ROC-AUC はプール 25% で 0.940、50% で 0.954、100% で 0.955。プールを 1/4 に絞っても性能はわずかしか落ちません。

参照プールサイズと性能:プールを25%まで減らしてもROC-AUCは0.940と緩やかにしか落ちない

横軸がプールサイズ、縦軸が ROC-AUC です。プールを 100% から 25% まで減らしても、性能は 0.955 から 0.940 へ緩やかに下がるだけで、検索ベースの優位は保たれます。これは論文 Fig.7 の傾向(少ない事例でも頑健)と一致します。少数の正常事例さえ集められれば動く、という実務上の安心材料です。

最後に、RATFM がどこで失敗するのか、限界も押さえておきましょう。

RATFM の限界 — 3つの誤り事例

論文は誤り分析(6.3節)で、RATFM が外す典型を3つ挙げています。手法の射程を正しく理解するために重要です。論文 Fig.8 が、その3ケースを実データで可視化しています。

出典: RATFM, arXiv:2506.02081 (CC-BY 4.0), Fig.8。RATFMが外す3つの誤り事例(a)(b)(c)。

出典: Maru & Sato, RATFM (arXiv:2506.02081, CC-BY 4.0), Fig.8。(a) 事例とターゲットで未来が食い違うケース(青帯=偽陽性)、(b) 小さな逸脱の異常(ピンク=見逃し)、(c) 異常が次窓の予測を汚すケース(紫=正検出、青=後引きの偽陽性)。

RATFMが苦手な3つの誤り事例:(a)参照の未来が食い違う (b)小さな異常は見逃す (c)異常が次窓の予測を汚す

  • (a) 参照の未来がターゲットと食い違う: 入力どうしは似ていても、その先の続きが事例とターゲットで違うと、コピーした未来が実測から外れて偽陽性になります。検索は「入力の類似」で選ぶので、未来まで一致する保証はありません。
  • (b) 小さなずれの異常は見逃す: 異常スコアは逸脱の大きさに比例するため、高頻度だが振幅の小さい異常はスコアが伸びず、しきい値に届きません。
  • (c) 異常が次の予測を汚す: 異常区間がモデルの入力に含まれると、その後の予測精度が落ち、本来正常な後続区間まで高スコアになって偽陽性を生みます。異常の「後引き」です。

これらは予測ベース異常検知に共通の課題でもあり、検索拡張だけでは解けません。スコアリングの工夫(SMA はその一歩)や、異常を含む入力への頑健化が今後の課題として残されています。

まとめ

本記事では、RATFM(検索拡張・時系列基盤モデル)による異常検知を、理論から機構デモまで解説しました。

  • 発想: 大規模言語モデルの in-context learning を時系列に持ち込み、ドメイン別の微調整の代わりに、検索した正常事例をお手本として注入する
  • 検索: 相互相関係数で、テスト窓に最も似た正常区間(入力+その未来)をプールから選ぶ
  • 注入と予測: 「事例の入力⊕事例の未来⊕ターゲット入力」を連結して基盤モデルに入れ、未来を予測。お手本の使い方は多ドメインの後付け学習で身につける
  • スコアと後処理: 予測誤差 $|\hat{x}_t – x_t|$ を異常スコアとし、SMA でとげをならして真の異常を浮かせる
  • 評価: UCR の9ドメインで、RATFM は out-domain FT を超え、コスト上限の in-domain FT に迫る。VUS を採り、水増しの大きい point-adjust は避ける
  • 限界: 参照の未来の食い違い、小さな異常、異常の後引きには弱い

「学習させづらい現場こそ狙う」という問題設定が RATFM の魅力です。検索という軽い仕組みで、重い微調整を肩代わりさせる発想は、基盤モデル時代の異常検知の有力な方向性と言えます。

次のステップとして、以下の記事も参考にしてください。

本記事の概念図 Fig.1 は Maru & Sato, “RATFM: Retrieval-augmented Time Series Foundation Model for Anomaly Detection” (arXiv:2506.02081, CC-BY 4.0) の Fig.1 を引用しています。

出典: Maru & Sato, RATFM (arXiv:2506.02081), Fig.1

出典: Maru & Sato, RATFM: Retrieval-augmented Time Series Foundation Model for Anomaly Detection (arXiv:2506.02081), Fig.1。学習時は多ドメインの「事例+ターゲット」を連結して未来予測を学び、評価時は未知ドメインで検索した事例を注入して予測、ずれを異常とみなします。