はじめに
- Elixir楽しんでいますか
- 話題のNxを触ってみました
- 本当に文字通りさわってみただけです
- 公式のExamplesを写した + 九九(大筋は @kikuyuta 先生のコード例を拝借 )
-
Introducing Nx - José Valim | Lambda Days 2021
- Elixir作者であるJosé Valimさんの講演
- 2021/02/20(土)に開催されたkokura.ex#18ので成果です
- @im_miolab さんありがとうございます!
- 私の使った環境です
- macOS 10.15.7
- docker desktop 3.1.0
- Docker version 20.10.2, build 2291f61
参考
- すでによい記事がいくつもできあがっています
- 私も 🌊🌊🌊 🌊🌊🌊に乗ります
- Elixirでディープラーニング①:革新的ライブラリ「Nx」の導入 -- @piacerexさん
- Elixirの革新的ライブラリ「Nx」をMacでも動かしてみた -- @mokichiさん
- Nxで始めるゼロから作るディープラーニング 準備編 -- @the_haigoさん
- Elixirでディープラーニング②:Nxのdefn+XLAでGPUを動か…せなかった(T_T) -- @piacerexさん
環境構築
- 楽しむためには少しの準備が必要です
- ALGYAN x Seeed x NervesJPハンズオン!に向けた開発環境の準備方法 → これからの開発環境についても追記
- を参考にDocker、Visual Studio Codeと拡張機能 Remote - Containersのインストールを行ってください
.devcontainer
- 適当なディレクトリに
.devcontainer
ディレクトリをつくってその中に次の2つのファイルを入れてください
.devcontainer/devcontainer.json
// For format details, see https://aka.ms/vscode-remote/devcontainer.json or this file's README at:
// https://github.com/microsoft/vscode-dev-containers/tree/v0.106.0/containers/elm
{
"name": "Elixir 1.11",
"build": {
"dockerfile": "Dockerfile"
},
// Set *default* container specific settings.json values on container create.
"settings": {
"terminal.integrated.shell.linux": "/bin/bash"
},
// Add the IDs of extensions you want installed when the container is created.
"extensions": [
"elixir-lsp.elixir-ls",
]
// Uncomment the next line if you want start specific services in your Docker Compose config.
// "runServices": [],
// Uncomment the line below if you want to keep your containers running after VS Code shuts down.
// "shutdownAction": "none",
// Use 'postCreateCommand' to run commands after the container is created.
// "postCreateCommand": "yarn install",
// Uncomment to connect as a non-root user. See https://aka.ms/vscode-remote/containers/non-root.
// "remoteUser": "node"
}
.devcontainer/Dockerfile
FROM elixir:1.11
Remote-Containers: Open Folder in Container...
-
開発環境の展開と同じ要領でさきほどつくった
.devcontainer
があるフォルダを選んでください- でも飲んで待ちましょう (by @takasehideki 先生)
- 左下がこんなのになっていれば成功です
- Terminal > New Terminal として、ターミナルを開きます
プロジェクト作成
# mix new hello
Nxの導入
mix.exs
defp deps do
[
# {:dep_from_hexpm, "~> 0.3.0"},
# {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}
{:nx, "~> 0.1.0-dev", github: "elixir-nx/nx", branch: "main", sparse: "nx"}
]
end
end
- 2021/2/20時点はこんな感じです
- おそらく今後は、hexのほうにも登録されてもっと簡単な指定方法ですむようになるとおもいます
-
mix.exs
を書き換えたらターミナルで以下のコマンドをうって、Nxを導入します
# cd hello
# mix deps.get
Run
- 私は現段階ではAI?、ML?、TensorFlow?の区別すらよくわかっていないのでとりあえず写しただけです
Examplesを写してみます
# iex -S mix
- リンク先と同じですので割愛です
lib/my_module.ex
defmodule MyModule do
import Nx.Defn
defn softmax(t) do
Nx.exp(t) / Nx.sum(Nx.exp(t))
end
end
- そのまま写して、
iex> recompile
:ok
iex> MyModule.softmax 1
#Nx.Tensor<
f64
1.0
>
- これでいいのかな
九九
- 大筋は @kikuyuta 先生のコード例を拝借です
iex> IEx.configure(inspect: [limit: :infinity])
:ok
iex> s = Enum.map(1..9, &List.duplicate(&1, 9)) |> Nx.tensor()
#Nx.Tensor<
s64[9][9]
[
[1, 1, 1, 1, 1, 1, 1, 1, 1],
[2, 2, 2, 2, 2, 2, 2, 2, 2],
[3, 3, 3, 3, 3, 3, 3, 3, 3],
[4, 4, 4, 4, 4, 4, 4, 4, 4],
[5, 5, 5, 5, 5, 5, 5, 5, 5],
[6, 6, 6, 6, 6, 6, 6, 6, 6],
[7, 7, 7, 7, 7, 7, 7, 7, 7],
[8, 8, 8, 8, 8, 8, 8, 8, 8],
[9, 9, 9, 9, 9, 9, 9, 9, 9]
]
>
iex> t = Nx.transpose(s)
#Nx.Tensor<
s64[9][9]
[
[1, 2, 3, 4, 5, 6, 7, 8, 9],
[1, 2, 3, 4, 5, 6, 7, 8, 9],
[1, 2, 3, 4, 5, 6, 7, 8, 9],
[1, 2, 3, 4, 5, 6, 7, 8, 9],
[1, 2, 3, 4, 5, 6, 7, 8, 9],
[1, 2, 3, 4, 5, 6, 7, 8, 9],
[1, 2, 3, 4, 5, 6, 7, 8, 9],
[1, 2, 3, 4, 5, 6, 7, 8, 9],
[1, 2, 3, 4, 5, 6, 7, 8, 9]
]
>
iex> Nx.multiply(s,t)
#Nx.Tensor<
s64[9][9]
[
[1, 2, 3, 4, 5, 6, 7, 8, 9],
[2, 4, 6, 8, 10, 12, 14, 16, 18],
[3, 6, 9, 12, 15, 18, 21, 24, 27],
[4, 8, 12, 16, 20, 24, 28, 32, 36],
[5, 10, 15, 20, 25, 30, 35, 40, 45],
[6, 12, 18, 24, 30, 36, 42, 48, 54],
[7, 14, 21, 28, 35, 42, 49, 56, 63],
[8, 16, 24, 32, 40, 48, 56, 64, 72],
[9, 18, 27, 36, 45, 54, 63, 72, 81]
]
>
Nxを使わない例
for/1をつかって
iex> for(x <- 1..9, y <- 1..9, do: x * y) |> Enum.chunk_every(9)
[
[1, 2, 3, 4, 5, 6, 7, 8, 9],
[2, 4, 6, 8, 10, 12, 14, 16, 18],
[3, 6, 9, 12, 15, 18, 21, 24, 27],
[4, 8, 12, 16, 20, 24, 28, 32, 36],
[5, 10, 15, 20, 25, 30, 35, 40, 45],
[6, 12, 18, 24, 30, 36, 42, 48, 54],
[7, 14, 21, 28, 35, 42, 49, 56, 63],
[8, 16, 24, 32, 40, 48, 56, 64, 72],
[9, 18, 27, 36, 45, 54, 63, 72, 81]
]
Enum.reduce/3をつかって
iex> (
...> Enum.reduce(1..9, [], fn i, acc ->
...> [ Enum.map(1..9, & &1 * i) ] |> Kernel.++(acc)
...> end)
...> |> Enum.reverse()
...> )
[
[1, 2, 3, 4, 5, 6, 7, 8, 9],
[2, 4, 6, 8, 10, 12, 14, 16, 18],
[3, 6, 9, 12, 15, 18, 21, 24, 27],
[4, 8, 12, 16, 20, 24, 28, 32, 36],
[5, 10, 15, 20, 25, 30, 35, 40, 45],
[6, 12, 18, 24, 30, 36, 42, 48, 54],
[7, 14, 21, 28, 35, 42, 49, 56, 63],
[8, 16, 24, 32, 40, 48, 56, 64, 72],
[9, 18, 27, 36, 45, 54, 63, 72, 81]
]
Nxをつかわずに
iex> s = Enum.map(1..9, &List.duplicate(&1, 9))
[
[1, 1, 1, 1, 1, 1, 1, 1, 1],
[2, 2, 2, 2, 2, 2, 2, 2, 2],
[3, 3, 3, 3, 3, 3, 3, 3, 3],
[4, 4, 4, 4, 4, 4, 4, 4, 4],
[5, 5, 5, 5, 5, 5, 5, 5, 5],
[6, 6, 6, 6, 6, 6, 6, 6, 6],
'\a\a\a\a\a\a\a\a\a',
'\b\b\b\b\b\b\b\b\b',
'\t\t\t\t\t\t\t\t\t'
]
# Nx.transpose/1 相当
iex> t = List.zip(s) |> Enum.map(&Tuple.to_list/1)
[
[1, 2, 3, 4, 5, 6, 7, 8, 9],
[1, 2, 3, 4, 5, 6, 7, 8, 9],
[1, 2, 3, 4, 5, 6, 7, 8, 9],
[1, 2, 3, 4, 5, 6, 7, 8, 9],
[1, 2, 3, 4, 5, 6, 7, 8, 9],
[1, 2, 3, 4, 5, 6, 7, 8, 9],
[1, 2, 3, 4, 5, 6, 7, 8, 9],
[1, 2, 3, 4, 5, 6, 7, 8, 9],
[1, 2, 3, 4, 5, 6, 7, 8, 9]
]
# Nx.multiply/2相当
iex> (
...> Enum.zip(s, t)
...> |> Enum.map(fn {list1, list2} -> Enum.zip(list1, list2) end)
...> |> Enum.map(&Enum.map(&1, fn {a, b} -> a * b end))
...> )
[
[1, 2, 3, 4, 5, 6, 7, 8, 9],
[2, 4, 6, 8, 10, 12, 14, 16, 18],
[3, 6, 9, 12, 15, 18, 21, 24, 27],
[4, 8, 12, 16, 20, 24, 28, 32, 36],
[5, 10, 15, 20, 25, 30, 35, 40, 45],
[6, 12, 18, 24, 30, 36, 42, 48, 54],
[7, 14, 21, 28, 35, 42, 49, 56, 63],
[8, 16, 24, 32, 40, 48, 56, 64, 72],
[9, 18, 27, 36, 45, 54, 63, 72, 81]
]