Dieser Beitrag ist eine formatierte Version meines Blogposts für Qiita. Wenn es zusätzliche Artikel gibt, werde ich sie auf dem Blog schreiben. __ "Einführung in die Bibliothek für maschinelles Lernen SHOGUN" __ http://rest-term.com/archives/3090/
The machine learning toolbox's focus is on large scale kernel methods and especially on Support Vector Machines (SVM)
Installation HINWEIS: Installation der Abhängigkeitsbibliothek SWIG BLAS (ATLAS) / LAPACK / GLPK / Eigen3 NumPy Vorsichtsmaßnahmen beim Kompilieren hello, world (libshogun) Hinweise zur Speicherverwaltung Python Modular
Die offizielle Website beschreibt das Setup-Verfahren usw. unter der Voraussetzung von Debian OS, aber Sie können es auch mit Redhat problemlos installieren. Wenn es sich um ein Debian-System handelt, wird die alte Version im Deb-Paket verteilt. Da es sich hier jedoch um CentOS handelt, kompilieren / installieren Sie es aus der Quelle. Da Aufgaben im Zusammenhang mit maschinellem Lernen oft lange dauern, empfehlen wir, dass Sie eine solche Software, nicht nur SHOGUN, in der Umgebung erstellen, in der sie tatsächlich ausgeführt wird, und sie im optimalen Zustand verwenden.
Es scheint, dass es zuvor mit Autotools (./configure && make) erstellt wurde, aber das neueste Versionspaket war mit CMake kompatibel. Die Anzahl der CMake-Benutzer wie OpenCV und MySQL hat in den letzten Jahren zugenommen.
$ git clone git://github.com/shogun-toolbox/shogun.git
$ cd shogun
$ mkdir build && cd build
$ cmake -DCMAKE_INSTALL_PREFIX=/usr/local/shogun-2.1.0 \
-DCMAKE_BUILD_TYPE=Release \
-DBUNDLE_EIGEN=ON \
-DBUNDLE_JSON=ON \
-DCmdLineStatic=ON \
-DPythonModular=ON ..
##Abhängige Bibliotheken werden überprüft und die Build-Konfiguration wird angezeigt.
-- Summary of Configuration Variables
--
-- The following OPTIONAL packages have been found:
* GDB
* OpenMP
* BLAS
* Threads
* LAPACK
* Atlas
* GLPK
* Doxygen
* LibXml2
* CURL
* ZLIB
* BZip2
* Spinlock
-- The following REQUIRED packages have been found:
* SWIG (required version >= 2.0.4)
* PythonLibs
* PythonInterp
* NumPy
-- The following OPTIONAL packages have not been found:
* CCache
* Mosek
* CPLEX
* ARPACK
* NLopt
* LpSolve
* ColPack
* ARPREC
* HDF5
* LibLZMA
* SNAPPY
* LZO
-- ==============================================================================================================
-- Enabled Interfaces
-- libshogun is ON
-- python modular is ON
-- octave modular is OFF - enable with -DOctaveModular=ON
-- java modular is OFF - enable with -DJavaModular=ON
-- perl modular is OFF - enable with -DPerlModular=ON
-- ruby modular is OFF - enable with -DRubyModular=ON
-- csharp modular is OFF - enable with -DCSharpModular=ON
-- R modular is OFF - enable with -DRModular=ON
-- lua modular is OFF - enable with -DLuaModular=ON
--
-- Enabled legacy interfaces
-- cmdline static is ON
-- python static is OFF - enable with -DPythonStatic=ON
-- octave static is OFF - enable with -DOctaveStatic=ON
-- matlab static is OFF - enable with -DMatlabStatic=ON
-- R static is OFF - enable with -DRStatic=ON
-- ==============================================================================================================
##Wenn es kein Problem zu geben scheint, kompilieren und installieren Sie
$ make -j32
$ sudo make install
Es scheint, dass jeder Compiler, der C ++ 11-Funktionen unterstützt, einige Funktionen (std :: atomic usw.) nutzt. Die meisten Funktionen von C ++ 11 werden vom redhat 6.x-System GCC (v4.4.x) nicht unterstützt.
In meiner Umgebung habe ich zusätzlich zu libshogun der Bibliothek selbst die Befehlszeile und die Schnittstelle für Python installiert. Wenn Sie viele Schnittstellen für Skriptsprachen haben möchten, müssen Sie SWIG separat installieren.
SWIG SWIG ist ein Tool, das Bindungen für die Verwendung von Modulen (gemeinsam genutzten Bibliotheken) erstellt, die in C / C ++ aus höheren Sprachen wie Skriptsprachen geschrieben wurden. Gelegentlich mache ich auch PHP-Bindungen für Webschnittstellen mit SWIG in meinem Unternehmen. Ab November 2013 erfüllen die Pakete, die mit yum installiert werden können, nicht die SHOGUN-Versionsanforderungen. Kompilieren / installieren Sie sie daher auch aus der Quelle. Für Debian ist "$ apt-get install swig2.0" in Ordnung.
##Abhängiges Paket PCRE(Perl Compatible Regular Expressions)Wenn nicht enthalten, geben Sie ein
$ sudo yum pcre-devel.x86_64
##Wenn es ein altes RPM-Paket gibt, löschen Sie es
$ sudo yum remove swig
$ wget http://prdownloads.sourceforge.net/swig/swig-2.0.11.tar.gz
$ tar zxf swig-2.0.11.tar.gz
$ cd swig-2.0.11
$ ./configure --prefix=/usr/local/swig-2.0.11
$ make -j2
$ sudo make install
##Fügen Sie einen binären symbolischen Link in den PFAD ein
$ sudo ln -s /usr/local/swig-2.0.11/bin/swig /usr/local/bin
Lassen Sie uns SHOGUN erneut erstellen, nachdem Sie das Verarbeitungssystem der Sprache ausgerichtet haben, für die Sie die Bindung mit SWIG herstellen möchten.
BLAS(ATLAS)/LAPACK/GLPK/Eigen3
Eine Gruppe von Bibliotheken zur linearen Algebra. Ein Paket, das mit yum installiert werden kann, ist in Ordnung. ATLAS ist eine der optimierten BLAS-Implementierungen und sollte enthalten sein, da es einfach zu installieren ist (BLAS ist eine Referenzimplementierung). Darüber hinaus scheint SHOGUN CPLEX zusätzlich zu GLPK zu unterstützen. Wenn Sie es also für geschäftliche Zwecke verwenden möchten, CPLEX Es scheint, dass die Leistung durch die Einführung von /) weiter verbessert wird. Lassen Sie uns unser Bestes tun, um das Genehmigungsformular zu schreiben (es scheint, dass es für akademische Zwecke kostenlos verwendet werden kann). Was Eigen3 betrifft, erfüllen die mit yum installierbaren Pakete ab November 2013 nicht die SHOGUN-Versionsanforderungen. Wenn Eigen3 jedoch nicht verfügbar ist, lädt CMake den Quellcode herunter (Header-Dateien, da es sich um eine Vorlagenbibliothek handelt). Es scheint, dass Sie anweisen können. Sie können der CMake-Option -DBUNDLE_EIGEN = ON
hinzufügen.
##Installieren Sie alle Bibliotheken, die sich auf die lineare Algebra beziehen
## atlas-Lapack, wenn Sie die Entwicklung einbeziehen möchten-Keine Entwicklung erforderlich
$ sudo yum install blas-devel.x86_64 lapack-devel.x86_64 atlas-devel.x86_64 glpk-devel.x86_64
NumPy ** NumPy ist erforderlich, um die Python-Schnittstelle zu installieren **. Ich habe NumPy bereits in meinem Blog vorgestellt, also als Referenz. Die Python-Oberfläche von OpenCV (Computer Vision Library) verwendet übrigens auch NumPy.
Die Installation ist mit pip einfach (ein Tool zum Installieren und Verwalten von Python-Paketen).
$ sudo pip install numpy
Das Gesamtbild der SHOGUN-Bibliothek ist in der folgenden Abbildung dargestellt, und ich bin mir nicht sicher. Es werden auch Schnittstellen für andere Skriptsprachen als die in dieser Abbildung gezeigten unterstützt, z. B. Java, Ruby und Lua. Installieren Sie wie oben erwähnt SWIG und erstellen Sie eine Bindung für die Sprache, die Sie verwenden möchten.
Wenn Sie SHOGUN in einer billigen VPS-Umgebung mit wenig physischem Speicher / virtuellem Speicher veröffentlichen und erstellen, besteht eine hohe Wahrscheinlichkeit, dass der cc1plus-Prozess von OOM Killer gewaltsam beendet wird. Ich habe es in einer virtuellen Umgebung mit 1 GB RAM / 2 GB Swap versucht, aber es wurde mit einer schrecklichen Punktzahl getötet. ..
kernel: Out of memory: Kill process 30340 (cc1plus) score 723 or sacrifice child
kernel: Killed process 30340, UID 500, (cc1plus) total-vm:2468236kB, anon-rss:779716kB, file-rss:2516kB
kernel: cc1plus invoked oom-killer: gfp_mask=0x200da, order=0, oom_adj=0, oom_score_adj=0
In diesem Fall sollten Sie die Swap-Kapazität erhöhen. Wenn der physische Speicher nur 1 GB groß ist, reicht es wahrscheinlich nicht aus, etwa die doppelte tatsächliche Speicherkapazität zu haben. Daher halte ich es für sicher, etwa viermal vorübergehend zu sichern. Es kann besser sein, ein wenig aufzugeben, wenn es sich um eine virtuelle OpenVZ-Umgebung handelt. ..
Außerdem sollte es in einer virtuellen Umgebung wie VPS nur wenige Inodes geben, sodass ich nicht denke, dass es möglich ist, eine große Menge an Trainingsdaten zu speichern. Es ist schwieriger, es gehorsam auf einem physischen Server aufzubauen. Ich habe es in einer Umgebung mit 32 Kernen / 96 GB RAM erstellt, aber die Ressourcen waren ausreichend und ich konnte es reibungslos erstellen.
Übrigens sind die Optimierungsoptionen von GCC in meiner Umgebung wie folgt.
-march=core2 -mcx16 -msahf -maes -mpclmul -mavx --param l1-cache-size=32 --param l1-cache-line-size=64 --param l2-cache-size=15360 -mtune=generic
hello, world (libshogun) Beginnen wir mit einer einfachen Aufgabe mit libshogun. [SVM (Support Vector Machine)](http://ja.wikipedia.org/wiki/%E3%82%B5%E3%83%9D%E3%83%BC%E3%83%88%E3%83% Es ist eine Stichprobe zur Klassifizierung von Daten unter Verwendung von 99% E3% 82% AF% E3% 82% BF% E3% 83% BC% E3% 83% 9E% E3% 82% B7% E3% 83% B3). ..
/* hello_shogun.cpp */
#include <shogun/labels/BinaryLabels.h>
#include <shogun/features/DenseFeatures.h>
#include <shogun/kernel/GaussianKernel.h>
#include <shogun/classifier/svm/LibSVM.h>
#include <shogun/base/init.h>
#include <shogun/lib/common.h>
#include <shogun/io/SGIO.h>
using namespace shogun;
int main(int argc, char** argv) {
// initialize
init_shogun_with_defaults();
// create some data
SGMatrix<float64_t> matrix(2,3);
for(int i=0; i<6; i++) {
matrix.matrix[i] = i;
}
matrix.display_matrix();
// create three 2-dimensional vectors
CDenseFeatures<float64_t>* features = new CDenseFeatures<float64_t>();
features->set_feature_matrix(matrix);
// create three labels
CBinaryLabels* labels = new CBinaryLabels(3);
labels->set_label(0, -1);
labels->set_label(1, +1);
labels->set_label(2, -1);
// create gaussian kernel(RBF) with cache 10MB, width 0.5
CGaussianKernel* kernel = new CGaussianKernel(10, 0.5);
kernel->init(features, features);
// create libsvm with C=10 and train
CLibSVM* svm = new CLibSVM(10, kernel, labels);
svm->train();
SG_SPRINT("total sv:%d, bias:%f\n", svm->get_num_support_vectors(), svm->get_bias());
// classify on training examples
for(int i=0; i<3; i++) {
SG_SPRINT("output[%d]=%f\n", i, svm->apply_one(i));
}
// free up memory
SG_UNREF(svm);
exit_shogun();
return 0;
}
##C für einen relativ neuen Compiler++Es ist gut, mit 11 zu kompilieren.
$ g++ -g -Wall -std=c++0x -L/usr/local/lib64 -lshogun hello_shogun.cpp -o hello_shogun
$ ./hello_shogun
matrix=[
[ 0, 2, 4],
[ 1, 3, 5]
]
total sv:3, bias:-0.333333
output[0]=-0.999997
output[1]=1.000003
output[2]=-1.000005
Extrahieren Sie Feature-Vektoren (CDense-Features) aus der Matrix, legen Sie die richtigen Labels (CBinaly-Labels) fest und lernen Sie mit SVM (CLib SVM) mithilfe des Gaußschen Kernels. Im Folgenden sind einige Funktionen aufgeführt.
Merkmalsvektoren werden aus einer Matrix mit Column-Major gelesen, ähnlich wie OpenGL, CUBLAS usw. (eine Spalte wird zu einem Merkmalsvektor). Externe Bibliotheken wie LibSVM und SVMLight können intern über die SHOGUN-Schnittstelle zum Erlernen von SVM verwendet werden (siehe shogun / classifier / svm / unten).
Der obige Code scheint eindeutig ein Speicherverlust zu sein, aber als ich ihn mit valgrind überprüft habe, scheint es, dass der Speicher intern ordnungsgemäß verwaltet wird. SHOGUN verwaltet Objekte intern nach Referenzanzahl. Ich verwende dies, weil ein Makro (SG_REF / SG_UNREF) definiert ist, das diesen Referenzzähler erhöht / verringert, aber es ist nicht erforderlich, den Zählerstand für alle Instanzen manuell zu bearbeiten. Ich habe die Implementierung zur Speicherverwaltung in SHOGUN gelesen und sie verringert den Referenzzähler der referenzierten Instanz, wenn die referenzierende Instanz freigegeben wird (dh im Destruktor). Da die Instanz freigegeben wird, wenn der Referenzzähler 0 oder weniger wird, werden im obigen Code beim Freigeben der SVM-Instanz andere Instanzen in einer Kettenreaktion freigegeben.
Bitte beachten Sie, dass ** nichts unternommen wird, wenn der Bereich außerhalb des Bereichs liegt **, sodass die Entscheidung zur Freigabe der Instanz nur getroffen wird, wenn sich der Referenzzähler ändert. Es fühlt sich wie eine kleine Freundlichkeit und eine große Hilfe an, aber es kann nicht geholfen werden, daher scheint es notwendig, mit diesem Mechanismus gut umzugehen. Ich werde einige Richtlinien schreiben.
// C++
std::unique_ptr<CDenseFeatures<float64_t> > features(new CDenseFeatures<float64_t>());
SG_REF(features);
//
import numpy as np
def genexamples(n):
class1 = 0.6*np.random.randn(n, 2)
class2 = 1.2*np.random.randn(n, 2) + np.array([5, 1])
labels = np.hstack((np.ones(n), -np.ones(n)))
return (class1, class2, labels)
#include <shogun/labels/BinaryLabels.h>
#include <shogun/features/DenseFeatures.h>
#include <shogun/kernel/GaussianKernel.h>
#include <shogun/classifier/svm/LibSVM.h>
#include <shogun/io/SGIO.h>
#include <shogun/io/CSVFile.h>
#include <shogun/evaluation/ContingencyTableEvaluation.h>
#include <shogun/base/init.h>
#include <shogun/lib/common.h>
using namespace std;
using namespace shogun;
int main(int argc, char** argv) {
try {
init_shogun_with_defaults();
// training examples
CCSVFile train_data_file("traindata.dat");
// labels of the training examples
CCSVFile train_labels_file("labeldata.dat");
// test examples
CCSVFile test_data_file("testdata.dat");
SG_SPRINT("training ...\n");
SGMatrix<float64_t> train_data;
train_data.load(&train_data_file);
CDenseFeatures<float64_t>* train_features = new CDenseFeatures<float64_t>(train_data);
SG_REF(train_features);
SG_SPRINT("num train vectors: %d\n", train_features->get_num_vectors());
CBinaryLabels* train_labels = new CBinaryLabels();
SG_REF(train_labels);
train_labels->load(&train_labels_file);
SG_SPRINT("num train labels: %d\n", train_labels->get_num_labels());
float64_t width = 2.1;
CGaussianKernel* kernel = new CGaussianKernel(10, width);
SG_REF(kernel);
kernel->init(train_features, train_features);
int C = 1.0;
CLibSVM* svm = new CLibSVM(C, kernel, train_labels);
SG_REF(svm);
svm->train();
SG_SPRINT("total sv:%d, bias:%f\n", svm->get_num_support_vectors(), svm->get_bias());
SG_UNREF(train_features);
SG_UNREF(train_labels);
SG_UNREF(kernel);
CBinaryLabels* predict_labels = svm->apply_binary(train_features);
SG_REF(predict_labels);
CErrorRateMeasure* measure = new CErrorRateMeasure();
SG_REF(measure);
measure->evaluate(predict_labels, train_labels);
float64_t accuracy = measure->get_accuracy()*100;
SG_SPRINT("accuracy: %f\%\n", accuracy);
SG_UNREF(predict_labels);
SG_UNREF(measure);
SG_SPRINT("testing ...\n");
SGMatrix<float64_t> test_data;
test_data.load(&test_data_file);
CDenseFeatures<float64_t>* test_features = new CDenseFeatures<float64_t>(test_data);
SG_REF(test_features);
SG_SPRINT("num test vectors: %d\n", test_features->get_num_vectors());
CBinaryLabels* test_labels = svm->apply_binary(test_features);
SG_REF(test_labels);
SG_SPRINT("num test labels: %d\n", test_labels->get_num_labels());
SG_SPRINT("test labels: ");
test_labels->get_labels().display_vector();
CCSVFile test_labels_file("test_labels_file.dat", 'w');
test_labels->save(&test_labels_file);
SG_UNREF(svm);
SG_UNREF(test_features);
SG_UNREF(test_labels);
exit_shogun();
} catch(ShogunException& e) {
SG_SPRINT(e.get_exception_string());
return - 1;
}
return 0;
}
training ...
num train vectors: 400
num train labels: 400
total sv:37, bias:-0.428868
accuracy: 99.750000%
testing ...
num test vectors: 400
num test labels: 400
test labels: vector=[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1]
SHOGUN hat genau das richtige Maß an Granularität im Klassendesign, und die API ist ausreichend abstrahiert, aber der Code wird schmutzig, wenn die Referenzzähloperation enthalten ist. .. Außerdem werden die Trainingsdaten mithilfe der CCSVFile-Klasse aus der Datei gelesen. Obwohl es CSV heißt, kann es auch Dateien lesen, in denen zweidimensionale Daten getrennt durch Leerzeichen anstelle des CSV-Formats geschrieben werden.
Um mit SHOGUN und OpenCV auszukommen, kann es nützlich sein, einen Adapter zu erstellen, der zwischen shogun :: SGMatrix und cv :: Mat konvertieren kann. OpenCV ist auch mit CUDA kompatibel, daher möchte ich, dass SHOGUN es ebenfalls unterstützt.
Python Modular Als nächstes verwenden wir die Python-Bindung von SHOGUN. Zwei werden bereitgestellt, python_static und python_modular, aber ich werde python_modular verwenden, da es eine intelligentere Oberfläche hat.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import modshogun as sg
import numpy as np
import matplotlib.pyplot as plt
def classifier():
train_datafile = sg.CSVFile('traindata.dat')
train_labelsfile = sg.CSVFile('labeldata.dat')
test_datafile = sg.CSVFile('testdata.dat')
train_features = sg.RealFeatures(train_datafile)
train_labels = sg.BinaryLabels(train_labelsfile)
test_features = sg.RealFeatures(test_datafile)
print('training ...')
width = 2.1
kernel = sg.GaussianKernel(train_features, train_features, width)
C = 1.0
svm = sg.LibSVM(C, kernel, train_labels)
svm.train()
sv = svm.get_support_vectors()
bias = svm.get_bias()
print('total sv:%s, bias:%s' % (len(sv), bias))
predict_labels = svm.apply(train_features)
measure = sg.ErrorRateMeasure()
measure.evaluate(predict_labels, train_labels)
print('accuracy: %s%%' % (measure.get_accuracy()*100))
print('testing ...')
test_labels = svm.apply(test_features)
print(test_labels.get_labels())
if __name__=='__main__':
classifier()
training ...
total sv:37, bias:-0.428868128708
accuracy: 99.75%
testing ...
[ 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
...Kürzung
Ich habe das gleiche Ergebnis wie die C ++ (libshogun) -Version. Lassen Sie uns das Klassifizierungsergebnis mit matplotlib visualisieren.
import numpy as np
import matplotlib.pyplot as plt
##Klassifizierungsgrenze abrufen
def getboundary(plotrange, classifier):
x = np.arange(plotrange[0], plotrange[1], .1)
y = np.arange(plotrange[2], plotrange[3], .1)
xx, yy = np.meshgrid(x, y)
gridmatrix = np.vstack((xx.flatten(), yy.flatten()))
gridfeatures = sg.RealFeatures(gridmatrix)
gridlabels = classifier.apply(gridfeatures)
zz = gridlabels.get_labels().reshape(xx.shape)
return (xx, yy, zz)
##Ermitteln Sie die Klassifizierungsgrenze, indem Sie den Zeichnungsbereich und den Klassifizierer angeben
xx, yy, zz = getboundary([-4,8,-4,5], svm)
##Klassifizierungsgrenzen zeichnen
plt.contour(xx, yy, zz, [1,-1])
Zur Zeit habe ich eine einfache Verwendung in C ++ und Python organisiert. Da SHOGUN nicht nur SVM, sondern auch verschiedene Algorithmen für maschinelles Lernen implementiert, möchte ich mit der Überprüfung anhand praktischerer Aufgaben fortfahren.
Recommended Posts