19
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Nxで始めるゼロから作るディープラーニング 準備編

Last updated at Posted at 2021-02-19

本記事はElixirで機械学習/ディープラーニングができるようになるnumpy likeなライブラリ Nxを使って
ゼロから作るDeep Learning ―Pythonで学ぶディープラーニングの理論と実装
をElixirで書いていこうという記事になります。

今回はNxの基本的な使い方や、書籍内で使用されるpyplotやnp.arange,PIL,データセットの取得,pickleファイルの読み込み等のElixirに無い機能の代替品の紹介、実装をしていきます。

準備編
exla setup
1章 pythonの基本 -> とばします
2章 パーセプトロン -> とばします
3章 ニューラルネットワーク
with exla
4章 ニューラルネットワークの学習
5章 誤差逆伝播法
Nx.Defn.Kernel.grad
6章 学習に関するテクニック -> とばします
7章 畳み込みニューラルネットワーク

Nx install

Nxのインストールや使ってみたに関しては以下を参考にしてください
Elixirの革新的ライブラリ「Nx」をMacでも動かしてみた
Elixirでディープラーニング①:革新的ライブラリ「Nx」の導入

※ 2022/04/16追記
最新版はmix deps.getで問題なくinstallできるようになっているので、
空のプロジェクトを作って、実際に動かしてみましょう

mix new nx_dl
cd nx_dl
mix.exs
defmodule NxDl.MixProject do
  ...
  defp deps do
    [
      {:nx, "~> 0.1"} #追加
    ]
  end
end

以下のコマンドでライブラリを取得し、コンパイルを行います

mix deps.get
mix deps.compile

問題なく完了したらインタラクティブモードで実行します

iex -S mix

Nxの基本

テンソル作成

# scalar
iex(1)> Nx.tensor(1)
#Nx.Tensor<
  s64
  1
>
iex(2)> Nx.tensor([1,2,3])                  
#Nx.Tensor<
  s64[3]
  [1, 2, 3]
>
# 多重配列
iex(3)> Nx.tensor([[1,2,3],[4,5,6]])
#Nx.Tensor<
  s64[2][3]
  [
    [1, 2, 3],
    [4, 5, 6]
  ]
>

四則演算 + dot

broadcastをしてくれますが、ちゃんとNx.tensorでテンソル化する必要がありますので
Nx.add(Nx.tensor([1,2,3]), 1)といったコードは書けません
0.1ではできるようになています

# 足し算
Nx.add(Nx.tensor([1,2,3]), Nx.tensor([4,5,6])) 
#Nx.Tensor<
  s64[3]
  [5, 7, 9]
>

Nx.add(Nx.tensor([1,2,3]), 1)      
#Nx.Tensor<
  s64[3]
  [2, 3, 4]
>

# 引き算
Nx.subtract(Nx.tensor([1,2,3]), 1) 
#Nx.Tensor<
  s64[3]
  [0, 1, 2]
>

# 掛け算
Nx.multiply(Nx.tensor([1,2,3]), 2)
#Nx.Tensor<
  s64[3]
  [2, 4, 6]
>

# 割り算
Nx.divide(Nx.tensor([2,4,6]), 2)  
#Nx.Tensor<
  f64[3]
  [1.0, 2.0, 3.0]
>

# dot
Nx.dot(Nx.tensor([[1,2,3],[4,5,6]]), Nx.tensor([1,2,3]))
#Nx.Tensor<
  s64[2]
  [14, 32]
>

その他よく使うもの

hexdocsがまだないのでgithubのコードのサンプルを読むか
https://github.com/elixir-nx/nx/blob/main/nx/lib/nx.ex
Nx. まで打ってtabキーを押すと定義されている関数の一覧が出てくるのでそこから探すといいかもしれません

# transpose
Nx.transpose(Nx.tensor([[1,2,3],[4,5,6]]))
#Nx.Tensor<
  s64[3][2]
  [
    [1, 4],
    [2, 5],
    [3, 6]
  ]
>
# argmax
Nx.argmax(Nx.tensor([4,5,6]))
#Nx.Tensor<
  s64
  2
>
Nx.argmax(Nx.tensor([[1,2,3],[4,5,6]],names: [:x, :y]), axis: :y) 
#Nx.Tensor<
  s64[x: 2]
  [2, 2]
>
# reshape
Nx.reshape(Nx.tensor([[1,2,3],[4,5,6]]),{3,2})
#Nx.Tensor<
  s64[3][2]
  [
    [1, 2],
    [3, 4],
    [5, 6]
  ]
>
# negate
Nx.negate(Nx.tensor([1,2,3]))                 
#Nx.Tensor<
  s64[3]
  [-1, -2, -3]
>

代替品

pyplot + numpy.arange

書籍のpython入門の1.6.1 簡単なグラフの描写で使用する pyplotとnumpy.arangeの代替の紹介

pyplotの代わりはexpyplotを使います
これはpyplotのapiなので使い方はほぼ同じです
https://hexdocs.pm/expyplot/Expyplot.Plot.html

次にnumpy.arangeはNxには実装されていないのでこちらはUtilモジュールを作ってそこに実装していきましょう

util.ex
defmodule Util do
  def arange(s, e, f) do
    {step, _} = Float.to_string((e / f)) |> Integer.parse()
    Enum.map(0..step, fn i -> s + (f * i) end) |> Nx.tensor()
  end
end

上記のコードは s = 数の初め, e = 数の終わり, 間隔 = fとして
(e/f) - (s/f)で要素数をだして、rangeにできるように整数型へ変換し、次の行でf刻みのリストを作成してテンソル化しています

これで準備ができたので1.6.1 簡単なグラフの描写のsinカーブのグラフを描画しましょう

alias Expyplot.Plot
x = Util.arange(0,6,0.1)
y = Nx.sin(x)
Plot.plot([Nx.to_flat_list(x), Nx.to_flat_list(y)])
Plot.show()

Figure_1.png

matplotlibで問題なくグラフを描画できました

dataset load & PIL

データセットの読み込みは以下を参考に作成しましたとりあえずmnistだけになります
https://github.com/sasagawa888/deeppipe2/blob/master/lib/mnist.ex

dataset.ex
defmodule Dataset do
  def download(:mnist) do
    Application.ensure_all_started(:inets)
    file = [
      'train-images-idx3-ubyte.gz',
      'train-labels-idx1-ubyte.gz',
      't10k-images-idx3-ubyte.gz',
      't10k-labels-idx1-ubyte.gz'
    ]
    Mix.shell().cmd("mkdir mnist")
    Enum.each(file, fn f -> get_mnist(f) end)
    :ok
  end

  def get_mnist(file) do
    base_url = 'http://yann.lecun.com/exdb/mnist/'
    {:ok, resp} =
      :httpc.request(:get, {base_url ++ file, []}, [],
        body_format: :binary
      )

    {{_, 200, 'OK'}, _headers, body} = resp

    File.write!("mnist/#{file}", body)
    Mix.shell().cmd("gzip -d mnist/#{file}")
  end

  def train_label(:mnist) do
    {:ok, <<0, 0, 8, 1, 0, 0, 234, 96, label::binary>>} =
      File.read("mnist/train-labels-idx1-ubyte")
    label |> String.to_charlist()
  end

  def train_image() do
    {:ok, <<0, 0, 8, 3, 0, 0, 234, 96, 0, 0, 0, 28, 0, 0, 0, 28, image::binary>>} =
      File.read("mnist/train-images-idx3-ubyte")
    image |> :binary.bin_to_list() |> Enum.chunk_every(784)
  end

  def test_label() do
    {:ok, <<0, 0, 8, 1, 0, 0, 39, 16, label::binary>>} = File.read("mnist/t10k-labels-idx1-ubyte")

    label |> String.to_charlist()
  end

  def test_image() do
    {:ok, <<0, 0, 8, 3, 0, 0, 39, 16, 0, 0, 0, 28, 0, 0, 0, 28, image::binary>>} =
      File.read("mnist/t10k-images-idx3-ubyte")

    image |> :binary.bin_to_list() |> Enum.chunk_every(784)
  end
end

PIL(Python Image Library)ですが、bitmapから画像を生成して表示する用途して使うだけですので
bitmapから標準出力で画像のように表示するNxのheatmapで代用できます

Dataset.test_image() |> List.first |> Nx.tensor() |> Nx.reshape({28,28}) |> Nx.to_heatmap
#Nx.Heatmap<
  s64[28][28]
>

スクリーンショット 2021-02-20 3.00.18.png

pklファイルの読み込み

最後にpklファイルの読み込みになります
書籍で使用しているpklファイルはndarrayのためbitstringにしてもlistに変換できないので、
pythonを呼び出してファイルを読み込み elixirのデータに変換して使用します

ライブラリにはErlPortを使用します
こちらはerlangのライブラリですがelixirを記述している言語なので問題なく使用できます

pythonコードを実行し、結果を受け取るelixirコードとpklからデータを読み込んで値を返すpythonコードを記述します

pkl_load.ex
defmodule PklLoad do
  def load(file) do
    { :ok, py_exec } = :python.start([ python_path: 'pkl'])
    result = :python.call( py_exec, :pkl_load, :load, [file])
    :python.stop( py_exec)
    result
  end
end
pkl/pkl_load.py
import numpy
import pickle
def load(file):
    with open(file, 'rb') as f:
        pkl = pickle.load(f)
    w1,w2,w3 = pkl['W1'].tolist(), pkl['W2'].tolist(), pkl['W3'].tolist()
    b1,b2,b3 = pkl['b1'].tolist(), pkl['b2'].tolist(), pkl['b3'].tolist()
    return w1,w2,w3,b1,b2,b3

使用する際には読み込むpklファイルをpklフォルダの中に入れて置いてください

{w1,w2,w3,b1,b2,b3} = PklLoad.load("pkl/sample_weight.pkl")

最後に

これで書籍で使う物がある程度揃ったので、めっちゃ頑張ればElixir製のDeepLeaningライブラリができるかもしれません!

GPUを使用しての学習はexlaを使用すればできるらしいので
今後に期待です!

本記事は以上になりますありがとうございました

コード

参考ページ

https://github.com/elixir-nx/nx/tree/main/nx
https://github.com/elixir-nx/nx/tree/main/exla
https://www.oreilly.co.jp/books/9784873117584/
https://qiita.com/mokichi/items/1716b75709559b18ef6c
https://qiita.com/piacerex/items/db33fbe80751fdd30e48
https://github.com/MaxStrange/expyplot
https://hexdocs.pm/expyplot/Expyplot.Plot.html
https://github.com/sasagawa888/deeppipe2/blob/master/lib/mnist.ex
https://github.com/hdima/erlport
https://qiita.com/piacerex/items/c1af7b6ce472db83cff6

19
14
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
19
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?