Libraries
# Data wrangling
library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr 1.1.4 ✔ readr 2.1.5
## ✔ forcats 1.0.0 ✔ stringr 1.5.1
## ✔ ggplot2 3.5.0 ✔ tibble 3.2.1
## ✔ lubridate 1.9.3 ✔ tidyr 1.3.1
## ✔ purrr 1.0.2
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
# Image manipulation
library(imager)
## Loading required package: magrittr
##
## Attaching package: 'magrittr'
##
## The following object is masked from 'package:purrr':
##
## set_names
##
## The following object is masked from 'package:tidyr':
##
## extract
##
##
## Attaching package: 'imager'
##
## The following object is masked from 'package:magrittr':
##
## add
##
## The following object is masked from 'package:stringr':
##
## boundary
##
## The following object is masked from 'package:dplyr':
##
## where
##
## The following object is masked from 'package:tidyr':
##
## fill
##
## The following objects are masked from 'package:stats':
##
## convolve, spectrum
##
## The following object is masked from 'package:graphics':
##
## frame
##
## The following object is masked from 'package:base':
##
## save.image
# Deep learning
library(keras)
# Model Evaluation
library(caret)
## Loading required package: lattice
##
## Attaching package: 'caret'
##
## The following object is masked from 'package:purrr':
##
## lift
library(purrr)
options(scipen = 999)
EDA
folder_list <- list.files("/Users/gabrielmedina/Desktop/red neuronal/train")
folder_list
## [1] "Jarra" "Plato" "Vaso"
folder_path <- paste0("/Users/gabrielmedina/Desktop/red neuronal/train/", folder_list, "/")
folder_path
## [1] "/Users/gabrielmedina/Desktop/red neuronal/train/Jarra/"
## [2] "/Users/gabrielmedina/Desktop/red neuronal/train/Plato/"
## [3] "/Users/gabrielmedina/Desktop/red neuronal/train/Vaso/"
# Get file name
file_name <- map(folder_path,
function(x) paste0(x, list.files(x))
) %>%
unlist()
# first 6 file name
head(file_name)
## [1] "/Users/gabrielmedina/Desktop/red neuronal/train/Jarra/IMG_3140.jpg"
## [2] "/Users/gabrielmedina/Desktop/red neuronal/train/Jarra/IMG_3141.jpg"
## [3] "/Users/gabrielmedina/Desktop/red neuronal/train/Jarra/IMG_3142.jpg"
## [4] "/Users/gabrielmedina/Desktop/red neuronal/train/Jarra/IMG_3143.jpg"
## [5] "/Users/gabrielmedina/Desktop/red neuronal/train/Jarra/IMG_3144.jpg"
## [6] "/Users/gabrielmedina/Desktop/red neuronal/train/Jarra/IMG_3145.jpg"
length(file_name)
## [1] 80
# Randomly select image
set.seed(123)
sample_image <- sample(file_name, 6)
# Load image into R
img <- map(sample_image, load.image)
# Plot image
par(mfrow = c(2, 3)) # Create 2 x 3 image grid
map(img, plot)

## [[1]]
## Image. Width: 5712 pix Height: 4284 pix Depth: 1 Colour channels: 3
##
## [[2]]
## Image. Width: 5712 pix Height: 4284 pix Depth: 1 Colour channels: 3
##
## [[3]]
## Image. Width: 5712 pix Height: 4284 pix Depth: 1 Colour channels: 3
##
## [[4]]
## Image. Width: 5712 pix Height: 4284 pix Depth: 1 Colour channels: 3
##
## [[5]]
## Image. Width: 4032 pix Height: 3024 pix Depth: 1 Colour channels: 3
##
## [[6]]
## Image. Width: 5712 pix Height: 4284 pix Depth: 1 Colour channels: 3
# Full Image Description
img <- load.image(file_name[1])
img
## Image. Width: 5712 pix Height: 4284 pix Depth: 1 Colour channels: 3
# Image Dimension
dim(img)
## [1] 5712 4284 1 3
# Function for acquiring width and height of an image
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])
# Randomly get sample images
set.seed(123)
sample_file <- sample(file_name)
# Run the get_dim() function for each image
file_dim <- map_df(sample_file, get_dim)
head(file_dim, 10)
summary(file_dim)
## height width filename
## Min. :3024 Min. :4032 Length:80
## 1st Qu.:3024 1st Qu.:4032 Class :character
## Median :4284 Median :5712 Mode :character
## Mean :3953 Mean :5271
## 3rd Qu.:4284 3rd Qu.:5712
## Max. :4284 Max. :5712
Procesamiento
# Desired height and width of images
target_size <- c(64, 64)
# Batch size for training the model
batch_size <- 32
# Image Generator
train_data_gen <- image_data_generator(rescale = 1/255, # Scaling pixel value
horizontal_flip = T, # Flip image horizontally
vertical_flip = T, # Flip image vertically
rotation_range = 45, # Rotate image from 0 to 45 degrees
zoom_range = 0.25, # Zoom in or zoom out range
validation_split = 0.2 # 20% data as validation data
)
# Training Dataset
train_image_array_gen <- flow_images_from_directory(directory = "/Users/gabrielmedina/Desktop/red neuronal/train/", # Folder of the data
target_size = target_size, # target of the image dimension (64 x 64)
color_mode = "rgb", # use RGB color
batch_size = batch_size ,
seed = 123, # set random seed
subset = "training", # declare that this is for training data
generator = train_data_gen
)
## Found 66 images belonging to 3 classes.
# Validation Dataset
val_image_array_gen <- flow_images_from_directory(directory = "/Users/gabrielmedina/Desktop/red neuronal/train/",
target_size = target_size,
color_mode = "rgb",
batch_size = batch_size ,
seed = 123,
subset = "validation", # declare that this is the validation data
generator = train_data_gen
)
## Found 14 images belonging to 3 classes.
library(dplyr)
# Number of training samples
train_samples <- train_image_array_gen$n
# Number of validation samples
valid_samples <- val_image_array_gen$n
# Number of target classes/categories
output_n <- n_distinct(train_image_array_gen$classes)
# Get the class proportion
table("\nFrequency" = factor(train_image_array_gen$classes)
) %>%
prop.table()
##
## Frequency
## 0 1 2
## 0.3484848 0.3484848 0.3030303
# input shape of the image
c(target_size, 3)
## [1] 64 64 3
library(torch)
# Definir el modelo
model <- nn_module(
"ConvNet",
initialize = function() {
self$conv1 <- nn_conv2d(3, 32, kernel_size = 3, padding = 1)
self$conv2 <- nn_conv2d(32, 64, kernel_size = 3, padding = 1)
self$fc1 <- nn_linear(64 * 16 * 16, 128) # Ajustar el tamaño según la reducción de la dimensionalidad
self$fc2 <- nn_linear(128, 10) # Suponiendo 10 clases
},
forward = function(x) {
x %>%
self$conv1() %>%
nnf_relu() %>%
nnf_max_pool2d(2) %>%
self$conv2() %>%
nnf_relu() %>%
nnf_max_pool2d(2) %>%
torch_flatten(start_dim = 2) %>%
self$fc1() %>%
nnf_relu() %>%
self$fc2()
}
)
# Crear una instancia del modelo
net <- model()
# Ver el modelo
print(net)
## An `nn_module` containing 2,117,962 parameters.
##
## ── Modules ─────────────────────────────────────────────────────────────────────
## • conv1: <nn_conv2d> #896 parameters
## • conv2: <nn_conv2d> #18,496 parameters
## • fc1: <nn_linear> #2,097,280 parameters
## • fc2: <nn_linear> #1,290 parameters
model <- keras_model_sequential(name = "cnn_model") %>%
layer_conv_2d(filters = 32, kernel_size = c(3,3), activation = 'relu', padding = 'same', input_shape = c(64, 64, 3)) %>%
layer_max_pooling_2d(pool_size = c(2,2)) %>%
layer_conv_2d(filters = 64, kernel_size = c(3,3), activation = 'relu', padding = 'same') %>%
layer_max_pooling_2d(pool_size = c(2,2)) %>%
layer_flatten() %>%
layer_dense(units = 128, activation = 'relu') %>%
layer_dense(units = 3, activation = 'softmax') # 3 unidades para Vaso, Plato, Jarra
model %>% compile(
loss = 'categorical_crossentropy',
optimizer = 'adam',
metrics = c('accuracy')
)
model %>% summary()
## Model: "cnn_model"
## ________________________________________________________________________________
## Layer (type) Output Shape Param #
## ================================================================================
## conv2d_1 (Conv2D) (None, 64, 64, 32) 896
## max_pooling2d_1 (MaxPooling2D) (None, 32, 32, 32) 0
## conv2d (Conv2D) (None, 32, 32, 64) 18496
## max_pooling2d (MaxPooling2D) (None, 16, 16, 64) 0
## flatten (Flatten) (None, 16384) 0
## dense_1 (Dense) (None, 128) 2097280
## dense (Dense) (None, 3) 387
## ================================================================================
## Total params: 2117059 (8.08 MB)
## Trainable params: 2117059 (8.08 MB)
## Non-trainable params: 0 (0.00 Byte)
## ________________________________________________________________________________
history <- model %>% fit(
x = train_image_array_gen,
steps_per_epoch = ceiling(train_samples / batch_size),
epochs = 10,
validation_data = val_image_array_gen,
validation_steps = ceiling(valid_samples / batch_size)
)
## Epoch 1/10
## 3/3 - 4s - loss: 1.4423 - accuracy: 0.2879 - val_loss: 1.5416 - val_accuracy: 0.3571 - 4s/epoch - 1s/step
## Epoch 2/10
## 3/3 - 3s - loss: 1.3800 - accuracy: 0.3030 - val_loss: 1.3658 - val_accuracy: 0.2857 - 3s/epoch - 1s/step
## Epoch 3/10
## 3/3 - 3s - loss: 1.2043 - accuracy: 0.3030 - val_loss: 1.1049 - val_accuracy: 0.2857 - 3s/epoch - 1s/step
## Epoch 4/10
## 3/3 - 3s - loss: 1.0914 - accuracy: 0.3636 - val_loss: 1.0876 - val_accuracy: 0.4286 - 3s/epoch - 1s/step
## Epoch 5/10
## 3/3 - 3s - loss: 1.1079 - accuracy: 0.3939 - val_loss: 1.0915 - val_accuracy: 0.3571 - 3s/epoch - 1s/step
## Epoch 6/10
## 3/3 - 3s - loss: 1.0907 - accuracy: 0.4091 - val_loss: 1.0775 - val_accuracy: 0.3571 - 3s/epoch - 1s/step
## Epoch 7/10
## 3/3 - 3s - loss: 1.0873 - accuracy: 0.4394 - val_loss: 1.0428 - val_accuracy: 0.4286 - 3s/epoch - 1s/step
## Epoch 8/10
## 3/3 - 3s - loss: 1.0823 - accuracy: 0.3788 - val_loss: 0.9995 - val_accuracy: 0.3571 - 3s/epoch - 1s/step
## Epoch 9/10
## 3/3 - 3s - loss: 1.0690 - accuracy: 0.3485 - val_loss: 0.9543 - val_accuracy: 0.3571 - 3s/epoch - 1s/step
## Epoch 10/10
## 3/3 - 3s - loss: 1.0530 - accuracy: 0.3636 - val_loss: 0.9049 - val_accuracy: 0.5000 - 3s/epoch - 1s/step
Evaluación
# Evaluación del modelo
evaluation_result <- model %>% evaluate(
x = val_image_array_gen,
steps = val_image_array_gen$n
)
## 14/14 - 0s - loss: 0.9011 - accuracy: 0.4286 - 482ms/epoch - 34ms/step
# Hacer algunas predicciones (ejemplo)
predictions <- model %>% predict(
x = val_image_array_gen,
steps = 1
)
## 1/1 - 1s - 514ms/epoch - 514ms/step
predicted_classes <- apply(predictions, 1, which.max) - 1 # Ajusta el índice si es necesario
# Suponiendo que tienes un vector o lista `class_names` que corresponde a los índices de clase:
class_names <- c("Vaso", "Plato", "Jarra") # Asegúrate de que esto coincida con el orden de tus clases
predicted_labels <- class_names[predicted_classes + 1] # +1 en R ya que los índices comienzan en 1
print(evaluation_result)
## loss accuracy
## 0.9010932 0.4285714
print(predicted_labels)
## [1] "Plato" "Vaso" "Plato" "Plato" "Plato" "Plato" "Plato" "Plato" "Vaso"
## [10] "Vaso" "Vaso" "Plato" "Plato" "Plato"