Newer
Older
TelosDB / journals / 20260219-0009-純RustによるSVD実装とLSA精度向上.md

20260219-0009-純RustによるSVD実装とLSA精度向上

作業実施の理由

LSA(Latent Semantic Analysis)の検索機能において、現状の実装がダミーデータ(全てのベクトルがゼロ、または同一)を返していたため、検索結果に意味のある差異が生じていなかった。ndarray-linalg などの外部LAPACK依存を避けつつ、純粋なRust実装(ndarrayのみ)で特異値分解(SVD)を実装し、精度の高い意味検索を実現する必要があった。

指示内容

  • 背景: lsa.rstrain 関数がダミー実装であり、検索結果が常に同一(1.0 または 0.0)であった。
  • 観点: 外部の動的ライブラリ(OpenBLAS等)に依存せず、Windows環境で安定して動作する数理ロジックを実装すること。
  • 意図: 起動時や再学習時に、文書集合から正しく潜在概念を抽出し、クエリに対して意味的に近い文書が上位に来るようにする。

指摘事項とその対応

  • 指摘: 検索スコアに差がない、または 0 になる。
  • 対応:
    1. TermDocumentMatrixBuilder に TF-IDF 重み付けを実装し、単語の重要度を反映させた。
    2. LsaModel::trainべき乗法(Power Method)とデフレーション(Deflation) による、反復的截断SVD(Truncated SVD)を実装した。
    3. LSA投影ベクトルを単位長に正規化することで、sqlite-vec(L2距離)での近傍検索がコサイン類似度と等価になるようにした。
    4. ユニットテストを追加し、「山」というクエリに対して山関連のドキュメントが最も高く、無関係なドキュメントが低くなることを確認した。

作業詳細

AIエージェントは以下の手順で実装を行った。

  1. TF-IDFの実装:

    • build_matrix 内で文書頻度(DF)を計算し、ln(N/(df+1)) + 1 による IDF を適用。
    • 文書内の最大単語頻度で正規化した TF を使用。
  2. SVDアルゴリズムの実装:

    • 行列 $A A^T$ に対してべき乗法を適用し、左特異ベクトル(単語-概念)を抽出。
    • 抽出後の成分をデフレーション($A_{next} = A - s u v^T$)で除去し、順次上位 $k$ 個の主成分を特定。
    • 数値的な安定性のため、初期ベクトルに摂動を加え、イテレーションを100回に設定。
  3. 正規化と距離計算の改善:

    • project_query において、射影後のベクトルを $L2$ ノルムで正規化。
    • これにより、DBに保存されたベクトル間の $L2$ 距離を最小化することが、コサイン類似度を最大化することと直結するようになった。
  4. 検証:

    • ユニットテスト test_lsa_variance を作成。
    • Similarities: [0.965, 0.061, 0.0] のように、意味的に近い文書にのみ高いスコアが出ることを実証した。

AI視点での結果

純Rust実装のSVDにより、外部依存のトラブル(DLLの不一致やビルドエラー)を完全に回避しつつ、実用的な精度のLSA検索が可能となった。 特に、截断SVD(Truncated SVD)は必要な上位 $k$ 成分のみを抽出するため、今回の TelosDB のような小〜中規模な文書管理には非常に効率的である。 今後は、文書数が増えた際の計算負荷を監視し、必要であればより高度なアルゴリズム(Lanczos法やRandomized SVD)へのアップグレードを検討する余地がある。

graph TD
    A[文書集合] --> B[Tokenizer / Vibrato]
    B --> C[Term-Document Matrix / TF-IDF]
    C --> D[SVD Training / Power Method]
    D --> E[LSA Model / Topic Space]
    F[Query] --> G[LSA Projection / Normalized]
    G --> H[sqlite-vec / Vector Search]
    H --> I[Scored Results]
    E -.-> G