Sveučilište u Zagrebu
Fakultet elektrotehnike i računarstva
http://www.fer.unizg.hr/predmet/su
Ak. god. 2015./2016.
(c) 2015 Jan Šnajder
Verzija: 0.7 (2015-10-21)
In [1]:
import scipy as sp
import scipy.stats as stats
import matplotlib.pyplot as plt
from numpy.random import normal
%pylab inline
Dvije vrste induktivne pristranosti:
Pristranost jezika (pristranost ograničenjem): odabiremo model $\mathcal{H}$ koji ograničava skup prikazivih hipoteza
Pristranost preferencijom (pristranost pretraživanja): definiramo način pretraživanja unutar $\mathcal{H}$
(2) Funkcija gubitka $L(y, h(\mathbf{x}))$
Izračunava kolika je pogreška hipoteze (naučenog modela) na primjeru $\mathbf{x}^{(i)}$
Uobičajene funkcije gubitka:
Funkcija pogreške definirana je kao očekivana vrijednost funkcije gubitka na primjerima iz $\mathcal{X}\times\mathcal{Y}$ $$ E(h) = \mathbb{E}_{\mathbf{x},y}[L] $$
(3) Optimizacijski postupak
Funkcija gubitka je kvadratna: $$ L(y, h(\mathbf{x})) = (y - h(\mathbf{x}))^2 $$ pa je empirijska pogreška hipoteze $$ E(h|\mathcal{D})=\color{red}{\frac{1}{2}}\sum_{i=1}^N\big(y^{(i)}-h(\mathbf{x}^{(i)})\big)^2 $$ NB: Umjesto $1/N$, kod pogreške regresije koristimo $1/2$ zbog kasnije matematičke jednostavnosti. To međutim nema utjecaja na optimizaciju (radi se o konstanti)
Linearan model: hiperravnina u $\mathbb{R}^n$
(1) Model:
In [2]:
def h(x, w): return w[1] * x + w[0]
(2) Funkcija gubitka (i njoj odgovarajuća funkcija pogreške):
In [3]:
def quadratic_loss(y, hx):
return (y - hx)**2
def error(h, X, y):
err = 0
for xi, yi in zip(X, y):
err += quadratic_loss(yi, h(xi))
return 0.5 * err
Funkcija koja generira podatke (i koju zapravo želimo naučiti):
In [4]:
def f(x): return 3 * x + 2
xs = sp.linspace(0, 10)
plt.plot(xs, f(xs));
Skup primjera za učenje $\mathcal{D}=(\mathbf{X},\mathbf{y})$ dobiven je iz $f(x)$, uz dodatan šum:
In [5]:
X = linspace(0, 10)
y = f(X) + 2 * stats.norm.rvs(scale=3, size=50)
In [6]:
X
Out[6]:
In [7]:
len(_)
Out[7]:
In [8]:
y
Out[8]:
In [6]:
plt.plot(xs, f(xs), '--')
plt.scatter(X, y)
plt.show()
Dvije hipoteze iz našeg modela:
In [7]:
def h1(x): return h(x, [0,1])
def h2(x): return h(x, [0,2])
In [8]:
weights = [[0,1], [0,2], [1,2]]
plt.plot(xs, f(xs), '--')
plt.scatter(X, y)
plt.plot(xs, h1(xs), 'r', label='h1')
plt.plot(xs, h2(xs), 'g', label='h2')
plt.legend();
Empirijske pogreške hipoteza na skupu $\mathcal{D}$:
In [9]:
error(h1, X, y)
Out[9]:
In [10]:
error(h2, X, y)
Out[10]:
(3) Optimizacijski postupak
In [11]:
N = len(X)
x_mean = sp.mean(X)
y_mean = sp.mean(y)
w1 = (np.dot(X, y) - N * x_mean * y_mean) / (sum(X**2) - N * (x_mean**2))
w0 = sp.mean(y) - w1 * sp.mean(X)
In [12]:
print w1, w0
In [13]:
def h_best(x): return h(x, [w0,w1])
In [14]:
plt.plot(xs, f(xs), '--')
plt.scatter(X, y)
plt.plot(xs, h_best(xs), 'r');
In [15]:
error(h_best, X, y)
Out[15]:
Međutim, mogli smo odabrati i složeniji model, npr. polinom drugog stupnja: $$ h_2(x) = w_2 x^2 + w_1 x + w_0 $$ ili četvrtog stupnja: $$ h_4(x) = w_4 x^4 + w_3 x^3 + w_2 x^2 + w_1 x + w_0 $$
Ovo je i dalje linearna regresija, i dalje ima analitičko rješenje
In [16]:
from SU import PolyRegression
In [18]:
X1 = X.reshape((50,1))
h2 = PolyRegression(2).fit(X1, y)
h4 = PolyRegression(4).fit(X1, y)
In [19]:
plt.plot(xs, f(xs), '--')
plt.scatter(X, y)
plt.plot(X1, h2.predict(X1), 'r');
plt.plot(X1, h4.predict(X1), 'g');
In [20]:
error(h2, X, y)
Out[20]:
In [21]:
error(h4, X, y)
Out[21]:
In [22]:
def g(x): return x**3 - 10 * x**2 + 2 * x - 2
xs = sp.linspace(0, 10)
plt.plot(xs, g(xs));
In [23]:
X = sp.linspace(0,10)
y = g(X) + 5 * stats.norm.rvs(scale=3, size=50)
plt.plot(xs, g(xs), '--')
plt.scatter(X, y)
plt.show()
In [24]:
plt.plot(xs, g(xs), '--')
plt.scatter(X, y)
X1 = X.reshape((50,1))
for degree in range(1, 8):
h = PolyRegression(degree).fit(X1, y)
plt.plot(X1, h.predict(X1), label="d=%d" % degree);
print "error(h%d) = %.2f" % (degree, error(h, X, y))
plt.legend()
plt.show()
Međutim, modeli $h_4$ i $h_5$ imaju manju pogrešku od $h_3$
Očito, što je veći kapacitet modela $\mathcal{H}$, to je manja pogreška $E(h|\mathcal{D})$, $h\in\mathcal{H}$
Dvije krajnosti:
Podnaučenost (engl. underfitting) - $\mathcal{H}$ je prejednostavan u odnosu na stvarnu funkciju $\Rightarrow$ loša klasifikacija na viđenim i neviđenim primjerima
Prenaučenost (engl. overfitting) - $\mathcal{H}$ je previše složen u odnosu na stvarnu funkciju $\Rightarrow$ loša klasifikacija na neviđenim primjerima (loša generalizacija)
Što ako želimo optimirati parametre modela?
Ne možemo to raditi na skupu za provjeru!
Trebamo još jedan skup: skup za provjeru (engl. validation set)
Tročlana particija skupa primjera: $$ \mathcal{D} = \mathcal{D}_{\mathrm{train}} \cup \mathcal{D}_{\mathrm{val}} \cup \mathcal{D}_{\mathrm{test}} $$ $$ \mathcal{D}_{\mathrm{train}} \cap \mathcal{D}_{\mathrm{val}} = \mathcal{D}_{\mathrm{train}} \cap \mathcal{D}_{\mathrm{test}} = \mathcal{D}_{\mathrm{val}} \cap \mathcal{D}_{\mathrm{test}} = \emptyset $$
In [25]:
XY = np.column_stack((X1, y))
np.random.shuffle(XY)
In [28]:
X_train, y_train = XY[:30,0:1], XY[:30,1]
X_test, y_test = XY[30:,0:1], XY[30:,1]
In [29]:
len(X_train), len(X_test)
Out[29]:
In [30]:
plt.plot(xs, g(xs), '--')
plt.scatter(X_train, y_train, c='b')
plt.scatter(X_test, y_test, c='r');
In [31]:
plt.plot(xs, g(xs), '--')
plt.scatter(X_train, y_train, c='b')
plt.scatter(X_test, y_test, c='r');
for degree in range(1, 8):
h = PolyRegression(degree).fit(X_train, y_train)
plt.plot(X1, h.predict(X1), label="d=%d" % degree);
print "train_error(h%d) = %.2f; test_error(h%d) = %.2f" % (degree, error(h, X_train, y_train), degree, error(h, X_test, y_test))
plt.legend()
plt.show()
In [32]:
train_errors = []
test_errors = []
degrees = range(1,8)
for degree in degrees:
h = PolyRegression(degree).fit(X_train, y_train)
train_error = error(h, X_train, y_train)
test_error = error(h, X_test, y_test)
train_errors.append(train_error)
test_errors.append(test_error)
In [33]:
plt.plot(list(degrees), train_errors, label="train_error")
plt.plot(list(degrees), test_errors, label="test_error")
plt.legend()
plt.show()