自然言語とスケッチで株価を検索する:CLIP流対照学習とツインオートエンコーダによる金融時系列検索(Bamford+ ICAIF’23)

株価の時系列データベースに「今より少しボラティリティが高くて、右肩上がりの銘柄」を探させたいとします。既存の時系列データベース(InfluxDB、TimescaleDB、KDB+ など)は高速なSQLライクなクエリをサポートしていますが、書けるのは WHERE monthly_return > 0.05 のような硬直したフィルタだけです。「ボラティリティが高い」という感覚を、SQLの1本の条件式にどう落とし込めばいいのでしょうか。標準偏差の閾値? どの窓幅で? 多くのアナリストにとって、これは考えるだけで面倒な作業です。

この問題に、J.P. Morgan AI Research のチームが挑んだのが、本記事で扱う Tom Bamford, Andrea Coletta, Elizabeth Fons, Sriram Gopalakrishnan, Svitlana Vyetrenko, Tucker Balch, Manuela Veloso, “Multi-Modal Financial Time-Series Retrieval Through Latent Space Projections,” ICAIF 2023(International Conference on AI in Finance の Best Industry Paper Award 受賞論文、arXiv:2309.16741)です。原論文を精読し、数式・データセット構築・実験結果を可能な限り忠実にたどります。

SQLライクな硬直クエリとマルチモーダル検索の対比

なぜこれを学ぶのか

応用先は明確です。

  • アナリストによるシナリオ検索:「高ボラティリティで上昇中」「急落からのリバウンド」のような自然言語の記述、あるいは手描きのラフなスケッチだけで、過去の似た値動きを瞬時に探し出したい。バックテストや類似事例調査で威力を発揮します。
  • より一般的な時系列データベースの検索性向上:金融に限らず、レジーム(運転モード・相場局面)を持つあらゆる時系列データベースに、SQLを超えた直感的な検索モードを与える設計思想として応用できます。

この記事の内容

  • 問題設定:時系列検索を関数 $f(q, \mathcal{D}, k) \to R \subset \mathcal{D}$ として定式化する
  • テキストベース検索:CLIP型の対照学習と、素朴なハードラベルとの違い
  • スケッチベース検索:価格系列とボラティリティ系列を別々にエンコードするツインオートエンコーダ
  • データセット構築:離散平均回帰過程・メガショック・3段階のキャプション生成(Unfiltered/Filtered/Filtered+)
  • 論文の実験結果(Table 1〜3の実測値)
  • Python実装:合成データ生成・対照学習のソフトターゲットの数値実証・ツインAEによる検索実験の再現

1. 問題設定 — 時系列を「同じ空間」に射影して検索する

論文はまず、時系列空間を $\chi = \mathbb{R}^L$($L$ は系列長)と定義し、$N$ 個の時系列からなるデータセット $\mathcal{D} = \{\bm{x}^i\}_{i=1}^N$($\bm{x}^i \in \chi$)からの検索問題を定式化します。目標は、入力クエリ $q$ が与えられたとき、最も良くマッチする $k$ 件を返す関数

$$ \begin{equation} f(q \in \chi, \mathcal{D}, k) \to R \subset \mathcal{D} \end{equation} $$

を学習することです。ここで重要なのは、クエリ $q$ の「型」がテキストであれ、画像であれ、スケッチであれ、同じ関数 $f$ で扱えること——つまりマルチモーダル検索です。

金融時系列には、単なるトレンド(右肩上がり/下がり)を超えた統計的な性質があります。これは金融工学で stylized facts(定型化された事実、例えばボラティリティ・クラスタリングや裾の厚い分布)と呼ばれ、既存のクエリ言語では表現しづらいものです(Bouchaud et al., 2018)。論文の目標は、トレンドだけでなく、こうした金融的に重要な性質もまとめて検索できるようにすることです。

論文はこの一般的アプローチを、2つの具体的なクエリモード——自然言語によるテキスト検索と、手描きスケッチによる検索——で実証します。両方に共通するアーキテクチャが下図です。

学習・データベース・検索の全体アーキテクチャ

出典: Bamford, Coletta, Fons, Gopalakrishnan, Vyetrenko, Balch, Veloso, “Multi-Modal Financial Time-Series Retrieval Through Latent Space Projections,” ICAIF 2023, Fig. 2.

流れは3段階です。Training:異なるモダリティのデータをエンコーダに通し、共有の「マルチモーダル潜在空間」を学習する。Database:学習済みエンコーダで実データ(例:時系列)を埋め込み、$\mathcal{D}_z = \{(\bm{y}_i, \bm{x}_i)\}_{i=1}^N$(埋め込みと元データのペア)としてルックアップテーブルに保存する。Retrieval:ユーザーのクエリ(例:自然言語)を同じ潜在空間に埋め込み、データベース中の埋め込みとのコサイン類似度で最近傍を検索する。

ポイントは、データベース側の埋め込みは一度計算すれば固定なので事前に保存でき、検索時にはクエリ1件分の埋め込み計算とベクトル化されたコサイン類似度計算だけで済むということです。これが後述する計算速度の優位性の土台になります。

論文はこの枠組みを2つのインスタンスで実演します。1つはテキストベース検索(CLIP型の対照学習)、もう1つはスケッチベース検索(ツインオートエンコーダ)です。順に見ていきましょう。


2. テキストベース検索 — CLIP型の対照学習

論文が実際に構築したプロトタイプUIは次のようなものです。左が自然言語によるテキスト検索、右がスケッチによる検索のインターフェースです。

論文が開発したプロトタイプUI(テキスト検索・スケッチ検索)

出典: Bamford, Coletta, Fons, Gopalakrishnan, Vyetrenko, Balch, Veloso, “Multi-Modal Financial Time-Series Retrieval Through Latent Space Projections,” ICAIF 2023, Fig. 1.

左のテキスト検索では “upward trend with high volatility” のような記述に対し、”has infrequent jumps”(稀なジャンプがある)、”the price is volatile”(価格が不安定)といった例文候補が示され、実際に上昇トレンドの時系列候補が4件返っています。右のスケッチ検索では、ユーザーが左側のキャンバスに手描きした概形(緑の曲線)に対し、右側に実際の株価データ(GOOGの過去データ)がマッチした結果として表示されています。

2.1 2つのエンコーダ

テキストによる検索を実現するため、論文は時系列データを画像として描画し(224×224ピクセル)、画像と自然言語を同じ空間に射影します。

  • 画像エンコーダ:ImageNetで事前学習済みの ResNet50(2015年、He et al.)。残差ブロック(スキップ接続で恒等写像を学習しやすくする構造)を50層積んだCNNで、224×224画像を入力に2048次元のベクトルを出力します。
  • テキストエンコーダSentence-BERT(Reimers & Gurevych, 2019)。通常のBERTが単語/サブワード単位のトークン化を行うのに対し、Sentence-BERTはSiamese構造とtriplet lossで文単位の意味的に一貫した埋め込みを学習します。英語Wikipedia(25億語超)で初期化された事前学習済みモデルを、SNLI・MultiGenre NLIデータセットでさらにファインチューンしたものを使用しています。

両エンコーダの出力は、次元を揃える1層の射影ヘッドを通してから、対照損失で位置合わせされます。

2.2 対照損失 — なぜ素朴なCLIPの対角ラベルではないのか

バッチ内の画像埋め込み $\bm{v}$ とテキスト埋め込み $\bm{t}$ が与えられたとき、まずモダリティ間の類似度をスケーリング付きコサイン類似度として計算します。

$$ \begin{equation} S \equiv S(\bm{t}, \bm{v}^T) = \frac{\bm{t}\cdot \bm{v}^T}{\tau} \end{equation} $$

ここまでは通常のCLIP(Radford et al., 2021)と同じです。CLIPは通常、バッチ内の $i$ 番目の画像と $i$ 番目のテキストだけを正例とし、それ以外を全部負例として扱う対角のハードラベル(単位行列)で交差エントロピー損失を取ります。しかし、金融の時系列キャプションでは「上昇トレンドかつ低ボラティリティ」のような同じレジームを指すキャプションがバッチ内に複数存在することが珍しくありません。対角ラベルでこれを学習すると、実質的に同じ意味を持つペア同士まで「負例」として引き離そうとする誤った勾配が発生します。

そこで論文は、各モダリティ内の自己類似度をブレンドしたソフトターゲットを使います。まずテキスト同士・画像同士の自己類似度を計算し、

$$ \begin{equation} S(\bm{t}, \bm{t}^T) = \frac{\bm{t}\cdot \bm{t}^T}{\tau}, \qquad S(\bm{v}, \bm{v}^T) = \frac{\bm{v}\cdot \bm{v}^T}{\tau} \end{equation} $$

これらを平均してソフトマックスを取ったものを目標分布とします。

$$ \begin{equation} S_{target} = \mathrm{softmax}\left(\frac{S(\bm{t}, \bm{t}^T) + S(\bm{v}, \bm{v}^T)}{2\tau}\right) \end{equation} $$

最終的な損失は、この目標分布に対する交差エントロピーを両方向(画像→テキスト、テキスト→画像)で平均したものです。

$$ \begin{equation} \mathcal{L} = \frac{\mathcal{L}_{CE}(S, S_{target}) + \mathcal{L}_{CE}(S^T, S_{target}^T)}{2} \end{equation} $$

式の意味を読み解くと、$S(\bm{t},\bm{t}^T)$ は「テキストどうしが意味的にどれだけ近いか」、$S(\bm{v},\bm{v}^T)$ は「画像(時系列)どうしがどれだけ似ているか」を表します。この2つを足して正規化した $S_{target}$ は、「バッチ内のどのペアが本当に意味的に近いか」をモダリティ非依存に近似した分布になります。対角だけを1にする単位行列と違い、$S_{target}$ は同じレジームを指す複数のペアに適切な重みを分配します。これにより、たまたまバッチ内に同じレジームの言い換えが複数含まれても、モデルはそれらを無理に引き離そうとしません。この効果は3節で数値的に確認します。

2.3 推論時の効率性

学習済みエンコーダの利点は、データベース側の埋め込みが固定であることです。一度計算した埋め込みをルックアップテーブルに保存しておけば、検索時にはクエリ1件の埋め込みを計算し、ベクトル化されたコサイン類似度計算を1回行うだけで済みます。これは後述するUMAPベースの手法との速度差の核心です。


3. スケッチベース検索 — ツインオートエンコーダで派生時系列を扱う

自然言語ではなく、ユーザーが時系列の概形を手描きして検索したい場合もあります。論文はこちらに、CLIPのような大規模事前学習モデルではなく、軽量な全結合オートエンコーダを使います。

3.1 ボラティリティを「派生時系列」として明示的に扱う

スケッチはトレンド(概形)の情報しか与えませんが、論文はここにボラティリティという金融的に重要な性質も組み込みます。工夫は、ボラティリティを追加の数値パラメータとして扱うのではなく、元の時系列から計算される、もう1本の時系列として扱うという発想です。

$$ \begin{equation} \bm{v}_i = \sigma(\bm{x}_{i-m:i+m}), \qquad m=4 \end{equation} $$

つまり、時刻 $i$ を中心とする前後 $m=4$ ステップ(計9点)の窓の標準偏差を、新しい時系列 $\bm{v}$ の $i$ 番目の値とします。この発想は、金融分析で使われる移動平均やRSI(相対力指数)のような派生指標を時系列として扱う考え方と同じで、ボラティリティに限らずどんな性質 $\xi(\bm{x})$ にも一般化できます。

元の価格系列から派生するボラティリティ時系列

上の図は、メガショック(急激な価格変動)を含む価格系列(上)と、そこから計算したボラティリティ時系列(下)です。急変動が起きた区間だけ、ボラティリティ時系列に明確な山ができています。トレンドを見ただけでは気づきにくい特徴が、派生時系列にすると視覚的にもモデル的にも捉えやすくなる——これがこの設計の狙いです。

3.2 2本の独立したオートエンコーダ

論文は、価格系列 $\bm{x}$ 用の全結合オートエンコーダ $E_t$ と、ボラティリティ系列 $\bm{v}$ 用の全結合オートエンコーダ $E_v$ を別々に学習します。両方とも次の再構成損失で学習される、通常のオートエンコーダです。

$$ \begin{equation} \min \; \lVert \bm{x}_i – \bar{\bm{x}}_i \rVert_2^2, \qquad \min \; \lVert \bm{v}_i – \bar{\bm{v}}_i \rVert_2^2 \end{equation} $$

ネットワーク構造は、入力サイズ30(1ヶ月分の系列長)に対し、エンコーダの隠れ層が512・256・16(最後が潜在空間)、デコーダはその逆順という、比較的小規模な全結合ネットワークです。ReLUを各層に使い、デコーダの最終層だけは非線形を掛けません。

最終的な埋め込みは、2つのエンコーダの出力を連結して正規化したものです。

$$ \begin{equation} E(\bm{x}, \bm{v}) = \mathrm{normalize}\big([E_t(\bm{x});\, E_v(\bm{v})]\big) \end{equation} $$

ツインオートエンコーダのアーキテクチャ

この埋め込みをデータベース中の全時系列について計算し、FAISS(Facebook AI Similarity Search, Johnson et al., 2019)というベクトル検索ライブラリの索引に格納します。検索時は、ユーザーのスケッチからトレンド $\bm{x}$ とそこから計算したボラティリティ $\bm{v}$ の埋め込みを作り、コサイン類似度が最大のデータベースエントリを取得します。

重要な実用上の利点は、既存の時系列データベースが「2次曲線近似」のような硬直したトレンド定義をユーザーに要求するのに対し、オートエンコーダはどんな概形のスケッチでも自然に近似・マッチングできることです。柔軟性と検索速度の両方を得られる、というのが論文の主張です。


4. データセット構築 — 離散平均回帰過程とメガショック

金融の時系列とキャプションが対になったデータセットは存在しないため、論文は合成データを自作します。

4.1 合成株価時系列

論文が使うのは、金融市場のモデル化にも生物学的過程のモデル化にも使われる離散平均回帰過程です。

$$ \begin{equation} r_t = \max\{0,\; \kappa \bar{r} + (1-\kappa) r_{t-1} + u_t\}, \qquad r_0 = \bar{r} \end{equation} $$

ここで $\bar{r}$ は系列の平均値、$\kappa$ は平均回帰の強さを決めるパラメータ、$u_t \sim \mathcal{N}(0,\sigma^2)$ はランダムノイズです。これに方向性を持たせるためトレンド $T$ を各ステップに加え、さらに稀に大きな価格変動が起きるメガショックを導入します。メガショックは確率 $p$ で発生し、$\sigma_{shock} \gg \sigma$ を満たす $\mathcal{N}(0, \sigma_{shock}^2)$ からサンプリングされます(論文はメガショックの着想を Byrd, 2019 の市場シミュレーション研究から得ています)。生成された系列は224×224の画像として描画されます。

合成株価データセットの4つのレジーム例

上図は、本記事で複製した生成器による4つのレジームです。低ボラティリティの上昇/下降トレンドは滑らかな系列になりますが、高ボラティリティかつメガショックを含む系列は、急激なジャンプを伴う荒い値動きになります。右下の「トレンドなし」の系列も、$\kappa$ が小さい(弱い平均回帰)ためランダムウォーク的にドリフトしており、これは自然な挙動です。

4.2 キャプションの3段階生成

パラメータの値から自動でキャプションを生成する際、論文は3段階のアプローチを試しています。

  • Unfiltered:各パラメータ($\bar{r}, \kappa, \sigma, T, p, \sigma_{shock}$)の数値を直接、対応する感情表現(”upward”, “declining” 等)に変換する素朴な方法。しかしパラメータ間に相互依存があるため、特に高ボラティリティ設定で「見た目」と食い違うキャプションが生成されることが判明しました。
  • Filtered:生成後の系列に対し、線形回帰の傾きでトレンドのレジームを、勾配の閾値超えでショックのレジームを、事後的に再判定します。ボラティリティも標準偏差ではなく実行中の偏差(running deviation)に基づいて再ラベル付けすることで、より一貫性のあるキャプションになりました。
  • Filtered+:手作業で作れるキャプションの語彙には限りがあるため、ChatGPTに少数の例文を与えて意味的に類似したバリエーションを大量生成させ、語彙数を36から500以上に拡張。これによりデータセットも4,000サンプルから16,000サンプルへと拡大しています。

実データについては、Yahoo Financeから GOOG・AMD・INBX・DAWN(それぞれ高・中・低ボラティリティのレジームを代表する銘柄)を取得し、60ステップの窓でオーバーラップサンプリングして1,500〜3,000件の時系列データセットを構築しています。低流動性の銘柄ほどボラティリティが高いという金融の経験則(Bouchaud et al., 2018)を使い、流動性でボラティリティのラベルを付けています。


5. 評価指標とベースライン

5.1 テキストベース検索

評価には Rank@9(in-sample/out-of-sample)と、多様性(Diversity)という指標が使われます。多様性は「全クエリを通して検索されたユニークな時系列画像の割合」で、値が高いほど「同じ画像ばかり返す」というモード崩壊を起こしていないことを意味します。

比較対象は2つです。

  • Neural Net Classifier:検索を分類問題として再定式化し、Word2Vec(Text8データセットで事前学習)でキャプションを埋め込み、各データベースエントリに対する類似度を固定出力ノードで直接回帰する方式。ネットワーク構造がデータベースのサイズに固定されるため、新しいエントリの追加には全体の再学習が必要という柔軟性の欠如があります。
  • Word2Vec-UMAP:深層エンコーダの代わりに伝統的な表現学習(テキスト側=Word2Vec、画像側=UMAP)を使い、同じ対照損失と射影ヘッドで位置合わせする方式。50,176次元(224×224を平坦化)の画像空間でUMAPを学習するコストが高く、訓練は4,000枚に制限されています。

5.2 スケッチベース検索

評価指標は MAPE(トレンドの平均絶対誤差率、ただし論文は百分率でなく比で表示)、CORR(ピアソン相関係数)、計算時間(平均・標準偏差)です。ベースラインは3つ。

  • BF(総当たり探索):クエリと全データベースエントリの間のユークリッド距離だけで最近傍を探す。ボラティリティ情報は無視。
  • BF_avg:元の時系列とボラティリティ時系列、両方のユークリッド距離を平均して最近傍を探す。
  • UMAP:時系列とボラティリティ時系列をそれぞれUMAPで埋め込み、連結・正規化してFAISSに格納。次元数はオートエンコーダに合わせている。

6. 実験結果

6.1 テキストベース検索(合成データ)

論文Table1: 合成データでのテキスト検索結果

3種のフィルタリング設定すべてで、提案手法(Deep Encoding Networks)はベースラインを上回っています。特に Filtered+ が Rank@9 out-of-sample で 0.89 と、Filtered(0.71)やno-filtering(0.51)を大きく上回りました。ただし興味深いことに、多様性はFiltered(0.50)がFiltered+(0.30)より高いという結果も出ています。ChatGPTでキャプションの語彙を増やし精度を上げた一方で、検索結果がやや画一化する(同じような「模範解答」的な画像に収束しやすい)というトレードオフが生じている可能性があり、論文自身は明示的に議論していませんが、注目すべき副作用です。

6.2 テキストベース検索(実データ)

実データでの結果は、合成データで学習したモデルをそのまま使う場合と、実データで再学習する場合を比較しています。興味深いのは、ボラティリティのラベル付けを「実行中偏差に基づくフィルタリング」に変更しても、必ずしも精度が上がらず、むしろ悪化することがあるという結果です。論文は「流動性に基づくシンプルなラベル付けの方が、事後フィルタリングより一貫性があった」可能性を示唆しています。一方で、データセットを1,500件から3,000件に拡大して再学習すると、in-sample Rank@9 が0.69から0.75へ向上しており、データを増やせば実データでも合成データと同等の性能に近づくと論文は結論づけています。

6.3 スケッチベース検索

論文Table3: スケッチ検索の精度と速度のトレードオフ

トレンドそのものの一致度(TS-MAPE/CORR)では、総当たり探索(BF)が最良という結果でした。これは当然で、BFはクエリと全データの間のユークリッド距離を愚直に最小化しているからです。しかし、この距離の近さはボラティリティの一致には結びつきません。ボラティリティ一致度(Vol-MAPE/CORR)で見ると、ボラティリティ情報を明示的に組み込んだ手法(BF_avg・UMAP・AE)がBFを上回り、オートエンコーダはボラティリティ指標で最良かそれに近い成績を残しています。

そして最大の実用上の差は計算時間です。UMAPは新しいクエリのたびにUMAP変換自体を計算し直す必要があり、平均7.7秒かかるのに対し、オートエンコーダはわずか0.019秒——400倍以上高速です。UMAPとAEは同じ次元のFAISS索引を使っているにもかかわらず、これほどの差が生まれるのは、UMAPの「新しい点を既存の低次元空間に射影する」処理そのものが重いためです。ニューラルネットのフォワードパス1回で済むオートエンコーダの構造的な優位性がここに表れています。


7. Python実装

理論を実装で確かめていきます。まず、論文の合成データ生成器を複製します。

import numpy as np

def gen_series(L=60, r_bar=50.0, kappa=0.05, sigma=1.0, trend=0.0,
                p_shock=0.0, sigma_shock=8.0, rng=None):
    r = np.zeros(L); r[0] = r_bar
    for t in range(1, L):
        u = rng.normal(0, sigma)
        shock = rng.normal(0, sigma_shock) if rng.random() < p_shock else 0.0
        r[t] = max(0.0, kappa * r_bar + (1 - kappa) * r[t - 1] + u + trend + shock)
    return r

def vol_ts(x, m=4):
    L = len(x); v = np.zeros(L)
    for i in range(L):
        lo, hi = max(0, i - m), min(L, i + m + 1)
        v[i] = x[lo:hi].std()
    return v

論文本体は基本の $r_t$ の式のみを明示し、トレンドとメガショックをどう結合するかは文章で説明するにとどめているため、本実装では自然な解釈として両者を式の中に直接加算しています。前節の図2・図3はこのコードで生成しました。

7.1 対照学習のソフトターゲットを数値で確認する

2節で見たソフトターゲット $S_{target}$ が、同じレジームを指す言い換えペアにどう重みを配るかを確認します。バッチ内に6件のペアを用意し、item0・item1を「高ボラティリティ上昇」の言い換え、item2・item3を「低ボラティリティ横ばい」の言い換え、item4・item5を単独のレジームとします。

rng = np.random.default_rng(3)

def unit(x):
    return x / np.linalg.norm(x)

d = 16
regimes = [unit(rng.normal(size=d)) for _ in range(4)]

def noisy(base, scale=0.15):
    return unit(base + rng.normal(scale=scale, size=d))

group = [0, 0, 1, 1, 2, 3]     # 0,1が同一レジーム / 2,3が同一レジーム / 4,5は単独
t = np.stack([noisy(regimes[g]) for g in group])   # テキスト側埋め込み(ダミー)
v = np.stack([noisy(regimes[g]) for g in group])   # 画像側埋め込み(ダミー)
tau = 0.3

def softmax(x, axis=-1):
    x = x - x.max(axis=axis, keepdims=True)
    e = np.exp(x); return e / e.sum(axis=axis, keepdims=True)

S_tt = (t @ t.T) / tau
S_vv = (v @ v.T) / tau
S_target = softmax((S_tt + S_vv) / (2 * tau), axis=1)

print("S_target[0,1](同一レジームの言い換え) =", round(S_target[0, 1], 3))
print("S_target[0,4](無関係なレジーム)       =", round(S_target[0, 4], 3))
S_target[0,1](同一レジームの言い換え) = 0.079
S_target[0,4](無関係なレジーム)       = 0.0

ソフトターゲットとハードターゲットの比較

素朴なCLIPの対角ラベル(単位行列)であれば、item0の画像はitem1のテキストとの類似度を強制的に0にされてしまいます。しかし実際には、item0とitem1は同じレジームの言い換えであり、意味的には近い関係にあるはずです。ソフトターゲット $S_{target}$ は、この同一レジームのペア(0-1、2-3)にそれぞれ0.08、0.12の確率質量を正しく配分し、無関係なペア(0-4など)には0を割り当てています。これが、バッチ内に類似したキャプションが複数存在する金融データセット特有の状況で、この設計が効く理由です。

7.2 ツインオートエンコーダによる検索実験

続いて、3節のツインオートエンコーダを実装し、「トレンドだけの埋め込み」と「トレンド+ボラティリティの埋め込み」で検索精度がどう変わるかを検証します。トレンド方向(上昇/下降)とボラティリティレジーム(低/高)の2×2、計4クラスの合成データを作ります。

import torch, torch.nn as nn

torch.manual_seed(0); rng = np.random.default_rng(0)
L = 60
configs = [
    ("up_low",   dict(sigma=0.6, trend=0.5)),
    ("down_low", dict(sigma=0.6, trend=-0.5)),
    ("up_high",  dict(sigma=2.4, trend=0.5)),
    ("down_high",dict(sigma=2.4, trend=-0.5)),
]
N_per = 200
X, V, Y = [], [], []
for label, (name, kw) in enumerate(configs):
    for _ in range(N_per):
        s = gen_series(L=L, rng=rng, **kw)
        X.append(s); V.append(vol_ts(s)); Y.append(label)
X = np.array(X); V = np.array(V); Y = np.array(Y)

論文と同じくmin-max正規化し、80/20に分割してから、価格系列用・ボラティリティ系列用の2本のオートエンコーダ(60→512→256→16)を学習します。

def minmax(A):
    lo, hi = A.min(), A.max()
    return (A - lo) / (hi - lo + 1e-8)

Xn, Vn = minmax(X), minmax(V)
idx = rng.permutation(len(Xn)); n_tr = int(0.8 * len(idx))
tr, te = idx[:n_tr], idx[n_tr:]
Xtr = torch.tensor(Xn[tr], dtype=torch.float32); Xte = torch.tensor(Xn[te], dtype=torch.float32)
Vtr = torch.tensor(Vn[tr], dtype=torch.float32); Vte = torch.tensor(Vn[te], dtype=torch.float32)
Ytr, Yte = Y[tr], Y[te]

class AE(nn.Module):
    def __init__(self, L=60, h=(512, 256, 16)):
        super().__init__()
        self.enc = nn.Sequential(nn.Linear(L, h[0]), nn.ReLU(), nn.Linear(h[0], h[1]), nn.ReLU(), nn.Linear(h[1], h[2]))
        self.dec = nn.Sequential(nn.Linear(h[2], h[1]), nn.ReLU(), nn.Linear(h[1], h[0]), nn.ReLU(), nn.Linear(h[0], L))
    def forward(self, x):
        z = self.enc(x); return z, self.dec(z)

def train_ae(model, data, epochs=300, lr=1e-3):
    opt = torch.optim.Adam(model.parameters(), lr=lr)
    for _ in range(epochs):
        opt.zero_grad(); z, xr = model(data); loss = ((xr - data) ** 2).mean()
        loss.backward(); opt.step()
    return loss.item()

E_t, E_v = AE(L), AE(L)
loss_t = train_ae(E_t, Xtr); loss_v = train_ae(E_v, Vtr)

学習した埋め込みで、テスト集合の各クエリについて訓練集合内の最近傍(コサイン類似度)を探し、トレンド方向とボラティリティレジームがそれぞれ一致するかを調べます。

with torch.no_grad():
    zt_tr, _ = E_t(Xtr); zt_te, _ = E_t(Xte)
    zv_tr, _ = E_v(Vtr); zv_te, _ = E_v(Vte)

def l2norm(z):
    return z / (z.norm(dim=1, keepdim=True) + 1e-8)

e_trend_tr, e_trend_te = l2norm(zt_tr), l2norm(zt_te)                       # trendのみ
e_full_tr = l2norm(torch.cat([l2norm(zt_tr), l2norm(zv_tr)], dim=1))        # trend+ボラ
e_full_te = l2norm(torch.cat([l2norm(zt_te), l2norm(zv_te)], dim=1))

def split_labels(Yarr):
    trend = np.where(np.isin(Yarr, [0, 2]), 1, 0)
    vol = np.where(np.isin(Yarr, [0, 1]), 0, 1)
    return trend, vol

trend_te, vol_te = split_labels(Yte); trend_tr, vol_tr = split_labels(Ytr)

def nn_match(emb_te, emb_tr, lab_te, lab_tr):
    sims = emb_te @ emb_tr.T
    nn_idx = sims.argmax(dim=1).numpy()
    return (lab_tr[nn_idx] == lab_te).mean()

print("trendのみ  : trend一致=", nn_match(e_trend_te, e_trend_tr, trend_te, trend_tr),
      " vol一致=", nn_match(e_trend_te, e_trend_tr, vol_te, vol_tr))
print("trend+ボラ: trend一致=", nn_match(e_full_te, e_full_tr, trend_te, trend_tr),
      " vol一致=", nn_match(e_full_te, e_full_tr, vol_te, vol_tr))
trendのみ  : trend一致= 0.981  vol一致= 0.838
trend+ボラ: trend一致= 0.625  vol一致= 0.963

検索一致率の比較:trendのみ vs trend+ボラ

trendのみの埋め込みでもボラティリティは0.838とそこそこ一致します。これは、価格系列の生の振れ幅(振幅)にボラティリティの情報が暗黙的に漏れ出しているためです。一方、ボラティリティ埋め込みを結合すると、ボラティリティ一致率は0.963まで上がりますが、トレンド一致率が0.981から0.625へと大きく低下しています。

これは論文が明示的に議論している現象ではありませんが、本記事の検証で見つかった重要な実装上の注意点です。原因は単純な代数で説明できます。2つの単位ベクトルを連結して再正規化したコサイン類似度は、連結前の各ブロックのコサイン類似度の平均になります($\langle[\bm{a};\bm{b}], [\bm{a}’;\bm{b}’]\rangle = \bm{a}\cdot\bm{a}’ + \bm{b}\cdot\bm{b}’$、各ブロックが単位ノルムなら全体のノルムは $\sqrt{2}$ で共通)。ここでボラティリティのクラス間差(低ボラ vs 高ボラ、振幅が数倍違う)はトレンドのクラス間差(緩やかな上昇 vs 下降、ノイズに埋もれがち)よりずっとシャープです。等ウェイトで連結しても、クラス分離がシャープな方の枝が最近傍検索を実質的に支配してしまうのです。論文自身のTable3では、AEのTS-MAPE/CORRはBFよりやや劣る程度(0.276 vs 0.084、相関0.824 vs 0.983)に留まっており、本記事の合成実験ほど極端な低下は起きていません。これはおそらく、論文のデータセットにおける実際のボラティリティ差がここまで極端ではなく、両ブランチの「分離のシャープさ」がもう少し拮抗しているためだと考えられます。いずれにせよ、複数モダリティの埋め込みを単純に連結する設計には、片方のブランチが支配的になるリスクがあるという教訓は、マルチブランチの埋め込み設計全般に当てはまる実用上の注意点です。


8. まとめ

Bamford et al., “Multi-Modal Financial Time-Series Retrieval Through Latent Space Projections” (ICAIF 2023, Best Industry Paper Award) を、原論文を精読しながらたどりました。

  • 問題提起:既存の時系列データベースはSQLライクな硬直したクエリしか提供せず、「高ボラティリティで上昇中」のような直感的な検索ができない。
  • アーキテクチャ:エンコーダで異なるモダリティを共有の潜在空間に射影し、コサイン類似度で検索するTraining→Database→Retrievalの枠組み。
  • テキスト検索:ResNet50(画像化した時系列)とSentence-BERT(自然言語)をCLIP型の対照学習で位置合わせ。ただし対角のハードラベルではなく、モダリティ内自己類似度をブレンドしたソフトターゲットを使い、バッチ内の同一レジームペアを正しく扱う。
  • スケッチ検索:価格系列とそこから計算したボラティリティ系列を、別々の全結合オートエンコーダでエンコードし連結する。FAISSでの検索はUMAPベースの手法より400倍以上高速。
  • データセット:離散平均回帰過程+トレンド+メガショックによる合成データと、3段階(Unfiltered/Filtered/Filtered+)のキャプション生成。
  • 実証:本記事の実装でも、ソフトターゲットが同一レジームペアに正しく重みを配ること、そしてツインエンコーダの単純結合がトレンド一致率とボラティリティ一致率のトレードオフを生むことを数値で確認した。

金融に限らず、レジームを持つ時系列データベース全般に応用できる考え方です。SQLでは表現しづらい「文脈」を自然言語やスケッチで直接指定できるようにするというアイデアは、時系列データベースのユーザー体験を変えるポテンシャルを持っています。

主な参考文献

  • T. Bamford, A. Coletta, E. Fons, S. Gopalakrishnan, S. Vyetrenko, T. Balch, M. Veloso, “Multi-Modal Financial Time-Series Retrieval Through Latent Space Projections,” ICAIF 2023. arXiv:2309.16741.
  • A. Radford et al., “Learning Transferable Visual Models From Natural Language Supervision,” ICML 2021 (CLIP).
  • K. He, X. Zhang, S. Ren, J. Sun, “Deep Residual Learning for Image Recognition,” arXiv:1512.03385, 2015.
  • N. Reimers, I. Gurevych, “Sentence-BERT: Sentence Embeddings using Siamese BERT-Networks,” arXiv:1908.10084, 2019.
  • L. McInnes, J. Healy, J. Melville, “UMAP: Uniform Manifold Approximation and Projection for Dimension Reduction,” arXiv:1802.03426, 2018.
  • J. Johnson, M. Douze, H. Jégou, “Billion-scale similarity search with GPUs,” IEEE Transactions on Big Data, 7(3), 535–547, 2019.
  • J.-P. Bouchaud, J. Bonart, J. Donier, M. Gould, “Trades, quotes and prices: financial markets under the microscope,” Cambridge University Press, 2018.