Notas para contenedor de docker:

Comando de docker para ejecución de la nota de forma local:

nota: cambiar <ruta a mi directorio> por la ruta de directorio que se desea mapear a /datos dentro del contenedor de docker.

docker run --rm -v <ruta a mi directorio>:/datos --name jupyterlab_r_kernel_openblas -p 8889:8888 -d palmoreck/jupyterlab_r_kernel_openblas:1.1.0

password para jupyterlab: qwerty

Detener el contenedor de docker:

docker stop jupyterlab_r_kernel_openblas

Al ejecutar el run anterior se descargará la imagen y posteriormente se instalará OpenBLAS adaptado a su sistema. Esto tardará $10-15$ minutos aproximadamente. Pueden revisar de vez en vez con el commando:

docker logs jupyterlab_r_kernel_openblas

hasta que salga un mensaje del tipo: ...Installed kernelspec ir in /usr/local/share/jupyter/kernels/ir...The Jupyter Notebook is running at... y poder acceder al puerto 8888 de sus máquinas

Nota: Lo anterior se realizó de esta forma (construir una imagen de docker con software simple y posteriormente instalar el software especializado) pues si hubiera construído la imagen de docker adaptada a mi máquina, es muy probable que se tendría que haber adaptado nuevamente a sus máquinas. Ver: docker images with architecture-optimisation

Documentación de la imagen de docker palmoreck/jupyterlab_r_kernel_openblas:1.1.0 en liga.



In [1]:
install.packages("microbenchmark",lib="/usr/local/lib/R/site-library/",
                 repos="https://cran.itam.mx/",verbose=TRUE)


system (cmd0): /usr/lib/R/bin/R CMD INSTALL

foundpkgs: microbenchmark, /tmp/RtmpUFXbQV/downloaded_packages/microbenchmark_1.4-7.tar.gz

files: /tmp/RtmpUFXbQV/downloaded_packages/microbenchmark_1.4-7.tar.gz

1): succeeded '/usr/lib/R/bin/R CMD INSTALL -l '/usr/local/lib/R/site-library' /tmp/RtmpUFXbQV/downloaded_packages/microbenchmark_1.4-7.tar.gz'


In [2]:
library(microbenchmark)

Implementaciones de la API standard de BLAS y LAPACK

En Handle different versions of BLAS and LAPACK se explica que BLAS: Basic Linear Algebra Subprograms y Linear Algebra Package: LAPACK además de ser implementaciones, también son API* standard para operaciones básicas del álgebra lineal. Muchas implementaciones de la API existen. Un ejemplo de implementaciones son las incluidas al instalar R o Python. Otras son las que se pueden instalar vía línea de comando:

sudo apt-get install -y libblas3 libblas-dev liblapack3 liblapack-dev

en un sistema operativo Ubuntu por ejemplo. Ver libblas3 libblas-dev liblapack3 liblapack-dev.

*Ver Application Programming Interface: API para una explicación de lo que es una API.

Sin embargo existen otras implementaciones de la API que están optimizadas para la arquitectura de nuestras máquinas, por ejemplo:

Revisaremos en esta nota algunas comparaciones en tiempo de ejecución de la API de BLAS y LAPACK que viene integrada en R vs la que provee OpenBLAS.

OpenBLAS

En la documentación de OpenBLAS podemos revisar la liga supported-cpus-and-operating-systems para conocer procesadores y sistemas operativos soportados. En específico, la instalación que se realiza con la imagen de docker detallada al inicio de la nota utiliza Precompiled installation packages.

Las siguientes mediciones fueron calculadas con un procesador: (hay que usar el kernel de Python3 para la siguiente línea)


In [1]:
%%bash
lscpu


Architecture:        x86_64
CPU op-mode(s):      32-bit, 64-bit
Byte Order:          Little Endian
CPU(s):              8
On-line CPU(s) list: 0-7
Thread(s) per core:  2
Core(s) per socket:  4
Socket(s):           1
NUMA node(s):        1
Vendor ID:           GenuineIntel
CPU family:          6
Model:               60
Model name:          Intel(R) Core(TM) i7-4790 CPU @ 3.60GHz
Stepping:            3
CPU MHz:             2535.912
CPU max MHz:         4000.0000
CPU min MHz:         800.0000
BogoMIPS:            7195.53
Virtualization:      VT-x
L1d cache:           32K
L1i cache:           32K
L2 cache:            256K
L3 cache:            8192K
NUMA node0 CPU(s):   0-7
Flags:               fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm cpuid_fault epb invpcid_single pti ssbd ibrs ibpb stibp tpr_shadow vnmi flexpriority ept vpid fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid xsaveopt dtherm ida arat pln pts md_clear flush_l1d

Ejemplos de la implementación de BLAS y LAPACK vía la instalación de R

En R a diferencia de Python podemos cambiar de implementación con las siguientes líneas de comando (hay que usar el kernel de Python3 para la siguiente línea):


In [2]:
%%bash
sudo update-alternatives --config libblas.so.3-x86_64-linux-gnu


There are 2 choices for the alternative libblas.so.3-x86_64-linux-gnu (providing /usr/lib/x86_64-linux-gnu/libblas.so.3).

  Selection    Path                                             Priority   Status
------------------------------------------------------------
* 0            /usr/lib/x86_64-linux-gnu/openblas/libblas.so.3   40        auto mode
  1            /usr/lib/x86_64-linux-gnu/blas/libblas.so.3       10        manual mode
  2            /usr/lib/x86_64-linux-gnu/openblas/libblas.so.3   40        manual mode

Press <enter> to keep the current choice[*], or type selection number: 

In [3]:
%%bash
sudo update-alternatives --config liblapack.so.3-x86_64-linux-gnu


There are 2 choices for the alternative liblapack.so.3-x86_64-linux-gnu (providing /usr/lib/x86_64-linux-gnu/liblapack.so.3).

  Selection    Path                                               Priority   Status
------------------------------------------------------------
* 0            /usr/lib/x86_64-linux-gnu/openblas/liblapack.so.3   40        auto mode
  1            /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3     10        manual mode
  2            /usr/lib/x86_64-linux-gnu/openblas/liblapack.so.3   40        manual mode

Press <enter> to keep the current choice[*], or type selection number: 

Entonces desde una terminal se ejecutan las líneas anteriores y elegimos la opción $1$ en ambas. Se obtendrá un output similar a:

update-alternatives: using /usr/lib/x86_64-linux-gnu/blas/libblas.so.3 to provide /usr/lib/x86_64-linux-gnu/libblas.so.3 (libblas.so.3-x86_64-linux-gnu) in manual mode
update-alternatives: using /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3 to provide /usr/lib/x86_64-linux-gnu/liblapack.so.3 (liblapack.so.3-x86_64-linux-gnu) in manual mode

para la primera y segunda línea respectivamente.

Comprobamos que estamos usando la implementación que está en la instalación de R (hay que usar el kernel de R para la siguiente línea) con:


In [2]:
sessionInfo()


R version 3.6.3 (2020-02-29)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 18.04.3 LTS

Matrix products: default
BLAS:   /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.7.1
LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.7.1

locale:
 [1] LC_CTYPE=C.UTF-8       LC_NUMERIC=C           LC_TIME=C.UTF-8       
 [4] LC_COLLATE=C.UTF-8     LC_MONETARY=C.UTF-8    LC_MESSAGES=C.UTF-8   
 [7] LC_PAPER=C.UTF-8       LC_NAME=C              LC_ADDRESS=C          
[10] LC_TELEPHONE=C         LC_MEASUREMENT=C.UTF-8 LC_IDENTIFICATION=C   

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] microbenchmark_1.4-7

loaded via a namespace (and not attached):
 [1] compiler_3.6.3  IRdisplay_0.7.0 pbdZMQ_0.3-3    tools_3.6.3    
 [5] htmltools_0.4.0 pillar_1.4.3    base64enc_0.1-3 crayon_1.3.4   
 [9] Rcpp_1.0.4      uuid_0.1-4      IRkernel_1.1    jsonlite_1.6.1 
[13] digest_0.6.25   repr_1.1.0      rlang_0.4.5     evaluate_0.14  

y hacemos algunas pruebas: no realizar los siguientes writes en máquinas con menos de 11gb


In [3]:
set.seed(2020)
m<-10**4
r<-10**4
A <- matrix(runif(m*r), m, r)
write(format(A,digits=16), "A_R.txt", ncolumns=r)

In [1]:
set.seed(2021)
r<-10**4
n<-10**4
B <- matrix(runif(r*n), r, n)
write(format(B,digits=16), "B_R.txt", ncolumns=n)

Multiplicación de matrices sin openBLAS

Mientras se ejecuta la siguiente celda se sugiere en la terminal ejecutar en la línea de comando htop


In [3]:
m<-10**4
r<-10**4
A<-scan("A_R.txt",what = numeric(0),sep='')
A_mat<-matrix(A,nrow=m,ncol=r,byrow=T)

In [4]:
rm(A)

Mientras se ejecuta la siguiente celda se sugiere en la terminal ejecutar en la línea de comando htop


In [5]:
r<-10**4
n<-10**4
B<-scan("B_R.txt",what = numeric(0),nmax=r*n,sep='')
B_mat<-matrix(B,nrow=r,ncol=n,byrow=T)

In [6]:
rm(B)

In [ ]:
mbk<-microbenchmark(
    A_mat%*%B_mat,
    times=2
    )

después de $5$ min no terminó el proceso anterior...

Ejemplos de la implementación de BLAS y LAPACK vía OpenBLAS

Para el caso de OpenBLAS volvemos en la terminal a ejecutar las líneas de comando: (hay que usar el kernel de Python3 para la siguiente línea)


In [1]:
%%bash
sudo update-alternatives --config libblas.so.3-x86_64-linux-gnu


There are 2 choices for the alternative libblas.so.3-x86_64-linux-gnu (providing /usr/lib/x86_64-linux-gnu/libblas.so.3).

  Selection    Path                                             Priority   Status
------------------------------------------------------------
  0            /usr/lib/x86_64-linux-gnu/openblas/libblas.so.3   40        auto mode
* 1            /usr/lib/x86_64-linux-gnu/blas/libblas.so.3       10        manual mode
  2            /usr/lib/x86_64-linux-gnu/openblas/libblas.so.3   40        manual mode

Press <enter> to keep the current choice[*], or type selection number: 

In [2]:
%%bash
sudo update-alternatives --config liblapack.so.3-x86_64-linux-gnu


There are 2 choices for the alternative liblapack.so.3-x86_64-linux-gnu (providing /usr/lib/x86_64-linux-gnu/liblapack.so.3).

  Selection    Path                                               Priority   Status
------------------------------------------------------------
  0            /usr/lib/x86_64-linux-gnu/openblas/liblapack.so.3   40        auto mode
* 1            /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3     10        manual mode
  2            /usr/lib/x86_64-linux-gnu/openblas/liblapack.so.3   40        manual mode

Press <enter> to keep the current choice[*], or type selection number: 

Entonces desde una terminal se ejecutan las líneas anteriores y elegimos la opción $0$ en ambas.

Comprobamos que estamos usando la implementación que está en la instalación de R (hay que usar el kernel de R para la siguiente línea) con:


In [3]:
sessionInfo()


R version 3.6.3 (2020-02-29)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 18.04.3 LTS

Matrix products: default
BLAS:   /usr/lib/x86_64-linux-gnu/openblas/libblas.so.3
LAPACK: /usr/lib/x86_64-linux-gnu/libopenblasp-r0.2.20.so

locale:
 [1] LC_CTYPE=C.UTF-8       LC_NUMERIC=C           LC_TIME=C.UTF-8       
 [4] LC_COLLATE=C.UTF-8     LC_MONETARY=C.UTF-8    LC_MESSAGES=C.UTF-8   
 [7] LC_PAPER=C.UTF-8       LC_NAME=C              LC_ADDRESS=C          
[10] LC_TELEPHONE=C         LC_MEASUREMENT=C.UTF-8 LC_IDENTIFICATION=C   

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] microbenchmark_1.4-7

loaded via a namespace (and not attached):
 [1] compiler_3.6.3  IRdisplay_0.7.0 pbdZMQ_0.3-3    tools_3.6.3    
 [5] htmltools_0.4.0 pillar_1.4.3    base64enc_0.1-3 crayon_1.3.4   
 [9] Rcpp_1.0.4      uuid_0.1-4      IRkernel_1.1    jsonlite_1.6.1 
[13] digest_0.6.25   repr_1.1.0      rlang_0.4.5     evaluate_0.14  

y hacemos algunas pruebas: no realizar los siguientes writes en máquinas con menos de 11gb


In [3]:
set.seed(2020)
m<-10**4
r<-10**4
A <- matrix(runif(m*r), m, r)
write(format(A,digits=16), "A_R.txt", ncolumns=r)

In [1]:
set.seed(2021)
r<-10**4
n<-10**4
B <- matrix(runif(r*n), r, n)
write(format(B,digits=16), "B_R.txt", ncolumns=n)

Multiplicación de matrices con openBLAS

Mientras se ejecuta la siguiente celda se sugiere en la terminal ejecutar en la línea de comando htop


In [4]:
m<-10**4
r<-10**4
A<-scan("A_R.txt",what = numeric(0),sep='')
A_mat<-matrix(A,nrow=m,ncol=r,byrow=T)

In [5]:
rm(A)

Mientras se ejecuta la siguiente celda se sugiere en la terminal ejecutar en la línea de comando htop


In [6]:
r<-10**4
n<-10**4
B<-scan("B_R.txt",what = numeric(0),nmax=r*n,sep='')
B_mat<-matrix(B,nrow=r,ncol=n,byrow=T)

In [7]:
rm(B)

Mientras se ejecuta la siguiente celda se sugiere en la terminal ejecutar en la línea de comando htop


In [10]:
mbk<-microbenchmark(
    A_mat%*%B_mat,
    times=2
    )

In [11]:
print(mbk)


Unit: seconds
            expr      min       lq     mean   median      uq     max neval
 A_mat %*% B_mat 11.16604 11.16604 11.18097 11.18097 11.1959 11.1959     2

Resultados

  • Para la multiplicación de matrices con OpenBLAS se observa una reducción de tiempo siendo la implementación vía OpenBLAS más rápida que la que viene integrada en la instalación de R. De hecho la de R no terminó después de $5$ min en la línea de microbenchmark.

Referencias:

Para referencias sobre el uso de BLAS y LAPACK con C ver:

Hay implementaciones en paralelo de BLAS para sistemas de memoria distribuida. Ver por ejemplo:

También NVIDIA tiene su propia implementación de BLAS para uso con GPU's: CUBLAS y su implementación de LAPACK: CUSOLVER. Para más sobre CUBLAS y CUSOLVER ver: C/extensiones_a_C/CUDA/CUBLAS y C/extensiones_a_C/CUDA/CUSOLVER/

Otras referencias para uso de GPU's con implementaciones de BLAS y LAPACK se encuentran:

Para otra implementación de BLAS y LAPACK ver: