ラベル ライブラリ の投稿を表示しています。 すべての投稿を表示
ラベル ライブラリ の投稿を表示しています。 すべての投稿を表示

2014年10月5日日曜日

HMMLearn導入メモ

どうもご無沙汰しております。気づけば一年以上ぶりですね。
忙しさを言い訳に全く何もしてない状況が続いていましたが、さすがにこれはマズいとそろそろ重い腰を上げたいところです。

最近はデータ解析のまねごとに勤しんだり、新しい機能の開発をやってみたり、新卒の子のフォローをしてみたりと色々やっているわけですが、ここに来てまた他のことにも手を出そうとしています。下手の横好きとも

ということで、タイトルのネタです。

諸々の事情により時系列データの予測をする必要に迫られそうなので、とりあえずHMM使ってみるかー、という安易な発想に基づき手頃なライブラリとして sklearn を導入することに。

が、

HMMのリファレンスいわく、
Warning

The sklearn.hmm module has now been deprecated due to it no longer matching the scope and the API of the project. It is scheduled for removal in the 0.17 release of the project.

This module has been moved to a seperate repository: https://github.com/hmmlearn/hmmlearn
とのこと。
仕方ないので、hmmlearnのリポジトリに飛んで記載されている手順通りにインストール。

  1. git clone git://github.com/hmmlearn/hmmlearn.git
  2. cd hmmlearn
  3. python setup.py install
  4. nosetests
すると、4. で以下のエラーに遭遇。

E.E
======================================================================
ERROR: Failure: ImportError (cannot import name _hmmc)

まぁ、なんやかんやあって切り離されたライブラリみたいだし、しょうがないかと思ってissuesを漁るとありました、ドンピシャのやつ。
https://github.com/hmmlearn/hmmlearn/issues/3
見るとまだ解決していないようですが、とりあえず全部コピればOKのようです。

……汚くなるからやだなぁ。

ということで色々試してみた結果、以下のようにすれば良さそうです。
$ cp -r hmmlearn/utils/ ${PYTHON_ROOT}/site-packages/hmmlearn/utils/
(${PYTHON_ROOT}はpythonのインストール先。virtualenv使ってたら、${VIRTUAL_ENV}/lib/pythonx.x/とかでしょうか)

どうもこのutils直下にいるfixes.pyを読んでいる感じですが、詳細不明なのでとりあえずの対処ということで。
ひょっとしなくてもvirtualenv使ってるとおかしくなるとかそういうアレかもしれません。

割とニッチなライブラリみたいなので困っている方はいない気もしますが、万一お困りの方がいれば参考までに。

2012年7月25日水曜日

続・Macでのlibjpegとかlibpngとか

またしてもひと月おきの更新です。
さて。
今回はタイトルにも掲げていますが、先日書いた記事(Macでのlibjpegとかlibpngとか)の続き(というかまとめ)です。*1
あんまり追加情報はありません。

まとめ

先日の記事で書いた、「-Lオプション付ける位置次第で動いたり動かなかったりする」という問題は、どうやらNetBeansに依存する問題のようです。*2
ということで、Macでlibjpegおよびlibpngをうまいこと動かすには、

  1. libjpegはbrewなどでインストールしたモジュールを使う
    1. ライブラリパス /usr/local/lib は、デフォルトでdyldが探すので、手動で追加しない
    2. インクルードパス /usr/local/include は指定する(-I/usr/local/include)
  2. libpngは下手にbrewなどで追加しない
    1. 最初から(?) /usr/X11/lib にライブラリファイルがあるはずなので、それを使う
    2. ライブラリパスに /usr/X11/lib を追加する(-L/usr/X11/lib)
    3. インクルードパス /usr/X11/include も指定する(-I/usr/X11/include)

ということが重要なようです。
ちなみに、X11の下にlibpngがいない場合は、XCodeをインストールした後、Command Line Toolsという追加コンポーネントをダウンロードする必要があるかもしれません。

  • *1:閲覧数を見る限り割と需要がありそうだったので。
  • *2:ターミナルからgcc直接叩いたら問題なく動いた。

2012年6月28日木曜日

Cakefile書こうとして一歩目から躓いたお話

ご無沙汰しています。
最近自分のコードを書く気力がなくてどんよりしてます。

さて。

突然ですが、私、ここ最近CoffeeScriptに魅了されております。
会社の先輩にそそのかされたとかなんとか。

仕事で結構な行数のJavaScriptを書くことがあるのですけど、素のJavaScriptを書いているとどうもしんどいことが多々有りまして。
その点CoffeeScriptだと、手軽にコードが書けて非常に便利です。

んで、諸々の事情により、CoffeeScriptを自動コンパイルする必要が出てきて、Cakefileの書き方を調べていたのですが、初手から躓いたので、そこら辺をメモしておきます。

一番単純な(ハズの)Cakefile

まずはと思って、CakeFileの使い方 -CoffeeScript-を参考に一番単純なCakefileを書いてみました。
sys = require 'sys'

sys.puts 'Heloi, word.'

するとなぜかエラー。
sys.puts〜を削除してもエラー。

ここでようやく、エラーメッセージを確認するわけですが、
path.existsSync is deprecated. It is now called `fs.existsSync`.

sys.js:1
throw new Error(
      ^
Error: The "sys" module is now called "util".
    at sys.js:1:69
    at NativeModule.compile (node.js:585:5)
    at Function.require (node.js:553:18)
    at Function._load (module.js:297:25)
    at Module.require (module.js:362:17)
    at require (module.js:378:17)
    at Object. (/Users/kyama/xxx/xxx/.../xxx/Cakefile:4:9)
    at Object. (/Users/kyama/xxx/xxx/.../xxx/Cakefile:8:4)
    at Module._compile (module.js:449:26)
    at Object.run (/Users/kyama/.node/v0.7.9/lib/node_modules/coffee-script/lib/coffee-script/coffee-script.js:79:25)
とのこと。

おや?
どうやら6行目のメッセージによると "sys" は "util" に変わっているようです。

ということで、書き直して↓
util = require 'util'

util.puts 'Heloi, word.'

結果は↓
path.existsSync is deprecated. It is now called `fs.existsSync`.
Heloi, word.
Cakefile defines the following tasks:
    

結局 sys を util に変更することで事なきを得たという実にくだらないお話でした。
これで自分の環境が原因だったら更にくだらない…

2012年5月1日火曜日

SBJsonでの自作クラスJSON化

最近色々動けていなかった鬱憤を晴らすかのように2本目です。

何の因果か、ここのところiOSの開発もできるようにならないといけなくてお勉強したりしているわけですが、ちょっとライブラリを使うときにハマったので、軽くがっつりメモしておきます。

iOSでJSON文字列を生成する

google先生によると、どうやらiOSでJSONを使う場合、SBJsonというライブラリを使うのが一般的な様子。
昔はJson.frameworkと呼ばれていたようですが、いまはSBJsonとなっているそうです。

で、2012/05/01現在、SBJsonの最新バージョンは3.1になっていました。
トップページのAPI DocumentationにはVersion 3.1(Alpha)と書かれていますが、githubを見てみるとひと月前くらいにアップデートされているみたいですね。
ちなみに3.0と3.1の差異はARC対応しているかどうかだそうです→http://d.hatena.ne.jp/paraches/20120115/1326650073

ひとまずgithubからバージョン3.1のzipを落としてきて展開します。


インストールの方法はいくつかあるらしいのですが、他でも紹介されているようにソース一式をプロジェクトに追加しました。


これで準備は完了したので、後はコードを書いていきます。

必要なところで#import "SBJson.h"すれば、すぐにパーサが使えるようになるようです。
文字列をオブジェクトに変換するクラスはSBJsonParserで、このクラスのobjectWithStringなどを使うといい感じに変換してくれます。

んで、例えば↓
 [
  {
     "name":"google",
     "url":"www.google.com"
   },
   {
     "name":"yahoo",
     "url":"www.yahoo.com"
   }
 ]
のようなJSON文字列をパースしてオブジェクト化する場合のコードが↓↓
    SBJsonParser *parser = [[SBJsonParser alloc] init];
    NSError *error = nil;
    // jsonStrにJSON文字列が入ってます
    NSArray *resultList = [parser objectWithString:jsonStr error:&error];
    if ( error ) {
        NSLog(@"parse error: %@", jsonStr);
    } else {
        NSLog(@"%@", resultList);
    }
です。

これを実行してみると、
 (
    {
        name = google;
        url = "www.google.com";
    },
    {
        name = yahoo;
        url = "www.yahoo.com";
    }
 )
という感じの出力が得られるはずです。

逆に、配列などをJSONにしたい場合はSBJsonWriterを使います。
例えば、
    SBJsonWriter *writer = [[SBJsonWriter alloc] init];
    NSMutableDictionary *dstDict = [NSMutableDictionary dictionaryWithCapacity:100];
    [dstDict setObject:[NSNumber numberWithDouble:123.27] forKey:@"latitude"];
    [dstDict setObject:[NSNumber numberWithDouble:74.027] forKey:@"longitude"];
    [dstDict setObject:[NSNumber numberWithDouble:0.0001] forKey:@"accuracy"];
    error = nil;
    jsonStr = [writer stringWithObject:dstDict error:&error];
    if ( error ) {
        NSLog(@"parse error: %@", dstDict);
    } else {
        NSLog(@"%@", jsonStr);
    }
のようなコードを実行すると、
{"longitude":74.027000000000001,"latitude":123.27,"accuracy":0.0001}
という文字列を返してくれます。

自作クラスをSBJsonWriterに引数として直接渡す

前フリが長かったですが、ここからが本題です。
SBJsonWriterを使ってJSON文字列を作成する場合、stringWithObjectを使うことになります。
このとき、引数として渡すオブジェクトはなんでもいいのですが、基本的にはNSArrayかNSDictionaryしか渡すことができません。
自作クラスのオブジェクトも渡せますが、普通に渡すとエラーが返ってきます。
しかしどうにかして自作クラスを直接渡したい。

ということで軽くソースを眺めてみると、SBJsonStreamWriter.hの41行目以降に書いてありました。
 If you have a custom class that you want to create a JSON representation for you can implement this method in your class. It should return a representation of your object defined in terms of objects that can be translated into JSON. For example, a Person object might implement it like this: 
 @code
 - (id)proxyForJson {
        return [NSDictionary dictionaryWithObjectsAndKeys:
        name, @"name",
        phone, @"phone",
        email, @"email",
        nil];
 }
 @endcode
ということで、proxyForJsonメソッドを実装すれば良いそうです。

で、実際に実装してみた結果が以下。

MyClassSample.h
@interface MyClassSample : NSObject

@property (nonatomic, strong) NSString *name;
@property (nonatomic) uint age;

- (id)proxyForJson;  // SBJsonを使用して任意のオブジェクトをjsonにする場合,このメソッドを実装する必要がある
@end
MyClassSample.m
#import "MyClassSample.h"

@implementation MyClassSample

@synthesize name;
@synthesize age;

- (id) proxyForJson {
    return [NSDictionary dictionaryWithObjectsAndKeys:
            name, @"name",
            [NSNumber numberWithUnsignedInt:age], @"age", 
            nil];
}

@end
呼び出し側
    MyClassSample *obj1 = [[MyClassSample alloc] init];
    obj1.name = @"name1";
    obj1.age = 21;
    
    error = nil;
    jsonStr = [writer stringWithObject:obj1 error:&error];
    if ( error ) {
        NSLog(@"parse error: %@", obj1);
    } else {
        NSLog(@"%@", jsonStr);
    }
実行結果
{"age":21,"name":"name1"}

ということで、無事に自作クラスをJSON化できました。
ちなみに、自作クラスをNSDictionaryに追加してもちゃんと動作して、
呼び出し側
    MyClassSample *obj1 = [[MyClassSample alloc] init];
    MyClassSample *obj2 = [[MyClassSample alloc] init];
    obj1.name = @"name1";
    obj1.age = 21;
    obj2.name = @"name2";
    obj2.age = 42;
    NSDictionary *userMap = [NSDictionary dictionaryWithObjectsAndKeys:
                             obj1, @"user1", 
                             obj2, @"user2", 
                             nil];
    
    error = nil;
    jsonStr = [writer stringWithObject:userMap error:&error];
    if ( error ) {
        NSLog(@"parse error: %@", userMap);
    } else {
        NSLog(@"%@", jsonStr);
    }
実行結果
{"user2":{"age":42,"name":"name2"},"user1":{"age":21,"name":"name1"}}

という感じになり、こちらも無事にJSON文字列を取ってくることができました。

2012年4月7日土曜日

Macでのlibjpegとかlibpngとか

凄まじくハマったので、忘れないように(AND 追加の問題発生時の対応用に)メモ。
試行錯誤しながらやったので、細かい部分は曖昧です。

(2012/07/25追記)
下記の内容をまとめました→(続・Macでのlibjpegとかlibpngとか
お急ぎの方ははまとめをご覧下さい。


何をしようとしたか

そもそもの発端は、前回までの続きとしてミクさんをプログラム的に呼び出す方法を調べていたことでした。
んで、工学ナビさんが急募してたのでMacでGLMetaseqを使ってみたとか、「ARToolKitで初音ミク」をやってみようといったエントリを参考に、環境構築をしていたわけです。
最初は順調だったんですが、工学ナビさんが急募してたのでMacでGLMetaseqを使ってみた(続き)に書かれているpng対応などを追加したあたりから雲行きが怪しく…。

最初作っていた環境はMacports経由で色々インストールしていたので、状況は全く同じはずだったんですが、なぜか実行時に"symbol not found"などと怒られ、一切実行できなくなってしまいました。

libjpeg.dylibとかlibpng.dylibのあるディレクトリにはパス通してました*1し、原因が一切思いつかないので、とりあえず最近流行りらしいし、パッケージ管理をMacportsからhomebrewに変えようと思い、一式アンインストールして入れなおすという暴挙に。

続く迷走

暴挙に出た結果としては、そもそもコンパイルすら通らなくなる有様*2…。
この辺からよく分からなくなって、brewがインストールするときに張るシンボリックリンクをImageIO.frameworkの下にいるlibjpeg.dylibとかに張り替えるとか、挙句OSのクリーンインストールまでやる始末。
また、OpenCVの中でlibjpegとか呼んでるのが悪いんじゃないかと考えて、ImageIO.frameworkの配下にいるライブラリを叩くように修正しようかと、訳のわからないことをやろうとしたりで、大迷走。

ライブラリの読み込み順

たださすがにOpenCV自体をいじるのはコスト的に美味しくないので、どうにかならないかと調べていたら、以下のエントリがまさに答えを示していました。

MacPorts のために DYLD_LIBRARY_PATH を使ってはいけない理由

曰く、
Macではランタイムライブラリの検索順序について、「man 1 dyld」 で確認することができます。
曰く、以下の順序で検索されます。
1. DYLD_LIBRARY_PATH
If it still can’t find the library, it then searches DYLD_FALLBACK_FRAMEWORK_PATH and DYLD_FALLBACK_LIBRARY_PATH in turn.
2. DYLD_FALLBACK_FRAMEWORK_PATH
By default, it is set to /Library/Frameworks:/Network/Library/Frameworks:/System/Library/Frameworks
3. DYLD_FALLBACK_LIBRARY_PATH
By default, it is set to $(HOME)/lib:/usr/local/lib:/lib:/usr/lib.
とのこと。

デフォルト状態ではDYLD_LIBRARY_PATHは設定されていないので、IDEなどで明示的に設定しない場合のライブラリ検索順序は、

  1. /Library/Frameworks:/Network/Library/Frameworks:/System/Library/Frameworks
  2. $(HOME)/lib:/usr/local/lib:/lib:/usr/lib

となるはず。
Macportsを使っていたときは、/opt/local/libの下にライブラリ一式がいたので意味がなかったのですけど、homebrewは/usr/local/libにライブラリ一式を追加してくれてます。

…ということで、これまで自力でライブラリパスを通していたのが実は裏目に出ていたようです。
これで、libjpegまわりのエラーはなくなりました。

で、libpngについてですが、homebrewの管理から外れているということは承知の上で、brew search libpngを実行したところ、こんなメッセージが。
Apple distributes libpng with OS X, you can find it in /usr/X11/lib. However not all build scripts look here, so you may need to call ENV.x11 in your formula's install function.
…おや?
そう、なにもサードパーティのlibpngを入れるまでもなく、最初から入ってたんですね。
もちろんヘッダファイルも/usr/X11/includeにしっかりいました。

で、/usr/X11/libはどこにもパス指定されていないので、コンパイル時には指定しないとダメなはずですが、今回はNetBeansがよしなに計らってくれているようで*3、うまいことできてました。
自分のために、ライブラリパスを明示的に設定しない場合と設定した場合に実行されたコマンドを貼っておきます。


  • 設定しない場合(うまく実行できる)
gcc     -framework GLUT -framework OpenGL -L/usr/X11/lib -o dist/Debug/GNU-MacOSX/glmetaseq_test build/Debug/GNU-MacOSX/_ext/2091976640/GLMetaseq.o build/Debug/GNU-MacOSX/_ext/2091976640/main.o -ljpeg -lpng
  • 設定した場合(実行できない)
gcc     -framework GLUT -framework OpenGL -L/usr/X11/lib -o dist/Debug/GNU-MacOSX/glmetaseq_test build/Debug/GNU-MacOSX/_ext/2091976640/GLMetaseq.o build/Debug/GNU-MacOSX/_ext/2091976640/main.o -L/usr/X11/lib -ljpeg -lpng
オブジェクトファイルの後ろで-Lオプションつけると何が変わるんでしたっけ…?


(2012/4/8追記)
上記/usr/X11/libへのパスですが、自分で強引に設定していたのを忘れていました…。
プロジェクトのプロパティー→構築→リンカーとたどって、普通は「追加のライブラリディレクトリ」としてパスを設定すると思いますが、今回は「追加のオプション」に -L/usr/X11/lib を追加することでうまくいっていました。(=明示的に設定している)
ただ、やっぱりオブジェクトファイルのあとで-Lオプションつけるのと何が違うのか、さっぱりです。

…動いたからよしとしましょう。

結論

今回の結論としては、

  1. デフォルトで検索されるライブラリパスはいじらないほうが吉
  2. いじる必要がある場合、他のものに出る影響を最小化するために、DYLD_FALLBACK_LIBRARY_PATHへ追加する

といったところでしょうか。
本来ならもっとスマートに解決できそうに思いますが、どうもこのへんが限界です

先のエントリの結論にも書かれてますが、こういうのは「既存ソフトウェアに影響があるので、新規ライブラリ (ports で入れたライブラリ等) はデフォルトライブラリの後で読み込むようにしましょう。」この一言につきますね。



…しかしOpenCVと組み合わせたらまた問題が出そうな気がしますね、コレ。

  • *1:これがそもそもの間違い
  • *2:こっちもシンボル見つからない系のエラーを吐いてた
  • *3:こういう姿勢がもう色々とダメ