Apple Silicon M1で R が動いて8.7倍速い件 (aarch64ネイティブ) ベンチもあるよ! -2021/4追記

2021/4 この記事の続きを、こちらに追記しています：

https://qiita.com/taiyodayo/items/c31c1aa1c5e642024cfe

以下は2021/2に書いた記事です：

# 新しいもの好きのMacユーザさんお待たせしました！
```
R version 4.0.4 (2021-02-15) -- "Lost Library Book"
```
から、まだテスト用ですが Apple Silicon / ARM64 に対応したビルドが公開されました。

RStudioがまだ対応していませんのでそれ目的にはまだ使えませんが、
(Jupyter Labからなら使えそうです)
Tidyverseなども対応したとの事でこれは期待です！
既存のスクリプトがどこまで早く実行できるか楽しみですね。

導入にはいくつか方法がありますが、
・Homebrew
・手動で開発版をインストール
ここでは単純に Homebrew を試してみます。


なお手動で詳しく調べたい方は、
R-Blogger にて、 hrbrmstr 氏のブログに手順が掲載されていました。
https://www.r-bloggers.com/2021/02/fully-native-m1-apple-silicon-r-setup/

必須フレームワークなどの一部が手動でインストールが必要など、ナイス情報が多いので
homebrew でやる方も一度こちらのスクリプトに一度目を通してからが安心かと思います。
一部こちらからスクリプトを以下に拝借しています。

＃なおあくまで開発版ですので、今後数日以内にも情報が変わる場合があります。GCC最新版を入れたりx86-64環境を削除する部分もあるので、お試し用のMacで実行なさってくださいね。
ウチはデプロイは全て docker なのでローカルはガシガシ弄っちゃいます。

# homebrew を一度抜いて入れ直す

最新のHomebrew3.0より前のリリースをインストール済みの場合、
一度完全削除して入れ直す必要があります。
brew コマンドを arch 指定してエイリアス化していた方は、そちらもアンエイリアスしましょう。

（インストール済みのパッケージを復元したい方は、```brew leaves > list.txt``` でリストを保存して、再インストール後に ```xargs brew install < list.txt``` すると同じパッケージを入れ直す事ができます。）

```
# uninstall x86_64 homebrew
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/uninstall.sh)"

# make sure you unalias "brew" if you aliased it with "arch"

# install arm64 homebrew
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
# install wget (to make sure stuff is working)
brew install wget
```

# R 入れる
```
brew install R
```
これはもうめちゃ単純ですね。
これだけでRが入ります！


```
❯ R --version 
R version 4.0.4 (2021-02-15) -- "Lost Library Book"
Copyright (C) 2021 The R Foundation for Statistical Computing
Platform: aarch64-apple-darwin20.3.0 (64-bit)
```

# フレームワーク類を手動で入れる <- これもう必要ないですね2021/4 メモとして残しておきます
上記のままだと、```install.packages("pacman")```などとしてもエラーで止まってしまうと思います。
まず、homebrewで必要なパッケージを追加します

```
# install libxml2 and ccache (unless you don't use ccache)
brew install libxml2 ccache libgit2 unixodbc
```

続いて、これは必要かどうかわからないのですが、
hrbrmstr 氏の方法を参考に、ライブラリとフレームワークを手動でインストールする必要があるかもしれません。(勢いでバーっとやったら動いてしまったw)
参考までに転記しておきます：

```
# place for r-libs
mkdir ~/Downloads/libs-arm64/

# go there
cd ~/Downloads/libs-arm64

# grab'em from https://mac.r-project.org/libs-arm64/
for dl in $(curl -sS "https://mac.r-project.org/libs-arm64/" \
  | xmllint --html --xpath '//td/a[contains(@href, 'tar.gz')]/@href' 2>/dev/null - \
  | sed -e 's/ href="//g' -e 's/"/\n/g'); do wget https://mac.r-project.org/libs-arm64/${dl} ; done

# prime sudo
sudo ls ~/Downloads/libs-arm64

# extract'em
for gz in $(ls ~/Downloads/libs-arm64/*gz); do  
  sudo tar fvxz ${gz} -C /
done

# grab r-devel
wget https://mac.r-project.org/big-sur/R-devel/arm64/R-devel.tar.gz

# extract it
tar fvxz R*.tar.gz -C /
```


# envを指定します
catalina以降は zsh が標準ですので、 ~/.zshrc に以下の一行を最後に追加し、読み込みます。

```
# put this in your shell startup (macOS folks shld get used to zsh, so ~/.zshrc is a good place to stick it at the end)
export PATH=/opt/R/arm64/bin:$PATH

# 変更を読み込む
source ~/.zshrc
```


# 試してみよう！

```
Rscript -e "pacman::p_load(tidyverse)"
```
ひゃっほう！普通に使えました！
以下はSessionInfo()です：

```
> sessionInfo()
R version 4.0.4 (2021-02-15)
Platform: aarch64-apple-darwin20.3.0 (64-bit)
Running under: macOS Big Sur 11.2.1

Matrix products: default
BLAS:   /opt/homebrew/Cellar/openblas/0.3.13/lib/libopenblasp-r0.3.13.dylib
LAPACK: /opt/homebrew/Cellar/r/4.0.4/lib/R/lib/libRlapack.dylib

locale:
[1] ja_JP.UTF-8/UTF-8/ja_JP.UTF-8/C/ja_JP.UTF-8/ja_JP.UTF-8

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

other attached packages:
[1] ggraph_2.0.4   devtools_2.3.2 usethis_2.0.1  ggplot2_3.3.3

loaded via a namespace (and not attached):
 [1] Rcpp_1.0.6         pillar_1.4.7       compiler_4.0.4     viridis_0.5.1
 [5] remotes_2.2.0      prettyunits_1.1.1  tools_4.0.4        digest_0.6.27
 [9] testthat_3.0.2     pkgbuild_1.2.0     pkgload_1.1.0      viridisLite_0.3.0
[13] memoise_2.0.0      lifecycle_0.2.0    tibble_3.0.6       gtable_0.3.0
[17] pkgconfig_2.0.3    rlang_0.4.10       igraph_1.2.6       tidygraph_1.2.0
[21] DBI_1.1.1          cli_2.3.0          ggrepel_0.9.1      fastmap_1.1.0
[25] gridExtra_2.3      withr_2.4.1        dplyr_1.0.4        graphlayouts_0.7.1
[29] generics_0.1.0     desc_1.2.0         fs_1.5.0           vctrs_0.3.6
[33] rprojroot_2.0.2    grid_4.0.4         tidyselect_1.1.0   glue_1.4.2
[37] R6_2.5.0           processx_3.4.5     pacman_0.5.1       sessioninfo_1.1.1
[41] polyclip_1.10-0    farver_2.0.3       tweenr_1.0.1       tidyr_1.1.2
[45] purrr_0.3.4        callr_3.5.1        magrittr_2.0.1     MASS_7.3-53
[49] scales_1.1.1       ps_1.5.0           ellipsis_0.3.1     assertthat_0.2.1
[53] ggforce_0.3.2      colorspace_2.0-0   munsell_0.5.0      cachem_1.0.4
[57] crayon_1.4.1
```

Apple Silicon M1の圧倒的な「熱くならない」性能はマジですごいです。
Rも動けば、ローカルで実行できるタスクの幅が広がりますね。嬉しい！

JupyterlabやVSCodeなども既にネイティブで動いているので、
RStudioの対応待ちの間、他のR向けGUIを試してみるのも面白いかもしれません。

Dockerもテスト版の扱いですが、既にAMD64バイナリのトランスコード実行などは割と安定して動いているので
Apple Silicon 周りが早速面白くなってきました！


# せっかくなのでベンチマークも取ってみた <- 2021/4 追記 もっと速くなったよ！

https://www.alexejgossmann.com/benchmarking_r/
を参考に、ベンチマークを取ってみました

```
# MacBook Pro (13-inch, M1, 2020)
pacman::p_load(microbenchmark)

set.seed(2017)
n <- 10000
p <- 100
X <- matrix(rnorm(n*p), n, p)
y <- X %*% rnorm(p) + rnorm(100)

check_for_equal_coefs <- function(values) {
  tol <- 1e-12
  max_error <- max(c(abs(values[[1]] - values[[2]]),
                     abs(values[[2]] - values[[3]]),
                     abs(values[[1]] - values[[3]])))
  max_error < tol
}

mbm <- microbenchmark(
               "lm" = { b <- lm(y ~ X + 0)$coef },
               "pseudoinverse" = {
                 b <- solve(t(X) %*% X) %*% t(X) %*% y},
               "linear system" = {
                 b <- solve(t(X) %*% X, t(X) %*% y)},
               check = check_for_equal_coefs)

mbm
2021/2 時点（R4.0.4)
Unit: milliseconds
          expr       min       lq     mean   median       uq       max neval
            lm 48.381271 52.94970 59.08991 54.19146 57.52372 101.80624   100
 pseudoinverse 12.097091 15.61460 24.98325 18.77353 24.74903  85.70808   100
 linear system  8.435914 10.31964 15.69662 12.77080 14.71629 107.23456   100

2021/4 時点(R4.0.5) - 更に10%くらい速くなってたよ！
Unit: milliseconds
          expr       min        lq     mean   median       uq      max neval
            lm 49.051744 50.826265 52.95558 51.80733 52.80433 65.09148   100
 pseudoinverse 11.956379 14.711989 17.91940 16.34217 18.85711 34.07059   100
 linear system  8.523859  9.505297 11.80922 10.88540 12.43758 60.45782   100


```
#さてこれは速いのか？
事務所内のマシン、ついでに Docker/QEMU でのAMD64動的エミュ(Rosetta2で静的コンパイルできない<b>最遅</b>の方法)と比べてみます：

```
# Intel MacBook Pro 16 inch (2019) Core i9 (8-core) @ 2.3GHz
Unit: milliseconds
          expr       min        lq      mean    median       uq      max neval
            lm  97.25333 106.07812 110.52555 109.50081 113.4430 133.7976   100
 pseudoinverse 126.66369 137.49634 143.64142 141.95922 148.4088 173.3653   100
 linear system  66.99625  75.51475  80.96854  79.02423  85.9040 123.8282   100

# Linux マシン (GPUホスト)
# model name	: Intel(R) Core(TM) i9-7900X CPU @ 3.30GHz
# Linux 5.4.0-65-generic #73-Ubuntu SMP
Unit: milliseconds
          expr       min        lq      mean    median        uq       max neval
            lm  82.07969  84.43838  88.18862  87.02851  89.37451 108.46766   100
 pseudoinverse 110.66148 113.61129 116.64092 115.37820 117.84845 139.03118   100
 linear system  58.79841  61.27981  64.23350  62.86225  65.15092  83.25834   100

# Apple Silicon - docker/qemu AMD64 simulation 
# via 'docker run -p 9999:8888 jupyter/datascience-notebook'
Unit: milliseconds
          expr       min        lq     mean    median        uq       max neval
            lm 1413.5442 1438.1617 1450.816 1443.4323 1457.1110 1506.8140   100
 pseudoinverse 1110.0444 1114.0501 1125.837 1115.8733 1129.0334 1276.9825   100
 linear system  580.3113  583.0921  589.804  584.6334  587.8716  633.4169   100

```

えー、こちらは実行時間なので、「低い方が速い」なのですが...

# やべえじゃん M1www マジで速い！！！
(2021/4 のスコアで下記の倍率計算しなおしました)
特にpseudoinverse(擬似逆行列)とか、インテルMBPの<b>「8.7倍」</b>速い...だとぅ??
14コア(28ht)のデスクトップ用CPU、Core i9-7900X と比較しても<b>「7倍」</b>速い
そしてQEMUのAMD64エミュと比較すると<b>「68.3倍」</b>!!

こりゃもう乗るしかないビッグウェーブが来てますね！

と、なんだかおらワクワクすっぞな感じで記事を終わります
次は tensorflow on apple silicon やってみよかなー？



# おまけ
RStudioもARM64へポートされた方がいらっしゃいました。
https://hub.docker.com/r/amoselb/rstudio-m1
docker for mac previewビルドを入れたら、下記を実行します：

```
docker run -d -p 8787:8787 -e PASSWORD=YOURPASSWORD amoselb/rstudio-m1
```

ですが、こちらはまだ最適化が進んでいないのかな？
上記ベンチでは下記のようなスコアとなりました。
これでもどのインテルCPUよりも速いのですが、伸びふちがまだまだありますね

```
Unit: milliseconds
          expr      min       lq     mean   median       uq       max neval
            lm 90.76642 93.50796 98.29742 95.22010 98.27842 122.62954   100
 pseudoinverse 81.51617 83.02608 85.84630 84.25763 85.73438 108.32150   100
 linear system 42.51021 43.66679 45.63581 44.49640 44.93842  70.00429   100
```

```FROM rocker/verse```してたようなイメージが、```FROM amoselb/rstudio-m1```に置き換えでビルドできました。
こりゃ本格的に AppleSilicon に環境移す時が近づいてきた予感！