scikit-learnのSVMと他のSVMとの関係の調査のために記したメモで、まだ整理されていません。
scikit-learnの利便性に惹かれているが、C++言語での利用のためには、他の実装も参考とする必要があり、調査している。
機械学習では最近、深層学習 DeepLearningが話題となっているが、
サポートベクターマシン(SVM)は、その能力の高さと利用しやすさにおいて
輝きを失っていないと思う。
###どの実装を使うかは関係しない部分
SVMを使いこなす!チェックポイント8つ
http://qiita.com/pika_shi/items/5e59bcf69e85fdd9edb2
サポートベクトルマシンとその他の機械学習手法
http://qiita.com/ynakayama/items/afa2212cf561f2067606
どの実装を使うかに依存しない部分で、SVMを活用するための前処理や、交差検証の部分などについて十分な知見をもつことは、機械学習を成功させるうえで重要なポイントです。
英語が苦にならない方には、次の文献を推奨します。
A Practical Guide to Support Vector Classification
主成分分析をSVMの前段階に使うことがあります。
主成分分析の特徴は、
1.主成分分析の結果得られた固有ベクトルは、直交しているので、得られた係数は、
相関を持たない変数の組み合わせになる。
相関を持っている変数を使ってモデルを構築すると、意図しない現象を生じやすいが、直交していて無相関になっているパラメータは扱いやすくなってくる(注)。
2.実際のデータの変動が、どのような変動が多く含まれていて、変動のどれくらいを、何次の固有ベクトルまでで説明可能なのかを定量的に示してくれる。
そのため、原理的にはありうるけれども、事実上無視できる変動成分が明らかになるので、着目すべき成分だけに着目して、現象を捉えることが可能になる。
そのため、主成分分析は、次元圧縮の目的で使われます。
次元圧縮で興味深いことは、次元圧縮して学習した方が、次元圧縮なしに学習した場合よりも良好な機械学習結果を与える場合があるということです。
Machine Learning with Scikit Learn (Part I)
オリジナル画像データをそのまま使うと40%くらいの精度しか出ないが、固有顔に次元圧縮してから分類すると85%くらいの精度が出る。
次元圧縮した結果、どのようなデータになったのかということは、次元圧縮したデータを元の空間に再投影することでわかります。その例は、次のPCAについての記事で、画像として確認することができます。
sklearn.decomposition のPCAを利用したもの PythonでPCAを行う方法
scikit-learn のPCAではPCA(n_components=2)
などとn_componentsで次元削減後の次元数を指定します。
numpy でPCAを実装した記事 Pythonで主成分分析をするコード
PythonでのOpenCVのPCAのクラスはcv2.PCAComputeクラスになっている。
OpenCV [cv2.PCACompute](http://docs.opencv.org/3.1.0/d3/d8d/classcv_1_1PCA.html#gsc.tab=0)
cv2.PCACompute(data[, mean[, eigenvectors[, maxComponents]]]) -> mean, eigenvectors
でmaxComponentsで次元削減後の次元数を指定します。
OpenCV/C++ でPCAを利用した記事画像の主成分分析
[OpenCVで主成分分析をしてみた]
(http://www.yasutomo57jp.com/2010/10/26/opencv%E3%81%A7%E4%B8%BB%E6%88%90%E5%88%86%E5%88%86%E6%9E%90%E3%82%92%E3%81%97%E3%81%A6%E3%81%BF%E3%81%9F/)
[libpca C++ library: A C++ library for principal component analysis]
(https://sourceforge.net/projects/libpca/)
このようにして得られた主成分分析での固有ベクトルの係数は、次数が高くなるにしたがって絶対値が小さくなります。そのままだと、絶対値の小さなパラメータは、SVMで十分に利用しきれなくなってしまいます。そこで、SVMでは、入力データを規格化して大きさをそろえることがなされています。
機械学習の分野では、主成分分析でfitした結果を用いて、別のデータに対して射影を計算して、それを機械学習の入力値にすることが多い。主成分分析結果のデータを利用して、射影を行えるようにデータを保存して読み込む枠組みを確認しよう。
主成分分析が実際にはどういう線形代数をしているのかを理解するには、「実践コンピュータビジョン」の主成分分析 PCAの説明がわかりやすいだろう。scikit-learnやOpenCVのコードを利用するだけだと、どういう線形代数を行っているのかが隠されている。特徴量の次元数に比べてサンプル数が少ないときの主成分分析では、サンプル数の次元で行列計算の使用メモリの大きさが決まることがわかりやすくなる。このようなことへの理解を積み重ねていくことが、実際の問題を解決していく際の力になっていくだろう。
また、主成分分析をしたときには、その固有ベクトル(画像の場合には固有画像)を確認することを推奨します。どのような変動が含まれているのかを理解することで、どのように機械学習すべきかのヒントが得られます。学習データの分布がどのようになっているのかを理解することにつながります。
###PCAのライブラリ
scikit-learn | OpenCV | その他 | |
---|---|---|---|
URL | sklearn.decomposition.PCA() http://scikit-learn.org/stable/modules/generated/sklearn.decomposition.PCA.html |
cv2.PCACompute() http://docs.opencv.org/2.4.12/modules/core/doc/operations_on_arrays.html?highlight=pca#cv2.PCACompute |
numpyによる実装例 http://www.yasutomo57jp.com/2012/02/24/python%E3%81%A7pca/ |
射影 | pca.transform(X) | pcacompute.project(X) | |
画像での主成分分析 | 固有顔 http://scikit-learn.org/stable/auto_examples/decomposition/plot_faces_decomposition.html | 画像の主成分分析 http://suzuichibolgpg.blog.fc2.com/blog-entry-62.html | フォントの主成分分析例 http://www.oreilly.co.jp/pub/9784873116075/ |
iris data | PCA example with Iris Data-set http://scikit-learn.org/stable/auto_examples/decomposition/plot_pca_iris.html | ||
次元圧縮のコード例 | from sklearn import decomposition pca = decomposition.PCA(n_components=3) pca.fit(X) pca.transform(X) |
cv2.PCACompute(data[, mean[, eigenvectors[, maxComponents]]]) -> mean, eigenvectors |
###SVMのライブラリ
以下、python環境で使えるSVMのライブラリを3例しめします。
目的の作業に応じて使い分けてみてください。
・Scikit-learn:
機械学習のライブラリが充実している環境。Pythonで利用するインタフェースが、学習アルゴリズムを変えても共通性が高く作られているので、試行錯誤をするうえで便利。
・LibSVM:
LibSVMの開発者が公開しているものにpythonバインディングが含まれている。疎な学習データに対応している。
・OpenCV:
OpenCV/C++の環境に将来移行するのは便利だ。ただし、OpenCV-Pythonのバインディングのインタフェースは変化が激しく、ドキュメントが追いついていないことがある。
・dlib
dlibにもSVMの実装があり、C++ Pythonの両方で利用可能です。
http://dlib.net/python/#dlib.svm_c_trainer_histogram_intersection
・LIBLINEAR -- A Library for Large Linear Classification
次の表は作成中
scikit-learn | libSVM | OpenCV | |
---|---|---|---|
URL | http://scikit-learn.org/stable/ | https://www.csie.ntu.edu.tw/~cjlin/libsvm/ | http://opencv.org/ |
モジュールの読み込み | from sklearn import svm | from svm import * | import cv2 |
学習 | clf = svm.SVC(C=22, gamma=2-11) | m = svm_train(prob, param) | svm = cv2.SVM() |
学習 | clf.fit(x,y) | m = svm_train(prob, param) | svm.train(x, y) |
判定 | clf.predict(x) | result = svm_predict(test_label, test_data , t) | result = svm.predict_all(testData) |
多クラス | 1対1 | 1対1 | 1対1 |
モデルの保存 | s = pickle.dumps(clf) | svmutil.svm_save_model('libsvm.model', m) | svm.save("/path/to/model.xml") |
モデルの読み込み | clf2 = pickle.loads(s) | m = svmutil.svm_load_model('libsvm.model') | svm2 = cv2.SVM();svm2.load("/path/to/model.xml") |
確率推定の有無 | あり classifier = svm.SVC(gamma=0.001, probability=True); classifier.fit(X, Y);predicted_Prob = classifier.predict_proba(Xnew) | あり | |
iris dataの例 | http://scikit-learn.org/stable/auto_examples/svm/plot_iris.html | データの所在 https://www.csie.ntu.edu.tw/~cjlin/libsvmtools/datasets/multiclass.html#iris | |
C/C++の有無 | なし | あり | あり |
ライセンス | commercially usable - BSD license | the modified BSD license | 3-clause BSD License |
###scikit-learnの実装を利用する記事
Scikit-learnは機械学習関係のライブラリがそろっているので
SVMを始めやすい。
scikit-learn [Recognizing hand-written digits]
(http://scikit-learn.org/stable/auto_examples/classification/plot_digits_classification.html#example-classification-plot-digits-classification-py)
scikit-learn [1.4. Support Vector Machines]
(http://scikit-learn.org/stable/modules/svm.html)
scikit-learn [Plot different SVM classifiers in the iris dataset]
(http://scikit-learn.org/stable/auto_examples/svm/plot_iris.html)
ブログ上のサンプルコードは、scikit-learnのサイトのサンプルコードとはまた違った視点で書かれていたりします。
Python: scikit-learn の手書き数字データセットを SVM で分類してみる
http://blog.amedama.jp/entry/2016/01/03/143258
scikit-learn Recognizing hand-written digits
scikit-learnによる多クラスSVM
http://qiita.com/sotetsuk/items/3a5718bb1f945a383ceb
scikit-learnのSVMを使って多クラス分類を試す
http://minus9d.hatenablog.com/entry/2015/04/19/190732
[Python: Iris データセットをサポートベクターマシンで分類してみる]
(http://momijiame.tumblr.com/post/114751531866/python-iris-%E3%83%87%E3%83%BC%E3%82%BF%E3%82%BB%E3%83%83%E3%83%88%E3%82%92%E3%82%B5%E3%83%9D%E3%83%BC%E3%83%88%E3%83%99%E3%82%AF%E3%82%BF%E3%83%BC%E3%83%9E%E3%82%B7%E3%83%B3%E3%81%A7%E5%88%86%E9%A1%9E%E3%81%97%E3%81%A6%E3%81%BF%E3%82%8B)
scikit-learn Plot different SVM classifiers in the iris dataset
n-classの識別は1対1で実装されていることが書かれています。
scikit-learn [SVC and NuSVC implement the “one-against-one” approach (Knerr et al., 1990) ]
(http://scikit-learn.org/stable/modules/svm.html)
n-classの識別は1対1で実装するのが精度を出しやすいようです。
1対他のベースでの実装は、両者を識別する境界が多次元空間上で狭くなってしなう
[scikit-learn Model persistence]にモデルを保存し、読み込む方法が紹介されている。
(http://scikit-learn.org/stable/modules/model_persistence.html)
ここに示すpickleを使って識別器のインスタンスを保存する方法は、保存する側と読み出す側とが同じバージョンのscikit-learnを使っている必要が高い。
import pickle
s = pickle.dumps(clf)
clf2 = pickle.loads(s)
次の記事は、SVMの他にも興味ある学習手法を紹介しています。
画像をみるだけでも結構たのしい。
Machine Learning with Scikit Learn (Part I)
主成分分析とSVMとは相性がいいようで次の例を見つけました。
scikit-learn [Faces recognition example using eigenfaces and SVMs]
(http://scikit-learn.org/stable/auto_examples/applications/face_recognition.html)
###libSVMを利用している記事
使うべきアルゴリズムがSVMに絞り込んであり、C/C++言語で実装しなおす予定がある場合、実績の高いライブラリであるlibSVMを直接使うことも考えようと思う。libSVMも多クラスの学習が可能である。
libSVMの場合には、特徴量が疎な場合でも、学習が可能になっている。
libSVMは、コマンドラインから利用できるexe形式、pythonから利用できるpythonモジュール、C言語から利用できるモジュールとそろっているので、どれかの階層でうまくいくことを確かめてから、別の階層で利用することが容易そうである。
LIBSVM Tools
は今も更新されているので、昔よく見ていた人も、再度アクセスする価値があります。
PythonでLIBSVMを使う
http://hy-adversaria.blogspot.jp/2011/04/pythonlibsvm.html
[Python] python から SVM を使うときのメモ [SVM]
http://gasser.blog114.fc2.com/blog-entry-498.html
サポートベクターマシン(のライブラリLIVSVM)を使ってpythonでFizzBuzzを書いてみた。
http://qiita.com/cof/items/e02ada0adb1106635ac9
LIBSVMを使ってデータ予測してみた
https://airtoxin.wordpress.com/2013/02/03/libsvm%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E3%83%87%E3%83%BC%E3%82%BF%E4%BA%88%E6%B8%AC%E3%81%97%E3%81%A6%E3%81%BF%E3%81%9F/
toto予想のためのPython入門【第3回】 PythonでSVMを使う(後編) 記事をクリップする
http://blogs.yahoo.co.jp/gdg00431/2211049.html
Pythonでlibsvmをインストールする
http://pumpkinkaneko.com/python%E3%81%A7libsvm%E3%82%92%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%81%99%E3%82%8B
LIBSVM(python)の使い方
http://liberte599.jimdo.com/2011/02/25/libsvm-python-%E3%81%AE%E4%BD%BF%E3%81%84%E6%96%B9/
livSVM のFAQでもone-against-one.
の実装であることを述べています。
学習結果の保存と読み込み
svmutil.svm_save_model('libsvm.model', m)
m = svmutil.svm_load_model('libsvm.model')
libSVMでは、判定の結果だけではなく、判定時の確率を返すことが可能です。
ブログ記事SVM による MNIST 手書き数字分類結果の詳細
###OpenCVのSVMを利用している記事
[OpenCV-Python Tutorials >> Machine Learning >> Understanding SVM]
(http://opencv-python-tutroals.readthedocs.org/en/latest/py_tutorials/py_ml/py_svm/py_svm_basics/py_svm_basics.html#svm-understanding)
OpenCV 2.4.11 Documentation [Support Vector Machines]
(http://docs.opencv.org/2.4/modules/ml/doc/support_vector_machines.html#cvsvm-cvsvm)
ドキュメントを読む限り、多クラス分類もサポートしているようだ。実際、後の例題を実行して確かめた。
(n-class classification という表現がある。)
OpenCVのSVMはpythonからも利用可能であるし、C++言語からも利用可能である。
pythonからはmatplotlibを使ってグラフを簡単に作れるので、結果をチェックするのがやりやすい。
その方式がうまくいくことがわかってからは、グラフの作成は省略して、個々の学習と識別にだけ専念することができる。
そのときにはC++言語での実装が無駄なく、高速な処理ができるだろう。
OpenCVの標準の配布に含まれているsamplesを見てみる。
cv2.SVMとは別クラスのSVMクラスを定義している。(複数の手法との比較をしやすくするために、同一のインタフェースを与えている。)
(opencvのディレクトリ)\sources\samples\python2 digits.py
(opencvのディレクトリ)\sources\samples\python2 letter_recog.py
OCR of Hand-written Digits
http://docs.opencv.org/3.1.0/dd/d3b/tutorial_py_svm_opencv.html#gsc.tab=0
svm = cv2.SVM()
svm.train(trainData,responses, params=svm_params)
result = svm.predict_all(testData)
このスクリプトを動作させるためのデータの所在を確認しよう。
[pythonでsvm]
(http://ffuyyo.blogspot.jp/2012/08/pythonsvm.html)
C++からの利用例 OpenCV日記(9)カーネル法を使った非線形SVM
OpenCV2で
"train data must be floating-point matrix"
のエラーが出たときには
train()に与えるnumpyのarrayデータをfloat32に変えるとよいようだ。
OpenCV のSVMについてのブログ記事pythonでsvm
も同様なことを書いている
使ってみようとして、エラーを生じる際には、元のC++モジュールの中でエラーメッセージを検索することが
対策方法の早道かもしれない。
OpenCV-PythonでのSVMクラスのpredict()の戻り値
cv2.SVM.predict(sample[, returnDFVal]) → retva
cv2.SVM.predict_all(samples[, results]) → results
OpenCV-PythonでのSVMクラスのpredict_all()の戻り値のnumpy.arrayの形状は、scikit-learnのSVMのpredict()と異なっている。
学習結果の保存と読み込み
次のようにXMLファイルでの保存なので、OpenCVのバージョンによる依存性は少なそうです。ただし、そのままでは学習結果を秘匿するには向かないので工夫が必要になります。
上記のdigits.pyのsave()結果のファイルはYAMLでした。
model = cv2.SVM(points, labels)
# Store it by using OpenCV functions:
model.save("/path/to/model.xml")
# Now create a new SVM & load the model:
model2 = cv2.SVM()
model2.load("/path/to/model.xml")
[answers.opencv.org/ OpenCVのSVMのモデルを保存し、読み込む]
(http://answers.opencv.org/question/5713/save-svm-in-python/)
なお、SVMのインスタンスをpickleすることはOpenCVのPythonバインディングでも可能です。
pickle.dump(model, open("save.pkl", 'w'))
これはSVM単独ではない使い方
HOG+SVMによる検出器がOpenCVには用意されている。
CPU版、GPU版とも用意されている。ドキュメンテーションはGPUを参考にしてCPU版を利用する。
Object Detection gpu::HOGDescriptor
[HOG + SVMで人物検出【OpenCV & Python】]
(http://yusuke1581.hatenablog.com/entry/2014/11/26/153901)
OpenCVは3.1が公開されて、OpenCV2.xから移行も進んでいるだろうか?
OpenCV3.1 系統の記事?
サポートベクタマシン(SVM, Support Vector Machines))
####学習結果の評価ツール(scikit-learn.metrics)
・学習に用いなかったデータを使って学習結果を評価する。
評価のない機械学習はありえない。
ありがちなことは、学習に使ったデータに対してだけは良好な結果を与えるが、
それ以外の結果の対しては無残な結果を与えるということだ。
「実践 機械学習システム」を読むことだ。データの準備と評価の部分をどれだけ重要視しているかが、わかるはずだ。
cv2のSVMを使う場合でも、自前のnumpyのpythonコードでも、それ以外でも
scikit-learn.metricsは役立つ。
sklearn.metrics Classification metrics
Recognizing hand-written digits
の中でsklearn.metrics.classification_report(expected, predicted)
sklearn.metrics.confusion_matrix(expected, predicted)
がどのように使われているのかを、知るのは有意義だ。
####データこそが重要である
機械学習の分野では、まだまだデータこそが重要である。多クラス分類の場合だと、sklearn.metrics.classification_report中のrecall rate の値とprecision の値の両方に着目すると、どの分類の学習データが足りていないのかを知ることができる。足りない分類の学習データを補うと、recall rate の値、precision の値が改善されていくはずだ。そのような繰り返しをして、実際の問題に対して使えるレベルになっていく。
参考情報:
####C++でのscikit-learn相当のライブラリ
C++でのscikit-learn相当のライブラリがないかという質問に対して、次のライブラリが紹介されていた。
C++でscikit-learn相当のライブラリが必要になったときには、調査してみよう。
The Shogun Machine Learning Toolbox
日本語の解説記事 機械学習ライブラリ SHOGUN入門
日本語の解説記事 shogunの使い方
Shark – Machine Learning 3.0
####Javaで書かれた機械学習ソフトウェア Weka
Weka
####注:パラメータに相関をもたないようにする
パラメータに相関をもたないようにすることは、多変量解析の分野でもよくなされることです。
(身長、体重)という組み合わせよりは、(身長、BMI)という組み合わせの方が相関がない(もしくは十分無視できる)組み合わせになるので、多変量解析の説明変数にするのに適しています。
説明変数間の相関が高い場合には,本来取り得ないような結果となる場合がある。
説明変数間の相関がとても高い場合、回帰モデルは非常に不安定になる。
説明変数間の相関がとても高い場合、回帰モデルは非常に不安定になる。これは、説明
変数の間にすでに別の線形回帰関係が含まれているということであり、その意味でこのよ
うな現象を「多重共線性(multi colinearity)」と言う。経験的に、説明変数間の相関が
0.7以上ならば危険であると言われている。
多重共線性に注意するために、回帰分析を行う際には、まず説明変数間の相関行列を見
て、相関がとても強いものがあれば、片方は説明変数から除く、といったことが必要であ
る。
####注:モデルを記述する際の自由度
モデルを記述する際にその自由度をいくらにすべきかという部分では、AIC(赤池情報量規準)という量が評価の目安になる。
赤池情報量規準
パラメータの数や次数を増やせば増やすほど、その測定データとの適合度を高めることができる。しかし、その反面、ノイズなどの偶発的な(測定対象の構造と無関係な)変動にも無理にあわせてしまうため、同種のデータには合わなくなる
####数学に興味がある人へ
SVMでは、多次元空間に射影して分離可能にしているという点、その多次元空間での計算が、カーネルトリックという手法によって、計算量の増加をもたらすことなしに実現しているというのがすばらしいところです。
####Cuda
GPU-accelerated LIBSVM
http://mklab.iti.gr/project/GPU-LIBSVM
追記(2019.06.03)
「scikit-learnとTensorFlowによる実践機械学習」
の目次には
5章 サポートベクトルマシン(SVM)
8章 次元削減
がある。
主成分分析(PCA)で次元削減を実施してサポートベクトルマシン(SVM)で分類するという定石が説明されている。
追記:深層学習があってもSVMが役立つ理由
学習ができたかどうかを判定するとき、学習や評価に用いたデータを分離できれば十分とだけ考えると、どんなにギリギリであっても分離できていればOKということになってしまう。間違えていない限り、修正に寄与しない。それがほとんどの深層学習の状況だ。だからこそ、人には気づかないような微小なノイズを加えることによっても、分類を騙すことができることが知られている。
Convolutional Neural Networkに対する攻撃手法 -誤分類の誘発-
それに対してSVMでは、分類する際の境界領域を大きくとるような仕組み(
マージン最大化)がある。
だから、SVMで定式化できる場合には、SVMを用いた方がいいと思う。
参考記事
pythonでSVM実装
SlideShare[Pythonによる機械学習入門〜基礎からDeep Learningまで〜]
(http://www.slideshare.net/yasutomo57jp/pythondeep-learning-60544586?next_slideshow=1)
SVMにはGrid Search を併用しよう。
https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.GridSearchCV.html