さくらレンタルサーバーに、Python3.6と、numpy、scipy、scikit-learn、gensimなどのPythonモジュールをインストールした模様をレポートします。
これらのインストールの前に、必要なgcc、gfortranのインストールからレポートを始めます。
はじめに
機械学習の結果のCGIを動かす環境が必要になりました。Python3の、scikit-learn、gensimを使ったCGIです。
VPSを借りれば良いのでしょうが、とりあえずさくらレンタルサーバーでやってみようと。
gensimにはnumpy、scipyが必要。numpy、scipy、scikit-learnには代数演算ライブラリ(ATLASなどのBLAS, LAPACK)が必要。
そして代数演算ライブラリのビルドにはFortranが必要。
さくらレンタルサーバーにはgccはあるけどgfortranは入っていない。Python2.7は入っているけどPython3は入っていない。
ということでアップデートも兼ねてgccからインストールしよう!
後悔先に立たず。
良い子はマネしちゃダメ。
以下のレポートについて
本稿はさくらレンタルサーバーに特化した、FreeBSD、管理者権限なしでのインストールのレポートです。(Linuxだったり管理者権限があったりする場合はもっと簡単なことでしょう。)
FreeBSDへのLinux等のパッケージのビルドはPortsを利用するのが正統なようです。しかしレンタルサーバーにPortsは入っていないでしょうし、管理者権限もありません。
それでも以下のように必要なもののビルドは可能でした。しかし実行時に何かしらエラーはでるかもしれません。
もし追試しようと思われている方は、一度長文(5000文字超)を通し読みして頂いたほうがよろしいかと思います。その上で自己責任にてお願いします。
試行錯誤の連続でしたので、正確に記録していません。記述間違いはあると思いますので、各位の経験で補正してください。
パッケージ名は作業ディレクトリに残っているのを見ればわかるのですが、ダウンロードURLは記録していません。検索してお探しください。(ほぼGNUのサイトですが。)
そしてインストールするツールやモジュールのバージョンが異なると、このレポートとは異なるエラーも出ることでしょう。
また、ビルドはレンタルサーバーのCPUリソースが必要でしょうから、極力しないことをおすすめします。(自分のことは棚に上げて。)
事前準備
ユーザーディレクトリ直下にlocalを作成して、インストールは全てここにすることにします。作業用にtmpディレクトリも作ります。
また.cshrcもあらかじめ編集しておきます。
mkdir ~/local mkdir ~/tmp cp .cshrc .cshrc.bak vi .cshrc
set pathの最初に「$HOME/local/bin
」を追加し、以降に環境変数の設定を追加します。
set path = ($HOME/local/bin /sbin /bin /usr/sbin /usr/bin /usr/local/sbin /usr/local/bin $HOME/bin ) setenv PYTHON $HOME/local setenv PYTHONPATH $HOME/local/lib/python3.6/site-packages setenv C_INCLUDE_PATH $HOME/local/include setenv CPLUSE_INCLUDE_PATH $HOME/local/include setenv LIBRARY_PATH $HOME/local/lib setenv LD_LIBRARY_PATH $HOME/local/lib
上の記述は十分で無いかもしれませんが、この内容で以下のレポート内容は可能でした。
環境の変更を適応し、作業ディレクトリに移動します
source ~/.cshrc cd ~/tmp
以降、一つ一つのイントールが完了するたびに上を行い、直後からツールが使えるようにして作業ディレクトリにもどります。
これらの記述は、以降省略します。
慣れている方にとっては当たり前ですが、そうでない方はお忘れなく~。
GNUツールのビルドとインストール
まずはGNUのツールからインストールします。
gccに必要なツールのインストール
インストール方法は、凡そ以下です。
wget <URL> tar xf <パッケージのアーカイブ> cd <展開先> ./configure prefix=$HOME/local make make install
インストールしたパッケージは以下です。
- gmp-5.1.3.tar.xz
- mpfr-3.1.5.tar.xz
- mpc-1.0.2.tar.gz
- make-3.82.tar.gz
- binutils-2.29.tar.gz
gccのインストールに必須なのは最初の3つ。gmpは6系だとm4がないとかエラーがでました。
既存のmakeはFreeBSDのものなので、理解できない変数があるとエラーが出がち。GNU makeも入れてしまえ。しかし既存のmakeでビルドできるのは、ちょっと古い上のバージョン。(一回入れてしまえば、それで新しいのも入るかも。)
binutilsも入れておきます。
gccのインストール
パッケージはgcc-6.4.0.tar.gzです。
wgetしてtar xfの後から…
cd gcc-6.4.0 mkdir build cd build ../configure --prefix=$HOME/local --enable-languages=c,c++,fortran --disable-bootstrap CFLAGS="-I$HOME/local/include" CPPFLAGS="-I$HOME/local/include" CXXFLAGS="-I$HOME/local/include" LDFLAGS="-L$HOME/local/lib" CFLAGS_FOR_TARGET="-I$HOME/local/include" CPPFLAGS_FOR_TARGET="-I$HOME/local/include" CXXFLAGS_FOR_TARGET="-I$HOME/local/include" LDFLAGS_FOR_TARGET="-L$HOME/local/lib" make make install
4行のconfigure:
../configure --prefix=$HOME/local --enable-languages=c,c++,fortran --disable-bootstrap CFLAGS="-I$HOME/local/include" CPPFLAGS="-I$HOME/local/include" CXXFLAGS="-I$HOME/local/include" LDFLAGS="-L$HOME/local/lib" CFLAGS_FOR_TARGET="-I$HOME/local/include" CPPFLAGS_FOR_TARGET="-I$HOME/local/include" CXXFLAGS_FOR_TARGET="-I$HOME/local/include" LDFLAGS_FOR_TARGET="-L$HOME/local/lib"
ですが、~FLAGS_FOR_TARGET
も設定してあげないとエラーになりました。環境変数に適切に設定すれば必要ないのかもしれませんが、試行錯誤の結果がこの形です。
あと最初は--enable-languages
を指定していませんでしたが、javaのライブラリのビルドでエラーがでるので、fortranまでの指定にしました。
sourceの後、--version
を指定するなどして、gcc, gfortranが使えることを確認します。
Python3のインストールとCGIテスト
続いてPython3をインストールします。
Python3.6のインストール
Python-3.6.2.tgzのwget、tar xfの後から、
cd Python-3.6.2 ./configure --prefix=$HOME/local make make install
sourceの後にpython3とpip3が使えることを確認します。
以降pythonと打ってしまうと、/usr以下の2.7が動くのでご要注意を。
CGIのテスト環境の作成
次々章に書きますPythonモジュールのインストールにおいて、CGIの実行時ではじめてエラーがでる、という場合が多々ありました。
最初にCGIのテスト環境を作っておき、逐次CGIでの確認を行う方が効率良いです。
HTTPでアクセスできるそのテスト環境を「~/www/test
」とします。
mkdir ~/www/test chmod 755 ~/www/test
そして以下の2つのファイルを作成し、FTPなどでこのディレクトリにアップロードします。(さくらレンタルサーバーは拡張子が.cgiの場合は.htaccessはいらないかも。)
.htaccess
AddHandler cgi-script .cgi
test.cgi
#!/home/your-site/local/bin/python3 import os, sys, platform def import_check(name): print("") try: mod = __import__(name) if name=="numpy" or name=="scipy": print("%s config:" % name) mod.show_config() print("Success to import %s." % name) except: print(sys.exc_info()) print("Fail to import %s." % name) sys.exit(1) print("Content-type: text/plain") print("") print("Python %s" % platform.python_version()) modules = ["numpy", "scipy", "sklearn", "gensim", ] for mod in modules: import_check(mod) print("Success to import all.")
1行の「/home/your-site/
」はユーザーディレクトリです。各位の環境に読み替えて下さい。(以下同様)
そして少なくとも、この行の改行コードはLFでないと動きません。(CRLFでも後ろに記号を付けるという回避策があったかと思いますが忘れました。)
コンソールに戻りパーミッションを変えます。
chmod 755 ~/www/test/test.cgi ~/www/test/test.cgi
2行でtest.cgiを実行し、「Python 3.6.2
」のように表示されることを確認します。(numpyはまだインストールしていないのでFail。)
そしてブラウザからtest.cgiにアクセスし、同様に表示されれば成功です。
もし500エラーが出る場合は、各ファイルの内容、改行コード、パーミッションを確認してみてください。
Pythonモジュールのインストールの準備
Pythonモジュールのインストールの前に、幾つか準備が必要です。
numpy,scipy,scikit-learnが参照する代数演算ライブラリからインストールします。(ここからURLもメモしてあります。)
ATLASのインストール
代数演算ライブラリのATLASをLAPACK付きでインストールします。このビルドにFortranが必要です。
http://www.netlib.org/lapack/ からlapack-3.7.1.tgzを、https://sourceforge.net/projects/math-atlas/ からatlas.3.10.3.tar.bz2をダウンロードします。
wget http://www.netlib.org/lapack/lapack-3.7.1.tgz wget https://downloads.sourceforge.net/project/math-atlas/Stable/3.10.3/atlas3.10.3.tar.bz2 tar xf atlas3.10.3.tar.bz2 cd ATLAS mkdir build cd build ../configure -b 64 -C ic gcc -F ic -O3 -C if gfortran -F if -O3 --prefix=$HOME/local --shared --with-netlib-lapack-tarfile=$HOME/tmp/lapack-3.7.1.tgz make make install
7行のconfigure:
../configure -b 64 -C ic gcc -F ic -O3 -C if gfortran -F if -O3 --prefix=$HOME/local --shared --with-netlib-lapack-tarfile=$HOME/tmp/lapack-3.7.1.tgz
のオプションは、展開後ディレクトリのdoc/atlas_install.pdf
を参考にしました。
make install
でエラーが出ますが、dllとかdylibとか必要ない拡張子のファイルのコピーの失敗なので気にしないことにします。
ATLASの追加インストール
上のATLASでnumpyをインストールした時に、CGIにて「import numpy
」の実行時に「libtatlas.soが参照するlibgfortran.soが見つからないよ。再インストールし直せ
」というエラーが発生しました。(sshから叩くと発生しません。)
そこで以下のように、libtatlas.soをビルドし直したところ、CGIでのエラーは消えました。
cd ~/tmp/ATLAS/build cp -r lib xlib cd xlib gcc -fomit-frame-pointer -mfpmath=sse -O2 -fno-schedule-insns2 -mavx -m64 -fPIC -shared -o libtatlas.so -Wl,-rpath $HOME/local/lib -Wl,--whole-archive libptlapack.a libptf77blas.a libptcblas.a libatlas.a -Wl,--no-whole-archive -L$HOME/local/lib -lgfortran -lc -lpthread -lm –lgcc cp libtatlas.so ~/local/lib
4行のリンクのコマンドライン:
gcc -fomit-frame-pointer -mfpmath=sse -O2 -fno-schedule-insns2 -mavx -m64 -fPIC -shared -o libtatlas.so -Wl,-rpath $HOME/local/lib -Wl,--whole-archive libptlapack.a libptf77blas.a libptcblas.a libatlas.a -Wl,--no-whole-archive -L$HOME/local/lib -lgfortran -lc -lpthread -lm –lgcc
に関して、makeでは「-Wl, -rpath-link
」で$HOME/local/lib
を設定していましたが、上では「-Wl,-rpath
」にしています。-rpath-link
でもよいように思うのですがね。(今見るとスペースのせいでしょうか。makeではダブルクォーテーションがあり、このコマンドラインは失敗していました。)
もう一つのlibsatlas.soも一応リンクし直しておきます。
gcc -fomit-frame-pointer -mfpmath=sse -O2 -fno-schedule-insns2 -mavx -m64 -fPIC -shared -o libsatlas.so -Wl,-rpath $HOME/local/lib -Wl,--whole-archive liblapack.a libf77blas.a libcblas.a libatlas.a -Wl,--no-whole-archive -L$HOME/local/lib -lgfortran -lc -lpthread -lm -lgcc cp libsatlas.so ~/local/lib
CGIでの実行時にLD_LIBRARY_PATHが有効になるやり方があれば、この工程は必要ないのでしょう。
モジュールのエラー
Pythonモジュールを普通にインストールしたとき、sshから手で叩くと実行できるのにCGI経由だとエラーがでるケースがありました。
それらのエラーは、前節のATLASと同様「共有ライブラリ(so)からさらに共有ライブラリを呼ぶときに見つからない」というものです。
LD_LIBRARY_PATH
かDT_RUNPATH
の類の環境変数を設定すれば良いかと思いましたが、さくらレンタルサーバーのsuexec経由では.htaccessでのSetEnvが効きません。
sitecustomize.pyを作成して、そこで「import os; os.environ["LD_LIBRARY_PATH"] = "/home/your-site/local/lib"
」とかやってもエラーは消えませんでした。
シェルスクリプト等で環境変数を設定する踏台CGIを作るという手も考えられますが、その度に踏台を作るのも面倒です。
ここでの解決策は「rpathを指定してビルドする」という面倒なものです。もしライブラリパスが設定できる解決策がありましたら、そちらのほうが楽です。
(リンカ―のrpathオプションは、オブジェクトが共有ライブラリを探すときのパスをそのオブジェクト自身に書き込む、というものです。)
pip.confの作成
rpathの指定はpipのオプションで指定できます。たぶん以下のような感じ。(試していません。)
pip3 install numpy --global-option=build_ext --global-option=-R/home/your-site/local/lib
しかし今後、soを作るかもしれないモジュールをインストールする度にオプションを指定するのも面倒です。そしてきっと忘れますので、ここでpip.confを作っておきます。(もしpython2にもpipを入れていましたら、そちらのpipも同じpip.confを参照するかもしれませんのでご注意ください。)
mkdir ~/.pip vi ~/.pip/pip.conf
pip.confの内容は次の2行です。
[install] global-option = build_ext --rpath=/home/your-site/local/lib
setup.pyのbuild_extコマンド実行で--rpath
を指定しています。
(もしかしたら「global-option = build_ext --rpath=/home/your-site/local/lib:/usr/lib:/lib
」などのほうが良かったかもしれませんが、.cshrcのLD_LIBRARY_PATH
も前述の通りだからまいっか。パスの区切りがコロンで良いかは調べていません。)
参考:
- stackoverflow「python pip specify a library directory and an include directory」
- pip Reference Guide「Per-requirement Overrides」
- pip User Guide「Configlation」
補
前節のようにpip.confを設定すると、pipでのインストールの際に「global-optionが指定されているのでバイナリパッケージは使わないよ」というようなメッセージが表示されるようになります。
バイナリパッケージでインストールが当然のWindowsやMac(恐らくIntel上のメジャーなLinuxも)と違い、モジュールのインストールにえらく時間が掛かります。verboseにしない限りはバーが回るくらいですから、根気よく待ちましょう。
global-optionを指定しなかったとしても、FreeBSD9.1用のバイナリパッケージがある可能性はそう高くはないと思いますが。(もしnumpyのバイナリパッケージがあったなら、ビルド済代数演算ライブラリも同梱され、ATLASのインストールなど必要ないことでしょう。Windowsのように。)
そして次章に書きますようにpipでインストールできない場合はsetup.pyでもインストールしますから、distutils.cfgも設定した方が良いのかもしれません。(私はしていません)。
またPythonモジュールのみならず、~/local/lib
以下にインストールするライブラリをgccでビルドするときにも「LDFLAGS="-rpath $HOME/local/lib"
」を指定したほうが良いのでしょう。(.cshrcに書いておくべきか?そしてこれまでのライブラリは大丈夫なのか?)
Pythonモジュールのインストール
やっとPythonモジュールのインストールの準備が整いました。numpyからインストールします。
以降のコマンドラインの記述において、pip3コマンドではバージョンを指定せずに最新版をインストールしようとしています。
新しいバージョンではおまじないが必要でなかったり、pipで失敗することもないかもしれませんので、一度お試しください。
もしエラーが出る場合は「pip3 install numpy==1.13.3
」のように、記述のバージョンまで指定すると追試可能と思います。
蛇足ですが、以下のように(2017年末で)最新のパッケージがインストールできるのはここまでの環境設定のためです。端折っていると、pipやsetup.pyは、GNUの新しめのコンパイラ・リンカでなく、FreeBSDのccやリンカ、或いはサーバーの古いgccを使おうとしてエラーが出ることでしょう。
numpyのインストール
現時点で最新のnumpy-1.13.3をインストールします。
pipを使いますが、その前におまじないが必要です。
unsetenv SHELL pip3 install numpy
おまじないの理由は、Github、numpyのissue「Build from sources fails when /bin/tcsh is the default shell #9970」をご参照ください。コンパイルオプションの「-DATLAS_INFO="\"None\""
」のダブルクォーテーションがエスケープできずエラーになるようです。
インストールが成功したら確認します。
python3 -c "import numpy;numpy.show_config()"
ここでエラーが起きず、表示された「atlas_3_10_ … _info
」「blas_opt_info
」「lapack_opt_info
」などのカテゴリの「libraries
」の項に、「tatlas
」があれば成功、ATLASが認識されています。
そしてWebブラウザからtest.cgiにアクセスして、エラーがないことを確認します。(numpy.show_config()
はここでも確認できます。)
numpyのインストールに、代数演算ライブラリのインストールは必須ではないようです。(但し遅いらしい。)
しかし後にインストールするscipyさんやscikit-learnさんは、代数演算ライブラリがあるかどうかをnumpyさんから聞くようです。ですので一番最初に、ちゃんとATLASなどBLASライブラリを認識したnumpyさんをインストールしたほうがよいかと思います。
そしてscipyさんscikit-learnさんのインストールのときにも、pip3やsetup.pyの前に「unsetenv SHELL
」が必要です。以降のインストールを続けて行う場合は良いですが、シェルを開き直した場合はご注意下さい。
scipyのインストール
scipyはpipでインストールしました。バージョンは1.0.0です。
pip3 install scipy
完了までにはかなり時間が掛かります。ご飯を食べに行きましょう。もし会社で5時過ぎでしたら、ディスプレイだけ消して帰りましょう。
成功していたら、numpyと同様に確認します。
python3 -c "import scipy;scipy.show_config()"
エラーが起きず、numpyと同様atlas, blas, lapack関係にtatlasの表示がなされれば成功です。
ブラウザからtest.cgiにアクセスして、エラーがないことも確認します。
scikit-learnのインストール
最初scikit-learnのインストールをpipでしましたら、実行時に「pairwise_fast.soにATL_dasumがないよ
」とエラーが出ました。
Github、scikit-learnのissue「pairwise_fast.so is not linked against ATLAS or BLAS #6130」を見ると、lddで見てlibtatlas.soへの参照がないとエラーになるようです。以下のように…
ldd ~/local/lib/python3.6/site-packages/sklearn/metrics/pairwise_fast.so /home/your-site/local/lib/python3.6/site-packages/sklearn/metrics/pairwise_fast.so: libm.so.5 => /lib/libm.so.5 (0x80123d000) libthr.so.3 => /lib/libthr.so.3 (0x80145e000) libc.so.7 => /lib/libc.so.7 (0x80081a000)
ですので、Githubの0.19.1のタグ(現時点での最新)からリポジトリを引っ張ってインストールします。
wget https://github.com/scikit-learn/scikit-learn/archive/0.19.1.zip -O scikit-learn-0.19.1.zip unzip scikit-learn-0.19.1.zip cd scikit-learn-0.19.1 python3 setup.py build_ext --rpath=$HOME/local/lib
ここで一度libtatlas.soが参照されているか確認してみます。
ldd build/lib.freebsd-9.1-RELEASE-p24-amd64-3.6/sklearn/metrics/pairwise_fast.so build/lib.freebsd-9.1-RELEASE-p24-amd64-3.6/sklearn/metrics/pairwise_fast.so: libtatlas.so => /home/your-site/local/lib/libtatlas.so (0x80123d000) libm.so.5 => /lib/libm.so.5 (0x8023b1000) libthr.so.3 => /lib/libthr.so.3 (0x8025d2000) libc.so.7 => /lib/libc.so.7 (0x80081a000) libgfortran.so.3 => /home/your-site/local/lib/libgfortran.so.3 (0x8027f4000) libquadmath.so.0 => /home/your-site/local/lib/libquadmath.so.0 (0x802b98000) libgcc_s.so.1 => /home/your-site/local/lib/libgcc_s.so.1 (0x802dde000)
参照されているようですね。site.cfgで設定はしていなくてもちゃんとnumpyさんから聞くようです。なぜpipからはそうならないのでしょう(謎)。
ともあれインストールを続行。
python3 setup.py install
一応test.cgiで確認していますが、大本のimportだけですので実行時にエラーは出るかもしれません。
gensimのインストール
最後のgensimです。
pip3 install gensim
バージョンは3.2.0でした。
ブラウザのtest.cgiで「Success…
」を確認します。
以上で目的は達成しました。お疲れ様でした。
(pandas-0.21.1も同様にpipで行けたと思います。)
教訓(Lessons Learned)
以上の作業での、教訓をまとめておきます。
FreeBSDとLINUXの違い
この作業をする前までは、FreeBSDもLinuxもほとんど同じと思っていました。
しかし結構違います。makeとか。それでPortsが存在。
以降は簡単に「ビルドしよう」とは発想しないことにします。
(いや自分でFreeBSDは使わないし、レンタルサーバーでビルドもほぼしませんが。)
探索作業のやめどき
このレポートでは、上流から下流へ書いていますが、実際はまっすぐ海まで下れる流れを下流から少しずつ探していく探索作業でした。
Web検索と試行錯誤の繰り返し。その日ダメでも一晩寝れば突破のアイデアが出てきます。キリがありません。
今回はうまくいきましたが、探索作業のやめどきの決定をどうするか、検討が必要ですね。
Pythonモジュールがインストールできないとき
バージョンを下げてみればインストール出来るかもしれません。
またリポジトリからソースをダウンロードしてsetup.pyの実行でなんとかなるかもしれません。site.cfgの設定やファイルの修正が必要かもしれません。
まとめ
とりあえずscikit-learnとgensimまではインストールできました。しかし正常動作するかはわかりません。
(インストールできたとはいえ、学習やモデルの作成はレンタルサーバーではいたしません。あくまでもCGIでのサービスが目的ですから。)
TensorFlowは無理っす。bazelとかFreeBSDでできる気がしない。