-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtorch_and_rcpp.qmd
126 lines (85 loc) · 3.25 KB
/
torch_and_rcpp.qmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
---
title: "Torch & Rcpp"
lang: fr
format: html
toc: true
author:
- Annaig De-Walsche
- Barbara Bricout
- Tristan Mary-Huard
- Armand Favrot
- Félix Cheysson
- Théodore Vanrenterghem
date: 20/08/2023
---
```{r}
#| message: false
#| warning: false
library(Rcpp)
library(RcppArmadillo)
library(torch)
library(tictoc)
library(bench) # comparaison des vitesses
library(ggplot2)
library(ggbeeswarm)
```
## Torch on R
La librairie {torch} de R permet la manipulation de tenseur en R. Elle permet notamment de faire la différenciation automatique, c-a-d d'évaluer numériquement le gradient d'une fonction et d'effectuer des descentes de gradient.
[Présentation finistR2022](https://stateofther.github.io/finistR2022/autodiff.html)
[Torch and Automatic differentiation](https://stateofther.netlify.app/post/rentree2022/AutomatedDifferentiation.pdf)
## Rcpp
L'utilisation de {Rcpp} permet d'exporter des fonctions `C++` en R. Les fonctions seront alors directement utilisables dans un script et avec des arguments R. Ainsi on peut tirer partie de la compilation d'un code `C++`, et accélérer de nombreux calculs algébriques.
Pour le calcul algébrique il est utile d'intégrer le package {RcppArmadillo} qui donne accès à la librairie {Armadillo} de `C++` lorsque l'on appel une fonction {Rcpp} dans R.
[Présentation finistR2018](https://stateofther.netlify.app/post/bases-rcpp/)
### Example
Dans cet exemple nous allons calculer la perte d'une fonction logistique en R et en `C++`. Puis comparer les résultats avec le package {bench} de R.
#### Coder la fonction en `C++`
```{r, eval = FALSE, file = "logisticloss.cpp"}
```
#### Appel et compilation du script depuis R avec la fonction `sourceCpp()` de {Rcpp}
```{r}
sourceCpp(file = "logisticloss.cpp")
```
#### Fonction loss en R
```{r}
loss_R <- function(theta, y, x) {
odds <- x %*% theta
log_lik <- sum(y * odds - log(1 + exp(odds)))
return(-as.numeric(log_lik))
}
```
#### Résultats
On remarque que les résultats sont identiques pour la fonction {Rcpp} et la fonction en R.
```{r}
theta = c(0.5, 0.1)
y = 1.0
x = matrix(c(0.1, 0.2), 1, 2)
```
```{r}
loss_cpp(theta, y, x)
```
```{r}
loss_R(theta, y, x)
```
Dans l'optique de comparer les performances de ces deux fonctions on utilise la fonction `mark()` du package {bench}.
```{r}
n_covar <- 300
size <- 1000
theta <- rnorm(n_covar)
y <- as.numeric(rbinom(size, 1, 0.3))
x <- matrix(rnorm(size * n_covar), size, n_covar)
```
```{r}
comp_tbl <- bench::mark(
loss_R(theta = theta, y = y, x = x),
loss_cpp(theta = theta, y = y, x = x),
iterations = 1000
)
autoplot(comp_tbl)
```
Comme on peut le voir sur le graphique plus haut la fonction `loss_cpp()` est environ **2 fois** plus efficace que la fonction `loss_R()`.
#### Attention aux librairies `BLAS` et `LAPACK`
La librairie `BLAS` de `OpenBlas` présentée lors de cette même session ne fonctionne pas correctement avec {Rcpp}. On observe une baisse de fonctionnement **très quantitative** (facteur 100). La librairie `BLAS` de `Intel MKL` reste quant à elle plus efficace.
## Références
- [Cours state of the R (2023)](https://stateofther.netlify.app/post/variational-autoencoder-with-torch/)
- [finistR2022 - Torch Auto Diff](https://stateofther.github.io/finistR2022/autodiff.html)