R Markdown

This is an R Markdown document. Markdown is a simple formatting syntax for authoring HTML, PDF, and MS Word documents. For more details on using R Markdown see http://rmarkdown.rstudio.com.

Introduction This document covers an image classification project using neural networks, where images are resized, converted into numeric data, and used to train models with varying hidden neuron sizes. All of the code and steps were developed independently by Harsh Sharma.

Installing and Loading Required Libraries

# Install necessary packages (if not already installed)
if(!requireNamespace("BiocManager", quietly = TRUE)) {
  install.packages("BiocManager")
}
if(!requireNamespace("imager", quietly = TRUE)) {
  install.packages("imager")
}
if(!requireNamespace("EBImage", quietly = TRUE)) {
  BiocManager::install("EBImage")
}

# Load required libraries
library(EBImage)
library(imager)
## Loading required package: magrittr
## 
## Attaching package: 'imager'
## The following object is masked from 'package:magrittr':
## 
##     add
## The following objects are masked from 'package:EBImage':
## 
##     channel, dilate, display, erode, resize, watershed
## 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
library(dplyr)
## 
## Attaching package: 'dplyr'
## The following object is masked from 'package:imager':
## 
##     where
## The following object is masked from 'package:EBImage':
## 
##     combine
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ forcats   1.0.0     ✔ readr     2.1.5
## ✔ ggplot2   3.5.1     ✔ stringr   1.5.1
## ✔ lubridate 1.9.3     ✔ tibble    3.2.1
## ✔ purrr     1.0.2     ✔ tidyr     1.3.1
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ imager::add()       masks magrittr::add()
## ✖ stringr::boundary() masks imager::boundary()
## ✖ dplyr::combine()    masks EBImage::combine()
## ✖ tidyr::extract()    masks magrittr::extract()
## ✖ tidyr::fill()       masks imager::fill()
## ✖ dplyr::filter()     masks stats::filter()
## ✖ dplyr::lag()        masks stats::lag()
## ✖ purrr::set_names()  masks magrittr::set_names()
## ✖ purrr::transpose()  masks EBImage::transpose()
## ✖ dplyr::where()      masks imager::where()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(RSNNS)
## Loading required package: Rcpp

Loading and Preprocessing the Image Data

# Define the path to the folder containing the image dataset
image_folder <- "C:/Users/Harsh sharma/Downloads/ASsignment image dataset"

# Get all category folders from the main dataset directory
categories <- list.dirs(image_folder, recursive = FALSE)
labels <- basename(categories)  # Extract category names from folder names

# Function to load and resize images
resize_image <- function(img_path, size = 128) {
  img <- load.image(img_path)      # Load the image
  img_resized <- resize(img, size, size)  # Resize to the desired dimensions
  as.numeric(img_resized)          # Convert the image to a numeric vector
}

# Function to create a labeled dataset from image files
load_images <- function(image_folder, categories) {
  image_data <- list()  # Initialize an empty list to store the data
  
  # Iterate over each category (folder)
  for (category in categories) {
    label <- basename(category)  # Extract the label from the folder name
    image_files <- list.files(category, full.names = TRUE)  # Get all image file paths
    
    # Iterate over each image file in the category
    for (image_file in image_files) {
      img_vector <- resize_image(image_file)  # Resize image and convert to vector
      image_data <- append(image_data, list(data.frame(label = label, img_vector = I(list(img_vector)))))  # Store in list
    }
  }
  
  return(do.call(rbind, image_data))  # Combine the list of data frames into a single data frame
}

# Load images from the dataset
image_data <- load_images(image_folder, categories)

Preparing the Data for Neural Network

# Flatten the image vectors into columns
image_data_flat <- do.call(rbind, lapply(image_data$img_vector, function(x) unlist(x)))

# Combine the flattened images with their labels
image_data_final <- data.frame(label = image_data$label, image_data_flat)

# Convert the labels into factors
image_data_final$label <- as.factor(image_data_final$label)

# Check the structure of the final dataset
str(image_data_final)
## 'data.frame':    750 obs. of  49153 variables:
##  $ label : Factor w/ 3 levels "Animal","Fruits",..: 1 1 1 1 1 1 1 1 1 1 ...
##  $ X1    : num  0.4118 0.0941 0.3412 0.1961 0.6039 ...
##  $ X2    : num  0.424 0.11 0.345 0.204 0.604 ...
##  $ X3    : num  0.467 0.173 0.325 0.208 0.604 ...
##  $ X4    : num  0.478 0.188 0.329 0.184 0.604 ...
##  $ X5    : num  0.506 0.247 0.329 0.204 0.604 ...
##  $ X6    : num  0.498 0.302 0.341 0.192 0.604 ...
##  $ X7    : num  0.569 0.349 0.341 0.169 0.604 ...
##  $ X8    : num  0.529 0.329 0.353 0.157 0.604 ...
##  $ X9    : num  0.431 0.263 0.353 0.169 0.6 ...
##  $ X10   : num  0.478 0.204 0.361 0.157 0.6 ...
##  $ X11   : num  0.514 0.188 0.376 0.2 0.6 ...
##  $ X12   : num  0.514 0.208 0.361 0.161 0.6 ...
##  $ X13   : num  0.518 0.231 0.353 0.141 0.592 ...
##  $ X14   : num  0.506 0.212 0.353 0.137 0.596 ...
##  $ X15   : num  0.514 0.212 0.357 0.145 0.592 ...
##  $ X16   : num  0.529 0.196 0.345 0.137 0.6 ...
##  $ X17   : num  0.478 0.208 0.353 0.157 0.596 ...
##  $ X18   : num  0.463 0.204 0.38 0.133 0.596 ...
##  $ X19   : num  0.557 0.2 0.384 0.137 0.596 ...
##  $ X20   : num  0.553 0.157 0.392 0.137 0.596 ...
##  $ X21   : num  0.553 0.165 0.392 0.122 0.565 ...
##  $ X22   : num  0.561 0.153 0.396 0.129 0.592 ...
##  $ X23   : num  0.502 0.161 0.396 0.149 0.616 ...
##  $ X24   : num  0.49 0.161 0.392 0.137 0.596 ...
##  $ X25   : num  0.498 0.125 0.392 0.149 0.604 ...
##  $ X26   : num  0.478 0.122 0.392 0.169 0.608 ...
##  $ X27   : num  0.435 0.114 0.416 0.184 0.604 ...
##  $ X28   : num  0.431 0.161 0.424 0.18 0.608 ...
##  $ X29   : num  0.478 0.224 0.427 0.141 0.612 ...
##  $ X30   : num  0.518 0.243 0.424 0.133 0.612 ...
##  $ X31   : num  0.522 0.22 0.416 0.165 0.612 ...
##  $ X32   : num  0.478 0.204 0.408 0.161 0.612 ...
##  $ X33   : num  0.482 0.192 0.384 0.122 0.569 ...
##  $ X34   : num  0.455 0.161 0.392 0.161 0.592 ...
##  $ X35   : num  0.408 0.188 0.373 0.165 0.62 ...
##  $ X36   : num  0.412 0.22 0.369 0.192 0.608 ...
##  $ X37   : num  0.459 0.204 0.369 0.212 0.612 ...
##  $ X38   : num  0.557 0.224 0.4 0.224 0.612 ...
##  $ X39   : num  0.706 0.29 0.416 0.192 0.604 ...
##  $ X40   : num  0.745 0.282 0.42 0.2 0.604 ...
##  $ X41   : num  0.737 0.275 0.42 0.196 0.604 ...
##  $ X42   : num  0.761 0.271 0.408 0.196 0.604 ...
##  $ X43   : num  0.71 0.412 0.4 0.161 0.6 ...
##  $ X44   : num  0.71 0.569 0.404 0.165 0.6 ...
##  $ X45   : num  0.69 0.6 0.392 0.184 0.6 ...
##  $ X46   : num  0.675 0.573 0.388 0.176 0.604 ...
##  $ X47   : num  0.659 0.4 0.392 0.173 0.608 ...
##  $ X48   : num  0.71 0.345 0.392 0.165 0.608 ...
##  $ X49   : num  0.714 0.373 0.392 0.188 0.616 ...
##  $ X50   : num  0.702 0.365 0.404 0.22 0.616 ...
##  $ X51   : num  0.667 0.341 0.392 0.227 0.616 ...
##  $ X52   : num  0.576 0.31 0.392 0.239 0.616 ...
##  $ X53   : num  0.624 0.329 0.384 0.255 0.624 ...
##  $ X54   : num  0.635 0.329 0.384 0.259 0.624 ...
##  $ X55   : num  0.655 0.302 0.384 0.227 0.62 ...
##  $ X56   : num  0.675 0.31 0.396 0.212 0.62 ...
##  $ X57   : num  0.639 0.322 0.392 0.231 0.62 ...
##  $ X58   : num  0.639 0.333 0.4 0.2 0.62 ...
##  $ X59   : num  0.655 0.325 0.38 0.204 0.62 ...
##  $ X60   : num  0.69 0.314 0.38 0.2 0.62 ...
##  $ X61   : num  0.624 0.31 0.376 0.204 0.616 ...
##  $ X62   : num  0.569 0.318 0.376 0.188 0.616 ...
##  $ X63   : num  0.494 0.322 0.38 0.149 0.612 ...
##  $ X64   : num  0.459 0.29 0.369 0.188 0.604 ...
##  $ X65   : num  0.467 0.278 0.388 0.216 0.62 ...
##  $ X66   : num  0.506 0.263 0.392 0.176 0.612 ...
##  $ X67   : num  0.518 0.227 0.38 0.2 0.616 ...
##  $ X68   : num  0.514 0.196 0.38 0.18 0.616 ...
##  $ X69   : num  0.557 0.161 0.392 0.176 0.612 ...
##  $ X70   : num  0.541 0.157 0.392 0.173 0.616 ...
##  $ X71   : num  0.518 0.169 0.388 0.176 0.62 ...
##  $ X72   : num  0.494 0.212 0.384 0.165 0.62 ...
##  $ X73   : num  0.616 0.243 0.384 0.173 0.624 ...
##  $ X74   : num  0.635 0.294 0.384 0.2 0.624 ...
##  $ X75   : num  0.494 0.294 0.376 0.212 0.627 ...
##  $ X76   : num  0.525 0.329 0.384 0.18 0.627 ...
##  $ X77   : num  0.565 0.404 0.373 0.22 0.624 ...
##  $ X78   : num  0.612 0.412 0.376 0.176 0.624 ...
##  $ X79   : num  0.667 0.38 0.38 0.176 0.624 ...
##  $ X80   : num  0.565 0.353 0.369 0.165 0.624 ...
##  $ X81   : num  0.561 0.271 0.369 0.169 0.624 ...
##  $ X82   : num  0.549 0.259 0.369 0.141 0.624 ...
##  $ X83   : num  0.482 0.259 0.353 0.173 0.624 ...
##  $ X84   : num  0.471 0.286 0.369 0.176 0.624 ...
##  $ X85   : num  0.518 0.318 0.337 0.2 0.624 ...
##  $ X86   : num  0.529 0.325 0.353 0.2 0.624 ...
##  $ X87   : num  0.475 0.361 0.353 0.184 0.62 ...
##  $ X88   : num  0.557 0.369 0.353 0.18 0.62 ...
##  $ X89   : num  0.616 0.306 0.357 0.271 0.62 ...
##  $ X90   : num  0.671 0.271 0.357 0.247 0.62 ...
##  $ X91   : num  0.745 0.216 0.361 0.227 0.62 ...
##  $ X92   : num  0.698 0.263 0.353 0.259 0.62 ...
##  $ X93   : num  0.718 0.337 0.361 0.255 0.624 ...
##  $ X94   : num  0.8 0.435 0.349 0.255 0.624 ...
##  $ X95   : num  0.788 0.443 0.341 0.263 0.624 ...
##  $ X96   : num  0.796 0.369 0.365 0.255 0.624 ...
##  $ X97   : num  0.718 0.255 0.341 0.275 0.624 ...
##  $ X98   : num  0.635 0.153 0.349 0.235 0.624 ...
##   [list output truncated]

Splitting the Data into Training and Testing Sets

# Split the data into 70% training and 30% testing sets
set.seed(123)  # Set seed for reproducibility
train_indices <- sample(1:nrow(image_data_final), size = 0.7 * nrow(image_data_final))
train_data <- image_data_final[train_indices, ]
test_data <- image_data_final[-train_indices, ]

# Convert image data to numeric (except labels)
train_data[-1] <- lapply(train_data[-1], as.numeric)
test_data[-1] <- lapply(test_data[-1], as.numeric)

Data Scaling for Neural Network Input

# Scale the numeric data before feeding into the neural network
train_data_scaled <- scale(train_data[, -1])  # Exclude labels for scaling
test_data_scaled <- scale(test_data[, -1])

# Convert the factor labels into numeric for classification tasks
train_labels <- as.numeric(as.factor(train_data[["label"]])) - 1  # Convert labels to 0-based numeric values
test_labels <- as.numeric(as.factor(test_data[["label"]])) - 1  # Convert test labels to numeric

Neural Network Model with 5 Neurons

# Train a neural network model with 5 hidden neurons
nn_model_5 <- mlp(as.matrix(train_data_scaled), 
                  train_labels, 
                  size = 5, 
                  maxit = 200, 
                  linOut = FALSE)  # linOut = FALSE for classification tasks

# Generate predictions on the test data
predictions_5_raw <- predict(nn_model_5, as.matrix(test_data_scaled))

# Convert the raw predictions to class labels
predicted_labels_5 <- apply(predictions_5_raw, 1, which.max) - 1  # Adjust for zero-based indexing

# Calculate accuracy
accuracy_5 <- mean(predicted_labels_5 == test_labels) * 100
cat("Accuracy of the neural network with 5 neurons:", accuracy_5, "%\n")
## Accuracy of the neural network with 5 neurons: 31.55556 %

Neural Network Models with 10 and 20 Neurons

# Train a neural network model with 10 neurons
nn_model_10 <- mlp(as.matrix(train_data_scaled), 
                   train_labels, 
                   size = 10, 
                   maxit = 200, 
                   linOut = FALSE)

# Train a model with 20 neurons
nn_model_20 <- mlp(as.matrix(train_data_scaled), 
                   train_labels, 
                   size = 20, 
                   maxit = 200, 
                   linOut = FALSE)

# Generate predictions for the models with 10 and 20 neurons
predictions_10_raw <- predict(nn_model_10, as.matrix(test_data_scaled))
predictions_20_raw <- predict(nn_model_20, as.matrix(test_data_scaled))

# Convert raw probabilities to class labels for both models
predicted_labels_10 <- apply(predictions_10_raw, 1, which.max) - 1
predicted_labels_20 <- apply(predictions_20_raw, 1, which.max) - 1

# Calculate accuracy for both models
accuracy_10 <- mean(predicted_labels_10 == test_labels) * 100
accuracy_20 <- mean(predicted_labels_20 == test_labels) * 100

cat("Accuracy of the neural network with 10 neurons:", accuracy_10, "%\n")
## Accuracy of the neural network with 10 neurons: 31.55556 %
cat("Accuracy of the neural network with 20 neurons:", accuracy_20, "%\n")
## Accuracy of the neural network with 20 neurons: 31.55556 %