deeplearn.jsのplaygroundで遊んでみる。SqueezeNetのソース理解

最近、おやつをガムに変えてみたところ、1か月で4キロほど痩せてしまった。
いままでどんだけおやつ食べてたんだと反省。

deeplearn.jsの勉強にと、とりあえず簡単そうなところから入ってみる。

playground

環境設定とかで躓きたくないので、とりあえずデモのPlayGroundで遊んでみる。
ここだと、サーバとか用意せず書いたコードをそのまま動かすことができるようだ。

deeplearnjs.org

SqueezeNet

playgroupndのリンクに「SqueezeNet - basic usage」とあったので、これ元にいじくって遊んでみよう。 その前に、SqueezeNetってなんだ?

https://www.semiconportal.com/archive/contribution/applications/170418-neurochip5-2.html

うーん、わからん。
わかったのは、ネットワークモデルの一種だということと、正確性より処理応答性を重視していることくらい。 使う分にはわからなくてもよいので、とりあえず表面をサラッと理解してみる。

ソースの理解

javascriptのソースを少しづつ理解していこう。

画像情報の読み込み

const catImage = document.getElementById('cat');

HTMLのIMGタグの画像情報を取り込んでいる。右下の猫の画像がそれ。
なんか細長い猫だなと思ったら、元画像は 240x217 で、IMGタグ内で 227x227 に変更している。 なんでやねんって、IMGタグのwidth x heightを240x217に変更して[RUN]を実行したらエラーになった。

Error: The output # of columns (119.5) must be an integer. Change the stride and/or zero pad parameters

どうやらSqueezeNetに読み込ませる画像は227x227出ないといけないようだ。

SqueezeNetのロード処理

const math = new dl.NDArrayMathGPU();
// squeezenet is loaded from https://unpkg.com/deeplearn-squeezenet
const squeezeNet = new squeezenet.SqueezeNet(math);
await squeezeNet.load();

SqueezeNetの何かを読み込んでいるらしい。
いきなり「dl」と出てきているが、これはplaygroundがデフォルトでdeeplean.jsを読み込んでいるため使えている。(だと思う)。 次の「NDArrayMathGPU()」は多次元配列をGPUで処理するものという理解(であっているのか?)

以下にdeeplearn.jsのチュートリアルを日本語訳されたサイトがあった。とても参考になる。

http://tensorflow.classcat.com/2017/08/20/deeplearn-js-tutorials-introduction/

イメージデータの変換

// Load the image into an NDArray from the HTMLImageElement.
const image = dl.Array3D.fromPixels(catImage);

何か変換しているのはわかるが、なんだろうこれ?よくわからないので「console.log()」で吐き出す。

console.log(catImage);
 ↓
[object HTMLImageElement]
console.log(image)
 ↓
Tensor dtype: int32 rank: 3 shape: [227,227,3] values: [[[255, 255, 255], [255, 255, 255], [255, 255, 255], ..., [255, 255, 255], [255, 255, 255], [255, 255, 255]], [[255, 255, 255], [255, 255, 255], [255, 255, 255], ..., [255, 255, 255], [255, 255, 255], [255, 255, 255]], [[255, 255, 255], [255, 255, 255], [255, 255, 255], ..., [255, 255, 255], [255, 255, 255], [255, 255, 255]], ... [[169, 193, 180], [165, 193, 178], [161, 196, 176], ..., [40 , 39 , 35 ], [55 , 51 , 48 ], [37 , 34 , 29 ]], [[150, 188, 173], [152, 190, 175], [158, 192, 175], ..., [27 , 26 , 22 ], [33 , 29 , 26 ], [30 , 27 , 22 ]], [[157, 194, 187], [164, 197, 186], [165, 198, 181], ..., [35 , 34 , 30 ], [49 , 44 , 40 ], [38 , 30 , 27 ]]]

IMGタグの画像情報をint32の3次元配列[227,227,3]に変換しているようだ。 画像が227x227なので、3はRGB情報だろう。

推論

// Predict through SqueezeNet.
const logits = squeezeNet.predict(image);

[Predict:予測] なので、たぶん推論しているんだろうな。 logitsって何だろう。

console.log(logits)
 ↓
Tensor dtype: float32 rank: 1 shape: [1000] values: [14.1952286, 12.3713379, 13.3236885, ..., 1.7310563, 17.3527832, 17.3972549]

float32の1次元配列[1000]が入っていた。よくわからない。

結果表示

// Convert the logits to a map of class to probability of the class.
const topClassesToProbs = await squeezeNet.getTopKClasses(logits, 10);
for (const className in topClassesToProbs) {
  console.log(
      `${topClassesToProbs[className].toFixed(5)}: ${className}`);
}

推論結果を出力。
squeezeNet.getTopKClassesの前にawaitが入っている。非同期処理を想定しているってことはそれなりに重い処理なのか?
想像するに、SqueezeNetには1000の答えがあり、上で求めた「logits」には、各答えの正解率が入っているのではないか?
「squeezeNet.getTopKClasses(logits, 10)」でそのうち上位10件を切り出している。そんなところだろう。

よくわからないこと

HTML部に

<script src='https://unpkg.com/deeplearn-squeezenet'></script>

とあるが、これはなんだ?削っても問題なく動くし。
アクセスするとよくわからないJavascriptソースが下りてきた。

まとめ

一番簡単そうなソースで遊んでみましたが、DeepLearningの知識がほとんどない自分には突っかかりまくりで大変でした。このソースを使って応用する場合、画像サイズは227x227にそろえることを覚えておこう。

以上