2012-08-30
Coursera Machine Learning Study Group at Silicon Valley
最近、courseraというオンライン大学が流行っていますが、ベイエリアでももちろん流行っていて、courseraで学んだことをオフラインでディスカッションしようぜ、みたいなmeetupもちらほら開催されてたりします。で、僕も先週から始まったAndrew先生のMachine Learningクラスをとっているので、そのmeetupに参加してきました。
僕が参加したのは、Silicon ValleyエリアのMachine Learning study groupで、Ruckus wirelessという会社の会議室に20人程が集まりました。先週第一回が行われて、今回が二回目の開催。僕は今回が初参加だったので、他の初参加者と一緒に、機械学習との接点や、今やっていることなど軽く自己紹介をしました。話を聞くとビッグデータをバックグランドにしている人が多いようです。
自己紹介が終わると、今回のメインセッション、PG&EのパフォーマンスエンジニアStephenによるプレゼンです。お題はMachine Learningのキャパシティプランニングやパフォーマンス解析への応用。サーバーのパフォーマンスをLinear Regressionを使って予測したり、サーバーのCPU Usage HistoryをSVMでパターン分けしたりといった実例を、Rのコードを使ってデモしてくれました。機械学習の実用、というと疑問に上がってくるのが「そんな仮定で大丈夫か?」という点で、例えば今回の例だと、例えばサーバーパフォーマンスをLinear functionと仮定していいのかとかという点が疑問でしたが、その辺りについては残念ながら特に深い考察はないようでした。(Stephen曰く、それがスタンダードだからLinear Regressionを使っているよ、とのことでした)SVMの方も、Rのsvm関数とtune.svmを使ってチューニングしているだけのシンプルな使い方をしているようです。
何より印象的だったのが、こちらの人々は本当によく質問や議論をする。Stephenのセッションはもともと45分の予定だったのですが、結局1時間半くらいかかりました。ここはちょっと分からないから後で自分で調べてみよう、なんて遠慮は一切なく、皆が皆、疑問点は余さず聞いてきます。まあそういうことが自然にできるのが、こちらの人の強み(で逆にできないのが日本人の弱み)だと良く言われますが、個人的には一長一短かなあと思っていて、結果的に全ての工程で分からない人に合わせて進めることになるので、効率が悪いと感じることもあります。
今回はプレゼンだけでタイムオーバーになってしまいましたが、今後はcourseraの課題を議論したり、ハッカソンをしたりと色々やっていく予定のようです。僕もPRML読書会落第生の名に恥じないように頑張っていく所存です。
ってなわけで、今シリコンバレーでモバイルエンジニアをやってます。まだまだ英語に四苦八苦していますが、なんとか生きてます。
2012-02-27
ライブラリに依存するプロジェクトのテストプロジェクトをantで実行できない件+AOSPにパッチを送ってみた件
Android SDK r14以降で、テストプロジェクトおよび、テスト対象の本体プロジェクトの両方がライブラリプロジェクトのクラスを呼び出している場合、antでのテスト実行で実行が失敗します。このままではJenkinsでテストを自動実行するときなどに困ってしまうので、Android SDKのbuild.xmlを書き換えて対応します。
- 修正済みbuild.xml(r16用) … Android SDK配下のtools/ant/build.xmlをこれで置き換えてください。
以下この問題の詳細についてです。
問題の概要
このようなプロジェクト構成をビルドしようとした場合に、取り得る手段は2通り考えられます。
- 本体プロジェクトのビルドパスにライブラリプロジェクトを追加して、本体プロジェクト側でライブラリプロジェクトをExportすることでテストプロジェクトは、ライブラリプロジェクトを参照させる
- 本体プロジェクト・テストプロジェクト両方のビルドパスにライブラリプロジェクトを追加する
ただ、これは両方ともうまくいきません。1はEclipse上ではうまく動きますが、antビルド時にはテストプロジェクトのコンパイルエラーが発生します。2はantテスト実行の際に、実行時例外が発生します。以下詳細を見てみます。
1のExport設定はEclipseのビルドパス設定で行うことができます。
この設定を行えば、Eclipse上でのテスト実行はうまくいきます。しかし、このExport設定が有効なのはEclipse上に限った話で、antからビルドしする際には読み込んでくれません。
そのため、テストプロジェクトをantでビルドしようとするとクラス解決がうまくいかず、コンパイルエラーになります。
$ ant clean debug install test
-compile:
[javac] Compiling 2 source files to /workspace/AndroidExampleTest/bin/classes
[javac] /workspace/AndroidExampleTest/src/com/polysfactory/antbuild/sample/test/TestCaseClass.java:5: シンボルを見つけられません。
[javac] シンボル: クラス LibraryClass
[javac] 場所 : com.polysfactory.andbuild.library の パッケージ
[javac] import com.polysfactory.andbuild.library.LibraryClass;
[javac] ^
[javac] /workspace/AndroidExampleTest/src/com/polysfactory/antbuild/sample/test/TestCaseClass.java:10: シンボルを見つけられません。
[javac] シンボル: 変数 LibraryClass
[javac] 場所 : com.polysfactory.antbuild.sample.test.TestCaseClass の クラス
[javac] String s1 = LibraryClass.test();
[javac] ^
[javac] エラー 2 個
2の両方にライブラリプロジェクトを参照する方法は、Eclipseでもantでも、テスト実行に失敗します。
以下のような実行時例外が発生するはずです。
test:
[echo] Running tests ...
[exec]
[exec] com.polysfactory.antbuild.sample.test.TestCaseClass:.
[exec] Error in testCase:
[exec] java.lang.IllegalAccessError: Class ref in pre-verified class resolved to unexpected implementation
[exec] at com.polysfactory.antbuild.sample.LibraryClassCaller.callLibraryClass(LibraryClassCaller.java:7)
[exec] at com.polysfactory.antbuild.sample.test.TestCaseClass.testCase(TestCaseClass.java:12)
[exec] at java.lang.reflect.Method.invokeNative(Native Method)
[exec] at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:169)
[exec] at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:154)
[exec] at android.test.InstrumentationTestRunner.onStart(InstrumentationTestRunner.java:529)
[exec] at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1448)
[exec]
[exec] Test results for InstrumentationTestRunner=..E
[exec] Time: 0.086
[exec]
[exec] FAILURES!!!
[exec] Tests run: 2, Failures: 0, Errors: 1
[exec]
[exec]
これは、本体プロジェクトから参照しているライブラリクラスと、テストプロジェクトから参照しているライブラリクラスが異なるために発生するエラーです。apkを解凍してみれば分かりますが、ライブラリプロジェクトのクラス群が本体プロジェクトのapkと、テストプロジェクトのapkの両方に含まれてしまっています。
Android SDK r13以前ではこの方法でうまくいっていました。Android SDK r14からAndroidのライブラリプロジェクトの扱い方が変わり、このような現象が発生するようになったようです。
ライブラリプロジェクトのクラス群は、本体apkのみに含まれて、テストapkには含まれないのが正しい動きです。しかしAndroid SDKに含まれるbuild.xmlは、そのようなビルドプロセスをサポートしていない為、この問題を解決するにはAndroid SDKのbuild.xmlを書き換える必要があります。
解決方法
build.xmlを書き換えます。antのビルドプロセスとして、テストプロジェクトのビルド->subantの呼び出しで本体プロジェクトのビルド->subantの呼び出しでライブラリプロジェクトのビルドとなっていますが、antではsubantの呼び出しをまたいで変数を共有できないので、一時ファイルにライブラリプロジェクトのjarのパスを保存しておくアプローチを取ります。
< <!-- Libraries property file --> < <property name="out.libraries.prop.file.name" value="libraries.prop" /> 452c450 < --- > 524d521 < 554,571d550 < < <!-- save libraries' jar paths to a temporary file --> < <propertyfile file="${out.absolute.dir}/${out.libraries.prop.file.name}"> < <entry key="libraries.jars" value="${toString:project.libraries.jars}" /> < </propertyfile> < < <!-- load tested project's libraries path if this is test project --> < <if> < <condition> < <and> < <isset property="tested.project.absolute.dir" /> < </and> < </condition> < <then> < <property file="${tested.project.absolute.dir}/${out.dir}/${out.libraries.prop.file.name}"/> < </then> < </if> < 626d604 < 628c606 < value="${tested.project.absolute.dir}/bin/classes;${libraries.jars}" --- > value="${tested.project.absolute.dir}/bin/classes"
AOSPにパッチ送ってみた
せっかくAndroid SDKを修正したので、これを機にAndroid Open Source Projectにパッチを送ってみました。もし応援してくれる人がいたらスターとかつけちゃってください!
2011-06-19
Windows VistaでKinect SDKを動かす方法
先日ついにMicrosoft公式のKinectSDKが発表されましたね!
さっそく試してみたかったのですが、KinectSDKはWindows7のみサポート、そして僕の持っているのはWindowsVistaのみ・・・。
ということで何とかWindowsVistaで動かせないものかと頑張ってみました。
で、結論から言うと、
という結果になります。
サンプルプログラムで言うと、SkeletalViewerはまったく問題なく動きます。ShapeGameは音声入力の機能以外は動きます。
もうちょっと頑張れば音声の部分も動かせるかもしれませんが、セットアップにそこまで時間をかける気力もなく、僕は諦めてWindows7を買ってしまいましたが、一応記録として方法を記しておきます。以下32ビット版での手順ですので、64ビットの場合ファイル名を読み替えてください。
手順1:msiファイルを展開する
KinectSDKのインストーラーKinectSDK32.msiを好きな場所にダウンロードします。
http://research.microsoft.com/en-us/um/redmond/projects/kinectsdk/download.aspx
そのあとコマンドプロンプトを立ち上げて、ダウンロードした場所まで移動し、以下のコマンドを発行します。
C:\Kinect\SDK\Directory> msiexec /a KinectSDK32.msi targetdir="C:\temp"
ここでtargetdirには展開したい場所を指定します。どこでもいいのですが、ここではC:\tempを指定しています。
このコマンドを実行すると以下のように5つのファイル・フォルダがtargetdirに展開されます。
手順2:フォルダの移動とパスの設定
手順1でできたPFilesX86フォルダを、C:\Program Files\Microsoft Research KinectSDKのパスに名前を変えて移動します。
移動が完了したら、環境変数のPathに「C:\Program Files\Microsoft Research KinectSDK」を追加します。
手順3:ドライバのインストール
Kinectを接続するとドライバのインストールが求められますので、「ドライバの場所を指定する」を選択して、「C:\Program Files\Microsoft Research KinectSDK\Drivers」を指定します。自動的に必要なドライバがインストールされます。
ドライバのインストール後、再起動が必要です。
完了
これだけで完了です!
C:\Program Files\Microsoft Research KinectSDK\SkeletalViewer.exe
や
C:\Program Files\Microsoft Research KinectSDK\ShapeGame.exe
をクリックすると以下のように動くことが確認できると思います。
追伸
2011-06-12
AndroidとOpenCVで試す特定物体認識
6月2日に開催されたDevLOVEさんと弊社の共同開催勉強会で、「Android×ComputerVision」というお題で発表してきました。
要はOpenCVをAndroidアプリに組み込んで特定物体認識を試そう、というもの。
資料は以下です。
ソースはgithubで公開してます。
https://github.com/thorikawa/AndroidObjectRecognition/
概要
資料にも記載していますが、カメラのプレビュー画像からSURFの特徴点を検出して、LSHで再近傍検索→特定物体認識というのを毎フレーム行っています。
「物体」はCDのジャケット画像を5枚の内から認識して、それぞれの画像にあった音を鳴らす、というデモを行い、うまく認識することができました。
構成・ビルド方法
チェックアウト後のソースは
- OpenCVをAndroidから利用しやすくするためのOpenCVプロジェクト(android-jni以下)
- アプリのプロジェクト(apps/ObjectRecognition以下)
- 検出対象の画像から特徴点を検出しておくユーティリティ(dump_keypoints.cpp)
上記1番はAndroidライブラリプロジェクトとなっており、2番から参照されているため、Eclipseでビルドする場合は、両プロジェクトをimportしておく必要があります。
また、検出対象となる物体の特徴ベクトルはapps/ObjectRecognition/assets/keypoints以下にテキストファイルが配置されています。追加したい場合は、dump_keypointsでダンプした結果をここに追加し、2番のJavaソースで読み込んでいる箇所を修正してみてください。
チェックアウト後のソースには、ビルド後のバイナリも含まれていますが、自分でビルドしたい場合、
apps/ObjectRecognition
に移動してantコマンドを実行することでAndroidアプリをビルドすることができます。
$ cd ${checkoutdir}/apps/ObjectRecognition $ ant debug
改変方法
ソースを自分でいじりたい場合、アプリ側のJavaソースだけならチェックアウト後のソースをそのまま変更することができます。
c++部分のソースをいじりたい場合は、AndroidをターゲットにしてOpenCVをビルドできる環境が必要です。
まだ環境を構築していない人は、
http://opencv.willowgarage.com/wiki/Android
を参考に環境構築してみてください。
課題と考察
SURFの特徴点検出がとにかく遅いです。濃淡の差が細かく激しい画像だと、1回の検出処理に約3sec程かかります。
OpenCVは、他にもデフォルトでSTARやFASTなどの特徴点検出アルゴリズムを搭載しており、これらの方がSURFよりも速いのですが、精度のチューニングが間に合わなかったため、SURFで実装しています。
実用化に向けては、速度と精度のバランスを取ったチューニングを行う必要があります。(←そりゃそうだ)
また、今回は毎回LSHに突っ込む特徴ベクトルを毎回読み込んでいるため、
という問題があります。
原理的には計算されたハッシュ値だけをデータとして持たせておけば再近傍の計算はできるはずなので、その部分も課題となります。
2011-05-23
MacとNexus OneでAndroid Oepn Accessoryを試してみる
先日サンフランシスコで行われたGoogle I/OのKeynoteでは様々な発表がありましたが、その中で、僕が特に面白いと思ったのが「Android Open Accessory」です。
簡単に言うと、Androidデバイスに接続するUSB周辺機器を、誰でも簡単に作ることができる仕組みです。
Google I/Oではこの仕組みを試すための開発ボード「ADK」が無償で配られたり、日本のメーカーからも発売されたりしていますが、電子工作ということで敷居が高いと感じている人も多いんじゃないかと思います。
しかし、Android Open Accessoryが適用できるのは、別に電子工作に限った話ではありません。PCとAndroid端末さえあれば、今すぐに試してみることができます。というわけで、早速デモを作ってみたので簡単に解説していきます。
用意するもの
- AndroidOS 2.3.4にアップデートしたNexus One(テストしてないけど、多分Nexus Sでも問題なし)
- libusb-1.0インストール済みのMac OS搭載PC (テストしてないけど、その他のUNIX系OSでも動く可能性あり)
今回作るものの概要
Mac PCにUSBで接続されたNexus One上のAndroidアプリと、Mac PC上の実行ファイルとの間で、USBポートを介してデータの通信を行います。
ただ単にデータ通信するだけでは面白くないので、KeyNoteのデモのように、端末の動きをゲームに反映させてみます。
アーキテクチャは以下の図のような感じで、Androidの傾きセンサーやボタンクリックを検出して、その値をUSBを介して通信し、最終的にJavaScriptで作ったゲームに端末の傾きの値を反映させたり、アプリのボタンをクリックするとボールが追加されるようにします。
JavaScriptのゲームはBox2DJSのデモをちょこっと改造した力学演算系のゲームです。
実際に動かしてみるとこんな感じになります。
ソース全体
github: https://github.com/thorikawa/android-openaccessory-with-pc-sample
にアップロードしています。
アプリ側のソース
android-app-usbフォルダがアプリ側のソースとなっています。
基本的には、USB Accessory | Android Developersに記載されている内容に準拠します。
AndroidManifestの記述
USB周辺機器(今回はPC)が端末に接続されたイベントを捕捉できるように、AndroidManifestにIntent-Filterを記述します。
<activity android:name=".Top" android:label="@string/app_name" <intent-filter> <action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" /> </intent-filter> <meta-data android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" android:resource="@xml/accessory_filter" /> </activity>
meta-dataのresourceにxmlファイルを指定していますが、これは別途作成します。
filtering用のxmlファイル作成
/res/xml以下に、上記Intent-Filterのmeta-dataに指定したaccessory_filter.xmlを作成します。
<?xml version="1.0" encoding="utf-8"?> <resources> <usb-accessory manufacturer="Poly's Factory" model="Android Oepn Accessory Demo" version="1.0" /> </resources>
ここで指定するManufacturer・Model・Versionによって、Activityが扱えるUSB Accessoryがフィルタリングされます。後で解説するPC側のプログラムでも、同じ値を指定します。
Activity作成
Activity側では、接続されたUSB Accessoryと通信するために、2通りの方法でUSB Accessoryオブジェクトを取得できます。
USB機器接続時のIntentからActivityが呼び出された場合、IntentからUSB Accessoryoオブジェクトを取得することができます。
Intent intent = getIntent();
if (UsbManager.ACTION_USB_ACCESSORY_ATTACHED.equals(intent.getAction())) {
mUsbAccessory = UsbManager.getAccessory(intent);
}
2.任意のタイミングで取得する場合
USB機器接続後に、任意のタイミングでUSB Accessoryオブジェクトを取得することもできます。
mUsbManager = UsbManager.getInstance(this); UsbAccessory[] accessoryList = mUsbManager.getAccessoryList(); for (UsbAccessory usbAccessory : accessoryList) { // 条件に合致するusbAccessoryを選択 .... }
USB Accessory取得後はUsbManager.openAccessory()で、ParcelFileDescriptorを取得することで、普通のファイルストリームと同じように扱うことができます。
ParcelFileDescriptor pfd = mUsbManager.openAccessory(mUsbAccessory); FileDescriptor fd = pfd.getFileDescriptor(); FileInputStream fis = new FileInputStream(fd); FileOutputStream fos = new FileOutputStream(fd); fos.write(....);
実際のデモプログラムの中では、傾きセンサーで取得された値と、ボール追加ボタンが押されたかどうかを、バイト列にしてFileOutputStreamに出力しています。
PC側のソース
pc-usb.cがPC側のソースになっています。libusbとリンクする必要があるので "gcc -lusb-1.0 pc-usb.c" などでビルドして下さい。
PC側では、Android Open Accessory専用のプロトコルである、Android accessory protocolで通信を行う必要があります。
プロトコルの内容は、Android Open Accessory Development Kit | Android Developersを見ればわかりますが、Using Android in Industrial Automation » Turn your Linux computer into a huge Android USB Accessoryの記事で、Cとlibusbを使ったサンプルソースを公開している方がいらっしゃるので、ここではそれを参考にしてプログラムを書いてみます。
Android端末との接続
まず、USBで繋がっているAndroid端末の接続ハンドルを取得します。
#define VID 0x18D1 #define PID 0x4E12 libusb_init(NULL); libusb_device_handle* handle = libusb_open_device_with_vid_pid(NULL, VID, PID);
ここでVendorIDとProductIDを指定して、ハンドルをオープンしていますが、このIDは機種ごとに異なり、また同じ端末でも、USBデバッグモードとそうでない時で異なるので注意してください。
上記のIDはNexus Oneのデバッグモードで指定するIDです。
VendorID・ProductIDは、Mac OSであれば
/Developer/Applications/Utilities/USB Prober.app/Contents/MacOS/USB Prober
などを使って簡単に調べることができます。
Accessory Modeのset up
次に、Android端末はそのままではAccessoryと通信を行うモードになっていないので、モードを変更します。
Attempt to start the device in accessory modeに記載されている通信を、libusbを介して行います。
手順は、(1)端末がAndroid accessory protocolに対応しているかどうかの判定 (2)Accessory Identificationの送信 (3)端末をAccessory modeに変更 です。
(1)端末がAndroid accessory protocolに対応しているかどうかの判定
libusb_control_transfer(handle,0xC0,51,0,0,ioBuffer,2,0);
ioBufferにサポートするaccessory protocolのバージョンが返り、この値が0以外ならば端末がaccessory protocolをサポートしていると判断します。(現在サポートしている場合のバージョンは"1"のみ存在する)
(2)Accessory Identificationの送信
libusb_control_transfer(handle,0x40,52,0,0,(char*)manufacturer,strlen(manufacturer),0); libusb_control_transfer(handle,0x40,52,0,1,(char*)modelName,strlen(modelName)+1,0); libusb_control_transfer(handle,0x40,52,0,2,(char*)description,strlen(description)+1,0); libusb_control_transfer(handle,0x40,52,0,3,(char*)version,strlen(version)+1,0); libusb_control_transfer(handle,0x40,52,0,4,(char*)uri,strlen(uri)+1,0); libusb_control_transfer(handle,0x40,52,0,5,(char*)serialNumber,strlen(serialNumber)+1,0);
この命令によって、USB機器を識別するためのManifactorer・Model・Versionなどの情報が端末に送信されます。accessory_filter.xmlに記載されたフィルタリング情報は、ここで送信された値と一致するかで判定します。
(3)端末をAccessory modeに変更
libusb_control_transfer(handle,0x40,53,0,0,NULL,0,0);
Accessory Modeでのデータ送受信
以上で端末がAccessory Modeに変更されました。
このタイミングで端末のProduct IDが変更されるので
libusb_close(handle);
によって、Accessory Mode変更前の接続ハンドルをクローズし、
#define ACCESSORY_PID 0x2D01 handle = libusb_open_device_with_vid_pid(NULL, VID, ACCESSORY_PID)
によって、新しいAccessory ModeのPIDで接続ハンドルを作り直します。
ここまで行えば、後はlibusb_bulk_transfer関数を通じて、端末とバイトストリームをやりとりすることができます。
#define IN 0x83 #define OUT 0x03 #define BUFFER 1024 unsigned char buffer[BUFFER]; static int transferred; while (libusb_bulk_transfer(handle, IN, buffer, BUFFER, &transferred, 0) == 0) { ... }
ここで定数INとOUTは、それぞれAndroid側のUSBインターフェースを識別する値で、これも端末ごとに異なっています。今回はNexusOneの値を採用しています。
他の端末の場合、ProductIDと同じようにUSB Proberなどで確認してください。
PC側プログラムではここで読み込んだ値を、JavaScriptからも読み込めるように、一旦テキストファイルに書きだしています。
JavaScriptゲーム側
box2d-with-usbフォルダ以下が、ブラウザで実行するJavaScriptゲームのソースになっています。
詳細は省きますが、PC側プログラムがテキストファイルに書きだした取得された傾きセンサーの値と、ボールが追加されたかどうかのフラグを参照して、それに応じた力学アニメーションを行うようになっています。
まとめ
Android Open Accessoryは「オリジナルな周辺機器を自分で作れる」という面に目が行きがちですが、PCとAndroid端末でも簡単に通信できるよ!ということでサンプルの解説をしてみました。
電子工作が苦手な人でも、USB通信の中身を完全に自作できる、と考えると夢が広がるのではないでしょうか!







