Lewati ke konten utama

Tutorial Autoencoder sebagai Klasifikator menggunakan Dataset Fashion-MNIST

Dalam tutorial ini, Anda akan mempelajari dan memahami cara menggunakan autoencoder sebagai pengklasifikasi di Python dengan Keras. Anda akan menggunakan dataset Fashion-MNIST sebagai contoh.
Diperbarui 28 Sep 2026  · 15 mnt Baca

Jelajahi bersama AI

ChatGPTClaudePerplexity

Catatan: Tutorial ini terutama akan membahas implementasi praktis klasifikasi menggunakan convolutional neural network dan convolutional autoencoder. Jadi, jika Anda belum familiar dengan convolutional neural network (CNN) dan autoencoder, Anda mungkin ingin melihat tutorial CNN dan Autoencoder.

Secara lebih spesifik, Anda akan membahas topik-topik berikut dalam tutorial hari ini:

  • Di awal, Anda akan mendapatkan ringkasan tentang Data Fashion-MNIST. Anda akan menggunakan berbagai pustaka Python untuk memuat, menjelajahi dan menganalisis data,
  • Setelah itu, Anda akan mempraolah data: Anda akan belajar cara mengubah ukuran, penskalaan ulang data, memverifikasi tipe data gambar, dan membagi data menjadi set pelatihan dan validasi.
  • Setelah semua selesai, Anda dapat membangun model convolutional autoencoder: Anda akan belajar cara memodelkan data dan membentuk jaringan. Selanjutnya, Anda akan melakukan kompilasi, melatih model, memvisualisasikan plot akurasi dan loss, dan akhirnya menyimpan model.
  • Berikutnya, Anda akan menyegmentasi data fashion-mnist: pertama Anda akan mengonversi label menjadi vektor one-hot encoding, membagi gambar pelatihan dan validasi beserta labelnya masing-masing. Lalu Anda akan mendefinisikan fungsi encoder yang sama seperti pada arsitektur autoencoder, diikuti dengan lapisan fully connected.
  • Anda akan belajar cara memuat bobot dari model terlatih ke beberapa lapisan model baru, memverifikasi matriks bobot model terlatih dan model baru, menjadikan beberapa lapisan model baru tidak dapat dilatih, dan akhirnya mengompilasi model klasifikasi baru, melatih model, serta menyimpan bobotnya.
  • Anda akan melatih ulang model dengan semua lapisan dapat dilatih, mengevaluasi model, memvisualisasikan plot akurasi dan loss, membuat prediksi pada data uji, mengonversi probabilitas menjadi label kelas dan memplot beberapa sampel uji yang diklasifikasikan dengan benar maupun salah oleh model Anda.
  • Terakhir, Anda akan memvisualisasikan laporan klasifikasi yang akan memberi Anda intuisi lebih mendalam tentang kelas mana yang (tidak) diklasifikasikan dengan benar oleh model Anda.

Kumpulan Data Fashion-MNIST

Sebelum mulai memuat dataset dan memprosesnya, ada baiknya memiliki gambaran singkat tentang seperti apa jenis datasetnya, bagaimana dimensinya, dan berapa banyak kelas berbeda yang ada dalam dataset.

Dataset Fashion-MNIST berisi gambar grayscale 28x28 dari 70.000 produk fesyen dari 10 kategori, dengan 7.000 gambar per kategori. Set pelatihan memiliki 60.000 gambar, dan set pengujian memiliki 10.000 gambar. Fashion-MNIST merupakan pengganti dataset MNIST asli untuk menghasilkan hasil yang lebih baik; dimensi gambar serta pembagian pelatihan dan uji serupa dengan dataset MNIST asli. Dataset ini tersedia gratis di URL ini dan dapat dimuat menggunakan tensorflow maupun keras sebagai kerangka kerja tanpa harus mengunduhnya ke komputer Anda.

Mirip dengan MNIST, Fashion-MNIST juga terdiri dari 10 kelas, tetapi alih-alih digit tulisan tangan, kita memiliki 10 kelas aksesori fesyen yang berbeda seperti sandal, kemeja, celana, dan sebagainya.

Tugas Anda adalah melatih convolutional autoencoder dan menggunakan bagian encoder dari autoencoder yang digabungkan dengan lapisan fully connected untuk mengenali sampel baru dari set uji secara benar.

Tip: jika Anda ingin belajar cara mengimplementasikan Multi-Layer Perceptron (MLP) untuk tugas klasifikasi dengan dataset MNIST, lihat tutorial ini.

Pada kode di bawah, Anda pada dasarnya menetapkan variabel lingkungan di notebook menggunakan os.environ. Sebaiknya lakukan hal berikut sebelum menginisialisasi Keras untuk membatasi backend TensorFlow Keras agar menggunakan GPU pertama. Jika mesin tempat Anda melatih memiliki GPU di 0, pastikan menggunakan 0 alih-alih 1. Anda bisa memeriksanya dengan menjalankan perintah sederhana di terminal: misalnya, nvidia-smi

import os
os.environ["CUDA_DEVICE_ORDER"]="PCI_BUS_ID"
os.environ["CUDA_VISIBLE_DEVICES"]="0" #model will be trained on GPU 0

Memuat Data

Selanjutnya, Anda mengimpor semua modul yang diperlukan seperti numpy, matplotlib, dan yang terpenting Keras, karena dalam tutorial hari ini Anda akan menggunakan keras sebagai kerangka kerja!

import keras
from matplotlib import pyplot as plt
import numpy as np
import gzip
%matplotlib inline
from keras.models import Model
from keras.optimizers import RMSprop
from keras.layers import Input,Dense,Flatten,Dropout,merge,Reshape,Conv2D,MaxPooling2D,UpSampling2D,Conv2DTranspose
from keras.layers.normalization import BatchNormalization
from keras.models import Model,Sequential
from keras.callbacks import ModelCheckpoint
from keras.optimizers import Adadelta, RMSprop,SGD,Adam
from keras import regularizers
from keras import backend as K
from keras.utils import to_categorical
Using TensorFlow backend.
/usr/local/lib/python2.7/dist-packages/h5py/__init__.py:34: FutureWarning: Conversion of the second argument of issubdtype from `float` to `np.floating` is deprecated. In future, it will be treated as `np.float64 == np.dtype(float).type`.
  from ._conv import register_converters as _register_converters

Di sini, Anda mendefinisikan fungsi yang membuka file gzip, membaca file menggunakan bytestream.read(). Anda meneruskan dimensi gambar dan jumlah total gambar ke fungsi ini. Lalu, menggunakan np.frombuffer(), Anda mengonversi string yang disimpan dalam variabel buf menjadi array NumPy bertipe float32.

Setelah dikonversi menjadi array NumPy, Anda membentuk ulang array menjadi array tiga dimensi atau tensor di mana dimensi pertama adalah jumlah gambar, dan dimensi kedua dan ketiga adalah dimensi gambar. Terakhir, Anda mengembalikan array NumPy data.

def extract_data(filename, num_images):
    with gzip.open(filename) as bytestream:
        bytestream.read(16)
        buf = bytestream.read(28 * 28 * num_images)
        data = np.frombuffer(buf, dtype=np.uint8).astype(np.float32)
        data = data.reshape(num_images, 28,28)
        return data

Sekarang Anda akan memanggil fungsi extract_data() dengan meneruskan file pelatihan dan pengujian beserta jumlah gambar masing-masing.

train_data = extract_data('train-images-idx3-ubyte.gz', 60000)
test_data = extract_data('t10k-images-idx3-ubyte.gz', 10000)

Demikian pula, Anda mendefinisikan fungsi ekstraksi label yang membuka file gzip, membaca file menggunakan bytestream.read(), yang Anda beri dimensi label (1) dan jumlah total gambar. Lalu, menggunakan np.frombuffer(), Anda mengonversi string yang disimpan dalam variabel buf menjadi array NumPy bertipe int64.

Kali ini, Anda tidak perlu membentuk ulang array karena variabel labels akan mengembalikan vektor kolom berdimensi 60.000 x 1. Terakhir, Anda mengembalikan array NumPy labels.

def extract_labels(filename, num_images):
    with gzip.open(filename) as bytestream:
        bytestream.read(8)
        buf = bytestream.read(1 * num_images)
        labels = np.frombuffer(buf, dtype=np.uint8).astype(np.int64)
        return labels

Sekarang Anda akan memanggil fungsi ekstrak label dengan meneruskan file label pelatihan dan pengujian beserta jumlah gambar masing-masing.

train_labels = extract_labels('train-labels-idx1-ubyte.gz',60000)
test_labels = extract_labels('t10k-labels-idx1-ubyte.gz',10000)

Setelah Anda memuat data pelatihan dan pengujian, Anda siap untuk menganalisis data guna mendapatkan intuisi tentang dataset yang akan Anda gunakan dalam tutorial hari ini!

Eksplorasi Data

Sekarang mari kita analisis seperti apa tampilan gambar dalam dataset dan lihat juga dimensi gambarnya dengan bantuan atribut array NumPy .shape:

# Shapes of training set
print("Training set (images) shape: {shape}".format(shape=train_data.shape))

# Shapes of test set
print("Test set (images) shape: {shape}".format(shape=test_data.shape))
Training set (images) shape: (60000, 28, 28)
Test set (images) shape: (10000, 28, 28)

Dari output di atas, Anda dapat melihat bahwa data pelatihan memiliki bentuk 60000 x 28 x 28 karena ada 60.000 sampel pelatihan masing-masing berupa matriks berdimensi 28 x 28. Demikian pula, data uji memiliki bentuk 10000 x 28 x 28 karena ada 10.000 sampel uji.

Catatan bahwa dalam tugas rekonstruksi menggunakan convolutional autoencoder Anda tidak memerlukan label pelatihan dan pengujian. Gambar pelatihan Anda akan berperan sebagai masukan sekaligus ground truth mirip dengan label yang Anda miliki pada tugas klasifikasi.

Namun untuk tugas klasifikasi Anda juga akan membutuhkan label beserta gambar, yang akan Anda lakukan nanti dalam tutorial. Meskipun tugas saat ini hanya berurusan dengan gambar pelatihan dan pengujian, untuk tujuan eksplorasi yang mungkin memberi Anda intuisi lebih baik tentang data, Anda akan memanfaatkan label.

Mari buat kamus yang berisi nama kelas dengan label kelas kategorikal yang sesuai:

# Create dictionary of target classes
label_dict = {
 0: 'A',
 1: 'B',
 2: 'C',
 3: 'D',
 4: 'E',
 5: 'F',
 6: 'G',
 7: 'H',
 8: 'I',
 9: 'J',
}

Sekarang, mari lihat beberapa gambar dalam dataset Anda:

plt.figure(figsize=[5,5])

# Display the first image in training data
plt.subplot(121)
curr_img = np.reshape(train_data[10], (28,28))
curr_lbl = train_labels[10]
plt.imshow(curr_img, cmap='gray')
plt.title("(Label: " + str(label_dict[curr_lbl]) + ")")

# Display the first image in testing data
plt.subplot(122)
curr_img = np.reshape(test_data[10], (28,28))
curr_lbl = test_labels[10]
plt.imshow(curr_img, cmap='gray')
plt.title("(Label: " + str(label_dict[curr_lbl]) + ")")
Text(0.5,1,'(Label: E)')
sample images

Keluaran dari dua plot di atas adalah salah satu gambar sampel dari data pelatihan dan pengujian, dan gambar-gambar ini diberi label kelas 0 atau A di satu sisi, dan 4 atau E di sisi lain. Demikian pula, alfabet lain akan memiliki label berbeda, tetapi alfabet yang sama akan memiliki label yang sama. Ini berarti semua 6.000 gambar kelas E akan memiliki label kelas 4.

Prapemrosesan Data

Gambar dalam dataset memang merupakan gambar grayscale dengan nilai piksel antara 0 hingga 255 dengan dimensi 28 x 28, jadi sebelum kita memasukkan data ke dalam model, sangat penting untuk memprosesnya terlebih dahulu. Anda akan terlebih dahulu mengonversi setiap gambar 28 x 28 dari set train dan test menjadi matriks berukuran 28 x 28 x 1, yang dapat Anda masukkan ke dalam jaringan:

train_data = train_data.reshape(-1, 28,28, 1)
test_data = test_data.reshape(-1, 28,28, 1)
train_data.shape, test_data.shape
((60000, 28, 28, 1), (10000, 28, 28, 1))

Selanjutnya, pastikan untuk memeriksa tipe data array NumPy pelatihan dan pengujian, seharusnya dalam format float32; jika tidak, Anda perlu mengonversinya ke format ini, tetapi karena Anda sudah mengonversinya saat membaca data, Anda tidak perlu melakukannya lagi. Anda juga harus melakukan penskalaan ulang nilai piksel ke rentang 0 - 1 inklusif. Mari kita lakukan!

Jangan lupa untuk memverifikasi tipe data pelatihan dan pengujian:

train_data.dtype, test_data.dtype
(dtype('float32'), dtype('float32'))

Selanjutnya, skala ulang data pelatihan dan pengujian dengan nilai piksel maksimum dari data pelatihan dan pengujian:

np.max(train_data), np.max(test_data)
(255.0, 255.0)
train_data = train_data / np.max(train_data)
test_data = test_data / np.max(test_data)

Mari verifikasi nilai maksimum data pelatihan dan pengujian yang seharusnya 1.0 setelah penskalaan ulang!

np.max(train_data), np.max(test_data)
(1.0, 1.0)

Setelah semua ini, penting untuk melakukan partisi data. Agar model kita dapat melakukan generalisasi dengan baik, Anda membagi data pelatihan menjadi dua bagian: set pelatihan dan validasi. Anda akan melatih model pada 80% data dan memvalidasinya pada 20% sisa data pelatihan.

Ini juga akan membantu mengurangi kemungkinan overfitting, karena Anda akan memvalidasi model pada data yang tidak dilihat saat fase pelatihan.

Anda dapat menggunakan modul train_test_split dari scikit-learn untuk membagi data dengan benar:

from sklearn.model_selection import train_test_split
train_X,valid_X,train_ground,valid_ground = train_test_split(train_data,
                                                             train_data,
                                                             test_size=0.2,
                                                             random_state=13)

Catatan: Anda akan menggunakan pembagian data di atas dua kali, sekali untuk tugas rekonstruksi menggunakan convolutional autoencoder yang tidak memerlukan label pelatihan dan pengujian. Itulah sebabnya Anda akan meneruskan gambar pelatihan dua kali. Gambar pelatihan Anda akan berperan sebagai masukan sekaligus ground truth mirip dengan label yang Anda miliki pada tugas klasifikasi.

Namun untuk tugas klasifikasi, Anda juga akan meneruskan label beserta gambar yang akan Anda lakukan nanti dalam tutorial.

Sekarang Anda siap untuk mendefinisikan jaringan dan memasukkan data ke dalam jaringan. Jadi tanpa berlama-lama, mari lanjut ke langkah berikutnya!

Convolutional Autoencoder

Gambar berukuran 28 x 28 x 1 atau vektor berdimensi 30976. Anda mengonversi matriks gambar menjadi array, melakukan penskalaan ulang antara 0 dan 1, membentuk ulang sehingga berukuran 28 x 28 x 1, dan memasukkan ini sebagai input ke jaringan.

Selain itu, Anda akan menggunakan ukuran batch 128; menggunakan ukuran batch yang lebih besar 256 atau 512 juga dapat dipertimbangkan—semuanya bergantung pada sistem tempat Anda melatih model. Ini sangat berkontribusi dalam menentukan parameter pembelajaran dan memengaruhi akurasi prediksi.

batch_size = 64
epochs = 200
inChannel = 1
x, y = 28, 28
input_img = Input(shape = (x, y, inChannel))
num_classes = 10

Seperti yang mungkin sudah Anda ketahui, autoencoder terbagi menjadi dua bagian: encoder dan decoder.

Encoder: Memiliki 4 blok Konvolusi, tiap blok memiliki lapisan konvolusi diikuti lapisan normalisasi batch. Lapisan max-pooling digunakan setelah blok konvolusi pertama dan kedua.

  • Blok konvolusi pertama memiliki 32 filter berukuran 3 x 3, diikuti lapisan downsampling (max-pooling),
  • Blok kedua memiliki 64 filter berukuran 3 x 3, diikuti lapisan downsampling lainnya,
  • Blok ketiga encoder memiliki 128 filter berukuran 3 x 3,
  • Blok keempat encoder memiliki 256 filter berukuran 3 x 3.

Decoder: Memiliki 3 blok Konvolusi, tiap blok memiliki lapisan konvolusi diikuti lapisan normalisasi batch. Lapisan upsampling digunakan setelah blok konvolusi kedua dan ketiga.

  • Blok pertama memiliki 128 filter berukuran 3 x 3,
  • Blok kedua memiliki 64 filter berukuran 3 x 3 diikuti lapisan upsampling,
  • Blok ketiga memiliki 32 filter berukuran 3 x 3 diikuti lapisan upsampling,
  • Lapisan terakhir encoder memiliki 1 filter berukuran 3 x 3 yang akan merekonstruksi kembali input yang memiliki satu kanal.

Lapisan max-pooling akan melakukan downsampling input sebanyak dua kali setiap kali digunakan, sementara lapisan upsampling akan melakukan upsampling input sebanyak dua kali setiap kali digunakan.

Catatan: Jumlah filter, ukuran filter, jumlah lapisan, jumlah epoch pelatihan model, semuanya adalah hiperparameter dan harus diputuskan berdasarkan intuisi Anda sendiri; Anda bebas mencoba eksperimen baru dengan mengutak-atik hiperparameter ini dan mengukur performa model Anda. Dan dari situlah Anda perlahan belajar seni deep learning!

Mari buat fungsi encoder dan decoder terpisah karena Anda akan menggunakan bobot encoder nanti untuk tujuan klasifikasi!

def encoder(input_img):
    #encoder
    #input = 28 x 28 x 1 (wide and thin)
    conv1 = Conv2D(32, (3, 3), activation='relu', padding='same')(input_img) #28 x 28 x 32
    conv1 = BatchNormalization()(conv1)
    conv1 = Conv2D(32, (3, 3), activation='relu', padding='same')(conv1)
    conv1 = BatchNormalization()(conv1)
    pool1 = MaxPooling2D(pool_size=(2, 2))(conv1) #14 x 14 x 32
    conv2 = Conv2D(64, (3, 3), activation='relu', padding='same')(pool1) #14 x 14 x 64
    conv2 = BatchNormalization()(conv2)
    conv2 = Conv2D(64, (3, 3), activation='relu', padding='same')(conv2)
    conv2 = BatchNormalization()(conv2)
    pool2 = MaxPooling2D(pool_size=(2, 2))(conv2) #7 x 7 x 64
    conv3 = Conv2D(128, (3, 3), activation='relu', padding='same')(pool2) #7 x 7 x 128 (small and thick)
    conv3 = BatchNormalization()(conv3)
    conv3 = Conv2D(128, (3, 3), activation='relu', padding='same')(conv3)
    conv3 = BatchNormalization()(conv3)
    conv4 = Conv2D(256, (3, 3), activation='relu', padding='same')(conv3) #7 x 7 x 256 (small and thick)
    conv4 = BatchNormalization()(conv4)
    conv4 = Conv2D(256, (3, 3), activation='relu', padding='same')(conv4)
    conv4 = BatchNormalization()(conv4)
    return conv4

def decoder(conv4):    
    #decoder
    conv5 = Conv2D(128, (3, 3), activation='relu', padding='same')(conv4) #7 x 7 x 128
    conv5 = BatchNormalization()(conv5)
    conv5 = Conv2D(128, (3, 3), activation='relu', padding='same')(conv5)
    conv5 = BatchNormalization()(conv5)
    conv6 = Conv2D(64, (3, 3), activation='relu', padding='same')(conv5) #7 x 7 x 64
    conv6 = BatchNormalization()(conv6)
    conv6 = Conv2D(64, (3, 3), activation='relu', padding='same')(conv6)
    conv6 = BatchNormalization()(conv6)
    up1 = UpSampling2D((2,2))(conv6) #14 x 14 x 64
    conv7 = Conv2D(32, (3, 3), activation='relu', padding='same')(up1) # 14 x 14 x 32
    conv7 = BatchNormalization()(conv7)
    conv7 = Conv2D(32, (3, 3), activation='relu', padding='same')(conv7)
    conv7 = BatchNormalization()(conv7)
    up2 = UpSampling2D((2,2))(conv7) # 28 x 28 x 32
    decoded = Conv2D(1, (3, 3), activation='sigmoid', padding='same')(up2) # 28 x 28 x 1
    return decoded

Setelah model dibuat, Anda harus mengompilasinya menggunakan optimizer RMSProp.

Perhatikan bahwa Anda juga harus menentukan jenis loss melalui argumen loss. Dalam kasus ini, yaitu mean squared error, karena loss setelah setiap batch akan dihitung antara batch keluaran yang diprediksi dan ground truth menggunakan mean squared error per piksel:

autoencoder = Model(input_img, decoder(encoder(input_img)))
autoencoder.compile(loss='mean_squared_error', optimizer = RMSprop())

Mari visualisasikan lapisan yang Anda buat pada langkah di atas menggunakan fungsi summary. Ini akan menampilkan jumlah parameter (bobot dan bias) di setiap lapisan dan juga total parameter dalam model Anda.

autoencoder.summary()
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_2 (InputLayer)         (None, 28, 28, 1)         0         
_________________________________________________________________
conv2d_16 (Conv2D)           (None, 28, 28, 32)        320       
_________________________________________________________________
batch_normalization_15 (Batc (None, 28, 28, 32)        128       
_________________________________________________________________
...

batch_normalization_28 (Batc (None, 14, 14, 32)        128       
_________________________________________________________________
up_sampling2d_4 (UpSampling2 (None, 28, 28, 32)        0         
_________________________________________________________________
conv2d_30 (Conv2D)           (None, 28, 28, 1)         289       
=================================================================
Total params: 1,758,657
Trainable params: 1,755,841
Non-trainable params: 2,816
_________________________________________________________________

Akhirnya saatnya melatih model dengan fungsi fit() Keras! Model dilatih selama 200 epoch. Fungsi fit() akan mengembalikan objek history; Dengan menyimpan hasil fungsi ini pada autoencoder_train, Anda dapat menggunakannya nanti untuk memplot kurva loss antara pelatihan dan validasi yang akan membantu Anda menganalisis performa model secara visual.

Latih Model

autoencoder_train = autoencoder.fit(train_X, train_ground, batch_size=batch_size,epochs=epochs,verbose=1,validation_data=(valid_X, valid_ground))
Train on 48000 samples, validate on 12000 samples
Epoch 1/200
48000/48000 [==============================] - 19s - loss: 0.0202 - val_loss: 0.0114s: 0.020
Epoch 2/200
48000/48000 [==============================] - 17s - loss: 0.0087 - val_loss: 0.0071  
...  
Epoch 199/200
48000/48000 [==============================] - 18s - loss: 7.0886e-04 - val_loss: 8.9876e-04
Epoch 200/200
48000/48000 [==============================] - 18s - loss: 7.0929e-04 - val_loss: 0.0010

Akhirnya! Anda melatih model pada dataset fashion-mnist selama 100 epoch, Sekarang, mari plot kurva loss antara data pelatihan dan validasi untuk memvisualisasikan performa model.

loss = autoencoder_train.history['loss']
val_loss = autoencoder_train.history['val_loss']
epochs = range(200)
plt.figure()
plt.plot(epochs, loss, 'bo', label='Training loss')
plt.plot(epochs, val_loss, 'b', label='Validation loss')
plt.title('Training and validation loss')
plt.legend()
plt.show()
training validation loss graph

Akhirnya, Anda dapat melihat bahwa loss validasi dan loss pelatihan selaras. Ini menunjukkan bahwa model Anda tidak overfitting: loss validasi menurun dan tidak meningkat, dan jarang ada celah antara loss pelatihan dan validasi sepanjang fase pelatihan.

Karena itu, dapat dikatakan kemampuan generalisasi model Anda baik.

Tetapi ingat, tugas kita adalah menggunakan bagian encoder dari model yang telah dilatih di atas untuk mengklasifikasikan gambar fashion mnist. Jadi, mari lanjut ke bagian berikutnya sekarang!

Simpan Model

Karena Anda akan memerlukan bobot encoder dalam tugas klasifikasi, pertama mari simpan bobot autoencoder lengkap. Anda akan mempelajari cara mengekstrak bobot encoder segera.

autoencoder.save_weights('autoencoder.h5')

Menyegmentasi Gambar Fashion Mnist

Sekarang Anda akan menggunakan bagian kepala autoencoder terlatih, yaitu bagian encoder, dan akan memuat bobot autoencoder yang baru saja Anda latih hanya ke bagian encoder dari model.

Anda akan menambahkan beberapa lapisan dense atau fully connected pada encoder untuk mengklasifikasikan gambar fashion mnist.

  • Mari terlebih dahulu mengonversi label menjadi vektor one-hot encoding.

    Bagi Anda yang belum tahu tentang one-hot encoding:

Dalam one-hot encoding, Anda mengonversi data kategorikal menjadi vektor angka. Alasan mengapa Anda mengonversi data kategorikal ke one-hot encoding adalah karena algoritme pembelajaran mesin tidak dapat bekerja langsung dengan data kategorikal. Anda membuat satu kolom boolean untuk setiap kategori atau kelas. Hanya satu dari kolom ini yang dapat bernilai 1 untuk setiap sampel. Karena itulah disebut one-hot encoding.

Untuk pernyataan masalah Anda, one hot encoding akan berupa vektor baris, dan untuk setiap gambar, dimensinya 1 x 10. Hal penting yang perlu diperhatikan di sini adalah vektor terdiri dari semua nol kecuali untuk kelas yang diwakilinya, dan untuk kelas itu nilainya 1.

Jadi mari konversi label menjadi vektor one-hot encoding:

# Change the labels from categorical to one-hot encoding
train_Y_one_hot = to_categorical(train_labels)
test_Y_one_hot = to_categorical(test_labels)

# Display the change for category label using one-hot encoding
print('Original label:', train_labels[0])
print('After conversion to one-hot:', train_Y_one_hot[0])
('Original label:', 9)
('After conversion to one-hot:', array([0., 0., 0., 0., 0., 0., 0., 0., 0., 1.]))

Cukup jelas, bukan?

  • Langkah terakhir ini krusial dan sudah pernah Anda lakukan saat fase pelatihan autoencoder, yaitu membagi data menjadi pelatihan dan validasi. Jadi mari cepat lakukan langkah itu untuk klasifikasi juga. Perhatikan bahwa Anda akan menggunakan random state yang sama seperti sebelumnya dan kali ini Anda juga akan meneruskan label yang baru saja Anda konversi menjadi vektor one-hot encoding.
train_X,valid_X,train_label,valid_label = train_test_split(train_data,train_Y_one_hot,test_size=0.2,random_state=13)

Untuk terakhir kalinya mari periksa bentuk set pelatihan dan validasi.

train_X.shape,valid_X.shape,train_label.shape,valid_label.shape
((48000, 28, 28, 1), (12000, 28, 28, 1), (48000, 10), (12000, 10))

Sekarang, mari definisikan model klasifikasi. Ingat bahwa Anda akan menggunakan bagian encoder yang persis sama seperti yang digunakan pada arsitektur autoencoder.

def encoder(input_img):
    #encoder
    #input = 28 x 28 x 1 (wide and thin)
    conv1 = Conv2D(32, (3, 3), activation='relu', padding='same')(input_img) #28 x 28 x 32
    conv1 = BatchNormalization()(conv1)
    conv1 = Conv2D(32, (3, 3), activation='relu', padding='same')(conv1)
    conv1 = BatchNormalization()(conv1)
    pool1 = MaxPooling2D(pool_size=(2, 2))(conv1) #14 x 14 x 32
    conv2 = Conv2D(64, (3, 3), activation='relu', padding='same')(pool1) #14 x 14 x 64
    conv2 = BatchNormalization()(conv2)
    conv2 = Conv2D(64, (3, 3), activation='relu', padding='same')(conv2)
    conv2 = BatchNormalization()(conv2)
    pool2 = MaxPooling2D(pool_size=(2, 2))(conv2) #7 x 7 x 64
    conv3 = Conv2D(128, (3, 3), activation='relu', padding='same')(pool2) #7 x 7 x 128 (small and thick)
    conv3 = BatchNormalization()(conv3)
    conv3 = Conv2D(128, (3, 3), activation='relu', padding='same')(conv3)
    conv3 = BatchNormalization()(conv3)
    conv4 = Conv2D(256, (3, 3), activation='relu', padding='same')(conv3) #7 x 7 x 256 (small and thick)
    conv4 = BatchNormalization()(conv4)
    conv4 = Conv2D(256, (3, 3), activation='relu', padding='same')(conv4)
    conv4 = BatchNormalization()(conv4)
    return conv4

Mari definisikan lapisan fully connected yang akan Anda tumpuk dengan fungsi encoder.

def fc(enco):
    flat = Flatten()(enco)
    den = Dense(128, activation='relu')(flat)
    out = Dense(num_classes, activation='softmax')(den)
    return out
encode = encoder(input_img)
full_model = Model(input_img,fc(encode))
for l1,l2 in zip(full_model.layers[:19],autoencoder.layers[0:19]):
    l1.set_weights(l2.get_weights())

Catatan: Langkah berikut cukup penting. Untuk memastikan apakah bobot pada bagian encoder autoencoder serupa dengan bobot yang Anda muat ke fungsi encoder model klasifikasi, Anda sebaiknya selalu mencetak bobot salah satu lapisan yang sama dari kedua model. Jika tidak serupa, maka tidak ada gunanya menggunakan strategi klasifikasi autoencoder.

Mari cetak bobot lapisan pertama dari kedua model.

autoencoder.get_weights()[0][1]
array([[[ 0.22935028, -0.800786  ,  0.42421195, -0.6509941 ,
         -0.82958347, -0.44448015,  0.04182598, -0.05483926,
          0.44611776,  0.7123421 , -0.4499234 ,  0.16125064,
          0.1174996 ,  0.12156075,  0.8391102 , -0.44067   ,
          0.02915774, -0.7223025 ,  0.33398604, -0.69252896,
          0.04369332, -0.3793029 ,  0.37535954,  0.34269437,
          0.8863593 , -0.2114254 ,  0.21323568, -0.4076597 ,
          0.2965019 ,  0.11617199, -0.22282824, -0.9501956 ]],

       [[ 0.23096658,  0.3701021 ,  0.78717273, -0.5014979 ,
         -1.3326751 , -0.73818666,  2.6434395 , -0.7560537 ,
         -0.52561104, -0.67917436,  2.0205429 ,  0.14013338,
         -0.9140436 ,  0.169709  ,  0.09063474, -0.20975377,
         -0.11247484, -0.09702996,  0.17846109,  0.40699893,
         -0.5722246 , -1.0119121 ,  0.30877167,  0.6645408 ,
         -0.68007207, -0.57144946, -0.68339616,  0.45407826,
          1.0148963 ,  0.88867754, -0.57179326,  0.01268557]],

       [[ 0.23020297,  0.14018346, -0.37600747, -0.6213855 ,
         -0.4104492 , -0.2036299 ,  0.12469969,  0.08351921,
          0.20644444, -0.01170571, -0.07618313,  0.23164392,
         -0.38417578,  0.3481844 , -0.8055927 ,  0.76824665,
          0.06819476,  0.93830526,  0.31898668,  0.51119566,
          0.4445658 , -0.4568496 ,  0.1269397 , -0.34482956,
         -1.3285302 , -0.20479   , -0.17618039, -0.22546193,
         -0.35588196,  0.9971566 , -0.03546353, -0.7294457 ]]],
      dtype=float32)
full_model.get_weights()[0][1]
array([[[ 0.22935028, -0.800786  ,  0.42421195, -0.6509941 ,
         -0.82958347, -0.44448015,  0.04182598, -0.05483926,
          0.44611776,  0.7123421 , -0.4499234 ,  0.16125064,
          0.1174996 ,  0.12156075,  0.8391102 , -0.44067   ,
          0.02915774, -0.7223025 ,  0.33398604, -0.69252896,
          0.04369332, -0.3793029 ,  0.37535954,  0.34269437,
          0.8863593 , -0.2114254 ,  0.21323568, -0.4076597 ,
          0.2965019 ,  0.11617199, -0.22282824, -0.9501956 ]],

       [[ 0.23096658,  0.3701021 ,  0.78717273, -0.5014979 ,
         -1.3326751 , -0.73818666,  2.6434395 , -0.7560537 ,
         -0.52561104, -0.67917436,  2.0205429 ,  0.14013338,
         -0.9140436 ,  0.169709  ,  0.09063474, -0.20975377,
         -0.11247484, -0.09702996,  0.17846109,  0.40699893,
         -0.5722246 , -1.0119121 ,  0.30877167,  0.6645408 ,
         -0.68007207, -0.57144946, -0.68339616,  0.45407826,
          1.0148963 ,  0.88867754, -0.57179326,  0.01268557]],

       [[ 0.23020297,  0.14018346, -0.37600747, -0.6213855 ,
         -0.4104492 , -0.2036299 ,  0.12469969,  0.08351921,
          0.20644444, -0.01170571, -0.07618313,  0.23164392,
         -0.38417578,  0.3481844 , -0.8055927 ,  0.76824665,
          0.06819476,  0.93830526,  0.31898668,  0.51119566,
          0.4445658 , -0.4568496 ,  0.1269397 , -0.34482956,
         -1.3285302 , -0.20479   , -0.17618039, -0.22546193,
         -0.35588196,  0.9971566 , -0.03546353, -0.7294457 ]]],
      dtype=float32)

Voila! Kedua array terlihat persis sama. Jadi, tanpa berlama-lama, mari kompilasi model dan mulai pelatihan.

Selanjutnya, Anda akan menjadikan bagian encoder yaitu sembilan belas lapisan pertama model tidak dapat dilatih. Karena bagian encoder sudah dilatih, Anda tidak perlu melatihnya. Anda hanya akan melatih bagian Fully Connected.

for layer in full_model.layers[0:19]:
    layer.trainable = False

Mari kompilasi model!

full_model.compile(loss=keras.losses.categorical_crossentropy, optimizer=keras.optimizers.Adam(),metrics=['accuracy'])

Mari cetak ringkasan model juga. Seharusnya ada parameter yang tidak dapat dilatih karena Anda menjadikan lima belas lapisan pertama model tidak dapat dilatih.

full_model.summary()
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_2 (InputLayer)         (None, 28, 28, 1)         0         
_________________________________________________________________
conv2d_55 (Conv2D)           (None, 28, 28, 32)        320       
_________________________________________________________________
batch_normalization_53 (Batc (None, 28, 28, 32)        128       
_________________________________________________________________
conv2d_56 (Conv2D)           (None, 28, 28, 32)        9248      
_________________________________________________________________
batch_normalization_54 (Batc (None, 28, 28, 32)        128       
_________________________________________________________________
max_pooling2d_11 (MaxPooling (None, 14, 14, 32)        0         
_________________________________________________________________
conv2d_57 (Conv2D)           (None, 14, 14, 64)        18496     
_________________________________________________________________
batch_normalization_55 (Batc (None, 14, 14, 64)        256       
_________________________________________________________________
conv2d_58 (Conv2D)           (None, 14, 14, 64)        36928     
_________________________________________________________________
batch_normalization_56 (Batc (None, 14, 14, 64)        256       
_________________________________________________________________
max_pooling2d_12 (MaxPooling (None, 7, 7, 64)          0         
_________________________________________________________________
conv2d_59 (Conv2D)           (None, 7, 7, 128)         73856     
_________________________________________________________________
batch_normalization_57 (Batc (None, 7, 7, 128)         512       
_________________________________________________________________
conv2d_60 (Conv2D)           (None, 7, 7, 128)         147584    
_________________________________________________________________
batch_normalization_58 (Batc (None, 7, 7, 128)         512       
_________________________________________________________________
conv2d_61 (Conv2D)           (None, 7, 7, 256)         295168    
_________________________________________________________________
batch_normalization_59 (Batc (None, 7, 7, 256)         1024      
_________________________________________________________________
conv2d_62 (Conv2D)           (None, 7, 7, 256)         590080    
_________________________________________________________________
batch_normalization_60 (Batc (None, 7, 7, 256)         1024      
_________________________________________________________________
flatten_4 (Flatten)          (None, 12544)             0         
_________________________________________________________________
dense_7 (Dense)              (None, 128)               1605760   
_________________________________________________________________
dense_8 (Dense)              (None, 10)                1290      
=================================================================
Total params: 2,782,570
Trainable params: 1,607,050
Non-trainable params: 1,175,520
_________________________________________________________________

Latih Model

Akhirnya saatnya melatih model dengan fungsi fit() Keras! Model dilatih selama 10 epoch. Fungsi fit() akan mengembalikan objek history; Dengan menyimpan hasil fungsi ini pada fashion_train, Anda dapat menggunakannya nanti untuk memplot akurasi dan loss antara pelatihan dan validasi yang akan membantu Anda menganalisis performa model secara visual.

classify_train = full_model.fit(train_X, train_label, batch_size=64,epochs=100,verbose=1,validation_data=(valid_X, valid_label))
Train on 48000 samples, validate on 12000 samples
Epoch 1/100
48000/48000 [==============================] - 6s - loss: 0.3747 - acc: 0.8732 - val_loss: 0.2888 - val_acc: 0.8935
Epoch 2/100
48000/48000 [==============================] - 6s - loss: 0.2216 - acc: 0.9178 - val_loss: 0.2942 - val_acc: 0.9010
Epoch 3/100
48000/48000 [==============================] - 5s - loss: 0.1762 - acc: 0.9340 - val_loss: 0.2868 - val_acc: 0.9078
...
Epoch 74/100
48000/48000 [==============================] - 6s - loss: 0.0182 - acc: 0.9953 - val_loss: 0.8069 - val_acc: 0.9109
Epoch 75/100
48000/48000 [==============================] - 6s - loss: 0.0102 - acc: 0.9971 - val_loss: 0.7872 - val_acc: 0.9125
Epoch 76/100
11776/48000 [======>.......................] - ETA: 3s - loss: 0.0084 - acc: 0.9977

Akhirnya! Anda melatih model pada fashion-MNIST hanya selama 10 epoch, dan dengan mengamati akurasi dan loss pelatihan, Anda dapat mengatakan bahwa model bekerja dengan sangat baik karena setelah 10 epoch akurasi pelatihan 99% dan loss validasi 98%.

Mari simpan model klasifikasi!

full_model.save_weights('autoencoder_classification.h5')

Selanjutnya, Anda akan melatih ulang model dengan menjadikan sembilan belas lapisan pertama dapat dilatih True alih-alih menjaganya False! Jadi, mari cepat lakukan itu.

for layer in full_model.layers[0:19]:
    layer.trainable = True
full_model.compile(loss=keras.losses.categorical_crossentropy, optimizer=keras.optimizers.Adam(),metrics=['accuracy'])

Sekarang mari latih seluruh model untuk terakhir kalinya!

classify_train = full_model.fit(train_X, train_label, batch_size=64,epochs=100,verbose=1,validation_data=(valid_X, valid_label))
Train on 48000 samples, validate on 12000 samples
Epoch 1/100
48000/48000 [==============================] - 13s - loss: 0.1584 - acc: 0.9718 - val_loss: 0.7902 - val_acc: 0.8960
Epoch 2/100
48000/48000 [==============================] - 12s - loss: 0.1049 - acc: 0.9759 - val_loss: 0.8327 - val_acc: 0.8893
Epoch 3/100
48000/48000 [==============================] - 12s - loss: 0.0792 - acc: 0.9804 - val_loss: 0.6947 - val_acc: 0.9099
...
loss: 0.0123 - acc: 0.9971 - val_loss: 0.6827 - val_acc: 0.9217
Epoch 98/100
48000/48000 [==============================] - 13s - loss: 0.0097 - acc: 0.9975 - val_loss: 0.7074 - val_acc: 0.9211
Epoch 99/100
48000/48000 [==============================] - 13s - loss: 0.0081 - acc: 0.9984 - val_loss: 0.6846 - val_acc: 0.9205
Epoch 100/100
48000/48000 [==============================] - 13s - loss: 0.0090 - acc: 0.9977 - val_loss: 0.6739 - val_acc: 0.9226

Mari simpan model untuk terakhir kalinya.

full_model.save_weights('classification_complete.h5')

Mari letakkan evaluasi model Anda dalam perspektif dan plot kurva akurasi dan loss antara data pelatihan dan validasi:

accuracy = classify_train.history['acc']
val_accuracy = classify_train.history['val_acc']
loss = classify_train.history['loss']
val_loss = classify_train.history['val_loss']
epochs = range(len(accuracy))
plt.plot(epochs, accuracy, 'bo', label='Training accuracy')
plt.plot(epochs, val_accuracy, 'b', label='Validation accuracy')
plt.title('Training and validation accuracy')
plt.legend()
plt.figure()
plt.plot(epochs, loss, 'bo', label='Training loss')
plt.plot(epochs, val_loss, 'b', label='Validation loss')
plt.title('Training and validation loss')
plt.legend()
plt.show()
graph
graph

Dari dua plot di atas, Anda dapat melihat bahwa model mengalami overfitting karena ada celah besar antara loss pelatihan dan validasi. Untuk mengatasi overfitting, Anda mungkin harus menggunakan beberapa teknik regularisasi seperti Dropout. Anda dapat mengikuti tutorial ini tentang CNN di Python dengan keras.

Evaluasi Model pada Set Uji

Terakhir, mari evaluasi model Anda juga pada data uji dan lihat bagaimana performanya!

test_eval = full_model.evaluate(test_data, test_Y_one_hot, verbose=0)
print('Test loss:', test_eval[0])
print('Test accuracy:', test_eval[1])
('Test loss:', 0.7068972043234281)
('Test accuracy:', 0.9205)

Prediksi Label

predicted_classes = full_model.predict(test_data)

Karena prediksi yang Anda dapatkan berupa nilai floating point, tidak akan mudah membandingkan label yang diprediksi dengan label uji yang benar. Jadi, Anda akan membulatkan keluaran yang akan mengonversi nilai float menjadi integer. Selanjutnya, Anda akan menggunakan np.argmax() untuk memilih nomor indeks yang memiliki nilai lebih tinggi dalam satu baris.

Misalnya, anggap satu prediksi untuk satu gambar uji adalah [0 1 0 0 0 0 0 0 0 0], keluaran untuk ini seharusnya label kelas 1.

predicted_classes = np.argmax(np.round(predicted_classes),axis=1)
predicted_classes.shape, test_labels.shape
((10000,), (10000,))
correct = np.where(predicted_classes==test_labels)[0]
print "Found %d correct labels" % len(correct)
for i, correct in enumerate(correct[:9]):
    plt.subplot(3,3,i+1)
    plt.imshow(test_data[correct].reshape(28,28), cmap='gray', interpolation='none')
    plt.title("Predicted {}, Class {}".format(predicted_classes[correct], test_labels[correct]))
    plt.tight_layout()
Found 9204 correct labels
images
incorrect = np.where(predicted_classes!=test_labels)[0]
print "Found %d incorrect labels" % len(incorrect)
for i, incorrect in enumerate(incorrect[:9]):
    plt.subplot(3,3,i+1)
    plt.imshow(test_data[incorrect].reshape(28,28), cmap='gray', interpolation='none')
    plt.title("Predicted {}, Class {}".format(predicted_classes[incorrect], test_labels[incorrect]))
    plt.tight_layout()
Found 796 incorrect labels
images

Laporan Klasifikasi

Laporan klasifikasi akan membantu Anda mengidentifikasi kelas yang salah klasifikasi secara lebih rinci. Anda akan dapat mengamati untuk kelas mana model berkinerja buruk dari sepuluh kelas yang ada.

from sklearn.metrics import classification_report
target_names = ["Class {}".format(i) for i in range(num_classes)]
print(classification_report(test_labels, predicted_classes, target_names=target_names))
             precision    recall  f1-score   support

    Class 0       0.83      0.89      0.86      1000
    Class 1       0.99      0.99      0.99      1000
    Class 2       0.89      0.87      0.88      1000
    Class 3       0.92      0.93      0.92      1000
    Class 4       0.85      0.90      0.88      1000
    Class 5       0.99      0.99      0.99      1000
    Class 6       0.81      0.72      0.76      1000
    Class 7       0.96      0.98      0.97      1000
    Class 8       0.98      0.98      0.98      1000
    Class 9       0.98      0.96      0.97      1000

avg / total       0.92      0.92      0.92     10000

Ingin menggali lebih dalam?

Tutorial ini merupakan awal yang baik untuk menggunakan autoencoder dan convolutional neural network yang fully connected dengan Python dan Keras. Jika Anda dapat mengikutinya dengan mudah atau bahkan dengan sedikit usaha lebih, bagus! Cobalah melakukan beberapa eksperimen mungkin dengan arsitektur model yang sama tetapi menggunakan berbagai jenis dataset publik yang tersedia.

Masih banyak yang harus dipelajari, jadi mengapa tidak mengambil kursus Deep Learning in Python dari DataCamp? Sambil menunggu, pastikan juga untuk memeriksa dokumentasi Keras, jika Anda belum melakukannya. Anda akan menemukan lebih banyak contoh dan informasi tentang semua fungsi, argumen, lebih banyak lapisan, dan lain-lain. Ini pasti akan menjadi sumber yang tak tergantikan saat Anda belajar cara bekerja dengan neural network di Python!

Jika Anda lebih suka membaca buku yang menjelaskan dasar-dasar deep learning (dengan Keras) beserta penggunaannya dalam praktik, Anda harus membaca buku Deep Learning in Python karya François Chollet.

Topik
Python
Machine Learning
Deep Learning

Kursus Python

Kursus

Pengantar Deep Learning dengan Python

4 jam
264.7K
Pelajari dasar-dasar jaringan saraf tiruan dan cara membangun model pembelajaran mendalam menggunakan Keras 2.0 dalam Python.
Lihat DetailRight Arrow
Mulai Kursus
Lihat SelengkapnyaRight Arrow
Terkait

blogs

Tutorial Korelasi di R

Dapatkan pengenalan dasar-dasar korelasi di R: pelajari lebih lanjut tentang koefisien korelasi, matriks korelasi, plotting korelasi, dan sebagainya.
David Woods's photo

David Woods

13 mnt

blogs

Spaghetti Plot dan Jalur Badai

Temukan alasan mengapa Anda sebaiknya (tidak) menggunakan spaghetti plot untuk menyampaikan ketidakpastian jalur prediksi badai serta dampaknya terhadap interpretasi.
Hugo Bowne-Anderson's photo

Hugo Bowne-Anderson

13 mnt

blogs

40 Pertanyaan Wawancara DBMS Teratas di 2026

Kuasai pertanyaan wawancara basis data, dari konsep SQL dasar hingga skenario desain sistem tingkat lanjut. Panduan mendalam ini mencakup semua yang Anda perlukan untuk sukses di wawancara DBMS dan meraih peran berikutnya.
Dario Radečić's photo

Dario Radečić

15 mnt

blogs

12 Alternatif ChatGPT Terbaik yang Bisa Anda Coba pada 2026

Artikel ini menyajikan daftar alternatif ChatGPT yang akan meningkatkan produktivitas Anda.
Javier Canales Luna's photo

Javier Canales Luna

14 mnt

Lihat SelengkapnyaLihat Selengkapnya