Conflict-Aware Anomaly Detection (CAD):MMoEで指標の衝突を解くアーキテクチャを徹底解説

多変量時系列の異常検知では、CPU・メモリ・レイテンシ・エラー率といった性質の異なる多数の指標(KPI)を、1つのモデルでまとめて再構成/予測するのが定番です。しかしこのとき、指標ごとの学習目標が衝突します。安定した指標と、正常なのにベースラインがずれる指標が混在すると、全指標を1つの損失で最適化するモデルは、各指標の勾配が食い違って打ち消し合い、性能が落ちます。

CAD(Conflict-Aware Anomaly Detection) は、この衝突をアーキテクチャで解く手法です(Si et al., ESEC/FSE 2023)。Multi-gate Mixture-of-Experts(MMoE)を時系列異常検知向けに作り替え、指標ごとに専門家の選び方を変えることで、衝突を隔離しつつ有益な指標間依存は活かします。

本記事は、CADのアーキテクチャと骨子——どんなコンポーネントが、どう繋がって動くのか——を数式とデータフローで追います。

本記事の内容

  • なぜ衝突が起きるのか(BD&ISF)と、それを勾配で実測
  • CADの全体データフロー(式1〜6)
  • 各コンポーネントの中身:task-oriented特徴選択 / 畳み込み専門家 / p&sゲート / tower / 損失

前提・関連記事

Bi-Attention × Mixture-of-Experts による多変量時系列の異常検知
MoEの基礎(gating/負荷分散)を実装で解説。CADの土台。
OmniAnomaly:確率的RNNによる多変量時系列の異常検知
全指標を共有モデルで扱う典型。CADが作り替える対象。

衝突の正体:BD&ISF

CADの出発点は、実データで観察される次の現象です。

ベースラインドリフトと固有揺らぎ(BD&ISF)

多くの指標(A)は安定したパターンを持つ一方、一部の指標(B)ではベースラインドリフト(baseline drift) や固有の確率的揺らぎ(inherent stochastic fluctuation) ——あわせて BD&ISF ——が起きます。これらは異常ではなく、ロードバランシング等の正当な要因による正常な挙動です。

論文では、この衝突を実データで可視化しています。

CAD論文Fig.1 指標間の目標衝突の例

出典: Si et al., “Beyond Sharing: Conflict-Aware Multivariate Time Series Anomaly Detection”, ESEC/FSE 2023, Fig.1 (arXiv:2308.08915, CC BY 4.0)

上3段は3つの指標の生波形で、metric 3には黄色枠のベースラインドリフトと、青帯の固有揺らぎ区間が見えます——いずれも正常な挙動です。下2段は異常スコアで、共有モデルのUSADはこの正常なドリフト/揺らぎ区間(青帯)を再構成しきれずスコアを跳ね上げ誤検出していますが、CADは同じ区間を平坦に保ち、真の異常(赤帯)だけを際立たせています。安定指標の目標が「細部に敏感であれ」と要求した結果、metric 3のBD&ISFが異常として漏れ出している——これが衝突の正体です。

全指標を1つの損失で学習すると、安定指標Aの目標は「細かい変動に敏感であれ」と要求し、その結果モデルはBのBD&ISFを異常と誤検出します。逆にBの目標は「大きな揺れを許容せよ」と要求する。目標が相反するため、パラメータの勾配が異なる方向に降下して打ち消し合うのです。

勾配の衝突を実測する

本当に勾配が食い違うのか、共有トランク+2指標ヘッドの小モデルで、各指標の損失勾配のコサイン類似度を測って確かめます。

import numpy as np, torch, torch.nn as nn
np.random.seed(7); torch.manual_seed(7)
L = 20

def make_pair(kind, N=3000, seed=0):
    rng = np.random.default_rng(seed); t = np.arange(N)
    a = np.sin(0.08*t) + 0.03*rng.standard_normal(N)
    if kind == "harmonious":                                    # A,Bは似た力学
        b = np.sin(0.08*t+0.3) + 0.03*rng.standard_normal(N)
    else:                                                       # Bはdrift+揺らぎ(BD&ISF)
        drift = np.cumsum(rng.standard_normal(N))*0.02
        b = np.sin(0.08*t) + drift + 0.18*rng.standard_normal(N)
    X = np.stack([a, b], 1).astype(np.float32)
    W = np.stack([X[i:i+L] for i in range(N-L)]); Y = X[L:N]
    return torch.tensor(W), torch.tensor(Y)

class SharedForecaster(nn.Module):
    def __init__(self, L, d=64):
        super().__init__()
        self.trunk = nn.Sequential(nn.Flatten(), nn.Linear(2*L,d), nn.ReLU(), nn.Linear(d,d), nn.ReLU())
        self.head_a = nn.Linear(d,1); self.head_b = nn.Linear(d,1)
    def forward(self, W):
        h = self.trunk(W); return self.head_a(h).squeeze(-1), self.head_b(h).squeeze(-1)

def grad_cosine_run(kind, steps=300, seed=0):
    torch.manual_seed(seed); W, Y = make_pair(kind, seed=seed)
    model = SharedForecaster(L); opt = torch.optim.Adam(model.parameters(), 1e-3)
    trunk = list(model.trunk.parameters()); coss = []
    for step in range(steps):
        idx = torch.randint(0, len(W), (128,)); w, y = W[idx], Y[idx]
        pa, pb = model(w)
        la = ((pa-y[:,0])**2).mean(); lb = ((pb-y[:,1])**2).mean()
        ga = torch.autograd.grad(la, trunk, retain_graph=True)   # 指標Aの勾配
        gb = torch.autograd.grad(lb, trunk, retain_graph=True)   # 指標Bの勾配
        fa = torch.cat([g.flatten() for g in ga]); fb = torch.cat([g.flatten() for g in gb])
        coss.append(float(torch.dot(fa,fb)/(fa.norm()*fb.norm()+1e-9)))
        opt.zero_grad(); (la+lb).backward(); opt.step()
    return np.array(coss)

ch = grad_cosine_run("harmonious", seed=1); cc = grad_cosine_run("conflicting", seed=2)
print("調和: 平均cos=%.3f 負%.0f%%" % (ch.mean(), 100*(ch<0).mean()))
print("衝突: 平均cos=%.3f 負%.0f%%" % (cc.mean(), 100*(cc<0).mean()))

実行結果は 調和: 平均cos=0.112 負33% / 衝突: 平均cos=-0.031 負61%。

指標間の勾配コサイン類似度ヒストグラム

衝突ケースでは勾配のコサインが0付近〜負に寄り、61%のステップで2指標の改善方向が逆向きになっています。共有モデルでは、ある指標を良くすると別の指標が悪くなる——この衝突を構造で解くのがCADです。

CADの全体アーキテクチャ

CADは予測ベース(forecasting-based)・教師なしの階層モデルで、指標ごとに独立した構造を持ちます。全体のデータフローはこうです。

CADの詳細データフロー

論文の構成図と並べると対応が掴めます。

CAD論文Fig.2 ネットワークアーキテクチャ

出典: Si et al., CAD, ESEC/FSE 2023, Fig.2 (arXiv:2308.08915, CC BY 4.0)

左から、$K$ 個の指標 $m_1,\dots,m_K$ の窓が共有された expert 1〜M に入り(専門家は全指標を見る)、出力が p-gate(個別)と s-gate(共有)の重みで $\otimes$ 融合され($\oplus$ で混ぜたゲートを使う)、指標ごとの tower K〜tower 1 を経て予測 $O_{pred}\in\mathbb{R}^{1\times K}$ になります。専門家は1組を全指標で共有(協調)し、ゲートとtowerは指標ごとに分岐(分離) ——この「共有と分離の同居」が図の骨格で、以降の式(1)〜(6)はこの図の各矢印を定式化したものです。

土台はGoogleの Multi-gate Mixture-of-Experts(MMoE) です。MMoEではタスク $k$ の出力を、共有された専門家群 $F(x)$ をタスク専用ゲート $g_k$ で重み付けして得ます。

$$ \begin{equation} y_k = h_k\big(g_k(x) \odot F(x)\big) \end{equation} $$

ただしMMoEをそのまま時系列異常検知に持ち込むと、3つの壁にぶつかります。CADはこれらを各コンポーネントで解決しました。

  1. 入力・出力空間の不整合 → task-oriented特徴選択(3.1)
  2. 時間×指標間の複雑な依存の抽出 → 畳み込み専門家(3.2)
  3. 指標が多いとゲートが収束しない → p&sゲート(3.3)

順に中身を見ます。

3.1 task-oriented 特徴選択

通常のMMoEは、ゲートが全入力を見て専門家の重みを決めます(各入力次元がタスクに等しく重要という前提)。しかし時系列異常検知では、指標 $k$ が異常かを判定するのに、他指標すべての履歴が自分の履歴と同じだけ重要、とは限りません。指標が多いほど、無関係な情報がゲートを撹乱します。

そこでCADは入力を指標レベルで分離します。まず、$M$ 個の専門家は全指標の窓 $w_t$ を入力に取り、その出力を並べて候補集合 $E$ を作ります。

$$ \begin{equation} E^{(t)}(w_t) = [\,f_1(w_t),\ f_2(w_t),\ \dots,\ f_M(w_t)\,] \end{equation} $$

ここで $f_i$ は $i$ 番目の専門家ネットワーク(3.2)です。次に、指標 $k$ 用のゲート $G_k$ は 自分の指標の窓 $w_t^k$ だけを見て専門家の重みを決め、候補集合を融合します。

$$ \begin{equation} B^{(t,k)} = G_k(w_t^k) \odot E^{(t)}(w_t) \end{equation} $$

最後に、指標 $k$ 専用の tower がこの融合表現から予測値を出します。

$$ \begin{equation} \hat{y}_k^{(t)} = \mathrm{Tower}_k\big(B^{(t,k)}\big) \end{equation} $$

骨子はここに集約されます——専門家は全指標を見て指標間依存を捉えるが、「どの専門家をどれだけ使うか」は指標ごとに自分の窓だけで決める。これにより、ある指標のBD&ISFが別の指標の判定経路に混入しません。

3.2 専門家ネットワーク(畳み込み)

各専門家は、1つの畳み込み層+2つの全結合層でできています。RNN/LSTM/GRUでなく畳み込みを使うのは、並列計算が速く、カーネルが連続区間の変化を鋭く捉えられるためです。

専門家ネットワークのConv構造

論文の専門家ネットワークの図はこうです。

CAD論文Fig.3 専門家ネットワーク

出典: Si et al., CAD, ESEC/FSE 2023, Fig.3 (arXiv:2308.08915, CC BY 4.0)

左の全 $K$ 指標の窓に対し、$n$ 個($=N$)のカーネルでCNNをかけ(各指標の窓→1値)、得た $N\times1\times K$ を flatten して2層のFeed Forwardに通し、1つの埋め込みを作ります。1個の専門家が「時間方向の畳み込み(指標内)」と「フィルタ共有による指標間依存」の両方を1パスで捉えている点が読み取れます。

畳み込み層は、幅 $l$(=窓長)・高さ1 のカーネルを $N$ 個持ちます。カーネルが全 $K$ 指標を含む窓 $w_t$ を走査すると、各指標の窓が1つの値に畳み込まれ、層の出力は $N \times 1 \times K$ のベクトルになります。

  • 時間依存: 各指標の窓を1値に畳む(指標内の時間方向)
  • 指標間依存: $N$ 個のフィルタを全指標で共有する(指標をまたぐ)

この出力を平坦化し、2層の全結合に通して埋め込みを得ます。$M$ 個の専門家の埋め込みが、式(1)の候補集合 $E$ を構成します。

3.3 personalized & shared (p&s) ゲート

ゲートは、選んだ入力を「候補集合の各埋め込みへの重み」に写します。CADの核心が、2種類のゲートを混ぜることです。

$$ \begin{equation} G_s(w_t^k) = W_s\, w_t^k, \qquad G_p^k(w_t^k) = W_{pk}\, w_t^k \end{equation} $$

$$ \begin{equation} G_k(w_t^k) = \mathrm{softmax}\big(\varepsilon \cdot G_s + (1-\varepsilon)\cdot G_p^k\big), \qquad \varepsilon > 0.5 \end{equation} $$

  • 共有ゲート $G_s$(重み行列 $W_s$ は全指標で共通): より多くのデータから頑健な対応関係を学び、専門家を支配的な特徴へ収束させる。
  • 個別ゲート $G_p^k$(重み行列 $W_{pk}$ は指標ごと): 指標間の微妙な差を調整する補助役。

なぜ混ぜるのか。指標が大量にあると、すべてを対等な個別ゲートだけで処理すると、専門家へ流れる逆伝播勾配が混乱し、パラメータ更新が振動して収束しません。そこで共有ゲートを大きめ($\varepsilon>0.5$)に効かせて学習を安定させ、個別ゲートで各指標の個性を微調整します。これが、個別ゲートだけのバニラMMoEが時系列で失敗する点を補う仕組みです。個別ゲートは同時に、専門家が「みな同じことを学ぶ」崩壊(expert collapse)も防ぎます。

3.4 tower と損失=異常スコア

tower は、融合埋め込み $B^{(t,k)}$ を1つの予測値に集約します。2つの全結合層+ReLU+ドロップアウトという構成です。全指標の予測 $\hat{\mathbf{y}}_t$ と真の観測 $\mathbf{y}_t$ の二乗L2ノルムが学習目標です。

$$ \begin{equation} \mathcal{L} = \|\mathbf{y}_t – \hat{\mathbf{y}}_t\|_2^2 = \frac{1}{K}\sum_{k=1}^{K}\big(y_k^{(t)} – \hat{y}_k^{(t)}\big)^2 \end{equation} $$

重要なのは、この $\mathcal{L}$ が推論時の異常スコアそのものだという点です。予測が外れた(再構成できない)時刻ほどスコアが高く、しきい値を超えれば異常と判定します。

なお、指標ごとに損失の大きさが違うと一部の指標が無視されるため、CADは別の損失重み調整は行わず、前処理(MinMaxスケーラで全指標を同程度のレンジに正規化) で各指標の損失を揃えています。

ゲートは本当に指標ごとに選び分けるのか

ここまでの仕組み——ゲート $G_k$ が指標ごとに専門家を重み付けする——が実際に機能しているかは、論文のケーススタディで確認できます。

CAD論文Fig.4 ゲートのケーススタディ

出典: Si et al., CAD, ESEC/FSE 2023, Fig.4 (arXiv:2308.08915, CC BY 4.0)

上段(a)は複数指標の生波形で、各指標の異常区間が赤でハイライトされています。波形のスケールも変動の質も指標ごとにバラバラなことが分かります。下段(b)は各指標のCADの異常スコアで、赤の点線が判定しきい値です。指標ごとにスコアの基準線(平常時の高さ)が違う——つまりゲートが指標ごとに専門家の組み合わせを切り替え、その指標固有のパターンに合わせた予測器を組み立てている証拠です。安定指標では平常時スコアが低く保たれ、BD&ISFを持つ指標では基準が引き上げられて正常な揺らぎを誤検出していません。

この「専門家の選び分け」を専門家側から見ると、各専門家が異なる特徴領域を担当していることが分かります。

CAD論文Fig.7 専門家の埋め込み分布

出典: Si et al., CAD, ESEC/FSE 2023, Fig.7 (arXiv:2308.08915, CC BY 4.0)

5つの専門家が出力する高次元埋め込みをt-SNEで2次元に落としたもので、色が専門家の番号です。専門家ごとに埋め込みが綺麗に分かれて固まっており、各専門家が異なる種類の時間パターンを担当していることを示します。仮にすべての専門家が同じことを学ぶ崩壊(expert collapse)が起きていれば、色は混ざり合って分離しません。p&sゲートの個別ゲートが崩壊を防ぎ、専門家が役割分担できていることの裏付けです。

共有モデルとの対比

ここまでの骨子を、従来の共有モデルと並べると違いが鮮明です。

共有モデルとMMoEの比較

従来は1つの網で全指標を予測するため、衝突する目標が同じパラメータを奪い合います。CADは専門家群を共有しつつ、指標ごとに専門家の重み付け(ゲート)と出力経路(tower)を分けることで、協調(専門家の共有)と分離(ゲート・towerの個別化)を両立させています。

評価

CADは3つの公開データセットで評価されました。

データセット エンティティ 指標(次元) 訓練長 テスト長 異常率
SMD 28 38 708,405 708,420 4.16%
SWaT 1 51 495,000 449,919 11.98%
WADI 1 123 784,517 172,801 5.77%

ベースラインは LSTM-NDT・DAGMM・MAD-GAN・OmniAnomaly・Interfusion・USAD・TranAD・DVGCRN。評価は point-adjust と k-th point-adjust の best-F1 です。CADは3データセット平均でF1スコア 0.943 を達成しました(point-adjust best-F1で 4.3%〜37.9% の改善)。

まとめ

CADのアーキテクチャを骨子から追いました。

  • task-oriented特徴選択(式1-3): 専門家は全指標の窓 $w_t$ を見るが、ゲート $G_k$ は自指標の窓 $w_t^k$ だけで専門家を重み付け
  • 畳み込み専門家(3.2): 幅 $l$・高さ1 のカーネル $N$ 個で $N\times1\times K$ を出力。時間依存(畳み込み)+指標間依存(フィルタ共有)
  • p&sゲート(式4-5): 共有ゲート($\varepsilon>0.5$で安定収束)+個別ゲート(個性調整・崩壊防止)
  • tower+損失(式6): 2層FC+ReLU+ドロップアウトで予測、MSEが学習目標かつ異常スコア

「全部を1つの網で」から「専門家は共有し、ゲートとtowerは指標ごとに分ける」へ。CADは、指標間の目標衝突をアーキテクチャで隔離する明快な設計です。コードは github.com/dawnvince/MTS_CAD で公開されています。

Bi-Attention × Mixture-of-Experts による多変量時系列の異常検知
MoEのgating/負荷分散を実装で。CADと合わせて読むと理解が深まる。
時系列異常検知の深掘りサーベイ
手法分類と評価の落とし穴(point-adjust/VUS)。

参考文献

  • H. Si, C. Pei, Z. Li, Y. Zhao ら. “Beyond Sharing: Conflict-Aware Multivariate Time Series Anomaly Detection.” ESEC/FSE 2023 (arXiv:2308.08915). コード: github.com/dawnvince/MTS_CAD
  • J. Ma ら. “Modeling Task Relationships in Multi-task Learning with Multi-gate Mixture-of-Experts (MMoE).” KDD 2018