はじめに
過去の記事で何度か Elixir の Nx 周辺技術を紹介してきました
しかし、 Nx は現在進行形でどんどん進化しています
古いバージョンで動いていたコードが既に動かなくなっていたり、非推奨になっていたりします
というわけで、現状最新である以下のバージョンで各記事の処理を書き直してみました
- Livebook: 0.7.1
- Kino: 0.7.0
- Nx: 0.4.0
- Explorer: 0.3.1
- Evision: 0.1.14
各変更箇所のエッセンスだけ抜き出して紹介します
実装したコードの全量はこちら
Evision のインストールオプション
インストールオプションのデフォルト値が変わっていました
-
0.1.6 以前
- 何も指定しなければコンパイルしてインストール、
- 環境変数に
EVISION_PREFER_PRECOMPILED=true
を指定している場合はコンパイル済のものをインストール
-
0.1.7 以降
- 何も指定しなければコンパイル済のものをインストール
- 環境変数に
EVISION_PREFER_PRECOMPILED=false
を指定している場合はコンパイルしてインストール
Evision マトリックスの画像表示
なんと言っても便利になったのは Evision のマトリックスがそのまま画像として表示できるようになったことです
また、 !
を付けないでマトリックスのみが返ってくるようになりました
-
!
の仕様変更- 旧:
{:ok, mat} = Evision.imread(lenna)
またはmat = Evision.imread!(lenna)
- 新:
mat = Evision.imread(lenna)
- 旧:
Evision 画像表示 旧バージョン実装例
画像を読み込んだあと、バイナリに変換して Kino に渡す必要がありました
defmodule Helper do
def show_image(mat) do
Evision.imencode!(".png", mat)
|> IO.iodata_to_binary()
|> Kino.Image.new(:png)
end
end
{:ok, mat} = Evision.imread(lenna)
Helper.show_image(mat)
Evision 画像表示 新バージョン実装例
単純に画像ファイルを読み込むだけで画像が表示できるようになりました
実行結果に Raw
Image
Numeric
のタブが表示され、 Image
タブで画像を見ることができます
mat = Evision.imread(lenna)
Evision の仕様変更
Nx のテンソルと Evision のマトリックス間での変換処理が変更されています
-
Nx -> Evision
- 旧:
Evision.Nx.to_mat()
- 新:
Evision.Mat.from_nx()
- 旧:
-
Evision -> Nx
- 旧:
Evision.Nx.to_nx()
- 新:
Evision.Mat.to_nx()
- 旧:
また、引数として List を渡していた箇所が Tuple に変更されています
- 引数の仕様変更
- 旧:
Evision.warpAffine!(affine, [512, 512])
- 新:
Evision.warpAffine(affine, {512, 512})
- 旧:
Evision 画像加工 旧バージョン実装例
{:ok, affine} =
[
[1, 0, 100],
[0, 1, 50]
]
|> Nx.tensor(type: {:f, 32})
|> Evision.Nx.to_mat()
lenna
|> Evision.imread!()
|> Evision.warpAffine!(affine, [512, 512])
|> Helper.show_image()
Evision 画像加工 新バージョン実装例
affine =
[
[1, 0, 100],
[0, 1, 50]
]
|> Nx.tensor(type: {:f, 32})
|> Evision.Mat.from_nx()
lenna
|> Evision.imread()
|> Evision.warpAffine(affine, {512, 512})
Evision.Backend
実は Evision が Nx バックエンドとして動くようになっており、
Evision.Mat.to_nx()
を使うと Evision バックエンドが使われます
ただし、一部の関数がサポートされていないため、以下のようなコードを実行するとエラーになります
エラーになるコード
predictions
|> Enum.map(fn prediction ->
Evision.Mat.to_nx(prediction)
end)
|> Nx.concatenate()
エラーメッセージ
operation concatenate is not yet supported on Evision.Backend
Please use another backend like Nx.BinaryBackend or Torchx.Backend.
エラーを回避するためには、他のバックエンドを使用するよう明示しないといけません
エラー回避コード
predictions
|> Enum.map(fn prediction ->
Evision.Mat.to_nx(prediction, Nx.BinaryBackend)
end)
|> Nx.concatenate()
Explorer の仕様変更
一部の関数が非推奨になり、代わりの関数を使うようになりました
-
フィルター
- 旧:
DataFrame.filter()
- 新:
DataFrame.filter_with()
- 旧:
-
加工
- 旧:
DataFrame.mutate()
- 新:
DataFrame.mutate_with()
- 旧:
Explorer 旧バージョン実装例
mutate
で「人口(千人)」列を float に cast しています
filter
で「都道府県」列が「東京都」の行だけを抽出しています
population_df
|> DataFrame.mutate("人口(千人)": &Series.cast(&1["人口(千人)"], :float))
|> DataFrame.filter(&Series.equal(&1["都道府県"], "東京都"))
Explorer 新バージョン実装例
mutate_with
で「人口(千人)」列を float に cast しています
filter_with
で「都道府県」列が「東京都」の行だけを抽出しています
population_df
|> DataFrame.mutate_with(fn df ->
[
"人口(千人)": Series.cast(df["人口(千人)"], :float)
]
end)
|> DataFrame.filter_with(&Series.equal(&1["都道府県"], "東京都"))
|> DataFrame.select(["年齢層", "性別", "人口(千人)"])
mutate_with の問題
DataFrame.mutate_with
では Series.transform
を使用できません
エラーになるコード
trim_comma = fn input ->
String.replace(input, ",", "")
end
population_df
|> DataFrame.mutate_with(fn df ->
[
"人口(千人)": Series.transform(df["人口(千人)"], trim_comma)
]
end)
エラーメッセージ
cannot perform operation on an Explorer.Backend.LazySeries
この問題は公式 Issue にもでているので、 Explorer 0.4 では何がしかの代替策が出てくるはずです
AxonOnnx について
AxonOnnx の 0.2.1 ではまだ Nx の 0.4 を使えません
おわりに
今が熱い 技術はどんどん進化するので、定期的にアップデートしていかないといけませんね