Este é um trabalho baseado no tutorial do DataCamp
Machine Learning, é uma sub área da Ciência da Computação, e suas aplicações são cada vez mais comuns no mundo contemporâneo. Uma das principais novidades em técnicas de machine learning, é o deep learning, um conjunto de técnicas e algoritmos, inspirados pelo funcionamento e estrutura do cérebro. Deep Learning, é especialmente eficiente em algumas áreas como robótica e reconhecimento de imagens.
Neste tutorial, daremos nossos primeiros passos no deep learning, fazendo uso da linguagem R e do pacote Keras.
Na área da ciência de dados em geral, as duas linguagens de programação mais utilizadas são o R e o Python, portanto, é comum que profissionais desenvolvam ferramentas para as suas linguagens de preferência. Neste caso, keras é um pacote de algoritmos de deep learning, originalmente desenvolvido na linguagem Python, entretanto, o pacote R keras, nos fornece uma tecnologia facil de instalar e usar, que nos permite fazer uso das implementações no pacote original, através de uma interface R familiar.
# Instalando o pacote
#devtools::install_github("rstudio/keras")
# Instalando o tensorflow
#install.packages('tensorflow')
library(tensorflow)
#install_tensorflow()
library(keras)
#install_keras()
Instalamos também o pacote tensorflow, que faz interface ao serviço homônimo, de computação em grafos.
Neste tutorial, faremos uso do famoso dataset iris, que inclui dados de flores
iris <- read.csv(url("http://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data"), header = FALSE)
View(head(iris))
Observando o dataset que importamos, percebemos que as colunas do mesmo não são nomeadas. Apenas para propósitos de exploração, vamos incluir estes nomes. Após isto, veremos em uma visualização rápida, como o comprimento e a largura das pétalas se correlacionam.
names(iris) <- c("Sepal.Length", "Sepal.Width", "Petal.Length", "Petal.Width", "Species")
View(head(iris))
library(ggplot2)
ggplot(iris, aes(x = Petal.Length, y = Petal.Width, colour = Species)) +
geom_point() +
labs(x = "Comprimento da pétala", y = "Largura da pétala", colour = "Espécie")
O gráfico indica uma correlação positiva entre as duas variáveis analizadas, entretanto, este tipo de relação deve ser testada fazendo uso da função cor(), neste caso temos uma correlação de 0.9627571, o que confirma a nossa observação.
Podemos generalizar esta análise de correlação, e explorar as relações entre todas as variáveis dos nossos dados, fazendo uso do corrplot.
#install.packages('corrplot')
library(corrplot)
## corrplot 0.84 loaded
cors <- cor(iris[,1:4])
corrplot(cors, method = "circle")
Antes de gerar algum modelo, precisamos ter certeza de que os dados estão limpos, completos e até as vezes normalizados e balanceados.
summary(iris)
## Sepal.Length Sepal.Width Petal.Length Petal.Width
## Min. :4.300 Min. :2.000 Min. :1.000 Min. :0.100
## 1st Qu.:5.100 1st Qu.:2.800 1st Qu.:1.600 1st Qu.:0.300
## Median :5.800 Median :3.000 Median :4.350 Median :1.300
## Mean :5.843 Mean :3.054 Mean :3.759 Mean :1.199
## 3rd Qu.:6.400 3rd Qu.:3.300 3rd Qu.:5.100 3rd Qu.:1.800
## Max. :7.900 Max. :4.400 Max. :6.900 Max. :2.500
## Species
## Iris-setosa :50
## Iris-versicolor:50
## Iris-virginica :50
##
##
##
str(iris)
## 'data.frame': 150 obs. of 5 variables:
## $ Sepal.Length: num 5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
## $ Sepal.Width : num 3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
## $ Petal.Length: num 1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
## $ Petal.Width : num 0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
## $ Species : Factor w/ 3 levels "Iris-setosa",..: 1 1 1 1 1 1 1 1 1 1 ...
A partir do sumário acima, percebemos que os dados não precisam ser normalizados, pois os valores estão em um intervalo próximo e aceitável, entre 0.1 e 7.9. Entretanto, podemos estudar o efeito da normalização no nosso modelo, para isso, usamos a função normalize() do keras. Agora é um bom momento para saber de uma propriedade importante do pacote. Boa parte de suas funções (como por exemplo a função normalize) funciona com dados no formato de matriz, portanto, precisamos converter o nosso data frame para este formato, para então realizar a normalização.
iris[,5] <- as.numeric(iris[,5])
iris <- as.matrix(iris, dimnames = FALSE)
Agora antes de construirmos nossos modelos, precisamos dividir os dados em conjuntos de teste e treino, desta forma podemos testar o poder preditivo dos nossos modelos em dados não vistos antes.
set.seed(42)
ind <- sample(2, nrow(iris), replace=TRUE, prob=c(0.67, 0.33))
iris.training <- iris[ind==1, 1:4]
iris.test <- iris[ind==2, 1:4]
# Separamos agora as variáveis objeto da análise
iris.trainingtarget <- iris[ind==1, 5]
iris.testtarget <- iris[ind==2, 5]
Por fim, é uma boa prática, transformar a variável objeto da análise, em uma matriz cujas colunas são os valores possíveis das classes, e os elementos são booleanos que indicam se aquela instância em particular faz parte daquela classe. Esta sintaxe é chamada de One-Hot Encoding e é muito útil para evitar que o modelo interprete diferentes valores para diferentes classes.
O pacote keras possui uma função que facilita este trabalho, to_categorical(). Usamos a função na nossa variável objeto.
iris.trainLabels <- to_categorical(iris.trainingtarget)[,2:4]
iris.testLabels <- to_categorical(iris.testtarget)[,2:4]
Antes de iniciar qualquer análise, precisamos saber de forma muito clara, qual o nosso objetivo. Neste caso, que pergunta buscamos a resposta nos dados?
Após pré processarmos os dados, sabemos que temos features numéricas e uma variável de saída no formato de One-Hot Encoding. Um tipo de rede neural que performa muito bem nestas condições é a multi-layer perceptron.
Iniciamos usando a função keras_model_sequential() para gerar o nosso modelo sequencial. Como o propósito deste tutorial é apenas de dar nossos primeiros passos com deep learning em keras, vamos usar a função de ativação mais comum relu e usaremos a função softmax para a camada de saída, pois desejamos que os valores de saída estejam entre 0 e 1, para poderem ser interpretados como probabilidades.
# Antes de mais nada criamos o modelo sequencial
model <- keras_model_sequential()
# Então adicionamos camadas no nosso modelo
# A camada de entrada, possui um input shape de 4 pois são 4 colunas na entrada
# A camada de saída por sua vez possui 3 neurons pois a mesma possui 3 classes possíveis
model %>%
layer_dense(units = 8, activation = 'relu', input_shape = c(4)) %>%
layer_dense(units = 3, activation = 'softmax')
Agora, compilamos o nosso modelo.
model %>% compile(
loss = 'categorical_crossentropy',
optimizer = 'adam',
metrics = 'accuracy'
)
Os três argumentos passados para a função compile, são essenciais para o funcionamento do modelo, metrics especifica a métrica que queremos maximizar, optimizer indica o algoritmo de otimização e loss representa a função que calcula o erro nas predições.
Os valores atribuídos à loss, são dependentes do domínio do problema, entretanto no nosso caso (problema de classificação com mais de duas classes) fazemos uso de categorical_crossentropy.
Agora treinamos o modelo usando nossos dados.
history <- model %>% fit(
iris.training,
iris.trainLabels,
epochs = 200,
batch_size = 5,
validation_split = 0.2
)
plot(history)
Usamos 200 epochs (iterações) e 5 de batch_size (número de valores que são propagados pela rede). E na visualização acima, podemos observar os valores de acurácia e perda, para os dados de treino e teste.
Por fim, vamos fazer uso do nosso modelo, para prever as classes dos elementos separados para teste.
classes <- model %>% predict_classes(iris.test, batch_size = 128)
table(iris.testtarget, classes)
## classes
## iris.testtarget 0 1 2
## 1 23 0 0
## 2 0 15 0
## 3 0 5 15
Os comandos acima usam o modelo para realizar as predições dos dados de teste e mostram a tabela com os resultados, entretanto, podemos usar o comando evaluate() para sumarizar estes valores.
score <- model %>% evaluate(iris.test, iris.testLabels, batch_size = 128)
print(score)
## $loss
## [1] 0.2290177
##
## $acc
## [1] 0.9137931
Se quisermos melhorar a avaliação do nosso modelo, precisaremos reconfigurá-lo de formas diferentes. Nossas opções são:
model <- keras_model_sequential()
# Quando especificamos o modelo, adicionamos as camadas
model %>%
layer_dense(units = 8, activation = 'relu', input_shape = c(4)) %>%
layer_dense(units = 5, activation = 'relu') %>%
layer_dense(units = 3, activation = 'softmax')
model %>% compile(
loss = 'categorical_crossentropy',
optimizer = 'adam',
metrics = 'accuracy'
)
model %>% fit(
iris.training, iris.trainLabels,
epochs = 200, batch_size = 5,
validation_split = 0.2
)
score <- model %>% evaluate(iris.test, iris.testLabels, batch_size = 128)
print(score)
## $loss
## [1] 0.1507161
##
## $acc
## [1] 0.9137931
model <- keras_model_sequential()
# Aqui também especificamos o número adicional de unidades
model %>%
layer_dense(units = 28, activation = 'relu', input_shape = c(4)) %>%
layer_dense(units = 3, activation = 'softmax')
model %>% compile(
loss = 'categorical_crossentropy',
optimizer = 'adam',
metrics = 'accuracy'
)
model %>% fit(
iris.training, iris.trainLabels,
epochs = 200, batch_size = 5,
validation_split = 0.2
)
score <- model %>% evaluate(iris.test, iris.testLabels, batch_size = 128)
print(score)
## $loss
## [1] 0.1697371
##
## $acc
## [1] 0.9137931
Além das opções supracitadas, podemos tentar alterar os parâmetros do algoritmo de otimização que passamos para a função compile(). podemos usar por exemplo, o algoritmo de gradiente descendente através da função optimizer_sgd(), este algoritmo recebe como parâmetro uma taxa de aprendizado que pode ser modificada para fins específicos.
Dependendo dos dados que usamos de entrada, as computações realizadas para gerar os modelos podem ser custosas. Por este motivo, é desejável a habilidade de salvar o trabalho realizado e retomá-lo futuramente. Keras oferece algumas funções que facilitam este trabalho.