#!/usr/bin/env python # coding: utf-8 # Sveučilište u Zagrebu
# Fakultet elektrotehnike i računarstva # # # Strojno učenje # # http://www.fer.unizg.hr/predmet/su # # Ak. god. 2015./2016. # # # Bilježnica 6: Linearni diskriminativni modeli # # (c) 2015 Jan Šnajder # # Verzija: 0.1 (2015-11-11) # In[188]: import scipy as sp import scipy.stats as stats import matplotlib.pyplot as plt import pandas as pd get_ipython().run_line_magic('pylab', 'inline') # ### Sadržaj: # # * Uvod # # * Poopćeni linearni model # # * Geometrija linearnog modela # # * Višeklasna klasifikacija # # * Klasifikacija regresijom # # * Gradijentni spust # # * Perceptron # # * Sažetak # # Uvod # # * **Diskriminativni modeli:** Za razliku od generativnih modela, koji modeliraju # $ # P(\mathcal{C}_j|\mathbf{x})\ \propto\ P(\mathbf{x}|\mathcal{C}_j) P(\mathcal{C}_j) # $, # modeliramo: # * izravno aposteriornu vjerojatnost klase, $P(\mathcal{C}_j|\mathbf{x})$, ili # * izravno *diskriminacijsku* (klasifikacijsku) funkciju $h(\mathbf{x})$ # # # * **Linearan modeli:** Granica je linearna (hiperravnina): # # $$ # h(\mathbf{x}) = \mathbf{w}^\intercal\tilde{\mathbf{x}} # $$ # # # * Model je linearan u značajkama $\mathbf{x}$ $\Rightarrow$ to daje linearnu granica u ulaznom # prostoru # # # * Granica je hiperravnina za koju $h(\mathbf{x})=0$ ili $h(\mathbf{x})=0.5$ (ovisno o modelu) # # # * Granicu zovemo **diskriminativna funkcija** (engl. *discriminative functions*) ili **granica odluke**, **decizijska granica** (engl. *decision boundary*) # In[189]: def h(x, w): return sp.dot(x, w) # In[190]: def plot_decision_boundary(h, boundary=0, margins=None): x = linspace(-10, 10) y = linspace(-10, 10) X1, X2 = np.meshgrid(x, y) XX = sp.dstack((sp.ones((50, 50)), X1, X2)) plt.contour(X1, X2, h(XX), linecolor='red', levels=[boundary]) if margins!=None: CS = plt.contour(X1, X2, h(XX), colors=['gray', 'gray'], levels=[margins[0],margins[1]]) plt.clabel(CS, fontsize=9, inline=1) # In[191]: w = [-2, 1, -0.5] plot_decision_boundary(lambda x : h(x, w), margins=(-1,1)) # In[112]: w = [2, -1, 0.5] plot_decision_boundary(lambda x : h(x, w), margins=(-1,1)) # In[115]: w = [2, -1.5, 0.3] plot_decision_boundary(lambda x : h(x, w), margins=(-1,1)) # # Poopćeni linearan model # # * **Aktivacijska funkcija:** nelinearna funkcija # $$ # f:\mathbb{R}\to[0,1] # $$ # ili # $$ # f:\mathbb{R}\to[-1,1] # $$ # # # * Poopćeni linearan model (engl. *generalized linear model*, GLM): # # $$ # h(\mathbf{x}) = \color{red}{f\big(}\mathbf{w}^\intercal\tilde{\mathbf{x}}\color{red}{\big)} # $$ # # $\Rightarrow$ **Linearna granica** u ulaznom prostoru (premda je $f$ nelinearna) # # $\Rightarrow$ Model je **nelinearan u parametrima** (jer je $f$ nelinearna) # # * Tipične funkcije preslikavanja: # * Funkcija identiteta (tj. kao da nema preslikavanja) # * Sigmoidalna (logistička) funkcija # * Funkcija skoka (step-funkcija) # In[32]: xs = sp.linspace(-5,5, 100) plt.plot(xs, xs); # In[33]: def sigm(x): return 1 / (1 + sp.exp(-x)) plt.plot(xs, sigm(xs)); # In[34]: plt.plot(xs, sign(xs)); # * Odabir funkcije $f$ nema utjecaja na linearnost granice, budući da će, očigledno, funkcija $f$ za iste ulazne vrijednosti $\mathbf{w}^\intercal\mathbf{x}$ davati iste vrijednosti $f(\mathbf{w}^\intercal\mathbf{x})$ # In[192]: w = [-4, 2, -1] plot_decision_boundary(lambda x : h(x, w), margins=(-1,1)) # In[193]: plot_decision_boundary(lambda x : sigm(sp.dot(x, w)), boundary=0.5, margins=(0.1,0.9)) # Kao i kod regresije, možemo koristiti preslikavanje # $\boldsymbol{\phi}:\mathbb{R}^n\to\mathbb{R}^m$ iz ulaznog # prostora u prostor značajki: # # $$ # h(\mathbf{x}) = f\big(\mathbf{w}^\intercal\mathbf{\phi}(\mathbf{x})\big) # $$ # # $\Rightarrow$ Linearna granica u prostoru značajki # # $\Rightarrow$ **Nelinearna granica** u ulaznom # prostoru # # $\Rightarrow$ Model je **nelinearan u parametrima** (jer je $f$ nelinearna) # # ### Primjer: # # * Preslikavanje iz dvodimenzijskog ulaznog prostora u 5-dimenzijski prostor značajki # # $$ # \boldsymbol{\phi}(\mathbf{x}) = (1,x_1,x_2,x_1 x_2, x_1^2, x_2^2) # $$ # In[194]: def h2(x, w): x2 = sp.dstack((x, x[:,:,1]*x[:,:,2], x[:,:,1]**2, x[:,:,2]**2)) return sp.dot(x2, w) # In[121]: w = [-0.05 , -0.15 , -0.5 , 0.15 , -0.08 , 0.05] plot_decision_boundary(lambda x : h2(x, w), margins=[-1, 1]) # # Geometrija linearnog modela # * [Skica] # # # * Za točke $\mathbf{x}_1$ i $\mathbf{x}_2$ na hiperravnini: # $$ # h(\mathbf{x}_1)=h(\mathbf{x}_2)=0\quad \Rightarrow\quad \mathbf{w}^\intercal(\mathbf{x}_1-\mathbf{x}_2) = 0 # $$ # $\Rightarrow$ $\mathbf{w}$ je normala hiperravnine # # # * **NB:** U iduće dvije točke $\mathbf{w}$ ne uključuje $w_0$ # # # * Za točku $\mathbf{x}$ na hiperravnini: # $$ # \mathbf{w}^\intercal\mathbf{x} + w_0 = 0 \quad\Rightarrow\quad # \frac{\mathbf{w}^\intercal\mathbf{x}}{\|\mathbf{w}\|}=-\frac{w_0}{\|\mathbf{w}\|} # $$ # $\Rightarrow$ udaljenost ravnine od ishodišta je $-w_0/\|\mathbf{w}\|$ # # # * Za točku $\mathbf{x}$ izvan hiperravnine: # $$ # \begin{align*} # \mathbf{x} &= \mathbf{x}_{\bot} + d\frac{\mathbf{w}}{\|\mathbf{w}\|}\\ # \mathbf{w}^\intercal\mathbf{x} + w_0 &= \mathbf{w}^\intercal\mathbf{x}_{\bot} + w_0 + d \frac{\mathbf{w}^\intercal\mathbf{w}}{\|\mathbf{w}\|}\\ # h(\mathbf{x}) &= d \|\mathbf{w}\| # \end{align*} # $$ # # $\Rightarrow$ udaljenost točke $\mathbf{x}$ od ravnine je $d=h(\mathbf{x})/\|\mathbf{w}\|$ # * $h(\mathbf{x}) > 0\ \Rightarrow\ $ $\mathbf{x}$ je na strani hiperravnine u smjeru normale $\mathbf{w}$ # * $h(\mathbf{x}) < 0\ \Rightarrow\ $ $\mathbf{x}$ je na suprotnoj strani hiperravnine # * $h(\mathbf{x}) = 0\ \Rightarrow\ $ $\mathbf{x}$ je na hiperravnini # In[122]: w = sp.array([-4, 2, -1]) X = sp.array([[1, 5, -1], [1, -5, 5]]) plot_decision_boundary(lambda x : h(x, w), margins=(-1, 1)) plt.scatter(X[:,1],X[:,2]); # In[78]: h(X[0], w) # In[82]: h(X[1], w) # In[176]: sp.linalg.norm(w[1:]) # In[195]: def distance(x,w): return sp.dot(x, w) / sp.linalg.norm(w[1:]) # In[196]: distance(X[0], w) # In[180]: distance(X[1], w) # In[181]: w2 = w/10.0 plot_decision_boundary(lambda x : h(x, w2), margins=(-1,1)) plt.scatter(X[:,1],X[:,2]); # In[182]: h(X[0], w2) # In[183]: h(X[1], w2) # In[185]: sp.linalg.norm(w2[1:]) # In[186]: distance(X[0], w2) # In[187]: distance(X[1], w2) # # Višeklasna klasifikacija ($K>2$) # # # * Shema **jedan-naspram-jedan** (engl. *one-vs-one*, **OVO**) # * $K\choose 2$ binarnih klasifikatora, razdjeljuju sve parove klasa # * Model: # $$ # h(\mathbf{x})=\mathrm{argmax}_i\sum_{i\neq j}\mathrm{sgn}\big(h_{ij}(\mathbf{x})\big) # $$ # gdje $h_{ji}(\mathbf{x})=- h_{ij}(\mathbf{x})$ # # # * [Skica: OVO] # # # * Shema **jedan-naspram-ostali** (engl. *one-vs-rest*, **OVR**, *one-vs-all*) # * $K$ binarnih klasifikatora s pouzdanošću, po jedan za svaku klasu # * Model: # $$ # h(\mathbf{x}) = \mathrm{argmax}_j\ h_j(\mathbf{x}) # $$ # # # * [Skica: OVR] # # # * Prednost OVR nad OVO je da imamo manje modela, međutim OVR lako rezultira neuravnoteženim brojem primjera kroz klase # In[197]: h1 = lambda x: h(x, [0, 2, 1]) plot_decision_boundary(h1) h2 = lambda x: h(x, [-0.2, 0.7, -0.8]) plot_decision_boundary(h2) h3 = lambda x: h(x, [-1.5, 0.1, 0.5]) plot_decision_boundary(h3) plt.scatter(X[:,1],X[:,2]); # In[152]: print h1(X[0]), h2(X[0]), h3(X[0]) # In[153]: print h1(X[1]), h2(X[1]), h3(X[1]) # In[198]: def ovr(x): return sp.argmax([h1(x), h2(x), h3(x)]) # In[199]: ovr(X[0]) # In[200]: ovr(X[1]) # In[157]: x = linspace(-10, 10) y = linspace(-10, 10) X1, X2 = np.meshgrid(x, y) XX = sp.dstack((sp.ones((50, 50)), X1, X2)) # In[166]: n, m, _ = shape(XX) YY = sp.zeros((n,m)) for i in range(0,n): for j in range(0,m): YY[i,j] = ovr(XX[i, j]) # In[175]: plt.contourf(X1, X2, YY); # # Klasifikacija regresijom # ### Podsjetnik # # * [Skica] # # # * Funkcija pogreške (empirijsko očekivanje kvadratnog gubitka): # $$ # E(\mathbf{w}|\mathcal{D})=\frac{1}{2} # \sum_{i=1}^N\big(\mathbf{w}^\intercal\boldsymbol{\phi}(\mathbf{x}^{(i)}) - y^{(i)}\big)^2 = # \frac{1}{2} # (\boldsymbol\Phi\mathbf{w} - \mathbf{y})^\intercal # (\boldsymbol\Phi\mathbf{w} - \mathbf{y}) # $$ # # # * Minimizator pogreške: # $$ # \mathbf{w} = (\boldsymbol\Phi^\intercal\boldsymbol\Phi)^{-1}\boldsymbol\Phi^\intercal\mathbf{y} # = \color{red}{\boldsymbol\Phi^{+}}\mathbf{y} # $$ # # # * **Q:** Kako iskoristiti regresiju za klasifikaciju? # ### Binarna klasifikacija $(K=2)$ # # * Ideja: regresijska funkcija $h(\mathbf{x})$ koja za primjere iz klase $\mathcal{C}_1$ daje $h(\mathbf{x})=1$, a za primjere iz klase $\mathcal{C}_2$ daje $h(\mathbf{x})=0$ # # # * Primjer $\mathbf{x}$ klasificiriamo u klasu $\mathcal{C}_j$ za koju je $h(\mathbf{x})$ najveći # # # * Granica između $\mathcal{C}_1$ i $\mathcal{C}_2$ je na $h(\mathbf{x})=0.5$ # # # * Primjer za $n=1$ # * $h(x) = w0 + w1 x$ # * [Skica] # # # * Primjer za $n=2$ # * $h(x) = w0 + w1 x_1 + w2 * x_2$ # * [Skica] # # # * Alternativno, model možemo trenirati tako da za primjere iz klase $\mathcal{C_2}$ bude ciljana vrijednost bude $y=-1$ # * Diskriminativna funkcija onda je $h(\mathbf{x})=0$ # ### Višeklasna klasifikacija $(K>2)$ # # * Shema jedan-naspram-ostali (OVR) # # # * Treniramo po jedan model $h_j$ za svaku klasu $\mathcal{C}_j$ # # $$ # h_j(\mathbf{x}) = \mathbf{w}_j^\intercal\boldsymbol{\phi}(\mathbf{x}) # $$ # # * Primjeri za učenje $\mathcal{D}=\{\mathbf{x}^{(i)},\color{red}{\mathbf{y}^{(i)}}\}_{i=1}^N$: # # \begin{align*} # \boldsymbol\Phi = # \begin{pmatrix} # \boldsymbol{\phi}(\mathbf{x}^{(1)})^\intercal \\ # \boldsymbol{\phi}(\mathbf{x}^{(2)})^\intercal \\ # \vdots\\ # \boldsymbol{\phi}(\mathbf{x}^{(N)})^\intercal \\ # \end{pmatrix}_{N\times (m+1)} # & # \qquad # \color{red}{\mathbf{y}_j} = # \begin{pmatrix} # y_j^{(1)}\\ # y_j^{(2)}\\ # \vdots\\ # y_j^{(N)} # \end{pmatrix}_{N\times 1} # \end{align*} # # # * [Primjer] # # # * Rješenje koje minimizira kvadratnu pogrešku: # \begin{equation*} # \mathbf{w}_j = (\boldsymbol\Phi^\intercal\boldsymbol\Phi)^{-1}\boldsymbol\Phi^\intercal\mathbf{y}_j = \boldsymbol\Phi^{+}\mathbf{y}_j # \end{equation*} # # # * Model (OVR): # $$ # h(\mathbf{x}) = \mathrm{argmax}_j\ \mathbf{w}_j\boldsymbol\phi(\mathbf{x}) # $$ # # * Primjer ($K=3$) # # ![Tri ravnine](images/ravnine3.png) # # # # ### Prednosti i nedostatci klasifikacije regresijom # # * Prednosti: # * Rješenje u zatvorenoj formi # * Jednostavan postupak # # # * Nedostatci: # * Izlazi modela nemaju vjerojatnosnu intepretaciju ($h(\mathbf{x})$ nije ograničena na interval $[0,1]$) # * Nerobusnost: osjetljivost na vrijednosti koje odskaču (kažnjavanje "pretočno'' # klasificiranih primjera) # * Zbog toga, u nekim slučajevima: pogrešna klasifikacija unatoč tome što su primjeri linearno odvojivi # # # * [Primjer] # # Gradijentni spust # # Perceptron # # Sažetak # # * **Diskriminativni linearni modeli** modeliraju granicu između klasa, ali ne i način generiranja primjera # # # * **Poopćeni linearan model** je linearan model s aktivacijskom funkcijom # # # * **Klasifikacija regresijom** je jednostavan postupak, ali nije robusan # # # * **Konveksna optimizacija** važna je za strojno učenje jer je funkcija gubitka (a time i funkcija pogreške) tipično konveksna # # # * Ako minimizacija pogreške nema rješenje u zatvorenoj formi, a možemo izračunati gradijent, onda možemo primijeniti **gradijentni spust** # # # * **Perceptron** je linearan klasifikacijski model koji gradijentnim spustom mimimizira aproksimaciju broja pogrešnih klasifikacija # # # * Perceptron **ne konvergira** za linearno nedvojive probleme, dok za linearno odvojive rješenje ovisi o inicijalizaciji i redoslijedu primjera # # # * Niti regresija niti perceptron ne daju probabilistički izlaz