maminusのメモか何か

2018-06-11

Win10のAnaconda環境にclpyをmingwビルドで入れた話

| 23:33

記事タイトル間違ってません

clpy*1というcupyをベースに?バックエンドをOpenCLにしたライブラリが出ていたのでさっそくMinGWビルドしてみた。

環境

前回と一緒

  • Windows10 pro 64bit
  • Anaconda3 5.1.0
  • pip 9.0.1
  • MinGW w64 7.3.0
  • clpy 2.1.0a0

clpyはGitHubからclone、もしくはzipダウンロードしておく。

前準備

  • g++にパスを通しておく
  • README.mdの通りに環境変数を設定する
    • C_INCLUDE_PATHとCPLUS_INCLUDE_PATHにOpenCLのインクルードパス
    • LIBRARY_PATHにOpenCLライブラリパス*2
    • CLPY_GENERATE_CUPY_ALIAS=1

CLPY_GENERATE_CUPY_ALIASを設定しておくとclpyと書くところをcupyと書くことができてcupyを使っているような感じでコーディングできるっぽい。


以降は魔改造した内容

distutils

  • Anaconda3\Lib\distutils\ccompiler.py の改造

ccompilerを直接使っているせいなのか、distutils.cfgを見てくれない。ので、無理やりmingw32にする。

 _default_compilers = (

     # Platform string mappings

     # on a cygwin built python we can use gcc like an ordinary UNIXish
     # compiler
     ('cygwin.*', 'unix'),

     # OS name mappings
     ('posix', 'unix'),
+    ('nt', 'mingw32'),
-    ('nt', 'msvc'),

     )
  • Anaconda3\Lib\distutils\cygwinccompiler.py の改造

sys.versionを見てVisual C++ ライブラリを決める箇所をMinGW向けにバージョン変更する

 def get_msvcr():
     """Include the appropriate MSVC runtime library if Python was built
     with MSVC 7.0 or later.
     """
     msc_pos = sys.version.find('MSC v.')
     if msc_pos != -1:
         msc_ver = sys.version[msc_pos+6:msc_pos+10]
         if msc_ver == '1300':
             # MSVC 7.0
             return ['msvcr70']
         elif msc_ver == '1310':
             # MSVC 7.1
             return ['msvcr71']
         elif msc_ver == '1400':
             # VS2005 / MSVC 8.0
             return ['msvcr80']
         elif msc_ver == '1500':
             # VS2008 / MSVC 9.0
             return ['msvcr90']
         elif msc_ver == '1600':
             # VS2010 / MSVC 10.0
             return ['msvcr100']
         elif int(msc_ver) >= 1900:
             # VS2015 / MSVC 14.0
+            return ['msvcr100']
-            return ['msvcr140']
         else:
             raise ValueError("Unknown MS Compiler version %s " % msc_ver)

clpyのinstall\build.py変更

g++には「MANIFEST」というコマンドライン引数は無いので、build_shlib()のpostargsを空っぽの配列に変更する

         try:
+            postargs = []
-            postargs = ['/MANIFEST'] if sys.platform == 'win32' else []
             compiler.link_shared_lib(objects,
                                      os.path.join(temp_dir, 'a'),

いつものcmath改造

mingw\lib\gcc\x86_64-w64-mingw32\7.3.0\include\c++\cmathの「hypot」でコンパイルエラーになるのでコメントアウトする。

-  using ::hypot;
+//  using ::hypot;

インストール

README.mdに書かれている通り、以下で大丈夫と思う。自分はビルド確認をやっていたのでbuildしてからinstallした。

$ python setup.py install

動作確認

pyopenclのハンズオン*3を見ながら書いていたコードをさらに改造して、行列積の結果をclpyと比較してみる。CLPY_GENERATE_CUPY_ALIASを設定してビルドしたので以下の通り「cupy」と書いてclpyを使える。

import pyopencl as cl
from pyopencl import mem_flags
import cupy
import numpy as np
import time

input_size = 1024

context = cl.create_some_context()
queue = cl.CommandQueue(context)

# inputs
lhs_host = np.random.randn(input_size, input_size).astype(np.float32)
rhs_host = np.random.randn(input_size, input_size).astype(np.float32)
lhs_cl = cupy.asarray(lhs_host)
rhs_cl = cupy.asarray(rhs_host)
lhs_dev = cl.Buffer(context, mem_flags.READ_ONLY|mem_flags.COPY_HOST_PTR, hostbuf=lhs_host)
rhs_dev = cl.Buffer(context, mem_flags.READ_ONLY|mem_flags.COPY_HOST_PTR, hostbuf=rhs_host)

# outputs
result_host_pycl = np.empty((input_size, input_size), np.float32)
result_dev = cl.Buffer(context, mem_flags.WRITE_ONLY, result_host_pycl.nbytes)
result_cl = cupy.array(result_host_pycl) # 暫定コード。emptyなcupy.ndarrayを作る方法が不明。

# pyopenclの行列積kernel(最適化なし)
program = cl.Program(context, '''
__kernel void mul(
    __global const float *a,
    __global const float *b,
    __global float *c,
    const int n
)
{
    const int i = get_global_id(0);
    const int j = get_global_id(1);
    const int index = j*n + i;

    float accm = 0;
    for (int k=0;k<n;k++) {
        accm += a[j*n + k] * b[k*n + i];
    }
    c[index] = accm;
}
''').build()

n = np.int32(input_size)

start = time.time()

# cupy行列積
result_cl = cupy.dot(lhs_cl, rhs_cl)

# pyopencl行列積
ev = program.mul(queue, lhs_host.shape, None, lhs_dev, rhs_dev, result_dev, n)
ev.wait()

stop = time.time()

# result_host_pycl <- result_dev
cl.enqueue_copy(queue, result_host_pycl, result_dev)

result_host_cupy = cupy.asnumpy(result_cl)

# 差分の絶対値から最大(差分が最大)のものを表示
print('clpy vs pyopencl diff(max):', np.max(np.abs(result_host_cupy - result_host_pycl)))
print(np.all(result_host_cupy == result_host_pycl)) # 全部同値ならTrueのつもり

print('CPU vs clpy diff(max):', np.max(np.abs(np.dot(lhs_host, rhs_host) - result_host_cupy)))
print(np.all(np.dot(lhs_host, rhs_host) == result_host_cupy))

print('exec time:', stop - start, 'sec')

実行結果はこんな感じ。GPU側はfmaが使われてCPUと結果が一致しないと思われる。

>python clpy-test.py

Choose platform:

[0] <pyopencl.Platform 'AMD Accelerated Parallel Processing' at 0x7ff9eaf54ab0>

Choice [0]:0

Choose device(s):

[0] <pyopencl.Device 'Ellesmere' on 'AMD Accelerated Parallel Processing' at 0x1c41c4c0540>

[1] <pyopencl.Device 'AMD Ryzen 7 1800X Eight-Core Processor' on 'AMD Accelerated Parallel Processing' at 0x1c41c612f30>

Choice, comma-separated [0]:1

Set the environment variable PYOPENCL_CTX='0:1' to avoid being asked again.

clpy vs pyopencl diff(max): 0.0

True

CPU vs clpy diff(max): 0.00021362305

False

exec time: 0.37632179260253906 sec

*1https://github.com/fixstars/clpy

*2OpenCLSDKを入れてない場合は「C:\Windows\System32」を入れておけばOpenCL.dllとリンクしてくれる

*3http://pykyoto201109-pyopencl.s3-website-ap-northeast-1.amazonaws.com/pyopencl.html

2018-05-24

Win10のAnaconda環境にpyopenclをmingwビルドで入れた話

| 23:18

pyopenclをpip installしようとしたら、cl.exeを要求されてC++ Build Tools入れるのが面倒なので軽く絶望したけど、なんやかんやでMinGWでのビルドに成功したのでメモ。

環境

  • Windows10 pro 64bit
  • Anaconda3 5.1.0
  • pip 9.0.1
  • pyopencl 2018.1.1
  • MinGW w64 7.3.0

前準備

  • g++にパスを通しておく
  • OpenCLのヘッダをインクルードパスを通しておく(set CPLUS_INCLUDE_PATHしておく)
  • pip install makoMakoを入れておく

pipのエラー回避

こちら*1で解説されている現象が発生したので、記載されている通りの対処を実施

コンパイラの切り替え

Anaconda3\Lib\distutils\distutils.cfg ファイルを新規作成する。

[build]
compiler = mingw32

これでcl.exeからg++に切り替わる。

pyopenclのパッケージファイルを入手する

手っ取り早いのは一度pip install pyopenclで失敗させておいて「Using cached〜」と表示されている箇所を見てファイルのURLを確認してブラウザなどでダウンロードする。

以降はダウンロードしたファイルを解凍してpyopencl-2018.1.1フォルダにカレントディレクトリを移して作業する。

MinGWのヘッダ改変

mingw\lib\gcc\x86_64-w64-mingw32\7.3.0\include\c++\cmathの「using ::hypot;」をコメントアウトする。pyopenclのインストールが終わったら元に戻しておく。

少しググった感じだとpythonのヘッダとC++ヘッダのinclude順で発生する問題?っぽいけど、該当箇所がビルド時に生成されるソースのようで編集が難しそうなのでMinGW側のヘッダ改変で対処する。

pyopenclの独自スレッドライブラリを無効化する

pyopencl-2018.1.1\src\c_wrapper\mingw-std-threadsに入っている3つのヘッダファイルを無効化する。ヘッダファイルの中身を#if 0でくくるなり、全削除するなりで無効化する。

(なぜかSTLスレッドライブラリが独自定義されていてMinGWSTLライブラリと衝突してしまうため)

コンパイル

いったんコンパイルする。リンクでこける。

pyopencl-2018.1.1>python setup.py build

コンソールにリンクで実行されるコマンドとオプションが表示されているのでコピーする。

リンク

先ほどコピーしたリンクのコマンドを改変する。

改変後のコマンドを実行してpydを生成する。

インストール

リンクが正常にできていれば以下のコマンドでインストールできる。

pyopencl-2018.1.1>python setup.py install

余談

2018-03-20

JetsonTX2にCaffe2を入れる

| 00:01

JetPack3.2が正式リリースされたとのことなので、開発PCをUbuntu16.04、TX2をJetPack3.2に入れなおした。

Chainerはデータごと死んだ環境がまっさらに戻ったので、せっかくなので他のDLフレームワークでも入れて遊ぼうということでTensorFlowはJetsonだとインストール面倒そうなのでぱっと見た感じ入れるのが楽そうだったCaffe2を入れてみた。


環境


Eigenのヘッダファイル詐称書き換え

CaffeのソースコードがEigen v3.0.0以上を前提としているらしく、バージョンが古いと #errorコンパイルエラーを吐いてしまう。JetPack3.2のlibeigen3はv3.3 beta1-2という微妙なバージョンになっている。しかもヘッダファイル上ではv3.2.92扱いになっている。これではビルドが通らない。

$ dpkg -s libeigen3-dev

(中略)

3.3~beta1-2

えいっ

$ sudo vi /usr/include/eigen3/Eigen/src/Core/util/Macros.h
- #define EIGEN_MAJOR_VERSION 2
- #define EIGEN_MINOR_VERSION 92
+ #define EIGEN_MAJOR_VERSION 3
+ #define EIGEN_MINOR_VERSION 0

これで無事ビルドは通った。何も見なかった。良いね?


依存パッケージのインストール

基本的にはソース一式に入っているcripts/build_tegra_x1.shの通りなんだけどvenv環境で動かしたので少し変更した。

$ sudo apt-get install python3-dev python3-venv
$ sudo apt-get install cmake libgflags-dev libgoogle-glog-dev libprotobuf-dev protobuf-compiler
$ sudo apt-get install libleveldb-dev liblmdb-dev libpython-dev libsnappy-dev
$ python3 -m venv py352env
$ source py352env/bin/activate
(py352env) :~$ pip install --upgrade pip
(py352env) :~$ pip install numpy
(py352env) :~$ pip install protobuf
(py352env) :~$ pip install hypothesis
(py352env) :~$ pip install six

ソースのダウンロードビルド

gitからソースを入手する。結構時間がかかる。ビルドも長いのでjetson_clockとnvpmodelを叩いておくと良さげ。

(py352env) :~$ git clone --recursive https://github.com/caffe2/caffe2.git
(py352env) :~$ cd caffe2
(py352env) :~/caffe2$ mkdir build
(py352env) :~/caffe2$ cd build
(py352env) :~/caffe2/build$ cmake -DCUDA_USE_STATIC_CUDA_RUNTIME=OFF ..
(py352env) :~/caffe2/build$ make -j 4

足りないパッケージ、jupyter notebookの追加、環境構築

futureは入ってないと「from caffe2.python import core」した時に

~/caffe2/build/caffe2/python/core.py in <module>()

---> 24 from past.builtins import basestring

ImportError: No module named 'past'

とかって怒られる。

(py352env) :~$ pip install future
(py352env) :~$ sudo apt-get install libfreetype6-dev libpng12-dev
(py352env) :~$ pip install matplotlib
(py352env) :~$ pip install jupyter
(py352env) :~$ jupyter notebook --generate-config
(py352env) :~$ ipython
(py352env) :~$ vi ~/.jupyter/jupyter_notebook_config.py
(py352env) :~$ cd caffe2/build
(py352env) :~/caffe2/build$ jupyter notebook

Jupyter Notebookは以前*1環境構築を記事にしたのでそちらもどうぞ。

caffe2のpythonモジュールはbuild/caffe2とかに入っているので、jupyterコマンドはbuildディレクトリで打つと「from caffe2」した時に良い感じになった。一応これで「python/tutorials/Basics.ipynb」の冒頭を実行できることは確認した。このまま少し遊んでみようと思う。

そういえば、caffe2をビルドはしたけどインストールしてないような気がする。ま、いいか


[2018/03/21 追記]

Basics.ipynbを試してたら可視化するところでパッケージが足りずエラーになってしまった。以下を追加して解決した。

$ sudo apt-get install graphviz
(py352env) :~$ pip install pydot

2018-02-16

JetsonTX2でOpenCVをビルド

| 23:20

発端

ChainerCVのチュートリアル*1をJetson TX2で試したところ、「OpenCVが入ってないから処理時間かかるよ」みたいなWarningが表示された。

「OpenCV4Tegra入ってるのでは?」と思って調べてみたところ、Python2からは呼び出せるがPython3からは呼べなかった。(Python2から呼ぶ場合、あらかじめpython-opencvをpipしておく必要がある)

NVIDIAのフォーラム*2を見た感じだと、OpenCV4Tegraはpython3には対応してない模様。「自分でビルドしたらいけるよ」的な感じで一瞬途方に暮れたけど、フォーラムの最後に偉大なる先駆者の方が「ブログに書いたよ」と報告されていた。

そこで今回は先駆者の方に従ってTX2にOpenCVを入れてみた。

手順(の補足)

ということで、インストール手順そのものは先駆者の方*3をなぞれば基本的に大丈夫。ここではわかりにくかった箇所、つまったところを中心に補足する。

matplotlibrc の編集内容

以下に示した通り、「gtk3agg」箇所を「TkAgg」に変更する。

backend      : gtk3agg # 変更後
# backend      : TkAgg # 変更前

cuda_gl_interop.h の編集内容

以下のようにaarch64時にコンパイルエラーになるようになっているのをコメントアウトしまくって常にGL/gl.hをincludeするように変更する。

#if defined(__APPLE__)

#include <OpenGL/gl.h>

#else /* __APPLE__ */

//#if defined(__arm__) || defined(__aarch64__)
//#ifndef GL_VERSION
//#error Please include the appropriate gl headers before including cuda_gl_interop.h
//#endif
//#else
#include <GL/gl.h>
//#endif

#endif /* __APPLE__ */

make中にコンパイルエラーになる

gccバグレポートがどうこうってエラーでビルドができない。関係あるのか不明だけど、プリコンパイルヘッダでやたらWarningでていた。

ためしにcmakeに「-D ENABLE_PRECOMPILED_HEADERS=OFF」を追加して「make -j6」ならビルドできた。「make -j」だとメモリを使いきって同じくエラーになってしまう。プリコンパイルヘッダを使った場合も、もしかしたらメモリを使いきっていた?


インストール中もなぜかビルドが走る

よくわからないけど、「sudo make install」した時になぜかいくつかビルドが走った。そのあとインストールが走ったから特に問題なさそう。


venv環境からcv2が見えない

そのままだとvenvからcv2がimportできなかった。

pyvenv.cfgを編集して「include-system-site-packages」を「true」にしてからactivateしたらimportできた。


謝辞

今回は先駆者の方の情報がとても役に立った。この場を借りて感謝いたします。

正直自分でやろうとしたら厳しかったのでは。


こんな感じでJupyter Notebookから呼べた。

f:id:maminus:20180216231247p:image

2018-02-14

JetsonTX2にChainerCVを追加インストール

| 23:19

前回*1につづいて、さらにChainerCVを追加したのでメモ。

手順

ChainerCVをインストールしようとすると、JetsonはPillowをソースコードからビルドしようとするらしくlibjpegとかのヘッダファイルなどが入っていないとエラーになる。こちら*2を参考にして依存パッケージを追加すると無事Pillowのビルドが通った。

$ sudo apt-get install libtiff5-dev libjpeg8-dev zlib1g-dev \
    libfreetype6-dev liblcms2-dev libwebp-dev libharfbuzz-dev libfribidi-dev \
    tcl8.6-dev tk8.6-dev python-tk
(py352env) $ pip install chainercv

インストール

インストール完了後の各パッケージは以下の通り。

(py352env) nvidia@tegra-ubuntu:~$ pip list --format=columns
Package            Version
------------------ -------
bleach             2.1.2
chainer            3.3.0
chainercv          0.8.0
cupy               2.3.0
cycler             0.10.0
decorator          4.2.1
entrypoints        0.2.3
fastrlock          0.3
filelock           3.0.4
html5lib           1.0.1
ipykernel          4.8.1
ipython            6.2.1
ipython-genutils   0.2.0
ipywidgets         7.1.1
jedi               0.11.1
Jinja2             2.10
jsonschema         2.6.0
jupyter            1.0.0
jupyter-client     5.2.2
jupyter-console    5.2.0
jupyter-core       4.4.0
MarkupSafe         1.0
matplotlib         2.1.2
mistune            0.8.3
nbconvert          5.3.1
nbformat           4.4.0
notebook           5.4.0
numpy              1.14.0
pandocfilters      1.4.2
parso              0.1.1
pexpect            4.3.1
pickleshare        0.7.4
Pillow             5.0.0
pip                9.0.1
pkg-resources      0.0.0
prompt-toolkit     1.0.15
protobuf           3.5.1
ptyprocess         0.5.2
Pygments           2.2.0
pyparsing          2.2.0
python-dateutil    2.6.1
pytz               2018.3
pyzmq              16.0.4
qtconsole          4.3.1
Send2Trash         1.4.2
setuptools         20.7.0
simplegeneric      0.8.1
six                1.11.0
terminado          0.8.1
testpath           0.3.1
tornado            4.5.3
traitlets          4.3.2
wcwidth            0.1.7
webencodings       0.5.1
widgetsnbextension 3.1.3

以上

これでChainerの初心者向けハンズオンは実行できるはず。まだ最後の学習処理が1エポックしか動かしてないけど残り99エポックも大丈夫と思われる。

ちなみにハンズオンの学習処理は結構時間がかかる。DeepCNNのAugmentationなし(「In [31]:」箇所)版が一番時間がかかって1エポック190秒ほどかかった。(実行はsudo nvpmodel -m 0でMAX-Nモードにした状態で実施)

ファンを回すと結構うるさいし、寝てる間に計算させようとするとつらい