Tensorflow.jsを使ってフロントエンドで画像解析

こんにちは、YAMAPでフロントエンドエンジニアとして働いている[SHiMPAY](https://qiita.com/SHiMPAY)です。
[YAMAP エンジニア Advent Calendar 2019](https://qiita.com/advent-calendar/2019/yamap-engginers)の21日目の記事になります。

ロングタイムアゴー、機械学習を勉強しようとしたのですが、僕の数学力が貧弱すぎて、
これは勉強しても頭がいい人は世界中にいるから同じ土俵で戦うのは無理だ。諦めようと決意しました🧟‍♂️

それからときが経ち、機械学習から離れている間に、Webブラウザ上で実行可能なライブラリとしてTensorFlow.jsが2018年に公開されていました🙌

フロントエンド側で利用できるなら、これは触る価値がある！
何かサービスに利用できないかと思い実際に触ってみました。

## TensorFlow.jsとは？ 🧠
TensorFlowは、機械学習向けに開発されたエンドツーエンドのオープンソース プラットフォームですが、
TensorFlow.jsは、ブラウザ内および Node.js上でモデルのトレーニングとデプロイを行うためのJavaScriptのライブラリです。

事前トレーニング済みのモデルが多数用意されているので、すぐに実行することが可能です。

## Model 
YAMAPではユーザーが活動日記という形で、登山記録を日記のように保存することができます。
活動日記はタグをつけることができるのですが、アップロードした写真から自動的にタグづけをできたら便利そうやなぁ。
と個人的に思いました。

そこで今回は [COCO-SSD](https://github.com/tensorflow/tfjs-models/tree/master/coco-ssd) というモデルを利用して画像からオブジェクト検出を行いました🖼

画像からオブジェクトを検出して、それをタグのレコメンドにしてみようという作戦です🧐

### 解析対象の画像

<img width="1100" alt="Screen Shot 2019-12-15 at 15.03.09.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61003/e54d642a-cc8d-6585-afc5-c839b14497a0.png">

今回はさくっと試したかったのでCDNを使用しています

```js

<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs"></script>
<script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/coco-ssd"></script>
```

### [NPM](https://www.npmjs.com/package/@tensorflow-models/coco-ssd)

```bash
npm i @tensorflow-models/coco-ssd
```

### コード

```js
const tags = document.querySelector('.tags')
const images = document.querySelectorAll('img')

const startAnalyse = () => {
    images.forEach(image => {
        analyseImage(image)
    })
}

const onClickAnalyseButton = () => {
    startAnalyse()
}

const analyseImage = async image => {
    await cocoSsd.load().then(model => {
        model.detect(image).then(predictions => {
            console.log(predictions)
            const analyseClass = predictions.map(prediction => prediction.class)
            if (analyseClass.length > 0) {
                const data = document.createElement('span')
                data.innerText = analyseClass
                tags.appendChild(data)
            }
        })
    })
}
```

### 結果...
<img width="1680" alt="Screen Shot 2019-12-15 at 15.22.10.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61003/c1be4f46-18e1-a620-3dd2-edc7c4f01954.png">

## YAMAPの命である山が検出されない😭😭😭

```
うまそうなラーメン -> ボウル 
ベンチで疲れてる女の子 -> ベンチ
ネコと山 -> ネコ
リナックスチョットデキルおじさん -> 人・一緒に写ってるペットボトル
```

まともにタグ付で使えそうなのネコちゃんだけ...😹
そこで、このモデルはどのようにオブジェクトを検出して、定義してるかちゃんと調べました。
プラグインの名前の由来通り[coco dataset](http://cocodataset.org/#home)から検出しているようです。

```
COCO is a large-scale object detection, segmentation, and captioning dataset.
```
とあるので、大まかなオブジェクトのセグメンテーションをしています。
90種類のクラスオブジェクトから検出されるみたいで、ここに山は定義されていませんでした🤣[here](https://github.com/tensorflow/tfjs-models/blob/master/coco-ssd/src/classes.ts)

## 所感

- 大まかなセグメントはできても、やはり自社サービスに特化したクラス検出は自社で実装する必要がありそう。
- Tensorflow.jsはサクッと実装できるので、参入障壁を下げてくれる。
- 山の画像は検出できなかったけど、画像から特定のオブジェクトを検出することがこれほど簡単にできるのはめっちゃすごいと思いました。
- データ分析チームの力をお借りすれば実現可能な未来もあるかと感じました⛰

今回は機械学習の本当に入り口ですが学習することできました。以前は書籍から概念を学ぼうとして断念しましたが、
学術的なことから学ぶより、実際に手を動かしてそこから中身を探っていく流れは、個人的に機械学習の苦手意識が下がった気がしてよかったです。

Tensorflow.jsには他にも事前トレーニング済みのモデルがあるので、試してみたいと思います（特にPoseNet Modelが気になります）

テクノロジーの力を利用して、もっと山のアップデートを行いたいと感じました！

おしまい