You are on page 1of 72

Ajzenhamer Nikola

Mašinsko učenje
— Kroz programski jezik Python —

30. jun 2018.


Sadržaj

Predgovor iii

1 Uvod u zadatak regresije 1


1.1 Linearna regresija . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1

2 Uvod u zadatak klasi kacije 7


2.1 Logistička regresija . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.2 Linearni klasi kator zasnovan na potpornim vektorima . . . . . . . . . . 8
2.3 Tehnike pripremanje podataka za klasi kaciju . . . . . . . . . . . . . . . 10
2.4 Poređenje klasi kacionih modela . . . . . . . . . . . . . . . . . . . . . . . 12

3 Modeli zasnovani na instancama 15


3.1 Kernelizovani model potpornih vektora . . . . . . . . . . . . . . . . . . . . 15
3.2 Nadaraja-Votson regresija . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
3.3 Prostorni kerneli . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18

4 Evaluacija i izbor modela 21


4.1 Bibliotečka podrška kroz scikit-learn . . . . . . . . . . . . . . . . . . . . . 21
4.2 Implementacija funkcija za evaluaciju i izbor modela . . . . . . . . . . . 24

5 Neuronske mreže 29
5.1 Neuronske mreže sa propagacijom unapred . . . . . . . . . . . . . . . . . 30
5.2 Implementacija neuronske mreže sa propagacijom unapred . . . . . . . 35
5.3 Konvolutivne neuronske mreže . . . . . . . . . . . . . . . . . . . . . . . . . 38
5.4 Različiti načini optimizacije neuronskih mreža . . . . . . . . . . . . . . . 44
5.5 Rekurentne neuronske mreže . . . . . . . . . . . . . . . . . . . . . . . . . 47

6 Učenje potkrepljivanjem 55

Literatura 63

i
Predgovor

Ovaj tekst predstavlja skriptu iz kursa ‚‚Mašinsko učenje'', na 5. godini smerova


Informatika i Računarstvo i informatika na Matematičkom fakultetu Univerziteta
u Beogradu, zasnovanu na materijalima Anđelke Zečević, beleškama sa časova ve-
žbi i skripti ‚‚Mašinsko učenje'' profesora Mladena Nikolića i Anđelke Zečević [1].
Skripta je prateći materijal pre svega studentima koji ovaj kurs slušaju u okviru
svojih studija, ali i svima Vama koji biste želeli da se upoznate sa ovom tematikom.
Ovaj materijal ne može zameniti pohađanje vežbi niti drugu preporučenu literaturu.

Ovaj tekst je u ranoj fazi formiranja. Ukoliko ste pažljivi čitalac ove skripte,
i ukoliko uočite bilo kakvu grešku ili propust, možete se javiti autoru na adresu
mi13050@alas.matf.bg.ac.rs. Svi komentari, sugestije, kritike, ali i pohvale ve-
zane za ovaj materijal su dobrodošli.

Autor

Podešavanje okruženja za rad


Da bi se uspešno pokretali primeri iz skripte, potrebno je instalirati 64-bitnu
Python 3.6.5 (ili višu) verziju. Najbolje je pri instalaciji odabrati opciju ADD TO
PATH. Zatim je neophodno pokrenuti naredne naredbe iz komandne linije
>>>
python -m pip install --upgrade pip
pip3 install numpy scipy
pip3 install pandas matplotlib
pip3 install sklearn
pip3 install tensorflow --no-warn-script-location
pip3 install keras
pip3 install jupyter --no-warn-script-location
pip3 install pydot
pip3 install gym --no-warn-script-location

iii
Glava 1

Uvod u zadatak regresije

In [1]:
import numpy as np
import pandas as pd

from matplotlib import pyplot as plt

from sklearn import linear_model


from sklearn import model_selection
from sklearn import metrics
from sklearn import datasets
from sklearn import preprocessing

1.1 Linearna regresija


Zadatak 1.1. Posmatrajmo model f(x) = β0 + β1 x. Generisati skup podataka od
100 elemenata na sledeći način: vrednosti atributa će biti podeoci ekvidistantne
mreže na intervalu [1, 5], a vrednosti ciljne funkcije će biti generisane po formuli
y = 11 · sin(x) uz dodatak slučajnog šuma iz normalne N (0, 1) raspodele.
In [2]:
N = 100
x = np.linspace(1, 5, N)
y = 11*np.sin(x) + np.random.randn(N)

Iscrtati generisani skup podataka. Elemente skupa prikazati tačkama.


In [3]:
plt.plot(x, y, 'o')
plt.show()

Podeliti skup podataka na trening i test u razmeri 3 : 2. Postaviti vrednost para-


metra random_state na 7.
In [4]:
x_train, x_test, y_train, y_test = model_selection.train_test_split( \
x, y, train_size=0.6, test_size=0.4, random_state=7 \
)

Trenirati model linearne regresije na trening skupu.

1
GLAVA 1. UVOD U ZADATAK REGRESIJE 2

In [5]:
model = linear_model.LinearRegression(fit_intercept=True)
model.fit(x_train.reshape(-1, 1), y_train)

Iscrtati model linearne regresije kao pravu uz dijagram pod a.


In [6]:
def f(x, beta_0, beta_1):
return beta_0 + beta_1*x

beta_0 = model.intercept_
beta_1 = model.coef_[0]

plt.plot(x, y, 'o')
plt.plot(x, f(x, beta_0, beta_1), '-')
plt.show()

Korišćenjem R2 i MSE oceniti moć predviđanja na test skupu.


In [7]:
y_pred = model.predict(x_test.reshape(-1, 1))

r2_score_test = metrics.r2_score(y_test, y_pred)


mse_score_test = metrics.mean_squared_error(y_test, y_pred)

print('R2 score: {0}, MSE score: {1}'.format(r2_score_test, mse_score_test))

Zadatak 1.2. Neka je dat skup podataka kao u zadatku 1.1. Rešiti matričnu jed-
načinu XT Xβ = XT Y, u kojoj je X matrica podataka, a Y matrica (vektor-kolona)
vrednosti ciljne promenljive.
In [8]:
train_size = x_train.shape[0]
M = np.vstack([np.ones(train_size), x_train.ravel()]).transpose()
coef_pseudo = np.linalg.pinv(M).dot(y_train)
num_of_coef = len(coef_pseudo)
coef_pseudo = coef_pseudo.reshape((2,))

Iskoristiti dobijene vrednosti za iscrtavanje skupa podataka u obliku tačaka, a


zatim, na istom gra ku, iscrtati model sa dobijenim koe cijentima kao isprekidanu
pravu.
In [9]:
beta_0 = coef_pseudo[0]
beta_1 = coef_pseudo[1]

plt.plot(x, y, 'o')
plt.plot(x, f(x, beta_0, beta_1), color='orange', linestyle ='--')
plt.show()

Korišćenjem R2 i MSE oceniti moć predviđanja na test skupu.


In [10]:
test_size = x_test.shape[0]

X_test = np.vstack([np.ones(test_size), x_test.ravel()]).transpose()


y_pred = X_test.dot(coef_pseudo)

r2_score_test = metrics.r2_score(y_test, y_pred)


GLAVA 1. UVOD U ZADATAK REGRESIJE 3

mse_score_test = metrics.mean_squared_error(y_test, y_pred)

print('R2 score: {0}, MSE score: {1}'.format(r2_score_test, mse_score_test))

Zadatak 1.3. Gradientni spust je optimizacioni metod kojim se iterativno dolazi


do optimuma (minimuma ili maksimuma) funkcije. U slučaju minimizacije funkcije,
prate se pravci gradijenta duž kojih vrednosti funkcije najviše opadaju. Neka je f(x)
funkcija jedne promenljive čiji se minimum traži i neka je x0 proizvoljno odabrana
tačka. Korak iteracije je određen sa xk+1 = xk − α∇f(xk ) za k = 0, 1, . . . Parametar α
se naziva korak učenja. Implementirati gradijentni spust.
In [11]:
def gradient_descent(f, grad, x, alpha, eps, max_iterations):
result = {}

x_old = x
for i in range(1, max_iterations+1):
x_new = x_old - alpha*grad(x_old)
if np.abs(f(x_new)-f(x_old))<eps:
break
x_old = x_new

result['converge'] = i != max_iterations
result['number_of_iterations'] = i
result['x_min'] = x_new
result['f_min'] = f(x_new)

return result

Korišćenjem gradijentnog spusta odrediti minimum funkcije f(x1 , x2 ) = 12 (x21 +


10x22 ). Za korak učenja uzeti α = 0.1, za preciznost uzeti eps = 0.01, a broj iteracija
ograničiti sa 1000. Krenuti od početne tačke (3, 5).
In [12]:
def f(x):
x1 = x[0]
x2 = x[1]
return 0.5*(x1**2 + 10*x2**2)

def grad(x):
x1 = x[0]
x2 = x[1]
return np.array([x1, 10*x2])

x0 = (3, 5)
alpha = 0.1
eps = 0.01
max_iterations = 1000

result = gradient_descent(f, grad, x0, alpha, eps, max_iterations)

Zadatak 1.4. U kontekstu linearne regresije, funkcija koja se minimizuje je funk-


cija greške. Metodom gradijentnog spusta implementirati minimizaciju funkcije
∑n−1
i=0 (β0 + β1 xi − yi ) . Minimizacija se radi po parametrima
1 2
greške L β0 ,β1 (x, y) = 2n
β0 i β1 . Koristiti skup podataka iz zadatka 1.1.
GLAVA 1. UVOD U ZADATAK REGRESIJE 4

In [13]:
def error_function(beta, x, y):
beta0 = beta[0]
beta1 = beta[1]

return 0.5*np.average((beta0 + beta1*x - y)**2)

def regression_gradient_descent(x, y, error_function, beta, alpha, \


eps, max_iterations, plot=False):
result = {}

beta0_old = beta[0]
beta1_old = beta[1]

error_old = error_function(beta, x, y)

errors = np.empty(0)
errors = np.append(errors, error_old)

for i in range(1, max_iterations+1):


beta0_update = np.average(beta0_old + beta1_old*x - y)
beta1_update = np.average((beta0_old + beta1_old*x - y)*x)

beta0_new = beta0_old - alpha*beta0_update


beta1_new = beta1_old - alpha*beta1_update

error_new = error_function((beta0_new, beta1_new), x, y)

if np.abs(error_new - error_old) < eps:


break

beta0_old = beta0_new
beta1_old = beta1_new
error_old = error_new
errors = np.append(errors, error_old)

result['converge'] = i != max_iterations
result['number_of_iterations'] = i
result['b_min'] = (beta0_old, beta1_old)

if plot is True:
plt.plot(np.arange(0, i), errors)

return result

Iskoristiti implementaciju metoda za minimizaciju funkcije greške. Za korak uče-


−4
nja uzeti α = 0.1, za preciznost uzeti eps = 10 , broj iteracija ograničiti sa 1000
i za početne vrednosti parametara uzeti (3, 1). Iscrtati graf zavisnosti greške od
broja iteracija.

In [14]:
beta = (3, 1)
alpha = 0.1
eps = 1e-4
max_iterations = 1000

result = regression_gradient_descent(x, y, error_function, beta, alpha, \


GLAVA 1. UVOD U ZADATAK REGRESIJE 5

eps, max_iterations, plot=True)

Zadatak 1.5. Iz paketa sklearn.datasets učitati skup podataka o ceni kuća u Bosto-
nu. Vrednosti atributa i vrednosti ciljne promenljive smestiti u zasebne promenljive
tipa pandas.DataFrame i postaviti odgovarajuće vrednosti za imena kolona.
In [15]:
data = datasets.load_boston()

x = pd.DataFrame(data.data, columns=data.feature_names)
y = pd.DataFrame(data.target, columns=["MEDV"])

Iscrtati histograme vrednosti za svaki atribut.


In [16]:
pd.DataFrame.hist(x, figsize = [15,15])

Iscrtati toplotnu mapu matrice korelacije vrednosti između atributa. Za boju


mape uzeti shemu 'ocean'. Prikazati i legendu boja.
In [17]:
number_of_features = len(data.feature_names)
plt.figure(figsize=(6, 6))
plt.xticks(range(number_of_features), data.feature_names, \
rotation='vertical')
plt.yticks(range(number_of_features), data.feature_names)
plt.imshow(x.corr(), cmap='ocean')
plt.colorbar()
plt.show()

Podeliti skup podataka na trening i test u razmeri 2 : 1. Postaviti random_state


na 7. Izvršiti standardizaciju podataka.
In [18]:
x_train, x_test, y_train, y_test = model_selection.train_test_split( \
x, y, train_size=0.66, test_size=0.33, random_state=7
)

scaler = preprocessing.StandardScaler()
scaler.fit(x_train)
x_train = scaler.transform(x_train)
x_test = scaler.transform(x_test)

Trenirati model linearne regresije na skupu za obučavanje. Oceniti dobijeni mo-


del u smislu MSE greške. Sačuvati model koji se isporučuje korisniku u promenljivoj
final_model.
In [19]:
x_train = scaler.transform(x_train)
x_test = scaler.transform(x_test)

model = linear_model.LinearRegression()
model.fit(x_train, y_train)
y_pred = model.predict(x_test)
metrics.mean_squared_error(y_test, y_pred)

final_model = linear_model.LinearRegression()
final_model.fit(x, y)
Glava 2

Uvod u zadatak klasi kacije

In [20]:
import os

import numpy as np
import pandas as pd

from matplotlib import pyplot as plt

from sklearn import datasets


from sklearn import feature_extraction
from sklearn import model_selection
from sklearn import preprocessing
from sklearn import linear_model
from sklearn import neighbors
from sklearn import svm
from sklearn import metrics

2.1 Logistička regresija


Zadatak 2.1. Iz paketa sklearn.datasets učitati skup podataka o malignim i benig-
nim tumorima. Vrednosti atributa i vrednosti ciljne promenljive smestiti u zasebne
promenljive (na primer, tipa pandas.DataFrame) i postaviti imena kolonama atributa.
In [21]:
data = datasets.load_breast_cancer()

x = pd.DataFrame(data.data, columns=data.feature_names)
y = data.target

Prikazati koliko instanci pripada kojoj klasi.


In [22]:
print('Benign: {0}, Malignant: {1}' \
.format(np.sum(y == 1), np.sum(y == 0)))

Podeliti skup podataka na trening i test u razmeri 2 : 1. Postaviti random_state


na 7. Izvršiti strati kaciju po ciljnoj promenljivoj. Standardizovati podatke.

7
GLAVA 2. UVOD U ZADATAK KLASIFIKACIJE 8

In [23]:
x_train, x_test, y_train, y_test = model_selection.train_test_split( \
x, y, test_size = 0.33, random_state = 7, stratify = y \
)

scaler = preprocessing.StandardScaler()
scaler.fit(x_train)
x_train = scaler.transform(x_train)
x_test = scaler.transform(x_test)

Trenirati model logističke regresije sa podrazumevanim parametrima nad sku-


pom za obučavanje.
In [24]:
model = linear_model.LogisticRegression()
model.fit(x_train, y_train)

Evaluirati model na trening i test podacima. Za metriku koristiti tačnost.


In [25]:
y_test_predicted = model.predict(x_test)
test_score = metrics.accuracy_score(y_test, y_test_predicted)

y_train_predicted = model.predict(x_train)
train_score = metrics.accuracy_score(y_train, y_train_predicted)

print("Train score: {train}, test score: {test}" \


.format(train=train_score, test=test_score))

Konstruisati instancu čije se vrednosti atributa dobijaju iz normalne N (0, 1) ras-


podele. Nad nalnim modelom predvideti klasu nove instance, i ispisati verovatno-
će pripadanja obema klasama.
In [26]:
final_model = model.fit(x, y)

x_new = np.random.randn(30)
y_new = model.predict(x_new.reshape(1, -1))
print('Benign' if y_new == 1 else 'Malignant')

probabilities = model.predict_proba(x_new.reshape(1, -1))


print ('Benign: {b}, malignant: {m}' \
.format(b=probabilities[0, 1], m=probabilities[0, 0]))

Prikazati matricu konfuzije i izveštaj klasi kacije za predviđanje nad skupom za


testiranje.
In [27]:
print(metrics.confusion_matrix(y_test, y_test_predicted))
print(metrics.classification_report(y_test, y_test_predicted))

2.2 Linearni klasi kator zasnovan na potpornim vek-


torima
Zadatak 2.2. Nad skupom podataka iz zadatka 2.1, trenirati nad skupom za obu-
čavanje linearni klasi kator zasnovan na potpornim vektorima. Za funkciju greške
GLAVA 2. UVOD U ZADATAK KLASIFIKACIJE 9

uzeti funkciju šarke, a za parametar C vrednost 1.0. Evaluirati dobijen klasi kator
nad skupom za obučavanje i skupom za treniranje u smislu metrike tačnosti.

In [28]:
model = svm.LinearSVC(loss='hinge', C=1.0)
model.fit(x_train, y_train)

y_pred_train = model.predict(x_train)
print()metrics.accuracy_score(y_train, y_pred_train))

y_pred_test = model.predict(x_test)
print(metrics.accuracy_score(y_test, y_pred_test))

Formirati mrežu hiperparametara na sledeći način:

−5 −4 4
• parametar C birati iz skupa {10 , 10 , . . . , 10 }

• parametar za funkciju greške birati iz skupa {šarka}

Zatim, za svaku kon guraciju, ponoviti postupak treniranja nad skupovima za obu-
čavanje i testiranje i evaluacije, i pri tome pamtiti dobijene ocene.

In [29]:
Cs = [10**i for i in range(-5, 5)]
losses = ['hinge']

train_scores = np.empty(0)
test_scores = np.empty(0)

for loss in losses:


for C in Cs:
model = svm.LinearSVC(loss=loss, C=C)
model.fit(x_train, y_train)

y_pred_train = model.predict(x_train)
y_train_score = metrics.accuracy_score(y_train, y_pred_train)

y_pred_test = model.predict(x_test)
y_test_score = metrics.accuracy_score(y_test, y_pred_test)

train_scores = np.append(train_scores, y_train_score)


test_scores = np.append(test_scores, y_test_score)

Iscrtati dijagram zavisnosti ocena od kon guracija. Imenovati svaki nacrt i pri-
kazati legendu na najpogodnijoj poziciji.

In [30]:
num_of_configs = len(configs)

plt.xticks(range(num_of_configs), configs, rotation='vertical')


plt.plot(range(num_of_configs), train_scores, color='blue', \
label='Train scores')
plt.plot(range(num_of_configs), test_scores, color='red', \
label='Test scores')
plt.legend(loc='best')
plt.show()
GLAVA 2. UVOD U ZADATAK KLASIFIKACIJE 10

Odabrati kon guraciju za koju se dobija najbolja ocena na skupu za obučava-


nje1 . Trenirati nad skupom za obučavanje model sa odabranom kon guracijom.
Evaluirati model nad skupovima za obučavanje i testiranje.
In [31]:
best_index = np.argmax(train_scores)
best_config = configs[best_index]
best_model = svm.LinearSVC(loss=best_config['loss'], C=best_config['C'])
best_model.fit(x_train, y_train)

y_pred_train = best_model.predict(x_train)
print(metrics.accuracy_score(y_train, y_pred_train))

y_pred_test = best_model.predict(x_test)
print(metrics.accuracy_score(y_test, y_pred_test))

Zadatak 2.3. Neka je dat skup podataka iz zadatka 2.1. Koristeći mrežu hiper-
parametara iz zadatka 2.2, metodom pretrage mreže unakrsnom validacijom pro-
naći najbolju kon guraciju za linearni model zasnovan na potpornim vektorima.
Pretragu vršiti nad skupom za obučavanje. Za metriku izabrati tačnost, a osta-
le parametre pretrage ostaviti na podrazumevane. Najbolju kon guraciju sačuva-
ti u promenljivu linear_svc_best_params, a najbolji model sačuvati u promenljivu
linear_svc_best_model.
In [32]:
estimator = svm.LinearSVC()
param_grid = { \
'C': Cs, \
'loss': losses \
}

grid_linear_svc = model_selection.GridSearchCV( \
estimator=estimator, param_grid=param_grid, scoring='accuracy' \
)
grid_linear_svc.fit(x_train, y_train)

linear_svc_best_params = grid_linear_svc.best_params_
linear_svc_best_model = grid_linear_svc.best_estimator_

2.3 Tehnike pripremanje podataka za klasi kaciju


Zadatak 2.4. Posmatrajmo tekst koji se sastoji od naredne dve rečenice: It is quite
strange to have snow in summer. Spring is strange, too. Konstruisati objekat koji
sadrži ove dve rečenice, a zatim transformisati tekst u reprezentaciju vreće reči
(engl. bag of words). Trenirani rečnik sačuvati u promenljivu vocabulary i odredi-
ti tip transformisanog teksta. U promenljivoj transformed_text sačuvati vektorsku
reprezentaciju početnog teksta i prikazati je.
In [33]:
x = ['It is quite strange to have snow in summer.', \
'Spring is strange, too.']

1 Napomenimo da ovakav pristup, iako prividno tačan, ipak ne predstavlja korektan postupak odre-

đivanja optimalne vrednosti hiperparametara. U zadatku 4.2 vratićemo se na ovaj problem i prikazati
ispravan postupak.
GLAVA 2. UVOD U ZADATAK KLASIFIKACIJE 11

vectorizer = feature_extraction.text.CountVectorizer()
vectorizer.fit(x)

x_bag_of_words = vectorizer.transform(x)

# Cuvanje recnika
vocabulary = vectorizer.vocabulary_

# Odredjivanje tipa transformisanog teksta


print(type(x_bag_of_words))

# Vektorska reprezentacija teksta


# Atributi se dobijaju pozivom vectorizer.get_feature_names()
transformed_text = x_bag_of_words.toarray()
print(transformed_text)

Zadatak 2.5. Neka je dat tekst iz zadatka 2.4. Transformisati dati tekst u TF-IDF
format.
In [34]:
tf_idf_vectorizer = feature_extraction.text.TfidfVectorizer()
tf_idf_vectorizer.fit(x)
x_tf_idf = tf_idf_vectorizer.transform(x)

Zadatak 2.6. Pretpostaviti da se u tekućem direktorijumu nalazi direktorijum smsspam


u kojem se nalazi datoteka SMSSpamCollection, koja sadrži skup podataka o SMS po-
rukama, odvojenih znakom za novi red, pri čemu je svaki red u formatu
(?P<klasa>(ham)|(spam))\t(?P<poruka>.+?)
Učitati podatke u promenljive text i y: prva promenljiva sadrži tekstove SMS poru-
ka, a druga sadrži brojeve 0 ili 1, u zavisnosti da li je poruka klasi kovana kao ham
ili spam, redom. Izračunati broj poruka koje pripadaju obema klasama.
In [35]:
with open(os.path.join('smsspam', 'SMSSpamCollection')) as f:
lines = [line.strip().split('\t') for line in f.readlines()]

text = [line[1] for line in lines]


y = [int(line[0] == 'spam') for line in lines]

print('Number of spam: {0}, number of ham: {1}' \


.format(y.count(1), y.count(0)))

Podeliti skup podataka na skup za obučavanje i testiranje u razmeri 2 : 1. Posta-


viti random_state na 7. Strati kovati podatke po ciljnoj promenljivoj. Transformisati
oba skupa u reprezentaciju pomoću vreće reči.
In [36]:
x_train, x_test, y_train, y_test = model_selection.train_test_split( \
text, y, test_size=0.33, random_state=7, stratify=y \
)

bow_vectorizer = feature_extraction.text.CountVectorizer()
bow_vectorizer.fit(text)
x_train = bow_vectorizer.transform(x_train)
x_test = bow_vectorizer.transform(x_test)
GLAVA 2. UVOD U ZADATAK KLASIFIKACIJE 12

2.4 Poređenje klasi kacionih modela


Zadatak 2.7. Neka je dat skup podataka iz zadatka 2.6. Konstruisati naredna tri
modela:
1. logistička regresija: podrazumevani parametri
2. linearni model potpornih vektora: podrazumevai parametri
3. k-najbližih suseda: za parametar k uzeti broj 3 i za metriku koristiti kosinusno
rastojanje
Obučiti modele nad podacima i izvršiti evaluaciju. Uporediti koji model ima najveću
ocenu.
In [37]:
scores = np.empty(0)
models = np.empty(0)

log_regr_model = linear_model.LogisticRegression()
log_regr_model.fit(x_train, y_train)
scores = np.append(scores, log_regr_model.score(x_test, y_test))
models = np.append(models, log_regr_model)

svc_model = svm.LinearSVC()
svc_model.fit(x_train, y_train)
scores = np.append(scores, svc_model.score(x_test, y_test))
models = np.append(models, svc_model)

knn_model = neighbors.KNeighborsClassifier(n_neighbors=3, metric='cosine')


knn_model.fit(x_train, y_train)
scores = np.append(scores, knn_model.score(x_test, y_test))
models = np.append(models, knn_model)

best_index = np.argmin(scores)
print(models[best_index])

Zadatak 2.8. Napisati funkciju visualize_coefficients(title, classifier, feature_names,


n_top_features=25) koja iscrtava stubičasti dijagram koe cijenata klasi katora classifier.
Naslov dijagrama se zadaje kroz parametar title, a nazivi atributa kroz feature_names.
Prikazati samo n_top_features pozitivnih i negativnih koe cijenata. Pozitivne koe-
cijente prikazati plavom, a negativne narandžastom bojom.
In [38]:
def visualize_coefficients(title, classifier, feature_names, \
n_top_features=25):
feature_names = np.array(feature_names)

coefs = classifier.coef_.ravel()
sorted_coefs_indices = np.argsort(coefs)

positive_coefficients = sorted_coefs_indices[-n_top_features:]
negative_coefficients = sorted_coefs_indices[:n_top_features]

interesting_coefficients = np.hstack( \
[negative_coefficients, positive_coefficients] \
)

plt.figure(figsize=(15, 5))
GLAVA 2. UVOD U ZADATAK KLASIFIKACIJE 13

plt.title(title)
colors = ['orange' if c < 0 else 'cadetblue' \
for c in coefs[interesting_coefficients]]
plt.bar(np.arange(2 * n_top_features), \
coefs[interesting_coefficients], color=colors)
plt.xticks(np.arange(0, 2 * n_top_features), \
feature_names[interesting_coefficients], rotation=60, ha="right")
Glava 3

Modeli zasnovani na
instancama

In [39]:
import numpy as np
import pandas as pd

from matplotlib import pyplot as plt


from mpl_toolkits.basemap import Basemap

from sklearn import datasets


from sklearn.datasets.species_distributions import construct_grids
from sklearn import preprocessing
from sklearn import model_selection

from sklearn import linear_model

from sklearn import svm


from sklearn import neighbors

from sklearn import metrics

Na ovom mestu je važno dati narednu napomenu. Da bi se uspešno pokrenuo


primer 3.5, potrebno je instalirati dodatne pakete. Za Unix-zasnovane operativne
sisteme, dovoljno je pokrenuti narednu naredbu u konzoli
>>>
pip3 install basemap

Za Windows operativni sistem, ovaj proces je značajno komplikovaniji — potreb-


no je da kompiliramo izvorne datoteke. Za više informacija, pogledati članak na
adresi https://blog.straywarrior.com/179.html.

3.1 Kernelizovani model potpornih vektora


Zadatak 3.1. Za skup podataka iz zadatka 2.1 konstruisati model potpornih vek-
tora zasnovan na instancama sa parametrima C=1.0, gamma=0.4 i kernel='rbf'.
In [40]:
kernel_model = svm.SVC(C=1, gamma=0.4, kernel='rbf')
kernel_model.fit(x_train, y_train)

15
GLAVA 3. MODELI ZASNOVANI NA INSTANCAMA 16

y_pred = kernel_model.predict(x_test)
metrics.accuracy_score(y_test, y_pred)

Zadatak 3.2. Generisati skup podataka od 1000 elemenata, uniformno raspoređe-


nih na skupu [−1, 1]2 . De nisati i funkciju ograničenja f(x1 , x2 ) = 2(x21 + x22 ≤ 12 ) − 1.
Svi elementi koji zadovoljavaju ograničenje pripadaju klasi 'orange', a ostali ele-
menti pripadaju klasi 'blue'. Prikazati skup podataka raspršenim dijagramom.
In [41]:
x1 = np.random.uniform(-1, 1, 1000)
x2 = np.random.uniform(-1, 1, 1000)
x = np.vstack([x1, x2]).transpose()

def f(x1_i, x2_i):


return 2*(x1_i**2 + x2_i**2 <= 0.5) - 1

y = f(x1, x2)

for (x1_i, x2_i) in zip(x1, x2):


plt.scatter(x1_i, x2_i, c = [ \
'blue' if f(x1_i, x2_i) == -1 else 'orange'])

Zadatak 3.3. Za skup podataka iz zadatka 3.2 formirati:

1. linearni model zasnovan na potpornim vektorima sa parametrima C=1.0 i loss='hinge'

2. model potpornih vektora zasnovan na instancama sa parametrima C=1.0 i gamma=1.0

Evaluirati oba modela i oceniti koji model ima bolju moć predviđanja na datom
skupu podataka. Uz vizualizaciju iz zadatka 3.2 prikazati (na primer, crvenom bo-
jom) instance koji čine potporne vektore.
In [42]:
linear_svm = svm.LinearSVC(loss='hinge', C=1.0)
linear_svm.fit(x_train, y_train)
y_pred = linear_svm.predict(x_test)
linear_acc = metrics.accuracy_score(y_test, y_pred)
print("Linear SVM: {0}".format(linear_acc))

kernelized_svm = svm.SVC(gamma=1, C=1.0)


kernelized_svm.fit(x_train, y_train)
y_pred = kernelized_svm.predict(x_test)
kernelized_acc = metrics.accuracy_score(y_test, y_pred)
print("Kernelized SVM: {0}".format(kernelized_acc))

for (x1_i, x2_i) in zip(x1, x2):


plt.scatter(x1_i, x2_i, c = [ \
'blue' if f(x1_i, x2_i)==-1 else 'orange'])

# Vizualizacija potpornih vektora


plt.scatter( \
kernelized_svm.support_vectors_[:, 0], \
kernelized_svm.support_vectors_[:, 1], \
c = ['red'])
GLAVA 3. MODELI ZASNOVANI NA INSTANCAMA 17

3.2 Nadaraja-Votson regresija


(x1 −x2 )2

Zadatak 3.4. De nisati Gausov kernel K(x1 , x2 , σ) = √ 1 2 e 2σ 2 . Neka je dat
2πσ
skup podataka od 100 elemenata, uniformno raspoređenih na skupu [−1, 1]. Vred-
nosti ciljne promenljive se računaju funkcijom y = (x + 1)2 uz dodatak šuma koji
potiče iz normalne raspodele N (0, 1).
In [43]:
def kernel(x1, x2, bandwidth):
return \
np.exp(-0.5*((x1-x2)**2)/(bandwidth**2))/np.sqrt(2*np.pi*bandwidth**2)

x = np.random.uniform(-1, 1, 100)
y = (x+1)**2 + np.random.randn(x.size)

De nisati funkciju koja predstavlja model predviđanja zasnovan na Nadaraja-


Votson regresiji. Novoj vrednosti se pridružuje vrednost koja je slična vrednostima
,,okolnih''
∑n instanci. Vrednost ciljne promenljive za novu instancu je težinski prosek
y = Σ1 i=1 ωi yi , gde vrednosti koe cijenata ωi zavise od vrednosti Gausovog kernela
između nove instance i ostalih instanci, a Σ je suma vrednosti koe cijenata ωi .
In [44]:
def estimator(x_new, x, y, bandwidth):
kernel_value = kernel(x, x_new, bandwidth)
return np.sum(kernel_value*y)/np.sum(kernel_value)

Podeliti skup podataka za skupove za obučavanje i testiranje u razmeri 2 : 1. Za


svaku od širina Gausovog kernela iz skupa {0.01, 0.1, 0.5, 1, 5, 10, 100} izvršiti leave-
one-out evaluaciju korišćenjem srednje kvadratne greške i pronaći širinu kernela
koja minimizuje ovu grešku. Za datu širinu evaluirati model Nadaraja-Votson re-
gresije na skupu za testiranje i prikazati korišćenjem raspršenog dijagrama:
• skup za testiranje, plavom bojom
• predviđene vrednosti, narandžastom bojom
• skup za testiranje, pri čemu se vrednosti ciljne promenljive dobijaju funkcijom
y = (x + 1)2 , crvenom bojom

In [45]:
bandwidths = np.array([0.01, 0.1, 0.5, 1, 5, 10, 100])
errors = []

for bandwidth in bandwidths:


leave_one_out_errors = np.zeros(x_train_val.size)

for i in range(0, x_train_val.size):


x_fit = np.delete(x_train_val, i)
y_fit = np.delete(y_train_val, i)

y_pred = estimator(x_train_val[i], x_fit, y_fit, bandwidth)

error = y_train_val[i] - y_pred


leave_one_out_errors[i] = error

# Racunanje srednje kvadratne greske za tekucu sirinu Gausovog kernela


error = np.mean(leave_one_out_errors**2)
GLAVA 3. MODELI ZASNOVANI NA INSTANCAMA 18

errors.append(error)

errors = np.array(errors)
best_bandwidth = bandwidths[np.argmin(errors)]

y_predictions = []
test_errors = []

for (x_new, y_new) in zip(x_test, y_test):


y_pred = estimator(x_new, x_train_val, y_train_val, best_bandwidth)
y_predictions.append(y_pred)

error = y_pred - y_new


test_errors.append(error)

test_errors = np.array(test_errors)
test_error = np.mean(test_errors**2)

plt.scatter(x_test, y_test, color='blue')


plt.scatter(x_test, y_predictions, color='orange')
plt.scatter(x_test, (x_test + 1)**2, color='red')

3.3 Prostorni kerneli


Zadatak 3.5. Učitati podatke o geografskoj raspodeli dveju vrsta korišćenjem funk-
cije sklearn.datasets.fetch_species_distributions. Posebno izdvojiti iz skupa za
obučavanje informacije o geografskoj dužini i širini (poziciju vrste), a zatim i o vrsta-
ma. Informacije o pozicijama vrste smestiti u matricu, a vrste dekodirati u cele bro-
jeve 0 i 1, u zavisnosti od toga da li je reč o 'Bradypus Variegatus' ili 'Microryzomys
Minutus', redom. Konstruisati i mrežu na mapi od podataka.
In [46]:
data = datasets.fetch_species_distributions()

latlong = np.vstack( \
[data.train['dd lat'], \
data.train['dd long']]).transpose()

species = np.array([ \
d.decode('ascii').startswith('micro') \
for d in data.train['species']], dtype=np.int16)

xgrid, ygrid = construct_grids(data)

Zadatak 3.6. Konstruisati mapu sa cilindričnom projekcijom nad skupom podataka


iz zadatka 3.5. Prikazati na mapi i: (1) granice mape, (2) boje kontinenata, (3) obode
i (4) granice zemalja.
In [47]:
m = Basemap(projection='cyl', resolution='c', \
llcrnrlat=ygrid.min(), urcrnrlat=ygrid.max(), \
llcrnrlon=xgrid.min(), urcrnrlon=xgrid.max())

m.drawmapboundary(fill_color='#DDEEFF')
GLAVA 3. MODELI ZASNOVANI NA INSTANCAMA 19

m.fillcontinents(color='#FFEEDD')
m.drawcoastlines(color='gray', zorder=2)
m.drawcountries(color='gray', zorder=2)

m.scatter(latlong[:, 1], latlong[:, 0], zorder=2, c=species, latlon=True)

Zadatak 3.7. TODO: Dodati tekst zadatka.


In [48]:
X, Y = np.meshgrid(xgrid[::5], ygrid[::5][::-1])
land_reference = data.coverages[6][::5, ::5]
land_mask = (land_reference > -9999).ravel()
xy = np.vstack([Y.ravel(), X.ravel()]).T
xy = np.radians(xy[land_mask])

fig, ax = plt.subplots(1, 2)
fig.subplots_adjust(left=0.05, right=0.95, wspace=0.05)
species_names = ['Bradypus Variegatus', 'Microryzomys Minutus']
cmaps = ['Oranges', 'Purples']

for i, axi in enumerate(ax):


axi.set_title(species_names[i])

m = Basemap(projection='cyl', llcrnrlat=Y.min(), \
urcrnrlat=Y.max(), llcrnrlon=X.min(), \
urcrnrlon=X.max(), resolution='c', ax=axi)
m.drawmapboundary(fill_color='#DDEEFF')
m.drawcoastlines()
m.drawcountries()

# Sfericni ocenjivac gustine


kde = neighbors.KernelDensity(kernel='gaussian', \
bandwidth=0.03, metric='haversine')
kde.fit(np.radians(latlong[species == i]))

Z = np.full(land_mask.shape[0], -9999.0)
Z[land_mask] = np.exp(kde.score_samples(xy))
Z = Z.reshape(X.shape)

levels = np.linspace(0, Z.max())


axi.contourf(X, Y, Z, levels=levels, cmap=cmaps[i])
Glava 4

Evaluacija i izbor modela

In [49]:
import numpy as np
import pandas as pd
from matplotlib import pyplot as plt

from sklearn import datasets


from sklearn import preprocessing
from sklearn import model_selection
from sklearn import linear_model
from sklearn import svm
from sklearn import metrics

4.1 Bibliotečka podrška kroz scikit-learn


Zadatak 4.1. Neka je dat skup podataka iz zadatka 2.1. Podeliti skup podataka
na skupove za obučavanje, validaciju i testiranje i izvršiti standardizaciju. Odnosi
podele su dati proporcijom train : val : test = 53 : 13 : 33. Postaviti random_state na
vrednost 7.
In [50]:
x_train_val, x_test, y_train_val, y_test = model_selection.train_test_split( \
x, y, train_size=0.67, test_size=0.33, random_state=7, stratify=y \
)

x_train, x_val, y_train, y_val = model_selection.train_test_split( \


x_train_val, y_train_val, train_size=0.8, test_size=0.2, \
random_state=7, stratify=y_train_val \
)

scaler_tr_val = preprocessing.StandardScaler()
scaler_tr_val.fit(x_train_val)
x_train_val = scaler_tr_val.transform(x_train_val)
x_test = scaler_tr_val.transform(x_test)

scaler_train = preprocessing.StandardScaler()
scaler_train.fit(x_train)
x_train = scaler_train.transform(x_train)
x_val = scaler_train.transform(x_val)

21
GLAVA 4. EVALUACIJA I IZBOR MODELA 22

Zadatak 4.2. Neka je data podela skupa podataka kao u zadatku 4.1. Potrebno
je odrediti optimalnu kon guraciju za kernelizovani model zasnovan na potpornim
vektorima. Za tehniku evaluacije izabrati evaluaciju pomoću skupova za validaciju
i testiranje. Prilikom izbora modela i evaluacije za metriku koristiti meru tačnosti.
Mreža hiperparametara je data sa:
−5 −4 4
• parametar C birati iz skupa {10 , 10 , . . . , 10 }
−3 −2 2
• parametar gamma birati iz skupa {10 , 10 , . . . , 10 }

In [51]:
Cs = [10**i for i in range(-5, 5)]
gammas = [10**i for i in range(-3, 3)]

best_score = 0
best_params = { 'C': None, 'gamma': None }

# Izbor modela
for C in Cs:
for gamma in gammas:
model = svm.SVC(C=C, gamma=gamma)
model.fit(x_train, y_train)

y_pred = model.predict(x_val)
score = metrics.accuracy_score(y_val, y_pred)

if score > best_score:


best_score = score
best_params['C'] = C
best_params['gamma'] = gamma

best_model = svm.SVC(C=best_params['C'], gamma=best_params['gamma'])

# Evaluacija izabranog modela


best_model.fit(x_train_val, y_train_val)
y_pred = best_model.predict(x_test)
print(metrics.accuracy_score(y_test, y_pred))

Zadatak 4.3. Neka je dat kernelizovani model zasnovan na potpornim vektorima


čiji su parametri dati iz izabranog modela iz zadatka 4.2. Evaluirati dati model po-
moću unakrsne validacije na 10 slojeva. Za metriku birati meru tačnosti. Prikazati
dobijenu ocenu za svaki sloj.
In [52]:
scaler_x = preprocessing.StandardScaler()
scaler_x.fit(x)
x = scaler_x.transform(x)

accuracy_scores = model_selection.cross_val_score( \
best_model, x, y, scoring='accuracy', cv=10)
print(accuracy_scores)

Zadatak 4.4. Izvršiti izbor modela i evaluaciju kao u zadatku 4.2. Za tehniku eva-
luacije izabrati unakrsnu validaciju na 10 slojeva.
GLAVA 4. EVALUACIJA I IZBOR MODELA 23

In [53]:
Cs = [10**i for i in range(-5, 5)]
gammas = [10**i for i in range(-3, 3)]

best_score = 0
best_params = { 'C': None, 'gamma': None }

for C in Cs:
for gamma in gammas:
model = svm.SVC(C=C, gamma=gamma)
accuracy_scores = model_selection.cross_val_score( \
model, x_train_val, y_train_val, scoring='accuracy', cv=10)
score = np.mean(accuracy_scores)

if score > best_score:


best_params['C'] = C
best_params['gamma'] = gamma
best_score = score

best_model = svm.SVC(C=best_params['C'], gamma=best_params['gamma'])


best_model.fit(x_train_val, y_train_val)

y_pred = best_model.predict(x_test)
print(metrics.accuracy_score(y_test, y_pred))

Zadatak 4.5. Uraditi zadatak 4.4 korišćenjem bibliotečke funkcije GridSearchCV iz


paketa sklearn.model_selection. Dodatno, sačuvati i ocene dobijene na skupu za
obučavanje.
In [54]:
estimator = svm.SVC()
param_grid = {
'C': [10**i for i in range(-5, 5)],
'gamma': [10**i for i in range(-3, 3)]
}

grid_svc = model_selection.GridSearchCV( \
estimator, param_grid, scoring='accuracy', cv=10, \
return_train_score=True)
grid_svc.fit(x_train_val, y_train_val)

y_pred = grid_svc.predict(x_test)
print(metrics.accuracy_score(y_test, y_pred))

Pročitati iz izveštaja informaciju o prosečnoj tačnosti za svaku kon guraciju i


prikazati je u vidu toplotne mape.
In [55]:
cv_results = pd.DataFrame(grid_svc.cv_results_)

number_of_Cs = len(Cs)
number_of_gammas = len(gammas)

mean_test_scores = cv_results['mean_test_score'] \
.values.reshape((number_of_gammas, number_of_Cs))

plt.figure(figsize=(10, 6))
plt.xticks(range(number_of_Cs), Cs)
GLAVA 4. EVALUACIJA I IZBOR MODELA 24

plt.yticks(range(number_of_gammas), gammas)
plt.xlabel('C')
plt.ylabel('gamma')
plt.imshow(mean_test_scores)
plt.colorbar()
plt.show()

Zadatak 4.6. Izvršiti izbor modela i evaluaciju kao u zadatku 4.2. Za tehniku eva-
luacije izabrati ugnežđenu unakrsnu validaciju na 5 unutrašnjih i 10 spoljašnjih
slojeva.
In [56]:
estimator = svm.SVC()

scores = model_selection.cross_val_score( \
model_selection.GridSearchCV( \
estimator, param_grid, scoring='accuracy', cv=5 \
), x, y, scoring='accuracy', cv=10 \
)

print(scores)

4.2 Implementacija funkcija za evaluaciju i izbor


modela
Zadatak 4.7. Napisati funkciju koja deli zadate skupove x i y na trening i test sku-
pove u zadatoj razmeri. Funkcija vraća skupove x_train, x_test, y_train i y_test.
Funkcija treba da oponaša funkcionalnosti sklearn.model_selection.train_test_split
metode.
In [57]:
def data_split(x, y, ratio):
N = int(y.size * ratio)

x_train = x[:N, :]
y_train = y[:N]

x_test = x[N:, :]
y_test = y[N:]

return x_train, x_test, y_train, y_test

Zadatak 4.8. Napisati funkciju koja trenira zadati model na trening skupu, a potom
evaluira i vraća vrednost funkcije greške na test skupu. Funkcija treba da objedini
funkcionalnosti fit, predict i score metoda.
In [58]:
def train_test_eval(model, x_train, y_train, x_test, y_test, \
error_function):
model.fit(x_train, y_train)
y_predicted = model.predict(x_test)

return error_function(y_test, y_predicted)


GLAVA 4. EVALUACIJA I IZBOR MODELA 25

Zadatak 4.9. Napisati funkciju koja podelom skupova x i y u zadatoj razmeri na


trening i validacioni skup određuje iz skupa zadatih kon guracija onu vrednost
kon guracionog parametra za koju model daje najmanju grešku. Funkcija vraća
najbolji model.
In [59]:
def train_valid_select(x, y, ratio, error_function, configure_model, \
configs):
x_train, x_validation, y_train, y_validation = data_split(x, y, ratio)

errors = []

for c in configs:
model = configure_model(c)
error = train_test_eval(model, x_train, y_train, x_validation, \
y_validation, error_function)
errors.append(error)

errors = np.array(errors)
c_best = configs[np.argmin(errors)]

model = configure_model(c_best)
model.fit(x, y)
return model

Zadatak 4.10. Napisati funkciju koja deli skupove na trening, test i validacione
skupove u zadatim razmerama, zatim određuje najbolji model korišćenjem funkcije
iz zadatke 4.9 i vraća ocenu njegove greške koriscenjem funkcije iz zadatka 4.8.
In [60]:
def train_valid_test_eval(x, y, ratios, error_function, configure_model, \
configs):
x_train_validation, x_test, y_train_validation, y_test = \
data_split(x, y, ratios[0] + ratios[1])
r = ratios[0]/(ratios[0] + ratios[1])

model = train_valid_select(x_train_validation, y_train_validation, \


r, error_function, configure_model, configs)

y_predicted = model.predict(x_test)

return error_function(y_test, y_predicted)

Zadatak 4.11. Napisati funkciju omotač kojom se može kon gurisati model logi-
stičke regresije. Zatim napisati funkciju koja se može koristiti za ocenu greške
−5 −4 4
klasi kacije. Neka je dat skup {10 , 10 , . . . , 10 } kon guracija za parametar C
logističke regresije.
In [61]:
def configure_logistic_model(c):
return linear_model.LogisticRegression(C=c)

def classification_error(y_true, y_predicted):


return 1 - metrics.accuracy_score(y_true, y_predicted)

configurations=[10**i for i in range(-5,5)]


GLAVA 4. EVALUACIJA I IZBOR MODELA 26

Učitati skup podataka iz zadatka 2.1 i odrediti najbolji model logističke regresije
na skupovima za treniranje i validaciju korišćenjem funkcije iz zadatka 4.9. Podelu
skupa izvršiti u razmeri 4 : 1.
In [62]:
model = train_valid_select(x, y, 0.8, \
classification_error, configure_logistic_model, configurations)

Nad istim skupom podataka izvršiti evaluaciju najboljeg modela korisćenjem


funkcije iz zadatka 4.10. Podelu skupa izvršiti u razmeri 3 : 1 : 1.
In [63]:
train_valid_test_eval( x, y, [0.6, 0.2, 0.2], \
classification_error, configure_logistic_model, configurations)

Zadatak 4.12. Napisati funkciju koja korišćenjem unakrsne validacije evaluira za-
dati model. Funkcija treba da vrati vrednost greške modela.
In [64]:
def cross_validation_evaluation(model, x, y, number_of_folds, \
error_function):
y_predicted = np.empty(y.size)

inds = np.arange(0, x.shape[0]) % number_of_folds

for i in range(0, number_of_folds):


x_train = x[inds != i, :]
x_test = x[inds == i, :]

y_train = y[inds != i]
y_test = y[inds == i]

model.fit(x_train, y_train)

y_predicted[inds == i] = model.predict(x_test)

return error_function(y, y_predicted)

Zadatak 4.13. Napisati funkciju koja korišćenjem unakrsne validacije bira najbolju
kon guraciju za zadati model. Funkcija vraća najbolji model.
In [65]:
def cross_validation_selection(x, y, number_of_folds, error_function, configure_model, configs):
errors = []

for c in configs:
model = configure_model(c)
error = cross_validation_evaluation( \
model, x, y, number_of_folds, error_function)
errors.append(error)

errors = np.array(errors)
c_best = configs[np.argmin(errors)]

model = configure_model(c_best)
model.fit(x, y)

return model
GLAVA 4. EVALUACIJA I IZBOR MODELA 27

Zadatak 4.14. Napisati funkciju koja korišćenjem ugnežđene unakrsne validacije


daje ocenu greške modela.
In [66]:
def nested_cross_validation_evaluation(x, y, number_of_folds, \
error_function, configure_model, configs):
y_predicted = np.empty(y.size)

inds = np.arange(0, x.shape[0]) % number_of_folds

for i in range(0, number_of_folds):


x_train_validation = x[ inds != i]
y_train_validation = y[ inds != i]

x_test = x [ inds == i]
y_test = y [ inds == i]

model = cross_validation_selection( \
x_train_validation, y_train_validation, number_of_folds, \
error_function, configure_model, configs)

y_predicted[ inds == i] = model.predict(x_test)

return error_function(y, y_predicted)

Zadatak 4.15. Korišćenjem funkcije iz zadatka 4.14, oceniti model logističke re-
gresije korišćenjem ugnežđene unakrsne validacije sa 5 slojeva. Mrežu parametra
podesiti kao u zadatku 4.11.
In [67]:
nested_cross_validation_evaluation( \
x, y, 5, classification_error, configure_logistic_model, \
configurations)
Glava 5

Neuronske mreže

In [68]:
import numpy as np
import scipy.io

import pandas as pd
import h5py

from matplotlib import pyplot as plt


import pydot
from IPython.display import SVG

from sklearn import datasets


from sklearn import model_selection
from sklearn import preprocessing
from sklearn import metrics

from keras.datasets import boston_housing


from keras.datasets import cifar10
from keras.datasets import imdb
from keras.datasets import mnist

from keras.utils import to_categorical


from keras.utils.vis_utils import model_to_dot

from keras.preprocessing import sequence

from keras.models import load_model


from keras.models import Sequential, Model

from keras.layers import Dense, Input


from keras.layers import Embedding
from keras.layers import ZeroPadding2D, Conv2D, MaxPool2D, Convolution2D, \
MaxPooling2D
from keras.layers import SimpleRNN, LSTM, GRU
from keras.layers import BatchNormalization, Activation, Flatten
from keras.layers import Dropout

from keras.optimizers import Adam, SGD, RMSprop

from keras.callbacks import EarlyStopping

29
GLAVA 5. NEURONSKE MREŽE 30

from keras.losses import binary_crossentropy, categorical_crossentropy


from keras.losses import mse

from keras import backend as K

5.1 Neuronske mreže sa propagacijom unapred


Zadatak 5.1. Iz paketa keras.datasets učitati podatke o nekretninama u Bostonu.
Pri učitavanju, podeliti skup podataka na skupove za obučavanje i treniranje u raz-
meri 2 : 1. Izvršiti standardizaciju podataka.
In [69]:
(x_train, y_train), (x_test, y_test) = \
boston_housing.load_data(test_split = 0.33)

scaler = preprocessing.StandardScaler()
scaler.fit(x_train)
x_train = scaler.transform(x_train)
x_test = scaler.transform(x_test)

Konstruisati gustu neuronsku mrežu sa propagacijom unapred. Mreža treba da


ima jedan ulazni sloj, jedan skriveni sloj sa 100 neurona i izlazni sloj. Broj neurona
ulaznog sloja odgovara broju atributa skupa podataka, dok broj neurona izlaznog
sloja je 1. Aktivaciona funkcija na prvom sloju je ispravljačka jedinica, optimizator
koji se koristi je ADAM i funkcija greške je srednjekvadratna greška. Prikazati i
pregled mreže.
In [70]:
number_of_features = x_train.shape[1]
output_size = 1

model = Sequential()
model.add(Dense(units=100, input_dim=number_of_features, activation='relu'))
model.add(Dense(units=output_size))
model.compile(optimizer='adam', loss='mse')

model.summary()

Obučiti konstruisanu mrežu na 100 epoha i batch_size 32. Sprečiti prikazivanje


treniranja pri svakoj eposi. Sačuvati i istoriju obučavanja. Iscrtati gra k zavisnosti
funkcije greške od broja epoha.
In [71]:
history = model.fit(x_train, y_train, epochs=100, batch_size=32, verbose=0)

epochs = history.epoch
losses = history.history['loss']

plt.xlabel('epoch')
plt.ylabel('loss)
plt.plot(epochs, losses)

Evaluirati model i generisati novu instancu iz uniformne U[0, 1] raspodele (za


svaki atribut) i izvršiti predviđanje vrednosti.
GLAVA 5. NEURONSKE MREŽE 31

In [72]:
print(model.evaluate(x_test, y_test))

x_new = np.random.uniform(0, 1, number_of_features). \


reshape(1, number_of_features)
print(model.predict(x_new, batch_size=1).ravel())

Za svaki sloj ispisati dimenzije matrica koe cijenata (težina koji karakterišu mre-
žu). Sačuvati težine u datoteku boston_housing_weights.hdf5. Prikazati i čuvanje
modela u datoteku boston_housing.hdf5, a zatim učitati sačuvani model.
In [73]:
weights = model.weights

for i in range(len(weights)):
print(weights[i].shape)

model.save_weights('boston_housing_weights.hdf5')
model.save('boston_housing.hdf5')
model = load_model('boston_housing.hdf5')

Zadatak 5.2. Učitati skup podataka iz zadatka 2.1 i izvršiti podelu na skupove za
2
obučavanje i testiranje u razmeri 2 : 1 i izvršiti standardizaciju .
In [74]:
np.random.seed(7)

data = datasets.load_breast_cancer()
x = data.data
y = data.target

x_train, x_test, y_train, y_test = model_selection.train_test_split( \


x, y, test_size=0.33, random_state=7, stratify=y \
)

scaler = preprocessing.StandardScaler()
scaler.fit(x_train)
x_train = scaler.transform(x_train)
x_test = scaler.transform(x_test)

Konstruisati gustu mrežu sa propagacijom unapred. Mreža treba da ima ulazni


sloj, dva skrivena sloja sa 100 i 40 neurona, redom, i izlazni sloj. Broj neurona ula-
znog sloja odgovara broju atributa skupa podataka. Broj neurona izlaznog sloja je
1. Aktivaciona funkcija za ulazni sloj i drugi sloj je ispravljačka jedinica, dok po-
slednji sloj ima sigmoidnu funkciju kao aktivacionu funkciju. Koristiti optimizator
ADAM, binarnu unakrsnu entropiju za funkciju greške i tačnost za metriku. Prika-
zati i pregled mreže.
In [75]:
number_of_features = x.shape[1]
number_of_outputs = 1

model = Sequential()
model.add(Dense(units=100, input_dim=number_of_features, activation='relu'))
model.add(Dense(units=40, activation='relu'))
model.add(Dense(units=number_of_outputs, activation='sigmoid'))

2
Probati zadatak uz vršenje strati kacije podataka pri podeli i bez nje.
GLAVA 5. NEURONSKE MREŽE 32

model.compile(optimizer='adam', loss=binary_crossentropy, \
metrics=['accuracy'])

model.summary()

Obučiti model na 30 epoha i veličinom batch skupa od 16. Iskoristiti 30% skupa
za obučavanje za validaciju. Prikazati gra k funkcije greške na skupu za obučavanje
i validacionom skupu u zavisnosti od broja epohe. Da li se model pretprilagođava
podacima? Ukoliko se model pretprilagođava, do koje epohe treba vršiti proces
obučavanja da li se sprečilo pretprilagođavanje?
In [76]:
history = model.fit(x_train, y_train, epochs=30, batch_size=16, \
validation_split=0.3, verbose=0)

epochs = history.epoch
train_loss = history.history['loss']
val_loss = history.history['val_loss']

plt.xlabel('Epochs')
plt.ylabel('Loss function')
plt.plot(epochs, train_loss, color='red', label='Train loss')
plt.plot(epochs, val_loss, color='orange', label='Val loss')
plt.legend(loc='best')

Prikazati i gra k tačnosti na skupovima za obučavanje i validaciji u zavisnosti od


broja epohe. Da li možemo doći do istih zaključka kao u prethodnoj analizi?
In [77]:
train_acc = history.history['acc']
val_acc = history.history['val_acc']

plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.plot(epochs, train_acc, color='green', label='Train accuracy')
plt.plot(epochs, val_acc, color='blue', label='Val accuracy')
plt.legend(loc='best')

Evaluirati konstruisanu mrežu, a zatim prepraviti proces obučavanja u skladu sa


prethodnim analizama. Da li se poboljšava tačnost u ovom slučaju?
In [78]:
test_scores = model.evaluate(x_test, y_test)
test_scores = pd.Series(test_scores, index=model.metrics_names)
print(test_scores)

model.fit(x_train, y_train, epochs=8, batch_size=16)

Zadatak 5.3. Skup podataka ,,Pima Indians Diabetes'' se sastoji iz 768 instanci,
od kojih svaka predstavlja vrednosti dobijene od pacijenata. Svi atributi su nu-
merički i opseg vrednosti varira od atributa do atributa. Svakoj instanci je pri-
družena klasa u zavisnosti od toga da li je pacijentu dijagnosti kovan dijabetes u
poslednjih 5 godina (vrednost 1) ili ne (vrednost 0). Ucitati podatke iz datoteke
prima-indians-diabetes.csv, izvršiti podelu podataka u razmeri 4 : 1 i izvršiti neop-
hodna pretprocesiranja.
GLAVA 5. NEURONSKE MREŽE 33

In [79]:
data = pd.read_csv('pima-indians-diabetes.csv')
attribute_names = data.columns.drop(['Target'])
x = data[attribute_names]
y = data['Target']

x_train, x_test, y_train, y_test = model_selection.train_test_split( \


x, y, test_size=0.2, random_state=7, stratify=y \
)

scaler = preprocessing.StandardScaler()
scaler.fit(x_train)
x_train = scaler.transform(x_train)
x_test = scaler.transform(x_test)

Konstruisati troslojnu neuronsku mrežu sa propagacijom unapred čija je arhi-


tektura mreže data sa:
• Sloj 1: 15 neurona, aktivaciona funkcija je ispravljačka jedinica
• Sloj 2: 8 neurona, aktivaciona funcija je ispravljačka jedinica
• Sloj 3: 1 neuron, aktivaciona funkcija je sigmoidna funkcija
Za funkciju greške uzeti binarnu unakrsnu entropiju, broj iteracija obučavanja je
200, veličina batch skupa je 5 i optimizator je ADAM. Za metriku uzeti tačnost.
Odvojiti 30% skupa za validacioni skup.
In [80]:
number_of_features = len(attribute_names)
output_size = 1

model = Sequential()
model.add(Dense(units=15, input_dim=number_of_features, activation='relu'))
model.add(Dense(units=8, activation='relu'))
model.add(Dense(units=output_size, activation='sigmoid'))
model.compile(optimizer='adam', loss=binary_crossentropy, \
metrics=['accuracy'])

history = model.fit(x_train, y_train, epochs=200, batch_size=5, \


validation_split=0.3, verbose=0)

Prikazati gra ke funkcije greške i tačnosti na skupovima za obučavanje i valida-


ciju u zavisnosti od broja epoha. Šta možemo zaključiti iz ovih gra ka?
In [81]:
epochs = history.epoch

loss = history.history['loss']
validation_loss = history.history['val_loss']
acc = history.history['acc']
validation_acc = history.history['val_acc']

plt.figure(figsize=(10, 8))
plt.plot(epochs, loss, c='red')
plt.plot(epochs, validation_loss, c='orange')
plt.show()

plt.figure(figsize=(10, 8))
plt.plot(epochs, acc, c='red')
GLAVA 5. NEURONSKE MREŽE 34

plt.plot(epochs, validation_acc, c='orange')


plt.show()

Zadatak 5.4. Učitati skup podataka iz paketa keras.datasets.mnist i upoznati se


sa podacima. Pripremiti podatke tako da mogu predstavljati ulaz u gustu neuron-
sku mrežu sa propagacijom unapred i izvršiti standardizaciju. Transformisati klase
(vrednosti ciljne promenljive) u one-hot reprezentaciju.
In [82]:
(x_train, y_train), (x_test, y_test) = data = mnist.load_data()
plt.imshow(x_train[0], cmap='gray')
print('U pitanju je broj {0}'.format(y_train[0]))

image_size = x_train[0].shape[0] * x_train[0].shape[1]


x_train = x_train.reshape((x_train.shape[0]), image_size).astype('float32')
x_test = x_test.reshape((x_test.shape[0]), image_size).astype('float32')

pixel_max = 255
x_train = x_train/pixel_max
x_test = x_test/pixel_max

number_of_classes = 10
y_train = to_categorical(y_train, number_of_classes)
y_test = to_categorical(y_test, number_of_classes)

Konstruisati model neuronske mreže sa propagacijom unapred sa narednom


kon guracijom:

• Sloj 1: gusti sloj sa 128 čvorova i ispravljačkom jedinicom kao aktivacionom


funkcijom

• Sloj 2: gusti sloj sa 512 čvorova i ispravljačkom jedinicom kao aktivacionom


funkcijom

• Sloj 3: gusti sloj sa onoliko čvorova koliko ima klasa i funkcijom mekog mak-
simuma kao aktivacionom funkcijom

Za funkciju greške uzeti kategoričku unakrsnu entropiju, broj iteracija obučava-


nja je 10, veličina batch skupa je 128 i optimizator je RMSPROP. Za metriku uzeti
tačnost. Evaluirati model na skupu za testiranje.
In [83]:
model = Sequential()
model.add(Dense(units=128, input_dim=image_size, activation='relu'))
model.add(Dense(units=512, activation='relu'))
model.add(Dense(units=number_of_classes, activation='softmax'))
model.compile(optimizer='rmsprop', loss=categorical_crossentropy, \
metrics=['accuracy'])

model.fit(x_train, y_train, batch_size=128, epochs=10)

test_scores = model.evaluate(x_test, y_test)

Odabrati prvih 20 instanci iz skupa za testiranje i prikazati ih u mreži gura


dimenzije 5 × 4. Prikazati za svaku instancu njenu tačnu i predviđenu klasu.
GLAVA 5. NEURONSKE MREŽE 35

In [84]:
y_pred = model.predict(x_test[:20, :])

columns = 5
rows = 4

orig_img_size = int(np.sqrt(image_size))

fig, axes = plt.subplots(rows, columns)

for r in range(rows):
for c in range(columns):
img = x_test[r+c].reshape((orig_img_size, orig_img_size))
ax = axes[r][c]
ax.figure.set_size_inches(15, 15)
ax.set_title('True class: {0},\nPredicted class: {1}'. \
format(np.argmax(y_test[r+c]), np.argmax(y_pred[r+c])))
ax.imshow(img, cmap='gray')

5.2 Implementacija neuronske mreže sa propagaci-


jom unapred
Zadatak 5.5. TODO: Dopuniti detaljnijim tekstom i srediti kod.
Pravimo mrezu koja od nas ocekuje koliko ima slojeva i kakve su kon guracije
tih slojeva (broj cvorova).
Slojevi mreze su uvezani - to pratimo preko matrica.
Koe cijent Wljk - veza izmedju k cvora l − 1 sloja i j cvora l sloja
Za jedan neuron: (1) on ima razlicite ulaze xi (2) svaki ulaz ima tezinu wi (3)
dodatno, posmatra se ∑ bias deo, kojim kontrolisemo ponasanje neurona: (4) pravi se
linearna kombinacija xi wi ≤ bias, gde je bias threshold da li se aktivira neuron ili
ne (5) mi se bavimo 0-1 vrednostima (6) izlaz neurona - aktivacija
Koe cijent blj znaci bias za j-ti cvor na sloju l.
Koe cijent alj znaci aktivacija j-tog cvora na sloju l:
(∑ )
l−1
alj = σ k w l
jk · a k + b l
j
U vektorskom obliku:
al = σ(Wl · al−1 + bl )
Izraz u zagradi obelezavamo zl .
∑ 2
, gde je L poslednji sloj, a y(x) prava
x y(x) − a (x)
1 L
Loss funkcija: C(W, b) = 2n
vrednost.
Ovo obelezavamo
∑ kao: 2 ∑
C(w, b) = n1 x cx , gde je cx = 12 y(x) − aL (x) = 12 j (yj − aLj )
In [85]:
def sigmoid(z):
return 1/(1+np.exp(-z))

def sigmoid_prime(z):
s = sigmoid(z)
return s*(1-s)

sigmoid(0)
sigmoid_prime(0)
GLAVA 5. NEURONSKE MREŽE 36

class Network():

# sizes - lista velicina slojeva


def __init__(self, sizes):
self.number_of_layers = len(sizes)
self.sizes = sizes
# za svaki cvor svakog sloja, osim prvog dodajemo bias, za sada random broj
self.biases = [np.random.randn(y, 1) for y in sizes[1:]]
# ovo ce biti dimenzije $l \times l-1$ umesto obrnuto da bi se lepo pomnozile
# na primer, ako imamo slojeve
# * *
# * *
# 2 cvora *
# 3 cvora
#
# onda je matrica dimezija 3x2
# zato, ako prosledimo vektor weights=[2, 3, 30, 4],
# onda mozemo da sklopimo ove matrice na sledeci nacin:
# [2, 3, 30, ] -> preskacemo poslednji
# \ \ \
# [, 3, 30, 4] -> preskacemo prvi
self.weights = [np.random.randn(y, x) for x, y in zip(sizes[:-1], sizes[1:])]

# ulazna aktivacija je x
def feedforward(self, network_input):
for b, w in zip(self.biases, self.weights):
# racunamo aktivacije za svaki sloj
network_input = sigmoid(np.dot(w, network_input) + b)

# vracamo aktivaciju poslednjeg sloja


return network_input

#stohasticki gradijentni spust


def SGD(self, training_inputs, training_results, epochs, mini_batch_size, alpha, test_data=No
n = len(training_inputs)
if test_data:
m = len(test_data)

for epoch in range(epochs):


# randomize

mini_batches = [
(training_inputs[k:k+mini_batch_size], training_results[k:k+mini_batch_size]) \
for k in range(0, n, mini_batch_size)
]

for mini_batch in mini_batches:


self.update_mini_batch(mini_batch, alpha)

if test_data:
print('Epoch {0}: {1}/{2}'.format(
epoch, self.evaluate(test_data[0], test_data[1]), m
))
else:
GLAVA 5. NEURONSKE MREŽE 37

print('Epoch {0} completed'.format(epoch))

# za pojedinacno x i y
def backpropagation(self, x, y):
nabla_b = [np.zeros(b.shape) for b in self.biases]
nabla_w = [np.zeros(w.shape) for w in self.weights]
activations = [x]
activation = x
zs = []

# forward pass
for b, w in zip(self.biases, self.weights):
z = np.dot(w, activation) + b
zs.append(z)
activation = sigmoid(z)
activations.append(activation)

# algoritam - back propagation


# cost_derivate je loss funkcija: (y-a)^2
# K1:
delta = self.cost_derivate(activations[-1], y) * sigmoid_prime(zs[-1])
nabla_b[-1] = delta
nabla_w[-1] = np.dot(delta, activations[-2].T)

for l in range(2, self.number_of_layers):


# K2:
z = zs[-l]
sp = sigmoid_prime(z)
delta = np.dot(self.weights[-l+1].T, delta) * sp
# K3:
nabla_b[-l] = delta
# K4
nabla_w[-l] = np.dot(delta, activations[-l-1].T)

return nabla_b, nabla_w

def update_mini_batch(self, mini_batch, alpha):


n = len(mini_batch)
nabla_b = [np.zeros(b.shape) for b in self.biases]
nabla_w = [np.zeros(w.shape) for w in self.biases]

# mini_batch[0] - sve x vrednosti


# mini_batch[1] - sve y vrednosti
for x, y in zip(mini_batch[0], mini_batch[1]):
delta_nabla_b, delta_nabla_w = self.backpropagation(x, y)
# azuriranje vrednosti
nabla_b = [nb+dnb for nb, dnb in zip(nabla_b, delta_nabla_b)]
nabla_w = [nw+dnw for nw, dnw in zip(nabla_w, delta_nabla_w)]

# azuriramo koeficijente mreze


self.weights = [w-alpha/n*nw for w, nw in zip(self.weights, nabla_w)]
self.biases = [b-alpha/n*nb for b, nb in zip(self.biases, nabla_b)]

def cost_derivate(self, activation, y):


GLAVA 5. NEURONSKE MREŽE 38

return activation-y

def evaluate(self, test_inputs, test_results):


results = [(np.argmax(self.feedforward(x)), np.argmax(y)) for x, y in zip(test_inputs, te

return sum([int(y_pred == y) for y_pred, y in results])

network = Network([2, 3, 10])

network.number_of_layers

network.sizes

[w.shape for w in network.weights]

network_input = np.array([1, 1]).reshape(2, 1)

network.feedforward(network_input)

Zadatak 5.6. TODO: Dopuniti detaljnijim tekstom i srediti kod.


Uraditi zadatak 5.4 korišćenjem implementacije MSPU iz zadatka 5.5.
In [86]:
(x_train, y_train), (x_test, y_test) = mnist.load_data()

x_train = x_train.astype('float32')
x_test = x_test.astype('float32')

x_train = x_train/255
x_test = x_test/255

training_inputs = [np.reshape(x, (784, 1)) for x in x_train]


test_inputs = [np.reshape(x, (784, 1)) for x in x_test]

def vectorize(digit):
v = np.zeros((10, 1))
v[digit] = 1

return v

training_results = [vectorize(y) for y in y_train]


test_results = [vectorize(y) for y in y_test]

training_results[1]

network = Network([784, 30, 10])

network.SGD(training_inputs, training_results, 10, 126, 0.1, test_data=[test_inputs, test_results

5.3 Konvolutivne neuronske mreže


Da bismo uspešno pokrenuli zadatak 5.7, potrebno je instalirati alat graphviz
koji je moguće pronaći na adresi https://www.graphviz.org/ (u ovoj skripti se po-
GLAVA 5. NEURONSKE MREŽE 39

zdrazumeva verzija 2.38). Nakon instalacije je neophodno ručno dodati putanju ka


instalacionom direktorijumu u environment promenljivu PATH (podrazumevano je
instalacioni direktorijum C:\Program Files (x86)\Graphviz2.38\bin).
Zadatak 5.7. Napisati funkciju koja učitava skup podataka iz datoteke path pomo-
ću paketa h5py. Funkcija treba da iscrtava i nasumičnih preview podataka iz skupa,
gde je vrednosti preview podrazumevano postavljena na vrednost 5. Funkcija vraća
skup za treniranje, razbijen na skup atributa i skup ciljne promenljive, kao i broj
klasa. Iskoristiti funkciju za učitavanje datoteke train_signs.h5 i prikazati jednu
nasumičnu instancu.
In [87]:
def load_train_dataset(path, preview=5):
train_dataset = h5py.File(path, 'r')
# train_set_x - slike
# train_set_y - brojevi prstiju na slici
# classes - 0, 1, ..., 5

train_x = np.array(train_dataset['train_set_x'])
train_y = np.array(train_dataset['train_set_y'])
classes = np.array(train_dataset['list_classes'])

print('train_x size: {0}'.format(train_x.shape))


print('train_y size: {0}'.format(train_y.shape))
print('classes:s {0}'.format(classes))

for i in np.arange(preview):
ind = np.random.randint(train_x.shape[0])
plt.figure()
plt.suptitle(train_y[ind])
plt.imshow(train_x[ind])

return train_x, train_y, len(classes)

def one_hot(y, C):


y_one_hot = np.zeros((y.shape[0], C))
# stavljamo 1 tamo gde je vrednost y
y_one_hot[np.arange(y.shape[0]), y] = 1

return y_one_hot

tix, tiy, C = load_train_dataset('train_signs.h5', preview=1)

Napisati funkciju koja od zadate klase vraća one-hot reprezentaciju. Funkcija


treba da oponaša rad metode keras.utils.to_categorical. Napisati funkciju, slič-
nu prethodnoj, za učitavanje skupa za testiranje. Iskoristiti funkciju sa učitavanje
datoteke test_signs.h5. Standardizovati podatke.
In [88]:
def load_test_dataset(path='test_signs.h5'):
test_dataset = h5py.File(path, 'r')

test_x = np.array(test_dataset['test_set_x'])
test_y = np.array(test_dataset['test_set_y'])

return test_x, test_y

test_x, test_y = load_test_dataset()


GLAVA 5. NEURONSKE MREŽE 40

tix = tix/255
test_x = test_x/255

tiy = one_hot(tiy, C)
test_y = one_hot(test_y, C)

Napisati funkciju koja na osnovu dimenzija slike i broja klasa konstruiše konvo-
lutivnu neuronsku mrežu zadatu narednom speci kacijom:

• Sloj 1: sloj za učitavanje

• Nadsloj 2: konvolutivni sloj, koji se sastoji od narednih slojeva

– sloj koji popunjava nulama okolinu slike


– dvodimenzionalni konvolutivni sloj sa 32 izlaza, 3 × 3 dimenzijom kernela
i pomerajem kernela za (1, 1)
– sloj normalizacije po izlaznim lterima iz prethodnog sloja
– aktivacioni sloj sa isravljačkom jedinicom

• Sloj 3: agregacioni sloj koji maksimizuje iz blokova dimenzije 2 × 2

• Nadsloj 4: konvolutivni sloj, koji se sastoji od istih slojeva kao nadsloj 2, sa


razlikom da konvolutivni sloj ima 64 izlaza

• Sloj 5: agregacioni sloj koji maksimizuje iz blokova dimenzije 2 × 2

• Nadsloj 6: konvolutivni sloj, koji se sastoji od istih slojeva kao nadsloj 2, sa


razlikom da konvolutivni sloj ima 16 izlaza

• Sloj 7: sloj koji sabija (engl. atten) podatke

• Sloj 8: dropout sloj sa verovatnoćom od 0.1 izbacivanja

• Sloj 9: gusti sloj sa 1024 neurona i ispravljačkom jedinicom kao aktivacionom


funkcijom

• Sloj 9: gusti sloj sa onoliko neurona koliko ima klasa i funkcijom mekog mak-
simuma kao aktivacionom funkcijom

Prikazati pregled mreže i uporediti ga sa narednim pregledom:

_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
input_1 (InputLayer) (None, 64, 64, 3) 0
_________________________________________________________________
zero_padding2d_1 (ZeroPaddin (None, 66, 66, 3) 0
_________________________________________________________________
conv2d_1 (Conv2D) (None, 64, 64, 32) 896
_________________________________________________________________
batch_normalization_1 (Batch (None, 64, 64, 32) 128
_________________________________________________________________
activation_1 (Activation) (None, 64, 64, 32) 0
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 32, 32, 32) 0
GLAVA 5. NEURONSKE MREŽE 41

_________________________________________________________________
zero_padding2d_2 (ZeroPaddin (None, 34, 34, 32) 0
_________________________________________________________________
conv2d_2 (Conv2D) (None, 32, 32, 64) 18496
_________________________________________________________________
batch_normalization_2 (Batch (None, 32, 32, 64) 256
_________________________________________________________________
activation_2 (Activation) (None, 32, 32, 64) 0
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 16, 16, 64) 0
_________________________________________________________________
zero_padding2d_3 (ZeroPaddin (None, 18, 18, 64) 0
_________________________________________________________________
conv2d_3 (Conv2D) (None, 16, 16, 16) 9232
_________________________________________________________________
batch_normalization_3 (Batch (None, 16, 16, 16) 64
_________________________________________________________________
activation_3 (Activation) (None, 16, 16, 16) 0
_________________________________________________________________
flatten_1 (Flatten) (None, 4096) 0
_________________________________________________________________
dropout_1 (Dropout) (None, 4096) 0
_________________________________________________________________
dense_1 (Dense) (None, 1024) 4195328
_________________________________________________________________
dense_2 (Dense) (None, 6) 6150
=================================================================
Total params: 4,230,550
Trainable params: 4,230,326
Non-trainable params: 224
_________________________________________________________________
Takođe, prikazati i graphviz dijagram date mreže.
In [89]:
def build_model(image_shape, C):
x_input = Input(image_shape)

# sta je to sto input sloj propagira kroz mrezu


x = ZeroPadding2D(padding=(1,1))(x_input)

# broj filtera/matrica
# dimenzija matrica
#strides - pomeraji horizontalno, vertikalno
x = Conv2D(32, (3, 3), strides=(1,1))(x)

# dobijemo standardizovane outpute


# kazemo po kojoj osi se vrsi normalizacija
# krenuli smo od slika 64x64 i tri kanala
# posto imamo 32 filtera, output je 64x64x32
# filteri sadrze atribute koje zelimo da koristimo,
# pa njih zelimo da koristimo
# normalizaciju radimo po atributima
x = BatchNormalization(axis=3)(x)

# aktivacioni sloj
GLAVA 5. NEURONSKE MREŽE 42

x = Activation('relu')(x)

# agregacioni sloj
# max pooling ili average pooling
# kazemo dimenzije blokova iz kojih izvlacimo max
x = MaxPool2D((2,2))(x)

# novi konvolutivni sloj


x = ZeroPadding2D(padding=(1,1))(x)
x = Conv2D(64, (3, 3), strides=(1,1))(x)
x = BatchNormalization(axis=3)(x)
x = Activation('relu')(x)

x = MaxPool2D((2,2))(x)

# novi konvolutivni sloj


x = ZeroPadding2D(padding=(1,1))(x)
x = Conv2D(16, (3, 3), strides=(1,1))(x)
x = BatchNormalization(axis=3)(x)
x = Activation('relu')(x)

# na kraju je cest scenario da se na kraju stavi jedan feed forward sloj


x = Flatten()(x)

# dropout sloj
# kazemo koji je procenat neurona
# cije cemo aktivacione funkcije postaviti na 0, tj.
# koje cemo izbaciti iz mreze
# vid regularizacije
x = Dropout(rate=0.1)(x)

# gusti sloj
x = Dense(units=1024, activation='relu')(x)
# poslednji gusti sloj za izlaz
x = Dense(units=C, activation='softmax')(x)

return Model(inputs=x_input, outputs=x, name='sign_cnn')

sign_cnn = build_model(tix[0].shape, C)
sign_cnn.summary()

display(SVG(model_to_dot(sign_cnn).create(prog='dot', format='svg')))

Obučiti model u 4 iteracije, sa veličinom batch skupa od 64, uz pomoć ADAM


optimizatora sa parametrom učenja 0.00075. Za funkciju greške uzeti kategoričku
unakrsnu entropiju, a za metriku uzeti tačnost. Evaluirati model.
In [90]:
sign_cnn.compile(optimizer=optimizers.Adam(lr=0.00075), \
loss=categorical_crossentropy, metrics=['accuracy'])

sign_cnn.fit(tix, tiy, epochs=4, batch_size=64)


sign_cnn.evaluate(test_x, test_y)

Zadatak 5.8. Iz paketa keras.datasets učitati skup podataka cifar10. Zbog velike
dimenzionalnosti skupa, izdvojiti 200 slika za obučavanje i 50 slika za evaluaciju.
GLAVA 5. NEURONSKE MREŽE 43

Prikazati jednu nasumičnu sliku i u naslovu staviti koje je klase. Takođe, ispisati i
dimenzije jednog podatka za obučavanje i proveriti broj raspoloživih klasa. Stan-
dardizovati ulazne podatke, a ciljne promenljive transformisati u one-hot reprezen-
taciju.
In [91]:
(x_train, y_train), (x_test, y_test) = cifar10.load_data()

train_ind = np.random.randint(0, x_train.shape[0], 200)


test_ind = np.random.randint(0, x_test.shape[0], 50)
x_train = x_train[train_ind]
y_train = y_train[train_ind]
x_test = x_test[test_ind]
y_test = y_test[test_ind]

plt.title('Klasa {0}'.format(y_train[0]))
plt.imshow(x_train[0])

print(x_train[0].shape)
num_of_classes = len(np.unique(y_train))
print('Broj klasa je {0}'.format(num_of_classes))

x_train = x_train/255
x_test = x_test/255
y_train = to_categorical(y_train, num_of_classes)
y_test = to_categorical(y_test, num_of_classes)

Konstruisati model konvolutivne neuronske mreže prema smernicama koje su


opisane narednim izveštajem
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
conv2d_1 (Conv2D) (None, 32, 32, 16) 448
_________________________________________________________________
conv2d_2 (Conv2D) (None, 32, 32, 64) 9280
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 16, 16, 64) 0
_________________________________________________________________
conv2d_3 (Conv2D) (None, 16, 16, 64) 36928
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 8, 8, 64) 0
_________________________________________________________________
flatten_1 (Flatten) (None, 4096) 0
_________________________________________________________________
dense_1 (Dense) (None, 512) 2097664
_________________________________________________________________
dense_2 (Dense) (None, 10) 5130
=================================================================
Total params: 2,149,450
Trainable params: 2,149,450
Non-trainable params: 0
_________________________________________________________________
uz naredne smernice
• veličinu kvadratnog kernela postaviti na 3
GLAVA 5. NEURONSKE MREŽE 44

• ispunjavanje (engl. padding) konvolucionih slojeva postaviti na 'same'


• za aktivacionu funkciju svih slojeva osim poslednjeg postaviti ispravljačku je-
dinicu
• za aktivacionu funkciju poslednjeg sloja postaviti funkciju mekog maksimuma

In [92]:
def build_model(input_size, num_of_classes):
model = Sequential()

model.add(Convolution2D(input_shape=input_size, filters=16, \
kernel_size=(3, 3), padding='same', activation='relu'))
model.add(Convolution2D(filters=64, kernel_size=(3, 3), padding='same', \
activation='relu'))
model.add(MaxPooling2D())
model.add(Convolution2D(filters=64, kernel_size=(3, 3), padding='same', \
activation='relu'))
model.add(MaxPooling2D())
model.add(Flatten())
model.add(Dense(units=512, activation='relu'))
model.add(Dense(units=num_of_classes, activation='softmax'))

return model

model = build_model(x_train[0].shape, num_of_classes)

Obučiti mrežu korišćenjem optimizatora ADAM u 10 iteracija sa veličinom batch


skupa od 32. Za funkciju gubitka uzeti kategoričku unakrsnu entropiju, a za metriku
uzeti tačnost. Odvojiti 30% skupa za validacioni skup. Dati ocenu greške.
In [93]:
model.compile(optimizer=Adam(), loss=categorical_crossentropy, \
metrics=['accuracy'])
history = model.fit(x_train, y_train, epochs=10, batch_size=32, \
validation_split=0.3)
model.evaluate(x_test, y_test)

5.4 Različiti načini optimizacije neuronskih mreža


Zadatak 5.9. Pretpostaviti da se u tekućem direktorijumu nalazi datoteka data.mat
koja sadrži informacije o skupu dvodimenzionalnih tačaka. Napisati funkciju koja
učitava podatke u skupove za obučavanje i testiranje, i iscrtava ih pomoću rasprše-
nog dijagrama. Tačke koje pripadaju klasi 0 prikazati plavom, a tačke koje pripa-
daju klasi 1 prikazati crvenom bojom. Funkcija treba da vraća skupove podataka u
obliku x_train, y_train, x_test, y_test.
In [94]:
def load_2D_dataset():
data = scipy.io.loadmat('data.mat')

train_X = np.array(data['X']).T
train_Y = data['y'].T
test_X = data['Xval'].T
test_Y = data['yval'].T
GLAVA 5. NEURONSKE MREŽE 45

colors = np.where(train_Y==0, 'blue', 'red')


plt.scatter(train_X[0, :], train_X[1, :], c=colors.flatten(), s=40, \
cmap=plt.cm.Spectral)

return train_X.T, test_X.T, train_Y.T, test_Y.T

x_train, y_train, x_test, y_test = load_2D_dataset()

Konstruisati model neuronske mreže sa propagacijom unapred, čiji su slojevi

• I sloj: 50 neurona, aktivaciona funkcija: 'relu'

• II sloj: 25 neurona, aktivaciona funkcija: 'relu'

• III sloj: 1 neuron, aktivaciona funkcija: 'sigmoid'

Detalji algoritma su dati sa

• Funkcija greške: srednjekvadratna greška

• Algoritam: gradijentni spust

• Metrika: tačnost

• Broj iteracija: 3000

• Batch size: 16

Ispisati tačnost ovog modela na skupovima za obučavanje i testiranje.


In [95]:
K.clear_session()

num_of_features = x_train.shape[1]
output_size = 1

model = Sequential()
model.add(Dense(input_dim=num_of_features, units=50, activation='relu'))
model.add(Dense(units=25, activation='relu'))
model.add(Dense(units=output_size, activation='sigmoid'))
model.compile(optimizer='sgd', loss=mse, metrics=['accuracy'])
model.fit(x_train, y_train, epochs=3000, batch_size=16, verbose=False)

eval_data_train = model.evaluate(x_train, y_train)


eval_data_test = model.evaluate(x_test, y_test)
eval_data = pd.DataFrame([eval_data_train, eval_data_test], \
columns=model.metrics_names, index=['Train', 'Test'])
print(eval_data)

Zadatak 5.10. Konstruisati model neuronske mreže sa propagacijom unapred koji


je isti kao i model iz zadatka 5.9, ali koji ima dropout sa narednim vrednostima:

• Nakon I sloja: 10%

• Nakon II sloja: 70%

• Nakon III sloja: 30%

Ispisati tačnost ovog modela na skupovima za obučavanje i testiranje.


GLAVA 5. NEURONSKE MREŽE 46

In [96]:
K.clear_session()

model = Sequential()
model.add(Dense(input_dim=num_of_features, units=50, activation='relu'))
model.add(Dropout(rate=0.1))
model.add(Dense(units=25, activation='relu'))
model.add(Dropout(rate=0.7))
model.add(Dense(units=output_size, activation='sigmoid'))
model.add(Dropout(rate=0.3))
model.compile(optimizer='sgd', loss=mse, metrics=['accuracy'])
model.fit(x_train, y_train, epochs=3000, batch_size=16, verbose=False)

eval_data_train = model.evaluate(x_train, y_train)


eval_data_test = model.evaluate(x_test, y_test)
eval_data = pd.DataFrame([eval_data_train, eval_data_test], \
columns=model.metrics_names, index=['Train', 'Test'])
print(eval_data)

Zadatak 5.11. Konstruisati model neuronske mreže sa propagacijom unapred koji


je isti kao i model iz zadatka 5.9, ali koji dodatno koristi tehniku ranog zaustavljanja
(engl. early stopping). Za parametre ranog zaustavljanja birati sledeće

• posmatrati vrednosti funkcije greške na skupu za obučavanje

• zaustaviti obučavanje nakon 5 iteracija gde nije dolazilo do napretka

Ispisati tačnost ovog modela na skupovima za obučavanje i testiranje.


In [97]:
K.clear_session()

model = Sequential()
model.add(Dense(input_dim=num_of_features, units=50, activation='relu'))
model.add(Dense(units=25, activation='relu'))
model.add(Dense(units=output_size, activation='sigmoid'))
model.compile(optimizer='sgd', loss=mse, metrics=['accuracy'])

model.fit( \
x_train, y_train, \
epochs=3000, \
batch_size=16, \
verbose=False, \
callbacks=[EarlyStopping(monitor='loss', patience=5)])

eval_data_train = model.evaluate(x_train, y_train)


eval_data_test = model.evaluate(x_test, y_test)
eval_data = pd.DataFrame([eval_data_train, eval_data_test], \
columns=model.metrics_names, index=['Train', 'Test'])
print(eval_data)

Zadatak 5.12. Konstruisati model neuronske mreže sa propagacijom unapred koji


je isti kao i model iz zadatka 5.11, ali koji dodatno koristi tehniku odsecanja gradi-
jenata na vrednost 0.2. Ispisati tačnost ovog modela na skupovima za obučavanje i
testiranje.
GLAVA 5. NEURONSKE MREŽE 47

In [98]:
K.clear_session()

model = Sequential()
model.add(Dense(input_dim=num_of_features, units=50, activation='relu'))
model.add(Dense(units=25, activation='relu'))
model.add(Dense(units=output_size, activation='sigmoid'))
model.compile(optimizer=SGD(clipvalue=0.2), loss=mse, metrics=['accuracy'])

model.fit( \
x_train, y_train, \
epochs=3000, \
batch_size=16, \
verbose=False, \
callbacks=[EarlyStopping(monitor='loss', patience=5)])

eval_data_train = model.evaluate(x_train, y_train)


eval_data_test = model.evaluate(x_test, y_test)
eval_data = pd.DataFrame([eval_data_train, eval_data_test], \
columns=model.metrics_names, index=['Train', 'Test'])
print(eval_data)

5.5 Rekurentne neuronske mreže


Zadatak 5.13. Učitati skup podataka o smotri lmova na veb sajtu IMDB iz paketa
keras.datasets.imdb. Pri učitavanju, postaviti da najveća veličina vokabulara iznosi
10 hiljada reči. Svaki podatak predstavlja niz brojeva, pri čemu su brojevi indeksi
reči u vokabularu. Treba primetiti da smotre imaju različit broj reči. Zbog toga,
treba uni kovati sve tekstove — transformisati ih u liste dužine 500. One liste koje
imaju više reči, treba odsecati, a one koje imaju manje, treba dopuniti. Ciljna pro-
menljiva ima vrednosti 0 ili 1 u zavisnosti od toga da li je smotra ocenjena negativno
ili pozitivno, redom.
In [99]:
max_features = 10000
(x_train, y_train), (x_test, y_test) = imdb.load_data(num_words=max_features)

maxlen = 500
x_train = sequence.pad_sequences(x_train, maxlen=maxlen)
x_test = sequence.pad_sequences(x_test, maxlen=maxlen)

Napisati funkciju koja kreira model rekurentne neuronske mreže koja zadovo-
ljava naredni prikaz

_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
embedding_2 (Embedding) (None, None, 32) 320000
_________________________________________________________________
simple_rnn_2 (SimpleRNN) (None, 32) 2080
_________________________________________________________________
dense_2 (Dense) (None, 1) 33
=================================================================
Total params: 322,113
GLAVA 5. NEURONSKE MREŽE 48

Trainable params: 322,113


Non-trainable params: 0
_________________________________________________________________
Za sloj ugnežđavanja, ulazna dimenzija treba biti postavljena na veličinu voka-
bulara, a izlazna dimenzija na veličinu ugnežđenih reprezentacija (u ovom primeru
ćemo koristiti veličinu 32). Za rekurentni sloj mreže, broj izlaza postaviti na 32. Za
aktivacionu funkciju poslednjeg sloja staviti funkciju mekog maksimuma. Obučiti
mrežu korišćenjem optimizatora RMSPROP u 5 iteracija sa veličinom batch skupa
od 128. Za funkciju gubitka uzeti binarnu unakrsnu entropiju, a za metriku uzeti
tačnost. Odvojiti 20% skupa za validacioni skup. Dati ocenu greške.
In [100]:
def build_model(input_dim, output_dim):
model = Sequential()

model.add(Embedding(input_dim=input_dim, output_dim=32))
model.add(SimpleRNN(units=32, activation='tanh'))
model.add(Dense(units=1, activation='softmax'))

return model

model = build_model(max_features, 1)
model.compile(optimizer='rmsprop', loss=binary_crossentropy, \
metrics=['accuracy'])
history = model.fit(x_train, y_train, epochs=5, batch_size=128, \
validation_split=0.2)
print(model.evaluate(x_test, y_test))

Prikazati gra ke zavisnosti funkcije gubitka i tačnosti na skupu za obučavanje i


validaciju.
In [101]:
epochs = history.epoch

loss = history.history['loss']
val_loss = history.history['val_loss']
plt.plot(epochs, loss, label='training_loss', c='blue')
plt.plot(epochs, val_loss, label='validation_loss', c='red')
plt.legend(loc='best')
plt.show()

acc = history.history['acc']
val_acc = history.history['val_acc']
plt.plot(epochs, acc, label='training_acc', c='blue')
plt.plot(epochs, val_acc, label='validation_acc', c='red')
plt.legend(loc='best')
plt.show()

Zadatak 5.14. Uraditi zadatak 5.13, ali koristiti jedinicu duge kratkoročne memo-
rije, i sigmoidnu funkciju kao aktivacionu funkciju poslednjeg sloja.
In [102]:
K.clear_session()

model = Sequential()
model.add(Embedding(input_dim=max_features, output_dim=32))
model.add(LSTM(32))
GLAVA 5. NEURONSKE MREŽE 49

model.add(Dense(1, activation='sigmoid'))
model.compile(optimizer='rmsprop', loss='binary_crossentropy', \
metrics=['accuracy'])

history = model.fit(x_train, y_train, epochs=5, batch_size=128, \


validation_split=0.2)
print(model.evaluate(x_test, y_test))

epochs = history.epoch

loss = history.history['loss']
val_loss = history.history['val_loss']
plt.plot(epochs, loss, label='training_loss', c='blue')
plt.plot(epochs, val_loss, label='validation_loss', c='red')
plt.legend(loc='best')
plt.show()

acc = history.history['acc']
val_acc = history.history['val_acc']
plt.plot(epochs, acc, label='training_acc', c='blue')
plt.plot(epochs, val_acc, label='validation_acc', c='red')
plt.legend(loc='best')
plt.show()

Zadatak 5.15. Pretpostaviti da se u tekućem direktorijumu nalazi datoteka


jena_climate_2009_2016.csv koja sadrži skup podataka različitih atmosferskih mere-
nja u periodu od 1.1.2009. do 1.1.2017. Merenja su vršena na svakih 10 minuta.
Učitati datoteku i parsirati je tako da se u promenljivoj headers pronađu nazivi kolo-
na, promenljiva float_data sadrži matricu atributa i njihovih vrednosti (po kolona-
ma) za svako merenje (po vrstama), pri čemu treba eliminisati kolonu sa vremen-
skom odrednicom, i promenljiva temp sadrži vrednosti ciljne promenljive (kolona 'T
(degC)' u originalnim podacima). Nacrtati gra k zavisnosti temperature od mere-
nja.
In [103]:
data = None
with open('jena_climate_2009_2016.csv', 'r') as f:
data = f.read()

all_lines = data.split('\n')
header = all_lines[0]
headers = header.split(',')

lines = all_lines[1:]
num_of_rows = len(lines)
num_of_columns = len(headers)-1

float_data = np.zeros((num_of_rows, num_of_columns))

for i, line in enumerate(lines):


values = [float(m) for m in line.split(',')[1:]]
float_data[i, :] = values

temp = float_data[:, 1]

plt.plot(range(len(lines)), temp)
GLAVA 5. NEURONSKE MREŽE 50

Napisati funkciju koja na osnovu podataka konstruiše generator skupova za obu-


čavanje, testiranje i validaciju, čije su odrednice date indeksima min_index i max_index.
Funkciji treba proslediti i lookback, tj. broj merenja koje gledamo unazad, steps, tj.
korak na kojem posmatramo merenja u okviru parametra lookback, delay, tj. broj
merenja koje želimo da predvidimo, shuffle, koji određuje da li se merenja biraju
nasumično i veličinu batch skupa. Podrazumevano postaviti da se posmatra svaki
6. korak, da ne vrši nasumično biranje, kao i da je veličina batch skupa 128.

In [104]:
def generator(data, min_index, max_index, lookback, delay, step=6, \
shuffle=True, batch_size=128):
# Moramo da se postaramo da je najveci indeks za podatke
# dovoljno udaljen od kraja, da bismo mogli da
# obucavamo model i za poslednjih delay merenja
if max_index is None:
max_index = len(data)-delay-1

# Takodje, treba da se osiguramo da


# imamo dovoljno merenja u proslosti
i = min_index + lookback

while True:
# Biramo...
if shuffle:
# ... ili nasumicnih batch_size merenja
rows = np.random.randint(low=i, high=max_index, size=batch_size)
else:
# ... ili prvih batch_size merenja
# (osim ako ih nema nedovoljno), pa vrsimo odsecanje
rows = range(i, np.min(i+batch_size, max_index))
i += rows

# Pripremamo dimenzije za skupove koje vracamo


num_of_rows = len(rows)
num_of_columns = lookback // step
num_of_depth = data.shape[-1]

samples = np.zeros((num_of_rows, num_of_columns, num_of_depth))


targets = np.zeros(num_of_rows)

for j, row in enumerate(rows):


# Za j-to merenje posmatramo lookback merenja iza j-tog merenja,
# a zatim svako step-to merenje
indices = range(rows[j]-lookback, rows[j], step)
samples[j] = data[indices]

# Da bismo odredili vrednost temperature koju odredjujemo,


# potrebno je da se od j-tog merenja pomerimo za delay merenja.
# Pristupamo koloni 1,
# jer se u njoj nalazi informacija o ciljnoj promenljivoj
targets[j] = data[rows[j] + delay][1]

yield samples, targets

Postaviti da se posmatraju merenja iz prethodnih 5 dana, kao i da je cilj predvi-


deti merenje za 24 sata. Korišćenjem napisane funkcije, konstruisati tri generatora,
za:
GLAVA 5. NEURONSKE MREŽE 51

• skup za obučavanje: instance su iz intervala indeksa [0, 200000], za ostale pa-


rametre koristiti podrazumevane vrednosti
• skup za validaciju: instance su iz intervala indeksa [200001, 300000), za ostale
parametre koristiti podrazumevane vrednosti
• skup za obučavanje: instance su iz intervala indeksa [3000001, None), za ostale
parametre koristiti podrazumevane vrednosti
Odrediti i broj koraka u fazi validacije i testiranja.
In [105]:
train_gen = generator(float_data, 0, 200000, lookback, delay)
val_gen = generator(float_data, 200001, 300000, lookback, delay)
test_gen = generator(float_data, 300001, None, lookback, delay)

test_steps = len(float_data)-300001-lookback
val_steps = 300000-200001-lookback

Konstruisati model rekurentne neuronske mreže koristeći jedinicu Gated Recur-


rent Unit. Model treba da zadovolji narednu speci kaciju
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
gru_1 (GRU) (None, 32) 4512
_________________________________________________________________
dense_1 (Dense) (None, 1) 33
=================================================================
Total params: 4,545
Trainable params: 4,545
Non-trainable params: 0
_________________________________________________________________
Obučiti model nad generatorom ksupa za obučavanje koristeći RMSPROP op-
3
timizator na 5 epoha , sa po 500 koraka po eposi. Za funkciju gubitka odabrati
srednjekvadratnu grešku. Za validacione podatke koristiti generator validacionog
skupa i postaviti odgovarajući broj validacionih koraka. Evaluirati model korišće-
njem generatora skupa za testiranje i postaviti odgovarajući broj koraka za testira-
nje.
In [106]:
model = Sequential()
model.add(GRU(32, input_shape=(None, float_data.shape[-1])))
model.add(Dense(1))
model.compile(optimizer='rmsprop', loss='mae')

model.summary()

history = model.fit_generator(train_gen, steps_per_epoch=500, epochs=5, \


validation_data=val_gen, validation_steps=val_steps)

model.evaluate_generator(test_gen, test_steps, verbose=True)

3
Napomenimo da je proces obučavanja značajno duži nego svi prethodni primeri — za jednu epo-
hu obučavanje može da traje i do 20 minuta! Naravno, u poređenju sa nekim primerima iz prakse, i
ovaj vremenski period može delovati kao niska vrednost, ali svakako treba dati na njegovom značaju u
kontekstu ove skripte.
GLAVA 5. NEURONSKE MREŽE 52

Zadatak 5.16. Arhiva ZonalDemands_2003-2016.csv.bz2 sadrži informacije o zahtevi-


ma za električnom energijom na svakih sat vremena u različitim delovima Kanade.
Podaci su prikupljani od maja 2003. godine do decembra 2016. godine. Učitati
skup podataka i upoznati se sa njim. Spojiti informacije o datumu i satu merenja na
nivou jedne odrednice, a zatim tu odrednicu iskoristiti za novi indeks skupa podata-
ka sa kojim se raspolaže. Nacrtati gra k električnih zahteva u vremenu za kolonu
'Total Ontario'. Nadalje koristiti samo ovaj skup vrednosti.
In [107]:
data = pd.read_csv('ZonalDemands_2003-2016.csv.bz2', engine='python', \
compression='bz2')
print(data.head())

def combine_date_and_hour(row):
date = pd.to_datetime(row['Date'])
hour = pd.Timedelta('{0} hours'.format(row['Hour']))
return date+hour

combined_cols = data.apply(combine_date_and_hour, axis=1)


data = data.set_index(combined_cols)
data = data.drop(labels=['Date', 'Hour'], axis=1)
print(data.head())

ontario_data = data['Total Ontario']


plt.plot(ontario_data)

Podeliti skup podataka na skupove za obučavanje i testiranje. Za datum podele


se može uzeti 1. januar 2014. godine. Nacrtati gra k ovih skupova. Izvršiti skalira-
nje podataka tako da vrednosti potrošnje budu u rasponu manjih vrednosti i ponovo
nacrtati gra k.
In [108]:
split_date=pd.Timestamp('2014-01-01')
train_ind = ontario_data.index < split_date
test_ind = ontario_data.index >= split_date
train_data = ontario_data[train_ind]
test_data = ontario_data[test_ind]

plt.plot(train_data)
plt.plot(test_data)
plt.show()

offset = 10000
scale = 5000
train_data = (train_data-offset)/scale
test_data = (test_data-offset)/scale

plt.plot(train_data)
plt.plot(test_data)
plt.show()

Ispitati ponašanje gusto povezane neuronske mreže sa propagacijom unapred u


zadacima predikcije potrošnje energije. Mreža kao ulaz treba da primi potrošnju
u tekućem satu i da dâ ocenu potrošnje za naredni sat. Speci kacija arhitekture
mreže je data narednim prikazom

_________________________________________________________________
GLAVA 5. NEURONSKE MREŽE 53

Layer (type) Output Shape Param #


=================================================================
dense_1 (Dense) (None, 24) 48
_________________________________________________________________
dense_2 (Dense) (None, 12) 300
_________________________________________________________________
dense_3 (Dense) (None, 6) 78
_________________________________________________________________
dense_4 (Dense) (None, 1) 7
=================================================================
Total params: 433
Trainable params: 433
Non-trainable params: 0
_________________________________________________________________

Funkcija koju treba minimizovati je srednjekvadratna greška, a kao optimizator


se može koristiti ADAM. Za broj epoha uzeti vrednost 200, a za veličinu paketa
(batch_size) 512. Nacrtati gra k dobijenih i očekivanih vrednosti i dati ocenu MSE
i R2 grešaka.
In [109]:
train_shifted = train_data.shift(-1)
test_shifted = test_data.shift(-1)
train_data = train_data[:-1]
y_train = train_shifted[:-1]
test_data = test_data[:-1]
y_test = test_shifted[:-1]

num_of_features = 1
output_size = 1

model = Sequential()
model.add(Dense(input_dim=num_of_features, units=24, activation='relu'))
model.add(Dense(units=12, activation='relu'))
model.add(Dense(units=6, activation='relu'))
model.add(Dense(units=output_size))
model.summary()

model.compile(optimizer='adam', loss=mse)
history = model.fit(train_data, y_train, batch_size=512, epochs=200, \
verbose=False)
y_pred = model.predict(test_data)

fig, (ax0, ax1) = plt.subplots(nrows=2, ncols=1)


ax0.plot(y_test.values, label='Expected data', color='blue')
ax1.plot(y_pred, label='Predicted data', color='red')
fig.legend(loc='upper right')

print(metrics.mean_squared_error(y_test, y_pred))
print(metrics.r2_score(y_test, y_pred))

Ispitati kako se ponaša rekurentna neuronska mreža koja koristi SimpleRNN ne-
urone u prvom sloju (ukupno njih 6), a zatim jedan gusti sloj. Funkcija koja se
minimizuje je srednjekvadratna greška, a kao optimizator se može koristiti ADAM
sa korakom učenja 0.0005. Voditi računa o tome da ulaz u SimpleRNN čvor mora biti
tenzor oblika ,,3D tensor with shape (batch_size, timesteps, input_dim)''. Za broj
GLAVA 5. NEURONSKE MREŽE 54

epoha i batch_size uzeti 1. Nacrtati gra k dobijenih i očekivanih vrednosti i dati


ocenu MSE i R2 grešaka.
In [110]:
K.clear_session()

model2 = Sequential()
model2.add(SimpleRNN(batch_input_shape=(1,1,1), units=6, \
kernel_initializer='ones', stateful=True))
model2.add(Dense(units=output_size, activation='relu'))
model2.compile(optimizer=Adam(lr=0.0005), loss=mse)
model2.summary()

x_train_t = train_data[:, None, None]


x_test_t = test_data[:, None, None]

y_train_t = y_train[:]
y_test_t = y_test[:]

history2 = model2.fit(x_train_t, y_train_t, batch_size=1, epochs=1, \


shuffle=False)
y_pred = model2.predict(x_test_t, batch_size=1)

fig, (ax0, ax1) = plt.subplots(nrows=2, ncols=1)


ax0.plot(y_test_t.values, label='Expected data', color='blue')
ax1.plot(y_pred, label='Predicted data', color='red')
fig.legend(loc='upper right')

print(metrics.mean_squared_error(y_test_t, y_pred))
print(metrics.r2_score(y_test_t, y_pred))

Ispitati kako se u istoj ovoj postavci ponasa LSTM sloj.


In [111]:
K.clear_session()

model3 = Sequential()
model3.add(LSTM(batch_input_shape=(1,1,1), units=6, \
kernel_initializer='ones', stateful=True))
model3.add(Dense(units=output_size))
model3.compile(optimizer=Adam(lr=0.0005), loss=mse)
model3.summary()

history3 = model3.fit(x_train_t, y_train_t, batch_size=1, epochs=1, \


shuffle=False)
y_pred = model3.predict(x_test_t, batch_size=1)

fig, (ax0, ax1) = plt.subplots(nrows=2, ncols=1)


ax0.plot(y_test_t.values, label='Expected data', color='blue')
ax1.plot(y_pred, label='Predicted data', color='red')
fig.legend(loc='upper right')

print(metrics.mean_squared_error(y_test_t, y_pred))
print(metrics.r2_score(y_test_t, y_pred))
Glava 6

Učenje potkrepljivanjem

In [112]:
import numpy as np
from matplotlib import pyplot as plt

import gym

from keras.utils import to_categorical


from keras.models import Sequential
from keras.layers import Dense

Zadatak 6.1. Jedno od okruženja koje postoji u OpenIA Gym biblioteci je 'NChain-v0'
okruženje u kojem se agent kreće kroz linearni lanac stanja. Dostupne su dve akci-
je: 0, tj. akcija pomeraja unapred za nagradom nula i 1, tj. akcija pomeraja nazad
na početno stanje koje ima malu nagradu. Na kraju lanca se nalazi velika nagra-
da i prelaskom u to stanje se može osvojiti ta nagrada. Takođe, pri svakom stanju
postoji mala verovatnoća da se agent ,,oklizne'' i da preduzme suprotnu akciju.
Učitati opisano okruženje, a zatim napisati funkciju koja koristeći naivni pohlep-
ni pristup pronalazi optimalnu politiku, odnosno, preslikavanje stanja u akcije koje
vodi maksimalnoj (ili, u praksi, dovoljno visokoj) dugoročnoj nagradi. Broj epizoda
postaviti na 100.
In [113]:
env = gym.make('NChain-v0')

def naive_sum_reward_table(env, number_of_episodes=100):


number_of_states = env.observation_space.n
number_of_actions = env.action_space.n

# Ovo je politika koju trazimo


r_table = np.zeros((number_of_states, number_of_actions))

for episode in range(number_of_episodes):


s = env.reset()
done = False

while not done:


if r_table[s, 0] == 0 and r_table[s, 1] == 0:
# Za prvi korak biramo nasumicnu akciju,
# jer jos uvek nemamo informaciju iz koje ucimo
a = env.action_space.sample()

55
GLAVA 6. UČENJE POTKREPLJIVANJEM 56

else:
# Inace, biramo akciju sa najvecom dobiti
a = np.argmax(r_table[s, :])

# Cinimo korak na osnovu izracunate akcije.


# Dobijamo informacije o:
# 1. novom stanju
# 2. nagradi koju smo dobili preduzimanjem akcije
# 3. informaciju o tome da li smo zavrsili, odnosno,
# da li je potrebno resetovati okruzenje
# 4. recnik sa informacijama korisnim za degabovanje
s_new, r, done, _ = env.step(a)

# Potrebno je da azuriramo tabelu nagrada za tekuce stanje


r_table[s, a] += r

# Prelazimo na naredno stanje


s = s_new

return r_table

naive_result = naive_sum_reward_table(env)
print(naive_result)

Zadatak 6.2. Učitati okruženje iz zadatka 6.1. Korišćenjem Q-learning algoritma


u toku od 100 epizoda naučiti optimalnu politiku. Za vrednost koraka učenja uzeti
0.8, a za metaparametar umanjenja uzeti vrednost 0.95.
In [114]:
env = gym.make('NChain-v0')

def q_learning(env, number_of_episodes=100):


number_of_states = env.observation_space.n
number_of_actions = env.action_space.n
q_table = np.zeros((number_of_states, number_of_actions))
alpha = 0.8
gamma = 0.95

for episode in range(number_of_episodes):


s = env.reset()
done = False

while not done:


if q_table[s, 0] == 0 and q_table[s, 1] == 0:
a = env.action_space.sample()
else:
a = np.argmax(q_table[s, :])

s_new, r, done, _ = env.step(a)

# Srz Q-learning algoritma se sastoji u funkciji Q


q_table[s, a] = q_table[s, a] + \
alpha*(r + gamma*np.max(q_table[s_new, :]) - q_table[s, a])

s = s_new

return q_table
GLAVA 6. UČENJE POTKREPLJIVANJEM 57

q_result = q_learning(env)
print(q_result)

Zadatak 6.3. Učitati okruženje iz zadatka 6.1. Korišćenjem Q-learning algoritma,


uz mogućnost eksperimentisanja (prelaska u nasumično stanje) od strane agenta, u
toku od 100 epizoda naučiti optimalnu politiku. Za vrednost koraka učenja uzeti 0.8,
a za metaparametar umanjenja uzeti vrednost 0.95. Obezbediti da na početku agent
eksperimentiše sa verovatnoćom 0.5, a da se pri svakoj epizodi ova verovatnoća
smanjuje faktorom opadanja 0.999.
In [115]:
env = gym.make('NChain-v0')

def eps_q_learning(env, number_of_episodes=100):


number_of_states = env.observation_space.n
number_of_actions = env.action_space.n
eps_q_table = np.zeros((number_of_states, number_of_actions))
alpha = 0.8
gamma = 0.95
eps = 0.5
# faktor opadanja
# u svakom narednom koraku, u ovoj meri se umanjuje vrednost epsilona
decay_factor = 0.999

for episode in range(number_of_episodes):


s = env.reset()
done = False
eps *= decay_factor

while not done:


if (eps_q_table[s, 0] == 0 and eps_q_table[s, 1] == 0) \
or np.random.random() < eps:
a = env.action_space.sample()
else:
a = np.argmax(eps_q_table[s, :])

s_new, r, done, _ = env.step(a)

# azuriranje vrednosti nagrada


eps_q_table[s, a] = eps_q_table[s, a] + \
alpha*(r + gamma*np.max(eps_q_table[s_new, :]) - \
eps_q_table[s, a])

s = s_new

return eps_q_table

eps_q_table = eps_q_learning(env)
print(eps_q_table)

Zadatak 6.4. Učitati okruženje iz zadatka 6.1. Korišćenjem dubokog Q-learning al-
goritma, uz mogućnost eksperimentisanja (prelaska u nasumično stanje) od strane
agenta, u toku od 100 epizoda naučiti optimalnu politiku. Kon gurisati neuronsku
mrežu sa propagacijom unapred na osnovu narednog prikaza
GLAVA 6. UČENJE POTKREPLJIVANJEM 58

_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
dense_1 (Dense) (1, 10) 60
_________________________________________________________________
dense_2 (Dense) (1, 2) 22
=================================================================
Total params: 82
Trainable params: 82
Non-trainable params: 0
_________________________________________________________________

Ulaz u mrežu treba da bude one-hot reprezentacija stanja, a izlaz vrednost Q-


funkcije za svaku od akcija. Aktivacione funkcije koje se koriste su: sigmoidna
na prvom sloju i linearna na drugom sloju. Funkcija koju treba minimizovati je
srednjekvadratna greška, a kao optimizator se može koristiti ADAM. Pri obučavanju
mreže, postaviti broj iteracija na 1 i veličinu paketa na 8.
In [116]:
def build_model(input_shape, output_size, verbose_summary=False):
model = Sequential()
model.add(Dense(units=10, activation='sigmoid', batch_input_shape=input_shape))
model.add(Dense(units=output_size, activation='linear'))

model.compile(loss='mse', optimizer='adam', metrics=['mae'])

if verbose_summary:
model.summary()

return model

Za vrednost koraka učenja uzeti 0.8, a za metaparametar umanjenja uzeti vred-


nost 0.95. Obezbediti da na početku agent eksperimentiše sa verovatnoćom 0.5, a
da se pri svakoj epizodi ova verovatnoća smanjuje faktorom opadanja 0.999.
In [117]:
def deep_q_learning(env, number_of_episodes=100, plot_learning=False):
number_of_states = env.observation_space.n
number_of_actions = env.action_space.n
nn_table = np.zeros((number_of_states, number_of_actions))
gamma = 0.95
eps = 0.5
decay_factor = 0.999

if plot_learning:
# U ovu listu smestamo prosecne vrednosti nagrade
# na nivou jedne epizode
r_avg_list = []

batch_input_shape = (1, number_of_states)


model = build_model(batch_input_shape, number_of_actions, True)

for i in range(number_of_episodes):
s = env.reset()
done = False
eps *= decay_factor
GLAVA 6. UČENJE POTKREPLJIVANJEM 59

if plot_learning:
r_sum = 0

while not done:


# odradimo preslikavanje tekuceg stanja u one-hot vector
s_one_hot = to_categorical(s, num_classes=number_of_states). \
reshape(batch_input_shape)
s_prediction = model.predict(s_one_hot)

if np.random.random() < eps:


a = env.action_space.sample()
else:
# Za ulaz s, predvidja se s_prediction, jer
# to su vrednosti Q funkcije koje odgovaraju stanju s.
# Biramo akciju koja daje najvecu Q vrednost za tekuce stanje s.
a = np.argmax(s_prediction)

s_new, r, done, _ = env.step(a)

s_new_one_hot = to_categorical(s_new, num_classes=number_of_states). \


reshape(batch_input_shape)
s_new_prediction = model.predict(s_new_one_hot)

target = r + gamma*np.max(s_new_prediction)

s_prediction[0][a] = target

model.fit(s_one_hot, s_prediction, epochs=1, batch_size=1, verbose=False)

s = s_new

if plot_learning:
r_sum += r

if plot_learning:
r_avg_list.append(r_sum / 1000)
plt.plot(range(number_of_episodes), r_avg_list)

for i in range(number_of_states):
state = to_categorical(i, num_classes=number_of_states). \
reshape(batch_input_shape)
nn_qi = model.predict(state)
nn_table[i, :] = nn_qi

return nn_table

nn_table = deep_q_learning(env, 100, plot_learning=True)


print(nn_table)

Zadatak 6.5. Učitati okruženje iz zadatka 6.1. Napisati funkciju koja na osno-
vu okruženja i tabele koja predstavlja optimalnu politiku računa ukupnu nagradu
ostvarenu ukoliko se prati tabela tokom prelaska između stanja.
In [118]:
def run_game(env, table):
s = env.reset()
total_reward = 0
GLAVA 6. UČENJE POTKREPLJIVANJEM 60

done = False

while not done:


a = np.argmax(table[s, :])
s_new, r, done, _ = env.step(a)
total_reward += r
s = s_new

return total_reward

Napisati funkciju koja testira funkcije iz zadataka 6.1 — 6.4, tako što pokreće
svaku strategiju number_of_iterations puta, računa ukupne nagrade i izračunava
koja je strategija najviše puta pobedila. Strategiju koja koristi neuronsku mrežu
obučiti samo u prvoj iteraciji i zatim je nadalje koristiti. Koristeći napisanu funkciju,
testirati strategije na 10 epizoda i 40 iteracija. Da li se rezultati opisanog ,,turnira''
menjaju ukoliko se postavi broj epizoda na 100?
In [119]:
def test_methods(env, number_of_episodes=100, number_of_iterations=100):
winners = np.zeros(4)

for i in range(number_of_iterations):
naive_table = naive_sum_reward_table(env, number_of_episodes)
q_table = q_learning(env, number_of_episodes)
eps_q_table = eps_q_learning(env, number_of_episodes)
if i == 0:
nn_table = deep_q_learning(env, number_of_episodes)

naive_result = run_game(env, naive_table)


q_result = run_game(env, q_table)
eps_q_result = run_game(env, eps_q_table)
nn_result = run_game(env, nn_table)

w = np.argmax([naive_result, q_result, eps_q_result, nn_result])

winners[w] += 1

return winners

winners = test_methods(env, 100, 40)


print(winners)

Zadatak 6.6. Jedno od okruženja koje postoji u OpenIA Gym biblioteci je 'Taxi-v2'
okruženje u kojem je cilj maksimizovati nagradu koja se dobija preuzimanjem put-
nika i njihovim prevoženjem na 4 različite lokacije. Za svakog prevezenog putnika
se dobija nagrada od 20 poena, a za svaki korak transfera se gubi 1 poen. Takođe,
postoji penal od 10 poena za svako nepropisno preuzimanje ili ostavljanje putnika.
Korišćenjem Q-learning algoritma naučiti optimalno kretanje taksija. Za vrednost
koraka učenja uzeti 0.8, a za metaparametar umanjenja uzeti vrednost 0.95.
In [120]:
env = gym.make('Taxi-v2')

def q_learning(env, number_of_episodes=500, plot_learning=False, plot_last_n_episodes=200):


q_table = np.zeros((env.observation_space.n, env.action_space.n))
alpha = 0.8
gamma = 0.95
GLAVA 6. UČENJE POTKREPLJIVANJEM 61

if plot_learning:
rewards_progress = {}

for episode in range(number_of_episodes):


s = env.reset()
done = False
i = 0
if plot_learning:
rewards_progress[episode] = [0]

while not done:


if q_table[s, 0] == 0 and q_table[s, 1] == 0:
a = env.action_space.sample()
else:
a = np.argmax(q_table[s, :])

s_new, r, done, _ = env.step(a)

q_table[s, a] += alpha*(r + gamma*np.max(q_table[s_new, :]) - q_table[s, a])

if plot_learning:
rewards_progress[episode].append(rewards_progress[episode][i] + r)

s = s_new
i += 1

if plot_learning:
rewards = []
for i in rewards_progress.keys():
rewards.append(rewards_progress[i][-1])
if plot_last_n_episodes is None:
plt.plot(rewards)
else:
plt.plot(rewards[-plot_last_n_episodes:])

return q_table

q_table = q_learning(env, 1150, True)


print(q_table)

Zadatak 6.7. Jedno od okruženja koje postoji u OpenIA Gym biblioteci je 'CartPole-v0'
okruženje u kojem je cilj maksimizovati nagradu koja se dobija balansiranjem isprav-
nog štapa na kolicima. Kolica se pomeraju duž horizontalne ose. Pri svakoj vre-
menskoj odrednici možemo da dobijemo informaciju o njihovoj poziciji x, brzini x′ ,
nagnutosti štapa theta i ugaonoj brzini theta′ . U svakom stanju, kolica imaju dve
moguće akcije: pomeriti se levo i pomeriti se desno. U ovakvom okruženju, nagra-
da se dobija sve dok je štap donekle uspravan i kolica su u okviru granica. Epizoda
je završena čim se štap nagne ispod određenog ugla ili kolica se pomere izvan gra-
nica. Problem se smatra rešenim kada štap stoji uspravno preko 195 vremenskih
odrednica i to 100 puta zaredom. Korišćenjem Q-learning algoritma naučiti opti-
malno kretanje taksija. Za vrednost koraka učenja uzeti 0.8, a za metaparametar
umanjenja uzeti vrednost 0.95. Obezbediti da na početku agent eksperimentiše sa
verovatnoćom 0.5, a da se pri svakoj epizodi ova verovatnoća smanjuje faktorom
opadanja 0.999.
GLAVA 6. UČENJE POTKREPLJIVANJEM 62

In [121]:
env = gym.make('CartPole-v0')

# Number of discrete states (bucket) per state dimension


NUM_BUCKETS = (1, 1, 6, 3) # (x, x', theta, theta')
# Number of discrete actions
NUM_ACTIONS = env.action_space.n # (left, right)
# Bounds for each discrete state
STATE_BOUNDS = list(zip(env.observation_space.low, env.observation_space.high))
STATE_BOUNDS[1] = [-0.5, 0.5]
STATE_BOUNDS[3] = [-np.radians(50), np.radians(50)]
# Index of the action
ACTION_INDEX = len(NUM_BUCKETS)

## Creating a Q-Table for each state-action pair


q_table = np.zeros(NUM_BUCKETS + (NUM_ACTIONS,))

## Learning related constants


MIN_EXPLORE_RATE = 0.01
MIN_LEARNING_RATE = 0.1

## Defining the simulation related constants


NUM_EPISODES = 1000
MAX_T = 250
STREAK_TO_END = 120
SOLVED_T = 199
DEBUG_MODE = False

def state_to_bucket(state):
bucket_indice = []
for i in range(len(state)):
if state[i] <= STATE_BOUNDS[i][0]:
bucket_index = 0
elif state[i] >= STATE_BOUNDS[i][1]:
bucket_index = NUM_BUCKETS[i] - 1
else:
# Mapping the state bounds to the bucket array
bound_width = STATE_BOUNDS[i][1] - STATE_BOUNDS[i][0]
offset = (NUM_BUCKETS[i]-1)*STATE_BOUNDS[i][0]/bound_width
scaling = (NUM_BUCKETS[i]-1)/bound_width
bucket_index = int(round(scaling*state[i] - offset))
bucket_indice.append(bucket_index)
return tuple(bucket_indice)

def get_learning_rate(t):
return max(MIN_LEARNING_RATE, min(0.5, 1.0 - np.log10((t+1)/25)))

def get_explore_rate(t):
return max(MIN_EXPLORE_RATE, min(1, 1.0 - np.log10((t+1)/25)))

def select_action(state, explore_rate):


# Select a random action
if np.random.rand() < explore_rate:
action = env.action_space.sample()
# Select the action with the highest q
else:
action = np.argmax(q_table[state])
GLAVA 6. UČENJE POTKREPLJIVANJEM 63

return action

def simulate():
rewards_progress = {}
## Instantiating the learning related parameters
learning_rate = get_learning_rate(0)
explore_rate = get_explore_rate(0)
discount_factor = 0.99 # since the world is unchanging

num_streaks = 0

for episode in range(NUM_EPISODES):


rewards_progress[episode] = [0]
# Reset the environment
obv = env.reset()

# the initial state


state_0 = state_to_bucket(obv)

for t in range(MAX_T):
#env.render()

# Select an action
action = select_action(state_0, explore_rate)

# Execute the action


obv, reward, done, _ = env.step(action)

# Observe the result


state = state_to_bucket(obv)

# Update the Q based on the result


best_q = np.max(q_table[state])
q_table[state_0 + (action,)] += \
learning_rate*(reward + discount_factor*(best_q) - q_table[state_0 + (action,)])

rewards_progress[episode].append(rewards_progress[episode][t] + reward)

# Setting up for the next iteration


state_0 = state

if done:
print("Episode %d finished after %f time steps" % (episode, t))
if (t >= SOLVED_T):
num_streaks += 1
else:
num_streaks = 0
break

# It's considered done when it's solved over 120 times consecutively
if num_streaks > STREAK_TO_END:
break

# Update parameters
explore_rate = get_explore_rate(episode)
learning_rate = get_learning_rate(episode)
GLAVA 6. UČENJE POTKREPLJIVANJEM 64

rewards = []
for i in rewards_progress.keys():
rewards.append(rewards_progress[i][-1])
plt.plot(rewards)

simulate()
Literatura

[1] M. Nikolić and A. Zečević, Mašinsko učenje (skripta). Matematički fakultet,


2018.

65

You might also like