Python
JavaScript
Keras
TensorFlow.js

1次元畳み込みを利用した時系列解析をTensorFlow.jsを使ってやって見た

More than 1 year has passed since last update.

今日はみなさん

前回の記事にてTensorFlow.jsでconv1dのモデルロード時におかしなことになっているということを書いたのですが、先ほど (2018/5/24 16:20現在) 解消されたことが確認されたため、早速1次元畳み込みを利用したモデルを作ってみようと思い立ちました。


TensorFlow.jsにおけるconv1d

まずは、モデルを決めるわけですが、問題とモデルについては、以前にKerasのアドカレでやったものを流用することにします。

https://qiita.com/niisan-tokyo/items/a94dbd3134219f19cab1

ここにあるモデルを同じものをTensorFlow.jsで組むには、次のように書きます。


model.js

const model = tf.sequential()

model.add(tf.layers.conv1d({filters: 64, kernelSize: 8, padding: 'same', inputShape: [64, 1], activation: 'relu'}))
model.add(tf.layers.maxPooling1d({poolSize: 2, padding: 'same'}))
model.add(tf.layers.conv1d({filters: 64, kernelSize: 8, padding: 'same', activation: 'relu'}))
model.add(tf.layers.maxPooling1d({poolSize: 2, padding: 'same'}))
model.add(tf.layers.conv1d({filters: 32, kernelSize: 8, padding: 'same', activation: 'relu'}))
model.add(tf.layers.conv1d({filters: 1, kernelSize: 8, padding: 'same', activation: 'tanh'}))

PythonのKerasで書いたのと同じようにかけるわけです。

注意点としては、Kerasのパラメータの書き方は snake_case でしたが、TensorFlow.js では、 lowerCamelCase になっているということくらいです。

知らないと割と戸惑いますが、一回書いちゃえば楽チンです。


訓練させてみる

1次元畳み込みモデルで、時系列データを解析させて見ましょう。


train.js

import * as tf from '@tensorflow/tfjs'

const save_model = 'indexeddb://conv1d_test'
const load_model = 'indexeddb://conv1d_test'

// モデルの作成
const model = tf.sequential()
model.add(tf.layers.conv1d({filters: 64, kernelSize: 8, padding: 'same', inputShape: [64, 1], activation: 'relu'}))
model.add(tf.layers.maxPooling1d({poolSize: 2, padding: 'same'}))
model.add(tf.layers.conv1d({filters: 64, kernelSize: 8, padding: 'same', activation: 'relu'}))
model.add(tf.layers.maxPooling1d({poolSize: 2, padding: 'same'}))
model.add(tf.layers.conv1d({filters: 32, kernelSize: 8, padding: 'same', activation: 'relu'}))
model.add(tf.layers.conv1d({filters: 1, kernelSize: 8, padding: 'same', activation: 'tanh'}))

model.compile({optimizer: 'adam', loss: 'meanSquaredError'})

// データの作成
let raw_data = []
for (let i = 0; i < 10000; i++) {
raw_data.push((Math.sin(i) + Math.sin(3 * i) + Math.sin(10 * i) + Math.cos(5 * i) + Math.cos(7 * i)) / 5)
}

let xs = []
let ys = []

for (let j = 0; j < 9900; j++) {
xs.push(raw_data.slice(j, j+64))
ys.push(raw_data.slice(j+64, j+80))
}

const train_X = tf.tensor2d(xs, [9900, 64]).reshape([9900, 64, 1])
const train_Y = tf.tensor2d(ys, [9900, 16]).reshape([9900, 16, 1])

// 訓練
async function train() {
const start = new Date()
console.log('start!!')
await model.fit(train_X, train_Y, {epochs: 10, validationSplit: 0.1})
console.log('end!!')
const saveResult = await model.save(save_model)
model.predict(tf.tensor3d(raw_data.slice(9600, 9664), [1, 64, 1])).print()
console.log(raw_data.slice(9664, 9680))
const end = new Date()
console.log((end - start) / 1000)
}

train()


データの作成が若干面倒なものの、そこまで難しいコードになっているわけでもありませんね。

時間計測は console.log((end - start) / 1000)で出力していて、10epochで78.6秒という結果になりました。

訓練後はモデルのサイズが大きいので、localstorage ではなく indexedDBに入れています。


予測してみる

せっかくモデルが保存できたのだから、モデルをロードして予測してみましょう。


use.js

const load_model = 'indexeddb://conv1d_test'

async function predict(input, output) {
const model = await tf.loadModel(load_model)
tf.tidy(() => {
const x = tf.tensor3d(input, [1, 64, 1])
const y = tf.tensor3d(output, [1, 16, 1])
const res = model.predict(x)
res.print()
y.print()
y.sub(res).print()
})
}

const output = raw_data.slice(9664, 9680)
const input = raw_data.slice(9600, 9664)
predict(input, output)


予測値と期待値、およびその誤差を出してみました。

誤差はこんな感じです

Tensor

[[[0.0092286 ],
[0.0060897 ],
[-0.0017973],
[0.0042615 ],
[-0.0065808],
[0.0222413 ],
[0.0032337 ],
[0.0058675 ],
[-0.0066878],
[-0.005791 ],
[0.0043528 ],
[-0.0015932],
[0.005485 ],
[-0.0038473],
[-0.0019049],
[0.0048645 ]]]

うーん、まあ、こんなところなのかな。


でもやっぱり遅い?

ついでなので、PythonのKerasを使った場合との速度差を比較して見ます。

モデル自体は以前の記事を参照ください。

で、これで比較すると、Kerasを使った場合私の環境では、10epochsの学習時間が38.9秒となりました。

つまり、CPUを使っているはずのKerasの方が2倍も早いということです。

ちなみに、tf.setBackend('cpu')によって、jsの方のバックエンドをcpuにすると、これだけの学習がいつまでも終わらなくなります。

よくわからないですが、TensorFlow.js + webgl はpython の TensorFlow使った場合に比べて遅いらしいです。

https://www.publickey1.jp/blog/18/tensorflowjswebwebglgpu.html

KerasはバックエンドでTensorFlow使っていますし( xeonじゃないけど )、計測した内容に近いので、まあ、そうなんでしょう。

まだまだ、一般gpuによる超高速学習への道は険しいのかもしれません。


まとめ

conv1dを利用した時系列解析をTensorFlow.jsで実装して見ました。

ついでに、修正されたモデルの保存機能を試して、別のjsから保存したモデルをロードする機能を試して、推量を実施して見ました。

ブラウザ上で動かしているためか、どうしても計算速度が遅くなってしまうところですが、そこはwebglを使って補っている感じでしょうか。

なんにせよ、JavaScriptでも本格的な機械学習ができるようになりつつあって、喜ばしい限りです。

今回はこんなところです。