TensorFlow : Tutorials : データ表現 : カーネル法を使用した線形モデルの改良 (翻訳/解説)
翻訳 : (株)クラスキャット セールスインフォメーション
作成日時 : 11/23/2018 (v1.12.0)
* 本ページは、TensorFlow の本家サイトの Tutorials – Data representation – Improving Linear Models Using Explicit Kernel Methods を翻訳した上で適宜、補足説明したものです:
* サンプルコードの動作確認はしておりますが、適宜、追加改変しています。
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。
- お住まいの地域に関係なく Web ブラウザからご参加頂けます。事前登録 が必要ですのでご注意ください。
- Windows PC のブラウザからご参加が可能です。スマートデバイスもご利用可能です。
◆ お問合せ : 本件に関するお問い合わせ先は下記までお願いいたします。
株式会社クラスキャット セールス・マーケティング本部 セールス・インフォメーション |
E-Mail:sales-info@classcat.com ; WebSite: https://www.classcat.com/ |
Facebook: https://www.facebook.com/ClassCatJP/ |
このチュートリアルでは、(explicit) カーネル法の線形モデルとの結合が (訓練と推論時間を本質的に増やすことなく) 後者の予測の品質をどのように劇的に増加させるかを示します。dual カーネル法とは違い、explicit (primal) カーネル法は訓練/推論時間とメモリ要求の両者の観点から訓練データセットのサイズと共に上手くスケールします。
対象読者: explicit カーネル法に関連した概念の高位な概要を提供しますが、このチュートリアルは主として少なくともカーネル法とサポートベクターマシン (SVM) の基本的な知識を既に持つ読者を対象とします。もしカーネル法を知らないのであれば、イントロダクションのために次のソースのいずれかを参照してください :
- 強力な数学的背景を持つ場合には : Kernel Methods in Machine Learning
- カーネル法 wikipedia ページ
現在、TensorFlow は密な特徴のための explicit カーネル・マッピングだけをサポートします ; TensorFlow は後のリリースで疎な特徴のためのサポートを提供します。
このチュートリアルは ML モデルのために tf.contrib.learn (TensorFlow の高位機械学習 API) Estimator を使用します。この API に馴染みがない場合には、Estimator ガイド で始めるのが良いでしょう。MNIST データセットを使用します。チュートリアルは次のステップから成ります :
- 分類のために MNIST データをロードして準備する
- 単純な線形モデルを構築し、それを訓練し、そして評価データ上でそれを評価します。
- 線形モデルを kernelized 線形モデルを置き換え、再訓練し、そして再評価します。
分類のために MNIST データをロードして準備する
MNIST データセットをロードするために次のユティリティコマンドを実行します :
data = tf.contrib.learn.datasets.mnist.load_mnist()
先のメソッドは (70K サンプルを含む) MNIST データセット 全体をロードしてそれをそれぞれ 55K, 5K, そして 10K サンプルを持つ訓練、検証、そしてテストデータに分割します。各分割は (shape [sample_size, 784] を持つ) 画像のための一つのnumpy 配列と (shape [sample_size, 1] を持つ) ラベルのための一つを含みます。このチュートリアルでは、モデルを訓練して評価するためにそれぞれ訓練と検証分割だけを使用します。
tf.contrib.learn Estimator にデータを供給するために、それを Tensor に変換することは有用です。このため、入力関数を使用します、これは TensorFlow グラフに (実行されたとき) ダウンストリームに使用される Tensor のミニバッチを作成する Ops を追加します。入力関数の更なる背景については、入力関数のこのセクション をチェックしてください。この例では、 tf.train.shuffle_batch Op を使用します、これは numpy 配列を Tensor に変換することに加えて、batch_size と input_fn Ops が実行されるたびに入力をランダム化するか否かを指定することを可能にします (ランダム化は典型的には訓練の間の収束を早めます)。データをロードして準備するための full コードは下のスニペットで示されます。この例では、訓練のためにサイズ 256 のミニバッチをそして評価のためにサンプル全体 (5K エントリ) を使用します。異なるバッチサイズで自由に実験してください。
import numpy as np import tensorflow as tf def get_input_fn(dataset_split, batch_size, capacity=10000, min_after_dequeue=3000): def _input_fn(): images_batch, labels_batch = tf.train.shuffle_batch( tensors=[dataset_split.images, dataset_split.labels.astype(np.int32)], batch_size=batch_size, capacity=capacity, min_after_dequeue=min_after_dequeue, enqueue_many=True, num_threads=4) features_map = {'images': images_batch} return features_map, labels_batch return _input_fn data = tf.contrib.learn.datasets.mnist.load_mnist() train_input_fn = get_input_fn(data.train, batch_size=256) eval_input_fn = get_input_fn(data.validation, batch_size=5000)
単純な線形モデルを訓練する
今では MNIST データセットに渡り線形モデルを訓練できます。10 数字を表わす 10 クラスで tf.contrib.learn.LinearClassifier estimator を使用します。入力特徴は 784-次元密ベクトルを形成し、これは次のように指定できます :
image_column = tf.contrib.layers.real_valued_column('images', dimension=784)
LinearClassifier estimator を構築し、訓練して評価するための full コードは次のようなものです :
import time # Specify the feature(s) to be used by the estimator. image_column = tf.contrib.layers.real_valued_column('images', dimension=784) estimator = tf.contrib.learn.LinearClassifier(feature_columns=[image_column], n_classes=10) # Train. start = time.time() estimator.fit(input_fn=train_input_fn, steps=2000) end = time.time() print('Elapsed time: {} seconds'.format(end - start)) # Evaluate and report metrics. eval_metrics = estimator.evaluate(input_fn=eval_input_fn, steps=1) print(eval_metrics)
次のテーブルは評価データ上の結果を要約します。
メトリック | 値 |
loss | 0.25 to 0.30 |
accuracy | 92.5% |
training time | ~25 seconds on my machine |
(訓練) バッチサイズと訓練ステップの数で実験することに加えて、調整可能な 2, 3 の他のパラメータもあります。例えば、利用可能な optimizer のコレクションから他の optimizer を明示的に選択することにより損失を最小化するために使用される最適化メソッドを変更できます。例として、次のコードは特定の学習率と L2-正則化を持つ Follow-The-Regularized-Leader (FTRL) 最適化ストラテジーを使用する LinearClassifier を構築します。
optimizer = tf.train.FtrlOptimizer(learning_rate=5.0, l2_regularization_strength=1.0) estimator = tf.contrib.learn.LinearClassifier( feature_columns=[image_column], n_classes=10, optimizer=optimizer)
パラメータの値にかかわらず、線形モデルがこのデータセット上で達成できる最大精度はおよそ 93% が上限です。
線形モデルで explicit カーネル・マッピングを使用する
MNIST に渡る比較的高いエラー (~7%) は入力データが線形分離可能ではないことを示します。分類エラーを減じるために explicit カーネル・マッピングを使用します。
直感: 高位のアイデアは入力空間を (可能なより高位次元の) もう一つの特徴空間に変換するために非線型マップを使用することです、そこでは (変換された) 特徴は (殆ど) 線形分類可能でそれからマップされた特徴上で線形モデルを適用します。これは次の図で示されます :
技術的詳細
この例では入力データをマップするために、Rahimi と Recht によるペーパー "Random Features for Large-Scale Kernel Machines" で紹介された、乱択化フーリエ特徴 (Random Fourier Features) を使用します。乱択化フーリエ特徴は次のマッピング :
$$
RFFM(\cdot): \mathbb{R}^d \to \mathbb{R}^D, \quad
RFFM(\mathbf{x}) = \cos(\mathbf{\Omega} \cdot \mathbf{x}+ \mathbf{b})
$$
を通してベクトル \(\mathbf{x} \in \mathbb{R}^d\) を \(\mathbf{x'} \in \mathbb{R}^D\) にマップします。ここで\(\mathbf{\Omega} \in \mathbb{R}^{D \times d}\), \(\mathbf{x} \in \mathbb{R}^d,\) \(\mathbf{b} \in \mathbb{R}^D\) そして cosine は element-wise に適用されます。
この例では、\(\mathbf{\Omega}\) and \(\mathbf{b}\) のエントリはマッピングが次のプロパティを満たすように分布からサンプリングされます :
$$
RFFM(\mathbf{x})^T \cdot RFFM(\mathbf{y}) \approx
e^{-\frac{\|\mathbf{x} – \mathbf{y}\|^2}{2 \sigma^2}}
$$
上の式の右辺の量はRBF (or ガウシアン) カーネル関数として知られています。この関数は機械学習で最も広く使用されるカーネル関数の一つで元の一つよりも異なる、遥かに高い次元空間で類似性を暗黙的に計測します。より詳細については Radial basis function kernel を見てください。
カーネル分類器
tf.contrib.kernel_methods.KernelLinearClassifier は事前パッケージされた tf.contrib.learn estimator で、explicit カーネルマッピングのパワーを線形モデルと結合しています。そのコンストラクタは LinearClassifier estimator のそれと殆ど同じですが、分類器が使用する各特徴に適用される explicit カーネルマッピングのリストを指定するための追加のオプションを伴います。次のコードスニペットは LinearClassifier を KernelLinearClassifier とどのように置き換えるかを示します。
# Specify the feature(s) to be used by the estimator. This is identical to the # code used for the LinearClassifier. image_column = tf.contrib.layers.real_valued_column('images', dimension=784) optimizer = tf.train.FtrlOptimizer( learning_rate=50.0, l2_regularization_strength=0.001) kernel_mapper = tf.contrib.kernel_methods.RandomFourierFeatureMapper( input_dim=784, output_dim=2000, stddev=5.0, name='rffm') kernel_mappers = {image_column: [kernel_mapper]} estimator = tf.contrib.kernel_methods.KernelLinearClassifier( n_classes=10, optimizer=optimizer, kernel_mappers=kernel_mappers) # Train. start = time.time() estimator.fit(input_fn=train_input_fn, steps=2000) end = time.time() print('Elapsed time: {} seconds'.format(end - start)) # Evaluate and report metrics. eval_metrics = estimator.evaluate(input_fn=eval_input_fn, steps=1) print(eval_metrics)
KernelLinearClassifier に渡される唯一の追加のパラメータは対応する特徴カラムに適用される feature_columns からカーネルマッピングのリストへの辞書です。次の行群は分類器に乱択化フーリエ特徴を使用して最初に初期 784-次元画像を 2000-次元ベクトルにマップしてそれから変換されたベクトル上で線形モデルを学習することを指示します :
kernel_mapper = tf.contrib.kernel_methods.RandomFourierFeatureMapper( input_dim=784, output_dim=2000, stddev=5.0, name='rffm') kernel_mappers = {image_column: [kernel_mapper]} estimator = tf.contrib.kernel_methods.KernelLinearClassifier( n_classes=10, optimizer=optimizer, kernel_mappers=kernel_mappers)
stddev パラメータに注意してください。これは近似された RBF カーネルの標準偏差 (\(\sigma\)) で分類で使用される類似尺度を制御します。stddev は典型的にはハイパーパラメータ調整を通して決定されます。
前のコードの実行結果は次のテーブルで要約されます。マッピングの出力次元を増やして標準偏差を調整することにより精度を更に増加できます。
メトリック | 値 |
loss | 0.10 |
accuracy | 97% |
training time | ~35 seconds on my machine |
stddev
分類品質は stddev の値に非常に敏感です。次のテーブルはstddev の異なる値について評価データ上の分類器の精度を示します。最適な値は stddev=5.0 です。小さすぎる、あるいは高すぎる stddev 値がどのように劇的に分類精度を下げるかに注意してください。
stddev | 評価精度 |
1.0 | 0.1362 |
2.0 | 0.4764 |
4.0 | 0.9654 |
5.0 | 0.9766 |
8.0 | 0.9714 |
16.0 | 0.8878 |
出力次元
直感的には、マッピングの出力次元がより大きくなるにつれて、2 つのマップされたベクトルの内積はカーネルをより密接に近似し、これは典型的にはより良い分類精度に繋がります。これについて考えるもう一つの方法は出力次元は線形モデルの重みの数に等しいということです ; モデルの「自由度」もより大きくなります。けれども、ある閾値後には、より高い出力次元は精度を非常に小さい幅で増加させる一方で、訓練により多くの時間がかかります。これは次の 2 の図で示されます、これは評価精度をそれぞれ出力次元と訓練時間の関数として描きます。
Summary
explicit カーネルマッピングは非線形モデルの予測パワーを線形モデルのスケーラビリティと結合します。伝統的な dual カーネル法とは違い、explicit カーネル法は何百万あるいは何億のサンプルにスケール可能です。explicit カーネルマッピングを使用するとき、次の tips を考慮してください :
- 乱択化フーリエ特徴は密特徴を持つデータセットのために特に効果的です。
- カーネルマッピングのパラメータはしばしばデータ依存です。モデル品質はこれらのパラメータに非常に敏感であり得ます。最適な値を見つけるためにハイパーパラメータ調整を使用してください。
- 複数の数値特徴を持つ場合、それらを単一のマルチ次元特徴に結合してカーネルマッピングを結合されたベクトルに適用してください。
以上