未踏IoT開発合宿 #1に参加しました

未踏社団が昨年開催した未踏開発合宿#0が好評だったので、IoT研究会の上田真史さんにご尽力頂いて、IoTにテーマを絞った合宿を行いました。

今回、僕は上田さんの講義を聞きつつ、センサと液晶をI2Cバスにつないで、センサから読んだデータを液晶に書くというのをやりました。おかげで今までよくわかっていなかったI2Cについてかなり理解が深まりました。そこで半年後の自分が復習しやすいようにスライドにまとめておきました。

本合宿には、未踏社団の法人会員でもあるさくらインターネット様から「さくらのIoT」のα版を無償提供いたきました。また個人会員である青木俊介さんのご協力でkonashiの提供を頂きました。この合宿については未踏研究会#3でも報告される予定です。

未踏社団に開発合宿のノウハウが蓄積されて、こういう開発合宿をどんどん開催できるようになると、未踏社団の目的でもある「創造的人材を多角的に支援し、業界横断的なネットワークをつくることで、ITを中心としたイノベーションを加速すること」にもつながっていくかと思います。次回は9月ごろ開催予定です。

レジ「972円です」客、支払う。レジ「104円のお返しです!」

ビジネス街のレストランで972円の昼ごはんを食べている僕。聞くとはなしにレジのやり取りが聞こえていくる。


レジ「972円です」
レジ「104円のお返しです!」


……えっ、何が起きたんだ?

出題編

しばらく考えて、客もレジも間違ったコインを渡したり、渡さなくて良い余計なコインを渡したりしていなくても成立しうるストーリーを思いついた。これを考えるのは結構面白かったので、ブログ記事にすることにした。(間違いを許容すると別解がある)

ヒント編

僕の思考の過程を追いながら一歩ずつ回答に近づいていこう。




僕「100円がお釣りとして返ってくるということは、客は100円玉は出していないということだろう」



僕「仮に客が1000円を出していたら、お釣りは28円だ」



僕「客が104円のお釣りを受け取るには、1076円払う必要がある。76円払うには1円玉を出す必要があり、お釣りに1円玉が返ってきているからこれはおかしい」



僕「仮に客が1500円出していたとしたら、528円返ってくる。これもおかしい」



僕「レジが972円だと言ったが、実際に支払われたのは972円ではないのでは?」



僕「このシチュエーションでそんなことが起こるには…」



僕「今僕が食べているランチも972円」



僕「回りを見渡すと、僕みたいに一人で食べている人も、複数人で食べている人もいるな」



僕「複数人で972円のランチを食べてレジに向かえば、レジが『一人あたり』972円と言って、客が複数人分まとめて異なった額の支払をするケースはありえる」



僕「2人分払って2000円出すとお釣りは56円、3人分だと84円、4人分だと112円」



僕「実際のお釣りは104円だった」



僕「4人だとオーバーするし、2人だと48円足りない」



僕「3人だと20円足りない」



解答編

僕「つまり、こうだ」


客、3人でレジに向かう。
レジ「(一人あたり)972円です」
客、3020円払う。
レジ、それを見て3人分だと理解する。
レジ「104円のお釣りです」


客の暗算能力が低くても、レジには計算機があるから問題無いだろう。


レジ「(一人あたり)972円です」
客、3000円取り出す。
レジ、それを見て3人分だと理解して計算機に3人分と入力する。
計算機に、2916円と表示される。
客、それを見て、財布にあった10円玉を2枚追加する。
レジ、受取額として3020円と入力する。
計算機に104円と表示される。
レジ「104円のお釣りです」

別解

コインの間違いを許容する場合「客がお釣りを100円にしたくて1072円支払おうとしたのだけど、1円玉と間違えて5円玉を出してしまい、1076円支払ったことになり、お釣りが104円になった」という別解がある。「4円」が「1円と5円の差」だという解釈だ。

TensorFlow Playgroundはニューラルネットを理解するのにおススメ

ネットワークの重みや各ニューロンがどういう入力の時に発火するのかが、学習していく過程で各時刻可視化されてとても良い教材です。 http://playground.tensorflow.org/

うずまきのデータセットに関して「中間層が1層しかないとうずまき(線形非分離な問題)は解けない」という誤解があるようなので、まずは1層でできるという絵を紹介。なお僕のタイムライン上では id:a2c が僕より先に気付いていたことを名誉のために言及しておきます。

で、じゃあよく言われる「線形非分離な問題が解けない」ってのはどういうことか。それはこんな問題設定。入力に適当な係数を掛けて足し合わせただけでは適切な境界を作ることができません。

こういうケースでは中間層を追加すると、中間層が入力の非線形な組み合わせを担当してくれるおかげで解けなかった問題が解けるようになります。


1つ目のデータセットでは特徴量の選択の重要さがわかります。このデータセットではx^2とy^2を入力にすると問題が線形分離になるのであっさり解けます。「x^2 + y^2 < R」ってのが「半径Rの内側」に対応するのです。

だけども、xとyだけでは線形には分離できません。

そこで中間層を追加してみると、それぞれの中間層が少しずつ分担して問題を解くのを観察できます。中間層のニューロンの個数を増やしたり減らしたりしてみても面白いでしょう。1個、2個、3個の各パターンを観察するのがおすすめ。




と、こんな感じできれいに可視化された環境でいじって試すことができるので、とても良い教材だと思います。

Amazonの購入履歴を確定申告に使ったログ(2016年)

来年度の確定申告をもっと楽にするために、2016年3月に経験したことと、どういう設計だったらハッピーか考えたことをメモしておく。余裕があれば実装したいけど、たぶん余裕ないだろうなぁ。

freee

まずfreeeにAmazonからの読み込み機能があるから、これを使って確定申告も全部freeeでやったら楽ちん、と思った。Amazon - 購入履歴を取り込む – ヘルプセンター

アカウントを作って試してみたのだけど、運悪く「一時的なエラーのためAmazonの同期に失敗しました」になっちゃった。1月ぐらいに余裕をもって確定申告の準備してたら、しばらく待って試すというのも手だったのかもしれないけど、今日は締め切り前最後の週末なのでそんな悠長なことを言ってられず断念。

これがすんなり動いたらベストだと思うので来年1月に再度試してみる。やっぱ、価値のあるサービスに対してはきちんと対価を支払って、それを原資としてエンジニアにきちんと給料を支払ってメンテナンスするってのが、サービスの持続性とエンジニアの幸福のために大事だと思うので。

しかし一方で、Amazonにログインしようとしていた過程で「1分以内に画像認証に答えろ」とか「郵便番号は何か答えろ」とか色々大変そうな気配のするやりとりがあったので、Amazonはログインに対して割と制約が厳しいんだろうなぁと思う。freeeさんのアプローチはいばらの道っぽい。

TSV出力ブックマークレット

次はこれを試した: Amazonで一年間に使った金額と、注文履歴のTSVを出力するブックマークレット【2015年版】 - Qiita

こちらは、ユーザが手元でログインしたAmazonの画面に対してJSを突っ込んで動作させるので「Amazonへの認証」といういばらの道を回避できる。一方でDOM構造はやはりいばらの道。

最初このスクリプトChromeの開発者ツールのコンソールで動かして、$("

")が正しいセレクタでないというエラーになってしまったが、ブックマークレットとして動かせばちゃんと動いた。ただし、ポップアップがブロックされてもう一度実行する羽目に。ポップアップじゃなくてdocument.writeで書き換えるタイプにした方が良いのでは?

スクリプトを外部においてそれをロードしたいけどHTTPでサーブしてHTTPSAmazonに入れるのができない」という悩みをどこかで見かけたけど、個人だったらDropboxにおいたらHTTPSだから手軽に試せると思う。既にHTTPSでサービスを提供している事業者さんがサーブするのも悪くないかもね。出力後に自社サービスの広告を出すとかやれば「確定申告をしている人」というセグメントに低コストに広告できる。

出力されたTSVをExcelに貼り付けたら、Excelがタブをスペースに変換して悲しいことになった。また、僕がけっこう「書籍をまとめ買いする」という行動パターンのため、金額が出力されていないケースが多い。また、書籍と著者の対応付けがくるっているなど、割と「DOM周りでいろいろやりすぎてその後のAmazon側の変更に追随できてない」という現象が起きている。

このスクリプトによって出力された金額は無視して、自分で購入履歴を見ながら入力することにした。とはいえ、品名は既に入力済みなのでひたすら数字を入れるだけ。「選択してコピペ」とか「かな漢字変換」とかが必要ない分だけだいぶ楽である。

ただし、品物の下に書かれている「その商品の値段」を合算したものが必ずしも注文の総額にならない。送料などのせい。というわけで列は「年月日、総額、個別金額、品名」という感じにした。また手で打ってるので、経費にならないもの(食品とか娯楽とか)は金額を転記しなかった。そんな感じでの入力で、1ポモドーロで入力完了。全購入履歴311件中、入力された総額が106件。というわけで調査と金額入力で1時間程度でAmazonで購入した経費の整理ができた。

実装するなら総額と個別金額をわけて出力する機能はぜひつけたい。それができたら労力はさらに減る。

ただし何点か例外処理があった。まず、一度に7件注文したケースで、4件だけが表示され、残りが別ページにくくりだされていた。この場合TSVには品名が出力されていない。でもこれレアケースだし、僕の場合全部書籍だったのでどうせ全部書籍費として合算されるから「書籍A,B,C,D,その他3冊」という扱いにした。

もう一点の例外処理は、運悪く経費でない食料品と経費である参考図書とが同梱されて送られてきたケース。これは商品ごとの個別金額を手入力して食料品をスキップした。こういう状況で送料も掛かっているケースだと、送料を全額経費に積めなくて按分すんのどうすんのと言うことになりそうだが、どうせ大した金額ではないし頭を使うだけ面倒だということでまったく計上しないことにした。

この2点に関しては機械的にサポートしないで手で例外処理する形でいいんじゃないかなぁ。

室内の二酸化炭素濃度を測ってみた

3日分のデータを見て結構予想外

  • 通常の24時間換気だけで家に妻だけがいる時は十分換気される
  • 僕が帰宅して2人になると濃度がどんどん上がる
  • 2人が出かけるとすぐ下がる

2人が家にいるだけでこんなにスピーディに濃度が上がるとは思わなかった。

初日、設置から12時ぐらいまでの謎の動きはおそらくキャリブレーション。自宅に妻一人の間、400ppmでほぼフラット。19時半に僕が帰って来てからの1時間半で800弱まで急上昇。その後、僕が旅行に出かけたら、自然に低下している。

2日目、僕が旅行でいない間、400〜600で安定している。21時に僕が帰宅してから一気に900越えまで上昇。

3日目、900ppmからじわじわと減少。眠っているときには活動が控えめだから二酸化炭素の出る量も少ないのかな?それでも750くらいあったが、2人でランチに出かけている1時間半の間に500まで低下。その後帰宅して5時間で300ppm上昇。最後に5分ほど換気をしたら500ppmまで戻った。

センサーはこれ:Netatmo ウェザーステーション NET-OT-000001

当初この件に関しては「血中酸素濃度を測ろう」というアプローチでやってたのだけど、おうちハック同好会チームラボオフィスの空気環境(CO2)を測定して改善している話:tks(高須 正和)のブロマガ - ブロマガを知って、こっちの方が楽だなぁと方針転換した。

プログラミングシンポジウムでの情報教育の議論について

今年のプログラミングシンポジウムの夜のセッションでは情報教育についての熱い討論が行われました。その場で出た「この議論に関してブログなどに書くことは有益」という意見に賛成なのでこの記事を書きました。

手段の良しあしを議論するためには、まず「その手段を行うことでで達成したい『目的』は何なのか」が明確である必要があります。そうしなければ「手法Xは(目的Aのために)有益だ」「いや、手法Xは(目的Bのためには)有益ではない」という無意味な水掛け論につながるからです。

以前、首藤先生が指摘されたことですが、プログラミング教育の目的は少なくとも3つあります。「プログラミングのやり方の教育」「コンピュータ科学教育」「プログラミング行為の楽しさの伝道」です。

「『プログラミング教育』とひとくくりにされていて、違いが認識されていないことは、不幸のもとかもしれない」(首藤先生) この意見に私も賛成です。

2番目の目的には、コンピュータサイエンスアンプラグドとかビスケット開発者「原田ハカセ」のコンピュータサイエンス入門などがあります。会場で原田さんに、トランプを伏せて二人組で片方が指示だけして片方だけがトランプを見ることで「やり方(アルゴリズム)の工夫によって効率に大きな差が出るんだ」ということを教える話を聞いて、とても感銘を受けました。オセロのコマを使った誰でもできるマジック(種はパリティビットの概念)の話も面白かったです。

この種の「コンピュータ科学教育のやり方」を、もっと作ったり、共有したり、実際に使ってみたりして、改善のサイクルを回していくことで、目的2を達成しやすくなるでしょう。


目的の別の切り口として「a. すでに頭角を現しているトップ軍団を加速する」「b. 将来トップ軍団に入りうる人を見つけるための選抜を行う」「c. 広くすべての国民の底上げを図る」の3つがあります。会場での話題を見ていると 2-c「広くすべての国民にコンピュータ科学の基礎を習得させる」がよいことでありやるべきことであると前提した発言もあったように思います。この前提に関しては私は疑問ですが「全国民に習得させる」という手段の良しあしを議論するのであれば、その目的がなんであるかをまず明確化する必要があるでしょうね。

Windowsで会場のLANにつなぎつつインターネットはiPhoneのテザリングを使う

会場のLANにIRCサーバが立っているのでそこに接続したいが、ホテルから外に向かうネットワークがへぼい場合、インターネットへの接続は自分のiPhoneなどをUSB接続してテザリングした方が快適だったりする。両立するにはどうすればいいか、という話。

まあ「ルーティングの設定をする」が正解なのだろうけど、Windowsでどうやるのかなぁと思って検索して調べたもでやり方をメモしておく。

まず今のルーティングテーブルを表示してみる。関係なさそうなところは削除してある。会場のLANが 192.168.200.0/24 で、チャットサーバーは192.168.200.5で立っている。

>route print

IPv4 ルート テーブル
===========================================================================
アクティブ ルート:
ネットワーク宛先        ネットマスク          ゲートウェイ       インターフェイス  メトリック
          0.0.0.0          0.0.0.0    192.168.200.1   192.168.200.99     25
          0.0.0.0          0.0.0.0      172.20.10.1      172.20.10.7     20
    192.168.200.0    255.255.255.0            リンク上    192.168.200.99    281
   192.168.200.99  255.255.255.255            リンク上    192.168.200.99    281
  192.168.200.255  255.255.255.255            リンク上    192.168.200.99    281

一番上の行を消せばいいだけのように思うので以下のように実行。

> route DELETE 0.0.0.0 MASK 0.0.0.0 192.168.200.1
 OK!

もう一度printしてみたらちゃんと削除されてた。僕の期待していたように振舞っているのかtracertで確認。

> tracert 8.8.8.8

google-public-dns-a.google.com [8.8.8.8] へのルートをトレースしています
経由するホップ数は最大 30 です:

  1     1 ms    <1 ms    <1 ms  172.20.10.1
(以下略)

> tracert 192.168.200.5

192.168.200.5 へのルートをトレースしています。経由するホップ数は最大 30 です

  1     2 ms     1 ms     6 ms  192.168.200.5

トレースを完了しました。

ちゃんと確認するためには、削除する前に「8.8.8.8にアクセスしたときに192.168.200.1を通る」を検証しておくべきだったな。



続き。翌日。

元に戻ってる。

IPv4 ルート テーブル
===========================================================================
アクティブ ルート:
ネットワーク宛先        ネットマスク          ゲートウェイ       インターフェイス  メトリック
          0.0.0.0          0.0.0.0    192.168.200.1   192.168.200.99     25
          0.0.0.0          0.0.0.0      172.20.10.1      172.20.10.7     20

ということに変に接続が切れるので気づいた。

~$ git clone https://github.com/miyo/geister_server.java.git
Cloning into 'geister_server.java'...
fatal: unable to access 'https://github.com/miyo/geister_server.java.git/': Failed to connect to github.com port 443: Connection refused

~$ git clone https://github.com/miyo/geister_server.java.git
Cloning into 'geister_server.java'...
error: RPC failed; result=6, HTTP code = 0
fatal: The remote end hung up unexpectedly


あれー、ちゃんとiPhoneの側を通っているなぁ。

> tracert github.com

github.com [192.30.252.130] へのルートをトレースしています
経由するホップ数は最大 30 です:

  1     2 ms    <1 ms    <1 ms  172.20.10.1


ルートをDELETEしたらエラーメッセージが変わった。

~$ git clone https://github.com/miyo/geister_server.java.git
Cloning into 'geister_server.java'...
fatal: unable to access 'https://github.com/miyo/geister_server.java.git/': Could not resolve host: github.com

~$ git clone https://github.com/miyo/geister_server.java.git
Cloning into 'geister_server.java'...
fatal: unable to access 'https://github.com/miyo/geister_server.java.git/': Could not resolve host: github.com

うーん、どうしたらいいいのかな。名前解決できないことが問題の根っこじゃなさそうだ。

~$ git clone https://192.30.252.129/miyo/geister_server.java.git
Cloning into 'geister_server.java'...
fatal: unable to access 'https://192.30.252.129/miyo/geister_server.java.git/': Failed to connect to 192.30.252.129 port 443: Connection timed out