https://www.kaggle.com/polavr/twoclass-weather-classification
Pada project ini, saya megambil data dari kaggle yang bernama Two-class weather classification. Disini saya membuat model mengganakan aristektur CNN, dan memakai image data generator
# Data Pre-Processing
library(tidyverse)
# Image manipulation
library(imager)
# Deep learning
library(keras)
library(tensorflow)
# Model Evaluation
library(caret)
List.files dibawah ini berfungsi untuk men-listing file yang ada di dalam folder train
folder_list <- list.files("dataset/WeatherClassification/train/")
folder_path digunakan untuk menambil path dari setiap folder class
folder_path <- paste0("dataset/WeatherClassification/train/", folder_list, "/")
file_path digunakan untuk menyimpan file path dari setiap gambar
file_path <- map(folder_path,
function(x) paste0(x, list.files(x))) %>%
unlist()
head(file_path)
## [1] "dataset/WeatherClassification/train/cloudy/c0001.jpg"
## [2] "dataset/WeatherClassification/train/cloudy/c0002.jpg"
## [3] "dataset/WeatherClassification/train/cloudy/c0003.jpg"
## [4] "dataset/WeatherClassification/train/cloudy/c0004.jpg"
## [5] "dataset/WeatherClassification/train/cloudy/c0005.jpg"
## [6] "dataset/WeatherClassification/train/cloudy/c0006.jpg"
Disini kita mengambil sample dari file path dan menjadikan image, sehingga kita tau image seperti apa yang akan kita gunakan
set.seed(2021)
sample_img <- sample(x = file_path, size = 2)
img <- map(sample_img, load.image)
map(img, plot)
## [[1]]
## Image. Width: 200 pix Height: 200 pix Depth: 1 Colour channels: 3
##
## [[2]]
## Image. Width: 200 pix Height: 200 pix Depth: 1 Colour channels: 3
Setelah mengetahui image yang yang kita gunakan seperti apa, kita akan membuat funtion yang dimana akan mengambil dimension setiap image
get_dim <- function(x){
img <- load.image(x)
df <- data.frame(height = height(img),
width = width(img),
file_name = x)
return(df)
}
get_dim(file_path[1])
## height width file_name
## 1 200 200 dataset/WeatherClassification/train/cloudy/c0001.jpg
Kita akan gunakan function yang sudah kita buat sebelumnya agar mendapatkan dimension seluruh image, dan melakukan summary.
dim_img <- map_df(file_path, get_dim)
summary(dim_img)
## height width file_name
## Min. :200 Min. :200 Length:10000
## 1st Qu.:200 1st Qu.:200 Class :character
## Median :200 Median :200 Mode :character
## Mean :200 Mean :200
## 3rd Qu.:200 3rd Qu.:200
## Max. :200 Max. :200
Dari summary di atas, kita dapat lihat bahwa dimension keseluruhan iamge ialah 200x200. maka kita akan menggunakan target size berdimensi 200x200 dan kita memakai batch size sebesar 64
target_size <- c(200,200)
batch_size <- 64
Disini kita akan memakai image datta generator dan juga flow image from directory untuk mengambil semua gambar dan class dari folder.
train_img_array_gen <- flow_images_from_directory(directory = "dataset/WeatherClassification/train/",
generator = image_data_generator(
horizontal_flip = T,
vertical_flip = T,
zoom_range = 0.25,
rotation_range = 90,
rescale = 1/255),
target_size = target_size,
batch_size = batch_size,
color_mode = "rgb",
seed = 2021)
valid_img_array_gen <- flow_images_from_directory(directory = "dataset/WeatherClassification/test/",
generator = image_data_generator(
horizontal_flip = T,
vertical_flip = T,
zoom_range = 0.25,
rotation_range = 90,
rescale = 1/255),
target_size = target_size,
batch_size = batch_size,
color_mode = "rgb",
seed = 2021)
setelah kita mengambil gambar dan juga kelas nya, kita akan mengambil total kelas, gambar training, dan gambar validation. Disini kita juga melihat proporsi dari target classnya.
n_output <- n_distinct(train_img_array_gen$classes)
train_sample <- train_img_array_gen$n
valid_sample <- valid_img_array_gen$n
table(as.factor(train_img_array_gen$classes))
##
## 0 1
## 5000 5000
setelah dilihat dari proporsi kelasnya, kelar tersebut bisa dinyatakan balanced. Disini kita akan membuat arsitektur CNN nya.
Untuk model base nya sendiri, saya memakai 1x layer conv 2d, 1x max pooling, dan 2 hidel layer
untuk layer conv 2d nya disini memakai kernel size 3x3, activation relu, filters 8, padding same. untuk max pooling nya menggunakan pool size 2x2. untuk hiden layer pertama menggunakan units 64, dan activation relu untuk hiden layer kedua menggunakan konfigurasi yang sama seperti pertama dan untuk outputnya menggunakan activation sigmod dan units 2 karena target kita hanya mempunyai 2 class
model <- keras_model_sequential(name = "Model_base") %>%
layer_conv_2d(input_shape = c(target_size, 3),
filters = 8,
kernel_size = c(3,3),
padding = "same",
activation = "relu") %>%
layer_max_pooling_2d(pool_size = c(2,2)) %>%
layer_flatten() %>%
layer_dense(units = 64,
activation = "relu",
name = "satu") %>%
layer_dense(units = 64,
activation = "relu",
name = "dua") %>%
layer_dense(activation = "sigmoid",
units = n_output,
name = "output")
untuk model base sendiri, saya menggunakan optimizer adam dengan learning rate default atau 0.001
model %>%
compile(loss = "binary_crossentropy",
metrics = "accuracy",
optimizer = optimizer_adam(learning_rate = 0.001))
disini saya memakai epoch 10
set.seed(2021)
history_base <- model %>%
fit(train_img_array_gen,
epoch = 10,
steps_per_epoch = as.integer(train_sample / batch_size),
validation_data = valid_img_array_gen,
validation_step = as.integer(valid_sample/ batch_size))
plot(history_base)
## `geom_smooth()` using formula 'y ~ x'
dari hasil yang di dapatkan model_base, sebenernya hasil tersebut sudah cukup bagus dengan accuracy kurang lebih 85% dan val accuracy di 80%
disini kita mau membuat model tuning lagi, dengan konfugaris yang berbeda dari sebelumnya.
untuk model tune sendiri disini menggunakan layer conv 2x, max pooling 2x, hiden layer 3x, dan output layer 1x,
model_tune <- keras_model_sequential(name = "model_tuning") %>%
layer_conv_2d(input_shape = c(target_size, 3),
kernel_size = c(3,3),
filters = 16,
padding = "same",
activation = "relu") %>%
layer_max_pooling_2d(pool_size = c(3,3)) %>%
layer_conv_2d(kernel_size = c(2,2),
filters = 8,
padding = "same",
activation = "relu") %>%
layer_max_pooling_2d(pool_size = c(3,3)) %>%
layer_flatten() %>%
layer_dense(units = 256,
activation = "relu") %>%
layer_dense(units = 128,
activation = "relu") %>%
layer_dense(units = 64,
activation = "relu") %>%
layer_dense(units = 2,
activation = "sigmoid",
name = "Output")
mode tune sendiri menggunakan optimizer adam dengan menggunakan learning rate sebesar 0.0001.
untuk fit nya menggunakan epoch 10
model_tune %>%
compile(loss = "binary_crossentropy",
metrics = "accuracy",
optimizer = optimizer_adam(learning_rate = 0.0001))
history_tune <- model_tune %>%
fit(train_img_array_gen,
epoch = 10,
steps_per_epoch = as.integer(train_sample / batch_size),
validation_data = valid_img_array_gen,
validation_step = as.integer(valid_sample/ batch_size))
plot(history_tune)
## `geom_smooth()` using formula 'y ~ x'
setelah training, kita mendapatkan hasil yang bagus menggunakan model tune
setelah itu kita mengambil data test tanpa menggunakan data generator, dan file path dimasukan kedalam test_data beserta classnya
test_img_data_gen <- flow_images_from_directory(directory = "dataset/WeatherClassification/test/",
target_size = target_size,
batch_size = batch_size,
color_mode = "rgb")
test_data <- data.frame(file_name = paste0("dataset/WeatherClassification/test/", test_img_data_gen$filenames)) %>%
mutate(class = str_extract(file_name, "cloudy|sunny"))
disini kita membuat function yang digunakan untuk mengambil gambar dan dirubah kedalam array
image_prep <- function(x){
array <- lapply(x, function(path){
img <- image_load(path, target_size = target_size,
grayscale = F)
x <- image_to_array(img)
x <- array_reshape(x, c(1, dim(x)))
x <- x/255
})
do.call(abind::abind, c(array, list(along = 1)))
}
test_x <- image_prep(test_data$file_name)
disini kita memprediksi gambar yang sudah dirubah kedalam array.
pred_test <- predict(model_tune, test_x) %>% k_argmax() %>% as.array()
disini kita membuat function untuk merubah class dari 0 1 menjadi class sebenarnya
encode_label <- function(x) {
ifelse(x == 0, "cloudy", "sunny")
}
dan terakhir kita dapat melihat nilai akurasi, recall, dan precission
pred_test <- sapply(pred_test, encode_label)
confusionMatrix(as.factor(pred_test), as.factor(test_data$class))
## Confusion Matrix and Statistics
##
## Reference
## Prediction cloudy sunny
## cloudy 96 40
## sunny 4 113
##
## Accuracy : 0.8261
## 95% CI : (0.7737, 0.8707)
## No Information Rate : 0.6047
## P-Value [Acc > NIR] : 2.308e-14
##
## Kappa : 0.6576
##
## Mcnemar's Test P-Value : 1.317e-07
##
## Sensitivity : 0.9600
## Specificity : 0.7386
## Pos Pred Value : 0.7059
## Neg Pred Value : 0.9658
## Prevalence : 0.3953
## Detection Rate : 0.3794
## Detection Prevalence : 0.5375
## Balanced Accuracy : 0.8493
##
## 'Positive' Class : cloudy
##
Dan hasilnya sama sama bagus untuk model base dan tune, kita dapat memakai salah saatunya.