jupter notebookでjavascriptを使いたいと思っていたところ、以下のnotebookを見つけました。
この方法のポイントは、以下の通りです。
以下にDeep Learning with Javascriptの2章の例題をGoogle Colabで実行してみます。 例題は、以下のGithubにありました。
以下のセルを実行して、本ノートブックの再ロード(F5キーを押下)してください。
一度カーネル環境が作成された後(Google Colabのセッションが有効な間)は実行する必要はありません。
!npm install -g npm@latest
!npm cache verify
!npm install -g --unsafe-perm ijavascript
!ijsinstall --install=global
!jupyter-kernelspec list
ERROR! Session/line number was not unique in database. History logging moved to new session 59 /tools/node/bin/npm -> /tools/node/lib/node_modules/npm/bin/npm-cli.js /tools/node/bin/npx -> /tools/node/lib/node_modules/npm/bin/npx-cli.js + npm@6.14.4 added 325 packages from 161 contributors, removed 423 packages and updated 59 packages in 10.505s Cache verified and compressed (~/.npm/_cacache): Content verified: 78 (21053000 bytes) Index entries: 79 Finished in 0.705s /tools/node/bin/ijs -> /tools/node/lib/node_modules/ijavascript/bin/ijavascript.js /tools/node/bin/ijsconsole -> /tools/node/lib/node_modules/ijavascript/bin/ijsconsole.js /tools/node/bin/ijsinstall -> /tools/node/lib/node_modules/ijavascript/bin/ijsinstall.js /tools/node/bin/ijskernel -> /tools/node/lib/node_modules/ijavascript/lib/kernel.js /tools/node/bin/ijsnotebook -> /tools/node/lib/node_modules/ijavascript/bin/ijsnotebook.js > zeromq@5.2.0 install /tools/node/lib/node_modules/ijavascript/node_modules/zeromq > node scripts/prebuild-install.js || (node scripts/preinstall.js && node-gyp rebuild) + ijavascript@5.2.0 added 67 packages from 65 contributors in 4.07s
以降のセルからjavascriptが使えるようになります。
注意事項 constとlet文は使わず、varを使ってください
セル内でコマンドを実行するsh関数を定義します。
var { spawn } = require('child_process')
var sh = (cmd) => {
$$.async()
var sp = spawn(cmd, { cwd: process.cwd(), stdio: 'pipe', shell: true, encoding: 'utf-8' })
sp.stdout.on('data', data => console.log(data.toString()))
sp.stderr.on('data', data => console.error(data.toString()))
sp.on('close', () => $$.done())
}
var run_async = async (pf) => {
$$.async()
await pf()
$$.done()
}
sh('npm init -y')
Wrote to /content/package.json: { "name": "content", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC" }
sh('npm install @tensorflow/tfjs-node')
sh('npm install plotly-notebook-js')
npm WARN content@1.0.0 No description npm WARN content@1.0.0 No repository field.
+ plotly-notebook-js@0.1.2 added 1 package from 1 contributor and audited 167 packages in 1.071s 1 package is looking for funding run `npm fund` for details found 0 vulnerabilities
以下のセルの実行でエラーになった場合には、ブラウザーのF5(再読み込み)を実行してもう一度試してみまてください。
var tf = require('@tensorflow/tfjs-node')
console.log(tf.backend().isUsingGpuDevice)
node-pre-gyp info This Node instance does not support builds for N-API version 4 node-pre-gyp info This Node instance does not support builds for N-API version 5 node-pre-gyp info This Node instance does not support builds for N-API version 4 node-pre-gyp info This Node instance does not support builds for N-API version 5
false
(node:247) Warning: N-API is an experimental feature and could change at any time.
テストデータとして、ファイルサイズとダウンドード時間の観測データをtrainData, testDataにセットします。
var trainData = {
sizeMB: [0.080, 9.000, 0.001, 0.100, 8.000, 5.000, 0.100, 6.000, 0.050, 0.500,
0.002, 2.000, 0.005, 10.00, 0.010, 7.000, 6.000, 5.000, 1.000, 1.000],
timeSec: [0.135, 0.739, 0.067, 0.126, 0.646, 0.435, 0.069, 0.497, 0.068, 0.116,
0.070, 0.289, 0.076, 0.744, 0.083, 0.560, 0.480, 0.399, 0.153, 0.149]
}
var testData = {
sizeMB: [5.000, 0.200, 0.001, 9.000, 0.002, 0.020, 0.008, 4.000, 0.001, 1.000,
0.005, 0.080, 0.800, 0.200, 0.050, 7.000, 0.005, 0.002, 8.000, 0.008],
timeSec: [0.425, 0.098, 0.052, 0.686, 0.066, 0.078, 0.070, 0.375, 0.058, 0.136,
0.052, 0.063, 0.183, 0.087, 0.066, 0.558, 0.066, 0.068, 0.610, 0.057]
}
tf.tensor2d関数を使って2次元テンソルに変換します。[20,1]はデータの次数(shape)を指定します。
var trainTensors = {
sizeMB: tf.tensor2d(trainData.sizeMB, [20, 1]),
timeSec: tf.tensor2d(trainData.timeSec, [20, 1])
}
var testTensors = {
sizeMB: tf.tensor2d(testData.sizeMB, [20, 1]),
timeSec: tf.tensor2d(testData.timeSec, [20, 1])
}
trainDataとtestDataの分布をPlotlyライブラリを使って可視化(プロット)します。
plotlyに渡すデータ構造にするために、dataTraceTrain, dataTraceTestに必要な情報をセットします。
var dataTraceTrain = {
x: trainData.sizeMB,
y: trainData.timeSec,
name: 'trainData',
mode: 'markers',
type: 'scatter',
marker: {symbol: "circle", size: 8}
};
var dataTraceTest = {
x: testData.sizeMB,
y: testData.timeSec,
name: 'testData',
mode: 'markers',
type: 'scatter',
marker: {symbol: "triangle-up", size: 10}
};
var Plot = require('plotly-notebook-js')
var NotebookPlot = Plot.createPlot().constructor
NotebookPlot.prototype._toHtml = NotebookPlot.prototype.render
Plot.createPlot([dataTraceTrain, dataTraceTest], {
width: 700,
title: 'File download duration',
xaxis: {
title: 'size (MB)'
},
yaxis: {
title: 'time (sec)'
}
})
ニューラルネットワークの層を作成します。ここでは入力として1個の要素を持つ入れる配列を持つ、密結合の層(dense)を追加します。unitsで出力値が1個であると設定します。
オプティマイザーとして'sgd'(確率的勾配降下法) , 'meanAbsoluteError'(損失関数として絶対値の平均)を指定して、modelをコンパイルします。
var model = tf.sequential();
model.add(tf.layers.dense({
units: 1,
inputShape: [1],
}))
model.compile({ optimizer: 'sgd', loss: 'meanAbsoluteError' })
回帰で求めるのは、転送時間(timeSec)で、入力としてファイルサイズ(sizeMB)を与えます。
回帰分析ではニューラルネットの重みmと切片bで計算されます。 $$ timeSec = kernel * sizeMB + bias $$
setWeights関数で重みkの初期値と切片bの初期値をここでは0として開始します。
var k = 0
var b = 0
model.setWeights([tf.tensor2d([k], [1, 1]), tf.tensor1d([b])])
kerasと同様にfit関数で回帰を実行します。 出力のlossがEpoch毎に小さくなって収束しているのがわかります。
model.fit(trainTensors.sizeMB, trainTensors.timeSec, {epochs: 10})
Epoch 1 / 10
7ms 330us/step - loss=0.295 Epoch 2 / 10
8ms 377us/step - loss=0.192 Epoch 3 / 10
7ms 329us/step - loss=0.0899 Epoch 4 / 10
6ms 307us/step - loss=0.0725 Epoch 5 / 10
8ms 385us/step - loss=0.0632 Epoch 6 / 10
6ms 321us/step - loss=0.0825 Epoch 7 / 10
9ms 453us/step - loss=0.0370 Epoch 8 / 10
8ms 386us/step - loss=0.0671 Epoch 9 / 10
8ms 403us/step - loss=0.0411 Epoch 10 / 10
8ms 410us/step - loss=0.0798
History { validationData: null, params: { epochs: 10, initialEpoch: 0, samples: 20, steps: null, batchSize: 32, verbose: 1, doValidation: false, metrics: [ 'loss' ] }, epoch: [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ], history: { loss: [ 0.2950499951839447, 0.19248802959918976, 0.08992607891559601, 0.0724872499704361, 0.06317649036645889, 0.08248651027679443, 0.03697093203663826, 0.06710976362228394, 0.0411013700067997, 0.07980944216251373 ] } }
学習したニューラルネットのモデルを表示するために、testTensorsで評価してみましょう。 0.013と小さな誤差にまとまっているみたいです。
model.evaluate(testTensors.sizeMB, testTensors.timeSec).print()
Tensor 0.01322927325963974
新しいファイルサイズ(7.8)に対するダウンロード時間は、7.8を2重に鍵かっこ([])で括ってtensor2dに渡してpredict関数で計算することができます。グラフと比較すると0.59とよい値を予測していることがわかります。
model.predict(tf.tensor2d([[7.8]])).print()
Tensor [[0.5941021],]
回帰で求まったk, bの値をみてみましょう。
k = model.getWeights()[0].dataSync()[0]
b = model.getWeights()[1].dataSync()[0];
console.log(k, b)
0.06809000670909882 0.06300000101327896
kとbの値が求まったので、データと回帰直線を一緒にプロットしてみましょう。
var traceLine = {
x: [0, 10],
y: [b, b + (k * 10)],
name: 'trace line',
mode: 'lines'
}
Plot.createPlot([dataTraceTrain, dataTraceTest, traceLine], {
width: 700,
title: 'File download duration',
xaxis: {
title: 'size (MB)'
},
yaxis: {
title: 'time (sec)'
}
})