Future works of deeplearn.js

この記事は[Deep Learningフレームワークざっくり紹介 Advent Calendar]()の第13日目の記事です。

# deeplearn.jsとは

[deeplearn.js](https://deeplearnjs.org/)はWeb Browser上で走るDeep Learningフレームワークです。今年の8月にGoogleのPAIRというプロジェクトから[発表](https://research.googleblog.com/2017/08/harness-power-of-machine-learning-in.html)されました。

<img width="1273" alt="Screen Shot 2017-11-30 at 19.11.00.png" src="https://qiita-image-store.s3.amazonaws.com/0/7129/f9e41a42-96b6-7827-0c04-a23e9fdf0211.png">

特徴としては

* Web Browser上のJavaScriptコードとして動くブラウザアプリケーション用のフレームワーク
* WebGLを使ったHardware Accelerationが可能
* GoogleのPAIRというプロジェクトから[OSSとして公開されている](https://github.com/PAIR-code/deeplearnjs)

[deeplearn.jsの紹介記事](https://qiita.com/search?q=deeplearn.js)はすでに幾つか見つけたのですが、自分が開発に携わっているということもあり布教も兼ねて改めて紹介したいと思います。

# Teachable Machine

deeplearn.jsの面白さを体感するにはこの[Teachable Machine](https://teachablemachine.withgoogle.com/)という最近できたデモで遊んでみるのがよいと思います。

<img width="1177" alt="Screen Shot 2017-12-01 at 23.18.23.png" src="https://qiita-image-store.s3.amazonaws.com/0/7129/482ebed3-35a0-7af9-80f7-6e1134ae0b6c.png">

左の画像をデータに右の教師データへの対応付を学習させるというものです。パソコンにWeb Cameraがついていればすぐに試すことができます。これはWeb Browser上で動くdeeplearn.jsで学習を行っています。つまりクライアントサイドで訓練と予測両方ができるフレームワークとなっています。

# Getting Started

自分でdeeplearn.jsを使ったアプリケーションを作る場合には[npm](https://www.npmjs.com/package/deeplearn)あるいは[yarn](https://yarnpkg.com/en/package/deeplearn)のパッケージとなっているので

```
$ npm install deeplearn
Or
$ yarn add deeplearn
```
でプロジェクトに組み込むことができます。またdeeplearn.jsにはすでに多くのdemoアプリが作られているのでこちらを手元で走らせてみるのがよいでしょう。

まずプロジェクトをcloneしてきます。

```
$ git clone https://github.com/PAIR-code/deeplearnjs.git
$ cd deeplearnjs
```
プロジェクトのビルドを行います。

```
$ yarn prep
```

デモアプリケーションは`demos`ディレクトリの下にあり、`watch-demo`というスクリプトで起動することができます。例えば`model-builder`というアプリケーションを起動するなら

```
$ ./scripts/watch-demo demos/model-builder
```

`watch-demo`はファイルの更新を監視して定期的にリコンパイルをするのでアプリの様子を見ながらコードの変更ができます。

<img width="1279" alt="Screen Shot 2017-12-02 at 11.45.54.png" src="https://qiita-image-store.s3.amazonaws.com/0/7129/716ce92d-f7bc-2241-4963-b7f491f55941.png">

ちなみに`model-builder`はMNISTやCIFAR 10といった画像識別のためのモデルをブラウザ上で作成して、それをダウンロードすることができます。`demo`の下には[オフィシャルサイトのExample](https://deeplearnjs.org/index.html#demos)に含まれていないものも多いので試してみてください。

# Architecture

どうやってWebGLでのHardware Accelerationを実現しているかを簡単に紹介したいと思います。

<img width="1035" alt="Screen Shot 2017-12-02 at 11.49.55.png" src="https://qiita-image-store.s3.amazonaws.com/0/7129/b812a6cc-9f11-60fd-7a95-d2942d04b862.png">

<iframe src="//www.slideshare.net/slideshow/embed_code/key/EKHL1CDYWr8iJ8" width="595" height="485" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" style="border:1px solid #CCC; border-width:1px; margin-bottom:5px; max-width: 100%;" allowfullscreen> </iframe> <div style="margin-bottom:5px"> <strong> <a href="//www.slideshare.net/lewuathe/deep-dive-into-deeplearnjs" title="Deep dive into deeplearn.js" target="_blank">Deep dive into deeplearn.js</a> </strong> from <strong><a href="https://www.slideshare.net/lewuathe" target="_blank">Kai Sasaki</a></strong> </div>


deeplearn.jsは数値計算用のKernelを持った`math`というフレームワークを内部的に持っています。簡単な四則演算から、行列の掛け算、畳み込みなどの計算を行うコードが含まれています。この`math`というフレームワークはインターフェースのみ提供していて実装は`NDArrayMathCPU`と`NDArrayMathGPU`に委ねられています。これらが裏側でCPUで動かすかWebGL経由でのGPUコードを動かすかを決めます。つまりアプリケーションのコードからは`math`という共通化されたAPIを叩くだけなのでCPUで動かそうと、WebGLで動かそうとアプリケーションコードは変わらないことになります。例えば行列の掛け算を行うコードは下記のようになります。

```typescript
// CPUの場合はこちら
const math = new NDArrayMathCPU();
// GPUの場合はこちら
// const math = new NDArrayMathGPU();

const matrixShape = [2, 3];  // 2 rows, 3 columns.
const matrix = Array2D.new(matrixShape, [10, 20, 30, 40, 50, 60]);
const vector = Array1D.new([0, 1, 2]);
const result = math.matrixTimesVector(matrix, vector);

console.log("result", await result.data());
```

与える`math`によってどこで計算を行うかを切り替えることができます。TensorFlow likeにSessionを使った計算もできます。

```typescript
const graph = new Graph();

const x: Tensor = graph.placeholder('x', []);


const a: Tensor = graph.variable('a', Scalar.new(Math.random()));
const b: Tensor = graph.variable('b', Scalar.new(Math.random()));
const c: Tensor = graph.variable('c', Scalar.new(Math.random()));

const order2: Tensor = graph.multiply(a, graph.square(x));
const order1: Tensor = graph.multiply(b, x);
const y: Tensor = graph.add(graph.add(order2, order1), c);

const yLabel: Tensor = graph.placeholder('y label', []);
const cost: Tensor = graph.meanSquaredCost(y, yLabel);

// Sessionに対して計算プラットフォーム用のmathを与えてあげる。
const math = new NDArrayMathGPU();
const session = new Session(graph, math);
```

`NDArrayMathCPU`の場合には愚直にTypeScriptで実装されていますが、`NDArrayMathGPU`にはGPUのメモリにバインドされたTextureデータを操作するFragment ShaderとしてKernelが実装されています。この記事では詳細は割愛しますが、WebGLを通したGPGPUとしてのコードを見ることができて面白いです。

# Future Works

deeplearn.jsはまだリリースされたばかりで活発に開発が続けられています。最後に今後予定されている機能、改善を取り上げたいと思います。詳細は[Roadmap](https://deeplearnjs.org/docs/roadmap.html)に記載されています。

## Automatic TensorFlow to deeplearn.js

今でもTensorFlowのモデル(GraphDef)をdeeplearn.jsにインポートすることは[可能ですが](https://deeplearnjs.org/demos/mnist/mnist.html)、計算グラフ自体を自分でdeeplearn.jsのコードとして書く必要がありかなり煩雑です。`GraphDef`ファイルを読んで自動で計算グラフを構築する機能が予定されています。

## Decoupling NDArray from storage mechanism

deeplearn.jsの基本的なデータ型である`Tensor`は内部のデータ保持に更に`NDArray`という型を用いています。`NDArray`は本来は多次元配列を表すだけの抽象的なデータ構造として利用されるべきなのですが、deeplearn.jsではCPUとGPU上でのデータ構造と密結合してしまっています。これを疎結合にしてデータ構造を柔軟に扱えるようにします。特にWebGLTextureの情報ははずせるようにしたいです。

## Model zoo

deeplearn.jsで使えるようにした学習済モデルを増やしていきます。すでに[ここ](https://github.com/PAIR-code/deeplearnjs/tree/master/models)に幾つかありますが、これを別管理にできるようにするのだと思います。

# まとめ

この他にもかっこいい感じのdemoアプリはいつでもcontribution welcomeらしいので是非興味がありましたら、作ってみてください！