離島プログラマの雑記

島根県の離島、隠岐・西ノ島に移住して子育て中のフリープログラマです。

プログラミング教室のPCを Raspberry Pi に置き換えてマイクラでプログラミングまで

しばらく更新が滞っていましたが、にしのしまデジタルラボ・プログラミング教室は、おとなり海士町での開講に伴い、「隠岐デジタルラボ・プログラミング教室(西ノ島教室、海士教室)」として活動しています。

西ノ島教室では、某所からお下がりでもらった10年前くらいのデスクトップPCを使っていましたが、故障が目立つようになってきたため、リプレースとして最新の Raspberry Pi3 B+ を導入してみました。

Raspberry Pi のOSである Raspbian には、しばらく前から Mincraft Pi (Raspberry Pi 用のマイクラ)がプリインストールされており、さっそく小学生に見つかった(笑)のでみんなで遊んでみることにしました。Mincraft Pi の特徴はスクリプトでプレイヤーを動かしたり、ブロックを配置したりできるところなので、普段使っている Scratch と接続してマイクラプログラミングもやってみます。

f:id:k-aeg:20180620162349j:plain

購入した機材

f:id:k-aeg:20180604114229j:plain

本体セットアップ

OSイメージの準備

www.raspberrypi.org

から「RASPBIAN STRETCH WITH DESKTOP」をダウンロードして dd コマンドで SDに書き込み。 手順はいろんなページに書いてあるので省略します。

記事によってはSDカードのフォーマット操作してますが、ddコマンドで書き込む時にパーティションごと消えるので事前のフォーマット操作は不要です。

あと、こんな落とし穴があるらしいけど jessie 時代の話なので、stretch ではどうなってるか不明ですが、まあ conv=sync オプションもつけて置いたほうが無難そうです。

akkiesoft.hatenablog.jp

電源投入〜デスクトップ表示まで

最近はオートログインで、電源入れただけで一気にデスクトップ表示まで行くんですね。 なにもしなくても pi ユーザーで自動ログインされます。初期パスワードは「raspberry」。

日本語化 + 日本語入力

こちらを参考に設定しました。

deviceplus.jp

Mincraft Pi セットアップ

Scratch2MCPI のインストール

こちらの記事の通り、Scratch と Minecraft Pi の Python I/F をつなぐ Scratch2MCPI をインストールします。

thinkit.co.jp

ローカルネットワーク内のワールド共有

  1. ワールド共有したい Raspberry Pi (最大5台)を同じ LAN 内に接続する
  2. ホストするマシンで Mincraft Pi を起動し、ワールドを作成して動ける状態にしておく
  3. 他のマシンでも Minecraft Pi を起動し、Join Game をクリックして Steve Pi (192.168.xxx.xxx) に接続

4台で接続してワールド共有してみましたが、けっこうサクサク動きます。

Scratch との接続

  1. Minecraft Pi を起動してプレイヤーを動かせる状態で、TAB でカーソル解放
  2. Scratch2MCPI を起動
  3. Scratch でプログラムを書いて実行

特にトラブルなくあっさりうまくいきました。ワールド共有中でもスクリプトは実行可能です。

あそんでみる

さて、小学生3人と一緒に遊んでみました。マイクラができると聞いたとたんテンション爆上がりです(笑) Scratch2 単体の動作は描画が多いと若干カクっとしましたが、Minecraft Pi はかなり軽快に動きます。

イクラ自体ほとんどやったことなかったので、小学生の遊び方を観察したりしてみましたが、マイクラ内で鬼ごっこしたり、石を並べて宝石店を作り出したり、なかなかクリエイティブな遊びかたをするので、これはデジタル版のレゴなんだな〜という感じがします。

Scratch を通してのプログラミングも少し手をつけてみて、プレイヤーを色んな場所にワープさせたり、ブロックを直線に並べてみたりもしましたが、いつも使っている Scratch のインタフェースなので割とスムーズに受け入れてくれました。

ただ、グローバル変数(mcpiX、mcpiY、mcpiZ)に座標をセットしてsetPosなどのコマンド送信、という流れは普通のScratchプログラミングと異なるお作法(アセンブリ言語レジスタに値をセットして命令発行している感じ)なのでちょっと慣れが必要そうです。気軽に並列処理しようとするとメチャクチャになります(笑)

というわけで、しばらくマイクラ+プログラミングで遊んでみようと思います。

プログラミング教室近況

今年2月に開講した「にしのしまデジタルラボ」プログラミング教室は早9ヶ月となり、口コミでメンバーも増え現在は6名が在籍しています。11月初めには地域の文化展にて生徒作品の展示も行うことができました。

f:id:k-aeg:20171128031431j:plain:w400
文化展展示の様子

開講からこれまでは、ミッションカードとオリジナルゲーム制作を中心に授業を進めてきましたが、どうしてもタイピングの遅さがネックになってきたので、今月はタイピング強化月間としてScratchで作ったタイピングゲームでタイムを競い合ったりしています。

競争要素を持ち込むと小学生たちの場外マウンティング合戦(足は俺のほうが速いとか、成績は俺のほうが良いとかw)が始まって少しサツバツとするのがデメリット(?)ですが、かなりモチベーションは高まるようです。競い合った結果、授業時間の90分だけでひらがな入力スピードが3倍くらいになるなど、タイピングのような単純なスキルアップには効果があるようです。

ところで、授業で使っているタイピングゲームのような教材は、生徒がやっていることの延長線上に見えるようになるべく Scratch で作っています。今回のタイピングゲームは1時間程度で完成しましたが、マルチプラットフォーム対応(開発機はMac、生徒PCはLinuxWindows)でこの程度のアプリケーションを同じくらいの学習コスト、制作時間でできる環境って他に案外無いのでは?

f:id:k-aeg:20171128033356p:plain:w400
授業で使っているタイピングゲーム

プロジェクトを公開しているので、以下のリンクからタイピングゲームを遊べます。 scratch.mit.edu

昨今のプログラミング教育において、「教育用言語」と目される Scratch 後をどう他につなげるかという至上命題みたいなものがありますが、Scratch のポテンシャルを十分に引き出すことができれば、(現状では制約が多いものの)かなり有用なツールになり得るという感触があります。JavaScript ベースの Scratch 3.0 がリリースされれば、自由度は高まっていくと思われるので今後どうなるか楽しみです。

ScratchブロックをHTMLで描画する方法

プログラミング教室の教材を作るために Scratch ブロックの画像が欲しかったんですが、いちいちスクリーンショットを撮るのも面倒だし、ラスタ画像ファイルだと解像度の問題で取り回しが不便なので、ベクタ画像出力かつ更新が簡単な方法を探していたらドンピシャのライブラリがありました。

ScratchのWikiやフォーラムでも使われている blob8108 氏作の Block Plugin(scratchblocks)です。このライブラリはブラウザ上で動作するブロック画像ジェネレータとしても公開されていますが、Webページに組み込めば Scratchスクリプトからブロック画像を生成してHTMLにSVGとして埋め込むことができます。

教材の製本も視野に入れると、画像編集ツールを介さずにHTMLで完結できればCSS組版とも相性が良さそうです。

使い方

ライブラリのインクルード

現在の最新バージョンはver3.1なので、以下のJSファイルをインクルードします。

<script src="https://scratchblocks.github.io/js/scratchblocks-v3.1-min.js"></script>

ブロック表記を英語以外(今回は日本語)にするためにはさらに以下の翻訳データをインクルードします。

<script src="https://scratchblocks.github.io/js/translations-v3.1-min.js"></script>
描画

実際に描画してみたサンプルを GitHub Pages で公開しておきました。

https://ag-k.github.io/scratchblocks-html-sample-ja/

サンプルコード全体は以下で参照できます。

https://github.com/ag-k/scratchblocks-html-sample-ja/blob/master/index.html

以下は各描画方法の説明です。

ベーシックな描画方法

HTMLの要素としてScratchスクリプトを記述しておき、scratchblocks.renderMatching() で指定したセレクタに該当する要素をまとめて描画します。 指定するセレクタは自由ですが、preタグだとそのままスクリプトが書けるので便利です。

<pre id="blocks1" class="blocks">
  @greenFlag がクリックされたとき
  x座標を (0) 、y座標を (0) にする
  ずっと
    (10)回繰り返す
      @turnright (10) 度回す
      (5) 歩動かす
    end
    次のコスチュームにする
  end
</pre>
<pre id="blocks2" class="blocks">
  このスプライトがクリックされたとき
  もし <(向き) = [90]> なら
    ペンを下ろす
  でなければ
    ペンを上げる
  end
</pre>
// 'pre.blocks' セレクタで指定された要素をまとめて描画
scratchblocks.renderMatching('pre.blocks', {
  languages: ['ja', 'en'],
  render: function(doc, cb) {
    doc.render(function(svg) {
      var el = document.createElement('div');
      el.appendChild(svg);
      cb(el);
    });
  },
});
インラインで描画

scratchblocks.renderMatching() の第2引数 option に inline: true を指定するとインラインでブロックを描画できます。

scratchblocks.renderMatching() の第2引数 option に inline: true を指定すると、<code class=b>スタンプ</code>のようにインラインでブロックを描画できます。
// インラインで描画
scratchblocks.renderMatching("code.b", {
  languages: ['ja', 'en'],
  inline: true
});
サイズを拡大して描画

今のところブロックが描画サイズは固定になっているようですが、大きくして使いたい場面があったので、描画結果のサイズを変更する方法を考えました。ブロックはSVG形式で描画されるので、Document.render() から取得できるSVG要素を拡大してやれば良さそうなのですが、scratchblocks.renderMatching() に渡した場合、SVG要素のサイズが取得できませんでした(clientWidth, clientHeight, viewBox が0)。

一方、Document.render() を単体で使う場合は SVG要素のサイズが取得できたので、scratchblocks.parse() でスクリプトをパースしたオブジェクトを Document.render() でレンダリングし、結果のSVG要素を指定されたスケールに拡大するようにしました。

<code id="big_blocks">
  @greenFlag がクリックされたとき
  x座標を (0) 、y座標を (0) にする
  ずっと
    (10)回繰り返す
      @turnright (10) 度回す
      (5) 歩動かす
    end
    次のコスチュームにする
  end
</code>
<code id="middle_blocks">
  @greenFlag がクリックされたとき
  x座標を (0) 、y座標を (0) にする
  ずっと
    (10)回繰り返す
      @turnright (10) 度回す
      (5) 歩動かす
    end
    次のコスチュームにする
  end
</code>
<code id="small_blocks">
  @greenFlag がクリックされたとき
  x座標を (0) 、y座標を (0) にする
  ずっと
    (10)回繰り返す
      @turnright (10) 度回す
      (5) 歩動かす
    end
    次のコスチュームにする
  end
</code>
// スケールを変更する場合のブロック描画関数
//   renderMatching()で呼び出される doc.render()ではSVGのサイズが取得できないため、
//   parse() と doc.render() を使用して描画する。
var renderScaledBlocks = function(target, scale) {
  var doc = scratchblocks.parse(target.innerHTML, {
    languages: ['ja', 'en'],
  });
  doc.render(function(svg) {
    target.innerHTML = "";
    target.appendChild(svg);
    //SVGの拡大処理
    svg.setAttribute("width", svg.clientWidth * scale);
    svg.setAttribute("height", svg.clientHeight * scale);
    svg.setAttribute("viewBox", "0 0 " + svg.clientWidth / scale + " " + svg.clientHeight / scale );
  });
};

//各HTML要素に記述したスクリプトを元にブロックを描画
var titleBlocks = document.getElementById('big_blocks');
renderScaledBlocks(titleBlocks, 2.0);
var middleBlocks = document.getElementById('middle_blocks');
renderScaledBlocks(middleBlocks, 1.5);
var smallBlocks = document.getElementById('small_blocks');
renderScaledBlocks(smallBlocks, 1.0);

SVGの拡大方法については以下の記事を参照しました。

ASCII.jp:HTML5のInline SVGをJavaScriptで操作 (2/5)|古籏一浩のJavaScriptラボ

[SVG] viewBoxについての考察 - Qiita

つまづきどころ

  • 画像を含むブロックの入力方法

    これらのブロックはブロック名に画像が含まれているので、文字列で表現する時はエイリアス文字列が設定されています。

    ブロック 日本語スクリプト
    f:id:k-aeg:20170227224919p:plain @greenflag がクリックされたとき
    f:id:k-aeg:20170227225645p:plain @turnright (15) 度回す
    f:id:k-aeg:20170227225720p:plain @turnleft (15) 度回す
  • 日本語に翻訳されていないブロックがある

    「() 回繰り返す」などのループは閉じるコマンド(英語版では「end」)が必要なんですが、日本語に翻訳されていないので、languages に"ja"と"en"の両方を指定した上で「end」と記述する必要があります。

おすすめ作業フロー

HTMLでスクリプト手書きは結構面倒なので、Scratch プロジェクトのブロックからscratchblockのスクリプトを生成するジェネレータを活用するとラクです。以下の手順で作業するのが良さそうです。

  1. Scratchでプロジェクトを作成
  2. ブロックを組んで動作確認
  3. generator :: scratchblocks でScratchプロジェクトをscratchblockスクリプトに変換
  4. scratchblockスクリプトをHTMLに貼り付け

サックスのメンテナンス用リークライトを自作してみる

離島という環境ゆえ、近くに楽器屋さんがありません。 楽器のメンテナンスのたびにフェリーで3時間かけて本土まで行くのも大変なので、簡単なメンテナンスは自分でできるようにしようと思いたちました。

調べた限り、分解&組み立てレベルのサックスメンテナンスに関する日本語の文献はこの本がベスト(というかこれしかない)のようです。

サクソフォン マニュアル 日本語版

サクソフォン マニュアル 日本語版

さっそく買って読んでみましたが、日常のメンテナンスからタンポの交換まで、全ページカラー写真でとても丁寧に書かれていて良書でした。さすがに自力でタンポ交換は無理そうでしたが…。 本書では息漏れチェックの手段として2つ紹介されており、1つは薄い紙で作った隙間ゲージをタンポに挟んで引っ張るというものと、もう1つはリークライトをボアに挿入して光が漏れる場所をチェックするというものです。

後者のリークライトは、LEAK LIGHTSのようなところで買えるのですが、大体$100以上とお高めなので、LEDテープで自作することにしました。作り方は、奥津サックスマウスピース製作さんのブログで紹介されている通りです。

okutsumouthpieces.com

用意するもの

作り方

まずはLEDテープを切り出します。

f:id:k-aeg:20170225150112j:plain

出来上がりの長さは市販品と同じ21インチ(約53cm)にします。半分で折り返してくっつけるので、倍の長さを切り出します。今回使用したLEDテープは5cm間隔で切断可能になっているので、105cmとしました。

f:id:k-aeg:20170225150102j:plain

切断可能な部分は丸い端子が4つ並んでいるところの真ん中の線です。 切断したら、裏面の両面テープを剥がして真ん中で折って貼り合わせます。

f:id:k-aeg:20170225150533j:plain

今回はクリアタイプの熱収縮チューブがなかったので、根本だけ短いチューブで固定することにしました。チューブをLEDテープの根本にかぶせてライターやヒートガン、はんだごてなどで熱を加えて収縮させます。

f:id:k-aeg:20170225151147j:plain

最後に、DCコネクター変換プラグにドライバーで赤線と黒線を接続します。LEDは極性があるので注意が必要です。赤線は+、黒線は−につながないとLEDが壊れます(たぶん)。

f:id:k-aeg:20170225153407j:plain

これで完成です。ACアダプタを接続していざ点灯! ちゃんと尽きました。カメラのホワイトバランスで暗めに写ってますが、肉眼で見ると結構明るいです。

f:id:k-aeg:20170225153528j:plain

サックスに入れてみるとこんな感じになります。

f:id:k-aeg:20170225153815j:plain

総工費としては2000円以下で自作できました。めでたしめでたし。

子供向けプログラミング教室の開講とインターンシップを受け入れた話

今週は、西ノ島デジタルラボと称して子供向けのプログラミング教室を開講したり、近くの高校からインターン生を受け入れるなど、プログラミング教育について色々と知見を得られたので記録しておこうと思います。

プログラミング教室

昨年末から準備を進めていた子供向けプログラミング教室ですが、1月末に申込者があったため2月より開講の運びとなりました。一応「西ノ島デジタルラボ」という名前をつけているのは、今後プログラミング講座以外に、ファブ系(CAD、3Dプリンタ等デジタル工作機)の講座なども展開したいという事と、今は固定の活動場所は無いけれど、将来的にはPCやデジタル工作機などを常設して活動できるような拠点があると良いなーという想いからです。

インフラとしては町内の船越地区の公会堂をお借りして、お古のデスクトップパソコン数台に軽量 Linux を入れて、Scratch のオフラインエディタをインストールして実施しました。ネット環境が無いのがネックですが、データ保存用のUSBメモリを配布したりして、当面はオフラインで進められそうです。第1回の授業はインターン期間と重なったので、会場設営などインターン生に少しお手伝いしてもらいました。

低学年向けの配慮について

そんなわけで、第1回の授業は小学2年生と3年生の2名でのスタートでした。内容としては、ビジュアル言語のScratchを使ってゲームを作ろう、というスタンダードなものです。元々は小学4年生以上という条件で始めようと考えていましたが、低学年の子のほうがプログラミング(というよりゲーム制作?)に興味があるようで、希望者や興味がある層は軒並み低学年の子でした。当初、小学4年生という区切りにしていたのは、主に以下のような理由によります。

  1. 抽象的思考ができるようになる年齢(と言われているらしい)
  2. 低学年の子にとってはマウスやキーボードの操作自体が難しい(以前に実施したプログラミング体験講座での観察から)
  3. 低学年に読めない漢字が多い(教材に配慮が必要)

逆に上記をなんとかできれば、低学年向けにも実施できるだろうということで、せっかく希望者がいるのだしと、挑戦してみることにしました。

実際取り組んでみた結果、

  • 1については、第1回実施時点では内容もそこまで踏み込んでおらず、N数も2なので何とも言えませんが、想定よりもずっと積極的に探究心をもって取り組んでくれているので、経験を積んで土台を固めていくことで壁を乗り越えられるかも、という感触です。

  • 2については、マウスをクリックした時にカーソルがずれてしまったり、アルファベットが読めないのでローマ字が入力できないといった問題になりますが、対策としては子供の手に合うように小さめマウスを用意したり、マウス操作練習のゲームをScratchで作ったり、ローマ字入力表を配布したりしました。ただ、マウス操作は若干ぷるぷるしているものの、操作自体には支障がなかったのでマウス操作練習ゲームの出番はなかったり、アルファベットが読めなくてもローマ字入力表とにらめっこして、象形文字を読むかの如くに該当する文字を見つけ出してタイプしたりと、思ったより適応力が高く杞憂だった部分も多かったです。

  • 3については、プリント教材にはすべてルビを振るようにしました。画面上ではルビは表示されませんが、読めない漢字があっても絵として覚えられるようなので、特に操作のストレスになっている感じは見受けられませんでした。Scratch はすべての表示をひらがなにするモードがあるんですが、全部ひらがなだと逆に読みづらいし、前述のとおり漢字モードでも支障はなさそうなので、そのまま使ってもらっています。

という感じで、このまま継続していけそうな気がしています。

授業の進め方について

まず前提として、このプログラミング教室では何を目指すのかということですが、若年層向けのプログラミング教育の方向性としては大きく分けて以下の2つの方向性があると考えています。

  1. 教養としてのプログラミング
    • プログラミングができるようになることよりも、プログラミングというプロセスを通して論理的思考や創造性、問題解決能力といったものを身につけることを目的とする
  2. 実用としてのプログラミング
    • 職業や趣味として実用的なソフトウェアを制作できる能力を身につけることを目的とする

この教室では基本的にプログラミング自体に興味があることを前提として、2に重きを置いた方向性を目指しています。教養という意味では、今後小学校でも必修化されるプログラミングの授業で扱われるべきかなと思います。ただ、プログラムを書くことそのものは表現の一手段でしかないので、結局はどちらの方向性をとるにしても(プログラムによって動作を指示される対象となる)コンピュータというものの性質や振舞いを理解した上で、

  • どんなことができるのか
  • 何をしたいのか
  • どのようにやるのか

といったことを考えるのが本質なのかなとも思います。プログラミング言語というだけあって、あくまでコンピュータと対話するためのコミュニケーション手段でしかないので、例えば英語だけ勉強しても(言語自体への興味は別として)、肝心の伝えたい情報や欲しい情報がなければ意味がないのと同じです。 というわけで、授業の進め方としては以下の3つのフェーズを繰り返しながら発展させていくイメージです。

  1. 探求フェーズ
    • 自由にプログラムを組みながら、色々な機能を試したり、必要な概念を身につける
  2. 構想フェーズ
    • 紙のワークシートなどを使いながら、どんなものを作るかじっくり考える
  3. 実践フェーズ
    • 考えたものをプログラムとして形にする

初回授業の雑感

初回は探求フェーズということで、自由にプログラムを組んでいきますが、何も無い状態では右も左もわからない状態なので、適当なタイミングでちょっとした課題を出したり、同じ課題を別のやり方で実現してみたり、ということ繰り返しました。探求フェーズでは好奇心を重視して、課題からちょっと逸れたりしてもそのまま続けてもらい、その方向で発展できることがあれば新たに課題を設定することで、枝葉のように多方向に知識や経験を広げていきます。

一方、課題をこなすこと以上に大切なのは、遊ぶ時間をじっくり取ることでした。例えば、移動距離を指定する場所にありえないような大きい数値をいれたらどうなるか?とか、数値にマイナスを2つつけたらどうなるか?など直接課題に関係ないことでも、コンピュータの性質や振舞いを知るのには重要なことです。ただ、同じことを何度も繰り返して無限ループに入ってしまう場合があるので、そういう時には新しい機能や他のやり方のヒントを投下して興味を引きつけるとすんなり抜け出してくれました。

生徒同士の相互作用もなかなか有効に働きました。各々の好奇心ベースで進んでいくので、進んでいく方向も異なりますが、隣の人が自分の知らないことをやっていると真似してみたり、自分が経験したことで隣の人がつまづいていたら教えてあげたり、わからないところを一緒に考えたりというアクションが見られました。 情報の非対称性があることで、それを共有するモチベーションが生まれているようです。何より友達同士で教え合うほうが、先生が直接教えるよりも真剣に受け取っている感じがします(笑)。

インターンシップ受け入れ

話は変わって、隠岐島前地域唯一の高校である隠岐島前高校では、キャリア教育の一環として職業体験を実施しているそうです。今回は一週間のインターンシップ受け入れでした。自分はフリーランスプログラマなので、従業員採用のモチベーションも無ければ、技術職ゆえ手伝ってもらえるような仕事もほとんど無いのですが、隠岐島前地域にはエンジニア志望のインターン先が無いということなので、うちで引き取ってみることにしました。普通は技術職のフリーランスインターンする機会はあまり無いと思うので、ある意味離島ならではという気もします(笑)。

というわけで、せっかくなら色々体験してもらって興味の幅を広げつつ、こちらとしてはプログラミング教育の導入部に関するデータを収集させてもらおうと考えてスケジュールを組みました。

1日目: 業界や仕事内容についてのレクチャー、Scratch 入門 + プログラミング教室手伝い
2日目: Web開発入門(HTML + JavaScript)
3日目: Web開発入門(続き)、3Dプリンタによるお土産製作
4日目: Arduino による電子工作入門
5日目: Unity による3Dゲーム製作入門

本当はメインでやっているスマホアプリ開発も入れたかったのですが、インターン生のデバイスWindows + iPhone だったので、開発環境が無く断念しました。自分で書いたプログラムが手元のデバイスで動くのは結構感動するので、インターン向きの内容ではあるんですが条件がなかなか揃いません。

色々とメニューは用意しましたが、付きっきりになるのは仕事に支障が出るので、教材の評価も兼ねて基本的にはWebページや動画、本などの入門教材で自習してもらうことにしました。

1日目

業界や仕事内容について色々話しましたが、あまり興味はなさそうでした(笑)。まずソフトウェア開発というのがどういうことなのか分からない状態だったので、プログラミングを少しでも体験した後のほうが想像しやすかったかもしれません。 その後はプログラミング教室の手伝いをしてもらうために、スクラッチ2.0アイデアブックという本で予習をしてもらいました。

この本はなかなか良書だったようで、特につまづくところも無くスラスラと読みこなしていました。プログラミング教室の間は Scratch で自由にプログラム書いてもらっていましたが、ちゃんと応用してそれっぽい何か動くものを作っていました。

2日目

2日目はWeb開発入門ということで、ビジュアル言語を卒業して、プログラミング学習サイト ドットインストールの HTML 入門と JavaScript 入門の動画を見ながら自習してもらいました。結論から言うと動画ではほとんど理解に結びつかず、後で動画で説明されていた内容について質問してみてもまったく要領を得ませんでした。

動画教材は「とりあえず何か動くものを自分の手で作る」という体験に主眼が置かれていますが、初学者にとっては言語の基本的な文法などを理解していない状態では、何やっているのか分からずにとりあえず指示に従っているだけで、頭には入りにくいようです。他の言語を1つでも学習していれば、言語の差分で見られるのでスラスラ入ってくると思います。

また、Web上の JavaScript 入門は玉石混交で情報が古かったりということが多々あるため、初学者が自分で最適なページを見つけるのはかなり困難だなと感じました。あと、そもそもの話ですが、最近のデジタルネイティブの人はスマホを使えるけど、PCを使えないという噂を聞いていましたが、せいぜい学校の授業で Word、Excel に触るくらいしか経験がなく、ブラウザとYahoo(のページ)の区別がついてなかったので、噂は本当だということが分かりました(笑)。

まあ結論としては、ブラウザの説明から載っている、その時の最新の JavaScript 入門本を一冊読むというのが初学者にとっては良い選択肢かなと思いました。 ただ、Web開発は HTML/CSS など前提となる知識が色々必要でプログラミング始めるまでの道のりが長いので、最初は Processing などセットアップが容易な言語から始めたほうが良かったかもしれません。

3日目

3日目は前日のWeb開発入門のリカバーで直接講義してみました。ホワイトボードを使いながら変数やら文法やらの説明をして、なんとか FizzBuzz 問題を(半分くらい)自力で解いてもらうところまでは行きました。初学者あるあるですが、エラーメッセージの英語を全然読もうとしない(というか読めない)ので、Webで辞書を引いてちゃんと読むように指導しました。

JavaScript でだいぶ頭が疲れたようなので、午後は3Dプリンタで印刷しておいた活イカ活っちゃんストラップの仕上げ作業を体験してもらいました。ルーターでのバリ取り作業などはわりと無心でできるので、午前の作業とのバランスはとれたと思います(笑)。インターン生が自分で完成させたストラップはお持ち帰りいただきました。

4日目

4日目は趣向を変えて電子工作に取り組みました。この日も懲りずに ドットインストールArduino入門を活用してみました。 こちらはJavaScriptと違ってわりとスムーズにこなしているように見えましたが、ブレッドボード上の配線がどうなっているのかとか、コードの各行が意味するところの理解にはつながらなかったようです。結局かなりアフターフォローを入れつつ、光センサと圧電スピーカーを組合せてテルミンもどきみたいなデバイスができあがりました。

f:id:k-aeg:20170209172119j:plain

本当はこれをユニバーサル基板に移植して、CADでエンクロージャ(箱)を設計して、3Dプリンタでプリントしてミュージックデバイスとして完成させるところまでやれたら良かったんですが、そこまでは今回時間がありませんでした。

でもせっかくなので、後で完成させるつもりです。すでにCADでの設計を終えて箱をプリント済みなので、あとは回路をユニバーサル基板に移植して詰めるだけです(笑)。

5日目

最終日は Unity を使って3Dゲームを作りました。Unity がPCにインストールできないというハプニングがあり、午前中を消費してしまいましたが、こちらは公式のチュートリアルが優秀で、あまり手をかけずに自習できました。

tutorial.unity3d.jp

インターン生がFPS(一人称視点のシューティングゲーム)好きなのもあって、Unity なら比較的簡単に FPS が作れそうという体感を得ると、これまでの開発に比べ俄然やる気が見られました。チュートリアルの途中で時間切れになってしまいましたが、まだ続けたそうだったので、プログラミング教室の小学生もそうでしたが、やはり好奇心駆動開発は強いなと思いました(笑)。

まとめ

一口にプログラミング教育と言っても、プログラミングという行為自体の目的が多様化しているのもあり、どこを目指すのかという方向は教育者側では決められないので、各自の興味をきっかけとしてある程度のレベルまでサポートして、自分で学習できるところまでつないであげるのが教育者としての役目かな、と思いました。

一方で、諸外国ではCS(Computer science: 計算機科学)教育に力点を置いて、プログラミングに限らずコンピュータへの理解を深めようという動きが主流になっているのに対して、日本ではプログラミング教育という行為のみが切り出されてクローズアップされている感があり、コンピュータの本質的な理解に結びつかないのではないかという懸念もあります。コンピュータの可能性を最大限に引き出すには、やはりコンピュータ自体への理解が不可欠です。というわけで、プログラミング教室を名乗ってはいますが、プログラミングをきっかけとしてコンピュータに対する理解を深めるという目的も重視していこうと思います。

と、いきなり話が大きくなったりしてまとまりませんでした(笑)。

ディープラーニングことはじめ

最近はやりの人工知能で注目されているディープラーニングですが、どんなものか良く知らなかったので本を一冊読んでみました。

TensorFlowなどのフレームワークをいきなり触るのはなんだか難しそうだなー、と思っていたところに「ゼロから作る」というコンセプトの本を見つけたので手に取りました。結論から言うとわかりやすくて良い本だったので、入門にはおすすめです。

読んでみて理解したことを備忘録として羅列しておきます。

必要な前提知識

数学

数学の知識としては行列と微分が分かればOKという感じです。行列や微分の定義についてもちゃんと説明されているので、なんとなく分かってる程度でも読み進めることはできます。そこそこ数式も出てきますが、Python のコードを動かしながら進んでいくのでそんなに躓くことはありませんでした。

プログラミング言語(Python)

Python はほとんど使ったことないですが、演算や関数の定義などから説明があるので、他の言語をかじっていれば問題ないレベルです。 多次元配列や行列の計算には NumPy という数値計算ライブラリを使うので、ややこしい演算などはライブラリ側でやってくれます。

理解できたこと

自分が理解した内容の覚書なので、間違っているところもあるかもしれません。 本ではもう少しアルゴリズムの実装寄りの話が詳細に説明されており、実際にコードを動かして手元で確認しながら進みます。

パーセプトロン

ニューラルネットワークのもととなるアルゴリズム。 以下の特徴がある。

  • 複数の信号を入力として受け取り1つの信号を出力する
  • 信号の総和がある閾値を超えると発火(=1を出力)
  • 入力信号に重みバイアスというパラメータを設定
    重み
    各入力信号の重要性をコントロールするパラメータで。各入力信号にそれぞれの重みを乗算する。
    バイアス
    ニューロンの発火しやすさをコントロールするパラメータ。重みを乗算した入力信号の総和にバイアスを加算する。
  • 重みとバイアスを調整することで AND、NAND、ORのような単純な論理回路を表現できる

単層のパーセプトロンでは非線形な表現(XORゲートなど)ができない。
パーセプトロンを重ねることで非線形表現ができる

ニューラルネットワーク = 多層パーセプトロン

パーセプトロンの出力を次のパーセプトロンの入力信号とすることで、多層化することができる(多層パーセプトロン)。 多層化により、XORゲートなどの非線形表現が可能になる。 ニューラルネットワークは多層パーセプトロンとほぼ同じで、以下の特徴を持つ。

  • 入力層、中間層(隠れ層)、出力層に分類される層からなるニューロンのネットワーク
  • 各層には複数のニューロンが存在し、入力層〜中間層(1層以上)〜出力層の順に信号を伝達する(順方向伝播)
  • ある層の各ニューロンが出力する信号は、次の層の各ニューロンの入力となる
    • 例えば、ある層に存在する2つのニューロンの各出力(x1, x2)と重み(w)の和にバイアス(b)を足した値が、次層の3つのニューロン(y1, y2, y3)にそれぞれ伝播する
    • ニューロンから次層のニューロンへの各経路には、それぞれ異なる重みを設定する
    • 重み付き入力信号とバイアスの総和には活性化関数(h)を適用する
    • x1 → y1、x1 → y2 などの経路ごとに重みが違うため、y1, y2, y3 のニューロンへの入力はそれぞれ異なった値となる
      • y1 = h(x1 * (x1 → y1の重み) + x2 * (x2 → y1の重み) + b)
      • y2 = h(x1 * (x1 → y2の重み) + x2 * (x2 → y2の重み) + b)
      • y3 = h(x1 * (x1 → y3の重み) + x2 * (x2 → y3の重み) + b)
  • 活性化関数 入力信号の総和を出力信号に変換する関数 = 活性化関数 → 閾値を境にして出力が切り替わる性質を持ち、非線形関数である必要がある

出力層の設計

機械学習は分類問題と回帰問題に大別されるが、ニューラルネットワークはどちらにも使える。 出力層の活性化関数は問題に合わせて使い分ける必要がある。

  • 出力層の活性化関数
    • 恒等関数 → 回帰問題
    • シグモイド関数 → 2クラス分類問題
    • ソフトマックス関数 → 多クラス分類問題
      • 出力の総和が1になる = 確率として解釈可能
      • 出力層のニューロン数 = 分類したいクラスの数

ニューラルネットワークの推論(順方向伝播)

MNIST データセットを例に推論処理を実装する。

  • MNIST データセット
    • 0ら9までの手書きの数字画像
    • 訓練画像60000枚、テスト画像10000枚を含む
    • 画像データは 28 x 28 のグレー画像(256階調)
    • 各画像には対応するラベルが与えられている

ニューラルネットワークの設計は以下のようにする。

  • 前処理
    • ピクセルの値を 255 で除算(0.0〜1.0の範囲に正規化)
  • 入力層
  • 中間層(隠れ層)
    • 層の数やニューロン数は任意
      • 2つの隠れ層で、1層目が50個、2層目が100個、など
  • 出力層
    • ニューロン数 = 分類するクラス数
      • 10クラス(数字の0から9)に分類 = 10個
  • バッチ処理
    • NumPyなどの数値計算ライブラリは配列の計算を効率良く処理できるように最適化されている
      • 入力データをまとめて処理(バッチ処理)すると効率が良い
      • 入力データから100枚ずつ取り出してNumPy配列として処理する(NumPy配列の演算は配列のすべての値に適用される)

ニューラルネットワークの学習

特徴量 + 機械学習のアプローチでは問題に応じた(人力での)特徴量の設定が必要だが、ニューラルネットワークでは特徴量も機械が学習する。 ニューラルネットワークでは損失関数の値が小さくなるように最適なパラメータ(重みとバイアス)を探索する。

ニューラルネットワークでは、パラメータ解空間の探索方法として勾配法(確率的勾配降下法 = SGD)がよく用いられる。

  • 勾配法
    1. 偏微分により現在のパラメータにおける損失関数の勾配を求めて、最小値の方向を予測する
    2. 勾配から予測した最小値の方向へパラメータを更新する(移動する量 = 学習率)
    3. 1と2を繰り返して最小値へ向かって降下しながら、最小値を探索する

ただし、勾配が指す方向に必ず最小値があるとは限らない(極小値の可能性が高い)。 また、数値微分による勾配の計算は非常に時間がかかる。
誤差逆伝播(バックプロパゲーション)による勾配算出の高速化

誤差逆伝播法については、簡潔に説明するのが難しいので省略しますが、数値微分より大幅に少ない計算で勾配を算出できます。
本では一章丸々使って、計算グラフという表現方法で説明されています。

学習のテクニック
  • パラメータの更新方法
    パラメータの更新方法は学習の効率に大きく影響する。
    • SGD
      • シンプルだが関数の形状によっては探索が非効率
    • Momentum
      • 物理法則に従ってパラメータの移動場所を決める(お椀にボールを転がすイメージ)
    • AdaGrad
      • 学習率を徐々に減衰させる
    • Adam
      • Momentum + AdaGrad
  • 重みパラメータの初期値
    重みパラメータの初期値はモデルの表現力や学習の効率に大きく影響する。
    • Xavier の初期値
    • He の初期値
      • 活性化関数が ReLU の場合に特化した初期値
  • 過学習対策(正則化)
    • Weight decay(荷重減衰)
      • 大きな重みに対してペナルティを課す
    • Dropout
      • 訓練時に隠れ層のニューロンをランダムに消去しながら学習する
      • 実質的に複数のモデルに個別に学習させた平均をとることと同義なので、アンサンブル学習に類似
  • Batch Normalization
    • 2015年に提案された新しい手法
      • 学習の効率が良い
      • 初期値に依存しにくい
      • 過学習の抑制
    • 重みのパラメータの分布を強制的に分散させる
      • 活性化関数の前か後にデータ分布の正規化処理を行う
  • ハイパーパラメータの検証と最適化
    • 自動で学習できない(手動で設定する必要がある)パラメータ = ハイパーパラメータ
      • 各層のニューロン
      • バッチサイズ
      • パラメータ更新の学習率
      • Weight decay 係数
      • その他手法に応じて設定が必要なもの
    • 検証方法
      • ハイパーパラメータがテストデータに対して過学習を起こさないように、ハイパーパラメータ調整用の検証データを用意して検証
        • 訓練データから一部分離するなどして検証データを用意しておく
    • 最適化方法
      • ハイパーパラメータはモデルの認識精度で評価する
      • 試行を繰り返しながら良い値の範囲を絞り込んでいく
畳み込みニューラルネットワーク(CNN)

前述のニューラルネットワークでは全結合層を用いていたため、データの形状は無視されていた。 CNN ではデータの形状を維持する畳み込み層とプーリング層が追加される。 多段の畳み込み層では、前層の情報を元に段階的に高度な情報を認識することができるため、画像認識等の精度が向上する。

  • 畳み込み層

    • 入力データに対してフィルターを適用する
      • 入力データとフィルターの要素を乗算して和を求める(積和演算)
      • 3次元データ(奥行き = チャンネル方向が存在する)の場合、チャンネル毎に畳み込み演算した後、結果を合算して1つの出力を得る(チャンネルは1つになる)
    • パディング
      • 入力データの周囲に固定データを埋め込むことで、出力サイズを調整する
      • パディングを大きくすると出力サイズは大きくなる
    • ストライド
      • フィルターを適用する位置の間隔
      • ストライドを大きくすると出力サイズは小さくなる
  • プーリング層

    • 学習するパラメータがない
    • チャンネル数が変化しない

ディープラーニング(= 多層構造のニューラルネットワーク)

層を深くした多層構造のニューラルネットワークディープラーニングと呼ばれている。

  • 層を深くする意味
    • 理論的にはあまり分かっていないが、実践的には意味のある結果が出ている
      • (コンペティションの結果から)層が深まるほど認識精度が向上している
      • 層を深くすることで、パラメータ数を少なくできる
      • 層を深くすることで、学習データを少なくできる(=学習が高速化する)  
  • ディープラーニングの実装

  • 高速化

  • 実用例

    • 物体検出
      • R-CNN
    • セグメンテーション
      • FCN (Fully Convolutional Network)
    • 画像キャプション生成
      • NIC (Neural Image Caption) = Deep CNN + RNN (Recurrent Neural Network)
    • 画像スタイル変換
    • 画像生成
      • DCGAN (Deep Convolutional Generative Adversarial Network)
    • 自動運転
      • SegNet
    • Deep Q-Network (強化学習)

五線譜ノートアプリ PhraseNote ver1.2 リリース

iPhone/iPad向けアプリ PhraseNote を久々にアップデートしました。

PhraseNote - 五線譜ノート

PhraseNote - 五線譜ノート

  • Eiji Koyama
  • ミュージック
  • ¥480

ちゃんとブログに書いたことがありませんでしたが、PhraseNote はフレーズのメモやリードシート(メロディ+コード譜)の作成に特化した音楽ノートアプリです。ピアノ鍵盤でささっと音符が入力できたり、コードから伴奏を自動生成できたりするのが売りです。

f:id:k-aeg:20161203044443j:plain

ピアノ鍵盤に慣れている方なら、手書きタイプの記譜アプリよりスピーディーに入力できます。フルスコアなどきっちりとした譜面を作るのには向いていませんが、コードを入力すれば伴奏を自動生成するので、ジャズやポップス曲の作曲には役立つかと思います。 また、シラブルの表示機能(移動ドのドレミを表示)など、楽器の練習やソルフェージュ向きの機能もあります。

詳細はApp Storeの説明をご参照ください。

バージョン 1.2 の新機能

今回はリードシートの作成に必要な機能を中心にアップデートを図りました。

  • iPhone6/6 plus/7/7 plus 対応
    • スコアの解像度が上がって前よりきれいに表示されます
    • 小節幅も固定だったのを自動調節するようにしました
    • 小節数が増えると動作が重くなる問題を解消しました
  • 歌詞入力
    • それぞれの音符の位置に歌詞をつけられます
    • 最大で5番まで入力できます
  • 小節単位のコピー/カット/ペースト
    • テキストのメモ帳のような感じでコピペできるようになりました
    • 音符単位でもコピペできるようにしたいですが、今のところ未対応です
  • PDFエクスポート
    • 画像エクスポートも合わせてプレビュー表示がつきました
  • ヘ音記号
  • ダイアトニックコードの簡単入力パレット
    • 入力頻度の高いメジャー/マイナーのダイアトニックコードをボタンで簡単に入力できるようにしました
    • トライアドまたは7thコードを選択できます f:id:k-aeg:20161203044930j:plain
  • コードの入力履歴
    • 一度入力したコードは履歴ボタンに登録されて再度の入力が簡単になります
  • 繰り返し記号およびリハーサルマーク
    • 1カッコ、2カッコなどの繰り返し記号やリハーサルマークを追加しました
  • 付点音符入力の改善
    • 付点音符が選択中の音符の半分の長さの位置からも置けるようになりました
    • 小節からはみ出す場合は音符を自動分割して配置できるようになりました
余談

もともとはジャズのアドリブ練習用にフレーズをストックするために作り始めたアプリなので、それっぽい機能が備わっています。ご活用ください。

  • コードのルート音からのインターバル表示
    • インターバルがぱっと分かるのでフレーズのアナライズがしやすくなります
  • キー相対のシラブル表示
    • 移動ドでフレーズを覚えたりするのに便利です
  • 移調機能
  • 管楽器のための移調機能
    • Bb管、Eb管などの管楽器向けに曲のキーは変えずに表示上だけ移調できます