JavaScriptでDeep Learning


## 最近の興味

---

## 機械学習

---

## 私のレベル

- 昨年から年末年始にかけてCourseraの機械学習コースを修了
- 超基礎的なアルゴリズムがわかる
- 数式をみても説明ができる(厳密ではない…)
- [詳細はこちら](https://qiita.com/okmttdhr/items/092ec5fc450762a73ad0)

---

## JavaScriptで機械学習？

---

## JavaScriptで機械学習？

- Python/Rじゃないの？
- また「JSできもできちゃいました」系のやつ？

---

## JavaScriptで機械学習をするメリット

---

## JavaScriptで機械学習をするメリット

大きく2つ

1. JavaScriptが使える
2. 環境構築不要でGPUが使える

---

## 1. JavaScriptが使える

---

## 1. JavaScriptが使える

- JavaScriptは敷居がとっても低い言語
- 誰でも一度は書いたことがある
- ブラウザ開発者がなれた言語
- これはまあわからなくはない

---

## 1. JavaScriptが使える

ライブラリも結構ある。

- [karpathy/convnetjs](https://github.com/karpathy/convnetjs)
  - Deep Learning in Javascript. Train Convolutional Neural Networks (or ordinary ones) in your browser.
- [junku901/machine_learning](https://github.com/junku901/machine_learning)
  - Machine learning library for Node.js
- [janhuenermann/neurojs](https://github.com/janhuenermann/neurojs)
  - A javascript deep learning and reinforcement learning library.
- [cazala/synaptic](https://github.com/cazala/synaptic)
  - architecture-free neural network library for node.js and the browser
- [NaturalNode/natural](https://github.com/NaturalNode/natural)
  - general natural language facilities for node
- [wagenaartje/neataptic](https://github.com/wagenaartje/neataptic)
  - Blazing fast neuro-evolution & backpropagation for the browser and Node.js

デモ等

- [dmotz/thing-translator](https://github.com/dmotz/thing-translator)
  - Point your camera at things to hear how to say them in a different language
- [ofZach/landlines](https://github.com/ofZach/landlines)
  - landlines front end app
- [xviniette/FlappyLearning](https://github.com/xviniette/FlappyLearning)
  - Program learning to play Flappy Bird by machine learning (Neuroevolution)

---

## 1. JavaScriptが使える

##### **が、決定的ではない。**

##### **また、機械学習コミュニティもPython/Rと比べ物にならない。**

=>やっぱりPythonでいいのでは？

---

## 2. 環境構築不要でGPUが使える

---

## 2. 環境構築不要でGPUが使える

- 今日のメインはこっち
- GPUを手軽に使うことでプロトタイピングの高速化
- いろんな敷居が下がる

---

## GPUとは？

<img src="https://qiita-image-store.s3.amazonaws.com/0/22875/79cdb317-ff0e-e5d7-16ca-d0185e0d169e.jpeg" width="300"/>

- 元々画像処理のためのハード
- 高画質の動画を適切に処理するために、並列計算に特化したアーキテクチャ

---

## なぜGPUの話がでてくる？

- Deep Learningをやりたいのであれば、コンピュータの性能を無視することはできない
- むしろ、計算性能の向上がDeep Learningを支えている
- =>**「GPUの並列処理できるアーキテクチャを計算処理に利用してしまおう」**
- =>**GPGPU** (General-purpose computing on graphics processing units)
- =>**これがDeep Learningで使われている** (大量のデータを扱う場合/ニューラルネットの層が何層にもなる場合)

---

## GPGPUするには？

---

## GPUを用意する

GPUメーカー2強

- NVIDIA社: (GeForce/Quadro/Tesla)
- AMD社: (Radeon/FirePro/FireStream)

---

## 開発環境を用意する

GPUにアクセスするための開発環境/標準規格/フレームワーク/言語/APIがある

- CUDA
- OpenCL
- OpenGL
- DirectX
- etc

---

## 例.CUDA

- GPU購入(高いもので10万など)
- CUDAインストール
- cuDNNインストール(Deep Learning用のCUDAライブラリ)
- NVIDIAドライバーのセットアップ
- TensorFlow等フレームワークの環境構築
- ↑Dockerコンテナ等でつくる(好み)
- しかも、(CUDAに関しては)NVIDIA製のGPUを搭載しているハードウェアでしか使えない
- もしくはクラウドを使うという手もある(AWS/Azure/GCP。お金はかかるが時間は節約できる)
- =>**インフラ含めた環境構築が必要**

---

## 大変

---

## 大変 is

- それなりに準備が必要
- 開発環境への理解が必要
- 初学者には敷居が高い

---

## それ、JavaScriptとブラウザでできますよ

---

## WebGL

---

## WebGL

- OpenGLをJavaScriptに移植したもの
    - HTML上の画像や動画を簡単にテクスチャにできるように拡張してある
    - 関数名がJSっぽくなっている
- ブラウザからローカルマシンのGPUにアクセスできるAPI
- 閲覧者のOS/ハードウェアに関係なくクロスプラットフォーム
- =>**このGPU資産を演算に使う**
- =>**GPGPU**

---

## ブラウザからGPUを使って機械学習できるライブラリ

少ないが、いくつかある(&過去にもあった)

- [PAIR-code/deeplearnjs](https://github.com/PAIR-code/deeplearnjs)
  - Hardware-accelerated deep learning // machine learning // NumPy library for the web.
- [transcranial/keras-js](https://github.com/transcranial/keras-js)
  - Run Keras models in the browser, with GPU support using WebGL
- [mil-tokyo/webdnn](https://github.com/mil-tokyo/webdnn)
  - The Fastest DNN Running Framework on Web Browser
- [TensorFire](https://tenso.rs/)
    - TensorFire is a framework for running neural networks in the browser, accelerated by WebGL.
- [BrainJS/brain.js](https://github.com/BrainJS/brain.js)
  - 🤖 Neural networks in JavaScript

---

## deeplearn.js

---

## deeplearn.js

- Google製である
- WebGLを使ってGPUを使用した機械学習ができる
- 他のライブラリとは異なり、推論だけでなく学習も行うことができる
- TensorFlowといい感じに組み合わせて使うことができる

---

## ベンチマーク1

<img width="580" alt="スクリーンショット 2018-01-16 13.01.36.png" src="https://qiita-image-store.s3.amazonaws.com/0/22875/48c08db7-e2cd-8b66-16c9-90c4f936d927.png">

- [行列のかけ算](https://deeplearnjs.org/demos/benchmarks/)

---

## ベンチマーク2

<img width="1430" alt="スクリーンショット 2018-01-16 12.44.44.png" src="https://qiita-image-store.s3.amazonaws.com/0/22875/51805ae3-1263-4e69-3362-63c80c5ccc10.png">

- [MNISTの例](https://deeplearnjs.org/demos/model-builder/)
    - GPU: 数十秒で学習が収束してゆく
    - CPU: いつまでたっても終わらない…と思ったけど、コンソールでエラーが出ていて学習が開始しない:sweat_smile: ただ、そもそもCNNにおいて、基本的にはGPUを使用する。
    - 参考: [GPU vs CPU in Convolutional Neural Networks using TensorFlow](https://relinklabs.com/gpu-vs-cpu-in-convolutional-neural-networks-using-tensorflow)

---

## 使ってみた

---

## KaggleのTitanicチュートリアル

- [Titanic: Machine Learning from Disaster | Kaggle](https://www.kaggle.com/c/titanic)
- Kaggleの有名なチュートリアル
- Titanic号の沈没にて、どの乗客が死亡するか否かを予測する

---

## TypeScript環境の構築

- [GitHub](https://github.com/PAIR-code/deeplearnjs)にスターターがあるのでそれを真似ればOK
- TypeScriptなので、フロントエンドの人はいつものようにカスタマイズしてもOK

```json:package.json
{
  "name": "kaggle-titanic-deeplearn-js",
  "version": "1.0.0",
  "main": "main.js",
  "scripts": {
    "prep": "yarn && mkdirp dist",
    "watch": "watchify main.ts -p [tsify] -v --debug -o dist/bundle.js",
    "build": "browserify main.ts -p [tsify] -o dist/bundle.js",
    "lint": "tslint -p . -t verbose",
    "deploy": "yarn build && uglifyjs dist/bundle.js -c -m -o dist/bundle.min.js"
  },
  "dependencies": {
    "deeplearn": "^0.4.1"
  },
  "devDependencies": {
    "csv": "^2.0.0",
    "mkdirp": "~0.5.1",
    "tsify": "~3.0.3",
    "tslint": "~5.8.0",
    "typescript": "~2.6.1",
    "uglifyjs": "~2.4.11",
    "watchify": "~3.9.0"
  }
}
```

```json:tsconfig.json
{
  "compilerOptions": {
      "module": "commonjs",
      "sourceMap": true,
      "preserveConstEnums": true,
      "declaration": true,
      "target": "es5",
      "lib": ["es2015", "dom"],
      "outDir": "./dist"
  }
}
```

---

## データのクレンジング

- 不要なデータの削除
- 欠損値補完
- スケーリング
- 文字列の変数化

---

## 実装詳細

- 多層パーセプトロン
- 今回は入力、出力を合わせて3層だけ
- Optimizerは最急降下法(SGD)のみ
- 学習率、イテレーション数などはSGDが収束するように微調整した

```typescript:main.ts
import {
  Array1D,
  Array2D,
  NDArrayMathGPU,
  NDArrayMath,
  ENV,
  Scalar,
  Session,
  SGDOptimizer,
  InCPUMemoryShuffledInputProviderBuilder,
  CostReduction,
  Graph,
  Tensor,
  NDArray
} from 'deeplearn';

import {trainX} from './trainX';
import {trainY} from './trainY';
import {testX} from './testX';

const graph: Graph = new Graph();
const x: Tensor = graph.placeholder("x", [7]);
const t: Tensor = graph.placeholder('t', []);

// input layer - hidden layer
const w0: Tensor = graph.variable("w0", Array2D.randNormal([7, 7]));
const b0: Tensor = graph.variable("b0", Scalar.randNormal([]));
const h0: Tensor = graph.relu(graph.add(graph.matmul(x, w0), b0));

// hidden layer - output layer
const w1: Tensor = graph.variable("w1", Array2D.randNormal([7, 1]));
const b1: Tensor = graph.variable("b1", Scalar.randNormal([]));
const y: Tensor = graph.sigmoid(graph.reshape(graph.add(graph.matmul(h0, w1), b1), []));

const cost: Tensor = graph.meanSquaredCost(y, t);

const math: NDArrayMath = ENV.math;
const session: Session = new Session(graph, math);

math.scope((keep, track) => {
  const xs: Array1D[] = trainX.map(x => track(Array1D.new(x)));
  const ys: Scalar[] = trainY.map(x => track(Scalar.new(x)));

  const shuffledInputProviderBuilder = new InCPUMemoryShuffledInputProviderBuilder([xs, ys]);
  const provider = shuffledInputProviderBuilder.getInputProviders();
  const [xProvider, yProvider] = shuffledInputProviderBuilder.getInputProviders();

  const BATCHE_NUM = 500;
  const BATCH_SIZE = xs.length;
  const LEARNING_RATE = 1.13;

  const optimizer = new SGDOptimizer(LEARNING_RATE);
  console.log('BATCHE_NUM', BATCHE_NUM);
  console.log('LEARNING_RATE', LEARNING_RATE);

  for (let i = 0; i < BATCHE_NUM; i++) {
    const costValue = session.train(
        cost,
        [{tensor: x, data: xProvider}, {tensor: t, data: yProvider}],
        BATCH_SIZE, optimizer, CostReduction.MEAN
      );
    console.log('-----------------------------');
    console.log('index', i);
    console.log('cost', costValue.get());
  }
});
```

---

## デモ

こんな感じで、ブラウザ上で学習が進んでいく

<img width="693" alt="スクリーンショット 2018-01-17 18.12.56.png" src="https://qiita-image-store.s3.amazonaws.com/0/22875/cb7b8425-561f-ed52-0ede-351235fd1f6d.png">

<img width="695" alt="スクリーンショット 2018-01-17 18.13.15.png" src="https://qiita-image-store.s3.amazonaws.com/0/22875/ec00e212-fe7e-14af-7609-1332e64c75bd.png">

---

## 最終的な成果物をKaggleにsubmit

<img width="958" alt="スクリーンショット 2018-01-17 18.06.17.png" src="https://qiita-image-store.s3.amazonaws.com/0/22875/4ec01bd4-2b0f-6df0-2c5e-194a3718f8a8.png">

- Score 0.76076
- そんなによくはないですが、さくっとやった割にはいいのではないでしょうか…。
- もっと特徴量を細かく調整すればスコアは上がりそう。
- 機械学習力は今回のテーマとは別ということで…。

---

## いい感じに、学習から推論までJavaScript+ブラウザだけで完結できた

---

## ただし :warning: 

注意点として、以下の様なものがある。

1. 学習したモデルを使いまわせない
2. TensorFlowのモデルを(そのままでは)使えない

---

## 学習したモデルを使いまわせない :warning: 

<img width="1430" alt="スクリーンショット 2018-01-16 12.44.44.png" src="https://qiita-image-store.s3.amazonaws.com/0/22875/51805ae3-1263-4e69-3362-63c80c5ccc10.png">

- [MNISTの例](https://deeplearnjs.org/demos/model-builder/)
    - `Download model`をおしても、モデルの基本情報がダウンロードされるだけで、学習済みモデルのチェックポイントなどが手に入るわけではない。
    - これができないと、学習をJavaScript側で行うのは非現実的かもしれない
    - 現状TensorFlowのモデルをポーティングした方がいいかもしれない
    - これがないと始まらない感はあるので、すぐに対応されるとは考えられる

---

## TensorFlowのモデルを(そのままでは)使えない :warning: 

- Pythonで書いたモデルをそのまま使うことができない。
- 学習済み変数テンソルやバイアステンソルのチェックポイント時点の値は使用することができるのみ。
- Pythonのモデル実装をJSに書き直しているのに近い。
- 自動モデル生成を実装するのロードマップが公式にある

```js
import {CheckpointLoader, Graph} from 'deeplearnjs';
const reader = new CheckpointLoader('.');
reader.getAllVariables().then(vars => {
  // Write your model here.
  const g = new Graph();
  const input = g.placeholder('input', [784]);
  const hidden1W = g.constant(vars['hidden1/weights']);
  const hidden1B = g.constant(vars['hidden1/biases']);
  const hidden1 = g.relu(g.add(g.matmul(input, hidden1W), hidden1B));
  ...
  ...
  const math = new NDArrayMathGPU();
  const sess = new Session(g, math);
  math.scope(() => {
    const result = sess.eval(...);
    console.log(result.getValues());
  });
});
```

---

## JavaScriptで機械学習をするその他のメリット

- オンライン学習に使いやすい
- ネットワークが細くても、オフラインで動く
- APIを呼び出す必要がない

---

## まとめ

:thumbsup: 

- JavaScriptでDeep Learningをするメリットは少なくない
- JavaScriptという馴染みのある言語
- 環境構築不要、ブラウザだけでGPUを使用できる
- 高速な機械学習プロトタイプ開発
- オンライン学習に使いやすい
- ネットワークが細くても、オフラインで動く
- APIを呼び出す必要がない

:thumbsdown:

- 機械学習初心者が初めに触るには結局ハードルが高い
- 機械学習の開発環境について理解するために、結局TensorFlow等を一から学ぶ羽目になる(その結果、TensorFlowの環境構築ができるようになってしまうので、TensorFlow使ったほうがいいのでは、という結論も…)
- ライブラリの機能やコミュニティなど、まだ発展途上
- ローカルマシンのGPUでは足りないということもある(がっつりやるならやはりいいGPU環境が必要)
- 情報が少ない(Pythonが使われるようになったのも、エコシステムという側面がある。しかし、JavaScriptコミュニティは大きいのでこれから来るかもしれない)

---

## 参考

- [Google Developers Japan: deeplearn.js でブラウザから機械学習の力を活用](https://developers-jp.googleblog.com/2017/09/harness-power-of-machine-learning-in.html)
- [deeplearn.jsを遠くからそっと眺めてみた | adamrocker](http://blog.adamrocker.com/2017/08/deepleanjs.html)
- [deeplearn.jsを使ってKaggleのタイタニックをやってみる - tadajam's blog](http://tadajam.hateblo.jp/entry/2017/09/22/135505)
- [ブルゾンちえみ判別器をブラウザ上に実装する - Qiita](https://qiita.com/Quramy/items/d94178a830ff5e75e571)
- [10 Machine Learning Examples in JavaScript - Tutorialzine](https://www.one-tab.com/page/UhoSFxAfSe2UWYzgxE2XKQ)
- [初心者でも絶対わかる、WebGLプログラミング＜基礎知識編＞ | HTML5Experts.jp](https://html5experts.jp/yomotsu/2897/)
- [JavaScriptのWebGL 2.0でGPGPU - Qiita](https://qiita.com/teatime77/items/e867d7d462cb553b373d)
- [独学で 1 ヶ月間 OpenGL を学んで得た基礎知識のまとめ ~ 2D 編 ~ · けんごのお屋敷](http://tkengo.github.io/blog/2014/12/20/opengl-es-2-2d-knowledge-0/)
- [CUDAとOpenCLどっちがいいの？ - Qiita](https://qiita.com/aokomoriuta/items/777f00f4d9f2bec887ba)
- [Top Machine Learning Libraries for Javascript](https://www.one-tab.com/page/vcOuFcjHSZC4fswfTqAUYg)
- [PAIR: the People + AI Research Initiative](https://www.blog.google/topics/machine-learning/pair-people-ai-research-initiative/)
- [googlecreativelab/teachable-machine](https://github.com/googlecreativelab/teachable-machine)
- [研究開発:deeplearn.jsのインストールと実行環境 - livedoor Blog（ブログ）](http://blog.livedoor.jp/tak_tak0/archives/52382687.html)
- [はじめてのdeeplearn.js - Qiita](https://qiita.com/ashitani/items/6907215f47de229cf6bc)