Photo by Photo by Brian McGowan on Unsplash
Intro
Dalam project LBB kali ini, kita akan mencoba untuk mengaplikasikan
prinsip dasar Neural Network - Deep Learning pada kasus Image
Classification. Tantangan yang akan coba kita selesaikan kali ini adalah
menemukan Capybara dari 2 kelompok gambar yang berisikan
capybara dan beaver. Keduanya berasal
dari ordo rodent sehingga akan banyak kemiripan fitur antara
keduanya, seberapa jauh kemampuan model yang akan kita dalam membedakan
keduanya? Kita akan menggunakan semua matriks pada
confusionMatrix() seperti nilai Accuracy, Sensitivity,
Specificity dan Precision dalam evaluasi performa model kita. Selama
model kita dapat melewati batas 75%, maka model tersebut akan dianggap
baik. Kita akan menentukan toleransi dalam selisih nilai matriks antara
data train dan data test maksimal sebesar 15%.
Mari kita mulai dengan mengunduh gambar dari list url hasil web scrapping dan menyimpannya dalam lokal direktori kita.
Persiapan
Unduh Paket
Kita akan membutuhkan beberapa paket untuk mengunduh dan menyimpan
objek gambar hasil webscrapping pada lokal direktori, paket untuk
manipulasi dan pembersihan data, manipulasi gambar, deep learning dengan
keras serta evaluasi model hasil deep learning.
# membaca & menyimpan objek gambar
library(jpeg)
library(here)
# manipulasi dan pembersihan data
library(tidyr)
library(dplyr)
library(purrr)
library(stringr)
# Manipulasi data gambar
library(imager)
# Deep learning
library(keras)
# Evaluasi Model
library(caret)
#memilih conda env.
use_condaenv('r-tensorflow')
#nomor scientific
options(scipen = 999)
Unduh dan Simpan Gambar
Sebagai persiapan kita akan mengunduh data gambar yang akan kita
simpan dalam folder capybara/ dan beaver/ yang
akan kita gunakan nanti sebagai data training dan data test melalui
proses cross validasi dengan proporsi sebesar 80:20.
#simpan list url hasil dari webscrapping dalam objek dataframe
# dataframe dengan object beaver
beav <- read.csv('beavers.csv')
n_bv <- nrow(beav)
# dataframe dgn objek capybara
capy <- read.csv('capybaras.csv')
n_cpy <- nrow(capy)
Jalankan fungsi di bawah ini untuk mengunduh setiap objek gambar dari url yang telah disimpan dalam dataframe sebelumnya.
#mengunduh gambar dari list url hasil scrapping dan menyimpan dalam local directory
for (i in 1:n_bv) { #isi dengan jumlah kolom di setiap file berisikan list url
myurl <- paste(beav[i,1], sep = "") #you need the exact column number so change 1 to that value and change df to your df's name
z <- tempfile() #same as above
try(download.file(myurl,z,mode="wb"), silent = TRUE)
pic <- try(readJPEG(z), silent = TRUE)
try(writeJPEG(pic, here("beaver/", paste("image", i, ".jpg", sep = ""))), silent = TRUE)
try(file.remove(z), silent = TRUE)
}
EDA
Membuat path untuk mengakses data gambar pada folder data_input/ untuk masing-masing kelompok gambar.
folder_list <- list.files("data_input/")
folder_list
## [1] "beaver" "capybara"
folder_path <- paste0('data_input/', folder_list, '/')
folder_path
## [1] "data_input/beaver/" "data_input/capybara/"
# Mendapatkan nama file
file_name <- map(folder_path,
function(x) paste0(x, list.files(x))
) %>%
unlist()
# 6 file name pertama dan terakhir
head(file_name)
## [1] "data_input/beaver/image1.jpg" "data_input/beaver/image10.jpg"
## [3] "data_input/beaver/image100.jpg" "data_input/beaver/image102.jpg"
## [5] "data_input/beaver/image103.jpg" "data_input/beaver/image104.jpg"
tail(file_name)
## [1] "data_input/capybara/image92.jpg" "data_input/capybara/image94.jpg"
## [3] "data_input/capybara/image95.jpg" "data_input/capybara/image96.jpg"
## [5] "data_input/capybara/image97.jpg" "data_input/capybara/image98.jpg"
Ada berapa banyak data gambar dalam dataset kita?
#Mengetahui berapa banyak data untuk seluruh kategori
length(file_name)
## [1] 461
Selanjutnya kita akan coba menampilkan sample data gambar kita sebagai berikut,
#Memilih gambar secara random
set.seed(88)
sample_image <- sample(file_name, 6)
# Load gambar ke R
img <- map(sample_image, load.image)
# Plot gambar
par(mfrow = c(2, 3)) # tampilkan dlm 2 x 3 grid gambar
map(img, plot)
## [[1]]
## Image. Width: 2304 pix Height: 2304 pix Depth: 1 Colour channels: 3
##
## [[2]]
## Image. Width: 620 pix Height: 350 pix Depth: 1 Colour channels: 3
##
## [[3]]
## Image. Width: 1280 pix Height: 720 pix Depth: 1 Colour channels: 3
##
## [[4]]
## Image. Width: 1600 pix Height: 1200 pix Depth: 1 Colour channels: 3
##
## [[5]]
## Image. Width: 1300 pix Height: 866 pix Depth: 1 Colour channels: 3
##
## [[6]]
## Image. Width: 500 pix Height: 300 pix Depth: 1 Colour channels: 3
Dimensi Gambar
Dalam kasus image classification menggunakan neural-network/deep-learning, adalah penting untuk mengerti variasi ukuran / dimensi gambar untuk kemudian dapat diseragamkan. Karena dalam neural network, ukuran input akan mempengaruhi arsitektur model dan jumlah node pada input layer model deep-learning kita nanti akan sejumlah dimensi gambar setelah diseragamkan.
# Deskripsi Gambar Penuh
img <- load.image(file_name[1])
img
## Image. Width: 718 pix Height: 721 pix Depth: 1 Colour channels: 3
dim(img)
## [1] 718 721 1 3
# ssimpan dimensi gambar dalam data frame df_img
get_dim <- function(x){
img <- load.image(x)
df_img <- data.frame(height = height(img),
width = width(img),
filename = x
)
return(df_img)
}
get_dim(file_name[1])
## height width filename
## 1 721 718 data_input/beaver/image1.jpg
# ambil sampel random pada file_name utk mendapat 100 gambar
set.seed(88)
sample_file <- sample(file_name, 100)
# jalankan fungsi get_dim() utk tiap gambar
file_dim <- map_df(sample_file, get_dim)
head(file_dim, 10)
## height width filename
## 1 2304 2304 data_input/capybara/image127.jpg
## 2 350 620 data_input/beaver/image2.jpg
## 3 720 1280 data_input/capybara/image73.jpg
## 4 1200 1600 data_input/beaver/image55.jpg
## 5 866 1300 data_input/capybara/image299.jpg
## 6 300 500 data_input/beaver/image203.jpg
## 7 460 860 data_input/beaver/image31.jpg
## 8 720 720 data_input/capybara/image214.jpg
## 9 720 1280 data_input/beaver/image116.jpg
## 10 180 300 data_input/capybara/image91.jpg
Untuk mengetahui statistik dari data gambar yang akan digunakan, kita
manfaatkan fungsi summary().
# mengetahui statistik dari data sample gambar
summary(file_dim)
## height width filename
## Min. : 147.0 Min. : 220.0 Length:100
## 1st Qu.: 378.8 1st Qu.: 580.0 Class :character
## Median : 546.0 Median : 793.5 Mode :character
## Mean : 674.6 Mean : 990.1
## 3rd Qu.: 724.2 3rd Qu.:1125.0
## Max. :3456.0 Max. :5108.0
Dari informasi summary() 100 sample gambar, diketahui
bahwa ukuran tinggi (height) gambar bervariasi dari 147 hingga 3456
pixel, sedangkan ukuran lebar (width) gambar bervariasi antara 220
sampai 5108 pixels.
Ketidakseragaman ukuran gambar sebagai input model nantinya harus ditangani dengan metode augmentasi data, atau pengurangan jumlah informasi data sampai dengan jumlah tertentu tanpa menghilangkan informasi yang signifikan di dalamnya.
Pre-Processing Data
Seperti disebutkan sebelumnya, bahwa mengetahui dimensi data gambar
sangat dibutuhkan dalam pembuatan model karena nantinya akan dibutuhkan
keseragaman ukuran input data yang dapat dicapai melalui proses
modifikasi ukuran data lewat Data Augmentation dengan memanfaatkan
fungsi image_data_generator(). Dalam hal ini kita akan
mencoba untuk menyeragamkan data dimensi data menjadi 90 x 90 pixels dan
membagi ke dalam batches dgn ukuran 32 data point per batch.
# tinggi x lebar data gambar yg diinginkan
target_size <- c(90, 90)
# ukuran batch utk training model
batch_size <- 32
#image generator
train_data_gen <- image_data_generator(rescale = 1/255, # Scale nilai pixel menjadi rentang 0-1
horizontal_flip = T, # Balik gambar horisontal
vertical_flip = T, # Balik gambar vertikal
rotation_range = 45, # Rotasi gambar dari 0 - 45 derajat
zoom_range = 0.25, # perbesar perkecil gambar sesuai kisaran
validation_split = 0.2 # cross val. - 20% data dijadikan data validasi
)
Pada proses diatas, kita melakukan beberapa variasi gambar yaitu rotasi/tilting, flip, zoom, agar data train dapat menegnali variasi dari data2 tersebut dan akibatnya model menjadi lebih robust.
Selanjutnya adalah proses inputasi pada image generator untuk
menghasilkan data tarining dan validasi (cross validation).
Disini kita akan menggunakan data dari folder /train untuk
menghasilkan dataset training dan validasi, dengan proporsi 80:20.
Nantinya model akan kita latih dengan data set tersebut dan coba kita
evaluasi dengan dataset validasi yang berasal dari induk data yang
sama.
Selanjutnya kita akan masukkan data ke dalam image_generator sekaligus dilakukan cross-validation antara data train dan data validation/test:
#memasukkan data gambar ke dalam image generator
# Training Dataset
train_image_array_gen <- flow_images_from_directory(directory = "data_input/", # Folder data
target_size = target_size, # target dimensi gambar (64 x 64)
color_mode = "rgb", # warna RGB
batch_size = batch_size,
seed = 88, # set random seed
subset = "training", # utk training data
generator = train_data_gen
)
# Validation Dataset
val_image_array_gen <- flow_images_from_directory(directory = "data_input/",
target_size = target_size,
color_mode = "rgb",
batch_size = batch_size ,
seed = 88,
subset = "validation", # utk validation data
generator = train_data_gen
)
Untuk memastikan proporsi antar kelas dalam data train dan data validasi, kita jalankan fungsi berikut:
# jumlah training samples
train_samples <- train_image_array_gen$n
# jumlah validation samples
valid_samples <- val_image_array_gen$n
# jumlah kelas target / kategori
output_n <- n_distinct(train_image_array_gen$classes)
# proporsi kelas
table("\nFrequency" = factor(train_image_array_gen$classes)
) %>%
prop.table()
##
## Frequency
## 0 1
## 0.5594595 0.4405405
Dapat dilihat bahwa kedua kelas sudah proporsional atau seimbang dengan rasio 56 : 44. Proporsi kelas harus proporsional agar model yang kita hasilkan nantinya tidak bias terhadap salah satu kelas dan tidak robust terhadap data baru.
Label diasosikan dengan kelas sesuai urutan abjad, 0 : beaver 1 : capybara
CNN (Convolutional Neural Network)
Arsitektur Model Dasar
Untuk kasus klasifikasi image kita akan gunakan model CNN
(Convolutional Neural Network) dimana secara dasar, arsitektur CNN
terdiri atas layer yang sama dengan Neural Network pada umunya kecuali
adanya layer_conv_2d() dan
layer_max_pooling_2d() serta dilakukan flattening
untuk flattening layer dari 2D array ke 1D array mendekati layer
output.
Kita akan simpan model dasar kita dengan nama model_base
yang akan dibuat dengan menggunakan arsitektur CNN sbb :
# Set Random Weight Mula2
tensorflow::tf$random$set_seed(88)
model_base <- keras_model_sequential(name = "base_model") %>%
# Convolution Layer
layer_conv_2d(filters = 16, #jumlah filter
kernel_size = c(3,3), # ukuran filter konvolusi
padding = "same",
activation = "relu",
input_shape = c(target_size, 3)
) %>%
# Max Pooling Layer
layer_max_pooling_2d(pool_size = c(2,2)) %>%
# Flattening Layer
layer_flatten() %>%
# Dense Layer
layer_dense(units = 16,
activation = "relu") %>%
# Output Layer
layer_dense(units = output_n,
activation = "softmax",
name = "Output")
model_base
## Model: "base_model"
## ________________________________________________________________________________
## Layer (type) Output Shape Param #
## ================================================================================
## conv2d (Conv2D) (None, 90, 90, 16) 448
## ________________________________________________________________________________
## max_pooling2d (MaxPooling2D) (None, 45, 45, 16) 0
## ________________________________________________________________________________
## flatten (Flatten) (None, 32400) 0
## ________________________________________________________________________________
## dense (Dense) (None, 16) 518416
## ________________________________________________________________________________
## Output (Dense) (None, 2) 34
## ================================================================================
## Total params: 518,898
## Trainable params: 518,898
## Non-trainable params: 0
## ________________________________________________________________________________
Selanjutnya kita akan fitting model dasar kita dengan data train yang sudah disiapkan sebelumnya.
Model Fitting
Mula-mula, gunakan 30 epochs & 0.01 learning rate untuk proses
fitting pada model_base dengan optimizer jenis ADAM dan
loss function categorical_crossentropy.
model_base %>% compile(
loss = "categorical_crossentropy",
optimizer = optimizer_adam(lr = 0.01),
metrics = "accuracy"
)
# Fit data ke model
history <- model_base %>%
fit_generator(
# training data
train_image_array_gen,
# training epochs
steps_per_epoch = as.integer(train_samples / batch_size),
epochs = 30,
# validation data
validation_data = val_image_array_gen,
validation_steps = as.integer(valid_samples / batch_size)
)
Evaluasi Model
Evaluasi model dengan dataset validasi,
val_data <- data.frame(file_name = paste0("data_input/", val_image_array_gen$filenames)) %>%
mutate(class = str_extract(file_name, "beaver|capybara"))
head(val_data, 10)
## file_name class
## 1 data_input/beaver\\image1.jpg beaver
## 2 data_input/beaver\\image10.jpg beaver
## 3 data_input/beaver\\image100.jpg beaver
## 4 data_input/beaver\\image102.jpg beaver
## 5 data_input/beaver\\image103.jpg beaver
## 6 data_input/beaver\\image104.jpg beaver
## 7 data_input/beaver\\image105.jpg beaver
## 8 data_input/beaver\\image106.jpg beaver
## 9 data_input/beaver\\image11.jpg beaver
## 10 data_input/beaver\\image110.jpg beaver
Memeriksa proporsi kelas di dataset validasi dan memastikan masing-masing kelas terwakilkan secara proporsional / seimbang.
prop.table(table(val_data$class))
##
## beaver capybara
## 0.5604396 0.4395604
# Membuat fungsi utk konversi data gambar ke array
image_prep <- function(x) {
arrays <- lapply(x, function(path) {
img <- image_load(path, target_size = target_size,
grayscale = F # Set FALSE apabila gambar RGB
)
x <- image_to_array(img)
x <- array_reshape(x, c(1, dim(x)))
x <- x/255 # merubah skala pixel gambar menjadi rentang 0-1
})
do.call(abind::abind, c(arrays, list(along = 1)))
}
test_x <- image_prep(val_data$file_name)
# Cek dimensi data test_x
dim(test_x)
## [1] 91 90 90 3
Dimensi object test_x sudah sesuai dengan jumlah data
validasi yang kita cek di awal yaitu sebanyak 91 data point dengan
ukuran 64 x 64 dan 3 layer warna (RGB). Selanjutnya data
test_x akan digunakan untuk memprediksi hasil pemodelan
dengan model_base
#prediksi menggunakan data test_x
pred_test <- predict(model_base, test_x) %>% #menghasilkan peluang
k_argmax() %>% #mengambil yg peluang paling besar
as.array() %>%
as.factor()
head(pred_test, 10)
## [1] 0 1 1 1 1 1 1 0 1 1
## Levels: 0 1
# Konversi label numerik ke label huruf
decode <- function(x){
case_when(x == 0 ~ "beaver",
x == 1 ~ "capybara")
}
pred_test <- sapply(pred_test, decode)
head(pred_test, 10)
## [1] "beaver" "capybara" "capybara" "capybara" "capybara" "capybara"
## [7] "capybara" "beaver" "capybara" "capybara"
Kemudian kita lakukan evaluasi dengan menggunakan
confusionMatrix()
confusionMatrix(as.factor(pred_test),
as.factor(val_data$class)
)
Hasil dari COnfusionMatrix menunjukkan bahwa performa
model_base membutuhkan perbaikan yang signifikan karena
nilai akurasi yang rendah (~ 50%), Sensitivity dan
Specificity yang sangat timpang menunjukkan kemampuan belajar
hanya kuat pada salah satu kelas.
Tuning Model
Setelah melihat performa model_base yang masih jauh dari
target, maka kita akan melakukan sedikit penyesuaian pada model CNN kita
seperti,
Pada model_tuned akan diimplementasikan sebanyak 5 layer
konvolusi dengan arsitektur sbb:
- #1 Convolutional layer untuk ekstraksi fitur dari gambar 2D dengan fungsi aktifasi relu
- #2 Convolutional layer untuk ekstraksi fitur dari gambar 2D dengan fungsi aktifasi relu
- Max pooling layer
- #3 Convolutional layer untuk ekstraksi fitur dari gambar 2D dengan fungsi aktifasi relu
- Max pooling layer
- #4 Convolutional layer untuk ekstraksi fitur dari gambar 2D dengan fungsi aktifasi relu
- Max pooling layer
- #5 Convolutional layer untuk ekstraksi fitur dari gambar 2D dengan fungsi aktifasi relu
- Max pooling layer
- #6 Convolutional layer untuk ekstraksi fitur dari gambar 2D dengan fungsi aktifasi relu
- Max pooling layer
layer_flatten()untuk flattening layer dari 2D array ke 1D array- Dense layer utk menangkap lebih banyak informasi dengan fungsi aktivasi relu
- Dense layer utk output layer dengan fungsi aktivasi
softmax - Ukuran kernel 5x5 hanya digunakan pada layer konvolusi #1 & #2, sedangkan layer lainnya akan menggunakan ukuran kernel seragam 3x3
- Ukuran layer_max_pooling juga diseragamkan 2x2 untuk menghindari generalisasi nilai maksimum apabila dibuat terlalu besar
tensorflow::tf$random$set_seed(88)
model_tuned <- keras_model_sequential(name = "Tuned_00") %>%
# First convolutional layer
layer_conv_2d(filters = 32,
kernel_size = c(5,5), # 5 x 5 filters
padding = "same",
activation = "relu",
input_shape = c(target_size, 3)
) %>%
# second conv layer
layer_conv_2d(filters = 32,
kernel_size = c(5,5), # 5 x 5 filters
padding = "same",
activation = "relu"
) %>%
# Max pooling layer
layer_max_pooling_2d(pool_size = c(2,2)) %>%
# third convolutional layer
layer_conv_2d(filters = 64,
kernel_size = c(3,3),
padding = "same",
activation = "relu"
) %>%
# Max pooling layer
layer_max_pooling_2d(pool_size = c(2,2)) %>%
# forth convolutional layer
layer_conv_2d(filters = 128,
kernel_size = c(3,3),
padding = "same",
activation = "relu"
) %>%
# Max pooling layer
layer_max_pooling_2d(pool_size = c(2,2)) %>%
# fifth convolutional layer
layer_conv_2d(filters = 256,
kernel_size = c(3,3),
padding = "same",
activation = "relu"
) %>%
# Max pooling layer
layer_max_pooling_2d(pool_size = c(2,2)) %>%
# sixth convolutional layer
layer_conv_2d(filters = 256,
kernel_size = c(3,3),
padding = "same",
activation = "relu"
) %>%
# Max pooling layer
layer_max_pooling_2d(pool_size = c(2,2)) %>%
# Flattening layer
layer_flatten() %>%
# Dense layer
layer_dense(units = 90,
activation = "relu") %>%
# Output layer
layer_dense(name = "Output",
units = 2, #sesuaikan dengan kelas output
activation = "softmax")
model_tuned
## Model: "Tuned_00"
## ________________________________________________________________________________
## Layer (type) Output Shape Param #
## ================================================================================
## conv2d_6 (Conv2D) (None, 90, 90, 32) 2432
## ________________________________________________________________________________
## conv2d_5 (Conv2D) (None, 90, 90, 32) 25632
## ________________________________________________________________________________
## max_pooling2d_5 (MaxPooling2D) (None, 45, 45, 32) 0
## ________________________________________________________________________________
## conv2d_4 (Conv2D) (None, 45, 45, 64) 18496
## ________________________________________________________________________________
## max_pooling2d_4 (MaxPooling2D) (None, 22, 22, 64) 0
## ________________________________________________________________________________
## conv2d_3 (Conv2D) (None, 22, 22, 128) 73856
## ________________________________________________________________________________
## max_pooling2d_3 (MaxPooling2D) (None, 11, 11, 128) 0
## ________________________________________________________________________________
## conv2d_2 (Conv2D) (None, 11, 11, 256) 295168
## ________________________________________________________________________________
## max_pooling2d_2 (MaxPooling2D) (None, 5, 5, 256) 0
## ________________________________________________________________________________
## conv2d_1 (Conv2D) (None, 5, 5, 256) 590080
## ________________________________________________________________________________
## max_pooling2d_1 (MaxPooling2D) (None, 2, 2, 256) 0
## ________________________________________________________________________________
## flatten_1 (Flatten) (None, 1024) 0
## ________________________________________________________________________________
## dense_1 (Dense) (None, 90) 92250
## ________________________________________________________________________________
## Output (Dense) (None, 2) 182
## ================================================================================
## Total params: 1,098,096
## Trainable params: 1,098,096
## Non-trainable params: 0
## ________________________________________________________________________________
Model Fitting
Pada model_tuned digunakan epoch 50 dan learning rate of
0.001 dengan loss function sama seperti model_base
# compile model
model_tuned %>%
compile(
loss = "categorical_crossentropy",
optimizer = optimizer_adam(lr = 0.001),
metrics = "accuracy"
)
# fit model
history <- model_tuned %>%
fit_generator(
# training data
train_image_array_gen,
# epochs
steps_per_epoch = as.integer(train_samples / batch_size),
epochs = 50,
# validation data
validation_data = val_image_array_gen,
validation_steps = as.integer(valid_samples / batch_size),
# tampilkan progres tanpa menampilkan grafik
verbose = 1,
view_metrics = 0
)
Dengan fungsi plot(), kita akan mendapatkan hasil di
bawah :
Evaluasi Model
Memanggil validasi data yang sudah kita siapkan sebelumnya :
val_data <- data.frame(file_name = paste0("data_input/", val_image_array_gen$filenames)) %>%
mutate(class = str_extract(file_name, "beaver|capybara"))
head(val_data, 10)
## file_name class
## 1 data_input/beaver\\image1.jpg beaver
## 2 data_input/beaver\\image10.jpg beaver
## 3 data_input/beaver\\image100.jpg beaver
## 4 data_input/beaver\\image102.jpg beaver
## 5 data_input/beaver\\image103.jpg beaver
## 6 data_input/beaver\\image104.jpg beaver
## 7 data_input/beaver\\image105.jpg beaver
## 8 data_input/beaver\\image106.jpg beaver
## 9 data_input/beaver\\image11.jpg beaver
## 10 data_input/beaver\\image110.jpg beaver
# Fungsi konversi data gambar ke array
image_prep <- function(x) {
arrays <- lapply(x, function(path) {
img <- image_load(path, target_size = target_size,
grayscale = F # Set FALSE jika gambar format RGB
)
x <- image_to_array(img)
x <- array_reshape(x, c(1, dim(x)))
x <- x/255 # rescale image pixel
})
do.call(abind::abind, c(arrays, list(along = 1)))
}
test_x <- image_prep(val_data$file_name)
# Check dimension of testing data set
dim(test_x)
## [1] 91 90 90 3
Melakukan prediksi dengan data test_x yang berasal dari
dataset validasi
pred_test <- predict(model_tuned, test_x) %>% #menghasilkan peluang
k_argmax() %>% #mengambil yg peluang paling besar
as.array() %>%
as.factor()
head(pred_test, 10)
## [1] 0 0 0 0 0 0 0 0 0 0
## Levels: 0
Merubah kelas numerik 0,1 menjadi label beaver & capybara.
# Konversi ke label
decode <- function(x){
case_when(x == 0 ~ "beaver",
x == 1 ~ "capybara")
}
pred_test <- sapply(pred_test, decode)
head(pred_test, 10)
## [1] "beaver" "beaver" "beaver" "beaver" "beaver" "beaver" "beaver" "beaver"
## [9] "beaver" "beaver"
Evaluasi dengan confusionMatrix dan mendapatikan hasil
berikut
confusionMatrix(as.factor(pred_test),
as.factor(val_data$class)
)
Proses prediksi dengan data validasi untuk model_tuned
menghasilkan,
- Nilai matriks Accuracy <70 %
- Belum memenuhi kriteria > 75% semua kelas khususnya pada matriks Specificity dan Pos Pred Value/Precision
Kesimpulan
Dari beberapa hasil percobaan tuning model yang dilakukan dengan modifikasi arsitektur CNN, penambahan layer, penambahan ukuran gambar inputan dari 64x64 pixel sampai 90x90 pixels, variasi ukuran matriks konvolusi, hingga variasi epoch dan learning rate, didapatkan hasil bahwa akurasi maksimal dari model masih berada id kisaran ~70%, nilai matriks Specificity & Precision selalu <75%, atau dengan kata lain model cenderung membaca gambar sebagai beaver daripada capybara.
Solusi yang bisa dicoba untuk pengembangan selanjutnya adalah penambahan training data untuk kedua kelas. Kemiripan fitur pada beaver dan capybara membutuhkan bahan belajar yang lebih banyak untuk model kita. Menaikkan data training dari 50 - 100% mungkin bisa menjadi solusi untuk keterbatasan model saat ini.