stMind

about Tech, Computer vision and Machine learning

MacとLinuxでディレクトリ内ファイルリストを取得する時の挙動が違う?

以前作ったDeep Learningを使ったブランドロゴ認識だけど、ありがたいことに使ってくれる方がいて、githubにissueが来ました。

github.com

27クラスのロゴ画像をそれぞれ学習用、テスト用に分けてpickle化するスクリプトでエラーになるということらしい。Issueにあがってるエラーログを見ると、Macで実行したときと、ファイルリストを取得した結果が違っている。OSXで実行した時は、各ロゴのtestとtrainが交互で、かつソートされているので、パスのリストであるtrain_test_dirsっていう変数から、train_test_dirs[0::2]でtestのリストだけをpickleにして、train_test_dirs[1::2]でtrainのリストだけをpickleにするような処理をしていた。要は各フォルダがtest→trainという順番になっていることを想定していた。(フォルダパスをリストにするだけなのに、実際のフォルダ構成を調べて処理しなくてもよいのだけど)

train_datasets = maybe_pickle(train_test_dirs[1::2])  # trainをpickle化
test_datasets = maybe_pickle(train_test_dirs[0::2])  # testをpickle化

OSXでのリストはこんな感じ。

Adidas/test
Adidas/train
Apple/test
Apple/train
BMW/test
BMW/train
(以下略)

一方で、どのDistributionかはわからないけど、Linuxで実行したらしき結果はこんな感じ。

Texaco/train
Texaco/test
Starbucks/train
Starbucks/test
Mini/train
Mini/test
(以下略)

ソートされてないし、trainとtestの順序が逆になっている。とりあえず、リストをスライスするときに、最初がtrainで次がtestになるように、

train_datasets = maybe_pickle(train_test_dirs[0::2])  # 最初(0)がtrain
test_datasets = maybe_pickle(train_test_dirs[1::2])  # 次(1)がtest

と変更してもらったら、エラーは出なくなったようだ。ちなみに、centosだとエラーだったけど、debianにしたら動いた、という方もいた。

結局

StackOverflowに回答あるみたいだけど、MacLinuxというか、FileSystemによって順番は違っていて、順番を固定した処理がしたければos.listdirでリストを取得した後に明示的にソートしておくということか。stackoverflow.com

研究を売れ

研究を売れ!―ソニーコンピュータサイエンス研究所のしたたかな技術経営

研究を売れ!―ソニーコンピュータサイエンス研究所のしたたかな技術経営

ソニーコンピュータサイエンス研究所(CSL)の研究成果を実用化する研究営業組織、テクノロジープロモーションオフィス(TPO)の設立、活動内容とその手法に関する本です。

企業における研究開発の理想

企業に所属する研究者、開発者の立場から見て、研究開発の理想形とは何かと考えると、一つには次のような流れではないだろうか。

  1. 研究者の思いに基づいて研究が始まる
  2. トップカンファレンスに採択されるなど、研究が外部で認められる
  3. 社内の事業部に移管され、製品やサービスに実装される
  4. 製品やサービスが公開され、広く世の中で使われる

例えば、Jamie Shottonさん達のRandom Forestを使った姿勢推定の研究が、CVPR2010のベストペーパーになって、ゲームデバイスとして発売、2013年のデータですが全世界で2400万台も出荷されたKinect。改めて思うに、こういう研究が出来れば言うことないですね!

現実、そして研究営業を行うTPO

しかし、現実にはこんな風にうまくいく研究開発はなかなかない。書籍によると、研究から具体的な商品に結びついた成功事例は1万件に1件くらいじゃないかということなんで、ほとんどがうまくいかない!というのは実感としてわかるなぁと思うところです。実際、研究を事業にする際には、研究をしている部隊ごと事業部門に移管したり、研究している技術だけを移管したりすることが一般的に行われますが、いずれの場合でも移管をいかに効果的に行うかが課題となっていて、そこで、CSLの研究成果を実用に結びつけるための研究営業をメインに行う組織であるTPOが設立されたそうです。

試行錯誤と教訓

書籍では、実際の研究営業のやり方について、様々な事例を通して語られています。

  • 他の企業とのコラボ
  • 外部の人に使ってもらう
  • 社内の他部門との繋がりを大事にする
  • スピンアウトして事業をする会社を立ち上げる
  • 出張デモ
  • デモを実際に見てくれた人にだけ送るメルマガ

これらを読んでみると、よく言われている技術移管のための取り組みを愚直に実践しているのだなというのがわかりましたし、王道はないというのもその通りだなと思いました。結局、地道に続けていくしかないんですよね。こういった取り組みを繰り返し行なって環境など様々な条件が揃った時、書籍内の言葉で言うと時間と空間を超えて実用化に適したタイミングにハマった時に、CybercodeやPOBoxなどの成功事例が出て来るのだと思います。著者の方が、この研究営業を10年続けて得られた教訓、ぜひ書籍を見て内容を把握してほしいですが、項目だけ引用しておきます。

  • 全ては研究を出すタイミングにかかっている
  • 必要なコネはなんでも使え
  • 組織に対する先入観をもってはいけない
  • 顧客に対しては、ほぼ伝らない、という前提で努力すべし
  • メンタルを鍛えろ
  • 前例のないやり方を試せ
  • 一分一秒でも早く動くべし
  • 技術を移管した後も追い続けるべし
  • 単なる研究営業ではなく、研究プロデュースを目指すべし
  • 常に研究所のための営業であることを自覚せよ

さいごに

CSLほどの基礎研究ではないですが、応用研究に近い立場で長く仕事をしている身として、どういう考えで、どのフェーズに貢献すべきかというのは常に思っているところだったので、そのものズバリな書籍で非常に参考になりました。繰り返しになりますが、自分の思いとしては、KinectのJamie Shottonのように研究を立ち上げて、それを論文にして、さらに製品化にも関わって、という最初から最後まで中心で関わるというのが理想ではあるんですけどね。自分一人ではなく、チームでこれを目指せばいいよなと、読み終えた後に感じることが出来たので、これから少しずつ行動していきたいですね。

Habits change into character

休暇中ということもあり、2017年がふわっとスタートしたわけですが、一年の計は元旦にありの教えに従って今年の抱負を記しておきたいと思います。(既に元旦ではなくなってますが、それはおいておきます)

「身につけた習慣が個性になる」

タイトルを意訳すると、このような意味になるでしょうか。ローマの詩人Ovidの言葉だそうです。iOSアプリのDayoneを立ち上げた時に起動画面上に表示されていて、良いフレーズだなと思ったのでメモっておいたのでした。新年の抱負といえば今年にやりたいことを書くことが多いですが、少し抽象化して身につけたい習慣について書いてみようと思います。

ネイティブ英語を毎日聞く

英語論文を読んだり、英語ブログを読むことは苦もなく出来るようになりましたが、リスニングに関してはまだまだです。話している単語は所々で聞き取れるものの、内容が即座に理解できないことが多いです。ただ、英語字幕を見ながらであれば理解できるので、目から入力された英語に対する神経回路網は十分な量のデータで学習されていると思われます。また、字幕ありで約2ヶ月ほど毎日英語を聞いていた状態では、字幕なしの英語が理解できるようになっていたので、耳から入力された英語に対する脳の学習はできつつあったのだと思います。休暇に入って聞かなくなったら、元に戻ってしまいましたが...

英語字幕ありでの学習を習慣化して、リスニング脳を十分に学習させ、今年は英語リスニングを身につけたいと思います。Courseraでコースを取って聞くのが一石二鳥でいいかな。ビデオに字幕もついてるし(所々間違っているけど)、1つが10分前後で長さ的にもちょうどいい感じだし。

※英語ライティングも合わせてやっていきたいが、目と耳が鍛えられたら比較的楽に出来るのでは?とも思っていたり。

運動後のストレッチを怠らない

Runkeeperで記録をつけ始めてから約3年、合計の走破距離が1500キロ(1年で500キロ、1月で40キロちょっと、毎週10キロ程度)を超えるところまで来て、主にランニングですが運動をする習慣はほぼ身についていると思います。結果として、フルコートでサッカーをした時に、20代の若者についていけるくらいの体力は維持できているかなという実感があります。一方で、今まで経験したことのないような体の痛みを感じて、しかもそれが長引くということがあって、特に膝や肩などの関節で多く発生して、それが原因でランニングがしたくても出来ない状態がしばらく続くことになってしまいました。

今までは運動をする方ばかりを意識していましたが、今年は運動と運動後のケアはセットであるという意識付けをして、運動後にはストレッチを怠らないようにしたいと思います。運動を生涯継続するためには、ケアが大事!(それを実感した2016年の膝の痛みでした)

Deep Learningを自分の中に体系化する

https://www.quora.com/Is-deep-learning-overhypedwww.quora.com

Deep Learningや人工知能に関する話題は、毎日twitterに何十件も流れてきて、特にここ最近はarXivに論文が発表されると同時にgithubに実装が公開されるなど、進化のスピードがめちゃくちゃ速くて、ついていくのも大変です。とはいえ、Deep Learningが出来ていないタスクはたくさんあって、今後何年かかけて更に進化していくことになると思いますし、Computer Visionを仕事にしている以上、避けては通れないことも確か。そのためにも、情報に触れた時に、自分の中で整理・体系化していくことを習慣づけしていきたいと思います。単なる趣味として、githubにあるコードを動かしてみたり、Tensorflowなどのフレームワークを使って自分で作ってみたりなども、引き続きやっていこうとも思っています。ゼロから作るディープラーニングは、体系化するための基礎を、手を動かしながら理解するのに良さそうです。

Tensorflowでロゴ画像を分類する

UdacityのDeep LearningコースでTensorflowを試してみたものの、いまいちしっくりこない感じがありました。こういうのは、自分で何かしら作って試してみるのが一番ということで、ブランドロゴ画像の分類をしてみました。

なお、ここで書いたコードは

GitHub - satojkovic/DeepLogo: A brand logo recognition system using deep convolutional neural networks.

にあります。python3系ならば動くと思います。scipy、scikit-learn、Pillow(PIL)、numpyあたりを使ってますので、必要に応じてインストールしてください。

タスクとデータセット

データセットflikcr_logos_27_datasetを使います。AdidasAppleBMWなどなどの27種類のロゴ分類タスクです。

f:id:satojkovic:20160821151857p:plain

ロゴ識別CNN

今回作るCNNは、ナンバープレート認識をTensorflowでやってるブログを大いに参考にしました。発想としては単純で、ロゴ画像って文字や数字、模様から出来ていて、一方でナンバープレートは数字と文字で構成されていて、特徴として非常に似ているので、CNNのネットワーク構成がそのまま使えるかなと思った、とそれだけです。 違うのは、ナンバープレートはグレースケールなのに対して、ロゴ画像は色も特徴の一つになりそうなので、カラー画像で3チャンネルの入力になるところと、画像サイズが64 x 32になっているところです。 オリジナルのネットワーク図を書き換えると、次のような構成。

f:id:satojkovic:20160821161807p:plain

コードとしては、train_deep_logo_cnn.pyとtest_deep_logo_cnn.pyにあるmodelが該当するところです。重みとバイアス項は、mainの所で記述してmodelメソッドに渡しています。

def model(data, w_conv1, b_conv1, w_conv2, b_conv2, w_conv3, b_conv3, w_fc1,
          b_fc1, w_fc2, b_fc2):
    # First layer
    h_conv1 = tf.nn.relu(
        tf.nn.conv2d(
            data, w_conv1, [1, 1, 1, 1], padding='SAME') + b_conv1)
    h_pool1 = tf.nn.max_pool(
        h_conv1, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')

    # Second layer
    h_conv2 = tf.nn.relu(
        tf.nn.conv2d(
            h_pool1, w_conv2, [1, 1, 1, 1], padding='SAME') + b_conv2)
    h_pool2 = tf.nn.max_pool(
        h_conv2, ksize=[1, 1, 2, 1], strides=[1, 1, 2, 1], padding='SAME')

    # Third layer
    h_conv3 = tf.nn.relu(
        tf.nn.conv2d(
            h_pool2, w_conv3, [1, 1, 1, 1], padding='SAME') + b_conv3)
    h_pool3 = tf.nn.max_pool(
        h_conv3, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')

    # Fully connected layer
    conv_layer_flat = tf.reshape(h_pool3, [-1, 16 * 4 * 128])
    h_fc1 = tf.nn.relu(tf.matmul(conv_layer_flat, w_fc1) + b_fc1)

    # Output layer
    out = tf.matmul(h_fc1, w_fc2) + b_fc2

    return out

学習画像の生成

学習画像は、データセットアノテーションファイルを使ってロゴ部分だけを切り出し(crop)、切り出した画像についてデータオーグメンテーション(シフト、回転、拡大縮小)を適用して、全体で21万枚程度に増やしました。27クラスあるので、クラス毎に8000枚くらいになる計算ですね。実際には、結構偏りがありますが。

その後、train75%、test25%の割合にして、フォルダに画像を分けるようにしています。ここまでを、crop_and_aug.pyで実行します。

def main():
    annot_train = np.loadtxt(os.path.join(TRAIN_DIR, ANNOT_FILE), dtype='a')
    print('train_annotation: %d, %d ' % (annot_train.shape))

    # cropping and data augmentation
    crop_and_aug(annot_train)

    # train_test_split
    do_train_test_split()

さらに加えて、Tensorflowを使ってCNNを学習するためのデータ形式にするのに、gen_train_valid_test.pyを使ってpickleファイルをクラス毎に生成しています。ここまでやって、CNNを学習する準備が完了になります。学習画像の例(回転、シフトしているのが分かりにくいな...)。

f:id:satojkovic:20160821172356j:plain

学習とロゴ分類テスト

学習はtrain_deep_logo_cnn.pyで実行します。大体、3000ステップくらいでロスが小さくなって、学習が収束しているようです。学習データに対するAccuracyは90%、テストデータに対するAccuracyもあまり変わらず89%程度になっていました。また、学習が終わったモデルでテストしてみると、だいたい正しく分類してくれているようです。

$ python test_deep_logo_cnn.py 
Test image: flickr_logos_27_dataset/flickr_logos_27_dataset_cropped_augmented_images/Google/test/272645705_Google_6_2_r-13.jpg
Model restored
Class name: Google

Test image: flickr_logos_27_dataset/flickr_logos_27_dataset_cropped_augmented_images/Nbc/test/3570522135_Nbc_6_2_r0.jpg
Model restored
Class name: Nbc

Test image: flickr_logos_27_dataset/flickr_logos_27_dataset_cropped_augmented_images/Mini/test/2792546855_Mini_2_2_p-1-1.jpg
Model restored
Class name: Mini

まとめ

独自データセットで実際にTensorflowを使ってみることで、かなり理解が進みました。Tensorflow自体は使い方を知ってみれば難しくはなく、それよりもデータをどのように準備すればいいのかを決めて、データを準備するところがあまり面白くはないのですが、頑張る必要がありますね。

また、今回は参考になりそうなブログを見つけて、ほぼそのままのネットワーク構成を使いましたが、最初はあまり複雑なネットワーク構成を独自に作ったりせずに、シンプルな既存モデルから始めるのがアプローチとしては良いのかなと思いました。

matlabでは行列を行ベクトルにするとcolumn major order

3x3の行列Aを9x1の行ベクトルに直すと、1, 2, 3, 4, 5, 6, 7, 8, 9となると思っていたら、1, 4, 7, 2, 5, 8, 3, 6, 9だった... (column major order)

>> A

A =

     1     2     3
     4     5     6
     7     8     9

>> A(:)

ans =

     1
     4
     7
     2
     5
     8
     3
     6
     9

>> 

ちなみに、numpyだと指定しない限り、row major orderになる。

In [15]: A
Out[15]: 
matrix([[1, 2, 3],
        [4, 5, 6],
        [7, 8, 9]])

In [16]: np.ravel(A)
Out[16]: array([1, 2, 3, 4, 5, 6, 7, 8, 9])

In [17]: np.ravel(A, order='F')
Out[17]: array([1, 4, 7, 2, 5, 8, 3, 6, 9])

アーセナルの攻撃スタイルにみるUnix哲学

バーディー、結局残留ですってね。

www.soccer-king.jp

アーセナルに来たら、相手も引いて守るし、スペースがない中でバーディーは活躍できないんじゃないかなんて言われてましたが、 僕は十分フィットするなぁと思ってました。というよりも、バーディーのようなタイプのストライカーがちょうどはまるスタイルが 強いアーセナルの時の攻め方だと思います。

どういうことか? 昨年のユナイテッド戦の動画を見てもらうとすごくわかりやすい。1分22秒くらいから始まる二点目のシーンです。


HIGHLIGHTS ● BPL ► Arsenal 3 vs 0 Manchester United - 4 Oct 2015 | English Commentary

ベンゲルが作り上げたアーセナルらしい攻撃というのは、最も少ないパス交換で縦に速く動いてゴールを奪うシンプルさにこそあるのだと思うのです。 相手からのロングボールを跳ね返して、サンティ・カソルラがボールを拾った位置がハーフラインよりも自陣寄り。そこから、アレクシスへの縦パス、アレクシスからエジルへの落とし、そしてエジルからウォルコットへのスルーパスの合計3本でゴール前まで侵入しています。最後は、エジルがゴールへ流し込んで仕上げとなったのですが、その間わずか10秒ほど。 こういう攻撃ができている時はチーム状態がものすごくいいなぁと思えるし、実際この時はもう一点追加して勝ちを収めました。 複雑なパスではなく、ゴール直結の縦に速いパス交換を選手同士が連動しながら行ってゴールを奪う、まさに一つ一つの目的直結のコマンドをパイプで組み合わせて大きな目的を達成するUNIXそのものではないですか。(凄いこじつけ感)

確かに、引いて守る相手に対して、これでもかとパスを回してゴールを決めるスタイルも素晴らしくはありますが、アーセナルには合ってないんじゃないかなぁ。バーディー獲得は幻と消えてしまいましたが、そういうストライカーを是非獲得してほしいなぁと思った次第です。

How AlphaGo WorksとAlphaGoの裏側

www.slideshare.net

DeepMindがNatureに投稿した論文を、CMUのPhDの方が解説しているプレゼン資料がslideshareにありました。
AlphaGoの仕組みがとても分かりやすくまとめてあり、英語ですが一読の価値ありです。
スライドのアウトラインを部分的に日本語で書き出してみました。

まずはコンピュータ囲碁AIの定義

  • 碁盤を行列で表現
  • 1(黒)/ -1(白)/ 0(碁石なし)
  • d手目の碁盤の状態sが与えられた時に、最適なアクションaを選ぶ

実現方法

  • あらゆる碁盤の状態をどうやってシミュレートする?
  • d手目の全aについて、ゲームが終了となるまでシミュレーションして勝ちor負けを観測
  • 全シミュレーションで最も勝ち数が多いaを選択
  • これは不可能
  • 可能な碁盤の状態は、宇宙の原子数よりも多いと言われている

探索空間を絞り込むことがポイント

  • アクションaの候補を絞り込む = 幅削減
    • Policy Network
  • アクションaの良さを評価(位置の評価) = 深さ削減
    • Value Network
    • 最後までシミュレートしない
    • v(s): 碁盤の状態sの時の評価

アクションaの候補の絞り込み

  • P(a|s)を学習
  • プロ棋士の打ち方を学習(教師あり学習)
    • 5段から9段のプロ棋士
    • 対局数160K、30Mの棋譜データ
  • 13層のCNNで実現
    • 碁盤の状態sが与えられた時のaの確率P(a|s)
  • 自己対戦で強化学習

碁盤の状態の評価

  • CNNにレグレッション層を追加
  • 1に近いほど良い、0に近いほど悪い

Monte Carlo Search Tree

  • Selection
    • アクションaの候補絞り込み(Policy Network)
    • Shallow Networkを使ってP(a|s)の高速化(Rollout)
  • Expansion
  • Evaluation
    • 碁盤の状態評価(Value Network)
  • Backup

Results

  • Rollout + Policy Network + Value Networkでプロ5段くらいと予想される

スライドには図面があって、それを見て英語の解説を読むとまた理解は深まると思います。