局所的には正しいのに、全体としておかしい。
その矛盾を、構造として捉える。
はじめに
「層理論で不正検知ができる」と聞いたら、こう思いませんか?
「層って数学の専門用語じゃん。圏論とか出てくるんでしょ? 自分には無理…」
実は そんなに難しくありません。中身は 行列の引き算と転置 です。
数学的に専門的な議論をすると、背後には層・コホモロジー・制限写像といった高度な抽象数学の理論(微分幾何学や代数幾何学の理論)がありますが、この記事は入門向けなので、数学的な深い背景の議論は省略して、行列計算として実装できるPythonコードの解説と、概念を直感的に理解できるわかりやすい解説に集中します。
この記事では、高校で習った行列(忘れかけてても OK)から始めて、専門用語を ひとつずつ噛み砕きながら 紹介します。コードは全部 NumPy + SciPy で動きます。
この記事の核心 ─ 1 枚図で先に見せる
詳しい解説に入る前に、本記事のメッセージを 1 枚で示します。
用語の補足(画像内の言葉について)
-
大域切断 (global section):全ての辺で完全に整合している状態のデータの並びのこと。$\delta\mathbf{x} = \mathbf{0}$ となる $\mathbf{x}$ を指します。詳しくは第 5.4 節で解説します。
-
整合性半径 $\rho(\mathbf{x})$:データが大域切断からどれだけ離れているかを測る非負の数値。0 なら完全に整合、大きいほど不整合が深刻。
- コバウンダリ作用素 ($\delta$):辺ごとに「両端の翻訳結果の差」を計算する行列。画像内の「共境界演算子」と同じ意味です。
要するに本記事でやるのは:
- 各ノードに値を割り当てる(=切断)
- 辺ごとに「翻訳のルール」を持たせる(=制限写像)
- 全辺の不一致度を 1 つの数値に集約する(=整合性半径)
- その数値を見て、不整合のあるノード・辺を特定する
これだけです。あとは具体例とコードで、ひとつずつ追っていきます。
30 秒で読みたい方向けのサマリー
-
何ができるか:
① 銀行の不正口座
② サプライチェーンの売上水増し
③ マイクロサービスの障害
④ 故障センサー
→ どれも、「辺で結ばれた両端の値が一致しない場所」 を検出する問題で、Sheaf の枠組みで統一的に解ける
-
どう書くか:
NumPy + SciPy で疎行列を組むだけ。
L_F = δ.T @ δ($L_F = δ.T @ δ$) が層ラプラシアン
-
何が新しいか:
単なるグラフラプラシアンと違い、辺ごとに違う「翻訳のルール」を持てる ─ だから単位が違うセンサー、業務制約が違うノード同士でも整合性を測れる
詳しくは本文で、高校数学レベルから順を追って解説します。
「グラフラプラシアン」って何?(知らなくても OK)
簡単に言うと、ネットワーク上で「自分と隣の値の差」を計算する行列です。例えば「自分の温度 - 隣の温度」を全ノード分まとめて計算できます。詳しくは第 3 部で、行列の中身から丁寧に解説します。
この記事のゴール
- Sheaf 理論の 正式な数学用語(セルラー層、ストーク、制限写像、コバウンダリ作用素、整合性半径、切断、大域切断、核 (kernel)、整合性フィルトレーションなど)を、ひとつひとつ高校数学レベルから噛み砕いて理解する
- NumPy のコードと並べながら、各概念が実装で何に対応するかを把握する
- 動く 4 つのケーススタディ(銀行不正、サプライチェーン、マイクロサービス、センサー融合)を体験する
- 「ゆるい実装」と「数学的に厳密な実装」の違いを正しく理解する
前提知識
これだけあれば読めます:
- Python の基本(変数、関数、ループ、リスト)
- NumPy で行列を扱った経験(
np.array、.shape) - 高校レベルの行列の足し算・引き算(完全に忘れててもこの記事で復習します)
これは 不要 です:
- 大学の線形代数の知識(固有値分解、ランク等)
- 圏論、代数幾何、位相幾何学の知識
- PyTorch / TensorFlow
本記事の数学的な立ち位置について
Sheaf 理論(sheaf theory)は本来、代数幾何学・位相幾何学で発展した深い数学です。本記事は 教育目的 で、機械学習エンジニアが理解しやすいよう、最も基本的なケース(セルラー層と層ラプラシアン)に限定 して解説しています。
また、本記事の実装は Sheaf 理論の厳密な数学的定式化を、実用上の簡略化を加えた "Sheaf-inspired"(Sheaf 理論にインスパイアされた)アプローチ として位置づけています。簡略化の各箇所は本文中で明示します。
正式な数学的定義を厳密に追いたい方は、Hansen & Ghrist「Toward a Spectral Theory of Cellular Sheaves」(JACT, 2019)、Robinson「Sheaves are the canonical data structure for sensor integration」(Information Fusion, 2017) などの原典をご参照ください。
第1部:そもそも何の話?
1.1 解決したい問題
世の中のデータ分析でよくあるのが、こういう問題です:
複数の場所で記録された数値が、本当は一致するはずなのに、一致しない。なぜか? 誰のせいか?
例:
-
銀行のハブ口座:
お金が入ってきた量と出ていった量は、本当は釣り合うはず
→ 釣り合わない口座は不正の疑い
-
サプライチェーン:
A社から B社への出荷量と、B社が記録した A社からの仕入れ量は、本当は同じはず
→ 違っていたらどちらかが嘘の申告
-
マイクロサービス:
呼び出し元のサービスのレイテンシと、呼び出し先のサービスのレイテンシは、本当は連動しているはず
→ 連動していなかったら障害発生中
-
複数のセンサー:
同じ部屋を測っている温度計は、単位を揃えれば全部同じ値のはず
→ 1 つだけ違う値ならそのセンサーが故障
これらは全部 同じ構造の問題 です。「本当は一致するはずの数値が、グラフ(ネットワーク)上で一致するか?」をチェックしたい。
1.2 グラフって何?
「グラフ (graph)」と言っても、棒グラフや折れ線グラフのことではありません。点と線でつながったネットワーク図 のことを、数学やコンピュータサイエンスでは「グラフ」と呼びます。
- 点を「ノード (node)」または「頂点 (vertex)」と呼ぶ
- 線を「辺 (edge)」または「エッジ」と呼ぶ
例:銀行の取引グラフでは、口座がノードで、送金が辺。SNS では、人がノードで、友達関係が辺。
1.3 数学的な「整合性」とは
各ノードに何かしらの数値(またはベクトル)が割り当てられているとします。「整合性 (consistency) が取れている」とは:
辺で結ばれた両端のノードの値が、何らかのルールに従って対応している状態
例えば「両端の値が等しい」というルールなら、すべての辺で両端の値が等しいときに整合性が取れている、と言います。
整合性が取れていない辺があれば、その辺の 不一致度 を測れます。不一致度を全部足し上げて、「全体として、このネットワーク上のデータはどれだけ食い違っているか」を1つの数値で表したい。これが本記事のメインテーマです。
1.4 このあと出てくる結果のチラ見せ
理論パート(第 2〜5 部)に入る前に、この記事のゴールを先に見せておきます。
第 6 部以降で実際に動かすコードでは、次のような結果が得られます:
-
銀行不正検知:
30 口座のうち、埋め込まれた 不正口座 3 件を上位 3 位として完璧に検出(整合性半径 ρ = 923.75)
-
サプライチェーン監査:
売上を 1.5 倍に水増し申告した不正企業 parts_C を、寄与度 117.74 で他社の 2 倍以上の差をつけて特定
-
マイクロサービス障害:
6 サービス中で障害を起こした payment を、寄与度 726 で根本原因として特定(他のサービスの 3 倍以上)
-
多センサー融合:
摂氏・華氏・絶対温度の 4 センサーのうち、故障している sensor_D を 4 倍以上の寄与度で特定
実装はすべて NumPy + SciPy のみ。数式は全部「行列の引き算と転置」だけ で書けます。
急ぐ方は先に第 6 部の実行結果から眺めても OK です。理論を後で振り返るスタイルでも、本記事は読めるように書いてあります。
ただし、「ゆるい実装」と「数学的に厳密な実装」の違いを理解するには、第 5 部までの理論パートが必要です。
第2部:行列の復習(5 分)
この章は軽く流して OK です。覚えていれば飛ばして第 3 部へ。完全に忘れている方でも、5 分で必要最低限を取り戻せます。
2.1 ベクトルと行列
ベクトル: 数値を縦または横に並べたもの。例:
\mathbf{x} = \begin{pmatrix} 3 \\ 1 \\ 4 \end{pmatrix}
import numpy as np
x = np.array([3, 1, 4])
print(x.shape) # (3,) ← 3次元のベクトル
行列: 数値を縦横に並べた表のようなもの。例:
A = \begin{pmatrix} 1 & 2 \\ 3 & 4 \end{pmatrix}
A = np.array([[1, 2], [3, 4]])
print(A.shape) # (2, 2) ← 2行2列の行列
2.2 行列の引き算
行列同士の引き算は、同じ位置の数字同士を引く だけです。
a = np.array([5, 7])
b = np.array([2, 3])
print(a - b) # [3 4]
2.3 行列の掛け算と Python の @ 記号
ここが本記事で一番大事なポイントです。
行列の掛け算は、足し算や引き算と違って、ちょっと面倒です。「同じ位置の数字同士を掛けるのではなく、行と列の内積を取る」と覚えてください。
行列 $A$(2 行 3 列)とベクトル $\mathbf{x}$(3 次元)の掛け算 $A\mathbf{x}$ は、こう計算します:
A = \begin{pmatrix} 1 & 0 & 2 \\ 0 & 3 & 0 \end{pmatrix}, \quad \mathbf{x} = \begin{pmatrix} 5 \\ 6 \\ 7 \end{pmatrix}
A\mathbf{x} = \begin{pmatrix} 1 \cdot 5 + 0 \cdot 6 + 2 \cdot 7 \\ 0 \cdot 5 + 3 \cdot 6 + 0 \cdot 7 \end{pmatrix} = \begin{pmatrix} 19 \\ 18 \end{pmatrix}
Python では @ 記号 を使います:
A = np.array([[1, 0, 2],
[0, 3, 0]])
x = np.array([5, 6, 7])
print(A @ x) # [19 18]
重要:NumPy では * は 要素ごとの掛け算(同じ位置の数字を掛ける)で、@ が 行列の積(行列どうしの正式な掛け算)です。混同すると致命的なバグになります。
A * B # 要素ごとに掛け算(同じ形である必要)
A @ B # 行列としての掛け算
2.4 転置
行列を「斜めに反転」する操作を 転置 (transpose) と呼び、$A^\top$ と書きます。
A = \begin{pmatrix} 1 & 2 & 3 \\ 4 & 5 & 6 \end{pmatrix}, \quad A^\top = \begin{pmatrix} 1 & 4 \\ 2 & 5 \\ 3 & 6 \end{pmatrix}
A = np.array([[1, 2, 3], [4, 5, 6]])
print(A.T)
2.5 ベクトルの長さ ─ ノルム
ベクトルの「長さ」を ノルム (norm) と呼び、$|\mathbf{x}|$ と書きます。中学で習った三平方の定理($\sqrt{a^2 + b^2}$)の一般化です。
ノルムには種類があります。本記事では特に L2 ノルム と L1 ノルム という 2 つを区別します。
L2 ノルム(ユークリッドノルム)
各成分を 二乗 して、合計して、ルートを取る。
\|\mathbf{x}\|_2 = \sqrt{x_1^2 + x_2^2 + \cdots + x_n^2}
「L2」の「2」は、各成分を 2 乗 することから来ています。
x = np.array([3, 4])
print(np.linalg.norm(x)) # 5.0 ← √(9+16) = √25 = 5
これは中学で習った三平方の定理そのものです。$\mathbf{x} = (3, 4)$ のベクトルの長さが 5、というよく見るやつです。
L1 ノルム(マンハッタン距離)
各成分の 絶対値 を合計する。
\|\mathbf{x}\|_1 = |x_1| + |x_2| + \cdots + |x_n|
「L1」の「1」は、絶対値が「1 乗(つまりそのまま)」であることから来ています。
x = np.array([3, 4])
print(np.sum(np.abs(x))) # 7 ← 3 + 4
「碁盤の目状の街(マンハッタン)で、ある地点から別の地点まで歩く最短距離」と思ってください。斜めには進めないので、縦と横の移動距離の合計になります。
この記事ではどっちが出てくるか
主に L2 ノルム が出てきます。層ラプラシアンから自然に出る量が L2 ノルムだからです。
ノルムの 二乗 は、自分自身との内積に等しい:
\|\mathbf{x}\|_2^2 = \mathbf{x}^\top \mathbf{x}
print(x @ x) # 25
この公式は後でとても重要になります。
これだけです。これさえ思い出せば、本記事で出てくる数式は全部読めます。
第3部:ラプラシアンとは何か?
ここからが本題の入口です。「ラプラシアン」という名前にひるまず、行列の正体を見ていきます。
「ラプラシアン (Laplacian)」は数学で出てくる用語ですが、ここでは「隣同士の差」を表す行列、と覚えてください。
3.1 拡散(ディフュージョン)とは
ホットコーヒーをカップに注ぐと、しばらくして冷めますね。これは熱が 温度の高いところから低いところへ移動する からです。
このように「ある物理量が、勾配に沿って広がっていく現象」を 拡散 (diffusion) と言います。日本語ではそのままカタカナで「ディフュージョン」とも書きます。
ネットワーク上でも同じことが起こります。あるノードが「噂」を持っているとして、隣のノードに少しずつ伝わっていく ─ これも拡散です。
拡散をモデル化するときに必ず登場するのが ラプラシアン という行列です。
3.2 グラフラプラシアンの正体
グラフラプラシアン (graph Laplacian) $L$ は、ネットワーク上で「自分と隣の差を計算する装置」です。
ノード $v$ の値を $x_v$ とすると、$L\mathbf{x}$ の $v$ 番目の成分はこうなります:
(L\mathbf{x})_v = \sum_{u \sim v} (x_v - x_u)
ここで $u \sim v$ は「ノード $u$ と $v$ が辺でつながっている」という意味です。要するに、自分の値から、隣のノードたちの値を全部引き算して足したもの。
具体例で見ましょう。3 つのノード A, B, C が辺でつながっている(A-B, B-C)とします。
A --- B --- C
各ノードの値が x = [3, 5, 8] だったら:
- A の隣は B のみ。$(L\mathbf{x})_A = 3 - 5 = -2$
- B の隣は A と C。$(L\mathbf{x})_B = (5 - 3) + (5 - 8) = -1$
- C の隣は B のみ。$(L\mathbf{x})_C = 8 - 5 = 3$
これを 行列とベクトルの掛け算 1 回 で計算できるように整理してみます。グラフラプラシアン $L$ の各成分は、次のルールで決まります:
| 行列の位置 | 値 | 意味 |
|---|---|---|
| 対角成分 $L_{vv}$(自分と自分) | ノード $v$ の 次数 | 辺で繋がっている隣の数 |
| 非対角成分 $L_{vu}$(自分と隣) | -1 | $v$ と $u$ が辺で繋がっているとき |
| 非対角成分 $L_{vu}$(自分と非隣) | 0 | $v$ と $u$ が辺で繋がっていないとき |
このルールに従って 3 ノード A, B, C(辺は A-B, B-C)の行列を書くと:
L = np.array([
[ 1, -1, 0], # A の行: x_A を 1 回足し、x_B を 1 回引く(隣は B だけ)
[-1, 2, -1], # B の行: x_B を 2 回足し、x_A と x_C を 1 回ずつ引く(隣は A と C)
[ 0, -1, 1], # C の行: x_C を 1 回足し、x_B を 1 回引く(隣は B だけ)
])
x = np.array([3, 5, 8])
print(L @ x) # [-2 -1 3]
なぜこの行列で「自分と隣の差の総和」が出るのか?
各行は 「自分と隣の差を計算するレシピ」 になっています。B の行 $[-1, 2, -1]$ をベクトル $[x_A, x_B, x_C]$ に掛けると:
-x_A + 2x_B - x_C = (x_B - x_A) + (x_B - x_C)
真ん中の $2$ は 隣の数($x_B$ を隣の数だけ用意)、両側の $-1$ が その隣を引く 役割。これで「B と各隣の差の和」がそのまま出ます。A の行 $[1, -1, 0]$ も同じで、隣は B だけだから $x_A - x_B$ が出ます。
形式的には $L = D - A$ と書きます:
- 次数行列 $D$:対角に各ノードの次数を並べた行列。本例なら $D = \text{diag}(1, 2, 1)$
- 隣接行列 $A$:辺で繋がっていれば 1、繋がっていなければ 0(対角は 0)
- $L = D - A$:対角が次数、非対角が −1(辺あり)または 0(辺なし)になる
これが グラフラプラシアン です。
3.3 全体の不一致度を 1 つの数値にまとめる
$L\mathbf{x}$ はベクトル(各ノードでの差の総和)ですが、ネットワーク全体の不一致度を 1 つの数値にまとめたい ことがあります。
そのときは $\mathbf{x}^\top L \mathbf{x}$(これを 二次形式 (quadratic form) と呼びます)を計算します:
\mathbf{x}^\top L \mathbf{x} = \sum_{(u, v) \in E} (x_v - x_u)^2
これは 全ての辺について「両端の差の二乗」を足し合わせた量 です。「ネットワーク全体のばらつき度」を表す 1 つの数値。
result = x @ L @ x
print(result) # 13 = (3-5)² + (5-8)² = 4 + 9 = 13
これが小さいほど、ネットワーク全体で値が揃っている、ということになります。
3.4 層理論は実務でどう使われているか
ここまで読んで「Sheaf 理論って数学の遊びでしょ?」と思った方に、ちょっと待ってください。本記事の先で扱う層理論は、実は 欧米の銀行・防衛機関・宇宙機関で本番運用されている本物の道具 です。第4部以降の数学を読む前に、産業界・政府機関での実装事例を一望しておきましょう。
主要な実装事例(Web 公開情報で確認できた範囲)
| 組織・実装 | 拠点 | 用途 | 技術 | 規模感 |
|---|---|---|---|---|
| Conexus AI / CQL | 🇺🇸 米国 | データ統合・不整合検知 | 圏論 + 定理証明 (Java) | 米Top-10銀行、NASA、米国防総省で本番運用。Synchrony Financial で従来見えなかった 800 万米ドル相当のデータ依存性を発見 |
| Robinson 研 (American University) / PySheaf | 🇺🇸 米国 | センサー融合・不整合局所化 | 細胞層・整合性半径 (Python) | DARPA SIMPLEX、ONR、AFRL、PNNL が支援。クロクマ追跡実験で実証(Sensors 誌 2020)、BAE Systems と協働で DARPA SafeDocs |
| Twitter/X 研究 / Neural Sheaf Diffusion | 🇺🇸 米国 / 🇬🇧 英国 | ヘテロフィリー GNN | NSD 公式 PyTorch 実装 | NeurIPS 2022 発表(Bodnar et al., ケンブリッジ大 + Twitter)。学術ベンチマークで GCN を 5–20 ポイント上回る |
| Sapienza 大 + Twitter/X / Sheaf4Rec | 🇮🇹 イタリア / 🇬🇧 英国 | 推薦システム | $d \times d$ 制限写像を学習 (Python) | ACM TORS 2025 掲載(Purificato et al.) |
| AlgebraicJulia / Catlab.jl | 🇺🇸 米国 (Topos Institute) | 多エージェント協調 | 細胞層上の分散最適化 (Julia) | DARPA、ONR 支援。UAV/UUV 異種協調の論文系列 (Hanks-Riess 系 2024-2025) |
| MDPI Mathematics / PoR | 学術 (国際) | サプライチェーン整合性 | 整合性半径 (Python) | 2025 年 Mathematics 誌掲載(Pao et al.)、Proof of Relation として定式化 |
要するに、本記事の後半で書くコードと 同じ数学的枠組み が、米国の Top-10 銀行のマスターデータ管理、NASA のデータパイプライン、DARPA 支援のセンサー融合、Twitter/X の推薦システム研究で実装されています。
業界別に見ると、データ統合分野(MDM)では Java の CQL、不整合検知・センサー融合では Python の PySheaf、ヘテロフィリー GNN では Python の NSD 公式実装、多エージェント協調では Julia の AlgebraicJulia が主流です。本記事は読者に最も馴染みのある Python(NumPy + SciPy)で実装します。
これから第4部以降で学ぶ層ラプラシアン $L_\mathcal{F}$ や整合性半径 $\rho(\mathbf{x})$ は、上記の本番運用事例と同じ数学的対象です。「機械学習の論文で時々見かける流行りの手法」ではなく、10年以上にわたって産業界・政府機関で運用されてきた実績のある枠組み だと思ってお読みください。
なぜ米国の事例ばかりなのか?日本や中国の事例は?
ここまで読んで「事例が欧米ばかりじゃないか」と思った方もいるかもしれません。実際そのとおりで、本記事の調査では 日本・中国の事例は確認できませんでした。理由を整理しておきます。
Web 上で確認できた地域の偏り
| 地域 | 確認できた実例 |
|---|---|
| 🇺🇸 米国 | DARPA(SIMPLEX、SafeDocs)、ONR(海軍研究局)、AFRL(空軍研究所)、PNNL(エネルギー省)、NASA、米国防総省、Conexus AI が銀行・宇宙・防衛で運用 |
| 🇬🇧 英国 | ケンブリッジ大(Bodnar et al. の NSD)、Twitter/X 英国研究拠点 |
| 🇮🇹 イタリア | Sapienza 大(Sheaf4Rec)、Cambridge との共同研究 |
| 🇪🇺 EU | Horizon プログラムで応用圏論研究を一部支援(本記事の対象外) |
| 🇯🇵 日本 | 公開事例なし(AIST/理研/JAXA、銀行、大企業のいずれも) |
| 🇨🇳 中国 | 公開事例なし(公開情報が極めて限定的) |
| 🇰🇷 韓国・🇮🇳 インド・その他 | 公開事例なし |
米国偏重の構造的な理由
- 資金の出どころ:層理論の応用研究は DARPA・ONR・AFRL・PNNL が 10 年以上資金支援してきました。米国では「政府機関(主に国防系)が基礎研究を支援 → 民間企業(Conexus AI など)が商用化」というパイプラインが確立しています。
- 研究者の集中:Robinson(American University)、Ghrist(UPenn)、Spivak / Wisnesky(MIT 出身、現 Conexus AI)など中核となる研究者が米国に集中しています。
- オープン文化:米国の研究者・企業は技術詳細を論文・ブログ・ホワイトペーパーで積極的に公開する傾向があります。
日本・中国で「公開事例がない」ことの解釈
「公開事例がない = 使われていない」とは限りません。むしろ:
- 日本の大手銀行(三菱UFJ、SMBC、みずほ など)、大企業(NTT、富士通、NEC、日立など)は AI による不正検知システムを運用していますが、技術詳細はほぼ非公開です。層理論を使っていても外からは判別不可能です。
- 中国は AI 関連の技術公開がさらに限定的で、Web 検索の範囲では実態が見えません。
要するに、「Webサイト上の公開情報として開示されている情報は、米国・英国・イタリアの大企業・政府機関に関する情報に限られている」というのが実情であり、豪州・NZ・日本・中国・韓国・ロシア・インド・イスラエル・中近東諸国・アフリカ諸国・南米諸国の大企業及び政府機関については、「組織内部で使われている可能性は否定できないが、公開情報からは確認できない」 ということです。
本記事と上記事例の厳密さの違い
- 本記事のコード(第6部以降)は、教育目的で一部の数学的詳細を簡略化した Sheaf-inspired な実装です(具体的な簡略化箇所は第7部・第9部・第10部で明示します)。
- 上記の事例の中で 数学的に最も厳密なのは Conexus AI の CQL で、圏論ベース・コンパイル時定理証明まで備えています。
- 研究レベルの厳密さを持つのは Robinson 系の PySheaf と Twitter/X の NSD 公式実装です。これらの本格的な実装に進みたい方は、各リポジトリ (PySheaf, neural-sheaf-diffusion) を参照してください。
第4部:Sheaf(層)が登場する動機
ここが本記事の核心です。「なぜ Sheaf 理論が必要なのか?」「グラフラプラシアンでは何ができないのか?」をはっきりさせます。
4.1 グラフラプラシアンの限界
グラフラプラシアン $L$ には、暗黙の前提があります:
すべてのノードが「同じ単位・同じ意味」の数値を持っている
これが現実のデータでは成立しないのです。
例えば、3 つの温度センサーが同じ部屋を観測しているとします:
- センサー A:摂氏で「20」と報告
- センサー B:華氏で「68」と報告
- センサー C:絶対温度で「293.15」と報告
物理的には 3 つとも同じ温度を観測しています。でも数値は全然違います。素朴に $20 - 68 = -48$ を計算しても意味がありません。
つまり、比較する前に、同じ単位に変換する必要があります。この必要性を満たすのが、次に解説する複数の温度センサーが計測した数値どうしの「翻訳」作業です。
4.2 「翻訳のための行列」というアイデア
各辺に 翻訳のための行列 を持たせます。両端のノードの値を、辺の上で比較する前に、共通の単位に変換するための行列です。
数学の専門用語では、この翻訳行列のことを 制限写像 (restriction map) と呼びます。「写像 (map)」は「関数」とほぼ同じ意味で、ここでは「ベクトルを別のベクトルに変換するための行列の掛け算」と思ってください。
「制限写像」という名前は、Sheaf 理論で「ノード上のデータ(より広い場所のデータ)を、辺の上(より狭い場所)に『制限(=持ち越し)する』」という発想から来ています。
「制限」は「データを限定する」という意味ではなく、「ある場所のデータを、隣接する場所に持ち越す」という操作の名前として使われています。本記事では機能を強調して「翻訳のための行列」とも呼びますが、確立された数学用語は「制限写像」です。
辺の上で「両端が一致している」とは、こうなることです:
F_A x_A = F_B x_B
温度センサーの例で言えば:
- $F_A$ は摂氏から摂氏(変換不要)
- $F_B$ は華氏から摂氏($\times 5/9$ してから $-160/9$)
- $F_C$ は絶対温度から摂氏($-273.15$)
これらを通すと、20、20、20 になり一致します。
制限写像はハードコーディングだけではありません ─ 機械学習で自動更新する発展編
本記事では、温度センサーの単位変換($\times 5/9$ など)のように、制限写像を「業務知識から人間が設計する固定ルール」として解説します。直感的で理解しやすい一方、「実務では業務ルールが頻繁に変わるのに、毎回手で書き直すのか?」という疑問を持たれた方もいるかもしれません。
実は、制限写像をデータから自動学習する手法(Neural Sheaf Diffusion など)が NeurIPS 2022 で提案されており、機械学習モデルの推論でデータドリブンに制限写像を計算し、定期的に自動更新する設計が可能です。
詳細は本シリーズの別記事で解説しています:
GCNが見逃す不正を捕まえる ─ Neural Sheaf Diffusion で挑む不整合検知の実装ガイド
GCN がヘテロフィリーグラフ(マネーロンダリングのように不正者同士が繋がらないグラフ)で性能が出ない問題を、Neural Sheaf Diffusion で 20 ポイント差で克服する PyTorch 実装ガイド。
4.3 これが「Sheaf(層)」の核心
ここで本記事の中心概念を導入します。
Sheaf 理論の中でも本記事で扱うのは、セルラー層 (cellular sheaf) という最も基本的な構造です。グラフ(細胞複体の最も簡単なケース)の上で定義される層で、Hansen & Ghrist が体系的に研究しました。
セルラー層は次の 4 つの要素から成ります:
| 数学用語 | 意味(平易) |
|---|---|
| 節点ストーク (node stalk) $\mathcal{F}(v)$ | 各ノードの値が住んでいる空間(ベクトル空間) |
| 辺ストーク (edge stalk) $\mathcal{F}(e)$ | 各辺の上の「待ち合わせ部屋」(ベクトル空間) |
| 制限写像 (restriction map) $\mathcal{F}_{v \trianglelefteq e}$ | ノードのデータを辺の待ち合わせ部屋に翻訳する線形写像 |
| 層 (sheaf) $\mathcal{F}$ | 上記すべてを束ねたデータ構造 |
「ストーク (stalk)」は数学では「茎」と訳されることもありますが、機械学習論文ではカタカナ表記が一般的です。意味は「各ノード/各辺で値が住んでいる空間」と覚えてください。
「層 (sheaf)」という名前は数学の専門用語(代数幾何学・位相幾何学が起源)ですが、本記事のセルラー層の文脈では「ノードと辺に空間と翻訳行列を割り当てたデータ構造」と理解すれば十分です。
用語の整理(再掲)
- 層 (sheaf):本記事で扱う対象全体
- セルラー層 (cellular sheaf):グラフの上で定義される層(本記事で扱うのはこれ)
- ストーク (stalk):各ノード/各辺で値が住んでいる空間
- 制限写像 (restriction map):辺で両端を比較するときの 翻訳行列
聞き慣れない用語ですが、それぞれ「全体」「グラフ上の層」「空間」「翻訳行列」と置き換えてもらえば実装上は OK です。
第5部:層ラプラシアン
理論パートの最後です。これを読み終えれば数式はクリア、次は実装と結果(第 6 部)です。
5.1 コバウンダリ作用素 δ
各辺について「両端の特徴を翻訳して引き算する」操作を行列で書きます。これを コバウンダリ作用素 (coboundary operator) と呼び、$\delta$(デルタ)で書きます。
「コバウンダリ(coboundary)」を直訳すると「双対境界」になります。位相幾何学の深い背景を持つ用語で、数学的には豊かな意味があるのですが、本記事では「全ての辺で両端の翻訳結果の差を計算する装置」という機能だけ覚えれば十分です。
辺 $e = (u, v)$ について、
(\delta \mathbf{x})_e = F_v x_v - F_u x_u
これを全ての辺について並べたベクトルが $\delta \mathbf{x}$ です。全ての辺の不一致度を一気に計算できる。
実装:
import scipy.sparse as sp
# 辺の数だけ行を持つ疎行列 δ を作る
# 各辺 e=(u,v) について、行 e に
# 列 v に +F_v(=I の場合は +1)
# 列 u に -F_u(=I の場合は -1)
# を入れる
rows, cols, vals = [], [], []
for k, (u, v) in enumerate(edges):
rows.append(k); cols.append(v); vals.append(+1.0)
rows.append(k); cols.append(u); vals.append(-1.0)
delta = sp.csr_matrix((vals, (rows, cols)), shape=(n_edges, n_nodes))
5.2 層ラプラシアン
$\delta$ を使って 層ラプラシアン (sheaf Laplacian) を以下のように定義します:
L_\mathcal{F} = \delta^\top \delta
(右肩の $\top$ は転置、左肩の $\mathcal{F}$ は「層に関する」という意味)
これだけです。コードで書くと:
L_F = delta.T @ delta
この行列に意味があるのは、全体の不一致度を測れる からです。第 2.5 節の「ノルムの二乗 = 自分自身との内積」を使って計算してみると:
\mathbf{x}^\top L_\mathcal{F} \mathbf{x} = \mathbf{x}^\top (\delta^\top \delta) \mathbf{x} = (\delta \mathbf{x})^\top (\delta \mathbf{x}) = \|\delta \mathbf{x}\|_2^2
つまり「$\delta\mathbf{x}$ の L2 ノルムの二乗」、すなわち「全ての辺の不一致度の二乗の総和」になります。
5.3 整合性半径
この量の平方根を 整合性半径 (consistency radius) と呼び、$\rho(\mathbf{x})$ と書きます:
\rho(\mathbf{x}) = \sqrt{\mathbf{x}^\top L_\mathcal{F} \mathbf{x}} = \|\delta \mathbf{x}\|_2
0 なら全辺で完全に一致(整合)、大きいほど不整合 を意味します。これが本記事のメインの「検出量」です。
def consistency_radius(x, L_F):
"""整合性半径 ρ(x) = √(xᵀ L_F x)"""
quad = float(x @ (L_F @ x))
return np.sqrt(max(quad, 0.0)) # 数値誤差で負になるのを防ぐ
「半径」と呼ばれる理由は、次の節で詳しく解説します。これが本記事で最も大事な概念です。
5.4 「整合性半径」の幾何学的な意味 ─ ステップごとに丁寧に解説
ここからが本記事の山場です。「整合性半径」が何の「半径」なのかを、専門用語をひとつずつ噛み砕いて解説します。
ステップ 1:「整合した状態のデータ」を考える
いま、グラフのノードに値を割り当てた状態 $\mathbf{x}$ があります。
その中で、特に「全ての辺で両端の翻訳結果が一致する」ようなデータの並びを考えてみましょう。式で書くと:
\delta \mathbf{x} = \mathbf{0}
(全ての辺の不一致度がゼロ)
これは「ネットワーク上にデータが 完璧に整合した形で 配置されている状態」を意味します。
ステップ 2:「切断 (section)」とは何か
Sheaf 理論では、ノードに値が並んだ状態そのもの(整合しているか否かを問わず、各ノードに値を割り当てたデータの並び)を 切断 (section) または アサインメント (assignment) と呼びます。
切断 (section) = 各ノードに値を割り当てたデータの並び(=ベクトル $\mathbf{x}$ そのもの)
「切断」という名前は、英語の "section"(=「断面」「部分」)から来ています。「全体の中から切り出された一片のデータ」というイメージです。
例えば、3 つの口座 A、B、C に対して (in=100, out=80), (in=200, out=180), (in=50, out=50) という値を並べたら、これが 1 つの「切断」です。整合しているかどうかは別として、各ノードに値が割り当てられた状態すべてが「切断」と呼ばれます。
用語に関する注:本記事ではセルラー層(グラフ上の層)を扱っているので、「切断」は単に「各ノードに値を並べたベクトル $\mathbf{x}$」のことです。一般の Sheaf 理論ではより複雑な定義(局所切断・大域切断の区別など)がありますが、本記事のセルラー層では区別不要です。
ステップ 3:「大域 (global)」とは何か
「大域 (global)」とは、英語の "global" の訳で「全体にわたる」「ある一部分だけでなく、空間の全体で成立する」という意味です。対義語は「局所 (local)」(=部分的、限られた範囲での)。
例えば「大域的に整合している」と言ったら「ネットワークの全ての辺で整合している」という意味になります。
ステップ 4:「大域切断 (global section)」とは何か
ステップ 2 と 3 を組み合わせます。
大域切断 (global section) = ネットワーク全体で整合しているデータの並び
具体的には、$\delta\mathbf{x} = \mathbf{0}$ となる $\mathbf{x}$ のことです。「全ての辺で両端の翻訳結果が一致している」状態を表します。
例えば、3 つの温度センサー(摂氏、華氏、絶対温度)が同じ温度を観測していて、変換後にすべて 20 になる場合、(20, 68, 293.15) というベクトルは大域切断です。一方、センサー 1 つが故障して (20, 68, 300) と報告されたら、これは大域切断ではありません。
ステップ 5:「核 (kernel)」とは何か
数学では、ある行列 $A$ に対して、
A\mathbf{x} = \mathbf{0}
を満たすベクトル $\mathbf{x}$ の集まりを、$A$ の 核 (kernel) または 零空間 (null space) と呼び、$\ker(A)$ と書きます。カーネル とそのままカタカナで呼ばれることもあります(機械学習で「カーネル法」と呼ばれるカーネルとは別の概念なので、混同しないように注意してください。本記事では文脈を明確にするため「核」を主に使います)。
「核」と呼ばれる理由は、「行列 $A$ の作用で ゼロにつぶされる ベクトルたち」が、ある意味で行列の中心(核)を成しているからです。
セルラー層の場合、コバウンダリ作用素 $\delta$ の核 ─ つまり $\delta\mathbf{x} = \mathbf{0}$ となる $\mathbf{x}$ の集まり ─ が、まさにステップ 4 の 大域切断の集合 に等しくなります:
\{\mathbf{x} : \delta\mathbf{x} = \mathbf{0}\} = \ker(\delta) = \text{大域切断の集合}
ステップ 6:整合性半径と大域切断の関係
ここで本題です。整合性半径 $\rho(\mathbf{x})$ の重要な性質を整理します:
-
$\rho(\mathbf{x}) = 0$ ⇔ $\mathbf{x}$ は大域切断
なぜなら、$\rho(\mathbf{x}) = |\delta\mathbf{x}|_2 = 0$ は $\delta\mathbf{x} = \mathbf{0}$ と同じことだから。 -
$\rho(\mathbf{x})$ が大きいほど、$\mathbf{x}$ は大域切断から離れている
$\delta\mathbf{x}$ が大きい(全ての辺の不一致度が大きい)ほど、整合した状態から外れている。 -
$\rho(\mathbf{x}) > 0$ は、$\mathbf{x}$ が大域切断であることへの「妨害」を表す
イメージで言えば、「あるデータ点 $\mathbf{x}$」と「整合した状態の集まり(大域切断の集合)」があって、$\rho(\mathbf{x})$ は両者の 離れ具合 を測る非負の数値です。
正確には:整合性半径は「全ての辺で見た不一致度を L2 ノルムで集約した量」であり、Robinson (2018) の用語では「大域切断であることへの妨害 (obstruction)」と呼ばれます。
「最短距離」のような幾何学的解釈は、$\delta$ の構造によっては成り立つ場合もありますが、一般のセルラー層では厳密には成立しないことがあります。本記事では「整合した状態(大域切断)からの離れ具合」という直感的な意味で扱います。
ステップ 7:「半径」と呼ばれる理由
「半径」という名前は、整合した状態の集合(大域切断の集合)を「中心」とみなしたとき、$\rho(\mathbf{x})$ が「$\mathbf{x}$ がその中心からどれだけ外にあるか」を測る半径のような量だからです。
円の中心が「整合した状態」、半径が「ずれの大きさ」、というイメージで OK です。
ステップ 8:まとめ
整合性半径 $\rho(\mathbf{x})$ の意味:
| 状態 | 意味 |
|---|---|
| $\rho(\mathbf{x}) = 0$ | $\mathbf{x}$ は大域切断(=完全に整合した状態) |
| $\rho(\mathbf{x}) > 0$ | $\mathbf{x}$ は大域切断ではなく、整合性が崩れている |
| $\rho(\mathbf{x})$ が大きい | 大域切断から大きく離れている(=不整合が深刻) |
ここまでの数式まとめ
- $\delta$:コバウンダリ作用素(辺ごとに翻訳して引き算する行列)
- $L_\mathcal{F} = \delta^\top \delta$:層ラプラシアン
- $\rho(\mathbf{x}) = \sqrt{\mathbf{x}^\top L_\mathcal{F} \mathbf{x}}$:整合性半径(全辺の不一致度の L2 ノルム)
- $\ker(\delta) = {\mathbf{x} : \delta\mathbf{x} = \mathbf{0}}$:大域切断の集合(= $\delta$ の核)
- 整合性半径は 大域切断からの離れ具合 を表す非負の数値(0 なら完全に整合、大きいほど不整合)
第6部:実際に動かしてみる(まず結果を見る) ─ 銀行不正検知(ゆるい版)
お待たせしました、実装パートです。ここからは Python コードを動かして、実際に不正口座を検出します。
6.1 やりたいこと
取引グラフから、マネーロンダリング疑いのハブ口座(中継口座だが入金と出金が釣り合わない)を検出します。
6.2 業務上のルール
ハブ口座(取引数の多い中継口座)は、業務論理として:
- 正常なハブ:入金 ≈ 出金(顧客の一時預かり)
- 不正口座:入金 ≫ 出金(資金を「隠して」いる)
このルールを使って異常検知します。
6.3 サンプルデータ生成
30 口座のうち 3 口座を「不正口座」として埋め込みます。
注:本サンプルデータと実運用システムの差について
本記事のサンプルデータは 教育目的の合成データ で、不正口座のパターンを「入金が出金より明らかに多い」というシンプルな形に単純化しています。
実際のマネーロンダリングでは「層化 (layering)」と呼ばれる、複数の口座を経由して資金を分散・統合する複雑なパターンが取られます。
金融機関の本番 AML(マネーロンダリング対策)システムと、本記事のコードとの主な違い は以下のとおりです。
| 観点 | 本記事のコード | 金融機関の本番 AML システム(公開論文ベース) |
|---|---|---|
| データ規模 | 30 口座、合成データ | 数百万〜数十億ノード(例: Elliptic2 は 4900 万ノード、1.96 億辺) |
| 検出対象の構造 | 単一ハブ口座(1 ノード) | 部分グラフ (subgraph):層化を含む複数ノード経路全体を「不正の形 (shape)」として検出 |
| 時間軸 | 静的(時間情報なし) | 時系列 GNN(TGAT、Temporal GNN):取引タイムスタンプ・時間窓を考慮 |
| 特徴量 | 入金・出金 2 次元のみ | 各取引につき数百次元(取引額、頻度、KYC 区分、地理、デバイス、過去履歴など) |
| 学習方法 | 教師なし(整合性半径のみ) | 教師あり(過去ラベル付きデータ)+ 自己教師あり (Inspection-L 等) + ルールベース併用 |
| 主流アーキテクチャ | グラフラプラシアン由来の整合性半径 | GCN, GAT, GIN, GraphSAGE の組み合わせ、最近は 時間-周波数 GNN(ChronoWave-GNN 等)、部分グラフ GNN |
| クラス不均衡対策 | なし(均衡データ) | 不正は全体の 1% 以下のため、クラス重み付け、サンプリング、特殊な正規化 が必須 |
| 層理論との関係 | 整合性半径を直接スコアにする | 一部の研究では NSD などの層理論的 GNN が試行されているが、本番運用は GCN/GAT 系が主流 |
実装事例の典拠:
- Elliptic Bitcoin Dataset(AML 研究の標準ベンチマーク): https://www.kaggle.com/ellipticco/elliptic-data-set
- Elliptic2(より大規模、部分グラフ単位): https://arxiv.org/abs/2404.19109
- Inspection-L(自己教師あり GNN による AML): https://arxiv.org/abs/2203.10465
- ChronoWave-GNN(時間-周波数 GNN): Scientific Reports 2025
要するに、本記事は 「層理論的アプローチが何を計算しているか」を理解するための最小例 であり、本番システムは 時系列・部分グラフ・大規模・教師あり学習 を組み合わせた、根本的にスケールの異なる設計になります。
そこで、上の比較表の各観点(時系列・部分グラフ・大規模・教師あり学習・クラス不均衡など)を1本ずつ深堀りする連載シリーズを順次公開予定です。
本記事のコードはそのまま実運用には使えませんが、整合性半径の考え方(辺ごとの制約違反を集約する)は、本番システムの中の一要素として組み込む価値があります。
import numpy as np
import scipy.sparse as sp
def generate_transaction_graph(seed=42, n_accounts=30, n_fraudsters=3):
"""合成取引グラフ。3口座が不正(出金が入金の40%しかない)。"""
rng = np.random.default_rng(seed)
accounts = [f"acc_{i:03d}" for i in range(n_accounts)]
fraudster_ids = list(rng.choice(n_accounts, n_fraudsters, replace=False))
fraudsters = [accounts[i] for i in fraudster_ids]
normal_hub_ids = [i for i in range(n_accounts) if i not in fraudster_ids]
normal_hubs = list(rng.choice(normal_hub_ids, 5, replace=False))
transactions = []
# 正常ハブ: 入金 ≈ 出金 になる取引パターン
for hub_id in normal_hubs:
hub_acc = accounts[hub_id]
senders = rng.choice(
[i for i in range(n_accounts) if i != hub_id and i not in normal_hubs],
size=4, replace=False)
in_amounts = []
for sid in senders:
amt = rng.uniform(50, 150)
transactions.append((accounts[sid], hub_acc, amt))
in_amounts.append(amt)
total_in = sum(in_amounts)
receivers = rng.choice(
[i for i in range(n_accounts) if i != hub_id and i not in normal_hubs],
size=4, replace=False)
target_total = total_in * rng.uniform(0.95, 1.05)
for rid in receivers:
transactions.append((hub_acc, accounts[rid], target_total / 4))
# 不正口座: 入金多く、出金は40%のみ
for fid in fraudster_ids:
f_acc = accounts[fid]
senders = rng.choice(
[i for i in range(n_accounts) if i != fid], size=8, replace=False)
total_in = 0
for sid in senders:
amt = rng.uniform(50, 200)
transactions.append((accounts[sid], f_acc, amt))
total_in += amt
out_total = total_in * 0.4
receivers = rng.choice(
[i for i in range(n_accounts) if i != fid], size=4, replace=False)
for rid in receivers:
transactions.append((f_acc, accounts[rid], out_total / 4))
# ノイズ用の少量取引
for _ in range(20):
u, v = rng.choice(n_accounts, 2, replace=False)
transactions.append((accounts[u], accounts[v], rng.uniform(5, 30)))
return accounts, transactions, fraudsters
6.4 検出コード(ゆるい版)
def detect_anomaly_score(accounts, transactions, hub_threshold=8):
"""各ハブ口座の (入金 - 出金) のアンバランス度を直接計算。"""
n = len(accounts)
name_idx = {a: i for i, a in enumerate(accounts)}
inflow = np.zeros(n)
outflow = np.zeros(n)
degree = np.zeros(n)
for src, tgt, amount in transactions:
outflow[name_idx[src]] += amount
inflow[name_idx[tgt]] += amount
degree[name_idx[src]] += 1
degree[name_idx[tgt]] += 1
scores = {}
for i, name in enumerate(accounts):
if degree[i] >= hub_threshold: # 個人顧客は除外
imbal = abs(inflow[i] - outflow[i])
denom = inflow[i] + outflow[i] + 1e-6
scores[name] = imbal / denom
return scores
6.5 実行結果
実際の不正口座: ['acc_019', 'acc_002', 'acc_022']
account imbalance 真の状態
acc_002 0.3184 不正 ← 検出
acc_022 0.2516 不正 ← 検出
acc_019 0.2242 不正 ← 検出
acc_029 0.1612 正常
...
[評価] 上位3口座のうち真の不正口座数: 3 / 3
3 つの不正口座を全て上位 3 位として正確に検出できました。
第7部:重要な告白 ─ ケース1 はじつは「ゆるい版」だった
ここから「数学的に厳密な実装」に進みます。第 6 部のコードと、本物の層ラプラシアンを使った実装の違いを、丁寧に説明します。
ここでひとつ、正直に告白します。
第 6 部で書いたコードは、層ラプラシアン $L_\mathcal{F}$ を陽に使っていません。
|inflow - outflow| / (inflow + outflow) というスコアを直接計算しただけで、$\delta$ も $L_\mathcal{F}$ も $\rho(\mathbf{x})$ も出てきていません。
なぜ「ゆるい版」と呼ぶのか、そして「厳密に層ラプラシアンを使った検出」との違いは何か、丁寧に解説します。
7.1 「特殊化」とは何か
数学では、「特殊化 (specialization)」という考え方があります。これは:
一般的な構造に、特殊な値や条件を入れることで、構造がもっと単純な形に化ける
例えば:
- 一般の二次方程式 $ax^2 + bx + c = 0$ → 二次の係数 $a$ がゼロという特殊化を入れると「一次方程式」になる
- 一般の長方形 → 縦と横が同じという特殊化を入れると「正方形」になる
- 一般のセルラー層 → 「全ストークが 1 次元、全制限写像が ±1」という特殊化を入れると「自明な層」になる
層ラプラシアンも、特殊な条件下では、もっと簡単な行列(通常のグラフラプラシアン)に化けます。これを次の節で見ます。
7.2 制限写像が「単位行列」のときに起きること
単位行列 (identity matrix) $I$ とは、対角線が全部 1、それ以外が 0 の行列です。これは「何もしない翻訳行列」で、$I \mathbf{x} = \mathbf{x}$ となります。
**ノードのストークが 1 次元(各ノードがスカラー値を持つ)**で、全ての辺について、両端の制限写像が +1 と -1(向きを揃えるための符号規約)の場合、層ラプラシアン $L_\mathcal{F}$ は 通常のグラフラプラシアン $L$ と一致します。
「ストークが 1 次元」というのは「各ノードが 1 つの数値しか持たない」状態。「両端の制限写像が +1 と -1」というのは「辺で両端の値の差を取る」という、最もシンプルな比較ルールです(辺 $e = (u, v)$ について、$\delta\mathbf{x}_e = x_v - x_u$ になる構造)。
このような単純な層を、Sheaf 理論では 自明な層 (trivial sheaf) と呼びます。
この場合、第 5.2 節の式は次のようになります:
\mathbf{x}^\top L_\mathcal{F} \mathbf{x} = \sum_{(u,v) \in E} (x_v - x_u)^2
これはまさに通常のグラフラプラシアンによる「全辺の差の二乗の総和」と同じ式です。これを「層ラプラシアンが自明な層に特殊化したとき、グラフラプラシアンと一致する」と表現します。
用語について
「自明 (trivial)」とは、数学で「特殊な値や条件によって、複雑な構造が最も単純な形になっている状態」を指す確立用語です。「自明な層」は Sheaf 理論で標準的な用語で、「ストークがすべて同じ 1 次元空間で、制限写像がすべて(符号付きの)恒等写像」の場合の層を指します。
本記事のケース 1(銀行不正検知)では、後で見るように、入金と出金が同じ単位(円)で扱えるため、本質的にこの「自明な層」に近い構造をしています。
より一般のケースについての注
ストークが $d$ 次元(各ノードが $d$ 個の数値を持つ)で、全制限写像が $d \times d$ の単位行列(片端 +1、もう片端 -1)の場合、$L_\mathcal{F}$ は $L \otimes I_d$(クロネッカー積、$L$ をブロックごとに $d$ 倍に膨らませた形)になります。本記事ではストーク 1 次元の場合に限定して話を進めます。
7.3 ゆるい版が「自明な層に対応する」理由
第 6 部のコードは、まさにこの自明な層の状況を扱っています。「銀行口座の入金量と出金量」は同じ単位(円)で、各取引で「送金 = 受取」が成立するので、辺ごとの翻訳は不要です(制限写像は片端 +1、もう片端 -1 のみ)。
この状況下では、層ラプラシアンを陽に組み立てなくても、ノードレベルの集約量(入金や出金の総和)を直接スコア化 することで、似たような検出ができます。
ただし注意点があります。第 6 部のスコアと、層ラプラシアンから自然に出てくる量は、完全に等しいわけではありません。
7.4 ゆるい版と層ラプラシアン版の関係(ここ重要)
具体的に比べましょう。第 6 部のコードでは、こう計算しています:
\text{ゆるい版のスコア}_v = \frac{|\text{in}_v - \text{out}_v|}{\text{in}_v + \text{out}_v}
これは「入金と出金の不均衡を、口座のサイズで正規化した値」です。
一方、層ラプラシアンから自然に出てくる量は:
|\text{in}_v - \text{out}_v|
(正規化なし、絶対値だけ)
つまり、ゆるい版は分母で割って正規化していますが、層ラプラシアンが出す量は割り算をしません。
この違いは何を意味するか
数値で見るとイメージがわきます。例として 2 つの口座:
- 口座 A:入金 1,000、出金 500 → 差 = 500
- 口座 B:入金 100、出金 50 → 差 = 50
| ゆるい版のスコア | 層ラプラシアン版のスコア | |
|---|---|---|
| 口座 A | 500 / 1500 = 0.33 | 500 |
| 口座 B | 50 / 150 = 0.33 | 50 |
| どっちが大きいと判定? | 同じ | A の方が圧倒的に大きい |
両者は「スコアの絶対値」も「口座 A と B の相対的な順位」も違います。
結論:「順位ランキングが似た結果になることが多い」
実際にこの記事のサンプルデータでは、両者の上位 3 位は同じ口座です。これは「業務的なシグナル(不正口座は他より明らかに大きく不均衡)」が強く、正規化の有無で順位が変わらないからです。
しかし、両者は数学的に等価ではありません。「どっちが大きいか」が逆転するケースもあり得ます(上の例の A と B)。
「ゆるい版でも同じ結果が出るから OK」と決めつけるのは危険で、業務データの性質次第です。
7.5 では、層ラプラシアンを陽に使った厳密版はどう書く?
ハブ口座の「入金 = 出金」という業務制約を、Sheaf 理論の枠組みできちんと表現 してみます。
設計
- 各口座(ノード)のストーク = $\mathbb{R}^2$:
(in, out)の 2 次元ベクトル - 各ハブ口座について、辺ストーク = $\mathbb{R}^1$:1 次元(スカラー)
- 制限写像 $F = [1, -1]$:ノードの
(in, out)からin - outを取り出す
これにより、辺の上の値 $F \cdot (in, out)^\top = in - out$ が、整合性が取れているなら 0 になるはずです。
整合性半径は:
\rho(\mathbf{x}) = \sqrt{\sum_{\text{ハブ } v} (in_v - out_v)^2}
つまり「全ハブ口座のアンバランス度の二乗を合計して、ルートを取った量(L2 ノルム)」です。
数学的な注記:本記事のこの設計は、数学的に厳密なセルラー層の標準形を簡略化した、Sheaf-inspired な実装です。
セルラー層の正式な定義では、辺は 2 つの異なる端点ノード を持ちます。本記事では便宜上、「ハブ口座 1 つに対して辺 1 つ」という構造(ノード上の制約)を辺として扱っていますが、これは厳密には「辺」の標準的な定義からは逸脱しています。
数学的に厳密にやるなら、ハブ口座の中で「入金集約ノード」と「出金集約ノード」を分離するなど、追加のグラフ構造の工夫が必要です。本記事では実装の簡潔さを優先しています。
整合性半径の計算自体は同じ枠組みで動作するので、教育目的としては問題ありません。
厳密版の実装
def build_strict_sheaf(accounts, transactions):
"""層ラプラシアンを陽に組み立てる。
設計:
- 各口座のストーク: R^2 (in, out)
- 各ハブ口座について辺ストーク R^1 (in - out)
- 制限写像 F = [1, -1]: in - out を取り出す
"""
n = len(accounts)
name_idx = {a: i for i, a in enumerate(accounts)}
# 各口座の inflow / outflow を集計
inflow = np.zeros(n)
outflow = np.zeros(n)
degree = np.zeros(n)
for src, tgt, amt in transactions:
outflow[name_idx[src]] += amt
inflow[name_idx[tgt]] += amt
degree[name_idx[src]] += 1
degree[name_idx[tgt]] += 1
# ハブ口座を特定
hub_indices = [i for i in range(n) if degree[i] >= 8]
# ノード特徴 x: 各口座 (in, out) を縦に並べる
x = np.zeros(n * 2)
for i in range(n):
x[i * 2 + 0] = inflow[i]
x[i * 2 + 1] = outflow[i]
# δ を構築: 各ハブ口座について、(in, out) → (in - out)
rows, cols, vals = [], [], []
for k, hub_idx in enumerate(hub_indices):
rows.append(k); cols.append(hub_idx * 2 + 0); vals.append(+1.0) # +in
rows.append(k); cols.append(hub_idx * 2 + 1); vals.append(-1.0) # -out
delta = sp.csr_matrix(
(vals, (rows, cols)),
shape=(len(hub_indices), n * 2)
)
L_F = (delta.T @ delta).tocsr()
return L_F, delta, x, hub_indices
def localize_per_hub(x, delta, accounts, hub_indices):
"""各ハブ口座の不一致度を、δx の対応する成分から取得する。"""
deltax = delta @ x
contribs = {}
for k, hub_idx in enumerate(hub_indices):
contribs[accounts[hub_idx]] = abs(float(deltax[k]))
return contribs
# 実行
accounts, transactions, fraudsters = generate_transaction_graph()
L_F, delta, x, hub_indices = build_strict_sheaf(accounts, transactions)
rho = consistency_radius(x, L_F)
print(f"[整合性半径] ρ(x) = {rho:.4f}")
contribs = localize_per_hub(x, delta, accounts, hub_indices)
sorted_c = sorted(contribs.items(), key=lambda kv: -kv[1])
print(f"\n{'account':<10} {'|in - out|':>12} {'真の状態':>10}")
for name, c in sorted_c[:10]:
truth = "不正" if name in fraudsters else "正常"
print(f" {name:<10} {c:12.2f} {truth:>10}")
厳密版の実行結果
[整合性半径] ρ(x) = 923.7475
account |in - out| 真の状態
acc_002 601.95 不正 ← 検出
acc_022 524.26 不正 ← 検出
acc_019 419.88 不正 ← 検出
acc_029 164.11 正常
acc_006 100.83 正常
...
[評価] 上位3口座のうち真の不正口座数: 3 / 3
検出された 3 口座は ゆるい版と同じ(両方とも上位 3 口座が真の不正口座)です。
ただし第 7.4 節で説明したとおり、両者のスコアの絶対値も意味も違います。たまたまこのサンプルデータでは順位ランキングが一致しただけで、業務データによっては順位が変わる可能性があります。
7.6 ゆるい版と厳密版の比較
順位が同じだから「どっちでもいい」とは言えません。理由:
- 厳密版は他のケース(センサー融合、サプライチェーン)とコードが統一できる
- 整合性半径という単一スカラーで「ネットワーク全体の不整合度」を測れる(ゆるい版にはこの全体量がない)
- 業務制約の追加・変更が容易(別の制約を辺として足すだけ)
- 数学的に厳密な意味付けができる($\mathbf{x}$ が大域切断からどれだけ離れているかを表す非負の数値)
これらは長期保守性で大きな違いになります。
第8部:他の3ケースもざっと見る
ここからは応用編。同じ層ラプラシアンの枠組みで、サプライチェーン・マイクロサービス・センサー融合の 3 つを解きます。
紙幅の都合で、残り 3 ケースは設計のコアだけ示します。詳しいコードは GitHub に置きます(末尾参照)。
8.1 ケース 2 ─ サプライチェーン整合性
問題:8 社のサプライチェーンで、1 社が「売上を 1.5 倍に水増し申告」している。検出する。
設計のコア:
- 各企業のストーク = $\mathbb{R}^2$:
(申告仕入れ, 申告売上) - 各取引(辺)で「親の売上 = 子の仕入れ」を制約
- 親側の制限写像 $F_{u} = [0, 1]$(売上だけ取り出す)
- 子側の制限写像 $F_{v} = [1, 0]$(仕入れだけ取り出す)
結果: parts_C(不正企業)が圧倒的な不整合寄与度(117.74)で正しく検出。
8.2 ケース 3 ─ マイクロサービス障害根本原因
問題:6 サービス中 1 つ(payment)が障害発生中。根本原因サービスを特定。
設計のコア:
- 各サービスのストーク = $\mathbb{R}^3$:
(latency, success_rate, error_entropy) - 各呼び出し(辺)のストーク = $\mathbb{R}^3$
- 制限写像 = 対角行列
diag(1, 1, 0.5)(エラーエントロピーは部分的に伝わる)
結果: payment が圧倒的な寄与度(726)で根本原因として特定。
注:対角値 0.5 は経験則の仮の値で、ドメインエキスパートが調整するハイパーパラメータです。実運用では過去のインシデントデータから学習させる、または他の値を試すなどの調整が必要です。
8.3 ケース 4 ─ 多センサー融合
問題:4 つの温度センサー中、1 つが故障(+5°C オフセット異常)。検出する。
設計のコア:
- アフィン変換(後述)を線形化するため、ストーク = $\mathbb{R}^2$:
(reading, 1) - 単位変換を制限写像で表現:
- 摂氏 → 摂氏:$F = [1, 0]$
- 華氏 → 摂氏:$F = [5/9, -160/9]$
- 絶対温度 → 摂氏:$F = [1, -273.15]$
結果: sensor_D の寄与度が他より 4 倍以上、故障センサーとして特定。
第9部:ケース 4 の数学的背景 ─ 線形変換、アフィン変換、同次座標
この章は補足です。ケース 4(センサー融合)で使った「同次座標」というテクニックを、高校数学レベルから丁寧に解説します。
ケース 4 で「アフィン変換」「同次座標」という用語が出てきました。これらは 高校では習わないが、機械学習・コンピュータビジョン・コンピュータグラフィックスで頻繁に登場する 概念です。丁寧に解説します。
9.1 線形変換 (linear transformation) とは
中学・高校で習った関数 $y = ax$ のことを、数学では 線形変換 (linear transformation) と呼びます(原点を通る直線の式)。
特徴:
- $x = 0$ なら $y = 0$(原点を必ず通る)
- $x$ を 2 倍すると $y$ も 2 倍になる(比例関係)
行列で書くと、$\mathbf{y} = A \mathbf{x}$(行列 $A$ をベクトル $\mathbf{x}$ に掛ける)が線形変換です。
9.2 アフィン変換 (affine transformation) とは
一方、$y = ax + b$ という形($b \ne 0$)は アフィン変換 と呼びます。「アフィン」は英語の "affine"(関連がある、つながっている)から来ています。
特徴:
- $x = 0$ でも $y = b$(原点を通らない、$b$ だけずれている)
- 線形変換に 平行移動(全体を $b$ だけずらす)が加わったもの
9.3 アフィン変換の実例:温度の単位変換
身近な例として、温度の単位変換はすべてアフィン変換です:
- 摂氏 → 華氏:$y = \frac{9}{5}x + 32$(係数 $\frac{9}{5}$、切片 $32$)
- 華氏 → 摂氏:$y = \frac{5}{9}(x - 32) = \frac{5}{9}x - \frac{160}{9}$
- 絶対温度 → 摂氏:$y = x - 273.15$
これらは原点を通らないので、純粋な線形変換ではありません。
9.4 Sheaf 理論の困りごと:制限写像は線形写像でなければならない
セルラー層の定義では、制限写像は 線形写像 (linear map) に限定されます。アフィン変換はそのままでは使えません。
しかし、温度センサーのケースでは単位変換 = アフィン変換が必要です。どうしたらいいでしょうか?
9.5 解決策:同次座標 (homogeneous coordinates)
ここで 同次座標 (homogeneous coordinates) という工学的なテクニックが登場します。
用語について
「同次座標」と「斉次座標 (せいじざひょう)」は同じ意味で、英語の "homogeneous coordinates" の訳語です。コンピュータビジョン・機械学習・コンピュータグラフィックスの分野では「同次座標」、純粋数学(射影幾何学など)では「斉次座標」が多く使われます。本記事では「同次座標」で統一します。
アイデア
ベクトルを 1 次元増やして、最後の成分を常に 1 にする。これだけ。
例えば、これまで x = [reading](1 次元)としていたところを、
\mathbf{x} = \begin{pmatrix} \text{reading} \\ 1 \end{pmatrix} \quad (\text{2 次元の同次座標})
のように、末尾に「1」を付け足したベクトル にします。
すると、アフィン変換 $y = ax + b$ は:
\begin{pmatrix} y \end{pmatrix} = \begin{pmatrix} a & b \end{pmatrix} \begin{pmatrix} x \\ 1 \end{pmatrix} = ax + b
という 線形写像(行列との掛け算)で書けるようになります! 切片 $b$ が、行列の中に「吸収」されたわけです。
温度センサーの例で確認
- 摂氏:$F = \begin{pmatrix} 1 & 0 \end{pmatrix}$、$F \cdot (x, 1)^\top = x$(変換不要)
- 華氏 → 摂氏:$F = \begin{pmatrix} 5/9 & -160/9 \end{pmatrix}$、$F \cdot (x, 1)^\top = (5/9)x - 160/9$
- 絶対温度 → 摂氏:$F = \begin{pmatrix} 1 & -273.15 \end{pmatrix}$、$F \cdot (x, 1)^\top = x - 273.15$
すべて 1 行 2 列の行列で書ける線形写像になりました。
これでアフィン変換を、Sheaf 理論的に問題のない「線形写像」として扱えます。
「同次」の意味
「同次」とは「次数が同じ」という意味です。例えば、二次式の中で:
- $x^2 + 2xy + y^2$ は 同次(全ての項が 2 次)
- $x^2 + 2xy + y$ は 同次でない(2 次と 1 次が混在)
同次座標は、数学的に深い背景(射影幾何学)を持っていますが、本記事の用途では「1 次元増やして、末尾を 1 にすることで、アフィン変換を線形写像にする工学的テクニック」と理解すれば十分です。
設計上の注記:同次座標を使う方法は、ノードのストークが「末尾の成分は常に 1」という制約を持つ Sheaf-inspired なアプローチです。これはセルラー層の標準的な定義(ストークは制約のないベクトル空間)とは少し異なる扱いですが、整合性半径の計算は同じ枠組みで動作します。
実用上は、観測値ベクトル $\mathbf{x}$ を構築するときに「末尾を 1 にする」ことだけを守れば、結果は正しく出ます。
第10部:他のケースで使った「局所化」について
この章も補足です。第 8 部で出てきた「寄与度」が、Sheaf 理論ではどう定義される量なのかを説明します。
第 8 部で各ケースの結果を見たとき、「寄与度」というスコアが出てきました。これは「どのノードが不整合に最も寄与しているか」をランキングする量です。
これに関連する正式な数学概念として、整合性フィルトレーション (consistency filtration) があります。
10.1 整合性フィルトレーションとは
フィルトレーション (filtration) という数学用語は、「部分集合のサイズを変えながら、ある量の変化を追う手法」のことです。料理のフィルター(漉す網)を、目の細かさを変えながら使うイメージです。
整合性フィルトレーション は Robinson が提唱した概念で、グラフ $G$ の 部分グラフ全体 に対して整合性半径を計算したリストです。これにより「どの部分グラフが整合していて、どの部分グラフが整合していないか」がスコア化されます。
10.2 本記事の局所化は「整合性フィルトレーションの簡略版」
本記事では、各ケースで以下のような局所化を行いました:
- ケース 1(厳密版):各ハブに対応する $\delta\mathbf{x}$ の成分そのものをスコアにする(辺と検出対象が 1:1 対応するので可能)
- ケース 2、3、4:各ノードを除外したときに整合性半径がどれだけ減るかを見る("edge drop" 方式)
これらは 整合性フィルトレーションの最も簡単な近似 です。本格的な実装をしたい場合は、PySheaf の ConsistencyFiltration メソッドを参照してください。
本記事の局所化方法は、教育目的に簡略化したもので、PySheaf の正式な ConsistencyFiltration とは計算量が異なります。実用上は本記事の簡略版で十分機能しますが、より精密な解析が必要な場合は専用ライブラリを使うことをお勧めします。
第11部:用語集
ここはリファレンスです。記事を読み返すときの辞書として使ってください。
最後に、本記事で出てきた用語を全部整理します。
11.1 数学用語の和訳辞典
| 数学用語 | 本記事内での意味(平易) |
|---|---|
| ノード / 頂点 | ネットワーク図の点 |
| 辺 / エッジ | ネットワーク図の線 |
| グラフ | 点と線でつながったネットワーク図 |
| ベクトル | 数値を縦に並べたもの |
| 行列 | 数値を縦横に並べたもの |
| 転置 ($A^\top$) | 行列を斜めに反転 |
| ノルム ($|\mathbf{x}|$) | ベクトルの長さ |
| L1 ノルム | 各成分の絶対値の合計 |
| L2 ノルム | 各成分の二乗の合計のルート(三平方の定理の一般化) |
| 拡散 (diffusion) | 値が隣のノードへ広がる現象 |
| ラプラシアン | 「自分と隣の差」を表す行列 |
| グラフラプラシアン ($L$) | グラフ上のラプラシアン |
| 層 (sheaf) | ストーク + 制限写像のセット(本記事ではセルラー層を扱う) |
| セルラー層 (cellular sheaf) | グラフ上で定義される層 |
| 節点ストーク (node stalk) | ノードの値が住むベクトル空間 |
| 辺ストーク (edge stalk) | 辺の上の「待ち合わせ部屋」のベクトル空間 |
| 制限写像 (restriction map) | ノード上のデータを辺の上で比較するための線形写像(=翻訳行列) |
| 層ラプラシアン ($L_\mathcal{F}$) | 翻訳付きのラプラシアン($\delta^\top \delta$) |
| コバウンダリ作用素 ($\delta$) | 辺ごとに翻訳して引き算する行列 |
| 整合性半径 (consistency radius) ($\rho$) | 全辺の不一致度の L2 ノルム。0 なら大域切断、大きいほど大域切断から離れている |
| 切断 (section) | 各ノードに値を割り当てたデータの並び(=ベクトル $\mathbf{x}$) |
| 大域 (global) | 全体にわたる、空間の全体で成立する(対義語: 局所) |
| 大域切断 (global section) | ネットワーク全体で完全に整合しているデータの並び($\delta\mathbf{x} = \mathbf{0}$ となる $\mathbf{x}$) |
| 核 / カーネル (kernel) | $A\mathbf{x} = \mathbf{0}$ となるベクトル $\mathbf{x}$ の集まり。$\delta$ の核は大域切断の集合に等しい(機械学習で「カーネル法」と呼ばれる別概念とは異なるので注意) |
| 整合性フィルトレーション | 部分グラフ全体に対する整合性半径のリスト |
| 線形変換 | $y = ax$($b = 0$、原点を通る直線) |
| アフィン変換 | $y = ax + b$($b \ne 0$、平行移動を含む) |
| 同次座標 | アフィンを線形にするため、1 次元増やして末尾を 1 にしたベクトル |
| 特殊化 (specialization) / 自明化 | 一般的な構造に特殊な値や条件を入れて、もっと単純な形に化ける数学的な操作 |
| 二次形式 | $\mathbf{x}^\top L \mathbf{x}$ の形をした量 |
| 単位行列 ($I$) | 対角線が 1、それ以外が 0 の行列(何もしない変換) |
11.2 NumPy 記号の和訳辞典
| 記号 | 意味 |
|---|---|
np.array([1, 2, 3]) |
ベクトルを作る |
A.shape |
行列の形(行数、列数) |
A + B |
同じ位置の数を足す |
A * B |
同じ位置の数を掛ける(要素ごと積) |
A @ B |
行列としての掛け算(これが本記事で重要) |
A.T |
転置 |
np.linalg.norm(x) |
L2 ノルム(ベクトルの長さ) |
np.sum(np.abs(x)) |
L1 ノルム |
sp.csr_matrix(...) |
疎行列を作る(SciPy) |
L_F = delta.T @ delta |
層ラプラシアン |
x @ L_F @ x |
二次形式 $\mathbf{x}^\top L_\mathcal{F} \mathbf{x}$ |
第12部:まとめ
ここまでお疲れさまでした。本記事の要点を簡潔に整理します。
- Sheaf 理論を使った異常検知 = 行列の引き算と転置だけで実装できる
- 各辺に「翻訳のための行列(制限写像)」を持たせて、全辺の不一致度を集約したのが 整合性半径 $\rho(\mathbf{x})$
- 整合性半径は、データ $\mathbf{x}$ が「大域切断(=完全に整合した状態、$\delta$ の核に属するベクトル)」からどれだけ離れているか を表す非負の数値
- ゆるい実装(ノード集約量を直接スコアにする)と厳密な実装(層ラプラシアンを陽に使う)があり、順位ランキングが似た結果になることが多いが、スコアの絶対値や数学的意味は違う
- 4 つのケース(銀行、サプライチェーン、マイクロサービス、センサー融合)で全て上位検出に成功
不正検知は「点」(各ノードの値の異常)を見るのではなく、「構造の破れ」(辺で結ばれた両端の整合性の崩れ)を見る ─ それが本記事の核心メッセージです。
理論的背景の包括的な解説は、Zenn 版の記事 グラフの「不整合」を検出する:Sheaf による構造的データ解析入門(未公開・近日公開予定) を参照してください。
本記事の数学的厳密性についての再確認
本記事では、機械学習エンジニア向けの教育目的で、いくつかの数学的詳細を簡略化した Sheaf-inspired なアプローチをとっています:
- ケース 1 の「ハブ口座 1 つに対して辺 1 つ」という設計は、セルラー層の標準的な「2 つの端点を持つ辺」の定義から逸脱しています(第 7.5 節注記)
- ケース 4 の同次座標の使用は、ストークに「末尾の成分は常に 1」という制約を入れる扱いで、セルラー層の標準的な定義とは少し異なります(第 9.5 節注記)
- ケース 3 の制限写像の対角値 0.5 は経験則の仮の値で、データから学習することも可能です(第 8.2 節注記)
- 本記事の局所化方法は、整合性フィルトレーションの簡略版です(第 10.2 節注記)
正式な数学的取扱いについては、Hansen & Ghrist (2019)、Robinson (2017)、PySheaf 等を参照してください。
第13部:さらなる発展 ─ 本記事で扱わなかった層ベースの手法
ここはおまけです。本記事の先に進みたい方向けに、層ベースの主要手法を一覧と関係図で整理します。
本記事では 整合性半径 (Robinson 2017) と Neural Sheaf Diffusion (Bodnar et al. 2022) を中心に解説しましたが、層 (sheaf) を不整合検出・不正検出・データ解析に応用する手法は これら以外にも数多く存在します。
これから学習を進める方向性として、層ベースの主要手法の一覧と関係図を示します。
13.1 主要手法の一覧表
| 手法 | 提案者・年 | 特徴 | 不正・異常検知に直接使える? |
|---|---|---|---|
| 整合性半径 (consistency radius) | Robinson 2017 | データの不一致度を L2 ノルムで集約 | ✅ 直接使用 |
| 整合性フィルトレーション (consistency filtration) | Robinson 2018 | 部分グラフごとの整合性 | ✅ 局所化に強い |
| 層コホモロジー (sheaf cohomology) | Ghrist (古典) | 代数的な障害不変量 | ✅ より強力 |
| 持続的層コホモロジー (persistent sheaf cohomology) | 2022 | パラメータ依存の解析 | ⭕ 動的データに |
| 算術的持続性 (arithmetic persistence) | Ghrist & Ding 2025 | 精度階層の解析 | ⭕ 最先端 |
| 相対層障害理論 (relative obstructions) | 2026 | 障害の分離診断 | ⭕ 最先端 |
| Sheaf NN | Hansen & Gebhart 2020 | ドメイン知識から手作業で層を構築 | ⭕ ノード分類経由で |
| Neural Sheaf Diffusion (NSD) | Bodnar et al. 2022 | データから層を学習する代表的な手法 | ⭕ ノード分類経由で |
| Sheaf Attention NN | Barbero et al. 2022 | Attention 機構を層に組み込む | ⭕ |
| Connection Sheaf NN | Barbero et al. 2022 | リーマン幾何で層ラプラシアンを事前計算 | ⭕ |
| Sheaf Hypergraph NN | Duta et al. 2023 | ハイパーグラフへ拡張 | ⭕ |
| Sheaf4Rec | Purificato et al. 2024 | 推薦システム | ⭕ 関連商品検出 |
13.2 各手法の関係図(Mermaid)
これらの手法がどのように関連しているかを、図で整理します。
大きな構図:層ベースの手法は大きく分けて 「数学的・解析的アプローチ」(Robinson 系) と 「ニューラルネット系」(NN 系) の 2 系統があり、その中で時系列に発展してきました。
13.3 各手法のかんたん解説
数学的・解析的アプローチ系列
- 整合性半径 (Robinson 2017): 本記事のメイン。データの不一致度を全辺について L2 ノルムで集約し、1 つの数値で表す
- 整合性フィルトレーション (Robinson 2018): 部分グラフごとに整合性半径を計算し、どのサブネットワークが整合・不整合かを階層的に解析
- 層コホモロジー (Ghrist 系の古典理論): $H^0, H^1, \ldots$ という代数的不変量で、ネットワーク全体の本質的な障害を検出。整合性半径より細かい構造を見られる
- 持続的層コホモロジー (Russold 2022): パラメータを動かしながら層コホモロジーの変化を追う。トポロジカルデータ解析(TDA)の層への拡張
- 算術的持続性 (Ghrist & Ding 2025): $\mathbb{Z}_p$ 係数で層コホモロジーのねじれ部分を解析。ネットワークの精度しきい値を測る最先端手法
- 相対層障害理論 (2026): マッピング錐体を使い、本来の不整合と接地条件による不整合を分離して診断する最先端手法
ニューラルネット系列
- Sheaf NN (Hansen & Gebhart 2020): Sheaf Neural Network の初期提案。ドメイン知識から手作業で構築した層 を Sheaf Laplacian に使う
- Neural Sheaf Diffusion (Bodnar et al. 2022, NeurIPS): 本記事で言及。データから層を学習する代表的な手法。ヘテロフィリー(隣接ノード同士のラベルが違うグラフ)とオーバースムージング(層を重ねるとノード特徴が均一化する問題)に対処
- Sheaf Attention NN (Barbero et al. 2022): 注意機構(Attention)を層に組み込む。GAT(Graph Attention Network)の層への一般化
- Connection Sheaf NN (Barbero et al. 2022): リーマン幾何学を使って 層ラプラシアン部分を事前計算(学習せずに決定)し、その後のニューラルネット部分は通常通り学習する。学習の手間とコストを削減
- Sheaf Hypergraph NN (Duta et al. 2023): ハイパーグラフ(辺が 3 つ以上のノードを結ぶグラフ)に層を拡張
- Sheaf4Rec (Purificato et al. 2024): 推薦システムへの応用。LightGCN や KGTORe を層で改善し、ユーザー嗜好の複雑な相互作用を捉える
13.4 学習ロードマップの提案
本記事を読み終えた方に、以下の学習順序をおすすめします:
- 本記事のコードを動かす(整合性半径と層ラプラシアンに慣れる)
- 整合性フィルトレーション で局所化を試す(PySheaf を使うのが簡単)
- 層コホモロジー の基礎を学ぶ(Ghrist の論文や講義動画)
- Sheaf NN / Neural Sheaf Diffusion の論文と公式実装を読む(GNN の基礎が前提)
- 興味に応じて Sheaf Attention や Sheaf Hypergraph などの拡張へ
理論的な背景の包括的な解説は、Zenn Book グラフの「不整合」を検出する:Sheaf による構造的データ解析入門(未公開・近日公開予定) を参照してください。
参考
主要な実装
- twitter-research/neural-sheaf-diffusion ─ 層を「学習可能」にした PyTorch 実装(Neural Sheaf Diffusion)
- kb1dds/pysheaf ─ 層理論の本格実装(PySheaf、Python)
主要論文(本記事のメイン)
- Robinson, M. (2017). Sheaves are the canonical data structure for sensor integration. Information Fusion, 36, 208-224.
- Hansen, J. & Ghrist, R. (2019). Toward a spectral theory of cellular sheaves. Journal of Applied and Computational Topology, 3, 315-358.
- Bodnar, C. et al. (2022). Neural sheaf diffusion: A topological perspective on heterophily and oversmoothing in GNNs. NeurIPS 2022.
第13部で紹介した手法の主要論文
- Robinson, M. (2018). Assignments to sheaves of pseudometric spaces. arXiv:1805.08927. ─ 整合性フィルトレーション
- Hansen, J. & Gebhart, T. (2020). Sheaf neural networks. arXiv:2012.06333. ─ Sheaf NN
- Barbero, F. et al. (2022). Sheaf attention networks. NeurIPS 2022 Workshop. ─ Sheaf Attention
- Barbero, F. et al. (2022). Sheaf neural networks with connection Laplacians. ICML 2022 TAG Workshop. ─ Connection Sheaf NN
- Duta, I. et al. (2023). Sheaf hypergraph networks. arXiv:2309.17116. ─ Sheaf Hypergraph NN
- Purificato, A. et al. (2024). Sheaf4Rec: Sheaf neural networks for graph-based recommender systems. arXiv:2304.09097. ─ 推薦システム
- Ghrist, R. & Ding, C. (2025). Precision-graded cohomology and arithmetic persistence for network sheaves. arXiv:2511.00677. ─ 算術的持続性
著者の関連記事
本記事を読んで「もっと層理論や代数幾何学の AI 応用を知りたい」と思った方に、関連記事を紹介します。それぞれの記事の関係を図で示します。
連載シリーズ全体図 ─ Sheaf 理論を軸とした 10 編の旅
本記事の比較表(第6.3節)で示した各観点を、それぞれ独立した深掘り記事として展開する 10 本連載の全体像です。中央の「Sheaf による不整合検出」(本記事の中心概念)を軸に、各記事が Sheaf 理論とどう関係するかを示しています。
各記事の詳細(タイトル・想定読者・技術スタック)は、執筆進行に応じて順次公開します。新しい記事が公開されるたびに、本記事の Mermaid 図と「機械学習による発展を学びたい方」リストにリンクを追加していきますので、フォローまたはストックでお待ちいただけると幸いです 🙏
各記事の詳細(タイトル・想定読者・技術スタック)は、執筆進行に応じて順次公開します。新しい記事が公開されるたびに、本記事の Mermaid 図と「機械学習による発展を学びたい方」リストにリンクを追加していきますので、フォローまたはストックでお待ちいただけると幸いです 🙏
より広い視座:幾何学的データサイエンスの 9 領域地図
本連載(Sheaf 理論による不整合検出)は、より広い知識領域である 幾何学的データサイエンス(Geometric Data Science) の一部です。
筆者はこの連載と並行して、もう 1 本の連載 「TDA × ネットワーク理論」 も執筆中です。両連載は 幾何学的データサイエンスの 2 本柱 として企図されています。
【連載初回】グラフの「中心性・コミュニティ」と「穴・連結成分」を同時に捉える ─ ネットワーク理論と TDA、2 つのレンズ
下の地図では、金枠の領域(7. 層理論によるデータサイエンス) が本連載が照らす範囲、銀枠の領域(2. グラフ・ネットワーク、3. TDA) が並行する TDA × ネットワーク理論連載が照らす範囲です。残り 6 領域は、幾何学的データサイエンスの広大な探究領域として今後の連載や記事で扱っていきます。
図解: 幾何学的データサイエンス(Geometric Data Science)を構成する 9 つの研究領域。金枠の「7. 層理論によるデータサイエンス」が本連載が照らす領域、銀枠の「2. グラフ・ネットワーク」と「3. TDA」が並行する TDA × ネットワーク理論連載が照らす領域。両連載は補完関係にあり、データの「整合性」と「形」という 2 つの異なる視点から、グラフ構造データを読み解きます。
筆者は、上記の 9 領域のうち他の領域(多様体・リーマン幾何、群・対称性、ニューラルネット最適化の幾何学、ゲージ理論・ファイバー束など)についても Qiita・Zenn・GitHub にて解説記事を公開しています。著者ページからご覧いただけます。
各記事・コンテンツへのリンク:
機械学習による発展を学びたい方
本記事では制限写像を「人間が業務知識から設計する」前提で解説していますが、こちらの記事では制限写像を データから自動学習する Neural Sheaf Diffusion (NSD, NeurIPS 2022) を実装しています。GCN がヘテロフィリーグラフ(マネーロンダリングのように不正者同士が繋がらないグラフ)で性能が出ない問題を、NSD で 20 ポイント差で克服する具体例。
数学的系譜を知りたい方
代数幾何学そのものを学びたい方
- AIエンジニアのための代数幾何学入門【4レベル対応】
- How 200-Year-Old Algebraic Geometry Is Revolutionizing Deep Learning (PART 1) / (PART 2)
産業応用の事例を深く知りたい方
本記事の続編・付随コンテンツ
- Zenn Book(執筆中・近日公開予定): 「グラフの「不整合」を検出する:Sheaf による構造的データ解析入門」
本記事の内容を理論・実装・産業事例の3軸で包括的に解説する書籍版。Conexus AI(米Top-10銀行・NASA・米国防総省で本番運用)、DARPA 支援の Robinson 系 PySheaf、Twitter/X の NSD 公式実装などの産業実態に合わせた厳密さでセルラー層を Python で実装します。
- GitHub リポジトリ(準備中・来月公開予定): EtaleCohomology/geometric-intelligence-saga
本記事のコード一式、産業応用ガイド PDF(45 ページ、10 業界の実例調査)、Zenn Book の補助資料を順次公開します。
質問・指摘・改善案はコメント欄でお待ちしています 🙋





















