見出し画像

まずは機械学習の「モデル」を読み込むプログラミングから! 第1章❷ 変数と関数の基礎を理解する ー 『JavaScriptでやる1分間プログラミング』

たった5行のコードでプログラミングの超重要概念を理解する

本パートでは、さっそくお絵描き認識アプリのバージョン1作成を目指してプログラミングをしていきましょう!とは言っても今回書くのは

たったの5行!

でもそこからプログラミングの超重要な考え方をたっぷりと学ぶことができます。特にプログラミング初心者の方はじっくりと読み込んで基礎を理解してください。

今回はその5行のコーディングで次のプログラミング用語について理解します。

✅ 変数
✅ 関数
✅ 属性
✅ メソッド
✅ コールバック

たった5行の中にこの重要なコンセプトが盛り込まれています。これからプログラミングをする上でも大切な概念ですので、ぜひ頑張って理解してください!

あなたはもう機械学習のコードを書く準備ができている!

まずは前回の第❶章パート❶で作ったHTMLファイルで、夜空のビデオが背景になっているバージョン、Oekaki2を開いてください。コードは全パートの最後に掲載していますので、詳しくはそちらをご覧ください。

画像7

VSCodeを開き、「ファイル」ー「フォルダを開く」からOekaki2フォルダを選ぶだけです。ちなみにHTMLコードはこんな感じでした。

<!DOCTYPE html>
<html>
<head>
  <script src="https://cdn.jsdelivr.net/npm/p5@1.2.0/lib/p5.min.js"></script>
  <script src="https://unpkg.com/ml5@0.6.0/dist/ml5.min.js"></script>
  <link rel="stylesheet" href="style.css">
  <meta charset="utf-8" />
</head>

<body>
  <section class="wholesecion">
      <div class="video-container">
          <video src="https://traversymedia.com/downloads/video.mov" autoplay muted loop></video>
      </div>
      <div id="content-div" class="content">  
          <h1>この絵は何の絵?</h1>
          <div id="results-div" class="results"></div>
          <div id="canvas-div" class="canvas"></div>
      </div>
  </section>

  <script src="sketch.js"></script>
</body>
</html>

ではこのコードの5行目に注目してください。

<script src="https://unpkg.com/ml5@0.6.0/dist/ml5.min.js"></script>

実はこれ、機械学習を使うためのJavaScriptを参照しているコードなのです。つまり、今のコードですでに機械学習を使う準備はできていたということです。

よくわからないと思いますので一つ一つ説明します。

まず、『今すぐ書ける 1分間プログラミング』で使ったMagicWandのように、機械学習を使うためのJavaScriptモジュールをここで使えるようにしているのです。そのJavaScriptモジュールというのがML5.jsというものです。

機械学習というとPythonというプログラミング言語がよく利用されますが、ML5はJavaScriptによって機械学習を簡単にWebで使えるようにするプロジェクトで、ウェブサイト上で物体認識や画像比較、画像分類など様々なタスクを実行することができるとても便利なツールなのです。しかも使い方は簡単です。

その中で今回利用するのは画像分類(Image Classification)です。そこで、このML5を、自作したウェブページで使えるようにする魔法の1行が先の<script>タグです。ここではML5の0.6.0というバージョン(現時点での最新版)を参照し、「このモジュールを使いますよ」と宣言しています。

たったこれだけであながが書くJavaScript内でML5が使えるようになるのです!

画像1

ということで現在のHTMLにはすでにこの行が入っているので、とりあえず完了です。早速JavaScriptでのプログラミングをやっていきます。

今回のプログラミング作業の準備

作業を始める前にJavaScriptのコードで何をプログラミングするのか、まずはその概要を理解してください。

ステップ❶:画像分類をする”モデル”をウェブページ内に読み込む
ステップ❷:キャンバスに描いた絵をモデルに渡す
ステップ❸:モデルは何の絵であるか推測する
ステップ❹:モデルが推測した絵の名前を画面に表示させる

機械学習に触れるにあたって重要なのは「モデル」という概念を理解することです。きれいな”モデルさん”の「モデル」でもなく、プラモデルの「モデル」とも違います。いったん理解すると簡単なのですが、慣れてないと戸惑うはずです。まずはこれが何であるかをしっかり理解してください。プロローグでは機械学習の基礎を解説したメモを作っていますので、「モデル」を理解していない方は次のメモnoteを必ず読んでください

画像10

どうですか、モデルについては大体理解できましたか?要は、機械学習をするというのはモデルを作ったり、使ったりすることに他なりません。だから「モデル」が何であるかを知るのが大切なのです。

もちろん今回のプロジェクトでは、すでに作られたモデル(皆さんは一から作り上げる必要はありません)を皆さんに使ってもらい、それでもって手描きの絵の自動認識をするわけです。

今回使用するモデルDoodleNetと呼ばれるモデルです。このDoodleNet(ドゥードゥルネット)って何なのか是非知っておいてください。

【技術解説】DoodleNetって何?

ここで使う手書き絵の自動分類モデル、DoodleNetというのはニューヨーク大学の先生(Lecturer)のYining Shiさんが、Quick Draw(前回の第❶章パート❶で皆さんが遊んだお絵描きウェブサイトを覚えていますか?)でのデータをもとに345種類の絵を認識する機械学習モデルとして作り、それをML5用に提供したものです。詳しくはこのGitHubのページを読んでみてください。

ちなみに彼女が作ったサンプルアプリのサイトにどんな絵を認識するか一覧表があります。最初のいくつかだけを紹介します。

航空機運搬船、飛行機、目覚まし時計、救急車、天使、動物の移動、蟻、アンビル、リンゴ、腕、アスパラガス、斧、バックパック、バナナ、包帯、納屋、野球、野球バット、バスケット、バスケットボール、バット、バスタブ、ビーチ、クマ、ひげ、ベッド、蜂、ベルト、ベンチ、自転車、双眼鏡、鳥、バースデーケーキ、ブラックベリー、ブルーベリー、本、ブーメラン、ボトルキャップ、ボウタイ、ブレスレット、脳、パン、橋、ブロッコリー、ほうき、バケツ、ブルドーザー、バス・・・<以下省略>・・・

要は、彼女のおかげでこの345種類もの絵の認識をしてくれるモデルがML5で利用できるようになっているわけです。Yiningさんに感謝です!

では、機械学習においてモデルが何か、お絵描きアプリではどんなモデルを使うのかについて理解したら、いよいよプログラミングをやっていきましょう。

準備作業:プロジェクトフォルダを作成する

まずは本パート用にプロジェクトフォルダを作成します。

今回はOekaki3というフォルダを作って、Oekaki2の中身をそのままコピーしてください。フォルダの中にはindex.htmlとsketch.js、style.cssの3つのファイルがありますが、すべてそのままコピーしてOekaki3フォルダの中にペーストしてください。

フォルダの作成とファイルのコピーが完了したらVSCodeをスタートし、Oekaki3フォルダを開いてください

ステップ❶:手描き絵認識モデルをウェブページ内に読み込む

新たに作成したOekaki3の中にあるsketch.jsを開いてください。その中に、モデルを読み込む(「ロードする」とも言います)次のコードを追加します。function setup()という中括弧({と})で囲まれたセクションの中の後半に、次のように、「//モデルを読み込む」と書かれた行以下の3行のコードを加えてください。

注意://で始まる行はコメントといって「開発者メモ」の役割をする行なので実行されるプログラミングコードとは別です。なので行数には含めません。

めんどうであればこのsetupセクションをそのままコピペして上書きしても構いません。

function setup() {
    //キャンバスを用意
    canvas = createCanvas(400, 400);//Canvasを作成
    canvas.parent('canvas-div'); //@@@ここを追加@@@
    background(255); //Canvasの背景を白にする
    //ボタンを用意
    clearButton = createButton('消す');//ボタンを作成
    clearButton.parent('canvas-div'); //@@@ここを追加@@@
    clearButton.mousePressed(clearCanvas);//ボタンクリックの関数を指定
      
    //モデルを読み込む
    doodleClassifier = ml5.imageClassifier('DoodleNet');
    
    //ロード中のメッセージを表示
    resultsDiv = createDiv("モデルをロードしています・・・");
    resultsDiv.parent('results-div');
 }

まず加えたコードの最初の一行目を見てください。

//モデルを読み込む
doodleClassifier = ml5.imageClassifier('DoodleNet');

この行の意味を”翻訳”するとしたらこうなります:


doodleClassifierというのはml5imageClassifierの中でもDoodleNetという名前のものを持ってきたものです

さて、この一行を理解するにはどうしてもプログラミング用語の「変数」と「関数」、「メソッド」などの基礎概念を理解する必要があります。これはプログラミングをするには大変重要なポイントなので、メモ記事を用意して、超初心者でも理解できるように説明しました。まずはこのメモ記事を読んでから次に進んでください。

画像8

「関数」と「変数」はだいたいどんなものか理解できましたか?では実際のコードで変数と関数をさらに理解していきましょう。

【コード解説】DoodleNetのモデルの読み込み

コードをもう一度見てみます。

//モデルを読み込む
doodleClassifier = ml5.imageClassifier('DoodleNet');

この1行はこういうことです。ここでdoodleClassifierという変数の入れ物を作り、その中にDoodleNetのClassifier(つまりこれがモデルそのものです)をぶち込んでいます。ここではdoodleClassifierが「変数」、ml5.imageClassifierはモデルを差し出してくれる 「メソッド」です。’DoodleNet'というのは引用符でかこまれた文字列です。

そしてついでに説明すると、sketch.jsのJavaScript内にある、中括弧で囲まれたsetupセクションとdrawセクションはそれぞれ「関数」なのです。それぞれfunction(関数)で始まっているので明白ですよね。

function setup () {
  ・・・関数の中身・・・
}

function draw() {
  ・・・関数の中身・・・
}

モデルの読み込みには時間がかかるのです

モデルが読み込まれたら早速画像を認識しよう・・・といきたいところですが、その前に一つやることがあります。ユーザーに「機械学習のモデルを読み込んでいますよ」と教えてあげることです。

どうしてこんなことをするかというと、この画像認識のモデルはサイズが大きいのです。それがML5のサーバーから直接ブラウザ内にロードされるため、ネットスピードが遅い人には数秒時間がかかることもあります。モデルの読み込み前に絵を描いてもらっては困ります。そこで画面に「モデルをロードしています」というメッセージを表示させ、ユーザーに待ってもらうのです。パソコンを使っていて「〇〇しています」、「〇〇中・・・」というメッセージはよく見かけますよね。

そこでこのメッセージを表示するコードがこれです。モデルの読み込みをするコードの次にこの2行を追加しています。

//ロード中のメッセージを表示
resultsDiv = createDiv("モデルをロードしています・・・");
resultsDiv.parent('results-div');

これはP5を使っているから書けるコードで、通常のJavaScriptでHTMLページの中に文字を挿入する方法とは異なります。ここではcreateDivというP5の関数を使って「モデルをロードしています」というテキスト部分を作成し、それをHTML内の"results-div"という場所に表示しているのです。

ちょっと難しい説明になりました。このJavaScriptを使ってHTML内にテキストを入れる方法はまた後の章で詳しく解説します。とりあえず、この2行はページ内に「モデルをロードしています」というメッセージを表示しているのだという点だけ理解してください。

最終的なSetup関数はこうなります。

//キャンバスの設定
function setup() {
    //キャンバスを用意
    canvas = createCanvas(400, 400);//Canvasを作成
    canvas.parent('canvas-div'); //@@@ここを追加@@@
    background(255); //Canvasの背景を白にする
    //ボタンを用意
    clearButton = createButton('消す');//ボタンを作成
    clearButton.parent('canvas-div'); //@@@ここを追加@@@
    clearButton.mousePressed(clearCanvas);//ボタンクリックの関数を指定
    
      //モデルを読み込む
      doodleClassifier = ml5.imageClassifier('DoodleNet');
    
      //ロード中のメッセージを表示
      resultsDiv = createDiv("モデルをロードしています・・・");
      resultsDiv.parent('results-div');
}

書いたコードをテストする

ではsketch.jsのファイルを変更したので保存し、Oekaki3フォルダのindex.htmlファイルをダブルクリックして開いてみてください。

画像2

おおっ、キャンバスの上に例のメッセージが表示されている!すごい!

画像3

確かにすごいのですが、いつまでたっても「ロードしています・・・」のまま。一体モデルの読み込みはいつ完了するのでしょう。完了したら「ロードされました」とか言ってほしいですよね。そうなんですが、当然皆さんがコードを書かないとそんなことにはなりません

画像9

モデルの読み込みが完了はどうしたら分かる?

先のモデルの読み込みのコードをもう一度見てください。

//モデルを読み込む
doodleClassifier = ml5.imageClassifier('DoodleNet');

imageClassifierというメソッドに「DoodleNetのモデルをください」と言っているのですが、実はすぐにモデルがdoodleClassifierという変数に入るわけではないのです。ではモデルの読み込みが完了したら、そのimageClassiferというメソッドが教えてくれないの?と思った方。正解です!

実はimageClassifierメソッドにはこんな仕組みがあるのです。

//モデルを読み込む
doodleClassifier = ml5.imageClassifier('DoodleNet', [あなたの関数]);

この[あなたの関数]というところに、あなたが用意した関数を指定すると、モデルの読み込みが終わったらその関数を実行してくれるのです。メモnoteを読んだ方は理解していると思いますが、関数は「動作の入れ物」でしたよね。[あなたの関数]というところにあなたが用意した関数の入れ物の名前を指定しておいてやると、モデルがロードされたらそれを実行してくれます。そして、その関数の中で「モデルの読み込みが完了しました」というメッセージを表示させてやればよいのです。

なんだかよく分かりませんよね。では次の解説でもっとかみ砕いて説明します。

関数には「書き置き」をしてくれるものがある

まずこの仕組みを理解するために「書き置き」を思い浮かべてください。

何かを頼みたいのだけれど、肝心の相手が今いない。すぐに戻るかもしれないし、1時間くらいもかかるかもしれない。戻りの時間は分からないけれど、席に戻ったらあることをやってもらいたい。そんな時に「書き置き」をしますよね。

メッセージ_m

今回のモデルの読み込みも同じです。人によっては一瞬で終わるかもしれないし、5秒くらいかかるかもしれない。でも読み込みが終わったら「モデルが完了だよ!」というメッセージを表示させたい。この「表示」動作を指定してやるのが「書き置きの関数」なのです。

実際にコードを変更してみましょう。モデルの読み込みが終わったら実行する新しいセクション、つまり関数を作ります。ここではmodelReady(モデルの準備完了)という名前にしておきましょう。まずはモデルの読み込みのコードで「関数の入れ物」の名前、modelReadyを指定します。

//モデルを読み込む
doodleClassifier = ml5.imageClassifier('DoodleNet', modelReady);

「書き置き」のことを”コールバック”という

プログラミングでは思ったよりも時間がかかる処理というのはよくあることです。そんな時に「終わったら必ずやっておいてね」という仕組みがとても重宝されます。この「書き置き」の仕組みをコールバックと呼びます。時間がかかる処理がある時に使えると覚えておいてください。

初めての関数、modelRedyを書く!

さっそくmodelReady関数を書いてみます。次の3行のコードをsetupセクションのすぐ下に入れてください。

//モデルがロードされた時の処理
function modelReady() {
   resultsDiv.html("モデル準備完了!");
}

ここはresultsDivという、さっき「モデルをロードしています」というメッセージを表示したのと同じ場所に、今度は「モデル準備完了!」というメッセージを表示させます。全体はこんな感じになります。うまくいかない人はこれをsketch.jsにコピペしてみてください。

let canvas; //絵を描くエリア
let clearButton; //消すボタン

//キャンバスの設定
function setup() {
    //キャンバスを用意
    canvas = createCanvas(400, 400);//Canvasを作成
    canvas.parent('canvas-div'); //@@@ここを追加@@@
    background(255); //Canvasの背景を白にする
    //ボタンを用意
    clearButton = createButton('消す');//ボタンを作成
    clearButton.parent('canvas-div'); //@@@ここを追加@@@
    clearButton.mousePressed(clearCanvas);//ボタンクリックの関数を指定
      
    //モデルを読み込む
    doodleClassifier = ml5.imageClassifier('DoodleNet', modelReady);
    
    //ロード中のメッセージを表示
    resultsDiv = createDiv("モデルをロードしています・・・");
    resultsDiv.parent('results-div');
}

//モデルがロードされた時の処理
function modelReady() {
    resultsDiv.html("モデル準備完了!");
}

//マウスで絵を描くための関数
function draw() {
  if (mouseIsPressed) {
    strokeWeight(18);
    line(mouseX, mouseY, pmouseX, pmouseY);
  }
}

//絵を全て消すボタンの動作
function clearCanvas() {
    background(255);
}

では変更を保存して、ページを更新してみてください。ページを更新するとすぐに「モデルをロードしています」というメッセージが出てきて、その後は「モデル準備完了」に変わりますよね。最初のメッセージが表示される時間は皆さんのお使いのネット速度によって変わります。メッセージの切り替わりがよくわからなければブラウザのページ更新を何度かやってみてください。ページが更新されるたびにモデルがロードされます。

画像5

実はこのちょっとのタイムラグの間にモデルファイルが例のML5のサーバーからダウンロードされて、ブラウザの中でセットされるということが実行されているのです。そう、あなたの手元に機械学習モデルが運ばれてきたわけです!

画像6

では機械学習モデルの準備が完了したところで今回は終了。次回はいよいよモデルに描いた絵を渡し、それが何の絵であるか推測させます。

乞うご期待!!


この記事が気に入ったらサポートをしてみませんか?