Skip to content

Instantly share code, notes, and snippets.

@Athospd
Created August 25, 2021 21:42
Show Gist options
  • Save Athospd/05c856a1157b3b0201bf2349a5e4a337 to your computer and use it in GitHub Desktop.
Save Athospd/05c856a1157b3b0201bf2349a5e4a337 to your computer and use it in GitHub Desktop.
---
title: "Kaggle: Guess The Correlation (feat. {torchdatasets})"
date: "2021-01-10"
tags: ["torch", "deep learning", "r", "machine learning"]
categories: ["tutoriais", "r"]
banner: "img/banners/guess-the-correlation.png"
author: ["Athos"]
summary: "Solução para o Kaggle Guess The Correlation com {torch}."
draft: true
editor_options:
chunk_output_type: console
---
```{r, include=FALSE}
knitr::opts_chunk$set(
echo = TRUE,
warning = FALSE,
message = FALSE,
collapse = TRUE,
eval = FALSE
)
```
```{r setup}
library(torch)
library(torchdatasets)
library(torchvision)
library(tidyverse)
library(mestrado)
library(patchwork)
```
## Dados com {torchdatasets}
```{r}
train <- guess_the_correlation_dataset(
root = "~/datasets",
token = "~/kaggle.json",
download = TRUE,
split = "train"
)
submition <- guess_the_correlation_dataset(
root = "~/datasets",
token = "~/kaggle.json",
download = TRUE,
split = "submition"
)
```
Olhada no banco de dados
```{r}
# Número de imagens na base de treino
length(train)
# lista de ids e Y da base de treino
head(train$images)
# Dimensão das imagens
dim(train[2]$x)
```
```{r}
cria_template_bolinha <- function(kernel_size = 5) {
conv <- torch::nn_conv2d(1, 1, kernel_size, bias = FALSE)
template_bolinha <- torch::torch_tensor(array(c(0, 1, 1, 1, 0,
1, 1, 1, 1, 1,
1, 1, 1, 1, 1,
1, 1, 1, 1, 1,
0, 1, 1, 1, 0), dim = c(5,5)))
conv$parameters$weight$requires_grad_(FALSE) # torch, não otimizar esses params
conv$weight[1,1] <- template_bolinha
conv
}
transforma_imagem <- function(x) {
# retira os eixos da imagem
x <- x
ldim_x <- length(dim(x))
while(length(dim(x)) < 4) x <- x$unsqueeze(if(ldim_x == 2) 1 else 2)
# cria a máscara de centros das bolinhas
x <- x %>%
torch::torch_squeeze() %>%
torch::torch_less(0.1)
x
}
# x tem dimensao (H, W)
transforma_correlacao <- function(x) {
# encontra as coordenadas dos centros das bolinhas (X, Y)
x <- torch::torch_nonzero(x)
# calcula a correlação de pearson entre as coordenadas das bolinhas (X, Y)
# mean((x - mean(x)) * (y - mean(y)))/(sd(x)*sd(y))
media_desvpad <- torch::torch_std_mean(x$to(dtype = torch::torch_float()), dim = 1)
desvpad <- media_desvpad[[1]]
media <- media_desvpad[[2]]
corr <- x %>%
torch_subtract(media) %>%
torch_prod(dim = 2) %>%
torch_mean() %>%
torch_divide(torch_prod(desvpad)) %>%
torch_multiply(-1)
corr
}
```
```{r}
#
formato_para_o_ggplot <- function(item_do_df) {
item_do_df$x %>%
image_tensors_to_tbl() %>%
mutate(resp = paste("corr: ", scales::percent(item_do_df$y)))
}
map(1:4, ~train[.x]) %>%
map(~{.x$x <- transforma_imagem(.x$x); .x}) %>%
map_dfr(formato_para_o_ggplot) %>%
mutate(c1 = c1/max(c1)) %>%
ggpixelgrid(ncol = 4, label = resp)
```
## Dataloader
```{r}
minha_collate_fn <- function(batch) {
batch_transposto <- purrr::transpose(batch)
x <- torch::torch_stack(batch_transposto$x)
y <- torch::torch_tensor(unlist(batch_transposto$y), dtype = torch::torch_float())
id <- unlist(batch_transposto$id)
list(x = x, y = y, id = id)
}
```
```{r}
train_dl <- dataloader(
train, batch_size = 32,
shuffle = TRUE,
collate_fn = minha_collate_fn
)
```
## Device
```{r}
device <- torch_device(if(cuda_is_available()) "cuda" else "cpu")
```
## Modelo
### Modelo1
Apelar para calcular a correlação de pearson dos pontos da imagem.
1) achar o centro dos pontos
2) calcular a correlação entre X e Y desses centros
```{r}
# NN module
modelo_corr <- torch::nn_module(
"ModeloCorr",
initialize = function() {
self$lin <- nn_linear(
in_features = 1,
out_features = 1,
bias = TRUE
)
},
forward = function(batch) {
# ceu estrelado
x <- batch %>% transforma_imagem()
# certifica que tem a dimensao do Batch
if(length(dim(x)) < 3) x <- x$unsqueeze(1)
# correlação de pearson
x <- purrr::map(
torch::torch_unbind(x),
transforma_correlacao
) %>%
torch::torch_stack()
x <- x$unsqueeze(2) %>% self$lin()
x$squeeze()
}
)
modelo1 <- modelo_corr()
print(modelo1)
```
```{r}
modelo1$parameters
```
## Loss
```{r}
criterio <- torch::nn_mse_loss()
```
## Optimizer
```{r}
otimizador <- torch::optim_adam(modelo1$parameters, lr = 0.01)
```
## Loop de treinamento
```{r}
losses <- c()
# we can then loop trough the elements of the dataloader with
i <- 0
pb <- progress::progress_bar$new(total = length(train_dl), format = ":current / :total [:bar] :eta :percent - RMSE: :loss")
plot(1:length(train_dl), numeric(length(train_dl)), type = "l", ylim = c(0, 0.5))
for(batch in enumerate(train_dl)) {
i <- i + 1
otimizador$zero_grad()
y_pred <- batch[[1]] %>%
torchvision::transform_crop(5, 22, 125, 127) %>%
modelo1()
y_obs <- batch[[2]]
loss <- criterio(y_pred, y_obs)
loss$backward()
losses <- c(losses, as.numeric(loss))
otimizador$step()
pb$tick(tokens = list(loss = sqrt(as.numeric(loss))))
if(i %% 10 == 0)
points(i, as.numeric(loss))
}
plot(losses, type = "l", col = "royalblue")
```
## Predições
```{r}
submition_dl <- dataloader(submition, batch_size = 50000)
for(submition_item in enumerate(submition_dl)) {
df <- tibble::tibble(
id = submition_item[[3]],
corr = as.numeric( modelo1(submition_item[[1]]))
)
# submition_df <- submition_df %>% left_join(df, by = "id")
}
write_csv(df, "submit_modelo1.csv")
hist(df$corr)
hist(train$images$corr)
```
## Modelo2
CNN tradicional ---> invariante no espaço
1) MUITOS PARAMETROS
2) PERDA DE INFORMACAO ESPACIAL
```{r}
# NN module
modelo_marlesson <- torch::nn_module(
"ModeloMarlesson",
initialize = function() {
self$conv1 <- torch::nn_conv2d(1, out_channels = 32, kernel_size = c(3,3))
self$conv2 <- torch::nn_conv2d(32, out_channels = 64, kernel_size = c(5,5))
self$dense1 <- torch::nn_linear(12544, 256)
self$dense2 <- torch::nn_linear(256, 128)
self$dense3 <- torch::nn_linear(128, 1)
},
forward = function(batch) {
# ceu estrelado
x <- batch %>% # (B, 150, 150)
torchvision::transform_crop(5, 22, 125, 127) %>% # (B, 125, 127)
torch::torch_unsqueeze(2) %>% # (B, 1, 125, 127)
self$conv1() %>% # (B, 32, 123, 125)
torch::nnf_relu() %>%
torch::nnf_avg_pool2d(kernel_size = c(2,2)) %>% # (B, 32, 61, 62)
self$conv2() %>% # (B, 64, 57, 58)
torch::nnf_relu() %>%
torch::nnf_avg_pool2d(kernel_size = c(4,4)) %>% # (B, 64, 14, 14)
torch::torch_flatten(start_dim = 2) %>% # (B, 12544)
self$dense1() %>%
torch::nnf_relu() %>%
self$dense2() %>%
torch::nnf_relu() %>%
self$dense3()
x
}
)
modelo2 <- modelo_marlesson()
modelo2 <- modelo2$to(device = device)
print(modelo2)
```
```{r}
# teste
batch <- torch_stack(list(train[1]$x, train[2]$x))
modelo2(batch$to(device = device))
```
```{r}
criterio <- torch::nn_mse_loss()
otimizador <- torch::optim_adam(modelo2$parameters, lr = 0.1)
losses <- c()
# we can then loop trough the elements of the dataloader with
i <- 0
pb <- progress::progress_bar$new(total = length(train_dl), format = ":current / :total [:bar] :eta :percent - RMSE: :loss")
plot(1:length(train_dl), numeric(length(train_dl)), type = "l", ylim = c(0, 0.5))
for(batch in enumerate(train_dl)) {
i <- i + 1
otimizador$zero_grad()
y_pred <- modelo2(batch[[1]]$to(device = device))
y_obs <- batch[[2]]$to(device = device)
loss <- criterio(y_pred$squeeze(), y_obs)
loss$backward()
loss_r <- as.numeric(loss$to(device = "cpu"))
losses <- c(losses, loss_r)
otimizador$step()
pb$tick(tokens = list(loss = sqrt(loss_r)))
if(i %% 10 == 0)
points(i, loss_r)
}
plot(losses, type = "l", col = "royalblue")
```
```{r}
library(magrittr)
printscreen <- torchvision::magick_loader("content/blog/Screenshot from 2021-01-10 19-43-17.png")
printscreen_torch <- printscreen %>% # operador "então" "depois"
torchvision::transform_to_tensor() %>%
torchvision::transform_rgb_to_grayscale() %>%
torch::torch_unsqueeze(1) %>%
torch::torch_unsqueeze(1)
correlacao_predita <- modelo1(printscreen_torch)
as.numeric(correlacao_predita)
```
### Modelo3
CNN com kernel retangular ----> considera a posicao das coisas
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment