RubyKaigi2017 速報!! (2日目)

ちょっと遅くなりましたが、2日目の速報をドラゴンズファンの西岡(@nisshiee)からお送りします!

広島カープさん、優勝おめでとうございます。でも僕は心からドラゴンズを愛しているので、ハイタッチは頑なに拒否していましたすみません。 2日目はドラゴンズ愛を表現するためにドラゴンズのユニフォームでRubyKaigiに出席しました(会場に向かって歩いてるとき、やたら視線を受けていた気がします)。

f:id:nisshiee:20170920091040j:plain

さて、今日は「Ran」会場で、Workshopが開催されたのでこちらをレポートしようと思います。

PyCall Lecture

まずは弊社R&Dグループより@mrknより、PyCallのワークショップを開きました。 ワークショップの内容はこちらにJupyter notebookで公開されていますので、ワークショップを見逃した方や復習したい方はぜひ。

f:id:nisshiee:20170920091548j:plain

PyCallはRubyプロセス内にPythonをbindingし、RubyコードからPythonのオブジェクトを操作できるようにするライブラリです。 ワークショップでは、実際にPyCallでPythonオブジェクトを操作しながらPyCallの仕組みを学び、最後にPythonで使われているデータサイエンスや機械学習のライブラリをRubyから使ってみました。

「PythonにはC APIがあるので、これをRubyからbindingしてやれば、RubyのコードからPythonを動かせる」とは言っても、Rubyでコーディングする「楽しさ」や「気持ちよさ」を損なうことなく、かつ実用に耐えうる言語間連携を実現するためには、大小様々な課題があったはずです。本ワークショップでは、そのような課題をどうやって解決してきたか、その一部を見ることができました。(しかし、あれは氷山の一角で、実際にはもっとたくさんいろんな苦労や工夫があるんだろうなぁ・・・)

ところで、このハンズオンでは「何を」やっていたの?

途中でirisデータなるものを使ってごにょごにょやっていた箇所がありました。もしみなさんが機械学習などの分野の知識や経験を既にお持ちであれば、あの手順で何をやっていたか把握できたかと思うのですが、そうでなければ、「確かにPython動いてそうだけど、何やってるかわからん」と思われたかもしれません。そこで、本記事で簡単に解説をしたいと思います。

「iris」は日本語で「アヤメ」のことです。そしてやりたいことは、アヤメの花を観測して、品種を当てることです。

今回使用したデータは、150の、既に品種がわかっている個体について、「花びらの長さ」「花びらの幅」など4箇所を事前に測ったデータになります。このデータを学習させることで識別モデルを作り、「品種が未知の個体も、同じ箇所を測って数値を識別モデルに投入すれば、計算機が品種を判定してくれるよ!」という状況を作りたいわけです。

今回はデータが予め用意されているけども・・・

もし実用の場面で、識別器をゼロから(データ集めから)作ろうと思ったら以下のような課題があります。

  1. どこを測れば、品種判定に有用なデータとなるかわからない(あなたが植物学者でない限り)
    • 特に伝統的な機械学習の手法では、結局のところ「どこを測るか」が最も精度に影響する部分だったりします
  2. 実際に、品種がわかってるアヤメの個体をたくさんあつめて1つずつ測ってデータを取るのは大変
  3. 通常、実用の世界ではもっと多くのデータを扱うので、「試しに学習させて識別モデルをつくってみる」のに数時間から数日といった長い計算時間がかかる

そこでまずは1の課題を解決したいのですが、2、3の事情があるので、「実際に学習させてみて精度をみてみる」というやり方は非効率的です。ですので、簡易的に「この計測ポイントは有用か」を判定できると嬉しいということになります。

そして、よく行われる「簡易的な判定」の手法が、「主成分分析(PCA)を行って、データの分布を目視してみる」という方法です。

PCAして、目視?

例えば今回のデータのように、4箇所の長さを計測したとすると、各々の個体について4つの数値が得られます。これを並べると4次元ベクトル(特徴ベクトルと呼びます)ができます。つまり、150の個体を観測すると、150の点が4次元座標空間(特徴空間)内に分布することになります。

f:id:nisshiee:20170920093248p:plain

特徴ベクトルが、左の図のように、同じ品種のものが近くに固まり、品種間で離れているような分布をしている場合、識別の精度が高くなります。逆に右の図のように、違う品種であっても分布が重なっているような場合は、品種を判定するのに必要な特徴を抽出できていないと言うことができます。

さて、上の図は模式的に4次元空間を表現しましたが、実際には4次元空間を紙やディスプレイに表示することはできません。そこで、「4次元空間上での分布の様子を極力維持したまま2次元に次元削減する」ことによって擬似的に4次元空間での分布の様子を目視できるようにしてやります。この手法が「主成分分析」と呼ばれる手法、ということになるわけです。

ワークショップのnotebookに戻って

というわけで、ワークショップでは、

  • 「アヤメの花の特定の部位の長さを計測して、アヤメの品種を特定する」ということをやりたいのだけど、その事前検証として、「本当にこの4箇所を測れば品種を特定できそうか」を、PCAで2次元に落として目視してやることによって確認する

ということをやっていたのです!

f:id:nisshiee:20170920091829p:plain

そしてこちらの結果をみると、色分けした3品種がほぼ重なることなく分布していますね。なので、今回の例では、「どうやら計測する箇所はこの4箇所で問題無さそうだ」ということが解って、めでたしめでたし、という結果になりました!

Getting started to Red Data Tools project

さて、PyCallによって、RubyからPythonオブジェクトを操作することができるようになったのですが、Pythonの肩に乗ってRubyでデータ分析を行うためにはもう一つ課題があります。それがデータ変換のコストです。

PyCallではRubyのFloatやArrayといったオブジェクトをPythonに持っていくときにPythonのfloatやlistに暗黙的に変換してくれますが、データが巨大になればその変換コストは膨大なものになります。この問題はRuby-Python間だけで起こっている問題ではなく、他言語間であったり、言語は同じでも複数のライブラリを連携させる場合にも発生します。

そこでこの課題に対する解決策として「そもそも言語やライブラリを超えても同じメモリ空間を参照し、そこに共通のフォーマットでデータを置けばいいじゃん」という案が提唱されています。そしてその仕様を定義しているのがApatch Arrowです。

ワークショップでは弊社エンジニアの畑中(@hatappi)より、Arrowの説明をし、実際にPythonプロセスとRubyプロセスの間で、データをJSON形式で受け渡しした場合と、Arrow形式で受け渡しした場合とで、速度比較を行いました。

f:id:nisshiee:20170920091748j:plain

実用のためにはまだまだ作らなければならないものがたくさんあるというのが現状のようですが、「だからこそみんなで作っていこうよ」という須藤さん(@ktou)のメッセージとともにワークショップの締めとなりました。Red Data Toolsのポリシーはぜひ一度読んでいただきたいです。

さいごに

というわけで、RubyKaigi2017も残り1日となってしまいました。
ラストは天野(@pataiji)よりお送りします!お楽しみに!