Preporučujem da pogledate sledeće snimke:
https://www.youtube.com/watch?v=aircAruvnKk (prvi deo)
https://www.youtube.com/watch?v=IHZwWFHWa-w (drugi deo)
https://www.youtube.com/watch?v=Ilg3gGewQ5U (treći deo)
https://www.youtube.com/watch?v=tIeHLnjs5U8 (četvrti deo)
Delovi materijala su preuzeti iz skripte "Mašinsko učenje" profesora Mladena Nikolića
import numpy as np
from matplotlib import pyplot as plt
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras.datasets import mnist
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Input, Dense
np.random.seed(10)
MNIST je skup podataka koji sadrži slike rukom pisanih cifara. Slika ima ukupno 70000 od čega se obično 60000 slika koristi za treniranje, a preostalih 10000 za testiranje. Sve slike u skupu podataka su dimenzije 28px x 28px i u crno-belom su modu. Da bismo učitali MNIST skup podataka iskoristićemo podršku Keras biblioteke preko mnist.load_data() funkcije.
(X_train, y_train), (X_test, y_test) = mnist.load_data()
Prva instanca učitanog skupa izgleda ovako
plt.imshow(X_train[0], cmap='gray')
plt.show()
Da bismo slike prosledili kao ulaze mreže, transformisaćemo ih u vektore dužine 28x28=784.
image_size = X_train.shape[1]
X_train = X_train.reshape(X_train.shape[0], image_size*image_size)
X_test = X_test.reshape(X_test.shape[0], image_size*image_size)
Slike ćemo pripremiti tako što ćemo ih normalizovati, tj. svesti vrednosti pojedinačnih piksela na vrednost iz intervala iz [0, 1]. Prethodno ćemo promeniti tip elemenata matrice sa uint8 na float32 kako bi mogli da sačuvamo realne vrednosti.
X_train = X_train.astype('float32')
X_train /= 255
X_test = X_test.astype('float32')
X_test /= 255
Kao što smo videli, vrednosti ciljne promenljive su brojevi od 0 od 9. Uvid u brojnost instanci po klasama možemo dobiti na osnovu sledećeg grafika.
classes = np.unique(y_train)
plt.xlabel('Klasa')
plt.ylabel('Broj instanci')
plt.title ('MNIST skup za treniranje')
plt.xticks(classes)
plt.bar(classes, np.bincount(y_train))
plt.show()
Vrednosti ciljne promenljive ćemo pripremiti tako što ćemo ih transformisati u vektore dužine 10 sa jedinicom na poziciji koja odgovara vrednosti cifre (takozvano one-hot kodiranje). Na primer, broj 3 će biti transformisan u vektor [0, 0, 0, 1, 0, 0, 0, 0, 0, 0] sa jedinicom na poziciji tri.
number_of_classes = classes.shape[0]
y_train = keras.utils.to_categorical(y_train, number_of_classes)
y_test = keras.utils.to_categorical(y_test, number_of_classes)
Ulaz u mrežu je slika dimenzije 784 piksela.
Napravićemo mrežu koja ima dva skrivena sloja, jedan dimenzije 128 neurona i drugi dimenzije 64 neurona. Oba sloja kao aktivaciju koristiće relu funkciju.
Izlazni sloj mreže ima 10 neurona. Svaki od njih odgovara jednoj od cifara od 0 do 9. Ideja je da vrednosti izlaza predstavljaju verovatnoće pripadanja odgovarajućoj klasi cifara i dodeljujemo onu cifru za koju je verovatnoća najveća. Zato ćemo u poslednjem sloju mreže kao aktivacionu funkciju iskoristiti funkciju mekog maksimuma (engl. softmax).
model = Sequential([
Input(shape=(image_size*image_size, )),
Dense(units=128, activation='relu'),
Dense(units=64, activation='relu'),
Dense(units=number_of_classes, activation='softmax')
])
Model možemo kontrolno prikazati pozivom metode summary.
model.summary()
Model: "sequential_2"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
dense_6 (Dense) (None, 128) 100480
dense_7 (Dense) (None, 64) 8256
dense_8 (Dense) (None, 10) 650
=================================================================
Total params: 109,386
Trainable params: 109,386
Non-trainable params: 0
_________________________________________________________________
Za optimizaciju ćemo koristiti Adamov gradijentni spust.
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
Mrežu ćemo trenirati u 30 epoha korišćenjem paketića veličine 128 instanci.
batch_size = 128
epochs = 30
history = model.fit(X_train, y_train, batch_size=batch_size, epochs=epochs, verbose=0)
Možemo nacrtati i grafike funkcije gubitka i tačnosti u toku treniranja.
plt.figure(figsize=(10, 4))
plt.subplot(1, 2, 1)
plt.title('Funkcija gubitka')
plt.plot(np.arange(0, epochs), history.history['loss'], label='train')
plt.subplot(1, 2, 2)
plt.title('Tacnost')
plt.plot(np.arange(0, epochs), history.history['accuracy'])
plt.show()
Model ćemo oceniti na skupu za testiranje.
score = model.evaluate(X_test, y_test)
print('Test loss:', score[0])
print('Test accuracy:', score[1])
313/313 [==============================] - 0s 401us/step - loss: 0.1272 - accuracy: 0.9770 Test loss: 0.12718001008033752 Test accuracy: 0.9769999980926514
Dobili smo da je preciznost na test skupu 98%.