距離学習入門 ~様々なタスクに応用できる機械学習手法~

距離学習(Metric Learning)は、データ間の類似度を学習する 機械学習の一手法です。従来の教師あり学習が、与えられたデータから特定のラベルや値を予測することを目的とするのに対し、距離学習は、データ間の関係性そのものを学習します。
距離学習は、様々な分野で活用されています。例えば、画像検索では、画像間の視覚的な特徴を捉え、ある画像と似た画像を効率的に探し出すことができます。これにより、顔認証システムなどを構築することが可能です。また、推薦システムでは、ユーザーの過去の行動履歴から、そのユーザーが好むであろうアイテム同士の関連性を学習し、新たなアイテムを提案するといった利用が可能です。
さらに、深層ニューラルネットワークを用いてを距離学習に応用したものを深層距離学習と呼びますが、今回はmetric-learnと呼ばれるPythonパッケージに実装されているアルゴリズム(深層学習モデルは含まない)に焦点を当てて、距離学習とはどのようなものか解説します。
距離学習とは?
距離学習(Metric Learning)とは、データ間の類似度を学習する機械学習の一手法です。従来の機械学習が、与えられたデータから特定のラベルや値を予測することを目的とするのに対し、距離学習は、データ間の関係性そのものを学習します。
より具体的に言うと、距離学習は、データ間の距離を適切に定義し直すことで、あるデータと類似したデータ同士を近づけ、異なるデータ同士を遠ざけるような空間へデータを変換する技術です。
なぜ距離学習が必要なのか?
- データの複雑さ: 多くの現実世界のデータは、単純なユークリッド距離だけでは捉えきれない複雑な構造を持っています。
- 距離は、データ間の類似性を測る手段として重要です。
- 近いデータ同士を類似、遠いデータ同士を非類似と見なします。
- タスク依存性: 同じデータであっても、異なるタスクでは異なる距離の定義が適している場合があります。
距離学習のメリット
- 性能向上: 適切な距離を用いることで、様々な機械学習タスク(分類、クラスタリング、推薦など)の性能を向上させることができます。
- データ理解: データ間の関係性を可視化したり、特徴を抽出したりすることで、データの理解を深めることができます。
距離学習の応用例
- 画像検索: 画像間の視覚的な特徴を捉え、類似画像を検索する。
- 推薦システム: ユーザーの過去の行動履歴から、そのユーザーが好むであろうアイテムを推薦する。
- 顔認識: 顔画像間の類似度を計算し、個人を特定する。
- 自然言語処理: 文書間の意味的な類似度を計算し、文書分類や情報検索を行う。
距離学習の手法
距離学習には様々な手法が存在しますが、大きく分けて以下の2つに分類できます。
- マハラノビス距離学習: データの共分散構造を考慮した距離を学習する手法です。
- 深層距離学習: 深層学習を用いて、より複雑な特徴表現を学習し、距離を定義する手法です。
metric-learn とは?
metric-learn は、Python で実装されたオープンソースのパッケージで、データ間の距離の測り方(メトリック)を学習することを目的としています。機械学習において、データ間の距離を適切に測ることは、分類やクラスタリングなどのタスクの精度向上に大きく貢献します。
- データに適した距離を自動で学習: metric-learn は、与えられたデータセットから、そのデータの特性に最も合った距離の測り方(メトリック)を自動的に学習します。これにより、手作業でメトリックを定義する手間を省き、より効果的な分析が可能になります。
- scikit-learn との seamless な連携: scikit-learn は、Python で最も広く利用されている機械学習ライブラリのひとつです。metric-learn は scikit-learn との互換性を重視しており、scikit-learn の豊富な機能やパイプラインと組み合わせて使用することができます。
- 多様なアルゴリズム: metric-learn は、教師あり学習(ラベル付きデータを使用)と弱教師あり学習(データ間のペアやトリプレットの関係を用いた学習)の両方に対応した、複数の距離学習アルゴリズムを実装しています。これにより、様々なデータセットやタスクに対応することができます。
- 使いやすさ: インストールも簡単で、直感的な API を提供しているため、初心者でも気軽に利用できます。
教師あり手法
アルゴリズム | 特徴 | 強み | 弱み | 適用例 |
---|---|---|---|---|
Large Margin Nearest Neighbor Metric Learning (LMNN) | k-NN分類の精度を向上させることを目的としたアルゴリズム。マージン最大化により、同じクラスのサンプルは近づけ、異なるクラスのサンプルは遠ざける。 | k-NN分類器との組み合わせで高い性能を発揮。 | ハイパーパラメータのチューニングが重要。計算コストが高い場合がある。 | 画像分類、テキスト分類 |
Neighborhood Components Analysis (NCA) | スムーズな確率的な近傍グラフを作成し、分類精度を向上させるアルゴリズム。確率的な遷移行列を学習することで、データの低次元表現を得る。 | 次元削減と分類を同時に行える。 | ハイパーパラメータのチューニングが重要。計算コストが高い場合がある。 | 画像分類、音声認識 |
Local Fisher Discriminant Analysis (LFDA) | 局所的なFisher判別分析を行い、局所的な線形変換を学習するアルゴリズム。各データ点の近傍において、クラス内分散を小さくし、クラス間分散を大きくする。 | 局所的な構造を捉えることができる。 | ハイパーパラメータのチューニングが重要。計算コストが高い場合がある。 | 画像分類、顔認識 |
Metric Learning for Kernel Regression (MLKR) | カーネル回帰と距離学習を組み合わせたアルゴリズム。カーネル関数のパラメータを学習することで、非線形な関係をモデル化できる。 | 非線形なデータに対しても有効。 | カーネル関数の選択が重要。計算コストが高い場合がある。 | 回帰問題、時系列データ分析 |
弱教師あり手法
アルゴリズム | 特徴 | 強み | 弱み | 適用例 |
---|---|---|---|---|
Information Theoretic Metric Learning (ITML) | 相互情報量に基づいて、クラス内距離を縮め、クラス間距離を拡げる。 | 相互情報量という情報理論的な概念に基づいており、直感的な解釈がしやすい。 | ハイパーパラメータのチューニングが重要。 | 画像検索、テキスト分類 |
Sparse High-Dimensional Metric Learning (SDML) | L1ノルムを用いて、スパースな線形変換行列を学習する。高次元データに対して有効。 | 高次元データに対して有効。スパースな解を得ることができる。 | ハイパーパラメータのチューニングが重要。 | テキスト分類、遺伝子データ分析 |
Relative Components Analysis (RCA) | 相対的な比較情報から、低次元空間への射影を学習する。 | 低次元空間への射影を学習することで、可視化やクラスタリングに有効。 | 相対的な比較情報が十分に必要。 | 画像検索、顔認識 |
Metric Learning with Application for Clustering with Side Information (MMC) | クラスタリングと距離学習を統合したアルゴリズム。サイド情報(部分的なラベル情報など)を利用して、クラスタリングの精度を向上させる。 | クラスタリングと距離学習を統合することで、より柔軟な学習が可能。 | サイド情報の質に依存する。 | 文書クラスタリング、ソーシャルネットワーク分析 |
Sparse Compositional Metric Learning (SCML) | 複数の基底行列を組み合わせることで、複雑な距離メトリクスを学習する。 | 複雑なデータに対しても有効。 | 基底行列の数の設定が重要。 | 画像分類、オブジェクト認識 |
Metric Learning from Relative Comparisons by Minimizing Squared Residual (LSML) | 相対的な比較情報から、最小二乗法を用いて距離メトリクスを学習する。 | 計算が高速。 | 相対的な比較情報が十分に必要。 | 画像検索、顔認識 |
metric-learn の使い方
metric-learn は、以下のようにpipコマンド、またはcondaコマンドから簡単にインストールできます。
$ pip install metric-learn # pip コマンドを使用する場合
$ conda install -c conda-forge metric-learn # conda コマンドを使用する場合
metric-learn のお試し
では、Irisデータセット(3種類のあやめの花の分類)を利用して、距離学習を試してみます。このデータセットは、4つの説明変数と3種類のラベルを持つため、教師ありの距離学習手法を使用することにします。各距離学習モデルは、4次元データ(4つの説明変数のベクトル)から、2次元の埋め込み表現を学習するように実装します。
LMNNの実装
from metric_learn import LMNN def train_lmnn(x_train: np.ndarray, y_train: np.ndarray) -> LMNN: lmnn = LMNN( init="auto", # 線形変換の初期化: "auto", "pca", "identity", "random", または numpy 配列 の形状 (tuple) n_neighbors=5, # 考慮する隣接エッジの数 (自己エッジは含まない) min_iter=50, # 最適化の最小反復回数 max_iter=1000, # 最適化の最大反復回数 learn_rate=1e-6, # 最適化の学習率 convergence_tol=0.001, # 最適化の許容範囲: 目的値が convergence_tol 未満になった場合に最適化を停止 verbose=True, # 最適化の進行状況を表示するかどうか regularization=0.5, # pull-termとpush-termの相対的な重み: 0.5 は相対的に等しい重みを意味する n_components=2, # 埋め込み空間の次元 random_state=12345, # ランダムシード ) lmnn.fit(x_train, y_train) return lmnn
NCAの実装
from metric_learn import NCA def train_nca(x_train: np.ndarray, y_train: np.ndarray) -> NCA: nca = NCA( init="auto", # 線形変換の初期化: "auto", "pca", "identity", "random", または numpy 配列 の形状 (tuple) n_components=2, # 埋め込み空間の次元 max_iter=100, # 最適化の最大反復回数 tol=None, # 最適化の許容範囲: 目的値が tol 未満になった場合に最適化を停止 verbose=True, # 最適化の進行状況を表示するかどうか random_state=12345, # ランダムシード ) nca.fit(x_train, y_train) return nca
LFDAの実装
from metric_learn import LFDA def train_lfda(x_train: np.ndarray, y_train: np.ndarray) -> LFDA: lfda = LFDA( n_components=2, # 埋め込み空間の次元 k=None, # 局所スケーリングで使用される最近傍の数: None の場合、デフォルトは min(7, n_features - 1)となる embedding_type="weighted", # 埋め込み空間内のメトリックの種類: "weighted", "orthonormalized", または "plain" ) lfda.fit(x_train, y_train) return lfda
MLKRの実装
from metric_learn import MLKR def train_mlkr(x_train: np.ndarray, y_train: np.ndarray) -> MLKR: mlkr = MLKR( n_components=2, # 埋め込み空間の次元 init="auto", # 線形変換の初期化: "auto", "pca", "identity", "random", または numpy 配列 の形状 (tuple) tol=None, # 最適化の許容範囲: 目的値が tol 未満になった場合に最適化を停止 max_iter=1000, # 最適化の最大反復回数 verbose=True, # 最適化の進行状況を表示するかどうか random_state=12345, # ランダムシード ) mlkr.fit(x_train, y_train) return mlkr
埋め込み表現を可視化するための共通関数を定義
import matplotlib.pyplot as plt import numpy as np def show_embeddings(embeddings: np.ndarray, labels: np.ndarray, name: str) -> None: colors = ["blue", "red", "green"] for label in [0, 1, 2]: index = np.where(labels == label) x = embeddings[index] plt.scatter(x[:, 0], x[:, 1], s=10, c=colors[label], edgecolors=colors[label], label=str(label)) plt.title(name) plt.xlabel("$x_0^{{embedding}}$") plt.ylabel("$x_1^{{embedding}}$") plt.legend()
各アルゴリズムの比較
では、上記のコードを使用しつつ、各距離学習アルゴリズムを比較するコードを作成します。
from sklearn.datasets import load_iris # ここに上記で定義したコードが記述されているが、ここの説明では割愛する... if __name__ == "__main__": train_funcs = { "LMNN": train_lmnn, "NCA": train_nca, "LFDA": train_lfda, "MLKR": train_mlkr, } iris_data = load_iris() data_x = iris_data['data'] data_y = iris_data['target'] plt.figure(figsize=(15, 4)) plt.style.use('ggplot') for i, (algorithm, trainer) in enumerate(train_funcs.items()): plt.subplot(1, 4, i + 1) # 距離学習の実行 model = trainer(data_x, data_y) # 学習済みのモデルを使用して、データの埋め込み表現を取得 embeddings = model.transform(data_x) # 埋め込み表現の可視化 show_embeddings(embeddings, data_y, algorithm) plt.tight_layout() plt.savefig("iris_metric_learn.png") plt.show()
上記のコードを実行すると、次のような結果が得られます。各アルゴリズムとも、それぞれのラベルついて、まずまずのクラスタが出来ていることが確認できます。

まとめ
距離学習は、データ間の類似度を学習する機械学習の手法です。高次元のデータから、低次元の埋め込み表現も学習できることが特徴で、分類タスクやクラスタリングの精度を改善する前処理としても有効です。
今回は、metric-learnという距離学習ライブラリの中から、教師あり手法の実装例を紹介しました。この記事で紹介できなかった弱教師ありの手法については、公式のドキュメントを参照してください。
また、距離学習のライブラリには、metric-learnのほかにpyDMLなどがあります。ディープラーニングをベースにした深層距離学習のライブラリではpytorch-metric-learningなどが有名です。特に、深層距離学習は、大規模データからデータ感の類似度を学習するための強力なツールになります。今後、深層距離学習フォーカスして、実際の使い方について紹介できれば思います。
More Information:
- arXiv:1812.05944, Juan Luis Suárez-Díaz, Salvador García, Francisco Herrera, 「A Tutorial on Distance Metric Learning: Mathematical Foundations, Algorithms, Experimental Analysis, Prospects and Challenges (with Appendices on Mathematical Background and Detailed Algorithms Explanation)」, https://arxiv.org/abs/1812.05944
- arXiv:1908.04710, William de Vazelhes, CJ Carey, Yuan Tang, Nathalie Vauquier, Aurélien Bellet, 「metric-learn: Metric Learning Algorithms in Python」, https://arxiv.org/abs/1908.04710