Sapporo20140709
Upcoming SlideShare
Loading in...5
×
 

Like this? Share it with your network

Share

Sapporo20140709

on

  • 2,682 views

2014/7/9 Python札幌・ミニ勉強会

2014/7/9 Python札幌・ミニ勉強会
の資料です。

Remark.jsを使ってます。ソースコードはこちら: https://github.com/hamukazu/sapporo20140709

Statistics

Views

Total Views
2,682
Views on SlideShare
2,563
Embed Views
119

Actions

Likes
7
Downloads
7
Comments
0

3 Embeds 119

https://twitter.com 113
http://s.deeeki.com 4
http://www.slideee.com 2

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

Sapporo20140709 Presentation Transcript

  • 1. Numpy/Scipyを使った効率の良い 数値計算 加藤公一 2014/7/9 Python札幌・ミニ勉強会 1 / 32
  • 2. 自己紹介 加藤公一(きみかず) Twitter : @hamukazu シルバーエッグ・テクノロジー(株)チーフサイエンティスト 博士(情報理工学) レコメンドのアルゴリズムを考える仕事をしてます。 岩見沢市出身です。 Pythonを本格的に使い出したのは1年半前くらいです。(ビルドツールのwafは前か ら使ってた) 数学科出身、今まで数値解析、数理最適化などに関わる仕事をしてきました。 C, C++, Haskell, Scalaなどの経験あり。 2 / 32
  • 3. 所属会社 シルバーエッグ・テクノロジー株式会社 大手ショッピングサイトにレコメンドシステムを提供している会社です。また、レ コメンドの技術を利用した広告サービスもやっています。 3 / 32
  • 4. 告知 PyCon JP 2014 (9/12-15) のトークセッションで講演します。 (英語セッション) 今日の話はその縮小版です。 (9月に話す資料が今できているはずがない) まだわからないことも多いので、ご指摘お待ちしております。 (「もっといいやりかたあるよ」とか) 4 / 32
  • 5. 目次 イントロダクション(数値計算について) Numpy/Scipyについて 疎行列について ケーススタディ(機械学習でよく出てくるやつ) お詫び:資料作る時間があまりなかったので、ほとんど絵がないです。必要に応じて ホワイトボード等で解説します。 (SlideShareで見てる人ごめんなさい) 5 / 32
  • 6. 数値計算(数値解析) 常微分方程式、偏微分方程式、各種シミュレーション、機械学習、etc. 今日は主に行列計算の話 6 / 32
  • 7. 個人的なPython体験 最初:遅い! 使ってるうちに:遅すぎる! 慣れてくると:自分のコードが悪いんじゃね? さらに慣れると:そんなにおそくないじゃん(←いまここ) 7 / 32
  • 8. 数値計算のための プログラミング言語 FORTRAN, C 速い 最適化が効く コード書くのが大変 デバッグも大変 Python 生産性高い しかし遅い でもそんなに遅くない 8 / 32
  • 9. Pythonで数値計算をする メリット 生産性が高い デバッグのしやすさ 便利なライブラリ群 可視化が(もし必要ならば)楽 各種ウェブフレームワーク グラフの作成(matplotlib) 9 / 32
  • 10. リスト vs 配列(Numpy) 0から999999の和を計算してみる a=range(1000000) printsum(a) importnumpyasnp a=np.arange(1000000) printa.sum() ベンチマーク: >>>fromtimeitimporttimeit >>>timeit('sum(range(1000000))','fromnumpyimportarange',number=100) 1.927393913269043 >>>timeit('arange(1000000).sum()','fromnumpyimportarange',number=100) 0.10005307197570801 10 / 32
  • 11. 明示的なループは 避けるべき s=0 foriinrange(1000000): s+=i prints これは論外!(常識?) とてつもなく遅い。 11 / 32
  • 12. ブロードキャスティング importnumpyasnp a=np.array([1,2,3]) printa*2#=>[2,4,6] printnp.sin(a*np.pi/2)#=>[1,0,-1](だだし多少の誤差あり) printa>=2#=>[False,True,True] このsinのように、配列に適用すると各要素に作用させることができる関数はユニバ ーサル関数と呼ばれる。 12 / 32
  • 13. 要素ごとの積と行列積 >>>a=np.array([[1,2,3],[4,5,6],[7,8,9]]) >>>b=np.array([[1,0,0],[0,1,0],[0,0,1]]) >>>a*b array([[1,0,0], [0,5,0], [0,0,9]]) >>>np.dot(a,b) array([[1,2,3], [4,5,6], [7,8,9]]) 13 / 32
  • 14. ブロードキャスティング (2次元) >>>a=np.arange(12).reshape(3,4) >>>b=np.array([1,2,3,4]) >>>a array([[0, 1, 2, 3], [4, 5, 6, 7], [8, 9,10,11]]) >>>a*b array([[0, 2, 6,12], [4,10,18,28], [8,18,30,44]]) 14 / 32
  • 15. インデキシング 配列の[]の中身が配列等(シーケンス)だと、複数の要素を同時に取り出す。 例: >>>a=array([2,3,5,7]) >>>i=array([1,3]) >>>a[i] array([3,7]) 2次元の場合: >>>a=arange(9).reshape(3,3) >>>a array([[0,1,2], [3,4,5], [6,7,8]]) >>>i=array([0,1,1]) >>>j=array([0,1,2]) >>>a[i,j] array([0,4,5]) 15 / 32
  • 16. ブロードキャスティング、 インデキシングについて... もっとキモい複雑な使い方はNumpy Medkit参照 16 / 32
  • 17. 疎行列とは ほとんどの値がゼロである行列。 非ゼロ要素の値とインデックスを保持することで、メモリ消費、計算量ともに 少なくすることができる。 要素とインデックスの持ち方で、様々なデータ形式がある。 17 / 32
  • 18. numpy.sparse 主に3つの疎行列型 :lil_matrix, csr_matrx, csc_matrix(他にもあるが今日は忘れよ う) lil_matrix: 値を詰めるのに便利、実際の計算はcsr_matrixやcsc_matrixに変換し てから行う importscipy.sparseassparse a=sparse.lil_matrix((100,100)) a[0,0]=1.0 a[2,0]=2.0 a[0,5]=5.0 x=a.tocsr() #xに関する計算 csr_matrix: 行を取り出すのは高速。csr_matrix同士の和や積は高速。 csc_matrix: 列を取り出すのは高速。csc_matrix同士の和や積は高速。 18 / 32
  • 19. 以下応用編 19 / 32
  • 20. ケース1 ノルムの計算 密な場合 v=np.array([1,2,3,4]) print(v**2).sum()#こうするより... printnp.dot(v,v)#こっちのほうが速い 疎な場合 a=sp.lil_matrix((100,100)) a[0,0]=1 a[0,10]=2 a[10,5]=3 a[50,50]=4 a=sp.csr_matrix(a) printa.multiply(a).sum()#フロベニウスノルム r=a.getrow(0)#0行目の疎ベクトル printr.multiply(r).sum()#疎ベクトルのノルム multiplyメソッド便利! 疎行列でdotメソッドは遅い。(転置行列をとるとCSR→CSC, CSC→CSRに変わってし まう) 20 / 32
  • 21. ケース2 シグモイド関数の作用 importnumpyasnp defsig_warn(a): return1/(1+np.exp(-a)) defsig(a): return1/(1+np.exp(np.where(a<-5e2,5e2,-a))) 実行結果: >>>x=np.array([-1e100,1,-10]) >>>sig_warn(x) sig.py:4:RuntimeWarning:overflowencounteredinexp return1/(1+np.exp(-a)) array([ 0.00000000e+00, 7.31058579e-01, 4.53978687e-05]) >>>sig(x) array([ 7.12457641e-218, 7.31058579e-001, 4.53978687e-005]) σ(x) = 1 1 + e −x 21 / 32
  • 22. 同値な計算: defsig(a): return[1/(1+np.exp(5e2ifx<-5e2else-x))forxina] (Warningを無視していいのなら問題はない?) 条件分岐させたいときにwhereは便利。 22 / 32
  • 23. ケース3 ユニバーサル関数の作用 配列の各要素に作用できるユニバーサル関数は便利。 でも、これは疎行列にはそのまま使えない。$x=0$のときに$f(x)=0$となる関数な ら、関数を作用させたあとも疎行列のはずである。 csr_matrixに作用させたいものとして話を進める。(csc_matrixの場合も同様) importnumpyasnp importscipy.sparseassp a=np.array([1,2,3]) b=sp.lil_matrix((100,100)) b[0,0]=1.0 b[1,1]=2.0 b[2,2]=3.0 b=b.toscr() printnp.tanh(a)#計算できる printnp.tanh(b)#エラーになる 23 / 32
  • 24. ではどうするか? scipy.sparseの内部型を直接いじる ここでもブロードキャスティングを利用 24 / 32
  • 25. csr_matrixの内部構造 内部構造:data, indices, indptrによって表現 i行目について、行列の要素の値はdata[indptr[i]]~data[indptr[i+1]-1]に格納さ れていて、非ゼロ要素のインデックス はindices[indptr[i]]~indices[indptr[i+1]-1]に格納されている。 25 / 32
  • 26. 例: >>>b=np.array([[1,0,2],[0,0,3],[4,5,6]]) >>>b array([[1,0,2], [0,0,3], [4,5,6]]) >>>a=sp.csr_matrix(b) >>>a.data array([1,2,3,4,5,6]) >>>a.indices array([0,2,2,0,1,2],dtype=int32) >>>a.indptr array([0,2,3,6],dtype=int32) 1行目の情報:data[0]~data[1], indices[0]~indices[1] 2行目の情報: data[2], indices[2] 3行目の情報:data[3]~data[5], indices[3]~indices[5] 26 / 32
  • 27. csc_matrixの内部構造 csr_matrixの行と列を逆にしただけ(詳細略) >>>b=np.array([[1,0,2],[0,0,3],[4,5,6]]) >>>b array([[1,0,2], [0,0,3], [4,5,6]]) >>>a=sp.csc_matrix(b) >>>a.data array([1,4,5,2,3,6]) >>>a.indices array([0,2,2,0,1,2],dtype=int32) >>>a.indptr array([0,2,3,6],dtype=int32) 27 / 32
  • 28. コンストラクタ 内部データ構造を元に疎行列を作れる csr_matrix((data,indices,indptr),[shape=(M,N)]) 28 / 32
  • 29. csr_matrixへの ユニバーサル関数の作用 indicesとindptrはそのままにしておいて、dataだけ変換すればいい。 先ほどのコンストラクタを利用し、ここで配列へのユニバーサル関数の作用を使 う。 29 / 32
  • 30. importnumpyasnp importscipy.sparseassp a=sp.lil_matrix((5,5)) a[0,0]=1.0 a[1,1]=2.0 a[2,2]=3.0 printa print"------" a=a.tocsr() b=sp.csr_matrix((np.tanh(a.data),a.indices,a.indptr), shape=a.shape) printb 実行結果: (0,0) 1.0 (1,1) 2.0 (2,2) 3.0 ----- (0,0) 0.761594155956 (1,1) 0.964027580076 (2,2) 0.995054753687 30 / 32
  • 31. まとめ for文は極力使わない(リスト内包表記も) scipy.sparseは積極的に使おう 疎行列型は、必要であれば内部表現をグリグリいじる 高速化の知識とあわせて、そこに持っていく数学的同値変形重要 ちょっと中途半端な気もしますが、詳細はPyCon JPで話します。 31 / 32
  • 32. 参考文献 Gabriele Lanaro, "Python High Performance Programming," Packt Publishing, 2013. Stéfan van der Walt, Numpy Medkit 神嶌敏弘「機械学習の Python との出会い」 32 / 32