Skip to content
第12回:双曲幾何学 ~負の曲率の世界~

第12回:双曲幾何学 ~負の曲率の世界~

注意事項

  • 双曲空間が有効なのは、データに階層的・木構造的な性質がある場合に限られる。
  • すべてのデータが双曲空間に適しているわけではない(平坦・球面が適する場合も多い)。
  • 「曲率の選択」はタスク依存であり、万能の幾何学は存在しない。
  • Mixed-curvature spaces(複合曲率空間)は研究段階であり、標準手法ではない。
  • 本回で扱う「ポアンカレ円板」は双曲空間の一つのモデルであり、双曲空間そのものではない(同じ空間の異なる「地図」が複数存在する)。

導入:球面の「外」へ

第3回から第11回まで、私たちは主に正の曲率を持つ空間——球面——を舞台に議論してきた。正規化されたベクトルは単位球面上の点として、コサイン類似度は角度として解釈できた。この枠組みは、意味的な類似性を測る多くのタスクで有効だった。

しかし、世界には球面では表現しきれない構造がある。

WordNetの階層構造を考えてみよう。「動物」という概念の下には「哺乳類」「鳥類」「魚類」……と子概念が広がり、「哺乳類」の下にはさらに「犬」「猫」「人間」……と孫概念が連なる。この構造を球面に埋め込もうとすると、深い階層に行くほど「場所が足りなくなる」。球面の表面積は有限であり、指数関数的に増える子ノードを収容できないのだ。

本回では、この問題を解決する双曲空間(hyperbolic space) を導入する。負の曲率を持つこの空間は、階層構造を自然に表現する能力を持っている。なぜそうなるのかを、幾何学的な直感から理解していこう。

階層構造の埋め込み問題:なぜ球面では足りないのか

木構造の指数的成長

木構造(tree structure)は、自然言語処理、知識グラフ、生物学など、あらゆる分野に現れる基本的なデータ構造である。

その特徴は指数的な成長にある。根ノードから出発し、各ノードが b 個の子を持つとしよう(分岐数 b )。すると、深さ d にあるノードの数は bd である。深さが1増えるごとに、ノード数は b 倍になる。

深さ dノード数( b=2ノード数( b=10
011
1210
24100
381,000
101,02410,000,000,000

この指数的成長が、埋め込みにおいて問題を引き起こす。

ユークリッド空間での困難

ユークリッド空間 Rd に木構造を埋め込むことを考えよう。

直感的に、親ノードの「周り」に子ノードを配置したい。しかし、ユークリッド空間では、半径 r の球の表面積は rd1 に比例する(多項式的成長)。これは、木のノード数の指数的成長に追いつかない。

結果として、深い階層を埋め込もうとすると、以下の問題が生じる:

  1. 歪み(distortion)の増大:ノード間の距離関係が正しく保存されない
  2. 次元の爆発:歪みを抑えるために必要な次元数が指数的に増加する
  3. 親子関係の曖昧化:深い階層では、親と子の距離と、兄弟間の距離が区別しにくくなる

NOTE

歪みの定義: 埋め込み f歪み(distortion) は、グラフ上の最短経路距離 dG(u,v) と埋め込み空間での距離 dE(f(u),f(v)) を用いて、スケール係数 c>0 を最適化した上での「双方向の比の最大」として定義される:

distortion(f)=infc>0supuvmax(cdE(f(u),f(v))dG(u,v), dG(u,v)cdE(f(u),f(v)))

(通常、 f が異なる点を同一点に潰さない、すなわち uvdE(f(u),f(v))>0 を仮定する。)歪みが1に近いほど、元の距離関係が正確に保存されている。一般に、 n ノードの木をユークリッド空間に低歪みで埋め込むには、多くの次元を必要とすることが知られている。一方、Sarkar (2011) は双曲平面(2次元)への木の埋め込みが低歪みで可能であることを示した。

球面空間での困難

では、球面 Sd1 ではどうか。

球面は正の曲率を持つ。通常の2次元球面(球の表面、 S2 )の場合、ある点から測地線距離 r 離れた点の集合(測地線円の「円周」)の長さは 2πsin(r) となる。

問題は、 sin(r)r=π/2 で最大値を取り、それ以降は減少することだ。つまり、球面上では「中心から離れるほど周囲が広がる」のではなく、ある地点を境に狭くなる。これは、指数的に広がる木構造の表現には致命的である。

球面は、「対等な関係」(意味的な類似性、クラスタリング)には適しているが、「上下関係」(階層構造)には不向きなのだ。

空間曲率測地線円の周囲長(2次元、曲率 ±1 の場合)木構造への適性
ユークリッド平面02πr (線形)低い(深い階層で容量不足)
単位球面 S2+12πsin(r) (有界)低い(容量不足)
双曲平面 H212πsinh(r)πer (指数的)高い

双曲空間:負の曲率の世界

負の曲率とは何か

第0回で、曲率を「三角形の内角の和」で直感的に理解した。正の曲率(球面)では内角の和が180°を超え、負の曲率では180°を下回る。

負の曲率を持つ曲面の最も身近な例は鞍型曲面(saddle surface) である。馬の鞍や、プリングルスのチップスの形を思い浮かべてほしい。この曲面上で三角形を描くと、辺が「内側に引っ張られる」ように曲がり、内角の和は180°より小さくなる。

NOTE

局所的な形状と大域的な構造: 鞍型曲面は負の曲率の「局所的な形状」を示すが、完全な双曲平面(一定負曲率の完備曲面)を3次元ユークリッド空間に等長に埋め込むことはできない(Hilbertの定理)。ここで「完全(complete)」とは距離空間として完備(コーシー列が収束する)であることを意味し、リーマン多様体では Hopf–Rinow の定理により測地線が途中で途切れないという直感と対応する。「等長」とは距離関係を保存することを意味する。局所的な鞍型パッチは作れるが、双曲空間「全体」を歪みなく3次元に実現することはできない。そのため、双曲空間を視覚化するには「モデル」が必要になる。これは、球面を平面の地図で表すときに歪みが生じるのと似ている。

指数的に広がる周囲

双曲空間の最も重要な性質は、周囲長が指数関数的に増大することである。

具体的には、双曲平面 H2 (2次元双曲空間、曲率 1 )において、ある点から測地線距離 r 離れた点の集合(測地線円の「円周」)の長さは 2πsinh(r) となる。 r が大きくなると、 sinh(r)12er なので、周囲長は指数関数的に増大する。高次元双曲空間 Hd でも、測地線球面(半径 r の球面)の (d1) 次元体積は同様に指数的に成長する。

これが木構造の埋め込みに適している理由である:

  • 根ノード(中心)から離れるほど、「場所」が指数的に増える
  • 深さ d のノード数 bd を、半径 rd の位置に自然に配置できる
  • 親子関係は「中心からの距離」として、兄弟関係は「同じ深さでの角度」として表現される
txt
ユークリッド空間:          双曲空間:
  周囲 ∝ r               周囲 ∝ e^r

    ・・・                  ・・・・・・・・・・・・・・
   ・    ・                ・                      ・
  ・      ・              ・                        ・
 ・   ●   ・            ・           ●             ・
  ・      ・              ・                        ・
   ・    ・                ・                      ・
    ・・・                  ・・・・・・・・・・・・・・

(多項式的成長)          (指数的成長)

双曲空間の距離公式

d 次元双曲空間 Hd における2点間の距離は、座標系の取り方(モデル)によって異なる形で表される。最も基本的な双曲距離は、以下の性質を持つ:

  • 三角不等式を満たす
  • 中心から離れるほど、同じ座標差でも距離が大きくなる
  • 測地線(最短経路)は、モデルによって異なる見え方をする

具体的な距離公式は、次節で紹介するポアンカレ円板モデルで説明する。

ポアンカレ円板モデル:無限を有限に閉じ込める

モデルとは何か

完全な双曲空間は、3次元ユークリッド空間に等長に埋め込めない(前述のHilbertの定理)。そのため、私たちは双曲空間を「見る」ために、何らかのモデル(model) を使う必要がある。

これは、地球(球面)を平面の地図で表すのと同じ状況だ。メルカトル図法、正距方位図法、モルワイデ図法……いずれも同じ球面を表しているが、それぞれ異なる歪み方をする。

双曲空間にも複数のモデルがある:

モデル特徴用途
ポアンカレ円板単位円板内に表現、角度を保存(等角)可視化、多くの実装
ポアンカレ半平面上半平面に表現、等角理論的解析
ローレンツモデル高次元空間内の双曲面として表現数値的安定性
クラインモデル単位円板内に表現、測地線が直線特定の幾何学的議論

本回では、可視化に優れ、実装例も多いポアンカレ円板モデルを中心に扱う。

ポアンカレ円板の構造

ポアンカレ円板(Poincaré disk) は、2次元の場合、単位円板 D2={(x,y)R2:x2+y2<1} として表される。高次元の場合は単位球の内部 Dd={xRd:x<1} となる。

このモデルの驚くべき点は、有限の円板内に無限の双曲空間が収まっていることだ。

  • 円板の中心が双曲空間の「原点」に対応
  • 円板の境界(単位円)は「無限遠」に対応
  • 中心から境界へ向かうにつれ、双曲距離は無限大に発散

これを直感的に理解するために、エッシャーの版画「円の極限 (Circle Limit)」シリーズを思い出してほしい。中心から離れるほど図形が小さくなっていくが、双曲空間の「住人」から見ると、すべての図形は同じ大きさである。小さく見えるのは、私たちがユークリッド的な目で見ているからだ。

距離公式

ポアンカレ円板モデルにおける2点 u,vDd 間の双曲距離は:

dH(u,v)=arcosh(1+2uv2(1u2)(1v2))

ここで arcosh は双曲線余弦(ハイパボリックコサイン)の逆関数である。

この式から、いくつかの重要な性質が読み取れる:

  1. 境界効果u1 または v1 のとき、分母が0に近づき、距離は無限大に発散する。これが「境界は無限遠」の数学的表現である。

  2. 中心での近似u,v1 (中心付近)では、双曲距離はユークリッド距離に近似される。中心付近は「ほぼ平坦」に見える。

  3. 非対称なスケール:同じユークリッド距離 uv でも、境界に近い場所ほど双曲距離は大きくなる。

CAUTION

数値的安定性: ポアンカレ円板モデルでは、境界付近( x1 )で数値的な不安定性が生じやすい。実装では、ノルムを 1ϵ (例: ϵ=105 )でクリップするなどの対策が必要である。また、ローレンツモデルは数値的により安定であるため、大規模な学習ではローレンツモデルが採用されることも多い。

測地線の形状

ポアンカレ円板モデルにおける測地線(最短経路)は、円板の境界に直交する円弧として描かれる。中心を通る測地線に限り、直線(直径)になる。

これは、ユークリッド空間での直線が、このモデルでは曲がって見えることを意味する。双曲空間の「住人」にとっては真っ直ぐな道が、私たちの目には曲線に見えるのだ。

txt
ポアンカレ円板上の測地線:

       ┌────────────┐
      ╱              ╲
     │    ╭────╮      │
     │   ╱      ╲     │
     │  ╱   ●    ╲    │   ● = 中心
     │  ╲        ╱    │
     │   ╲      ╱     │
     │    ╰────╯      │
      ╲              ╱
       └────────────┘

(境界に直交する円弧が測地線)

階層構造の自然な埋め込み

木構造との対応

双曲空間の構造と木構造の構造には、自然な対応関係がある:

木構造の性質双曲空間での対応
根ノード円板の中心付近
深さ d のノード中心から双曲距離 dc の位置( c は定数)
親子関係半径方向の近さ
兄弟関係同じ半径上での角度
ノード数の指数的増加周囲長の指数的増加

この対応により、木構造を双曲空間に埋め込むと、以下の利点が得られる:

  1. 低歪み:親子間の距離と、非隣接ノード間の距離が正しく区別される
  2. 低次元の可能性:ユークリッド空間では多くの次元を必要とする場合でも、双曲空間では低次元(例:2次元や5次元)で良好な結果が得られることがある。ただし、これはデータの階層性の度合い、損失関数の設計、最適化の成否に依存する。
  3. スケーラビリティ:深い階層でも「場所が足りなくなる」ことがない

Poincaré Embeddings

Nickel & Kiela (2017) は、双曲空間(ポアンカレ円板モデル)に単語や概念を埋め込むPoincaré Embeddingsを提案した。これは、双曲幾何学を機械学習に応用した先駆的な研究である。

基本的なアイデアは、WordNetのような階層的語彙データベースを、ポアンカレ円板に埋め込むことである。「動物」「哺乳類」「犬」という上位-下位関係を持つ概念は、中心から外側へと配置される。

損失関数は、以下のような形で設計される:

L=(u,v)DlogedH(u,v)vN(u)edH(u,v)

ここで D は正例ペア(階層関係にある概念ペア)、 N(u) は負例サンプルである。

IMPORTANT

双曲空間での勾配降下: ポアンカレ円板はユークリッド空間ではないため、通常の勾配降下法をそのまま適用できない。リーマン勾配降下法を用いるか、指数写像(exponential map)と対数写像(logarithmic map)を使って「接空間での更新→多様体への射影」という操作を行う必要がある。詳細は実装ノートを参照。

応用例

双曲埋め込みは、以下のような応用で有効性が示されている:

WordNetの埋め込み:語彙の上位-下位関係を低次元で表現。ユークリッド空間の200次元と同等の表現力を、双曲空間の5次元で達成(Nickel & Kiela, 2017)。

知識グラフ:エンティティ間の「is-a」「part-of」などの階層的関係をモデル化。TransEなどのユークリッドベースの手法に対して、階層的関係の予測精度が向上(Balažević et al., 2019)。

社会ネットワーク:影響力の階層構造(インフルエンサー→フォロワー)をモデル化。スケールフリーネットワークの構造を自然に捉える。

系統樹:進化生物学における種の分岐構造。木構造そのものであるため、双曲空間との相性が極めて良い。

応用分野データ例双曲空間の利点
自然言語処理WordNet, ConceptNet語彙の上位-下位関係を低次元で表現
知識グラフFreebase, Wikidata階層的関係の予測精度向上
ネットワーク分析社会ネットワーク, Webグラフスケールフリー構造のモデル化
生物学系統樹, 遺伝子オントロジー木構造の低歪み埋め込み

球面との対比:正と負の曲率

幾何学的性質の比較

ここで、球面(正曲率)と双曲空間(負曲率)の性質を改めて比較しよう。以下は2次元の場合(単位球面 S2 と双曲平面 H2 、曲率 ±1 )である:

性質球面(正曲率)双曲空間(負曲率)
三角形の内角和> 180°< 180°
測地線円の周囲長2πsin(r) (有界)2πsinh(r)πer (指数的)
平行線存在しない(すべて交わる)無限に存在する
測地線の収束最終的に交わる発散する
全体の「形」閉じている(有限)開いている(無限)

適したデータ構造

この幾何学的な違いは、適したデータ構造の違いに直結する:

球面が適するケース

  • 等価な関係:意味的な類似性、クラスタリング
  • 循環的な構造:季節、曜日、色相環
  • 正規化が重要:表現のノルムを揃えたい場合

双曲空間が適するケース

  • 階層的関係:木構造、分類体系、組織図
  • スケールフリーネットワーク:次数分布がべき乗則に従うグラフ
  • 指数的成長:再帰的に分岐する構造

ユークリッド空間が適するケース

  • 平坦な関係:特に強い構造がない場合
  • 時系列:線形に進む時間
  • 加法的な性質:ベクトルの足し算が意味を持つ場合

NOTE

「適している」の意味: ここでの「適している」は、「低歪みで埋め込める」「少ない次元で表現できる」「下流タスクの精度が向上する」といった経験的な効果を指す。すべてのデータが明確にいずれかのカテゴリに属するわけではなく、実際には複数の構造が混在していることが多い。

曲率の学習

データの構造が事前に分からない場合、曲率自体を学習可能なパラメータとするアプローチもある。

曲率 K をパラメータとして、 K>0 なら球面的、 K=0 ならユークリッド、 K<0 なら双曲的な空間を表現する。学習を通じて、データに最適な曲率が決定される。

これは、「幾何学をデータから発見する」という野心的な方向性であり、現在も活発に研究されている(Gu et al., 2019; Bachmann et al., 2020)。

拡張:Mixed-Curvature Spaces

単一曲率の限界

現実のデータは、複数の構造が混在していることが多い。

例えば、商品カタログを考えよう:

  • カテゴリ階層:「電子機器 > スマートフォン > iPhone」→ 双曲的
  • 類似商品:「iPhone 15」と「iPhone 15 Pro」の類似性 → 球面的
  • 価格帯:連続的なスケール → ユークリッド的

すべてを単一の幾何学で表現しようとすると、どこかで無理が生じる。

複合曲率空間

Mixed-curvature spaces(複合曲率空間) は、異なる曲率を持つ部分空間を組み合わせるアプローチである:

M=Sd1×Hd2×Rd3

ここで Sd1 は球面、 Hd2 は双曲空間、 Rd3 はユークリッド空間である。

各部分空間が異なる種類の構造を担当することで、より柔軟な表現が可能になる:

  • 「意味的類似性」は球面部分で
  • 「階層構造」は双曲部分で
  • 「連続的なスケール」はユークリッド部分で

CAUTION

研究段階の技術: Mixed-curvature spacesは理論的には魅力的だが、実装の複雑さ、学習の不安定性、解釈の困難さなどの課題がある。標準的な手法として確立されているわけではなく、適用には注意が必要である。

関連研究

複合曲率空間に関する代表的な研究:

  • Ultrahyperbolic representations(Law et al., 2021):正と負の曲率を混合した擬リーマン多様体での表現学習
  • Product manifolds(Gu et al., 2019):球面・双曲・ユークリッドの直積空間での埋め込み
  • Gyrovector spaces:双曲空間におけるベクトル演算の体系化(Ungar, 2008)

Visualization Break IV:ポアンカレ円板を体験する

デモ:木構造の埋め込み比較

以下のデモでは、同じ木構造を(1)ユークリッド空間と(2)ポアンカレ円板に埋め込み、その違いを視覚的に理解する。

txt
木構造(3階層、分岐数2):

           0
         /   \
        1     2
       / \   / \
      3   4 5   6

ユークリッド空間での埋め込み

  • 深い階層のノードが密集しやすい
  • 親子関係と兄弟関係の区別が曖昧になる
  • 「場所が足りない」感覚

ポアンカレ円板での埋め込み

  • 根ノードは中心付近
  • 深い階層ほど外側(境界に近い)
  • 各階層に十分な「部屋」がある
  • 親子関係が半径方向、兄弟関係が角度方向に対応

TIP

インタラクティブな体験: ポアンカレ円板の直感を得るには、実際に操作してみるのが一番である。HyperToolsHyperbolic Embedding Playground などのツールで、双曲空間を体験できる。

まとめ

概念定義本回での役割
双曲空間負の曲率を持つ空間階層構造の自然な表現
ポアンカレ円板双曲空間のモデル(単位円板内)可視化と実装の基盤
指数的成長周囲長が er で増大木構造との対応の鍵
リーマン最適化多様体上での勾配法双曲埋め込みの学習に必須
Mixed-curvature複数の曲率を組み合わせ複雑なデータ構造への対応

本回のポイント

双曲空間は、「負の曲率」という一見奇妙な性質を持つ空間である。しかし、その性質——周囲長の指数的成長——は、木構造や階層構造の本質と深く対応している。

球面が「対等な関係」を表現するのに適しているのに対し、双曲空間は「上下関係」を表現するのに適している。これは、空間の曲率という幾何学的な概念が、データの構造という意味論的な概念と結びついていることを示している。

「どの幾何学を選ぶか」は、データの構造に依存する。万能の幾何学は存在しない。しかし、幾何学という言語を持つことで、「なぜこの設計が有効なのか」を説明し、「どのような構造に適しているのか」を予測できるようになる。

問い

データの「形」を事前に知ることなく、最適な幾何学を発見できるか?

曲率を学習可能にするアプローチ、複合曲率空間、あるいは全く新しい幾何学——この問いへの答えは、まだ探求の途上にある。

次回予告

第13回「高次元の深淵 ~幾何学的な恐怖と祝福~」では、これまで避けてきた高次元空間の「奇妙な性質」に正面から向き合う。

高次元空間では、ランダムに選んだ2つのベクトルがほぼ直交する。距離の区別がつきにくくなる。しかし同時に、指数的に多くの「ほぼ直交した」方向を持つことができる。この性質は、Mixture of Experts(MoE)やスパース表現の設計とどう関係するのか。高次元の「恐怖」と「祝福」を、幾何学的な視点から理解する。

実装ノート

NOTE

以下のコードは PyTorch >= 1.9 を前提とする。再現性のために torch.manual_seed(42) 等でシードを固定することを推奨。双曲幾何学の最適化には、Geoopt ライブラリが有用である。

IMPORTANT

曲率パラメータについて: 以下のコード例はすべて曲率 K=1 の標準双曲空間を仮定している。一般の曲率 K<0 では距離公式や指数写像の式が変わる(距離は曲率に応じてスケールし、実装ではモデルの定義に従う)。Geooptなどのライブラリでは曲率をパラメータとして指定できる。また、簡易版の実装では「直接更新して射影」という方法を用いているが、厳密なリーマン最適化では指数写像(expmap)を用いた更新が標準である。

ポアンカレ円板の距離計算

コード例: 12_poincare_distance.py
python
import torch


def poincare_distance(u, v, eps=1e-5):
    """ポアンカレ円板モデルにおける双曲距離

    Args:
        u: 点1 [batch, dim] または [dim]
        v: 点2 [batch, dim] または [dim]
        eps: 数値安定性のための小さな値

    Returns:
        双曲距離
    """
    # ノルムの2乗
    u_norm_sq = torch.clamp(torch.sum(u * u, dim=-1), max=1 - eps)
    v_norm_sq = torch.clamp(torch.sum(v * v, dim=-1), max=1 - eps)
    diff_norm_sq = torch.sum((u - v) ** 2, dim=-1)

    # 距離公式
    numerator = 2 * diff_norm_sq
    denominator = (1 - u_norm_sq) * (1 - v_norm_sq)

    # arcosh(1 + x) = log(1 + x + sqrt(x^2 + 2x)) for numerical stability
    x = numerator / (denominator + eps)
    return torch.log(1 + x + torch.sqrt(x * x + 2 * x + eps))


# 使用例
u = torch.tensor([0.0, 0.0])  # 中心
v = torch.tensor([0.5, 0.0])  # 中心から離れた点
w = torch.tensor([0.9, 0.0])  # 境界に近い点

print(f"d(center, mid): {poincare_distance(u, v):.4f}")
print(f"d(center, edge): {poincare_distance(u, w):.4f}")
print(f"d(mid, edge): {poincare_distance(v, w):.4f}")

# 期待される結果:
# 境界に近い点への距離が非常に大きくなる

指数写像と対数写像

コード例: 12_exp_log_maps.py
python
import torch


def mobius_add(u, v, eps=1e-5):
    """メビウス加法(双曲空間でのベクトル加法)

    ポアンカレ円板モデルにおける「平行移動」に相当する操作
    """
    u_norm_sq = torch.sum(u * u, dim=-1, keepdim=True)
    v_norm_sq = torch.sum(v * v, dim=-1, keepdim=True)
    uv = torch.sum(u * v, dim=-1, keepdim=True)

    numerator = (1 + 2 * uv + v_norm_sq) * u + (1 - u_norm_sq) * v
    denominator = 1 + 2 * uv + u_norm_sq * v_norm_sq + eps

    return numerator / denominator


def exp_map_0(v, eps=1e-5):
    """原点における指数写像

    接空間(ユークリッド)のベクトルを、
    ポアンカレ円板上の点に写す

    Args:
        v: 接空間のベクトル [batch, dim]

    Returns:
        ポアンカレ円板上の点
    """
    v_norm = torch.clamp(torch.norm(v, dim=-1, keepdim=True), min=eps)
    return torch.tanh(v_norm) * v / v_norm


def log_map_0(y, eps=1e-5):
    """原点における対数写像

    ポアンカレ円板上の点を、
    接空間(ユークリッド)のベクトルに写す

    Args:
        y: ポアンカレ円板上の点 [batch, dim]

    Returns:
        接空間のベクトル
    """
    y_norm = torch.clamp(torch.norm(y, dim=-1, keepdim=True), min=eps, max=1 - eps)
    return torch.atanh(y_norm) * y / y_norm


def project_to_poincare(x, eps=1e-5):
    """点をポアンカレ円板内に射影

    境界を超えた点を、境界内に引き戻す
    """
    norm = torch.norm(x, dim=-1, keepdim=True)
    max_norm = 1 - eps
    cond = norm > max_norm
    return torch.where(cond, x / norm * max_norm, x)


# 使用例:リーマン勾配降下法の1ステップ
def riemannian_sgd_step(x, euclidean_grad, lr=0.01):
    """リーマン勾配降下法の1ステップ

    1. ユークリッド勾配をリーマン勾配に変換
    2. 接空間で更新
    3. 多様体に射影
    """
    # リーマン計量によるスケーリング
    # ポアンカレ円板の計量テンソル: g_x = (2 / (1 - ||x||^2))^2 * I
    x_norm_sq = torch.sum(x * x, dim=-1, keepdim=True)
    scale = ((1 - x_norm_sq) ** 2) / 4
    riemannian_grad = scale * euclidean_grad

    # 接空間での更新(対数写像で接空間へ、更新後、指数写像で戻る)
    # 簡易版:直接更新して射影
    x_new = x - lr * riemannian_grad
    x_new = project_to_poincare(x_new)

    return x_new


# テスト
x = torch.tensor([[0.3, 0.4]])
grad = torch.tensor([[0.1, 0.1]])
x_new = riemannian_sgd_step(x, grad, lr=0.1)
print(f"Before: {x}, norm={torch.norm(x):.4f}")
print(f"After: {x_new}, norm={torch.norm(x_new):.4f}")

簡易的な木構造の埋め込み

コード例: 12_tree_embedding.py
python
import torch
import torch.nn as nn
import torch.optim as optim


class PoincareEmbedding(nn.Module):
    """ポアンカレ円板への埋め込み"""

    def __init__(self, num_nodes, dim, init_scale=0.001):
        super().__init__()
        # 小さな値で初期化(中心付近からスタート)
        self.embeddings = nn.Parameter(torch.randn(num_nodes, dim) * init_scale)
        self.eps = 1e-5

    def forward(self, indices):
        emb = self.embeddings[indices]
        # ポアンカレ円板内に射影
        return self._project(emb)

    def _project(self, x):
        norm = torch.norm(x, dim=-1, keepdim=True)
        max_norm = 1 - self.eps
        return torch.where(norm > max_norm, x / norm * max_norm, x)

    def distance(self, u, v):
        """ポアンカレ距離"""
        u_norm_sq = torch.clamp(torch.sum(u * u, dim=-1), max=1 - self.eps)
        v_norm_sq = torch.clamp(torch.sum(v * v, dim=-1), max=1 - self.eps)
        diff_norm_sq = torch.sum((u - v) ** 2, dim=-1)

        x = 2 * diff_norm_sq / ((1 - u_norm_sq) * (1 - v_norm_sq) + self.eps)
        return torch.log(1 + x + torch.sqrt(x * x + 2 * x + self.eps))


def train_tree_embedding(edges, num_nodes, dim=2, epochs=1000, lr=0.01):
    """木構造をポアンカレ円板に埋め込む

    Args:
        edges: エッジのリスト [(parent, child), ...]
        num_nodes: ノード数
        dim: 埋め込み次元
        epochs: エポック数
        lr: 学習率

    Returns:
        学習済み埋め込み
    """
    model = PoincareEmbedding(num_nodes, dim)
    optimizer = optim.Adam(model.parameters(), lr=lr)

    edges_tensor = torch.tensor(edges)

    for epoch in range(epochs):
        optimizer.zero_grad()

        # 正例:エッジで接続されたノードペア
        pos_u = model(edges_tensor[:, 0])
        pos_v = model(edges_tensor[:, 1])
        pos_dist = model.distance(pos_u, pos_v)

        # 負例:ランダムなノードペア
        neg_indices = torch.randint(0, num_nodes, (len(edges) * 5, 2))
        neg_u = model(neg_indices[:, 0])
        neg_v = model(neg_indices[:, 1])
        neg_dist = model.distance(neg_u, neg_v)

        # 損失:正例の距離を小さく、負例の距離を大きく
        margin = 1.0
        loss = torch.mean(torch.relu(pos_dist - neg_dist + margin))

        loss.backward()

        # 勾配クリップ(双曲空間では重要)
        torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)

        optimizer.step()

        # 射影(境界内に保持)
        with torch.no_grad():
            model.embeddings.data = model._project(model.embeddings.data)

        if (epoch + 1) % 200 == 0:
            print(f"Epoch {epoch + 1}, Loss: {loss.item():.4f}")

    return model


# 使用例:簡単な木構造
# 0 (root)
# ├── 1
# │   ├── 3
# │   └── 4
# └── 2
#     ├── 5
#     └── 6

edges = [(0, 1), (0, 2), (1, 3), (1, 4), (2, 5), (2, 6)]
num_nodes = 7

model = train_tree_embedding(edges, num_nodes, dim=2, epochs=1000)

# 結果の確認
with torch.no_grad():
    embeddings = model(torch.arange(num_nodes))
    norms = torch.norm(embeddings, dim=1)
    print("\n埋め込み結果:")
    for i in range(num_nodes):
        print(f"  Node {i}: pos={embeddings[i].numpy()}, norm={norms[i]:.4f}")

# 期待される結果:
# - 根ノード(0)は中心に近い
# - 葉ノード(3,4,5,6)は境界に近い
# - 深さに応じてノルムが増加

Geooptの利用例

コード例: 12_geoopt_example.py
python
# pip install geoopt

import geoopt
import torch


def geoopt_poincare_example():
    """Geooptライブラリを使ったポアンカレ球での操作例"""

    # ポアンカレ球多様体(デフォルトは曲率-1)
    ball = geoopt.PoincareBall()

    # ランダムな点を生成(多様体上に)
    x = ball.random(2, 5)  # [2, 5] の形状
    print(f"Points on Poincaré ball:\n{x}")
    print(f"Norms: {torch.norm(x, dim=-1)}")  # 必ず < 1

    # 2点間の距離
    y = ball.random(2, 5)
    dist = ball.dist(x, y)
    print(f"Distances: {dist}")

    # 指数写像(接空間 → 多様体)
    origin = torch.zeros(5)
    v = torch.randn(5) * 0.1  # 接ベクトル
    point = ball.expmap(origin, v)
    print(f"Exp map result: {point}, norm={torch.norm(point):.4f}")

    # 対数写像(多様体 → 接空間)
    v_back = ball.logmap(origin, point)
    print(f"Log map result: {v_back}")
    print(f"Original v: {v}")

    # 測地線に沿った補間
    t = 0.5
    midpoint = ball.geodesic(t, x[0], y[0])
    print(f"Midpoint on geodesic: {midpoint}")


def geoopt_optimization_example():
    """Geooptを使ったリーマン最適化の例"""

    ball = geoopt.PoincareBall()

    # 多様体上のパラメータ
    x = geoopt.ManifoldParameter(ball.random(10, 5), manifold=ball)

    # リーマン最適化器
    optimizer = geoopt.optim.RiemannianAdam([x], lr=0.01)

    # ダミーの最適化(中心に向かう)
    for i in range(100):
        optimizer.zero_grad()
        loss = torch.sum(x**2)  # 中心(原点)に近づける
        loss.backward()
        optimizer.step()

        if (i + 1) % 20 == 0:
            avg_norm = torch.norm(x, dim=-1).mean()
            print(f"Step {i + 1}, Loss: {loss.item():.4f}, Avg norm: {avg_norm:.4f}")


if __name__ == "__main__":
    print("=== Poincaré Ball Operations ===")
    geoopt_poincare_example()
    print("\n=== Riemannian Optimization ===")
    geoopt_optimization_example()

参考文献

双曲埋め込みの基礎

  • Nickel, M., & Kiela, D. (2017). Poincaré Embeddings for Learning Hierarchical Representations. NeurIPS 2017. arXiv: arXiv:1705.08039.
    • 双曲空間への単語埋め込みを提案した先駆的論文。WordNetでの実験で有効性を実証。
  • Nickel, M., & Kiela, D. (2018). Learning Continuous Hierarchies in the Lorentz Model of Hyperbolic Geometry. ICML 2018. arXiv: arXiv:1806.03417.
    • 数値的に安定なローレンツモデルでの双曲埋め込み。

理論的背景

  • Sarkar, R. (2011). Low Distortion Delaunay Embedding of Trees in Hyperbolic Plane. Graph Drawing 2011. DOI: 10.1007/978-3-642-25878-7_34.
    • 木構造の双曲平面(2次元)への低歪み埋め込みを示した理論的研究。双曲空間が木構造に適している理論的根拠を与える。
  • Krioukov, D., Papadopoulos, F., Kitsak, M., Vahdat, A., & Boguñá, M. (2010). Hyperbolic Geometry of Complex Networks. Physical Review E, 82(3), 036106. arXiv: arXiv:1006.5169.
    • 複雑ネットワークと双曲幾何学の関係を解明した物理学的研究。

知識グラフと双曲空間

  • Balažević, I., Allen, C., & Hospedales, T. (2019). Multi-relational Poincaré Graph Embeddings. NeurIPS 2019. arXiv: arXiv:1905.09791.
    • 知識グラフの多関係埋め込みへの双曲空間の適用。
  • Chami, I., Ying, Z., Ré, C., & Leskovec, J. (2019). Hyperbolic Graph Convolutional Neural Networks. NeurIPS 2019. arXiv: arXiv:1910.12933.
    • グラフニューラルネットワークの双曲空間への拡張。

Mixed-Curvature Spaces

  • Gu, A., Sala, F., Gunel, B., & Ré, C. (2019). Learning Mixed-Curvature Representations in Product Manifolds. ICLR 2019.
    • 球面・双曲・ユークリッドの直積空間での表現学習。
  • Bachmann, G., Bécigneul, G., & Ganea, O.-E. (2020). Constant Curvature Graph Convolutional Networks. ICML 2020. arXiv: arXiv:1911.05076.
    • 曲率を学習可能にしたグラフネットワーク。

実装とライブラリ

  • Kochurov, M., Karimov, R., & Kozlukov, S. (2020). Geoopt: Riemannian Optimization in PyTorch. arXiv: arXiv:2005.02819.

双曲幾何学の教科書