備忘録 blog

Docker/Machine Learning/Linux

Python2を高速化するtips(続)

sharply.hatenablog.com

これの続き。

単純に高速なアルゴリズムを使う

例えば"ham"という文字列がある配列に含まれるか?という問いに対して、

some_list = ["spam", "ham", "eggs"]
if "ham" in some_list

というリスト検索ではO(log(n))ですが、RubyにおけるHashと同様のものがPythonでも辞書(Dictionaly)として提供されており、

some_dict = {"spam":1, "ham":1, "eggs":1}
if "apple" in some_dict

とすればO(1)になります。もちろんこれが使えるのには条件がありますが、これで数秒程度早くなりました。

並列計算する

python律速となっているのはだいたいfor文であり、このfor文の実行回数をいかに減らせるか、ということがポイントとなります。 並列計算には、スレッド並列化(メモリを共有する)とプロセス並列化(メモリを共有しない)の2種類があります。しかしCPythonの実装ではGIL(Global Interpreter Lock)というものがあるので、プロセス並列化ぐらいしかできません。

GILとは、並列実行したときに安全でないコード(例えばグローバル変数を書き換えるような、スレッドセーフでないコード:しばしばCのモジュールに存在する)を実行しないようにするために、そのコードを他のスレッドで呼ばれないようにする排他ロックのことで、pythonrubyといったインタプリタ言語では一般に1つのプロセスに対して1つのGILが存在する。

GILがない実装としてJPython(JAVAによる実装)やIronPython、PypyのSTM版があげられますが、ここでは措きます。

CPythonでプロセス並列化によって高速化するには、for文の区間を分割して部分和を並列で計算し、あとでその総和をとるという手段が用いられます。しかしCのopenMPのように動的にfor文の処理をスレッドに割り当てるといったことは標準では用意されていないので、自分で実装するなりする必要があります。

qiita.com

Boost.pythonを使う

結局pythonで計算させるには限界があるので、C++で書いたコードをコンパイルしたものを共有ライブラリとしてpython側から呼び出す実装にしてみましょう。

#define BOOST_PYTHON_STATIC_LIB
#include <boost/python.hpp>

static void image_putpixel(image &i, const boost::python::tuple &x, const boost::python::tuple &y){
  double point[2] = {boost::python::extract<double>(x[0]), boost::python::extract<double>(x[1])};
  uchar color[3] = {boost::python::extract<uchar>(y[0]), boost::python::extract<uchar>(y[1]),boost::python::extract<uchar>(y[2])};
  i.putpixel(point, color);
}

BOOST_PYTHON_MODULE(brush)
{
    using namespace boost::python;

    class_<image>("image")
        .def("show", &image::show)
        .def("brush", &image_brush)
        .def("putpixel", &image_putpixel)
        .def("load", &image::load)
        .def("get", &image::get);
}

上記でわかるように、C++のクラスをpythonのクラスにみなせたり、pythonのtupleを引数としてとるような関数を定義することができます。

コンパイルオプションは例えばUnix環境ではこんな感じ。

g++ -std=c++11 -O2 -I`python -c 'from distutils.sysconfig import *; print get_python_inc()'` -DPIC -fPIC -shared -o brush.so src/brush.cpp -lboost_python

-Iにインクルードパスを指定したいのですが、そのパスが異なるコンピュータ上でも共通に実行できるように、``でpythonを実行するコードを囲うことでそれをシェル上で評価した結果が返ってきます。

python側からは、soファイルを同じディレクトリに置いてファイル名でimportすればOKです。さらに、openMPで実装したC++のコードをpython側から呼び出すこともでき、さらに速度が上がる可能性もあります。

光学設計者の学習メモ: Boost.pythonでOpenMP

APIサーバーが必要となった時のために

自前で実装する

サーバー側にけっこう大きなロジックが必要となる場合。この場合は、単なるRESTなリソースを提供するだけでなく、返り値のロジックが必要となるので、結局自分で全部書いたほうがラクになるということになる。HerokuやOpenShiftといったPaaSに立てることとなる。

Ruby on Railsの場合

qiita.com

Grapeというのがやりやすいらしい。

github.com

Pusherを使う

APIにしてスマホのネイティブアプリを作るのならばともかく、ブラウザでアクセスしてもよいということにして、かつWebSocket的なことがやりたいのであれば、Rails5を待つかコレを使う。

Pusher | Leader In Realtime Technologies

例えば、クライアントはpythonでも書ける。

github.com

Golangの場合

作ろうとするAPIがRESTfulなものでなくてよいなら、むしろこの程度シンプルなもののほうが作りやすいかもしれない。こっちのほうが当然ながら早い。

aial.shiroyagi.co.jp

qiita.com

BaaSサーバーの候補

サーバーは単にデータストア程度でよいとするならば、BaaSサーバーを使うという手がある。2015/10現在で試用が期限なし無料のサービスを列挙してみた。

国産

無料だとpush数が少ないのが劣る点。 www.appiaries.com

海外産

  • Parse

実質最大手。 www.parse.com

  • Quickbox

quickblox.com

変わり種

  • Mongolab

mongodbがクラウドで扱えるらしい。

mongolab.com

参考

iphone-dev.g.hatena.ne.jp

qiita.com

Python2のコードを高速化するための覚書

実行時間の測定方法

CPythonでpythonの素のコードを実行するとヤバイぐらいに時間がかかる。実際にどのぐらいかかるのかを調べる。

import time
def main():
  start = time.time()
  hoge()
  elapsed_time = time.time() - start

まあこれでもよいのだが、

python -m cProfile -c totaltime hoge.py

以上を実行すれば、それぞれの関数呼び出しの回数と、totalの実行時間が明らかになる。明らかになったところで、律速段階となっている関数の高速化に取り組みたいと思う。

高速化手法

numbaでjitを使う

from numba.decorators import jit

@jit
def hogehoge():

@jitをつけるだけでllvmjitしてくれる。あまり早くならなかった。

Numba — Numba

numpy.vectorizeを使う

numpy.vectorizeは配列を引数に取って配列として返す関数を作るものである。ここで、対象となる関数は引数が複数あってもよく、それぞれの引数についてベクトルを渡せばそれぞれの値に対して処理された結果が帰ってくるし、スカラーを渡せばそれはどのベクトルに対しても同じ値が引数として呼ばれる。

import numpy as np

def hogehoge(t, anchor):
    return "hogehoge"

def main()
    vhogehoge = np.vectorize(hogehoge, excluded=['anchor'])
    mlist = list(vhogehoge(np.arange(0.0, 1.01, 0.01), anchor=anchor))

引数のexcludedでanchorを除外することで、引数に配列を渡したいときにはその配列が分解されずにその関数に渡すことができる。 一方で、渡したいarray of arrayとなっている場合、引数に渡した配列excludedされては"array of array"のまま渡されるか、さもなければ1つのcellごと渡されることになるので、二次元配列を一次元分だけ渡すということはできない。

pypyを使う

これが現時点では最も効果が得られた。 pypyは、CPythonではないpythonの処理系の実装であり、JITコンパイルを適宜行って実行速度の改善が図られている。但しpypyではCPythonのCバインディングのところや、ライブラリの対応がまだ中途半端ということらしいが少なくとも、python2~3の互換性よりはpypyの方がスムーズに移行できた。つまり、コードの書き換えをほとんど必要としないということである。 実行するときは、公式サイトからダウンロードしたバイナリファイル(bin/pypy)をpythonの代わりに実行すればよい。 これを用いると、あるプログラムで11倍ほど高速化された。

pypy.org

Boost.Pythonを使う

これはpythonの範疇からはみ出してしまうが、C++でコードを書き、それをpythonでラッパーとして呼び出して実行する方法としてBoost.Pythonがある。 これについてはまだ研究中であり、ここでの詳述は避けたい。

http://alpha.osdn.jp/devel/boost.python_ja.pdf

Bootstrapの導入時に発生するエラーと解決法

ActionController::RoutingError (No route matches [GET] "/fonts/glyphicons-halflings-regular.woff")

Ruby on Rails4の開発で/vender/assets/stylesheets/によそからもってきたbootstrap.cssを入れているとき、上記のエラーが発生することがある。 その場合、フォントを/vendor/assets/fontsに置き、config/application.rbに

config.assets.paths << "#{Rails}/vendor/assets/fonts"

を挿入する必要があるが、もう1点しなければならないことがあり、それは/app/assets/stylesheets/custom.css.scssなどではなく、/vender/assets/stylesheets/bootstrap.cssを改変することである。

@font-face {
font-family: 'Glyphicons Halflings';
src: url("../assets/glyphicons-halflings-regular.eot");
src: url("../assets/glyphicons-halflings-regular.eot?#iefix") format("embedded-opentype"), url("../assets/glyphicons-halflings-regular.woff2") format("woff2"), url("../assets/glyphicons-halflings-regular.woff") format("woff"), url(     "../assets/glyphicons-halflings-regular.ttf") format("truetype"), url("../assets/glyphicons-halflings-regular.svg#glyphicons_halflingsregular") format("svg");
1215 }

上記に書き換えたところ、うまく動いた。

Note

webdesign.tutsplus.com

POH6をPythonで解く

動機

最近、学科内でPythonがブームとなっているようなので便乗して勉強してみた。 ただ勉強するだけでは面白くないので、オンラインハッカソンに挑戦して実際に書きながら学んでみたいと思う。

paiza.jp

コード

paiza.jp

input_lines = int(raw_input())
water = 0.0
powder = 0.0

for i in xrange(input_lines):
  s = raw_input().rstrip().split(' ')
  if s[0] == '1' :
    water += int(s[1])
  elif s[0] == '2' :
    powder += int(s[1])
  else :
    total = water+powder
    water -= int(s[1])*water/total
    powder -= int(s[1])*powder/total

print int(100*powder/(water+powder))

Firefoxを布教する

FirefoxJavascript

Firefoxでは、Shift + F4を押すことで、スクラッチパッドと呼ばれる画面を開くことができます。そこでjavascriptのコードを手軽に実行することができます。

javascriptとは、主にブラウザ上で実行されるプログラミング言語で、動的なウェブサイトを作る際などに用いられる。javaとは全く違う言語なので注意。

では試しに、このスクラッチパッドに

alert('Hello, world!')

と打ち込んで、Ctrl + R を押してみましょう。すると、ブラウザの画面に"Hello World!"がポップアップして表示されるはずです。

f:id:sharply:20150818181735j:plain

参考ページ

www.mozilla.org

articles.softonic.jp

Slackを布教する

Slackとは

IT系は一般にチームワークで仕事をしますが、その際に必要なのはコミュニケーションツールです。もちろん直接のオーラルコミュニケーションも大切ですが、非同期型の方法で文字に残る形でのやりとりもしたいはずです。

そんなとき、lineやFacebookのグループチャット機能を使えばいいじゃないか、と思うかもしれません。しかし誤って投稿を公開してしまったり、セキュリティの面での懸念があったりしますから、それ専用のツールを使うのが望ましいです。ここで紹介するSlackというツールは、ちょっと面白い出自のツールです。

f:id:sharply:20150818182008p:plain

このツールを作ったのはflickrという画像共有サービスを作ったスチュワート・バターフィールドらのチームです。彼らはもともとオンラインゲームを作ろ うとしていましたが、そのゲームは利用者が少なく、サービスは終了してしまいます。しかし転んでもただでは起きなかった彼は、ゲーム制作で使っていた社内 用のチャットツールを商品化したところ評判を呼び、多くの利用者を獲得するようになりました。

実際の開発現場で使われていたツールだったということもあり、使いやすく美しいUI、そして他サービスとの豊富な連携機能が特徴です。

参考ページ

blog.nanapi.co.jp

slack.com

JAVA/Scala/Web Framework

Twitterとの連携

Twitter4J - コード例

Play Framework

JavaGuide4

qiita.com

Login Inplements

hirahiro56.hatenablog.com

akiomik.hatenablog.jp

tkawachi.github.io

(Ruby on Railsの場合) ruby-rails.hatenadiary.com

Client Side Ruby

docs.voltframework.com

「資本主義と自由」読書会

「資本主義と自由」読書会

資本主義と自由 (日経BPクラシックス)

資本主義と自由 (日経BPクラシックス)

ミルトン・フリードマンの「資本主義と自由」の読書会を、大学3年生5人(法学部3人、教養学部1人、私)で行った。

序章・第一章・第二章を主な範疇とし、レジュメを読みながら各々が興味を持った事柄について話し、それについて意見交換した。

忘れないうちに、そこで得られた知見をまとめておこうと思う。以下に述べることは、読書会における議論からの借用がほとんどである。この場を借りて諸氏に謝辞を述べたい。

「資本主義と自由」への評価

この本は厳密に論証される部分と感覚で書かれている部分が混在しており、特にもともとフリードマンは政策論が専門であるから、第一章のような政治論は抽象的で、その部分における論理の飛躍や不整合はそれなりに許容すべきものだろう。しかしながらその政策論の各論という面でも、必ずしもそれらをすべて首肯できるわけではない。

今この本を読みなおす意義とは何か、という問題提起がたびたびなされたが、自由主義者の思考回路を理解するには適しているだろうが、あくまでここで述べられる政策論は理想に過ぎない。私はこの本はもはや、「プロテスタンティズムの倫理と資本主義の精神」や「共産党宣言」といった古典的名著と同様の扱いをすればよいのではないかと思う。

また他に、この本が前提としている完全自由競争が真に実現されうるのかという点は疑問視されており、情報の非対称性、既得権益云々によってそれが実現できないのであれば、そもそもこれらの議論が成り立たないのではないかという批判があった。

リバタリアンの盲点

自由主義がすべての国家で適応できるかというと、最貧国がいきなり関税撤廃したとして成長できるかというと、そうではない。幼稚産業育成論は世界中の多くの国で実践され、ある程度成果をあげてきた。

アメリカは確かに自由の国だが、独立当時のアメリカがすでに「持てる国」であったことが自由の基盤として大きな役割を果たしていたに違いない。

一方でヨーロッパ諸国ではカルテルを許す資本主義体制であったことは、自由主義の側面には反しているかもしれないが紛れもなく資本主義の一形態であり、持たざる国ヨーロッパの生き延びる手段であったのかもしれない。

新自由主義は成熟した先進国においてのみ可能なのであって、社会の発達は開発独裁によって十分に産業が育ってから、漸進的な自由化という過程を経てなされるのである。

今後の展望

興味深かったのは、「日本は最も成功した社会主義国である」という言説で知られるように日本の高度経済成長は政府主導の統制的な経済支配によってなされたということが言われていたが、最近の研究では実はそうでもなかったことが明らかになっているということである。

城山三郎官僚たちの夏」で描かれたような、経産官僚が積極的に支援して力を注いだ産業(たとえば鉄鋼業)が必ずしも日本の基幹産業となっているわけではなく、自動車産業といった自由競争に委ねられた産業が日本を支えていることがその証左である。

こういった視点を提供してくれるのは、ローゼンブルースの『日本政治の大転換: 「鉄とコメの同盟」から日本型自由主義へ』だそうだ。これも機会があれば読んでみたい。