先日の技術書展 6 での購入物の中にml5.js と p5.js でつくる機械学習コンテンツプログラミング があった。 連休中に取り組んだら、内容が面白かったので興味から「ml5.js 」の提供する他の機能を使ってみたので、そんなメモ。
目次
やりたいこと 「ml5.js 」は機械学習のライブラリなので、 「学習」をしてみたかった。 人間の姿勢取得や動体検知も面白いのだけど、 興味があったのは学習することだったので、タグ付けした多数の画像を入力にして、 学習データを作る。推論することを試すことにした。
学習する、推論するだけなら、ブラウザいらないよね! ダメだった。 ml5.js を参照しているコードを node のコマンドラインで実行したら、 window オブジェクトが無いという趣旨のエラーで解決できなかった。 悔しいが断念。
コード コマンドライン実行ができなかったので、 学習自体もブラウザで実行することにする。
ml5.js を npm からインストールしてきたが、使いたい KNN 分類器がどうも動作できず、Github の ml5.js の dist の ml5.min.js と ml5.min.js.map をダウンロードして、node_modules\ml5\dist
の中身を差し替えておく。 (この辺は github の使い方がちゃんとしてる人は、もっと違うやり方をするんだろうか?)
ディレクトリ構成は以下の通り、
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 │ package-lock.json │ package.json │ webpack.config.js ├─node_modules ├─public │ │ index.html │ │ list.json │ │ │ └─img │ │ test.jpg │ │ │ ├─A │ │ A1.jpg │ │ 画像多数 │ │ │ └─B │ B1.jpg │ 画像多数 │ └─src index.js
読み込みする画像と、タグ付けの内容を list.js に定義する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 {"data":[ {"path":"\/img\/A\/A1.jpg","tag":"A"}, ・ ・ ・ {"path":"\/img\/B\/B23.jpg","tag":"B"} ]} ``` 実装コードは以下の通り、 ```javascript index.js const ml5 = require("ml5"); const axios = require("axios"); let imageEl = document.getElementById("image"); let messageEl = document.getElementById("message"); let probabilityEl = document.getElementById("probability"); let KnnClassifier; let featureExtractor; let datalist = []; let setup = async () => { console.log("[exe]", "setup"); //データを準備 datalist = await axios.get("/list.json").then(res => { return res.data.data; }); console.table(datalist); //KNN分類器を作成 KnnClassifier = ml5.KNNClassifier(); featureExtractor = ml5.featureExtractor("MobileNet", culc); }; let showresult = async results => { console.log("[exe]", "showresult"); console.table(results); messageEl.innerText = `[判定結果]:${results.label}`; let text = (() => { let keys = Object.keys(results.confidencesByLabel); let tm = "判定確率\n"; for (let i = 0; i < keys.length; i++) { tm += `[${keys[i]}]:${results.confidencesByLabel[keys[i]]}\n`; } return tm; })(); probabilityEl.innerText = text; }; let ch_image = function(el, path) { console.log("[exe]", "ch_image"); el.src = ""; el.src = path; return new Promise(resolve => { el.onload = () => { resolve(); }; }); }; let setlabel = async function(el, path, label) { console.log("[exe]", "setlabel"); //画像差し替え await ch_image(el, path); //特徴量を取得し const features = featureExtractor.infer(imageEl); //knn分類機にlabelの名称で登録 KnnClassifier.addExample(features, label); }; let culc = async () => { console.log("[exe]", "culc"); //モデル作成 for (let i = 0; i < datalist.length; i++) { console.log("[img]", i); await setlabel(imageEl, datalist[i].path, datalist[i].tag); } //推論 await ch_image(imageEl, "./img/test.jpg"); const featuresTest1 = featureExtractor.infer(imageEl); console.log("推測開始:"); // KNN分類器で分類を開始 KnnClassifier.classify(featuresTest1, (err, result) => { // エラーを表示する if (err) { console.error(err); } console.log("結果"); console.log(result); showresult(result); }); }; (async () => { await setup(); })();
上記を作成し、npm run dev
で実行する。 コンソールに表示された URL にアクセスすることで、 パラパラと画像が連続で読み出しされて最後に、推論結果を表示する。
学習対象画像とタグ付けは、動物でも何でもいいと思う。 ただ、画像のサイズはそろえたほうが精度がいいような気がした。縮小専用。 使うかjimp とか使えばいいと思う。
TensorFlow.js で線形回帰分析だけ触って挫折した身からすると、 すごく触りやすかった。
ではでは。