Este relatório tem como objetivo principal demonstrar em forma de tutorial, como construir/utilizar uma rede neural para treinar um modelo que identifique o dígitos em imagens. Utilizando também transformações em imagens, como rotação, espelhamento, compactação, etc.

A base de dados utilizada foi: digit.recognizer, que pode ser encontrada no site Kaggle atráves do link https://www.kaggle.com/c/digit-recognizer.

#Inicio

Para inciar, temos que carregar os pacotes utilizados, chamar as bases de dados, definir o numero de linhas colunas e o total de classe..

suppressMessages(suppressWarnings(library(tidyverse)))
suppressMessages(suppressWarnings(library(keras)))

img_rows <- 28 # Numero de linhas
img_cols <- 28 # Numero de colunas
n_classes <- 10 # Numero de Classes

test <- read.csv("/opt/datasets/digits/test.csv")
label <- read.csv("/opt/datasets/digits/sample_submission.csv")
train <- read.csv("/opt/datasets/digits/train.csv")



train2<-train
train <- train2 %>%
  mutate(Flag = sample(x = c(0, 1),
                      size = n(),
                      replace = TRUE,
                      prob = c(.8,.2))) %>%
  sample_frac(1, replace = FALSE)

Uma nova variavel foi criada, para posteriormente separarmos nossa matriz de treinamento, em teste e treino. O primeiro passo é visualizarmos um digito. Algumas mudanças são necessarias para visualização do digito, então ao lado do codigo seguem os comentarios.

set.seed(1)
# Visualizing a random digit
train %>% 
  select(-label, -Flag) %>% 
  sample_n(1) %>%   
  unlist() %>% #Transforma em vetor
  matrix(nrow = 28, byrow = TRUE) %>% 
  #Pega linha e transforma numa matriz 28x28. byrow = TRUE faz mudança na linha, FALSE mexe nas colunas
  apply(2, rev) %>% #Faz o efeito do digito espelhado. ex: (1...12) -> (12...1).  apply(1, rev) 1 = linha, 2=coluna
  t() %>% #Rotaciona o digito em 90°
  image() 

Visualizando 9 digitos :

# Start Function
Label <- function(digits, base, nrows = 28, ncols = 28){
  stopifnot(digits %in% 1:nrow(base))
  if ("label" %in% colnames(base)) 
  {
    cat("\nRemoving label column...")
    base <- base %>%  select(-label)
  }
  if ("Flag" %in% colnames(base)) 
  {
    cat("\nRemoving Flag column...")
    base <- base %>%  select(-Flag)
  }
  # Check graphical parameters 
  val <- par(no.readonly=TRUE)
  n <- ceiling(sqrt(length(digits)))
  par(mfrow = c(ceiling(length(digits)/n),n), mar = c(0.1, 0.1, 0.1, 0.1))
  for (i in digits){ 
    m <- base %>% 
      filter(row_number() == i) %>%  
      unlist() %>%
      matrix(nrow = nrows, ncol = ncols, byrow = TRUE) %>% 
      apply(2, rev) %>% 
      t() %>% 
    image(col = grey.colors(255), axes = FALSE)
  }
  # reset the original graphics parameters
  par(val)                                               
}

# Call Function
Label(101:109, train) ##Define quantos digitos
## 
## Removing label column...
## Removing Flag column...

Como foi falado no incio, sera necessario criar as matrizes de treino e teste. Então iremos contar com o auxilio da nova variavel criada `Flag’.

set.seed(123)

x_train <- train %>% 
  filter(Flag == 0) %>% 
  select(-label, -Flag) %>% 
  mutate_all(function(x) x/255) %>% 
  as.matrix()

x_test  <- train %>% 
  filter(Flag == 1) %>% 
  select(-label, -Flag) %>% 
  mutate_all(function(x) x/255) %>% 
  as.matrix()

y_train <- train %>% 
  filter(Flag == 0) %>% 
  select(label)  %>% as.matrix() %>% 
  keras::to_categorical(num_classes = 10)

y_test <- train %>% 
  filter(Flag == 1) %>% 
  select(label)  %>% 
  as.matrix() %>% 
  to_categorical(num_classes = 10)

Segunda parte - Treino do modelo

É necessario ter o tensorflow ja instalado, poiss o keras ira utiliza-lo.

Definindo o método de modelagem e o hiperparâmetros do modelo, a serem utilizados.

Os modelos de redes neurais são estimados por meio de camadas. O comando layer_dense define estas camadas. Este modelo por sua vez é construidas em 3 camadas, contendo 256, 128 e 10 neurônios respectivamente.

Em resumo, os parametros são: units - número de parâmetros.

activation - função de ativação. input_shape - número das colunas da matriz e o número de colunas que serão utilizadas. layer_drop- Utilizado para nao gerar overfitting.

rnn_model <- keras_model_sequential() 
rnn_model %>% 
  layer_dense(units = 256, activation = 'relu', input_shape = c(img_cols*img_rows)) %>% 
  layer_dropout(rate = 0.4) %>% 
  layer_dense(units = 128, activation = 'relu') %>%
  layer_dropout(rate = 0.2) %>%
  layer_dense(units = n_classes, activation = 'softmax')

rnn_model %>% compile(
  loss = 'categorical_crossentropy', #categorical_accuracy
  optimizer = optimizer_rmsprop(),
  metrics = c('accuracy')
)


history <- rnn_model %>% fit(
  x_train, y_train, 
  epochs = 10, batch_size = 128, 
  validation_split = 0.2)

plot(history)   

rnn_model %>% evaluate(x_test, y_test)
## $loss
## [1] 0.1021235
## 
## $accuracy
## [1] 0.9740493

Ao utilizar a função evaluate pode se verficar a acúracia no modelo.

Aplicando o modelo com uma imagem

Antes de testar o modelo com a imagem inseridaa, sera testado com a propria base de dados.

## [1] "list"
## [1] 6
##      [,1]  [,2]  [,3]    [,4] [,5]    [,6] [,7] [,8] [,9] [,10]
## [1,]    0 2e-05 2e-05 0.99832    0 0.00163    0    0    0 1e-05

Testando o modelo na pratica, utiliza-se uma imagem qu contem um numero. O pacote imager será utilizado para carregar a imagem.

suppressMessages(suppressWarnings(library(imager)))

digit <- load.image("digit2.png")

plot(digit,axes = FALSE)

Desta forma podemos visualizar o numero que foi inserido.

digit28 <- digit %>%  resize(size_x = 28, size_y = 28, interpolation_type = 1L)

digit28 <- rowMeans(digit28, dims = 2)

digit28 %>%
  apply(1, rev) %>% 
  t() %>% 
  image(col = grey.colors(256), axes = FALSE)

Forma que o modelo recebe a imagem.

digit_test_2 <- digit28 %>%
  apply(2,function(x) x/255) %>% 
  apply(1, rev) %>% 
  t() %>% 
  as.vector()

# Prevendo
Y = (1 - digit_test_2) %*% Input + t(Input_bias)
Y_relu = Y * (Y > 0) # Activation Function
Z = Y_relu %*% Layer + t(Layer_bias)
Z_relu = Z * (Z > 0) # Activation Function
W = Z_relu %*% Output + t(Output_bias)
f_exp = exp(W)
W_softmax = f_exp/sum(f_exp)# softmax output

round(W_softmax, 5)
##      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
## [1,]    0    0    1    0    0    0    0    0    0     0

A saída representa as probabilidades para cada digito, onde a coluna que apresentar a a maior probabilidade será escolhido para a predição. obs:A coluna 1, representa o digito 0, a coluno dois o digito 1 e assim sucessivamente.

O nosso modelo estimou uma probabilidade 1 de ser o número 2 (coluna 3 ), que a imagem inserida, Logo o modelo acertou com 100%.