Introduction
Dans ce tutoriel, vous allez apprendre à utiliser l'interface graphique Scikit-learn Libsvm GUI, qui est une interface graphique simple pour Libsvm destinée principalement à des fins pédagogiques. Vous pouvez créer des points de données en cliquant et visualiser la région de décision induite par différents noyaux et paramètres de configuration.
Conseils sur la machine virtuelle
Une fois le démarrage de la machine virtuelle terminé, cliquez dans le coin supérieur gauche pour basculer vers l'onglet Notebook pour accéder à Jupyter Notebook pour pratiquer.
Parfois, vous devrez peut-être attendre quelques secondes pour que Jupyter Notebook ait fini de charger. La validation des opérations ne peut pas être automatisée en raison des limitations de Jupyter Notebook.
Si vous rencontrez des problèmes pendant l'apprentissage, n'hésitez pas à demander à Labby. Donnez votre feedback après la session, et nous résoudrons rapidement le problème pour vous.
Installer les packages requis
Avant de commencer, assurez-vous d'avoir installé les packages suivants :
- matplotlib
- numpy
- tkinter
- scikit-learn
Vous pouvez installer ces packages à l'aide de pip.
Importer les packages requis
La première étape consiste à importer les packages requis pour le projet.
import matplotlib
matplotlib.use("TkAgg")
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.backends.backend_tkagg import NavigationToolbar2TkAgg as NavigationToolbar2Tk
from matplotlib.figure import Figure
from matplotlib.contour import ContourSet
import sys
import numpy as np
import tkinter as Tk
from sklearn import svm
from sklearn.datasets import dump_svmlight_file
Créer la classe du modèle
Dans cette étape, nous allons créer la classe Model qui stocke les données. Elle implémente l'observable dans le modèle observateur et avertit les observateurs enregistrés en cas d'événement de changement.
class Model:
def __init__(self):
self.observers = []
self.surface = None
self.data = []
self.cls = None
self.surface_type = 0
def changed(self, event):
for observer in self.observers:
observer.update(event, self)
def add_observer(self, observer):
self.observers.append(observer)
def set_surface(self, surface):
self.surface = surface
def dump_svmlight_file(self, file):
data = np.array(self.data)
X = data[:, 0:2]
y = data[:, 2]
dump_svmlight_file(X, y, file)
Créer la classe du contrôleur
La classe Controller est utilisée pour contrôler la classe Model. Elle contient des méthodes pour ajuster le modèle, ajouter des exemples, effacer les données et refaire l'ajustement du modèle.
class Controller:
def __init__(self, model):
self.model = model
self.kernel = Tk.IntVar()
self.surface_type = Tk.IntVar()
self.fitted = False
def fit(self):
train = np.array(self.model.data)
X = train[:, 0:2]
y = train[:, 2]
C = float(self.complexity.get())
gamma = float(self.gamma.get())
coef0 = float(self.coef0.get())
degree = int(self.degree.get())
kernel_map = {0: "linéaire", 1: "rbf", 2: "poly"}
if len(np.unique(y)) == 1:
clf = svm.OneClassSVM(
kernel=kernel_map[self.kernel.get()],
gamma=gamma,
coef0=coef0,
degree=degree,
)
clf.fit(X)
else:
clf = svm.SVC(
kernel=kernel_map[self.kernel.get()],
C=C,
gamma=gamma,
coef0=coef0,
degree=degree,
)
clf.fit(X, y)
if hasattr(clf, "score"):
print("Précision :", clf.score(X, y) * 100)
X1, X2, Z = self.decision_surface(clf)
self.model.clf = clf
self.model.set_surface((X1, X2, Z))
self.model.surface_type = self.surface_type.get()
self.fitted = True
self.model.changed("surface")
def decision_surface(self, cls):
delta = 1
x = np.arange(x_min, x_max + delta, delta)
y = np.arange(y_min, y_max + delta, delta)
X1, X2 = np.meshgrid(x, y)
Z = cls.decision_function(np.c_[X1.ravel(), X2.ravel()])
Z = Z.reshape(X1.shape)
return X1, X2, Z
def clear_data(self):
self.model.data = []
self.fitted = False
self.model.changed("clear")
def add_example(self, x, y, label):
self.model.data.append((x, y, label))
self.model.changed("example_added")
self.refit()
def refit(self):
if self.fitted:
self.fit()
Créer la classe de vue
La classe View est utilisée pour afficher l'interface graphique utilisateur (GUI) et gérer les interactions de l'utilisateur.
class View:
def __init__(self, root, controller):
f = Figure()
ax = f.add_subplot(111)
ax.set_xticks([])
ax.set_yticks([])
ax.set_xlim((x_min, x_max))
ax.set_ylim((y_min, y_max))
canvas = FigureCanvasTkAgg(f, master=root)
canvas.draw()
canvas.get_tk_widget().pack(side=Tk.TOP, fill=Tk.BOTH, expand=1)
canvas._tkcanvas.pack(side=Tk.TOP, fill=Tk.BOTH, expand=1)
canvas.mpl_connect("button_press_event", self.onclick)
toolbar = NavigationToolbar2Tk(canvas, root)
toolbar.update()
self.controllbar = ControllBar(root, controller)
self.f = f
self.ax = ax
self.canvas = canvas
self.controller = controller
self.contours = []
self.c_labels = None
self.plot_kernels()
def plot_kernels(self):
self.ax.text(-50, -60, "Linéaire : $u^T v$")
self.ax.text(-20, -60, r"RBF : $\exp (-\gamma \| u - v \|^2)$")
self.ax.text(10, -60, r"Poly : $(\gamma \, u^T v + r)^d$")
def onclick(self, event):
if event.xdata and event.ydata:
if event.button == 1:
self.controller.add_example(event.xdata, event.ydata, 1)
elif event.button == 3:
self.controller.add_example(event.xdata, event.ydata, -1)
def update_example(self, model, idx):
x, y, l = model.data[idx]
if l == 1:
color = "w"
elif l == -1:
color = "k"
self.ax.plot([x], [y], "%so" % color, scalex=0.0, scaley=0.0)
def update(self, event, model):
if event == "examples_loaded":
for i in range(len(model.data)):
self.update_example(model, i)
if event == "example_added":
self.update_example(model, -1)
if event == "clear":
self.ax.clear()
self.ax.set_xticks([])
self.ax.set_yticks([])
self.contours = []
self.c_labels = None
self.plot_kernels()
if event == "surface":
self.remove_surface()
self.plot_support_vectors(model.clf.support_vectors_)
self.plot_decision_surface(model.surface, model.surface_type)
self.canvas.draw()
def remove_surface(self):
if len(self.contours) > 0:
for contour in self.contours:
if isinstance(contour, ContourSet):
for lineset in contour.collections:
lineset.remove()
else:
contour.remove()
self.contours = []
def plot_support_vectors(self, support_vectors):
cs = self.ax.scatter(
support_vectors[:, 0],
support_vectors[:, 1],
s=80,
edgecolors="k",
facecolors="none",
)
self.contours.append(cs)
def plot_decision_surface(self, surface, type):
X1, X2, Z = surface
if type == 0:
levels = [-1.0, 0.0, 1.0]
linestyles = ["dashed", "solid", "dashed"]
colors = "k"
self.contours.append(
self.ax.contour(X1, X2, Z, levels, colors=colors, linestyles=linestyles)
)
elif type == 1:
self.contours.append(
self.ax.contourf(
X1, X2, Z, 10, cmap=matplotlib.cm.bone, origin="lower", alpha=0.85
)
)
self.contours.append(
self.ax.contour(X1, X2, Z, [0.0], colors="k", linestyles=["solid"])
)
else:
raise ValueError("type de surface inconnu")
Créer la classe ControllBar
La classe ControllBar est utilisée pour contrôler les entrées de l'utilisateur et les afficher sur l'interface graphique utilisateur (GUI).
class ControllBar:
def __init__(self, root, controller):
fm = Tk.Frame(root)
kernel_group = Tk.Frame(fm)
Tk.Radiobutton(
kernel_group,
text="Linéaire",
variable=controller.kernel,
value=0,
command=controller.refit,
).pack(anchor=Tk.W)
Tk.Radiobutton(
kernel_group,
text="RBF",
variable=controller.kernel,
value=1,
command=controller.refit,
).pack(anchor=Tk.W)
Tk.Radiobutton(
kernel_group,
text="Poly",
variable=controller.kernel,
value=2,
command=controller.refit,
).pack(anchor=Tk.W)
kernel_group.pack(side=Tk.LEFT)
valbox = Tk.Frame(fm)
controller.complexity = Tk.StringVar()
controller.complexity.set("1.0")
c = Tk.Frame(valbox)
Tk.Label(c, text="C :", anchor="e", width=7).pack(side=Tk.LEFT)
Tk.Entry(c, width=6, textvariable=controller.complexity).pack(side=Tk.LEFT)
c.pack()
controller.gamma = Tk.StringVar()
controller.gamma.set("0.01")
g = Tk.Frame(valbox)
Tk.Label(g, text="gamma :", anchor="e", width=7).pack(side=Tk.LEFT)
Tk.Entry(g, width=6, textvariable=controller.gamma).pack(side=Tk.LEFT)
g.pack()
controller.degree = Tk.StringVar()
controller.degree.set("3")
d = Tk.Frame(valbox)
Tk.Label(d, text="degree :", anchor="e", width=7).pack(side=Tk.LEFT)
Tk.Entry(d, width=6, textvariable=controller.degree).pack(side=Tk.LEFT)
d.pack()
controller.coef0 = Tk.StringVar()
controller.coef0.set("0")
r = Tk.Frame(valbox)
Tk.Label(r, text="coef0 :", anchor="e", width=7).pack(side=Tk.LEFT)
Tk.Entry(r, width=6, textvariable=controller.coef0).pack(side=Tk.LEFT)
r.pack()
valbox.pack(side=Tk.LEFT)
cmap_group = Tk.Frame(fm)
Tk.Radiobutton(
cmap_group,
text="Hyperplans",
variable=controller.surface_type,
value=0,
command=controller.refit,
).pack(anchor=Tk.W)
Tk.Radiobutton(
cmap_group,
text="Surface",
variable=controller.surface_type,
value=1,
command=controller.refit,
).pack(anchor=Tk.W)
cmap_group.pack(side=Tk.LEFT)
train_button = Tk.Button(fm, text="Ajuster", width=5, command=controller.fit)
train_button.pack()
fm.pack(side=Tk.LEFT)
Tk.Button(fm, text="Effacer", width=5, command=controller.clear_data).pack(
side=Tk.LEFT
)
Créer la fonction principale
La fonction principale est utilisée pour exécuter le programme.
def main(argv):
root = Tk.Tk()
model = Model()
controller = Controller(model)
root.wm_title("Scikit-learn Libsvm GUI")
view = View(root, controller)
model.add_observer(view)
Tk.mainloop()
Exécuter le programme
Maintenant, vous pouvez exécuter le programme en appelant la fonction principale.
if __name__ == "__main__":
main(sys.argv)
Récapitulatif
Dans ce tutoriel, vous avez appris à utiliser l'interface graphique utilisateur (GUI) Scikit-learn Libsvm pour créer des points de données en cliquant et visualiser la région de décision induite par différents noyaux et paramètres. Vous avez également appris à créer les classes Model, Controller, View et ControllBar, ainsi que la manière d'exécuter le programme.