2015年に書いたblog振り返り 〜 Re:VIEWぱないの

2015年12月31日木曜日

去年(2014年)はあまりblogを書かなかったなーと思い、年初に「ひとまず年間50本は書こう」と考えました。というわけで振り返りといっても内容の話ではなく、下回りの話です。

blogを書くための負荷を下げよう

4月にblogをRe:VIEWで書くことを考えるというエントリを書きました。
Re:VIEWでblogを書きたいと考えた動機などはRe:VIEW developers meeting #2でのLTにて喋ったので、よければ資料を参照ください。

本blogの基盤にはBloggerを利用していますが、残念ながらBloggerの編集機能は20世紀で進化がほぼ止まっています。掲載画像をGoogleの写真サービスと連携して取り込む仕組みや投稿のフィードをGoogle+へ流すなど、いくらかの改修はおこなわれていますが、エントリをオフライン環境で書いたりいわゆる軽量マークアップを利用して書くような仕組みは提供されていません。
さいわいBloggerはAPIを提供しているので、一定の領域は外部でツールを整備することで都合よくできそうでした。
Re:VIEWのファイルをBloggerへ流し込めるようにするやつ*1をざっとgolangで書いてみて、これに対応するBlogger用のテンプレートを書いてみて(review-blog-template)9ヶ月間ほど運用してきました。
[*1] このリポジトリには未pushの手元限定差分が結構あってイマイチだなぁと思っていますが、Bloggerに画像アップロードAPIがない以上はどうにもならない気配があります。

Re:VIEW導入の効果

Re:VIEWの導入後は常時Atomを開きっぱなしにし、何か思いついたら新しいファイルを作ってざっと見出しを書いて保存して放置するという生活をするようになりました。
何かネタを思いついたら書き足したり、移動や休憩のタイミングで肉付けをしたりという具合で徐々に膨らませていき、ほどほどまとまったら一気に仕上げて公開するというスタイルです。
このスタイルを導入してから実際にどれぐらい書いたのか気になったので、月ごとに書いたblogエントリの総数とRe:VIEWを使って書いた数をまとめてみました(表1)。
表1 2015年に書いたblogエントリ数まとめ
本数
1月0本
2月7本
3月2本
4月12本(うち12本Re:VIEW)←ここでblog書きへRe:VIEW導入
5月5本(うち0本Re:VIEW)
6月6本(うち4本Re:VIEW)
7月3本(うち3本Re:VIEW)
8月2本(うち2本Re:VIEW)
9月0本
10月17本(うち17本Re:VIEW)
11月3本(うち3本Re:VIEW)
12月5本(うち4本Re:VIEW)
計 62本中45本(73%)をRe:VIEWで書きました。
この中には読書のメモなども含まれるので、全部がしっかりしたエントリというわけではありません(むしろしっかりしたエントリとは・・・という気持ち)。
9月は下書きをいくつか書いたものの、雑誌の原稿を書いているうちに月が変わってしまって翌月へまわった格好です。その分、10月の本数が伸びているのがよく分かりますね。

blogを書くのにRe:VIEWを使ってよかったこと

サクサク書いて公開できる(疲れない)

なんといってもこれです。
blogを書くこと自体に気合を入れる必要がほぼなくなり、内容や周辺の調査へ集中できるようになりました。とても快適です。

見栄えのことをほぼ気にしないで良い

Re:VIEWからHTML出力したものにほどほどのCSSを当てた結果は、大体脳内でシミュレート可能です。
Bloggerの編集機能を利用して書いていた際には細かな体裁を調節するのに時間を食われていたことを考えると、大きな進化です。

下書きがジャンジャン貯まる

さきほど9ヶ月で45本のblogエントリを書いたと述べましたが、実は下書き状態のものが51本あります。
大体いつでもどこでも書けるので、小ネタを書き溜める先としてEvernoteより良いです。
もちろん、ものによっては時事ネタで再利用不可能になるものもありますが、書きかけのものを拾ってきてAdvent Calendarのネタにしたり、雑誌原稿のネタにしたりと割と使い勝手よく転用できています。

来年も?

引き続きRe:VIEWでblogを書いていこうと思います。

ゆくSORAくるCOM

2015年12月23日水曜日

SIM Earth

「光あれ」
こうして光回線があった。
C89一日目のことである。
しかし極東の島国に天使が舞い降りた日、文明は歩みを止めた。
人々はそれをインガオホーと受け入れた。いや、受け入れることで自らの思考を縛り、困難から目を逸らしたといったほうが正確だろう。
それから数千年、いや悠久とすら呼べるほどの日々が過ぎ去った。人口が激減し、人類はもはやアンデス山脈の中腹に位置するツンドラ地帯のみに細々と逃げ延びる、トリクロデートに覆われた地球。
幼い日々に目を輝かせて百科事典をめくり続けた彼は、いつしか環境復帰プロジェクトの管理者になっていた。
うみが

じょうはつしています。

きおんをさげてください。
システムからのウォーニングメセッジが自棄に心を打つ。
そんなことはわかってる。もう何世紀も前からわかっているんだ。
そんなことを言われてもどうすればいいのか分からない。
生態系が破壊しつくされた
ジェームズ・ラヴロックに心酔した彼が求めた未来のひとつの形ともいえる。
人々は状況打開の鍵を伝説の書に求めている。
『クラウドデザインパターン』
「そう。過去数世紀にわたって観測されていない"雲"を再びデザインし、雨を降らせ、生態系を復活させることが人類復活のための希望(SIM)なんだ。」
21世紀に戻って伝説の書を入手し、それに従って気候改変をおこなう。
そうだ。SIMによって地球がひとつとなる。
ガイアが、そう囁くのだ。
彼は自らの心にそよ風が巻き起こるのを確かに感じていた。あたかも秩序無用のサーキュレータのように。
「おや、21世紀へ旅立つのかい」
「ええ。この機を逃すと次のチャンスは2,000年後になってしまいますから」
「知ってるかい、21世紀にはトウキョウのアカサカに"みんみん"という"ギョーザ"のおいしいお店があったそうだ。チェーンの"珉珉"じゃない。」
「おいしい餃子情報は大歓迎ですが、なんで今それを?」
「ジョークだよ。意味なんてない。」
そろそろエクソダスの時が来たようだ。
僕はこれに乗って過去を変え、そして未来である現在を取り戻すんだ。
あの日をやり直せるならば。このソラを取り戻せるならば。

SORACOM?

そういうわけでSORACOM Advent Calendarの23日目です。
SORACOM自体については、もはや改めて紹介するまでもなく皆さんご存知だと思うので省略します。
今回は、SORACOM関連で私が今年やったことをまとめます。

SORACOM APIのモックを作った

SoraCommonNetSandboxというものを作りました。これは、次に挙げる.NET版非公式SDKの開発途中で各種APIの呼び出しをほどよくテストする仕組みが欲しくなった結果、副産物として生じたものです。
.NET版非公式SDKの実装範囲しかモックも書いていないので、まだまだ機能が不足していますが、徐々に足していきます。少なくとも、SIMをterminateするAPIを安心して叩けるようになったので私の心には平穏が訪れました。
本家にきちんとしたAPI sandboxがあったほうが嬉しいに違いないのでSORACOMサンタにもお願いしました。本家での実装を楽しみに待ちましょう。
他言語用の非公式SDKを作っている方など、必要があれば適当に叩いていただいて構いません(エンドポイントの記載などは: C#でSORACOM APIのモックを作ったよー。ついでにC# 6+ASP.NET 5で楽にRESTfulサービスを書けてオススメという話にあります)。

.NET版非公式SDKを作った

ASP.NET 5のサーバから自分のSIM一覧を管理する仕組みを書きたかったので、.NET版の非公式SDKを作りました(SoraCommonNet)。
自分で使う機能から順次カバーしていっていますが、網羅度はあまり高くありません。まだ足りないところも結構あります。PCLで作っているのでXamarinにも持っていきやすい、というメリットがあったはずなのですが、携帯端末上から他端末のSIMを管理する仕組みの必要性はイマイチ謎でもあります。
もちろんIoT管理インフラとして考えるとそれなりに妥当性があるのですが、どのみち携帯端末側に持つのはUIのみで処理主体はサーバになるのでは、という気がしますね。
このあたりの経緯は以前SORACOM APIをC#から触れるようにしたで書きました。

APIドキュメントの変更を追跡した

SORACOM APIのリファレンスはそこそこの頻度で更新されています。ページ末尾に記載されているAPIバージョンが同じでも、ドキュメントは細かく改訂されていきます。
.NET版SDKやモックを作っていくうえで(そして、きっと他の言語用のバインディングを作っている方々も?)このドキュメントの更新箇所を把握できたほうが良いと感じたので、個人的に定点観測しています。
要はこのページのソースにあたるJSONデータを取得してきてせっせとdiffを取っています。
データ取得部分のコードはSoracomApiCrawlerとして公開してあります。APIの増減は最低限把握したかったので、生のJSONに加えてAPIサマリ(一覧)も別途出力できるようにしています。
とにかくサーバの運用をしたくない昨今、Azure Web ServicesのWebJobsを使いたかったので使ってみました。
開発に際しては、Azureの管理コンソールが旧ポータルから新ポータルへの移行期間にあたってしまい、片方のコンソールにしかない機能を使うために行き来するストレスがあったり、新ポータルが時折落ちていて作業が進まなかったのですが、今では良い思い出です。
ちなみに、まだあまり使ったことのある人が多くなさそうなAzureの新ポータルでのバッチジョブ画面は図1のような感じです。前よりもだいぶすっきりしました。
  図1 Azureのバッチジョブ画面
定期的に取得したデータはAzureのBLOBストレージへと保存しています(図2)。
図2 AzureのBLOBストレージへたまっていくJSON
Azureのバッチで1日3回取得してBLOB保存したJSONデータは、個人作業の合間や仕事の休憩中たまにAzureのポータルへログインして手動で(!)一覧ページを表示し、更新がありそうならファイルをダウンロードしてJSONのdiffを調べています。
この結果をgistへ貼り付け、コメントと共にTwitterへ流しています。
定点観測していると、案外ソラコム内でのドキュメント更新ではまだ時折ケアレスミスがあり、あるタイミングの記述修正がのちの更新でうっかり巻き戻ってその後さらに更新されて正しくなったりしている、という人間くささを感じられてほっこりします。中の人がんばってますね。
さて、前述の通りAPIドキュメントの定点観測においてデータ取得以外の変更検出と差分抽出は完全に手動作業です。これではさすがに手間がかかるので自動化すべく最近コードを書いています。コード本体よりも周辺環境(ASP.NET 5 RC1+EF7 RC1)のファイル構成がイマイチ安定していない*1ところに時間を取られて度々心が折れています。
年明けには多少マシな感じになるでしょう。
[*1] たとえば、パッケージ名が変わっていたり、VSのプロジェクトテンプレートによって生成される設定ファイルの内容に齟齬があったりと、正式リリース前らしさを感じるものがいろいろあります。

来年もSORACOM

主に.NET圏から眺めたり手を出したりしていきます。
SORACOMで覆われる地球、楽しみですね!
SORACOM Advent Calendar 2015も残すところあと2日となりました。
明日の担当はmana_catさんです。

ScalaとChiselで電子回路をつくる高位合成の話

2015年12月20日日曜日

このエントリはHDL Advent Calendarの20日目のものです。
同時に、2015/08/24-25にクパチーノでおこなわれたHot Chips 27カンファレンスへ参加し、そこで紹介されていたRISC-Vに興味を持った関連エントリです。
このカンファレンスではQUALCOMMの新DSPアーキテクチャ発表や5Gネットワークに関する講演、MicrosoftのSmartNICなど興味深いトピックが多く扱われていました。
この中で私が最も強く関心を持ったのがScalaからの高位合成ツールであるChiselです。

Chiselの概要

Chiselは次のような特徴を持ちます。
  • 入力言語にScalaを用いたオープンソースの高位合成ツールキット
    • 出力はVerilog
  • クロック同期保証つきのシミュレータコード(C++)を書き出すことができ、これによって大規模チップの開発イテレーションすら比較的高速に回せるとしている
    • UC Berkeleyで開発され、RISC-Vの開発に利用されている
私自身はScalaをよく分かっているわけではありませんが、別段Verilogへの習熟度が高いわけでもないので、IntelliJ IDEAを使ってサクサクとコードを書ける分だけScalaのほうが楽かな、という感じで興味を持ちました。

とにかくChiselを触ってみよう

何はともあれ、半加算器を作るところからスタートしてみます。
やることは
  • 入力値同士を足してキャリーを発生させる
だけなのですが、主にScalaに不慣れなあたりでハマりました。ざっと失敗した箇所を挙げてみます。
  • .otherwiseの最後のブレースを抜かしてコンパイルエラー
  • BoolをBOOLと書いてコンパイルエラー
  • := を =としていて再定義エラー
  • Bool宣言したものにそのままのboolean値を突っ込もうとして型ミスマッチエラー(Bool(true)な必要ある)
    • implicit type conversion入れといて欲しい・・・
  • expectにboolean値もBool(...)も渡せない問題
    • ここはBitsとして扱うしかなさそう
このあたりはScala自体の学習が圧倒的に足りないので、Scala関数型デザイン&プログラミング—Scalazコントリビューターによる関数型徹底ガイドを読んで勉強中です。
ともかく、以下のようなコードが書けました。テストコードもゴリゴリと書いています。
package Td4Scala

import Chisel._

class HalfAdder extends Module {
        val io = new Bundle {
                val in0 = Bool(INPUT)
                val in1 = Bool(INPUT)
                val out = Bool(OUTPUT)
                val carry = Bool(OUTPUT)
        }
        when (io.in0 ^ io.in1) {
                io.out := Bool(true)
        } .otherwise {
                io.out := Bool(false)
        }
        when (io.in0 && io.in1) {
                io.carry := Bool(true)
        } .otherwise {
                io.carry := Bool(false)
        }
}

class HalfAdderTests(c: HalfAdder) extends Tester(c) {
        poke(c.io.in0, false)
        poke(c.io.in1, false)
        step(1)
        expect(c.io.out, 0)
        expect(c.io.carry, 0)
  //
        poke(c.io.in0, true)
        poke(c.io.in1, false)
        step(1)
        expect(c.io.out, 1)
        expect(c.io.carry, 0)
  //
        poke(c.io.in0, false)
        poke(c.io.in1, true)
        step(1)
        expect(c.io.out, 1)
        expect(c.io.carry, 0)
  //
        poke(c.io.in0, true)
        poke(c.io.in1, true)
        step(1)
        expect(c.io.out, 0)
        expect(c.io.carry, 1)
}
テストモジュールをもりもり作りながら進めるスタイルが定着するのもいいなっという感じがしますね。

Verilogへ出してみる

書けたScalaソースファイルをScalaの流儀に従ってbuild.sbtファイルの定義のもとビルドしていくのですが、少々うまくいかないところもありました。
  • Makefileのターゲットを変えるとコマンド出力的にはできそうだが実際には.vファイルが生成されない
  • vpi_user.hが無いと怒られる
    • ハーネス側がだめっぽい?
    • 無駄オプションを削ってコンパイルオプションを--backend vだけにする
  • 普通に通った
    • やっぱハーネスかー。これは後で調べる
無事に通った結果、生成された.vファイルは次のようになりました。
module HalfAdder(
  input  io_in0,
  input  io_in1,
  output io_out,
  output io_carry
);

  wire T0;
  wire T1;
  wire T2;
  wire T3;


  assign io_carry = T0;
  assign T0 = T1 ? 1'h1 : 1'h0;
  assign T1 = io_in0 & io_in1;
  assign io_out = T2;
  assign T2 = T3 ? 1'h1 : 1'h0;
  assign T3 = io_in0 ^ io_in1;
endmodule
生成されていますね。
タイミング検証とテストコード実行をおこなうためのエミュレータ用C++コードは次のとおり生成されました。
#include "HalfAdder.h"

// ... 略 ...

void HalfAdder_t::clock_lo ( dat_t<1> reset ) {
  val_t T0;
  { T0 = HalfAdder__io_in0.values[0] ^ HalfAdder__io_in1.values[0];}
  val_t T1;
  { T1 = TERNARY(T0, 0x1L, 0x0L);}
  { HalfAdder__io_out.values[0] = T1;}
  val_t T2;
  { T2 = HalfAdder__io_in0.values[0] & HalfAdder__io_in1.values[0];}
  val_t T3;
  { T3 = TERNARY(T2, 0x1L, 0x0L);}
  { HalfAdder__io_carry.values[0] = T3;}
}

// ... 略 ...

この先

半加算器だけではなんとも悲しいので、ひとまずこのまま4bit同士の加算をできるところまで拡張してみて、手持ちのFPGA評価ボードで計算の途中経過をLED出力できるようにしてみようと思っています。
それには入力用のスイッチ8つと出力用のLED5つを制御する必要があるのですが、これPmod(手持ちのMicroZedは100ピンの高周波回路用コネクタ以外には基本的にPmodコネクタぐらいしかないので)ではギリギリ足りないな? と気付いて頭を抱えたりしている昨今です。

Scalaで電子回路、楽しいかもしれない

Chiselが高位合成ツールセットとして楽しいポイントは、概要にも書いたようにクロック同期保証付きのエミュレータ用コード生成をおこなってくれるあたりです。小さなものを書いている中でもすでにcpp経由で開発マシン上のバイナリを吐き出してサクサク実行できることの楽さは感じつつあります*1し、これはきっと扱う対象が大規模化するにつれて更に嬉しくなっていくのでしょう。
趣味で作るハードウェアでも「ScalaコードをコミットしたらJenkinsで速やかにタイミングチェックまでおこなって、結果が怪しければ即座にエラーメールが届く」というワークフローになるとずいぶん楽しいと思いませんか。
また、今回Chiselを使ってみた結果、Scalaを勉強する機会にもなりました。これまでScalaといえばコンパイルが遅い言語でなんとなくHaskellのほうがかっこいい、ぐらいの印象でいたのですが、ちゃんと学ぶ気力が湧いてきたのでとてもよかったと思います。
Chiselの続編はまたそのうち。明日の担当はikwzmさんです。
[*1] 特に私の場合はScalaにもVerilogにもさほど慣れていないので、コードの正しさを判定するためのセカンドオピニオンとしてC++コードを利用できる安心感は大きいです。

Xamarin.Forms+UWPの秘めた可能性とXamarin.IoTの夢

2015年12月17日木曜日

完全にこのタイトルを書きたかっただけです。本記事はXamarin Advent Calendar 17日目のものです。

Xamarin.Forms + Windows 10 IoT Coreの可能性

まずはRaspberry Pi2 + Windows 10 IoT Core + Xamarin.Forms でIoT向けのUWPアプリをサクサク書いてみようという話をします。
Xamarin.FormsをUWPで利用する方法はXamarin本家のチュートリアルページに記載されています(参照: https://developer.xamarin.com/guides/cross-platform/xamarin-forms/windows/getting-started/universal/)。
Visual Studio 2015上からXamarinプロジェクトを作成して手順に従います。
図1 Xamarin.Forms+UWPのチュートリアル
Windows 10 IoT Core上でXamarin.Forms利用プロジェクトを最低限動作させるまではとても簡単です。適当にUWPプロジェクトを生やしてXamarin.Formsをパッケージ追加し、メインのXamarinプロジェクト(PCLのもの)への参照も追加し、あとはチュートリアルどおりにいくつか.xamlファイルなどへ変更を加えるだけです。
図2 Xamarin.Forms on RPi2+Win10IoTCore
このスクリーンショットでは少々フォントサイズをいじって見やすく(図3)していますが、ともかく普通に動作します。
図3 VS上でXAMLを開いたところ
このUIはキーボードやマウスを利用して操作できます。もちろんボタンやラベルといったXamarin.Formsが提供する各種UIコンポーネントを利用できますし、データバインディングを活用したプログラミングも可能です。

まあつらいよね

実際にRaspberry Pi 2へWindows 10 IoT Core環境を作ってわざわざVisual Studioからデプロイするまでもなく、Xamarin.FormsをWindows 10 IoT Coreと組み合わせることの厳しさは明らかです。
Windows 10 IoT Coreはその名前のとおりIoTを中心とした組み込み向け(そのなかでも、とりわけ簡易的なユーザインタラクションを伴うのがせいぜいというエリア)のOSです。このため、ユーザとのインタラクションに関する厳密な規定を持ちません。当然、タッチスクリーンインタフェースの存在を前提とすることもできません。
いっぽうでXamarinが得意とするプラットフォームはタッチスクリーンインタフェースを前提とするものたち(iOS/Android/Windows 10 Mobile)です。いくらUWPなアプリがWindows 10 MobileとWindows 10 IoT Coreの間で垣根なく動作するといっても、用途の根幹が違うものを混ぜるのは基本的に悪手です。
Raspberry Pi2 + Windows 10 IoT Coreの用途自体がもう少しタッチスクリーンUIへと寄っていく*1ようなイベントが発生すればXamarin.Formsを活用できる場面が増えそうですが、それまでの間は残念ながら
  • iOS/Android向けにXamarin.Formsベースで構築した(さほどビューをゴリゴリ作りこんでいない)ものを大画面でのサイネージ表示用へと安価に転用する
という、わりとありがちなシナリオが現実的と考えられます。
この場合、用途としては50-80インチ程度のディスプレイとタッチパネルモジュールとの組み合わせを前提とするサイネージで、インタラクションはさほど発生させない前提(メインメニューからの階層をタップでたどっていく程度)がしっくりきます。商業施設内の簡易案内用システムなどで見かけるエリアですね。サイネージから手元スマフォでのアプリ利用へと誘導できるような仕掛けになっていれば一定回りそうではあります。
[*1] $20程度の安価なタッチパネル付きディスプレイモジュールがデファクト・スタンダードとして普及すればこれはあり得ます。現状の7"ディスプレイ単体で$50近くかかる状況では無理そうですね。

Raspberry Pi 2 + Windows 10 IoT Core + Xamarin - GUIでのインタラクション = ?

Raspberry Pi 2 + Windows 10 IoT Coreはとても良い組み合わせです。ハードウェアの持つ力を十分に発揮しうる組み合わせといえます。
そこにXamarinを足してそこから一旦GUIでのインタラクションを引いてみようと考えてみます。
ええと、UWP環境には元々C#コードの十分な実行環境が整っています。つまり、Xamarinの中ではメインのx-platコード実行基盤及び大半のBCLの出番がありません。そうなるとXamarinシリーズの中ではFormsコンポーネントやTest Cloudあたりが絡めそうなポイントです。
Test Cloudはさておき、GUIインタラクションを差し引くとFormsコンポーネントを追い出すことになります。結果、Xamarinらしいポイントは一切残らないということになってしまいます。
なんだか悲しいですね。そう思っているうちになんとなく「Xamarin.IoT」というフレーズを思いつきました。なんかかっこいいですね。せっかくなのでXamarin.IoTがどういうものであってほしいかを想像して書いてみることにしました。

Xamarin.IoTを想像してみる

Xamarinシリーズということは、きっとXamarin.IoTというのは「C#やF#といった言語で開発できてサーバとも連携させやすい、クロスプラットフォーム(x-plat)IoT開発をめっちゃ楽にしてくれるなにものか」でしょう*2
その担当するレイヤ境界は従来のXamarinの区切りと少々異なるはずで、「サービスの構築に直結する部分よりも下をごっそり抽象化した各種のcommon APIs」と「必要ならば自らそのサービスプロバイダを書いて拡張できる仕組み」となってほしいところです。
各種のcommon APIsというのは次のような感じでしょうか。
  • BLE足回りのx-plat基盤
  • x-platなGPIO基盤
    • え、それSystem.IO.Ports.SerialPortじゃダメなの?→どっちかというとGpioClx系では
      • シリアルポート抽象化は何かと嬉しい。たとえばそのプロバイダとしてBTなどを透過的に扱える形だと嬉しいのかも
    • あるいは、BT/ADK/USB-Hostなどを適宜下回りとして利用できるデジタル信号送受信の仕組み
他にはバケツリレー式でメッセージを適宜上位ノードへ持っていってくれる機能とか、SORACOM Beamのようなインテリジェントなゲートウェイを介するデータフロー作りとか、そういう方面でしょうか。もちろん、Xamarin.IoTを構成する要素のすべてでフルバージョンの.NETランタイムが動作する必要はないはずです。センサー値を定期的に取得して蓄積し、加工したうえで上位端末へ送信する役目を担う末端の端末*3ではごく限られたサイズのメインプログラムを動作させるためにminimalなランタイムとFull-AOTコードを突っ込むことになるのではないでしょうか。
きっとXamarinならこういう絵を描いて未来を見せてくれるはずだ! というわけで、なんというかAdvent Calendarというよりも「初夢Xamarin 2016」みたいな話になりました。
[*2] あれ、なんだかWCFの雰囲気を感じますね。気のせいでしょうか。
[*3] ARM Cortex-A9 Quad Core CPU + 1GBメモリなんてリッチに載っていない、Cortex-M0〜M3 CPU + 64 KBメモリ的環境を想定しています。

まとめ

Raspberry Pi 2 + Windows 10 IoT CoreにXamarin.Formsを持ち込んでも(今のところ)個人利用で嬉しいケースは少ないという話と、Xamarin.IoTという語感からその用途やあり方を想像してみると割と面白い気がしたという話でした。
明日の担当はMasaakiYoshidaさんです。

みんな知らない凄いヤツ はじめようProject Oxford

2015年12月14日月曜日

この記事はMS技術Advent Calendarの14日目のものです。

Project Oxfordとは何か

Project OxfordはMicrosoftの自然データ解釈技術をアプリやサービスへと簡単に取り込めるようにするプロジェクト(Microsoft Project Oxford)です。
2015年4月のMicrosoft主催のデベロッパーカンファレンス(//build 2015)で発表されました。
このカンファレンス時には多少話題になったのですが、実際のSDK提供までにしばらくのタイムラグがあったためあまり最近話題になっていないのが現状です。つまり、ほとんど知られていないので紹介していきますよという話です!
使える機能群には自然言語処理や画像認識など、事前にガンガンとトレーニングをかけた機械学習の権化のようなものがいっぱいあります。MSの技術というよりもMSR(Microsoft Research)の成果を一般転用したものという印象です。

アイドルCortanaさん

Project Oxfordで提供される仕組みを使った実世界のサービスの代表格がWindowsアイドル、Cortanaさんです。iOS界のスーパーアイドルSiriと競い合う感じで日々前へ出ようとしていますね。
コル、コル、タナーーー! みなさん一緒に、「「「コル、コル、タナーーー! 」」」

なぜProject Oxfordが嬉しいのか

みなさんご存知のhttps://how-old.net/、平和の極みみたいなサービスですよね。特に誰も傷つけることなく*1写真からの顔認識とその年齢推定を楽しさへと変えてくれるサービスです。
その昔、face.comというオンラインの顔認識サービスがありました。残念ながらFacebookが買収してサービスをシャットダウンしたので、私は安価/無料で比較的自由に利用できるオンラインの顔認識サービスがなくて厄介だなぁと思っていました。
Project Oxfordでは顔認識サービスも公開されています。顔認識と共に感情の推定もおこなってくれる、なかなかすごいやつです。
私はどちらかというと機械学習したいマンではなくて機械学習結果を使いたいマンなので、ひとまずProject Oxfordのあれこれを触ってみようという次第です*2
[*1] 勝手に他人の画像をアップロードして不快感を生むなどはさすがに例外とさせてください。
[*2] 同じ方面ではGoogleが2015年12月にCloud Vision APIという仕組みの限定プレビュー版を開始したようですね。https://cloud.google.com/vision/

提供されている機能の概要

Project Oxfordで提供する機能は多岐にわたります。ここでは本家サイトの構成に準ずる形で一覧を紹介します。
興味をもった項目はぜひリンクを辿って詳しく調べてみてください。
  • Vision
    • Computer Vision APIs
      • 画像分析、サムネイル生成、OCR(文字認識)
    • Face APIs
      • 顔認識、顔認証、類似顔検索、顔分類、顔識別
    • Emotion APIs
      • 感情認識
    • Video APIs
      • 未公開(実際にはProject Oxfordポータル側では映像の安定化(stabilize)、動き検出、顔認識とトラッキングを制限つきで提供するとあります)
  • Speech
    • Speech APIs
      • 音声認識、音声意図認識、音声合成(TTS)
    • Speaker Recognition APIs
      • 未公開(音声データを突っ込むと話者を識別して返してくれるものになるはず)
    • Custom Recognition Intelligent Service
      • 未公開(IBMのワトソンみたいな、とまではいかないまでも、アプリケーションを音声入力でサクサク使えるようにする仕組みのはず)
  • Language
    • Spell Check APIs
      • スペルチェッカとしての高度な機能(単語区切り位置の間違い訂正、スラング込みの認識、ありがちな名前のスペルミス訂正、文脈中での間違い訂正、最近のブランド名サポート)
    • Language Understanding Intelligent Service(LUIS)
      • 自然言語を使ってアプリケーションを操作する仕組みを簡単に実現する仕組み
一覧の最新版はわりとhttps://github.com/Microsoft/ProjectOxford-ClientSDKにまとまっています。

サポートするプラットフォーム

音声認識系APIが最も対応範囲の広いもので、Windows/iOS/Androidをサポートします。顔認識とCVはWindows/AndroidのSDKを提供しています。スペルチェックと感情認識はWindowsのSDKのみを提供しています。
音声認識など一部の機能はWindows 10に組み込まれているもので、Windows版SDKの内部でそのOS組み込み機能を呼んでいるようです。Windows 10 Mobileでの挙動についてはまだ実機で確認していないので把握できていません*3
[*3] MADOSMAのOTA更新がなかなか来ないのでそろそろマウスショップへ持ち込もうかなと思い始めた昨今です。

利用制限

利用制限はそれぞれのAPIごとに異なります。たとえば音声認識APIでは月間のAPI呼び出し可能回数が5,000回に制限されています。
詳しくはドキュメントを読む必要があります。

音声認識APIことはじめ

まずはこのデモをごらんください。
https://www.projectoxford.ai/demo/speech#recognition
これは、Project Oxfordの本家サイトでホストされている音声認識と音声合成のデモです。PC向けのモダンなWebブラウザで開くと、一切のプラグインを要求することなく音声認識を実現できることがわかるでしょう。
ちなみに音声認識についてはAndroid向けのクイックスタートガイドがあります。Android勢はこちらを参照してください。
そしてProject Oxfordの真骨頂ともいえるRESTのAPIはこのような構成です。もちろんRESTのAPIよりも事前に構成されたC# SDKのほうが使いやすいケースもあるでしょう。そのような場合にはお馴染みのドキュメントを出発点としてAPIを掘り下げられます。

私がやっていること

私は目下、Project Oxfordが提供する音声認識エンジンを使ってWebアプリを作っています。ここでは、この中で中核を担う音声認識部分のコード断片を紹介します。
まずは音声認識クライアントを生成してAPIキーを設定、そして送信する音声のフォーマット指定をおこないます。
  var speechClient = SpeechRecognitionServiceFactory.CreateDataClient(SpeechRecognitionMode.LongDictation, "en-us", API_KEY);
  speechClient.SendAudioFormat(SpeechAudioFormat.create16BitPCMFormat(8000));
SpeechRecognitionModeには短時間版と長時間(最大2分)版の二種類を設定できます。ここでは長時間版(LongDictation)を設定しました。
Project Oxfordが提供する音声認識エンジンで認識できる言語はいくつかあります。具体的にはこのページへ記載されているとおり「英語(US)、英語(英国)、ドイツ語、スペイン語、フランス語、イタリア語、中国語」です。ここでは英語(US)を指定しました。
APIキーは2015年11月まではMicrosoft Azureの管理画面から発行したものを利用していました。この手順はごく最近(2015年12月上旬?)に変わり、https://www.projectoxford.ai/Subscription/Indexへとアクセスして必要なAPIキーを発行するようになりました(図1)。
図1 保持しているProject Oxfordライセンスの一覧
このサイト上から残り利用可能なAPI呼び出し回数なども確認できるようになりました。
さて、コードに戻ります。
音声認識クライアントの初期化を完了したら、続いていくつかコールバックを仕込みます。
音声認識においては
  • 部分結果(認識途中の候補データ)
  • 最終結果(認識完了時の結果データ)
が大切です。最終結果だけを使うケースもありますが、今回は「音声認識実行中であり、何かしらの中間結果が得られている」ことを呼び出し側で判断したかったので次のように両方を利用しています。
  speechClient.OnPartialResponseReceived += async (sender, e) =>
  {
      await SendCommandToClient(new JsonCmd { Command = "partial-result", Parameters = e.PartialResult });
  };
  speechClient.OnResponseReceived += async (sender, e) =>
  {
      var result = e.PhraseResponse.Results.FirstOrDefault();
      if (result == null)
      {
          return;
      }
      var resultObj = new { text = result.MaskedInverseTextNormalizationResult };
      // ...
  };
OnPartialResponseReceivedで得られるのが途中結果、OnResponseReceivedで得られるのが最終結果です。
ここでは最終結果で渡される結果オブジェクト内のMaskedInverseTextNormalizationResultを読み出しています。これは、不適切なワード(いわゆる4-letter wordsなど)を****とマスクした状態で格納したものです。InverseTextNormalizationResultには認識結果がそのまま格納されます。
基本的に音声認識に関わるコードはこれだけです。これに加えて実際にはWebSocket経由でオーディオストリームを受け取って右から左へ流す仕組みや、不要の際に流れてきたデータを一時的に音声認識サーバへ流さず捨てる「ミュート」機能などを持ちますが、根っこの部分はこれだけです。

クロスプラットフォームでの音声認識API利用

音声認識APIは前述のようにWeb版(REST版)のみならずWindows版Android版、iOS版も提供しています。個人的にはWeb版(Rest版)ですべてのプラットフォームをカバーできるならばそれでよかったのですが、この場合に大きな壁となるのがiOSです。
iOSでは残念ながらiOS(Mobile Safari)のWebRTCサポートは弱く、音声キャプチャの機能がいまだに(iOS 9.2時点)存在しません*4
iOS側のサポート状況が改善するのを待つよりは普通にネイティブアプリで組んだほうが良い結果となりそうなので、目下Xamarinを通じてWindows Phone(Windows 10 Mobile)、iOS、Androidで共通利用できるラッパーライブラリを書いているところです。
こういうところでXamarinの楽しさが活きますね!
[*4] BowserというiOS向けのWebRTC機能組み込みWebブラウザを使えばゴリ押し利用できるのですが、いかんせん実験的なWebブラウザで出来がイマイチなので常用に耐えるものではありません。iOS版Firefoxでの音声キャプチャサポートはよ

ASP.NETに関わる部分

今回は音声認識結果をもとに遊ぶ簡単なゲームを作り、そのなかではVS 2015上でASP.NET 5のテンプレを使ってコードを書いてみました。
データの保存にはEF7(Entity Framework 7)を試しに使っているのですけれど、インデックスを張るためのAttributeを探したところなくなったようで難儀しました。結局、EF7では基本的にデータベースの細かな部分をすべてプログラム側コード(EF7の場合はC#)で完結するのではなく、適宜DDLを自前で書くのが良いという思想だと解釈して自分でインデックスをぽちぽちと張るようにしました。
ASP.NET 5系のロードマップ上でEF7自体に大きな手が入る場面はこの先なさそう&これはこれで良いと感じているのですが、EF7としてのプラクティス集(DOs and DON'Ts)が欲しいなと感じたりもしましたとさ。
あっ、Microsoft Azure Web Apps+ASP.NET系の環境でWebSocketを利用する場合には、AzureのPortal上からWebSocket利用オプションを有効にするのを忘れないようにしましょう。私はこれで割とハマりました。

まとめ

Project Oxfordすごいぞい楽しいぞいという話でした。
メインで紹介した音声認識系以外にも楽しい技術がいっぱいなので順次さわっていきたいところです。
明日のMS技術Advent Calendar担当はredwarriorさんです。

「Windows Phoneビジネスアプリケーション開発ガイド」の小並感と誤植一覧

2015年12月12日土曜日

12/4発売(12/12発行)のWindows Phone開発本を購入してざっと読んだので感想メモなど。


見つけた誤植一覧

    p.243 5行目 WrieableBitmap
        WriteableBitmap
    p.248 2行目 WritebleBitmap
        WriteableBitmap
    p.248 3行目 WritebleBitmap
        WriteableBitmap
    p.248 4行目 WritebleBitmap
        WriteableBitmap
    p.256 最終行 ここで「位置情報」選択します。
        を
    p.259 1行目「緯度 ̄経度」(実際は半角オーバーライン)
        「~」が正しい
    p.258 6行目「{0} ̄{1}」
        「~」が正しい
    p.270 下から2行目 「ファイルを開くのときと同様」
        開くとき
        項参照なら鍵括弧などで明示しないときつい
    p.280 8行目 duble?
        double?
    p.282 表3行目末尾の「。」
        他の項目についていないので不要
    サンプルコード中で「datas」という変数名があるのは、あまり気にしないことにした
    p.289 1行目「本章最後に」
        の
    p.292 サンプルコード内の「chank」
        さすがにchunk
    p.310 9行目 「それに参照しながら」
        それを