{"nbformat":4,"nbformat_minor":0,"metadata":{"anaconda-cloud":{},"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.5.1"},"colab":{"name":"classification 3.2 SVM.ipynb","provenance":[{"file_id":"https://github.com/jakevdp/PythonDataScienceHandbook/blob/master/notebooks/05.07-Support-Vector-Machines.ipynb","timestamp":1604819408143}]}},"cells":[{"cell_type":"markdown","metadata":{"id":"EHyLhNXzsH0T"},"source":["# Support Vector Machines"]},{"cell_type":"code","metadata":{"id":"xwWi0x9TsH0W"},"source":["%matplotlib inline\n","import numpy as np\n","import matplotlib.pyplot as plt\n","from scipy import stats\n","\n","# use seaborn plotting defaults\n","import seaborn as sns; sns.set()"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"UKWviTyssH0n"},"source":["## Η λογική των Μηχανών Διανυσμάτων Υποστήριξης\n"]},{"cell_type":"markdown","metadata":{"id":"WeEX0HGJsH0o"},"source":["Με τον Αφελή Μπεϋζιανό ταξινομητή είδαμε ένα παράδειγμα παραμετρικού μοντέλου το οποίο περιγράφει τις υποκείμενες κατανομές των δεδομένων προκειμένου να τα αποδώσει σε κλάσεις. Αυτή η κατηγορία ταξινομητών είναι η παραγωγική ή δημιουργική (generative). Τα SVM ανήκουν σε μια διαφορετική κατηγορία, στους μη-παραμετρικούς, διαχωριστικούς (discriminative) ταξινομητές οι οποίοι αντί να προσπαθούν να βρουν τις υποκείμενες κατανομές (δηλαδή της παραμέτρους τους) επιδιώκουν να βρουν μια ευθεία ή καμπύλη (σε δύο διαστάσεις) ή πολύπτυχο (manifold) σε περισσότερες τα οποία να διαχωρίζουν / διακρίνουν τις κατηγορίες μεταξύ τους. \n","\n","Σημειώστε ότι τα SVM είναι εγγενώς δυαδικοί ταξινομητές σε αντιδιαστολή πχ με τα MLP, ωστόσο υπάρχουν τεχνικές και επεκτάσεις για προβλήματα πολλών κλάσεων.\n","\n","Ας εξετάσουμε πρώτα μια απλή περίπτωση ταξινόμησης στην οποία οι δύο κλάσεις δεδομένων (σημείων) είναι εύκολα διαχωρίσιμες."]},{"cell_type":"code","metadata":{"id":"rNHsNV1-sH0q"},"source":["from sklearn.datasets.samples_generator import make_blobs\n","X, y = make_blobs(n_samples=50, centers=2,\n"," random_state=0, cluster_std=0.60)\n","plt.scatter(X[:, 0], X[:, 1], c=y, s=50, cmap='autumn');"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"lLWE6ri6sH0z"},"source":["Ένας γραμμικός διαχωριστικός ταξινομητής θα προσπαθήσει να φτιάξει μια ευθεία γραμμή η οποία θα διαχωρίζει τα δύο σύνολα δεδομένων, δημιουργώντας έτσι ένα μοντέλο ταξινόμησης (ο ορισμός μιας ευθείας είναι ο ορισμός της γενίκευσης). Για την απλή περίπτωση που εξετάζουμε θα μπορούσαμε εύκολα να βρούμε μια τέτοια ευθεία. Ωστόσο, αμέσως ανακαλύπτουμε ένα πρόβλημα: υπάρχουν περισσότερες από μια ευθείες, υπάρχουν μάλιστα άπειρες ευθείες που διαχωρίζουν τέλεια τις δύο κλάσεις.\n","\n","Μπορούμε να σχεδιάσουμε κάποιες από αυτές ως εξής:"]},{"cell_type":"code","metadata":{"id":"otcMRm7JsH00"},"source":["xfit = np.linspace(-1, 3.5)\n","plt.scatter(X[:, 0], X[:, 1], c=y, s=50, cmap='autumn')\n","plt.plot([0.6], [2.1], 'x', color='red', markeredgewidth=2, markersize=10)\n","\n","for m, b in [(1, 0.65), (0.5, 1.6), (-0.2, 2.9)]:\n"," plt.plot(xfit, m * xfit + b, '-r')\n","\n","plt.xlim(-1, 3.5);"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"rItKPlxmsH04"},"source":["Οι κόκκινες ευθείες ορίζουν τρεις πολύ διαφορετικές διαχωριστικές ευθείες - διαχωριστικούς ταξινομητές οι οποίοι διακρίνουν όλοι τέλεια τα δείγματα των δύο κλάσεων του συνόλου εκπαίδευσης.\n","\n","Το πρόβλημα διαπιστώνεται κατά τη γενίκευση: ανάλογα με το ποια διαχωριστική ευθεία θα επιλέξετε, αν εμφανιστεί ένα νέο δείγμα-σημείο από το σύνολο δεδομένων ελέγχου (π.χ. αυτό που σημειώνεται με το \"X\" σε αυτό το γράφημα), είναι πιθανό να εκχωρηθεί σε μια διαφορετική ετικέτα, ανάλογα την ευθεία.\n","Προφανώς, η απλή ιδέα μας για τη «διαμόρφωση μιας διαχωριστικής ευθείας μεταξύ των κλάσεων» δεν είναι επαρκής και πρέπει να σκεφτούμε λίγο πιο σύνθετα."]},{"cell_type":"markdown","metadata":{"id":"2iF9Ndz_sH04"},"source":["## Μηχανές Διανυσμάτων Υποστήριξης: μεγιστοποιώντας το περιθώριο\n","\n","Τα SVM προσφέρουν μια μέθοδο για να βελτιώσουμε την απόφασή μας. Η ιδέα είναι η εξής: αντί να σχεδιάσουμε ευθείες μηδενικού πλάτους, μπορούμε να σχεδιάσουμε γύρω από κάθε ευθεία ένα περιθώριο κάποιου πλάτους, το οποίο θα φτάνει μέχρι το κοντινότερο σημείο. \n","Στο παράδειγμά μας θα ήταν κάπως έτσι:"]},{"cell_type":"code","metadata":{"id":"wEe00NzpsH05"},"source":["xfit = np.linspace(-1, 3.5)\n","plt.scatter(X[:, 0], X[:, 1], c=y, s=50, cmap='autumn')\n","\n","for m, b, d in [(1, 0.65, 0.33), (0.5, 1.6, 0.55), (-0.2, 2.9, 0.2)]:\n"," yfit = m * xfit + b\n"," plt.plot(xfit, yfit, '-k')\n"," plt.fill_between(xfit, yfit - d, yfit + d, edgecolor='none',\n"," color='#AAAAAA', alpha=0.4)\n","\n","plt.xlim(-1, 3.5);"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"X7biIU2hsH08"},"source":["Στα SVM η γραμμή που μεγιστοποιεί το περιθώριο είναι αυτή που θα επιλεχθεί ως το βέλτιστο μοντέλο. Τα SVM είναι ένα παράδειγμα εκτιμητή μεγιστοποίησης του περιθωρίου (maximum margin estimator)."]},{"cell_type":"markdown","metadata":{"id":"TceIJWjqsH09"},"source":["### Προσαρμογή (εκπαίδευση) των SVM\n","\n","Ας δούμε ένα παράδειγμα πραγματικής εκπαίδευσης SVM σε αυτά τα δεδομένα.\n","Προς το παρόν, θα χρησιμοποιήσουμε έναν γραμμικό πυρήνα και θα ορίσουμε μια πολύ μεγάλη τιμή για την παράμετρο `C`"]},{"cell_type":"code","metadata":{"id":"5MiOhnVGsH09"},"source":["from sklearn.svm import SVC # \"Support vector classifier\"\n","model = SVC(kernel='linear', C=1E10)\n","model.fit(X, y)"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"2pezcZn0sH1E"},"source":["Για να οπτικοποιήσουμε καλύτερα το τί συμβαίνει εδώ, ας ορίσουμε για ευκολία μια συνάρτηση που σχεδιάζει τα όρια των αποφάσεων του SVM μας:"]},{"cell_type":"code","metadata":{"id":"191kg2FEsH1G"},"source":["def plot_svc_decision_function(model, ax=None, plot_support=True):\n"," \"\"\"Plot the decision function for a 2D SVC\"\"\"\n"," if ax is None:\n"," ax = plt.gca()\n"," xlim = ax.get_xlim()\n"," ylim = ax.get_ylim()\n"," \n"," # create grid to evaluate model\n"," x = np.linspace(xlim[0], xlim[1], 30)\n"," y = np.linspace(ylim[0], ylim[1], 30)\n"," Y, X = np.meshgrid(y, x)\n"," xy = np.vstack([X.ravel(), Y.ravel()]).T\n"," P = model.decision_function(xy).reshape(X.shape)\n"," \n"," # plot decision boundary and margins\n"," ax.contour(X, Y, P, colors='k',\n"," levels=[-1, 0, 1], alpha=0.5,\n"," linestyles=['--', '-', '--'])\n"," \n"," # plot support vectors\n"," if plot_support:\n"," ax.scatter(model.support_vectors_[:, 0],\n"," model.support_vectors_[:, 1],\n"," s=300, linewidth=1, facecolors='none');\n"," ax.set_xlim(xlim)\n"," ax.set_ylim(ylim)"],"execution_count":null,"outputs":[]},{"cell_type":"code","metadata":{"id":"8CookkKisH1M"},"source":["plt.scatter(X[:, 0], X[:, 1], c=y, s=50, cmap='autumn')\n","plot_svc_decision_function(model);"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"EasfmdOcsH1S"},"source":["Αυτή είναι η διαχωριστική γραμμή που μεγιστοποιεί το περιθώριο μεταξύ των δύο κλάσεων.\n","Παρατηρήστε ότι μερικά από τα σημεία εκπαίδευσης αγγίζουν το περιθώριο: υποδεικνύονται από τους μαύρους κύκλους στο σχήμα.\n","Αυτά τα σημεία είναι τα κεντρικά στοιχεία αυτής της προσαρμογής, τα αποκαλούμε διανύσματα υποστήριξης και δίνουν στον αλγόριθμο το όνομά του.\n","Στο Scikit-Learn, η θέση των διανυσμάτων υποστήριξης αποθηκεύεται στην ιδιότητα ``support_vectors_`` του ταξινομητή:"]},{"cell_type":"code","metadata":{"id":"CKE45qEWsH1T"},"source":["model.support_vectors_"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"U8LXZiLhsH1Z"},"source":["Ένα σημαντικό χαρακτηριστικό του ταξινομητή είναι ότι μόνο η θέση των διανυσμάτων υποστήριξης έχει σημασία για την εύρεση της βέλτιστης ευθείας. Τυχόν σημεία, μακριά από το περιθώριο, τα οποία βρίσκονται στη σωστή πλευρά δεν επηρεάζουν την εκπαίδευση. Τεχνικά, αυτό οφείλεται στο γεγονός ότι αυτά τα σημεία δεν συμβάλλουν στη συνάρτηση σφάλματος (loss function) που χρησιμοποιείται για να προσαρμοστεί το μοντέλο, επομένως η θέση και ο αριθμός τους δεν έχουν σημασία όσο δεν υπερβαίνουν το περιθώριο.\n","\n","Αυτό μπορούμε να το δούμε, για παράδειγμα, αν σχεδιάσουμε το μοντέλο που μάθαμε από τα πρώτα 60 σημεία και από τα πρώτα 120 σημεία αυτού του συνόλου δεδομένων:"]},{"cell_type":"code","metadata":{"id":"Swf4pbQMsH1b"},"source":["def plot_svm(N=10, ax=None):\n"," X, y = make_blobs(n_samples=200, centers=2,\n"," random_state=0, cluster_std=0.60)\n"," X = X[:N]\n"," y = y[:N]\n"," model = SVC(kernel='linear', C=1E10)\n"," model.fit(X, y)\n"," \n"," ax = ax or plt.gca()\n"," ax.scatter(X[:, 0], X[:, 1], c=y, s=50, cmap='autumn')\n"," ax.set_xlim(-1, 4)\n"," ax.set_ylim(-1, 6)\n"," plot_svc_decision_function(model, ax)\n","\n","fig, ax = plt.subplots(1, 2, figsize=(16, 6))\n","fig.subplots_adjust(left=0.0625, right=0.95, wspace=0.1)\n","for axi, N in zip(ax, [60, 120]):\n"," plot_svm(N, axi)\n"," axi.set_title('N = {0}'.format(N))"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"4Rft-IWUsH1i"},"source":["Στο αριστερά, βλέπουμε το μοντέλο και τα διανύσματα υποστήριξης για 60 σημεία εκπαίδευσης. Στα δεξιά, έχουμε διπλασιάσει τον αριθμό των σημείων εκπαίδευσης, αλλά το μοντέλο δεν έχει αλλάξει: τα τρία διανύσματα υποστήριξης από το αριστερό γράφημα εξακολουθούν να είναι τα διανύσματα υποστήριξης και στο δεξί.\n","\n","Αυτή η “αναισθησία” στην ακριβή συμπεριφορά των απομακρυσμένων σημείων είναι ένα από τα πλεονεκτήματα του μοντέλου SVM."]},{"cell_type":"markdown","metadata":{"id":"IcHP-rFZsH1j"},"source":["Στα notebooks μπορούμε να δούμε και διαδραστικά αυτή την ιδιότητα χρησιμοποιώντας τα widgets του IPython:"]},{"cell_type":"code","metadata":{"id":"wspW9zLIsH1k"},"source":["from ipywidgets import interact, fixed\n","!jupyter nbextension enable --py widgetsnbextension\n","interact(plot_svm, N=[10, 100, 200, 400], ax=fixed(None));"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"mfjbi0aBsH1t"},"source":["### Πέρα από τα γραμμικά διαχωρίσιμα προβλήματα: Kernel SVM\n","\n","Τα SVM γίνονται εξαιρετικά ισχυρά όταν συνδυάζονται με πυρήνες (kernels)\n","\n","Συναρτήσεις πυρήνων (kernel functions): αποκαλούμε συναρτήσεις πυρήνα ή απλά πυρήνες, συναρτήσεις που ορίζουν το εσωτερικό γινόμενο (ομοιότητα) μεταξύ δύο διανυσμάτων εισόδου σε έναν άλλο διανυσματικό χώρο, συχνά πολύ μεγαλύτερων (ή και άπειρων). διαστάσεων \n","\n","Για να δούμε τη χρησιμότητα των πυρήνων στα SVM ας δούμε μερικά δεδομένα που δεν είναι γραμμικά διαχωρίσιμα:"]},{"cell_type":"code","metadata":{"id":"dv01qLhSsH1v"},"source":["from sklearn.datasets.samples_generator import make_circles\n","X, y = make_circles(100, factor=.1, noise=.1)\n","\n","clf = SVC(kernel='linear').fit(X, y)\n","\n","plt.scatter(X[:, 0], X[:, 1], c=y, s=50, cmap='autumn')\n","plot_svc_decision_function(clf, plot_support=False);"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"sSoWq0-nsH10"},"source":["Είναι προφανώς ότι δεν μπορεί να γίνει γραμμικός διαχωρισμός στα δεδομένα αυτά. Μια συνηθισμένη τεχνική σε τέτοιες περιπτώσεις είναι να προβάλλουμε τα δεδομένα σε υψηλότερες διαστάσεις έτσι ώστε ένας γραμμικός διαχωριστής να είναι επαρκής.\n","\n","Για παράδειγμα, μια απλή προβολή που θα μπορούσαμε να χρησιμοποιήσουμε θα ήταν να υπολογίσουμε μια συνάρτηση ακτινική βάσης (radial basis function - RBF)\n","\n","![](https://miro.medium.com/max/1260/1*izqr1xGcP89B7Xs1EluIQQ.png)\n","\n"," με επίκεντρο τη μεσαία συστάδα δηλαδή center = (0,0):"]},{"cell_type":"code","metadata":{"id":"RvULF_dYsH11"},"source":["r = np.exp(-(X ** 2).sum(1))"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"xWINx5NAAqip"},"source":["Θυυμηθείτε ότι $||\\boldsymbol {x}||_{2}:={\\sqrt {x_{1}^{2}+\\cdots +x_{n}^{2}}}$ άρα τελικά έχουμε το άθροισμα των τετραγώνων όλων των διαστάσεων. Στην απλή αυτή περίπτωση λαμβάνουμε $γ=1$."]},{"cell_type":"markdown","metadata":{"id":"a9yqlaa7sH14"},"source":["![RBF](https://upload.wikimedia.org/wikipedia/commons/thumb/3/3e/Gaussian_2d.svg/300px-Gaussian_2d.svg.png)\n","\n","Μπορούμε να οπτικοποιήσουμε την πρόσθετη διάσταση με ένα τρισδιάστατο γράφημα. Εντός notebooks μπορούμε να χρησιμοποιήσουμε τα sliders για να περιστρέψουμε το γράφημα:"]},{"cell_type":"code","metadata":{"id":"rSOzWM43sH15"},"source":["from mpl_toolkits import mplot3d\n","\n","def plot_3D(elev=30, azim=30, X=X, y=y):\n"," ax = plt.subplot(projection='3d')\n"," ax.scatter3D(X[:, 0], X[:, 1], r, c=y, s=50, cmap='autumn')\n"," ax.view_init(elev=elev, azim=azim)\n"," ax.set_xlabel('x')\n"," ax.set_ylabel('y')\n"," ax.set_zlabel('r')\n","\n","interact(plot_3D, elev=[-90, 90], azip=(-180, 180),\n"," X=fixed(X), y=fixed(y));"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"UvHxQHsAsH18"},"source":["Μπορούμε να δούμε ότι με αυτήν την πρόσθετη διάσταση, τα δεδομένα καθίστανται γραμμικά διαχωρίσιμα, σχεδιάζοντας για παράδειγμα ένα διαχωριστικό επίπεδο στο, ας πούμε, r = 0,7 (άξονας του z).\n","\n","Πρέπει να επιλέξουμε προσεκτικά την προβολή μας: εάν δεν είχαμε “κεντράρει” τη συνάρτηση ακτινικής βάσης στη σωστή θέση, δεν θα είχαμε δει καθαρά, γραμμικά διαχωρίσιμα αποτελέσματα. Γενικά, η ανάγκη να κάνουμε μια τέτοια καλή επιλογή είναι πρόβλημα: θα θέλαμε να μπορούμε να βρούμε αυτόματα τις καλύτερες ακτινικές συναρτήσεις βάσης.\n","\n","Μία στρατηγική προς το σκοπό αυτό είναι να υπολογιστεί μια συνάρτηση βάσης που επικεντρώνεται σε κάθε σημείο του συνόλου δεδομένων και να αφήσουμε τον αλγόριθμο SVM να διαλέξει τα αποτελέσματα. Αυτός ο τύπος μετασχηματισμού συνάρτησης βάσης είναι γνωστός ως μετασχηματισμός πυρήνα, καθώς βασίζεται στη σχέση ομοιότητας (ή πυρήνα) μεταξύ κάθε ζεύγους σημείων.\n","\n","Ένα πιθανό πρόβλημα με αυτήν τη στρατηγική δηλαδή την προβολή $ N $ σημείων σε $ N $ διαστάσεις (όπου κάθε πρόβλημα γίνεται διαχωρίσιμο) είναι ότι μπορεί να γίνει πολύ ακριβή υπολογιστικά καθώς το $ N $ μεγαλώνει.\n","\n","Ωστόσο, χάρη σε μια πολύ βολική ιδιότητα γνωστή ως [kernel trick](https://en.wikipedia.org/wiki/Kernel_trick), η εκπαίδευση με δεδομένα που έχουν μετασχηματιστεί από την συνάρτηση πυρήνα σε πολύ μεγάλες διαστάσεις μπορεί να γίνει σιωπηρά, δηλαδή χωρίς ποτέ να υπολογίσουμε την πλήρη αναπαράσταση των διανυσμάτων στον χώρο προβολής του πυρήνα υψηλών διαστάσεων $ Ν $. Τα SVM βασίζονται στο kernel trick για την επίλυση μη γραμμικών προβλημάτων με προβολή σε χώρους υψηλής διαστατικότητας.\n","\n","Στο Scikit-Learn, μπορούμε να εφαρμόσουμε μετασχηματισμού πυρήνα στα SVM απλά αλλάζοντας τον γραμμικό μας πυρήνα σε έναν πυρήνα RBF (συνάρτηση ακτινικής βάσης), χρησιμοποιώντας την υπερπαράμετρο `kernel` του μοντέλου."]},{"cell_type":"code","metadata":{"id":"5v78_xbfsH18"},"source":["clf = SVC(kernel='rbf', C=1E6)\n","clf.fit(X, y)"],"execution_count":null,"outputs":[]},{"cell_type":"code","metadata":{"id":"KI3JRmNusH2A"},"source":["plt.scatter(X[:, 0], X[:, 1], c=y, s=50, cmap='autumn')\n","plot_svc_decision_function(clf)\n","plt.scatter(clf.support_vectors_[:, 0], clf.support_vectors_[:, 1],\n"," s=300, lw=1, facecolors='none');"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"yjrLKMWqsH2G"},"source":["Χρησιμοποιώντας αυτό το “κόλπο” με τα SVM, μπορούμε να μάθουμε ένα κατάλληλο μη γραμμικό όριο αποφάσεων (στο αρχικό χώρο των διανυσμάτων).\n","Αυτή η στρατηγική μετασχηματισμού πυρήνα χρησιμοποιείται συχνά στη μηχανική μάθηση για να μετατρέψει γρήγορες γραμμικές μεθόδους σε γρήγορες μη γραμμικές μεθόδους, ειδικά σε μοντέλα στα οποία μπορεί να χρησιμοποιηθεί το κόλπο του πυρήνα."]},{"cell_type":"markdown","metadata":{"id":"ic9wRzwtsH2H"},"source":["### Ρύθμιση των SVM: μαλακό περιθώριο\n","\n","Μέχρι στιγμής επικεντρώθηκε σε πολύ καθαρά σύνολα δεδομένων, στα οποία υπάρχει ένα τέλειο όριο αποφάσεων.\n","Τι γίνεται όμως αν τα δεδομένα μας έχουν κάποια αλληλεπικάλυψη;\n","Για παράδειγμα, μπορεί να έχετε δεδομένα όπως αυτό:"]},{"cell_type":"code","metadata":{"id":"1vsxkHwzsH2I"},"source":["X, y = make_blobs(n_samples=100, centers=2,\n"," random_state=0, cluster_std=1.2)\n","plt.scatter(X[:, 0], X[:, 1], c=y, s=50, cmap='autumn');"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"OWxO4bfKsH2N"},"source":["Για να χειριστεί αυτήν την περίπτωση, η υλοποίηση των SVM έχει μια ιδιότητα που \"μαλακώνει\" το περιθώριο: επιτρέπει δηλαδή σε ορισμένα από τα σημεία να περάσουν στο περιθώριο εάν αυτό επιτρέπει καλύτερη προσαρμογή.\n","Η σκληρότητα του περιθωρίου ελέγχεται από μια υπερπαράμετρο, πιο συχνά γνωστή ως $ C $ (από το “Cost”).\n","Για πολύ μεγάλα $ C $, το περιθώριο είναι σκληρό και δεν μπορούν να βρεθούν \n","καθόλου σημεία εντός του περιθωρίου.\n","Για μικρότερα $ C $, το περιθώριο είναι πιο μαλακό και μπορεί να συμπεριλάβει εντός του κάποια σημεία.\n","\n","Το διάγραμμα που φαίνεται παρακάτω δίνει μια οπτική εικόνα για το πώς η μεταβαλλόμενη υπερπαράμετρος $ C $ επηρεάζει την τελική λειτουργία του ταξινομητή, μέσω της εξασθένισης του περιθωρίου:"]},{"cell_type":"code","metadata":{"id":"a9WoArNEsH2N"},"source":["X, y = make_blobs(n_samples=100, centers=2,\n"," random_state=0, cluster_std=0.8)\n","\n","fig, ax = plt.subplots(1, 2, figsize=(16, 6))\n","fig.subplots_adjust(left=0.0625, right=0.95, wspace=0.1)\n","\n","for axi, C in zip(ax, [10.0, 0.1]):\n"," model = SVC(kernel='linear', C=C).fit(X, y)\n"," axi.scatter(X[:, 0], X[:, 1], c=y, s=50, cmap='autumn')\n"," plot_svc_decision_function(model, axi)\n"," axi.scatter(model.support_vectors_[:, 0],\n"," model.support_vectors_[:, 1],\n"," s=300, lw=1, facecolors='none');\n"," axi.set_title('C = {0:.1f}'.format(C), size=14)"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"yaxqYaAgsH2T"},"source":["Η εύρεση του βέλτιστου $C$, όπως για όλες τις υπερπαραμέτρους, γίνεται με διασταυρούμενη επικύρωση (cross-validation). \n","Αντιλαμβανόμαστε ότι τo $C$ είναι βέβαια μια παράμετρος ομαλοποίησης (regularization). Μεγάλο $C$ σημαίνει μεγάλη πόλωση (bias) όπου δεν αφήνουμε καθόλου λάθος ταξινομημένα δείγματα, πιθανώς οδηγώντας σε στενό μέγιστο περιθώριo, υπερεκπαίδευση και όχι καλή γενίκευση. Αντιθετοαντίστροφα, πολύ μικρό $C$ σημαίνει ότι επιτρέπουμε μεγάλα μέγιστα περιθώρια με πολλά δείγματα εντός του περιθωρίου"]},{"cell_type":"markdown","metadata":{"id":"weM5aJdTsH2U"},"source":["## Εφαρμογή: Επιβεβαίωση προσώπων (Face verification)\n","\n","\n","Για να δούμε τα SVM στην πράξη, θα εξετάσουμε ένα πρόβλημα επιβεβαίωσης προσώπων. Σημειώστε ότι αυτό είναι ένα διαφορετικό πρόβλημα από την αναγνώριση προσώπων (face recognition). Στην αναγνώριση θέλουμε να εντοπίσουμε τα πρόσωπα εντός μιας φωτογραφίας (την περιοχή που τα περικλύει, στην επιβεβαίωση έχουμε μόνο πρόσωπα εντός της εικόνας και θέλουμε βρούμε σε ποιον ανήκει το πρόσωπο.\n","\n","Θα χρησιμοποιήσουμε το σύνολο δεδομένων [“Labeled Faces in the Wild”](http://vis-www.cs.umass.edu/lfw/), το οποίο αποτελείται από αρκετές χιλιάδες συγκεντρωμένες φωτογραφίες διαφόρων δημόσιων προσώπων. Το σύνολο δεδομένων είναι ενσωματωμένο στο Scikit-Learn:"]},{"cell_type":"code","metadata":{"id":"y702L57PsH2V"},"source":["from sklearn.datasets import fetch_lfw_people\n","faces = fetch_lfw_people(min_faces_per_person=60)\n","print(faces.target_names)\n","print(faces.images.shape)"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"AF5Inh62sH2a"},"source":["Ας τυπώσουμε μερικές εικόνες για να δούμε με τι δουλεύουμε: "]},{"cell_type":"code","metadata":{"id":"UzymH55WsH2b"},"source":["fig, ax = plt.subplots(3, 5)\n","for i, axi in enumerate(ax.flat):\n"," axi.imshow(faces.images[i], cmap='bone')\n"," axi.set(xticks=[], yticks=[],\n"," xlabel=faces.target_names[faces.target[i]])"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"CJExtaEksH2g"},"source":["Κάθε εικόνα περιέχει [62 × 47] ή αλλιώς 2914 εικονοστοιχεία (pixels). Θα μπορούσαμε να προχωρήσουμε απλά χρησιμοποιώντας κάθε τιμή pixel ως χαρακτηριστικό, αλλά συχνά είναι πιο αποτελεσματικό να χρησιμοποιούμε κάποιο είδος προεπεξεργαστή για την εξαγωγή των περισσότερο σημαντικών χαρακτηριστικών. Εδώ θα χρησιμοποιήσουμε τη γνωστή μας ανάλυση σε κύριες συνιστώσες. Θα “πακετάρουμε” τον προεπεξεργαστή και τον ταξινομητή σε ένα pipeline:"]},{"cell_type":"code","metadata":{"id":"zR0xQmE7sH2h"},"source":["from sklearn.svm import SVC\n","from sklearn.decomposition import PCA as RandomizedPCA\n","from sklearn.pipeline import make_pipeline\n","\n","pca = RandomizedPCA(whiten=True)\n","svc = SVC(class_weight='balanced')\n","model = make_pipeline(pca, svc)"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"OIqRLJOZsH2o"},"source":["Κατά τα γνωστά, διαχωρίζουμε σε train και test set:"]},{"cell_type":"code","metadata":{"id":"rVFHYqYHsH2p"},"source":["from sklearn.model_selection import train_test_split\n","Xtrain, Xtest, ytrain, ytest = train_test_split(faces.data, faces.target)"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"fZ4VSJ6AsH2s"},"source":["Θα χρησιμοποιήσουμε διασταυρούμενη επικύρωση πλέγματος για να διερευνήσουμε τους συνδυασμούς όλων των υπερπαραμέτρων. Σημειώστε ότι και το είδος της συνάρτησης πυρήνα είναι υπερπαράμετρος και ότι η βιβλιοθήκη είναι αρκετά “έξυπνη” για να καταλάβει ότι ο γραμμικός πυρήνας δεν έχει πάραμετρο $γ$."]},{"cell_type":"code","metadata":{"id":"LA7XnP3-sH2t"},"source":["from sklearn.model_selection import GridSearchCV\n","param_grid = {'pca__n_components': [80, 100],\n"," 'svc__kernel': ['linear', 'rbf'],\n"," 'svc__C': [40, 50, 60],\n"," 'svc__gamma': [0.00025, 0.0005, 0.001]}\n","grid = GridSearchCV(model, param_grid)\n","\n","%time grid.fit(Xtrain, ytrain)\n","print(grid.best_params_)"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"k2LxHWYDsH2x"},"source":["Η υπερπαράμετρος $γ$ ελέγχει το μήκος της ακτίνας των RBF. Μεγάλο $γ$ δημιουργεί στενές και ψηλές RBF, μικρός $γ$ πλατιές και χαμηλές.\n","\n","![](https://miro.medium.com/max/2400/1*r9CO-gp1uuRsYooCLL9UeQ.png)\n","\n","Η εύρεση του βέλτιστου $γ$ είναι σημαντική για την σωστή εκπαίδευση SVM με πυρήνα RBF (αποφυγή υποπροσαρμογής - υπερπροσαρμογής). \n","\n","\n","Συνεχίζοντας, οι βέλτιστες τιμές πέφτουν προς τη μέση του πλέγματος μας. Αν έπεφταν στα άκρα, θα έπρεπε να επεκτείνουμε το πλέγμα για να βεβαιωθούμε ότι βρήκαμε το πραγματικό βέλτιστο.\n","\n","Μπορούμε πλέον να προβλέψουμε τις ετικέτες στα δεδομένα ελέγχου, τα οποία το μοντέλο δεν έχει δει ακόμη, ώστε να λάβουμε ένα μέτρο της ικανότητας γενίκευσής του:"]},{"cell_type":"code","metadata":{"id":"qw730iGFsH2z"},"source":["model = grid.best_estimator_\n","yfit = model.predict(Xtest)"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"H4RkjlHhsH24"},"source":["Ας ρίξουμε μια ματιά σε μερικές από εικόνες του test set μαζί με τις προβλεπόμενες ετικέτες τους:"]},{"cell_type":"code","metadata":{"id":"_KExiS94sH24"},"source":["fig, ax = plt.subplots(4, 6)\n","for i, axi in enumerate(ax.flat):\n"," axi.imshow(Xtest[i].reshape(62, 47), cmap='bone')\n"," axi.set(xticks=[], yticks=[])\n"," axi.set_ylabel(faces.target_names[yfit[i]].split()[-1],\n"," color='black' if yfit[i] == ytest[i] else 'red')\n","fig.suptitle('Predicted Names; Incorrect Labels in Red', size=14);"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"GCNIKEGhsH27"},"source":["Για τη συνολική αξιολόγηση της απόδοσης του ταξινομητή θα χρησιμοποιήσουμε το γνωστό μας `classification_report`:"]},{"cell_type":"code","metadata":{"id":"Qr6QoiJBsH27"},"source":["from sklearn.metrics import classification_report\n","print(classification_report(ytest, yfit,\n"," target_names=faces.target_names))"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"PwIngMdVsH2_"},"source":["Τυπώνουμε επίσης τον πίνακα σύγχυσης (confusion matrix):"]},{"cell_type":"code","metadata":{"id":"E-MAGsi0sH3A"},"source":["from sklearn.metrics import confusion_matrix\n","mat = confusion_matrix(ytest, yfit)\n","sns.heatmap(mat.T, square=True, annot=True, fmt='d', cbar=False,\n"," xticklabels=faces.target_names,\n"," yticklabels=faces.target_names)\n","plt.xlabel('true label')\n","plt.ylabel('predicted label');"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"8roOhfPSsH3C"},"source":["Ο πίνακας σύγχυσης μας βοηθά να κατανοήσουμε ποιες ετικέτες είναι πιθανό να συγχέονται από τον εκτιμητή. \n","\n","Η εφαρμογή που κάναμε είναι πολύ απλή. Μια σοβαρότερη εφαρμογή θα χρησιμοποιούσε την de facto βιβλιοθήκη όρασης υπολογιστών [OpenCV](http://opencv.org) για την εξαγωγή χαρακτηριστικών."]},{"cell_type":"markdown","metadata":{"id":"NPC7BddlsH3D"},"source":["## Support Vector Machines: Σύνοψη\n","\n","Στο notebook αυτό κάναμε μια διαισθητική εισαγωγή στις αρχές πίσω από τις μηχανές διανυσμάτων υποστήριξης.\n","\n","Τα SVM είναι μια ισχυρή μέθοδος ταξινόμησης για διάφορους λόγους:\n","\n","- Η εξάρτησή τους από σχετικά λίγα διανύσματα υποστήριξης σημαίνει ότι είναι πολύ συμπαγή μοντέλα και καταλαμβάνουν πολύ λίγη μνήμη.\n","- Εφόσον εκπαιδευτεί το μοντέλο, η φάση πρόβλεψης είναι πολύ γρήγορη. Συγκρίνετε με ταξινομητές βασισμένους σε στιγμιότυπα (instance-based) όπως ο kNN όπου για κάθε δείγμα του test πρέπει να υπολογίσουμε την απόστασή από όλα τα σημεία του train.\n","- Επειδή επηρεάζονται μόνο από σημεία κοντά στο περιθώριο, λειτουργούν καλά με δεδομένα υψηλών διαστάσεων - ακόμη και δεδομένα με περισσότερες διαστάσεις από ότι δείγματα, κάτι που αποτελεί πρόκληση για άλλους αλγόριθμους.\n","- Η ενσωμάτωσή τους με μεθόδους πυρήνα τα καθιστά πολύ ευέλικτα, ικανά να προσαρμοστούν σε πολλούς τύπους δεδομένων.\n","\n","Ωστόσο, τα SVM έχουν επίσης και αρκετά μειονεκτήματα:\n","\n","- Η κλιμάκωση με τον αριθμό των δειγμάτων $ N $ είναι στη χειρότερη $ {O} [N ^ 3] $ και $ {O} [N ^ 2] $ για αποτελεσματικές υλοποιήσεις. Για μεγάλο αριθμό δειγμάτων εκπαίδευσης, αυτό το υπολογιστικό κόστος μπορεί να είναι απαγορευτικό. Μια εναλλακτική λύση είναι η χρήση της παραλλαγής SMO (Sequential Minimal Optimization) των SVM. Η SMO σπάει το πρόβλημα βελτιστοποίησης των SVM σε πολλά μικρότερα προβλήματα, πιο εύκολα επιλύσιμα. Η SMO δεν υποστηρίζεται από το scikit, αλλά υποστηρίζεται από την \"canonical\" βιβλιοθήκη SVM, την [LIBSVM](https://www.csie.ntu.edu.tw/~cjlin/libsvm/). Περισσότερα για την SMO [link1](https://jonchar.net/notebooks/SVM/), [link2](http://chubakbidpaa.com/svm/2020/12/27/smo-algorithm-simplifed-copy.html). \n","\n","- Τα αποτελέσματα εξαρτώνται σε μεγάλο βαθμό από την κατάλληλη επιλογή για την παράμετρο μαλακώματος $ C $. Αυτό πρέπει να γίνει μόνο με cross-validation ή οποία μπορεί να είναι ακριβή υπολογιστικά αν έχουμε πολλά δεδομένα.\n","- Τα αποτελέσματα δεν έχουν άμεση πιθανοτική ερμηνεία (κατά πόσο ένα δείγμα ανήκει σε μία κλάση), όπως θα είχαμε σε ένα MLP με συνάρτηση ενεργοποίησης softmax στην έξοδο ή όπως έχουμε στη λογιστική παλινδρόμηση (logistic regression). Σε κάποιες περιπτώσεις SVM αυτό μπορεί να εκτιμηθεί μέσω μιας εσωτερικής διασταυρούμενης επικύρωσης (δείτε την παράμετρο \"probability\" του \"SVC\"), αλλά αυτή η επιπλέον εκτίμηση είναι υπολογιστικά δαπανηρή.\n","\n","Λαμβάνοντας υπόψη τα ανωτέρω χαρακτηριστικά, γενικά στρεφόμαστε στα SVMs όταν άλλες απλούστερες, ταχύτερες και λιγότερο απαιτητικές μέθοδοι έχουν αποδειχθεί ανεπαρκείς για τις ανάγκες του προβλήματος.\n","\n","Ωστόσο, εάν έχετε επαρκείς υπολογιστικούς πόρους για να δεσμεύσετε στην εκπαίδευση και την επικύρωση ενός SVM στα δεδομένα σας, η μέθοδος μπορεί να οδηγήσει σε εξαιρετικά αποτελέσματα."]},{"cell_type":"markdown","metadata":{"id":"EvsFMvcEBQcK"},"source":["# Τα είδη των ταξινομητών\n","\n","Έχουμε πλέον εξετάσει διάφορους ταξινομητές έτσι ώστε να μπορούμε να τους κατατάξουμε σε τρεις κατηγορίες, σύμφωνα με το επόμενο σχήμα.\n","\n","![](https://i2.paste.pics/8569adc1d80d3b5a37188897ac0375aa.png)"]}]}