In [1]:
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
import seaborn
In [2]:
from sklearn.datasets import fetch_mldata
mnist = fetch_mldata('MNIST original')
# przeksztalcamy dane tak by reprezentowaly obrazki
data = mnist.data.reshape(-1, 28, 28, 1)
target = mnist.target.astype(np.int32)
# zmieniamy target na kodowanie one_hot
target = np.eye(10)[target]
# tasujemy dane (ustawiamy seed na konkretna wartosc,
# zeby pozniej porownac rezultaty)
np.random.seed(1337)
shuffle = np.random.permutation(len(data))
data = data[shuffle]
target = target[shuffle]
# ostatnie 10k przykladow traktujemy jako zbior
# do walidacji wynikow
valid_data = data[-10000:]
valid_target = target[-10000:]
data = data[:-10000]
target = target[:-10000]
In [3]:
graph = tf.Graph()
with graph.as_default():
# zmieniamy ksztalt wejscia na [height, width, channels] - channels to na przyklad RGB
# w tym przypadku obrazek jest czarno-bialy wiec mamy tylko jeden kanal
x = tf.placeholder(tf.float32, shape=[None, 28, 28, 1])
y = tf.placeholder(tf.float32, shape=[None, 10])
# tworzymy filtry warstwy konwolucyjnej
# shape=[width, height, in_channels, out_channels]
conv1w = tf.Variable(tf.truncated_normal(shape=[3, 3, 1, 16], stddev=0.01))
conv1b = tf.Variable(tf.ones(shape=[16]))
conv2w = tf.Variable(tf.truncated_normal(shape=[3, 3, 16, 16], stddev=0.01))
conv2b = tf.Variable(tf.ones(shape=[16]))
conv3w = tf.Variable(tf.truncated_normal(shape=[3, 3, 16, 16], stddev=0.01))
conv3b = tf.Variable(tf.ones(shape=[16]))
# aplikujemy konwolucje
# strides=[batch, width, height, depth] - mowi jaki robimy krok przy aplikowaniu filtra
h = tf.nn.conv2d(x, conv1w, [1, 2, 2, 1], padding='SAME') + conv1b
h = tf.nn.relu(h)
h = tf.nn.conv2d(h, conv2w, [1, 2, 2, 1], padding='SAME') + conv2b
h = tf.nn.relu(h)
h = tf.nn.conv2d(h, conv3w, [1, 2, 2, 1], padding='SAME') + conv3b
h = tf.nn.relu(h)
# poniewaz po zastosowaniu konwolucji dalej mamy obraz
# musimy, podobnie jak poprzednio splaszczyc go do jednego wielkiego wektora
# tutaj pobieramy wymiary finalnego obrazka po konwolucjach [batch, width, height, channel]
conv_output_shape = h.get_shape().as_list()[1:]
# conv_vec_len = width * height * channel
conv_vec_len = np.prod(conv_output_shape)
h = tf.reshape(h, shape=[-1, conv_vec_len])
# teraz mozemy tak jak poprzednio zastosowac warstwy "fully connected"
# wagi pierwszej warstwy
w1 = tf.Variable(tf.truncated_normal(shape=[conv_vec_len, 128], stddev=0.01))
b1 = tf.Variable(tf.zeros(shape=[128]))
# wagi drugiej warstwy
w2 = tf.Variable(tf.truncated_normal(shape=[128, 10], stddev=0.01))
b2 = tf.Variable(tf.zeros(shape=[10]))
# pierwsza warstwa
h = tf.matmul(h, w1) + b1
h = tf.nn.relu(h)
# druga warstwa
h = tf.matmul(h, w2) + b2
y_ = tf.nn.softmax(h)
# funkcja straty (zmieniamy z MSE na CrossEntropy)
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=h, labels=y))
# tworzymy optimalizator i ustawiamy learning rate
optimizer = tf.train.AdamOptimizer(learning_rate=0.0001)
# tworzymy operacje trenowania (minimalizowanie straty)
train_step = optimizer.minimize(loss)
# dodatkowo liczenie dokladnosci
accuracy = tf.reduce_mean(tf.cast(tf.equal(tf.argmax(y_, axis=1),
tf.argmax(y, axis=1)),
tf.float32))
In [4]:
epochs = 5
batch_size = 32
# tworzymy sesje dla utworzonego wczesniej grafu
with tf.Session(graph=graph) as sess:
# inicjalizujemy zmienne
sess.run(tf.global_variables_initializer())
losses = []
acc = []
for e in range(epochs):
print('\nEpoch {}'.format(e))
for b in range(0, len(data), batch_size):
# pobieramy kolejna partie danych treningowych
be = min(len(data), b + batch_size)
x_batch = data[b: be]
y_batch = target[b: be]
# uruchamiamy obliczenia dla [loss, accuracy, train_step]
l, a, _ = sess.run([loss, accuracy, train_step],
feed_dict={x: x_batch, y: y_batch})
losses += [l]
acc += [a]
print('\r[{:5d}/{:5d}] loss = {}'.format(be, len(data), l), end='')
# policzymy teraz dokladnosc dla validation set
validation_accuracy = 0
for b in range(0, len(valid_data), batch_size):
be = min(len(valid_data), b + batch_size)
a = sess.run(accuracy, feed_dict={x: valid_data[b: be], y: valid_target[b: be]})
validation_accuracy += a * (be - b)
validation_accuracy /= len(valid_data)
plt.plot(losses)
plt.plot(acc)
plt.show()
print('Validation accuracy: {}'.format(validation_accuracy))
In [ ]: