pythonによる機械学習の最前線
TRANSCRIPT
Pythonによる機械学習の最前線
2016/2/4 ソフトウェアジャパン
ビッグデータ活用実務フォーラム
シルバーエッグ・テクノロジー(株) 加藤公一
自己紹介
加藤公一(かとうきみかず) シルバーエッグ・テクノロジー(株)
博士(情報理工学) (修士は数理科学)
Twitter: @hamukazu 機械学習歴・Python歴ともに3年 今の仕事: 機械学習に関する研究開発
特にレコメンデーション(自動推薦)システム、自然言語処理、画像処理など 過去の仕事: データ分析ツールの開発、3次元CADの開発、幾何計算のアルゴリズム設計、偏微分方程式のソルバなど
Pythonで使える 機械学習・データ分析のツール
• 汎用数値計算、科学技術計算:Numpy, Scipy
• 機械学習:scikit-learn
• 自然言語処理:nltk
• データ分析:pandas
• データ可視化:matplotlib
• 統合分析環境:jupyter-notebook
Pythonで使える ディープラーニングのライブラリ
• Pylearn2
• Caffe
• TensorFlow
• Chainer
Scikit-learn + matplotlib 分類 クラスタリング
回帰
機械学習アルゴリズムの適用と結果の可視化をとても便利にできる
絵はすべてscikit-learnホームページ(http://scikit-learn.org)より
matplotlib + scikit-learn入門にお薦め データサイエンティスト養成講座機械学習入門編
第2部特集2「Pythonによる機械学習入門」
可視化応用編
• さらにインタラクティブな可視化をしたいとき – 例えば…
• クリックした部分だけ拡大したい
• マウスオーバーすると詳細情報を表示したい
• そういうときはPython+JavaScriptが便利
• Pythonでアプリケーションサーバを立ち上げるのは簡単 – Bottle、Flaskなどの軽量フレームワーク
– サーバと連携してのJavaScriptでの可視化
• ウェブアプリの仕組みはデータ分析にも有用
などなど…
• 便利なツールとその使い方を挙げていくときりがありません
• これ以降は、ライブラリを使ってというより、フルスクラッチからアルゴリズムを書きたい人を対象の話
今日のターゲット
• 機械学習のアルゴリズムをゴリゴリ書きたい人
• (機械学習とは限らない)数値計算、アルゴリズムなどの分野で、他の言語で実装していて苦労している人
つまり、Pythonを使うべきなのに使ってない人がいるのでは?
スクリプト言語とは
「アプリケーションソフトウェアを作成するための簡易的なプログラミング言語の一種を指す」 -- Wikipedia Perl, Ruby, Pythonなど 特徴: • 短い行数で(少ないタイプ数で)書ける
– つまり生産性が高い – 初心者が学習しやすい
• インタプリタ型である • 実行速度が遅い
注意:Pythonは汎用言語です!
数学的用途以外にも使えます。
• ウェブアプリ作ったり
• ゲーム作ったり
• ツイッターのボット作ったり
• ラズベリーパイからLED光らせたり
もできます。
でも今日はその話はしません。
数値計算・数学的アルゴリズムでPythonを使うべき理由
• ライブラリが充実
• 結果の可視化が便利
• (うまくコードを書くと)速い⇨以降この話
数値計算、アルゴリズム系の人、
「Pythonは遅いからイヤ」と思ってる人が多いのでは?
Pythonでやってはいけないこと
s = 0
for i in range(1, 100000001):
s += i
print(s)
1から1億までの和を計算する
これはPython的な書き方ではない
改善例
s = sum(range(1, 100000001))
print(s)
1から1億を返すイテレータを用意し、その和を計算する
Numpyを使う
import numpy as np
a = np.arange(1, 100000001, dtype=np.int64)
print(a.sum())
1から1億が入った配列を用意し、その和を計算する
ベンチマーク
s = 0
for i in range(1, 100000001):
s += i
print(s)
s = sum(range(1, 100000001))
print(s)
30.21秒
12.33秒
0.38秒
import numpy as np
a = np.arange(1, 100000001, dtype=np.int64)
print(a.sum())
問題点(?)
• Numpy版は1~100000000が入った配列をあらかじめ用意している
• つまりメモリが無駄
• メモリにデータを入れるコストも無駄
⇨Pythonistaはそんなこと気にしない!
ここまでのまとめ
• Pythonの数値計算系ライブラリはC言語等で書かれているので速い
• できるだけ計算はライブラリに任せたほうがいい
• ライブラリとのやり取りを大量にするより、一度ライブラリに仕事を投げたらしばらく返ってこないくらいの処理がよい – Numpyには高速化のための仕組みがたくさんある(indexing, slicing, broadcasting, etc…)
• そのためにメモリ量やメモリコピーコストがかかっても気にしない
でもそれができないときがある
• ライブラリ内ではなく、Python側で条件分岐が大量に必要になる場合
• どうしてもfor文(while文)で細かい処理をたくさん回さなければいけないとき
• 例えば探索系アルゴリズム、組み合わせ最適化など
そんなときに…
Cython • PythonをベースにしたC言語のジェネレータ
• Pythonで書いたものをそのまま速くすることができる
• ちょっと手を入れることでさらに速く
ベンチマーク例
def prime(n): p = [True] * (n + 1) m = 2 while m < n + 1: if p[m]: i = m * 2 while i < n + 1: p[i] = False i += m m += 1 i = n while not p[i]: i -= 1 return i
n以下の最大の素数を返す関数 (エラトステネスのふるい)
通常のPython版:4.75秒 Cython化版:3.04秒
prime(10000000)を計算
(コードには手を入れず)
def prime(int n): cdef int i, m p = [True] * (n + 1) m = 2 while m < n + 1: if p[m]: i = m * 2 while i < n + 1: p[i] = False i += m m += 1 i = n while not p[i]: i -= 1 return i
def prime(n): p = [True] * (n + 1) m = 2 while m < n + 1: if p[m]: i = m * 2 while i < n + 1: p[i] = False i += m m += 1 i = n while not p[i]: i -= 1 return i
型宣言をいれる
3.04秒 0.41秒
def prime(int n): cdef int m, i cdef int * p = <int * >malloc((n + 1) * sizeof(int)) for i in range(n + 1): p[i] = 1 m = 2 while m < n + 1: if p[m]: i = m * 2 while i < n + 1: p[i] = 0 i += m m += 1 i = n while not p[i]: i -= 1 free(p) return i
0.41秒 0.17秒
リスト(配列)についてもC言語風の型宣言と動的割当て
FAQ
これって、最初からC言語で書いたほうが早くないですか?
Answer
• 確かに最初から最終形がわかっていればC言語で書いたほうが早いかもしれないです。
• しかし、とりあえずPythonで書いて動作を確
認し、それから徐々に高速化するというのにはCythonは便利です。
まとめ
• Pythonには数値計算、機械学習、データ分析に便利なライブラリがそろっている
• Pythonはうまくつかうとかなり速い
–できるだけ仕事はまとめてライブラリに任せる
–それができないときはCythonを使う
– Cythonならではの工夫(型宣言)などが必要