---
title: "R, fastai, fastaudio"
author: "Turgut Abdullayev"
date: "11/25/2020"
output: html_document
---


```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE, eval = TRUE)
```

## R interface to fastai

The fastai package provides R wrappers to [fastai](https://github.com/fastai/fastai).

The fastai library simplifies training fast and accurate neural nets using modern best practices. See the [fastai website](https://henry090.github.io/fastai/) to get started. The library is based on research into deep learning best practices undertaken at ```fast.ai```, and includes "out of the box" support for ```vision```, ```text```, ```tabular```, [audio](https://github.com/fastaudio/fastaudio), [time-series](https://github.com/tcapelle/timeseries_fastai) and ```collab``` (collaborative filtering) models. 

                                                                                             
```{r eval=T}
devtools::install_github('rstudio/reticulate',dependencies=FALSE)
devtools::install_github("henry090/fastai",dependencies=FALSE)
library(fastai)
install_fastai(gpu = TRUE)
detach("package:fastai", unload = TRUE)
```

## Dataset

Read train dataset:

```{r}
library(fastai)
library(magrittr)
library(zeallot)

path = "../input/rfcx-species-audio-detection"

train_fp = data.table::fread(paste(path,"train_fp.csv",sep="/"))
train_tp = data.table::fread(paste(path,"train_tp.csv",sep="/"))
train_fp$species_id = 0L

# shuffle
set.seed(42)
train_tp <- train_tp[sample(nrow(train_tp)),]

# read sample sub
sample_sub = data.table::fread(paste(path,"sample_submission.csv",sep="/"))

```

## Preprocess

Bind train datasets:

```{r}
#train = rbind(train_tp,train_fp)
train <- train_tp

summary(train)
```

Reshape it:

```{r}
train = data.table::dcast(data.table::melt(train[,1:2], id="recording_id", factorsAsStrings=FALSE), recording_id ~ value, drop=FALSE)
names(train) = names(sample_sub)
```

## Datablock

Create ```MultiCategory``` datablock because our target consists of several columns:

```{r}
mfcc = fastai::BasicMelSpectrogram(n_mels = 64)
tfms = list(AudioToSpec_from_cfg(mfcc))


auds = DataBlock(blocks = list(AudioBlock(), MultiCategoryBlock(encoded=TRUE, vocab=names(train)[-1])),  
                 splitter = RandomSplitter(),
                 item_tfms = tfms,
                 get_x=ColReader("recording_id",pref = paste(path,"train/",sep ="/"),suff = '.flac'), 
                 get_y=ColReader(names(train)[-1]))
```


## Dataloader

Prepare dataloader and print batch:

```{r}
audio_dbunch = auds %>% dataloaders(train, bs = 30)

audio_dbunch %>% one_batch()
```

See batch:

```{r fig.width=15,fig.height=15}
audio_dbunch %>% show_batch(figsize = c(15, 8.5), nrows = 3, ncols = 3, max_n = 9, dpi = 180)
```



## Learner

Create ```Learner``` and change channel number to 1:

```{r}
#learn = cnn_learner(audio_dbunch, 
#                    resnet101(), 
#                    config = list("n_in" = 1L), 
#                    opt_func = Adam,
#                    loss_func = BCEWithLogitsLossFlat(),
#                    metrics = accuracy_multi())

# alternatively work with models from timm package
learn = timm_learner(audio_dbunch, 
                     'resnest14d',
                     config=list("n_in"=1L), 
                     opt_func=Adam,
                     #loss_func=BCEWithLogitsLossFlat(),
                     metrics=accuracy_multi())

#learn %>% summary()
```


## Conclusion

Train your model:

```{r}
#tune = learn %>% fit_one_cycle(5, lr_max=slice(1e-3))
tune = learn %>% fine_tune(8,freeze_epochs = 1)
```

And make predictions for test dataset:

```{r}
# read test dataset
test_files = paste(paste(paste(path,'test',sep="/"),sample_sub$recording_id,sep = '/'),'.flac',sep = '')
head(test_files)

# predict
test_dl = learn$dls$test_dl(test_files)
predictions = learn$get_preds(dl = test_dl, with_decoded = TRUE)
head(predictions)

predictions = as.data.frame(as_array(predictions[[1]]))

names(predictions) = names(train)[-1]

# column bind
predictions = cbind(sample_sub[,1],predictions)

# write and exit
data.table::fwrite(predictions, "submission.csv")
```