Classifying MNIST Dataset – Coding

Pada lesson classifying MNIST Dataset Coding kita akan membuat model untuk mengolah data MNIST. Disini kita akan praktekan teori-teori yang sudah dibahas sebelumnya mulai dari tahapan membuat model, penggunaan objek TensorFlow, early stopping dan lainnya.

Berikut code untuk training model (disarankan menggunakan jupyter notebook, karena lebih interactive saat melakukan programming). SIlakan download file jupyter notebook disini.

#import library
import numpy as np
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data

mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)

#model 
input_size = 784
output_size = 10
hidden_layer_size = 50

tf.reset_default_graph()

inputs = tf.placeholder(tf.float32, [None, input_size])
targets = tf.placeholder(tf.float32, [None, output_size])

weights_1 = tf.get_variable("weights_1", [input_size, hidden_layer_size])
biases_1 = tf.get_variable("biases_1", [hidden_layer_size])

outputs_1 = tf.nn.relu(tf.matmul(inputs, weights_1) + biases_1)

weights_2 = tf.get_variable("weights_2", [hidden_layer_size, hidden_layer_size])
biases_2 = tf.get_variable("biases_2", [hidden_layer_size])

outputs_2 = tf.nn.relu(tf.matmul(outputs_1, weights_2) + biases_2)

weights_3 = tf.get_variable("weights_3", [hidden_layer_size, output_size])
biases_3 = tf.get_variable("biases_3", [output_size])

outputs = tf.matmul(outputs_2, weights_3) + biases_3

loss = tf.nn.softmax_cross_entropy_with_logits(logits=outputs, labels=targets)

mean_loss = tf.reduce_mean(loss)

optimize = tf.train.AdamOptimizer(learning_rate=0.001).minimize(mean_loss)

out_equals_target = tf.equal(tf.argmax(outputs, 1), tf.argmax(targets, 1))

accuracy = tf.reduce_mean(tf.cast(out_equals_target, tf.float32))

sess = tf.InteractiveSession()

initializer = tf.global_variables_initializer()
sess.run(initializer)

batch_size = 100

batches_number = mnist.train._num_examples // batch_size

max_epochs = 15

prev_validation_loss = 9999999.

import time
start_time = time.time()

for epoch_counter in range(max_epochs):
    curr_epoch_loss = 0.
    
    for batch_counter in range(batches_number):
        input_batch, target_batch = mnist.train.next_batch(batch_size)
        
        _, batch_loss = sess.run([optimize, mean_loss], 
            feed_dict={inputs: input_batch, targets: target_batch})
        
        curr_epoch_loss += batch_loss
    
    curr_epoch_loss /= batches_number
    
    input_batch, target_batch = mnist.validation.next_batch(mnist.validation._num_examples)
    
    validation_loss, validation_accuracy = sess.run([mean_loss, accuracy], 
        feed_dict={inputs: input_batch, targets: target_batch})
    
    print('Epoch '+str(epoch_counter+1)+
          '. Mean loss: '+'{0:.3f}'.format(curr_epoch_loss)+
          '. Validation loss: '+'{0:.3f}'.format(validation_loss)+
          '. Validation accuracy: '+'{0:.2f}'.format(validation_accuracy * 100.)+'%')
    
    if validation_loss > prev_validation_loss:
        break
        
    prev_validation_loss = validation_loss

print('End of training.')

Hasil program diatas akan ditampilkan di console kurang lebih seperti dibawah. Setiap program diatas dijalankan hasilnya akan berbeda.

Epoch 1. Mean loss: 0.419. Validation loss: 0.184. Validation accuracy: 94.80%
Epoch 2. Mean loss: 0.174. Validation loss: 0.136. Validation accuracy: 96.04%
Epoch 3. Mean loss: 0.132. Validation loss: 0.115. Validation accuracy: 96.44%
Epoch 4. Mean loss: 0.107. Validation loss: 0.107. Validation accuracy: 96.80%
Epoch 5. Mean loss: 0.088. Validation loss: 0.094. Validation accuracy: 97.28%
Epoch 6. Mean loss: 0.076. Validation loss: 0.095. Validation accuracy: 97.26%
End of training.

Selain code untuk training model, kita juga memerlukan code untuk tesing. Hasil dari test, akurasi model 97.1 %, Cukup tinggi nilai akurasinya.

#testing model
input_batch, target_batch = mnist.test.next_batch(mnist.test._num_examples)
test_accuracy = sess.run([accuracy], 
    feed_dict={inputs: input_batch, targets: target_batch})

test_accuracy_percent = test_accuracy[0] * 100.

print('Test accuracy: '+'{0:.2f}'.format(test_accuracy_percent)+'%')
Test accuracy: 97.10%

Pembahasan Code

Load library yang diperlukan yaitu numpy dan TensorFlow. Sedangkan data akan didownload dari internet menggunakan perintah input_data.read_data_sets.

File akan didownload ke path dimana file python atau jupyter notebook aktif dan disimpan ke folder MNIST_data (anda bisa mengganti nama foldernya).

Dataset sudah dibagi menjadi data untuk training, validation, and test subsets.

import numpy as np
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data

mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)

Tentukan ukuran input dan output. Seperti yang sudah dibahas pada lesson sebelumnya, input adalah matrix 784 x 1, dan output adalah matrix 10 x 1.

Ukuran hidden layer yang digunakan adalah 50. Karena ini hyperparameter, silakan bereksperimen.

input_size = 784
output_size = 10
hidden_layer_size = 50

Karena dalam modeling, program akan dijalankan berulang kali. Suatu kebiasaan baik , sebelum memulai, kita reset memory dari proses sebelumnya.

tf.reset_default_graph()

Deklarasi objek placeholder untuk menyimpan data input dan target. Perhatikan, ukuran target sama dengan ukuran output.

inputs = tf.placeholder(tf.float32, [None, input_size])
targets = tf.placeholder(tf.float32, [None, output_size])

Deklarasi weights dan biases untuk fungsi linear yang berada diantara inputs dan hidden layer yang pertama. Fungsi get_variable adalah initializer dengan default initializer Xavier. (lihat lesson sebelumnya tentang initializer).

 weights_1 = tf.get_variable("weights_1", [input_size, hidden_layer_size])
 biases_1 = tf.get_variable("biases_1", [hidden_layer_size])

Operasi antara inputs dan hidden layer pertama akan menggunakan ReLu sebagai activation function. Anda dapat gunakan activation function lainnya, silakan bereksperimen.

outputs_1 = tf.nn.relu(tf.matmul(inputs, weights_1) + biases_1)

Weights dan biases pada kombinasi linear kedua (terletak antara hidden layer pertama dan kedua)

weights_2 = tf.get_variable("weights_2", [hidden_layer_size, hidden_layer_size])
biases_2 = tf.get_variable("biases_2", [hidden_layer_size])

Operasi antara hidden layer pertama dan kedua. Kembali digunakan ReLu activation function.

outputs_2 = tf.nn.relu(tf.matmul(outputs_1, weights_2) + biases_2)

Weights dan biases untuk linear combination terakhir, terletak antara hiden layer kedua dengan output layer.

weights_3 = tf.get_variable("weights_3", [hidden_layer_size, output_size])
biases_3 = tf.get_variable("biases_3", [output_size])

Operasi antara hidden layer kedua dan final output. Disini tidak digunakan activation function. Activation function akan kita tambahkan di loss function. Hal ini bisa dilakukan untuk softmax dan sigmoid dengan cross entropy.

outputs = tf.matmul(outputs_2, weights_3) + biases_3

Deklarasi loss function untuk setiap output/target. Kita sengaja menggunakan fungsi yang menggabungkan softmax dan loss function karena akan mempercepat proses perhitungan dan lebih stabil. Hasilnya akan sama jika kita menambahkan softmaxt pada last layer, lalu kemudian menghitung cross entropy secara terpisah.

loss = tf.nn.softmax_cross_entropy_with_logits(logits=outputs, labels=targets)

Deklarasi optimisasi dengan menggunakan ADAM. Sangat mudah karena kita menggunakan library TensorFlow.

mean_loss = tf.reduce_mean(loss)

optimize = tf.train.AdamOptimizer(learning_rate=0.001).minimize(mean_loss)

Deklarasi fungsi untuk menghitung akurasi. tf.argmax akan mengambil nilai tertinggi dan mengembalikan nilai index axis (argument 1 menunjukan index axis yang akan direturn).

tf.equal akan membandingkan index nilai tertinggi dari vector outputs dan targets. Jika sama mengembalikan nilai 1, jika tidak sama mengembalikan nilai 0.

out_equals_target = tf.equal(tf.argmax(outputs, 1), tf.argmax(targets, 1))

accuracy = tf.reduce_mean(tf.cast(out_equals_target, tf.float32))

Sampai tahap diatas, kita sudah membentuk model. Saatnya kita mempersiapkan model untuk dilatih. Deklarasikan TensorFLow Session, lalu jalankan inisialisasi variable.

sess = tf.InteractiveSession()

initializer = tf.global_variables_initializer()
sess.run(initializer)

Kita akan lakukan batching, untuk itu kita tentukan ukuran batch, disini kita gunakan 100. Setelah itu hitung jumlah batches per epoch dari mnist training set. Perhatikan, jangan salah gunakan data.

batch_size = 100
batches_number = mnist.train._num_examples // batch_size

Kita akan gunakan basic early stopping dengan menentukan jumlah epoch maksimum

max_epochs = 15

Inisialisasi variable prev_validation_loss, pada inisialisasi awal gunakan angka random yang besar. Variable ini akan menyimpan nilai validation loss dari epoch sebelumnya. Digunakan untuk men-trigger early stopping ketika nilai validation loss naik.

prev_validation_loss = 9999999.

Block for Loop untuk proses training model. nilai variable epoch_counter akan otomatis mulai dari 0. Proses utama secara garis besar adalah:

  • Assign file batch berdasarkan ukuran batch.
  • Lakukan optimization dan hitung mean_loss dari batch.
  • Pada akhir epoch, lakukan validation loss dan cek akurasi.
  • Lakukan early stopping jika nilai validation loss naik.
  • Serta perintah print ke console agar kita bisa melihat proses yang sedang terjadi.

Silakan lihat baris komentar untuk lebih detail maksud dari tiap baris code.

# block for untuk epochs. Epoch_counter akan mulai dari nol
for epoch_counter in range(max_epochs):
    
    # deklarasi variable untuk simpan nilai total batch losses epoch saat ini.
    curr_epoch_loss = 0.
    
    # iterasi batch pada epoch saat ini.
    for batch_counter in range(batches_number):
        
        # isi Input batch and target batch dari train dataset berdasarkan ukuran batch
        input_batch, target_batch = mnist.train.next_batch(batch_size)
        
        # Jalankan optimization dan ambil nila mean loss pada batch saat ini.
        # data set yang digunakan adalah input_batch dan target_batch dari baris diatas.
        _, batch_loss = sess.run([optimize, mean_loss], 
            feed_dict={inputs: input_batch, targets: target_batch})
        
        # jumlahkan batch losses.
        curr_epoch_loss += batch_loss
    
    # curr_epoch_loss akan berisi jumlah dari selurub batches dalam epoch
    # hitung average batch losses terhadap seluruh epoch
    # average batch loss akan menggambarkan untuk epoch loss saat ini
    curr_epoch_loss /= batches_number
    
    # pada akhir setiap epoch, ambil nilai validation loss dan accuracy
    # gunakan data validation dataset
    input_batch, target_batch = mnist.validation.next_batch(mnist.validation._num_examples)
    
    # Jalankan tanpa optimzation (proses validasi tidak melakukan optimisasi)
    validation_loss, validation_accuracy = sess.run([mean_loss, accuracy], 
        feed_dict={inputs: input_batch, targets: target_batch})
    
    # Tampilkan proses training ke console
    print('Epoch '+str(epoch_counter+1)+
          '. Mean loss: '+'{0:.3f}'.format(curr_epoch_loss)+
          '. Validation loss: '+'{0:.3f}'.format(validation_loss)+
          '. Validation accuracy: '+'{0:.2f}'.format(validation_accuracy * 100.)+'%')
    
    # Trigger early stopping jika nilai validation loss naik.
    if validation_loss > prev_validation_loss:
        break
        
    # simpan validation loss pada epoch saat ini untuk digunakan pada iterasi berikutnya
    prev_validation_loss = validation_loss

# tampilkan ke console bila proses sudah selesai.
print('End of training.')
Sharing is caring: