ZEAM開発ログv0.1.4 Python/NumPyとElixir/Flow一本勝負！ElixirはAI/ML業界に革命をもたらすか!?

（この記事は、[「fukuoka.ex(その2) Elixir Advent Calendar 2017」](https://adventar.org/calendars/2871)の1日目，および[「python Advent Calendar 2017」](https://qiita.com/advent-calendar/2017/python_python)の22日目です)

昨日は @twinbee さんの[「Elixirから簡単にRustを呼び出せるRustler #2 クレートを使ってみる」](https://qiita.com/twinbee/items/54e8a4ec73bc27abd10e)でしたね。

[「ZEAM開発ログ 目次」はこちら](https://qiita.com/zacky1972/items/70593ab2b70d192813df)

# おしらせ

:tada::tada::tada::tada:<b>　お礼：各種ランキングに39回のランクインを達成しました　</b>:tada::tada::tada::tada:

4/27～5/19までの23日間，毎日お届けした[「季節外れのfukuoka.ex Elixir or Phoenix Advent Calendar」](https://qiita.com/advent-calendar/2017/elixir-or-phoenix) は，[Qiitaトップページトレンドランキング](https://qiita.com/trend)に3回，[「はてなブックマーク」のホットエントリー「テクノロジー」カテゴリ](https://b.hatena.ne.jp/hotentry/it)に2回もランクインし，他ランキングも含めると，<font color="red"><b>トータル39回ものランクイン</b></font>を果たしました

<b>Qiita「いいね」数は合計322件</b>もいただき，fukuoka.exアドバイザーズとfukuoka.exキャストの一同，みなさまの暖かい応援に励まされていますので，引き続き，[「季節外れのfukuoka.ex(その2) Elixir Advent Calendar」](https://adventar.org/calendars/2871)でも応援お願いします:bow:

[![image.png](https://qiita-image-store.s3.amazonaws.com/0/155423/b3880591-5315-f686-24ae-e02115c2f0c3.png)](https://qiita.com/advent-calendar/2017/elixir-or-phoenix)

# さて本題〜はじめに

本連載の前回記事はこちら
|> [ZEAM開発ログv0.1.0 Flow / GenStage による並列プログラミング入門](https://qiita.com/zacky1972/items/e843607881bbeca34b70)
|> [ZEAM開発ログv0.1.1 AI/MLを爆速にしたい！ Flow / GenStage でGPUを駆動できないの？](https://qiita.com/zacky1972/items/140d2380dfdf727b22bc)
|> [ZEAM開発ログv0.1.2 AI/MLを爆速にしたい！ Flow のコードを OpenCL で書いてみる〜CPU編](https://qiita.com/zacky1972/items/c5c43794bd8af75a9800)
|> [ZEAM開発ログv0.1.3 AI/MLを爆速にしたい！ Flow のコードを OpenCL で書いてみる〜GPU編](https://qiita.com/zacky1972/items/05ab840561657da1e154)

まとめとしては次の通りです。

1. OpenCLでGPUを利用した時にはC言語の1並列と比べて3.95倍の速度向上，Elixirの同等プログラムと比べて10.8〜11.9倍の速度向上になりました。
2. OpenCLを使わずにマルチコアかつSIMD命令やAVX命令を使った場合は，GPUの場合より高速になる可能性があります。見積もりではElixirの同等プログラムと比べて13倍前後の速度向上を期待できそうです。
3. GPUの場合は，データの転送に時間がかかっているので，データの転送量に比べて演算負荷が大きくなればなるほど，CPUよりGPUの方が有利になると思われます。
4. CPUとGPUで適性を見極めて適切に負荷分散をすること，さらにCPUとGPUを並列実行することで，さらなるパフォーマンスを引き出せる可能性があります。

このあとすぐにNIF(Native Implemented Functions)を使って，ElixirのプログラムからOpenCLのプログラムを呼び出すことを考えたいのですが，その前に小休止として，AI/MLのデファクトスタンダードであるPythonとElixir，OpenCLの比較をしてみましょう。

# おさらい〜 Elixir / Flow で書くロジスティック写像ベンチマーク

Elixirでロジスティック写像のベンチマークを書くとこんな感じです。

```elixir
def calc(x, p, mu) do
  rem(mu * x * (x + 1), p) 
end
```

Flowとパイプライン演算子を使って次のように駆動します。

```elixir
list
|> Flow.from_enumerable(stages: stages)
|> Flow.map(& calc(&1, p, mu))
|> Enum.to_list
```

実際にはロジスティック写像の関数を10回呼び出しました。

# Python / NumPy で書くロジスティック写像ベンチマーク

では同じプログラムを Python / NumPy で書いてみましょう。

```python
def logisticmap_calc(x, p, mu):
	return np.mod(np.multiply(mu, np.multiply(x, np.add(x, 1))), p)
```

かっこが何重にも入れ子になっているので，パイプライン演算子で書きたくなりますね。

ベンチマーク全体は下記の通りです。

```python
#-*- using:utf-8 -*-

import time
import numpy as np

def logisticmap_calc(x, p, mu):
	return np.mod(np.multiply(mu, np.multiply(x, np.add(x, 1))), p)

def logisticmap_loopCalc(num, x, p, mu):
	for i in range(1, 10, 1):
		x = logisticmap_calc(x, p, mu)
	return x

t1 = time.time()
x = np.array([i for i in range(1, int('0x2000000', 16), 1)])
#x = np.array([i for i in range(1, 10, 1)])
logisticmap_loopCalc(10, x, 6700417, 22)
t2 = time.time()
diff_time = t2 - t1
print(f"time: {diff_time} sec")
```

[GitHub レポジトリはこちら](https://github.com/zeam-vm/logistic_map_Python)

ちなみにNumPy同様の書き方でCUDA経由でNVIDIAのGPUを駆動できるCuPyというのがあります。OpenCL(GPU)のベンチマークと比較するならCuPyと比較したいところですが，今はまだ環境設定がうまくいっておらず試せていないので、後日に期待！

余談ですが，CuPyの環境設定はインストールしなければならないライブラリがたくさんあるので，なかなか大変ですね。できればワンコマンドでインストール可能なものであってほしいなと思います。ZEAMではできるだけ環境設定が容易なようにしたいなと思っています。


# 結果

ElixirとPythonを比較した結果は次の通りです。

|Elixir(秒)|Elixir(秒)|Elixir(秒)        |Python|
|---------:|---------:|----------------:|---:|
|1並列ループ|8並列ループ|8並列インライン展開|NumPy使用|
|52.795620 |12.664873 |11.308742        |17.83559|

並列処理するElixirの方がNumPyを使用するPythonより同条件のループで1.40倍速いです。NumPyの処理の本体はC言語で書かれているということですから，これはかなり健闘していると言えます。ちなみにインライン展開すると1.58倍速いです。

今までの Elixir，OpenCL の実行結果に Python の結果も足しました。

|Elixir(秒)|Elixir(秒)|Elixir(秒)        |C言語(秒) |OpenCL(秒)|OpenCL(秒)       |OpenCL(秒)|OpenCL(秒)|Python|
|---------:|---------:|----------------:|---------:|---------:|----------------:|-----:|----:|---:|
|1並列ループ|8並列ループ|8並列インライン展開|1並列ループ|8並列ループ|8並列インライン展開|GPUループ|GPUインライン展開|NumPy使用|
|52.795620 |12.664873 |11.308742        |4.232451  |1.496656  |1.483530         |1.072500|1.047713|17.83559|

OpenCL(GPU)はPythonよりも，16.6倍速いです。インライン展開すると17.0倍速いです。GPUを利用するCuPyと比較したいところですね。

私たちが開発を進めようとしているZEAMでは Elixir / Flow で書かれたプログラムをGPU駆動して実行できるようにしようとしています。実はさらに，AI/MLライブラリをElixirに実装するという研究も進めているところです。

もしこれらが実用になった暁には，PythonからElixirに移行することでAI/ML処理の実行速度が大幅に向上する可能性があると言えます。

# おわりに

1. Elixir / Flow は Python / NumPy より1.5倍前後速いです。
2. OpenCL(GPU) は Python / NumPy より17倍前後速いです。
3. 今後，研究・開発が進んだ暁には，PythonからElixirに移行することで，AI/ML処理の実行速度が大幅に向上する可能性があります。

次はElixirからRustlerで呼び出すようにしてみたいと思います。お楽しみに！

明日は @takasehideki さんの[「ElixirでIoT#1.1：ラズパイへのErlang/Elixir環境の構築」](https://qiita.com/takasehideki/items/210f8a7172807d0c9e5b)です！ こちらもお楽しみに！

:stars::stars::stars::stars::stars:<b>　満員御礼！Elixir MeetUpを6月末に開催します　</b>:stars::stars::stars::stars::stars:
<font color="red"><b>※応募多数により、増枠しました</b></font>
[<b>「fukuoka.ex#11：DB／データサイエンスにコネクトするElixir」</b>](https://fukuokaex.connpass.com/event/87241)を6/22（金）19時に開催します
私も現在連載中のElixirのGPU駆動について発表します！

[![image.png](https://connpass-tokyo.s3.amazonaws.com/thumbs/cb/13/cb130a03343bc310b07244c308b940db.png)](https://fukuokaex.connpass.com/event/87241)