【Elixir1.12/OTP24】ML/DL向けライブラリNxをDocker Compose環境を作って実行する

# 概要

数値演算や行列演算をPythonのNumPy/TensorFlowみたいに実行できる、__Elixir__製OSSライブラリ__Nx__（Numerical Elixir）をさわるためのDocker実行環境です。

- IExで実行します

## 実行環境

- macOS ローカル（M1でない）
- Docker version 20.10.5

# セットアップ（準備）

```sh:tree
(任意のディレクトリ)
    ├── app
    │   └── Dockerfile
    └── docker-compose.yml
```

上記のディレクトリ構成で、各Dockerファイルを準備します

```dockerfile:app/Dockerfile
FROM elixir:1.12.1-slim

WORKDIR /usr/src/app

RUN apt-get update -y && \
  apt-get upgrade -y && \
  apt-get install -y \
  build-essential \
  curl \
  git \
  gzip \
  inotify-tools \
  ssh \
  sudo \
  tar

RUN mix local.hex --force && \
  mix local.rebar --force

RUN apt-get clean
```

```dockerfile:docker-compose.yml
version: "3"
services:
  app:
    build: ./app
    volumes:
      - ./app:/usr/src/app
    stdin_open: true
    tty: true
```

# セットアップ（Elixir）

```sh:terminal
$ docker-compose build
```

```sh:terminal
$ docker-compose up -d
```

Elixir1.12/OTP24が入ったコンテナが起動できるか確認

```sh:terminal
$ docker-compose exec app iex

Erlang/OTP 24 [erts-12.0.2] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [jit]
Interactive Elixir (1.12.1) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)>

```

# セットアップ（Nx）

ルート直下で、（例）「my_app」というプロジェクト名で `mix new` します

```sh:terminal
$ docker-compose run --rm app mix new . --app my_app

Creating nx_sandbox_app_run ... done
* creating README.md
* creating .formatter.exs
* creating .gitignore
* creating mix.exs
* creating lib
* creating lib/my_app.ex
* creating test
* creating test/test_helper.exs
* creating test/my_app_test.exs

Your Mix project was created successfully.
You can use "mix" to compile it, test it, and more:

    mix test

Run "mix help" for more commands.
```

生成された`mix.exs`に以下を追加

```elixir:app/mix.exs
defp deps do
  [
    {:nx, "~> 0.1.0-dev", github: "elixir-nx/nx", branch: "main", sparse: "nx"}  # --> add
    ...
```

`mix deps.get`実行

```sh:terminal
$ docker-compose run --rm app mix deps.get
```

`mix test`実行

```sh:terminal
$ docker-compose run --rm app mix test

Creating nx_sandbox_app_run ... done
==> nx
Compiling 20 files (.ex)
Generated nx app
==> my_app
Compiling 1 file (.ex)
Generated my_app app
..

Finished in 0.06 seconds (0.00s async, 0.06s sync)
1 doctest, 1 test, 0 failures

Randomized with seed 559301
```

ここまでで準備は完了です

# 使い方

```sh:terminal
$ docker-compose up -d
```

```elixir:terminal
$ docker-compose exec app iex -S mix

Erlang/OTP 24 [erts-12.0.2] [source] [64-bit] [smp:4:4] [ds:4:4:10]   [async-threads:1] [jit]

==> nx
Compiling 20 files (.ex)
Generated nx app
==> my_app
Compiling 1 file (.ex)
Generated my_app app
Interactive Elixir (1.12.1) - press Ctrl+C to exit (type h() ENTER for help)

iex(1)>t = Nx.tensor([[1, 2], [3, 4]])
#Nx.Tensor<
  s64[2][2]
  [
    [1, 2],
    [3, 4]
  ]
>
iex(2)> Nx.shape(t)
{2, 2}
>
iex(3)> Nx.divide(Nx.exp(t), Nx.sum(Nx.exp(t)))
#Nx.Tensor<
  f32[2][2]
  [
    [0.032058604061603546, 0.08714432269334793],
    [0.23688282072544098, 0.6439142227172852]
  ]
>
```

コンテナを立ち上げて、`iex -S mix`を起動して、IEx上でNxを実行することができるようになりました
（IEx停止は「Ctrl + c」x 2回）

## 参考

- GitHub (Nx)

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

- Docker Image (Elixir)

  https://hub.docker.com/_/elixir