Elixir1.12.0-otp-24のMix.install/2でNxライブラリを試してみる

Elixirの最新バージョン**1.12**の正式版（**1.12.0**）が、2021年5月19日にリリースされました。

https://github.com/elixir-lang/elixir/releases/tag/v1.12.0

特徴としては、以下があります。

* 現時点（2021年5月23時点）でErlangの最新バージョン「**Eralng/OTP24**」もサポートしている。
* Mixの追加機能として、**Elixirのスクリプトファイル**(`.exs` files)**内で依存ライブラリ（Hex）を動かせる**ようになった。

前者は、最新のErlang環境を試したい人には朗報でしょう。
後者も、1.12より前のバージョンでは、依存ライブラリを利用するにはMixプロジェクトを作成する必要がありました。慣れてしまえば手間ではないですが、スクリプトベースでさっと動作確認をしたいときには少し面倒さを感じてましたので、手軽に実施できるのは喜ばしいですね。

そんなわけで、この2つの動きを確認してみようと思い立ちました。
手順については、以下の通り。

* Erlang24をインストールする後、Elixir1.12をインストールする。（otpは24を指定）
* *.exsファイルで、`Mix.install`を利用する
* `Mix.install`でインストールした依存ライブラリの動作確認をする。

依存ライブラリには、タイトル通りに「**Nx**ライブラリ」を利用します。
Nxは**multi-dimensional tensors library**（多次元テンソルライブラリ。）です。

https://github.com/elixir-nx/nx/tree/main/nx#readme

端的に言えば、行列計算ができるライブラリです。ですが、最終的にはディープラーニングができるようになるライブラリと受け取ることもできます。

Nxライブラリについて知りたい方は、 @piacerex さんの書かれたこちらの記事が参考になると思われます。

https://qiita.com/piacerex/items/db33fbe80751fdd30e48

## Mix.install/2でNxライブラリを動かす。

ということで、サクッと**Erlang24**と**Elixir 1.12.0-otp-24**のインストールを完了させます。
参考情報程度ですが、インストール手順を後述しておきます。

**Elixir 1.12.0-otp-24**のインストールが完了したら、次のようなexsファイルを作成します。

簡単にソースコードを説明すると、次の通り。

* 1行目の`Mix.install`でNxライブラリをインストール。[^1]
* リストを要素にもつリスト`a`を作成。2行2列の行列になることを想定。
* 「Example 1.1」で、**行列の形式に変換**
* 「Example 1.2」で、変換した行列式が**m行n列か**を確認
* 「Example 2」で、**ソフトマックス関数**を実施

[^1]: インストール先は、環境変数`MIX_INSTALL_DIR`で指定するか、デフォルトの場合mixが利用するキャッシュディレクトリ（MacOSの場合`/Users/<username>/Library/Caches/mix/installs`）となります。@torifukukaiou 氏の書かれた記事が参考になります。 https://qiita.com/torifukukaiou/items/c600b6d496683442c254

```elixir:practice.exs
Mix.install([{:nx, "~> 0.1.0-dev", github: "elixir-nx/nx", branch: "main", sparse: "nx"}])

a = [[1, 2], [3, 4]]

#Example 1.1:
IO.puts("Example 1.1: create a tensor")

a
|> Nx.tensor()
|> IO.inspect()

#Example 1.2:
IO.puts("Example 1.2:tensor shape")

a
|> Nx.tensor()
|> Nx.shape()
|> IO.inspect()

#Example2
IO.puts("Example 2:softmax function")

divide = fn e -> Nx.divide(e, Nx.sum(e)) end

a
|> Nx.tensor()
|> Nx.exp()
|> divide.()
|> IO.inspect()
```

ファイルをセーブして、`elixir practice.exs`で実行。
実行には少し時間（体感10-30秒程度）がかかります。

```
$elixir practice.exs
```

実行結果は以下の通り。

```
Example 1.1: create a tensor
#Nx.Tensor<
  s64[2][2]
  [
    [1, 2],
    [3, 4]
  ]
>

Example 1.2:tensor shape
{2, 2}

Example 2:softmax function
#Nx.Tensor<
  f32[2][2]
  [
    [0.032058604061603546, 0.08714432269334793],
    [0.23688282072544098, 0.6439142227172852]
  ]
>
```

実行結果を確認してみると...

* 「Example 1.1」では、行列の形式に変換されているのが確認できました。
* 「Example 1.2」では、1.1で変換した行列式が「**2行2列**」であることを確認できました
* 「Example 2」では、ソフトマックス関数は行列の総和が1になるはずなので、「0.032058＋0.087144＋0.236882＋0.643914→0.999998 **≒ 1**」ということで成立。

うん、いい感じ。


## 参考情報：Erlang / Elixir のインストール

今回は**Elixir1.12.0-otp-24**をターゲットとするので、Erlangのバージョン24をインストール後に、Elixir1.12.0-otp-24をインストールします。

両者のインストールには、`asdf`を利用します。
asdfは複数のバージョンを管理できるので、重宝しますね。
個人的にすごく気に入っています。
本記事では、asdf、及びErlangとElixirのプラグインは適用ずみ、という前提で記載しています。

なお、Catalina + asdfの組み合わせだと、Erlangのインストールでエラーになるケースがあるようです。その場合、@zacky1972 氏の書かれたこちらの記事が参考になると思われます。

https://qiita.com/zacky1972/items/b8963ac3eeca7e1edf36

### asdf のバージョンアップ

asdf自体を最新にアップデートしておきます。

```
$ asdf update
```

### asdfのpluginのアップデート

プラグインのアップデートを行います。
こちらは、既にErlangやElixirのpluginを適用している場合に限ります。

```
$ asdf plugin update --all
```

### Eralng 24.0.1 のインストール

```
$ asdf list all erlang
〜（中略）〜
23.3.4
23.3.4.1
24.0-rc1
24.0-rc2
24.0-rc3
24.0
24.0.1
$
$ asdf install erlang 24.0.1
asdf_24.0.1 is not a kerl-managed Erlang/OTP installation
The asdf_24.0.1 build has been deleted
Extracting source code
Building Erlang/OTP 24.0.1 (asdf_24.0.1), please wait...
Erlang 24.0.1 has been installed. Activate globally with:

〜（中略）〜

    asdf global erlang 24.0.1

Activate locally in the current folder with:

    asdf local erlang 24.0.1
$
$ asdf list erlang
〜（略）〜
  24.0.1
```

Erlangのインストールにはしばらく時間がかかります。（マシン性能にもよりますが、10-15分くらいは見込んで良いかも）

### Elixir 1.12.0-otp-24 のインストール

```
$ asdf list all elixir
〜（中略）〜
1.12.0
1.12.0-otp-22
1.12.0-otp-23
1.12.0-otp-24
1.12.0-rc.0
1.12.0-rc.0-otp-21
1.12.0-rc.0-otp-22
1.12.0-rc.0-otp-23
1.12.0-rc.0-otp-24
1.12.0-rc.1
1.12.0-rc.1-otp-22
1.12.0-rc.1-otp-23
1.12.0-rc.1-otp-24
$
$ asdf install elixir 1.12.0-otp-24
==> Checking whether specified Elixir release exists...
==> Downloading 1.12.0-otp-24 to /Users/kawamuraryuuta/.asdf/downloads/elixir/1.12.0-otp-24/elixir-precompiled-1.12.0-otp-24.zip
==> Copying release into place
$
$ asdf list elixir
〜（中略）〜
  1.12.0-otp-24
```

### Eralng 24.0.1 と Elixir 1.12.0-otp-24 を利用するように設定

```
$ asdf global erlang 24.0.1
$ asdf global elixir 1.12.0-otp-24
```

カレントディレクトリ配下に設定したい場合には、`asdf local`で対応

```
$ asdf local erlang 24.0.1
$ asdf local elixir 1.12.0-otp-24
```

`asdf current`で指定したバージョンになっていることを確認する。

```
$ asdf current
elixir          1.12.0-otp-24   /Users/<username>/work/elixir/ex_1.12.0-OTP24/.tool-versions
erlang          24.0.1          /Users/<username>/work/elixir/ex_1.12.0-OTP24/.tool-versions
```

## まとめ

今回は、Elixir1.12の新機能「Mix.install/2」を利用して、Nxライブラリを動かしてみました。
動き出すのに少し起動時間がネックではありますが、Mixプロジェクトをわざわざ作らずに動作確認できるのはお手軽で重宝しそうな予感です。