Parcelで始めるTensorFlow.js (ブラウザ/Node.js)

2018年3月末にGoogleが[TensorFlow.js](https://js.tensorflow.org/)を[発表](https://medium.com/tensorflow/introducing-tensorflow-js-machine-learning-in-javascript-bf3eab376db)しました。
早速触ってみたので、Parcelを使って「[TensorFlow.js - Getting Started](https://js.tensorflow.org/#getting-started)」に掲載されているコードをブラウザとNode.jsで動かすまでを紹介します。
成果物は 「[shisama/tfjs-practice#getting-started](https://github.com/shisama/tfjs-practice/tree/getting-started)」にあります。

以下の環境で動作確認済
- Chrome: 65
- Node.js: 8.9.1

# TL;DR
* ビルドはparcel使うだけ
* ブラウザでもNode.jsでも動かすことができる
* とにかく始めたい人は[これ](https://github.com/shisama/tfjs-practice/tree/getting-started)使ってください

# Tensorflow.jsをインストール
「[TensorFlow.js - Getting Started](https://js.tensorflow.org/#getting-started)」に載っているそのままです。

```bash:npm
npm install @tensorflow/tfjs
```

```bash:yarn
yarn add @tensorflow/tfjs
```

# Parcelをインストール
[Parcel](https://parceljs.org/)に関しては、昨年末バズった「[webpack時代の終わりとparcel時代のはじまり](https://qiita.com/bitrinjani/items/b08876e0a2618745f54a)」という記事をお読み下さい。
以下はグローバルにインストールしていますが、`--save-dev`でプロジェクトにインストールしても、もちろん問題ありません。

```bash:npm
npm install -g parcel-bundler
```

```bash:yarn
yarn global add parcel-bundler
```

# Tensorflow.jsを使ったコード
「[TensorFlow.js - Getting Started](https://js.tensorflow.org/#getting-started)」に載っているそのままです。
ここではファイル名をmain.jsにします。

```js:main.js
import * as tf from '@tensorflow/tfjs';

// Define a model for linear regression.
const model = tf.sequential();
model.add(tf.layers.dense({units: 1, inputShape: [1]}));

// Prepare the model for training: Specify the loss and the optimizer.
model.compile({loss: 'meanSquaredError', optimizer: 'sgd'});

// Generate some synthetic data for training.
const xs = tf.tensor2d([1, 2, 3, 4], [4, 1]);
const ys = tf.tensor2d([1, 3, 5, 7], [4, 1]);

// Train the model using the data.
model.fit(xs, ys).then(() => {
  // Use the model to do inference on a data point the model hasn't seen before:
  model.predict(tf.tensor2d([5], [1, 1])).print();
});
```

# ブラウザ用HTML
ここではビルド後のJavaScriptファイルを読み込むだけのHTMLファイルを用意します。
あとから紹介するparcelでのビルドでこのhtmlを指定します。

```html:index.html
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
</head>
<body>
<script src="main.js"></script>
</body>
</html>
```

# ブラウザで動かす
まずはブラウザで動かすためにparcelでビルドします。

```bash
parcel build index.html --public-url ./
```

ビルド後はdistというディレクトリが作成されています。

```bash
.
├── dist
│   ├── index.html
│   ├── main.31f12d6f.map
│   └── main.f903cd46.js
├── index.html
├── main.js
├── node_modules
├── package-lock.json
└── package.json
```

あとは`dist/index.html`をブラウザで開いてDevToolsのコンソールを確認してください。
リロードするたびにモデルの学習結果が変わります。

# Node.jsで動かす
Node.jsで動かすためにJavaScriptをビルドします。
以下例ではビルド後のJavaScriptファイルを`dist_node`というディレクトリに出力するために`-d`オプションを付けています。

```bash
parcel build main.js -d dist_node
```

`dist_node`に出力されたJavaScriptファイルを実行します。

```bash
node dist_node/main.js
```

# 出力結果
ブラウザでもNode.jsでも実行内容は変わりません。以下は例です。
結果は学習結果によるので、以下とは違う結果になるかと思います。

```bash
Tensor
     [[8.2074938],]
```

# 参考

- [Tensorflow.js](https://js.tensorflow.org/)
- [Introducing TensorFlow.js: Machine Learning in Javascript](https://medium.com/tensorflow/introducing-tensorflow-js-machine-learning-in-javascript-bf3eab376db)
- [Parcel](https://parceljs.org/)
- [webpack時代の終わりとparcel時代のはじまり](https://qiita.com/bitrinjani/items/b08876e0a2618745f54a)

# 次にやること
babelだけでも問題無いはずなので試したい。webpackでもいけるはず。

最後までお読み頂きありがとうございました。
不備や質問はコメント欄またはTwitter([@shisama_](https://twitter.com/shisama_))からお願い致します。