2021年12月26日日曜日

Fedora 35でOpen3D(CUDA+TensorFlow)をビルドする

目的


Fedora 35 + CUDAの環境でOpen3Dをビルドできるようにしたい。


環境


2021.12.25時点の環境は以下。
  • Fedora 35 x86_64
  • gcc version 11.2.1 20211203 (Red Hat 11.2.1-7) (GCC) 
  • CUDA 11.5 + cuDNN v8.3.1



Fedora 35で発生するビルドエラー


Open3DはLinuxディストリビューションではUbuntuが公式の環境となっている。

このため、Fedora 35だと様々なエラーが発生する。
  • サポートするPythonバージョンが一致しない。
  • GCCバージョンによる(CUDA、C++14 vs C++17)ビルド、リンク時にエラーが発生。
  • 不足しているモジュールのインストールが必要。

今回はそれらを解決・回避しながら、v0.14.0で追加されたOpen3D for TensorBoardが動作するところまでやってみる。


事前の準備


  • Python3.9のインストール


Fedora 35のPythonは3.10が標準である。
Open3DはPython 3.9までをサポートのため、ビルド時にエラーが発生する。
このため、Open3Dではなく、Fedoraに3.9をインストールし、仮想環境で対応することとする。
Python3.9のパッケージをインストール後、virtualenvwrapperで仮想環境を作成する。

sudo dnf install python3.9
mkvirtualenv --python=python3.9 open3d_p39

以降、仮想環境で作業する。


GCC 11.1のビルド


Fedora 35の場合、Open3DとTensorFlowをCUDAを有効でビルドする場合、GCCのバージョンが問題となる。
前回のブログを参照。

CUDAのコンパイラーのために、GCC11.1をソースビルドしておく。
ビルドについては上記のブログを参照。


TensorFlow 2.5のビルド


Open3D v0.14.0では、TensorFlow v2.5を期待している。

おそらく、TensorFlow v2.7でもOKな気がするが、 v2.5.2をビルドして、インストールする。

ビルド方法は前回のブログと同様なので詳細は割愛。    
ただし、v2.5.2の場合、ビルド中にRuyでビルドエラーが発生してしまう。

external/ruy/ruy/block_map.cc: In function ‘void ruy::MakeBlockMap(int, int, int, int, int, int, int, int, const ruy::CpuCacheParams&, ruy::BlockMap*)’:
external/ruy/ruy/block_map.cc:395:25: error: ‘numeric_limits’ is not a member of ‘std’
  395 |   int best_score = std::numeric_limits<int>::min();
      |                         ^~~~~~~~~~~~~~
external/ruy/ruy/block_map.cc:395:40: error: expected primary-expression before ‘int’
  395 |   int best_score = std::numeric_limits<int>::min();
      |                                        ^~~
Target //tensorflow/tools/pip_package:build_pip_package failed to build

ビルドエラーが発生した後、該当のモジュール(bazelのキャッシュにある)のソースを修正して、再度ビルドする。

<Bazelのキャッシュディレクトリ>external/ruy/ruy/block_map.cc
にヘッダのインクルードを追加する。
詳細は以下を参照。

ビルド後、pipパッケージを作成し、インストールする。


Open3Dのビルド


さて、ここまできたので後はOpen3Dのビルド。


必要なパッケージのインストール(思いつくもの)


Open3D for TensorBoardを動作させるために必要なモジュールをインストールする。
  • yapfはpipパッケージの作成の際にないとエラーとなる。
  • nodejs、jupyter関連のモジュールはTensorBoard起動時にないとエラーとなる。

sudo dnf install nodejs
sudo npm install -g yarn
pip install yapf
pip install jupyter_packaging ipywidgets jupyterlab


ソースコードのCloneと修正


現時点(2021.12.26)のOpen3Dのコードのままだとビルドできない。

一番の問題は、CUDAのコンパイラーを指定するCMAKE_CUDA_HOST_COMPILERフラグが3rdpartyモジュールで指定されないことと、3rdpartyモジュールのfaissはCMAKE_CUDA_HOST_COMPILERフラグにCMAKE_CXX_COMPILERフラグを指定していることである。

このため、3rdpartyモジュールのビルド時にビルドエラーが発生する。

3rdpartyモジュールにもCMAKE_CUDA_HOST_COMPILERフラグを指定することと、faissのCMakeLists.txtにパッチを当てる。

forkリポジトリに上記を対応したブランチを用意した。

これをつかってビルドを行う。

git clone https://github.com/NobuoTsukamoto/Open3D.git
cd Open3D
git ckeckout fedora_cuda_build
cd ..
git clone https://github.com/isl-org/Open3D-ML.git
mkdir build
cd build


CMAKE


BUILD_TENSORFLOW_OPSを有効としてビルドするのだが、そのままビルドすると、pipパッケージの作成でエラーが発生してしまう。
  • https://zenn.dev/link/comments/50c45f4523bb90

これは、TensorFlowはC++14でビルド(std=gun++14)だが、Open3DはC++17(GCC11.2のデフォルト)でビルドしているため。
tf.load_op_libraryでopen3d_tf_ops.soをロードする際にundefined symbolが発生してしまう。
詳細は以下のissueも参照。

このため、CMAKE_CXX_STANDARD=14を指定することで解決する。

上記の2つのポイントは、
  • CMAKE_CUDA_HOST_COMPILERでCUDAのコンパイラー(GCC 11.1)を指定
  • CMAKE_CXX_STANDARDでC++14を指定
である。

cmake ../Open3D \
  -DBUILD_TENSORFLOW_OPS=ON \
  -DBUILD_BENCHMARKS=ON \
  -DBUILD_CUDA_MODULE=ON \
  -DBUNDLE_OPEN3D_ML=ON \
  -DBUILD_JUPYTER_EXTENSION=ON \
  -DBUILD_WEBRTC=ON \
  -DOPEN3D_ML_ROOT=/home/xxxxx/WorkSpace/open3d/Open3D-ML/ \
  -DCMAKE_CXX_STANDARD=14 \
  -DCMAKE_CUDA_HOST_COMPILER=/home/xxxxx/gcc/11.1/bin/gcc


ビルド


あとは、ビルドしてpipパッケージを作成、インストールする。

make -j$(nproc)
sudo make install
make pip-package
pip install lib/python_package/pip_package/open3d-0.14.1+3d75e332f-cp39-cp39-manylinux_2_34_x86_64.whl


ビルド後の確認


Open3D for TensorBoardのサンプルの通りやってみる。

cd ../Open3D
python examples/python/gui/tensorboard_tensorflow.py small_scale
tensorboard --logdir demo_logs/tf

リンクを開くとTensorBoardが起動する。



OK!!!!!!!!!

2021年12月23日木曜日

Fedora 35 の GCC 11.2.1 20211203 で Tensorflow 2.7(CUDA11.5 cuDNN8.3.1)をビルドする

目的



その後、Fedora 35のGCCのバージョンがアップデートした。
  • GCC 11.2.1 20210728 → GCC 11.2.1 20211203

この変更、特にlibstdc++のヘッダーファイルの変更が影響してCUDA関連のビルドが失敗することがわかった。

注)
もちろんCUDAのGCCサポートはFedora 34のGCC 11(おそらく11.1)となっている。

このため、Fedora 35のGCC 11.2はサポート対象外であり、前回ビルドできたことは奇跡だったのである。
(そうでも、ちょっといきなりビルドできなくなるのはひどいが、、、)


GCC 11.2.1 20211203でのCUDA関連のビルドエラー


Fedora 35 の GCC 11.2.1 20211203でビルドすると下記の記事でまとめたが、ビルドエラーが発生する。
なお、これはTensorFlowに限らず、CUDA関連のビルドはすべて失敗すると思われる。


環境


2021.12.18時点の環境は以下。
  • Fedora 35 x86_64
  • Python 3.10.0 (default, Oct  4 2021, 00:00:00) [GCC 11.2.1 20210728 (Red Hat 11.2.1-1)] on linux
  • gcc version 11.2.1 20211203 (Red Hat 11.2.1-7) (GCC) 
  • CUDA 11.5 + cuDNN v8.3.1


事前の準備


対応の方針としては、いつものごとくCUDA用のGCCを別途用意する。
これは過去も同様。今回はGCC11.1を用意する。

GCC 11.1のビルド


ソースのダウンロード&変更


GCC11.1のソースをダウンロードする。

wget https://ftp.gnu.org/gnu/gcc/gcc-11.1.0/gcc-11.1.0.tar.gz
tar xf gcc-11.1.0.tar.gz
cd gcc-11.1.0/


そのままではビルドエラーになってしまうため、コードの一部を変更する。
エラーの内容、変更箇所は以下のGentooのバクレポートを参照。


ビルド


これも今までの通り。
以下のビルドオプションでビルドを行う。

./contrib/download_prerequisites
mkdir build
../configure \
  --enable-bootstrap \
  --enable-languages=c,c++ \
  --prefix=/home/xxxx/gcc/11.1 \
  --enable-shared \
  --enable-threads=posix \
  --enable-checking=release \
  --disable-multilib \
  --with-system-zlib \
  --enable-__cxa_atexit \
  --disable-libunwind-exceptions \
  --enable-gnu-unique-object \
  --enable-linker-build-id \
  --with-gcc-major-version-only \
  --with-linker-hash-style=gnu \
  --enable-plugin \
  --enable-initfini-array \
  --with-isl \
  --enable-libmpx \
  --enable-gnu-indirect-function \
  --build=x86_64-redhat-linux
make -j$(nproc)
make install


ビルド後の設定


ビルド後は、specsファイルを作成、設定する。

/home/xxxx/gcc/11.1/bin/gcc -dumpspecs > specs
$ vi specs

# before
*link_libgcc:
%D

# after
*link_libgcc:
%{!static:%{!static-libgcc:-rpath /home/xxxx/gcc/11.1/lib64/}} %D

$ mv specs /home/xxxx/gcc/11.1/lib/gcc/x86_64-redhat-linux/11/


TensorFlowのビルド


あとは、いつもどおりビルドすればOK。


Configure


configureではCUDAのコンパイラーにGCC11.1を指定する。

 ./configure 
You have bazel 3.7.2 installed.
Please specify the location of python. [Default is /home/xxxx/.virtualenvs/tf2.7/bin/python3]: 


Found possible Python library paths:
  /home/xxxx/.virtualenvs/tf2.7/lib/python3.10/site-packages
  /home/xxxx/.virtualenvs/tf2.7/lib64/python3.10/site-packages
Please input the desired Python library path to use.  Default is [/home/xxxx/.virtualenvs/tf2.7/lib/python3.10/site-packages]

Do you wish to build TensorFlow with ROCm support? [y/N]: 
No ROCm support will be enabled for TensorFlow.

Do you wish to build TensorFlow with CUDA support? [y/N]: y
CUDA support will be enabled for TensorFlow.

Do you wish to build TensorFlow with TensorRT support? [y/N]: 
No TensorRT support will be enabled for TensorFlow.

Found CUDA 11.5 in:
    /usr/local/cuda-11.5/targets/x86_64-linux/lib
    /usr/local/cuda-11.5/targets/x86_64-linux/include
Found cuDNN 8 in:
    /usr/local/cuda-11.5/targets/x86_64-linux/lib
    /usr/local/cuda-11.5/targets/x86_64-linux/include


Please specify a list of comma-separated CUDA compute capabilities you want to build with.
You can find the compute capability of your device at: https://developer.nvidia.com/cuda-gpus. Each capability can be specified as "x.y" or "compute_xy" to include both virtual and binary GPU code, or as "sm_xy" to only include the binary code.
Please note that each additional compute capability significantly increases your build time and binary size, and that TensorFlow only supports compute capabilities >= 3.5 [Default is: 6.1]: 


Do you want to use clang as CUDA compiler? [y/N]:                             
nvcc will be used as CUDA compiler.

Please specify which gcc should be used by nvcc as the host compiler. [Default is /usr/bin/gcc]: /home/xxxx/gcc/11.1/bin/gcc


Please specify optimization flags to use during compilation when bazel option "--config=opt" is specified [Default is -Wno-sign-compare]: 


Would you like to interactively configure ./WORKSPACE for Android builds? [y/N]: 
Not configuring the WORKSPACE for Android builds.

Preconfigured Bazel build configs. You can use any of the below by adding "--config=<>" to your build command. See .bazelrc for more details.
	--config=mkl         	# Build with MKL support.
	--config=mkl_aarch64 	# Build with oneDNN and Compute Library for the Arm Architecture (ACL).
	--config=monolithic  	# Config for mostly static monolithic build.
	--config=numa        	# Build with NUMA support.
	--config=dynamic_kernels	# (Experimental) Build kernels into separate shared objects.
	--config=v1          	# Build with TensorFlow 1 API instead of TF 2 API.
Preconfigured Bazel build configs to DISABLE default on features:
	--config=nogcp       	# Disable GCP support.
	--config=nonccl      	# Disable NVIDIA NCCL support.
Configuration finished


ビルド


あとはビルド。しばし待つ。

bazel build \
  --config=cuda \
  --config=v2 \
  --config=nonccl \
  --config=opt \
  //tensorflow/tools/pip_package:build_pip_package
./bazel-bin/tensorflow/tools/pip_package/build_pip_package /tmp/tensorflow_pkg
pip install /tmp/tensorflow_pkg/tensorflow-2.7.0-cp310-cp310-linux_x86_64.whl


2021年12月10日金曜日

Fedora 35 でTensorflow 2.7(CUDA11.5 cuDNN8.3.1)をビルドする

目的


Tensorflowの2.7をFedora 35でソースビルドする。


環境


  • SW
    • Fedora 35 x86_64
    • Python 3.10.0
    • GCC 11.2.1 20210728
    • CUDA 11.5 + cuDNN v8.3.1
  • HW
    • CPU AMD Ryzen 7 1700
    • GPU GeForce GTX 1070


事前の準備


CUDA、cuDNNのインストール


これは、以前と同様。
RPM FusionからCUDAを、NVIDIAよりcuDNNをそれぞれインストールする。

BAZELのインストール


FedoraのCOPR repositoryからインストールが可能。
3.x系と4.x系が選択可能なので3.x系をインストールする。



TensorFlow v2.7(後述のTensorFlow I/Oも含めて)のビルドにはBazel v3.7.2が必要(4.x系の場合、TensorFlow I/Oのビルドでエラーとなるため)。
しかし、現時点(2021.12.08)ではバージョンがv3.7.1。v3.7.2をソースコードからビルドするにはGCCのバージョンダウン(ソースビルド)が必要になる(Fedora 35のGCC11ではビルドができないため)。今回はv3.7.1で押し通すことにする。


TensorFlow I/Oのビルド


TensorFlow v2.7をビルド後、wheelパッケージをインストールする際にtensorflow_io_gcs_filesystemとtensorflow_ioのインストールを要求される(依存関係)。

しかしながら、Python3.10のパッケージは用意されていないためインストールできない。そこで、TensorFlow I/Oをビルド、io、io_gcs_filesystemのwheelパッケージも作成する。

なお、TensorFlow I/OのビルドにはTensorFlow v2.7が必要なため、デッドロックしてしまう。。。


なんでだよ。

さらにBazelが利用するモジュールがPython3.10に対応していないため、ビルドでエラーが発生してしまう。

ここで、TensorFlow I/Oのビルドは2つの手順に分かれている(TensorFlow I/Oのビルド手順を参照)。
  • Bazelを使ったビルド(共有ライブラリの作成)
  • Wheelパッケージの作成

    このため、ビルドはPython3.9環境で行い、パッケージ作成時にPython3.10環境に切り替えて行うこととする。Python3.9環境であれば、TensorFlowも公式のパッケージが提供されているのでデッドロックも回避できる。
    TensorFlow I/OのGithub Actionがこのような手順になっていたので参考にした。

    (じゃあ、Python3.9環境でよくない?というのは置いておく)


    まず、Python3.9をインストールし、virtualenvwrapper(virtualenv)でビルド用環境を作成し、必要なモジュールをインストールしておく。



    TensorFlow I/Oのリポジトリをクローンする。
    今回はPython3.10ビルドに対応となっていたmainブランチとする(でも対応していないけど、、、)。



    先程述べたBazelのバージョンが一致しない問題があるので、.bazelversionの内容を変更しておく。



    ビルド。


    wheelパッケージの作成。
    setup.pyがpython3.10をサポートしていないので修正。



    TensorFlowをインストールするためのPython3.10環境を作成、切り替えて、wheelパッケージを作成。できたパッケージをインストール。



    TensorFlowのビルド


    さて、あとは本題。

    TensorFlowのリポジトリをクローンしてv2.7.0をチェックアウト。
    Python3.10ではビルドが失敗するため、以下のコミットをcherry-pickする。



    Bazel3.7.1でビルドするために.bazelversionを修正。



    configureの実行。
    ccacheをインストールしているとビルドに失敗するため、host compilerにはGCCを指定する。



    ビルド。あとは待つだけ。



    ビルドが完了すれば、wheelパッケージを作成してインストールする!



    確認


    • tf.__version__が2.7であること。
    • GPUデバイスを認識していること



    OK〜✌

    2021年12月5日日曜日

    2021.11.23の釣行

     あたらしいロッドを買いました。

    カワセミラプソディの2021年モデル。

    ということで、初めて通年エリアに向かいました。

    ニジマスがターゲットです。

    今にも降り出しそう(と言うか、お昼前から降ってきた。。。)


    でもって、入魂!!!



    40オーバー。よく引いた。

    長靴釣行だったので、ネットインが大変だった。バレなくてよかった〜



    カワセミラプソディ、扱いやすくていいね!

    来シーズンが楽しみ!!

    2021年9月11日土曜日

    2021.9.11の釣行

    いつもの川。午前中だけ。

    やろうとおもっていたところは工事中だったので、もうすこし上流。

    いないかな〜と思っていたけど...

    イワナ、出てきてくれた😁(このちょっと前にもイワナばらしていた😭)

    もっと、写真のとり方うまくなりたい😇(このあと逃げていった...)


    これはスプーンだったけど、トリコロール舞45もよかったな〜





    あと、一回ぐらいかな?


    もうすぐ秋かな







    2021年5月1日土曜日

    Fedora 34でNVIDIA GPUのコンテナーを使う(Podman)

     目的


    Fedora 34でpodmanを使ってNVIDIA GPUのコンテナーを扱いたい。


    環境


    • Fedora 34 x86_64
    • CUDA 11.3 + cuDNN 8.2.0
    • CPU AMD Ryzen 7 1700
    • GPU GeForce GTX 1070


    参照




    手順


    NVIDIA Driver、CUDA、cuDNNのインストール


    RPM FusionのHowtoを参考にNVIDIA Driver、CUDAのインストールを行う。
    cuDNNは、NVIDIAのサイトからcuDNN v8.2のRedHat/Centos 8.1 x84_64向けのRPMをダウンロード、インストールする。理由は前回のブログを参照。


    nvidia-container-toolkitのインストール


    nvidia-dockerのリポジトリを追加する。Fedora向けはないためRHEL 8.3をインストールし、nvidia-container-toolkitをインストールする。

    $ curl -s -L https://nvidia.github.io/nvidia-docker/rhel8.3/nvidia-docker.repo |   sudo tee /etc/yum.repos.d/nvidia-docker.repo
    $ sudo dnf update
    $ sudo dnf install nvidia-container-toolkit

    SELinuxポリシーの変更が必要なのだが、RED HATブログにある手順ではうまくいかず、、、permissiveに変更して再起動した。


    動作確認


    Docker Hubからnvidia/cudaのイメージを取得して、確認する。

    $ sudo su
    # podman pull nvidia/cuda:11.3.0-base-ubuntu18.04
    # podman run -it --rm nvidia/cuda:11.3.0-base-ubuntu18.04 nvidia-smi
    Thu Apr 29 23:19:57 2021       
    +-----------------------------------------------------------------------------+
    | NVIDIA-SMI 465.24.02    Driver Version: 465.24.02    CUDA Version: 11.3     |
    |-------------------------------+----------------------+----------------------+
    | GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
    | Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
    |                               |                      |               MIG M. |
    |===============================+======================+======================|
    |   0  NVIDIA GeForce ...  Off  | 00000000:0A:00.0  On |                  N/A |
    |  0%   42C    P8     9W / 151W |    212MiB /  8116MiB |      0%      Default |
    |                               |                      |                  N/A |
    +-------------------------------+----------------------+----------------------+
                                                                                   
    +-----------------------------------------------------------------------------+
    | Processes:                                                                  |
    |  GPU   GI   CI        PID   Type   Process name                  GPU Memory |
    |        ID   ID                                                   Usage      |
    |=============================================================================|
    +-----------------------------------------------------------------------------+
    




    やったー👏👏👏👏👏👏👏👏

    Fedora 33のときは結構苦労した記憶があったけど、今回はあっさりOK!

    Fedora 34 でTensorflow 2.5-rc2(CUDA11.3 cuDNN8.2.0)をビルドする

    目的


    Tensorflowの2.5-rc2をFedora 34でソースビルドする。
    2.5の正式版リリースに向けての準備と備忘録。


    環境


    • Fedora 34 x86_64
    • Python 3.9.4(virtualenv)
    • GCC 11.0.1 20210324
    • CUDA 11.3 + cuDNN 8.2.0
    • CPU AMD Ryzen 7 1700
    • GPU GeForce GTX 1070


    事前の準備


    GCC10.2のビルド


    前回の記事
    と同様、CUDA 11.3がサポートするGCCは10.2.1で、Fedora 34のGCC11ではビルドができない。このため、まずはGCC10のビルドを行う。
    GCCのビルドについては、以前の記事を参照。


    GCC9.3のソースダウンロード&ビルド


    ソースをダウンロードし、ビルドする。

    $ wget http://ftp.tsukuba.wide.ad.jp/software/gcc/releases/gcc-10.2.0/gcc-10.2.0.tar.gz
    $ tar xf gcc-10.2.0.tar.gz
    $ cd gcc-10.2.0/
    $ ./contrib/download_prerequisites 
    $ mkdir build
    $ cd build/
    $ ../configure \
        --enable-bootstrap \
        --enable-languages=c,c++ \
        --prefix=/home/xxxxx/gcc/10.2 \
        --enable-shared \
        --enable-threads=posix \
        --enable-checking=release \
        --disable-multilib \
        --with-system-zlib \
        --enable-__cxa_atexit \
        --disable-libunwind-exceptions \
        --enable-gnu-unique-object \
        --enable-linker-build-id \
        --with-gcc-major-version-only \
        --with-linker-hash-style=gnu \
        --enable-plugin \
        --enable-initfini-array \
        --with-isl \
        --enable-libmpx \
        --enable-gnu-indirect-function \
        --build=x86_64-redhat-linux
    $ make -j16
    $ make install
    


    specsファイルの作成


    コンパイルしたGCC9でビルドした際に、適切な動的リンクライブラリ(libstdc++.so)がリンクされるようにSPECEファイルを修正する。

    $ /home/xxxxx/gcc/10.2/bin/gcc -dumpspecs > specs
    $ vi specs
    
    # before
    *link_libgcc:
    %D
    
    # after
    *link_libgcc:
    %{!static:%{!static-libgcc:-rpath /home/xxxx/gcc/10.2/lib64/}} %D
    
    $ mv specs /home/xxxx/gcc/10.2/lib/gcc/x86_64-redhat-linux/10/


    Environment Modulesの設定


    GCC10をEnvironment Modulesで切り替えられるようにする。environment-modulesをインストール後、/etc/modulefiles 配下に、gcc10xのファイルを作成する。

    $ sudo dnf install environment-modules
    
    $ sudo vi /etc/modulefiles/gcc10x
    
    #%Module 1.0
    #
    #  gcc-10.X module for use with 'environment-modules' package:
    #
    
    prepend-path    PATH                    /home/xxxxx/gcc/10.2/bin/
    


    Bazelのビルド


    Bazel をソースビルドする。最新の3.7.4をソースビルドした。
    公式のソースビルド方法はここを参照。手順どおりであり詳細の説明は割愛。


    CUDA、cuDNNのインストール


    CUDA: 11.3、cuDNN: 8.2.0をインストール。
    • CUDAはRPM Fusion Howto/ CUDA を参考にインストールを行う。
    • cuDNNはNVIDIAのダウンロードサイトからダウンロード、インストールを行う。
      2021.5.1時点ではRPM Fusion(Machine Learning repository)からインストールできるcuDNNがCUDA11.1の組み合わせで古いため。


    Tensorflowのビルド


    さて、本題。TensorFlow 2.5-rc2をビルドする。


    virtualenvの設定


    まずはvirtualenv(virtualenvwapper)でTensorflow用の仮想Python環境を作成し、必要なモジュールをインストールする。

    $ mkvirtualenv -p python3  tf2.5-rc2
    $ pip install pip numpy wheel
    $ pip install keras_preprocessing --no-deps

    ビルド


    Githubからソースを取得し、configureスクリプト実行し、ビルドを行う。
    • CUDAのサポートを有効とする。
    • Host compilerにGCC9のgccのパスを指定してあげる。
    • ビルドオプションには"--config=v2"と"--config=nonccl "を指定。


    (tf2.5-rc1) $ git clone -b r2.5 https://github.com/tensorflow/tensorflow.git
    (tf2.5-rc2) $ cd tensorflow
    (tf2.5-rc2) $ ./configure 
    (tf2.5-rc2) $ bazel build \
        --config=cuda \
        --config=v2 \
        --config=nonccl \
        --config=opt \
        //tensorflow/tools/pip_package:build_pip_package
    (tf2.5-rc2) $ ./bazel-bin/tensorflow/tools/pip_package/build_pip_package /tmp/tensorflow_pkg
    (tf2.5-rc2) $ pip install /tmp/tensorflow_pkg/tensorflow-2.5.0rc2-cp39-cp39-linux_x86_64.whl
    


    インストール確認


    • tf.__version__が2.5-rc2であること。
    • GPUデバイスを認識していること。

    (tf2.5-rc2) $ python
    Python 3.9.4 (default, Apr  6 2021, 00:00:00) 
    [GCC 11.0.1 20210324 (Red Hat 11.0.1-0)] on linux
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import tensorflow as tf
    2021-05-01 21:07:37.359112: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcudart.so.11.0
    INFO:tensorflow:Enabling eager execution
    INFO:tensorflow:Enabling v2 tensorshape
    INFO:tensorflow:Enabling resource variables
    INFO:tensorflow:Enabling tensor equality
    INFO:tensorflow:Enabling control flow v2
    >>> tf.__version__
    '2.5.0-rc2'
    >>> from tensorflow.python.client import device_lib
    >>> device_lib.list_local_devices()
    2021-05-01 21:08:05.854665: I tensorflow/core/platform/cpu_feature_guard.cc:142] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations:  SSE3 SSE4.1 SSE4.2 AVX AVX2 FMA
    To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.
    2021-05-01 21:08:05.865237: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcuda.so.1
    2021-05-01 21:08:05.908808: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
    2021-05-01 21:08:05.909879: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1733] Found device 0 with properties: 
    pciBusID: 0000:0a:00.0 name: NVIDIA GeForce GTX 1070 computeCapability: 6.1
    coreClock: 1.7085GHz coreCount: 15 deviceMemorySize: 7.93GiB deviceMemoryBandwidth: 238.66GiB/s
    2021-05-01 21:08:05.909938: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcudart.so.11.0
    2021-05-01 21:08:05.942599: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcublas.so.11
    2021-05-01 21:08:05.942733: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcublasLt.so.11
    2021-05-01 21:08:05.953447: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcufft.so.10
    2021-05-01 21:08:05.970201: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcurand.so.10
    2021-05-01 21:08:05.982505: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcusolver.so.11
    2021-05-01 21:08:05.994212: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcusparse.so.11
    2021-05-01 21:08:05.995767: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcudnn.so.8
    2021-05-01 21:08:05.995901: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
    2021-05-01 21:08:05.996970: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
    2021-05-01 21:08:05.997553: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1871] Adding visible gpu devices: 0
    2021-05-01 21:08:05.997592: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcudart.so.11.0
    2021-05-01 21:08:06.441157: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1258] Device interconnect StreamExecutor with strength 1 edge matrix:
    2021-05-01 21:08:06.441208: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1264]      0 
    2021-05-01 21:08:06.441217: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1277] 0:   N 
    2021-05-01 21:08:06.441408: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
    2021-05-01 21:08:06.441949: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
    2021-05-01 21:08:06.442510: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
    2021-05-01 21:08:06.442984: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1418] Created TensorFlow device (/device:GPU:0 with 6992 MB memory) -> physical GPU (device: 0, name: NVIDIA GeForce GTX 1070, pci bus id: 0000:0a:00.0, compute capability: 6.1)
    [name: "/device:CPU:0"
    device_type: "CPU"
    memory_limit: 268435456
    locality {
    }
    incarnation: 17887149015766682436
    , name: "/device:GPU:0"
    device_type: "GPU"
    memory_limit: 7332429824
    locality {
      bus_id: 1
      links {
      }
    }
    incarnation: 2150787946068778776
    physical_device_desc: "device: 0, name: NVIDIA GeForce GTX 1070, pci bus id: 0000:0a:00.0, compute capability: 6.1"
    ]
    >>> 
    

    OK!

    2021年3月30日火曜日

    2021年の初釣行

    去年は行けなかったので、ひさびさの釣行。

    いつもの渓流に。

    あと、新しく買ったランディングネットも使いたかった。

    前日の雨と雪代で増水、濁りもあるので支流で。


    まずはイワナがヒット!、ランディングネットも使ってみる!!

    うまく、撮るのむずかしい😅(尾が写ってるぐらい...?)

    Pixel 4a防水じゃないし...
    こんどは、防水ケースに入れていけばいいかな?

    あとは、もう一匹。ちっさいけど...ヒット
    ピンボケ...下手だ...

    この後、川を移動してもう一匹、ヒット(オートリリースしたので写真なし)

    午後からちょっと寒くなって終了。

    久々で満足の一日💪🎣

    春もそこまできてる。



    2021年2月22日月曜日

    Jetson (JetPack 4.5) でOpen3D + Open3D-MLをビルドする

    目的


    前回のブログではJetson Nano (Jetpack 4.5) でOpen3DをUSE_SYSTEM_LIBREALSENSE(インストール済みライブラリをリンク)でビルドした。

    今回は、Open3D-MLも含めてビルドする。


    リファレンス




    準備


    Pythonの仮想環境のインストール


    Open3D-MLを含めてビルド後、Python パッケージをインストールすると、システムでインストール済みのpyyamlを競合してしまう。
    このため、Pythonの仮想環境にインストールする。

    好みでvirtualenv virtualenvwrapperを選択。
    $ sudo pip3 install virtualenv virtualenvwrapper
    
    # Add to .bashrc
    # virtualenv and virtualenvwrapper
    export WORKON_HOME=$HOME/.virtualenvs
    export VIRTUALENVWRAPPER_VIRTUALENV=/usr/local/bin/virtualenv
    export VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3
    source /usr/local/bin/virtualenvwrapper.sh
    export VIRTUALENVWRAPPER_ENV_BIN_DIR=bin
    
    $ source .bashrc
    $ mkvirtualenv --python=python3 open3d
    $ workon open3d


    TensorFlowのインストール


    リファレンスを参考にインストール。
    (open3d) $ sudo apt-get update
    (open3d) $ sudo apt-get install libhdf5-serial-dev hdf5-tools libhdf5-dev zlib1g-dev zip libjpeg8-dev liblapack-dev libblas-dev gfortran
    
    (open3d) $ pip3 install numpy==1.16.1 future==0.18.2 mock==3.0.5 h5py==2.10.0 keras_preprocessing==1.1.1 keras_applications==1.0.8 gast==0.2.2 futures protobuf pybind11
    (open3d) $ pip3 install --pre --extra-index-url https://developer.download.nvidia.com/compute/redist/jp/v45 tensorflow


    PyTorchのインストル


    こちらもフォーラムにあるとおりにインストール。
    (open3d) $ wget https://nvidia.box.com/shared/static/cs3xn3td6sfgtene6jdvsxlr366m2dhq.whl -O torch-1.7.0-cp36-cp36m-linux_aarch64.whl
    (open3d) $ sudo apt-get install python3-pip libopenblas-base libopenmpi-dev
    (open3d) $ pip3 install Cython
    (open3d) $ pip3 install numpy torch-1.7.0-cp36-cp36m-linux_aarch64.whl


    Open3Dのビルド


    まずは、TensorFlow、PyTorchのCXX ABIの確認。
    Open3Dのドキュメントにもあるとおり、TensorFlow、PyTorch、Open3Dで異なる CXX ABIであると問題が発生する。
    (open3d) $ python -c "import torch; print(torch._C._GLIBCXX_USE_CXX11_ABI)"
    True
    (open3d) $ python -c "import tensorflow; print(tensorflow.__cxx11_abi_flag__)"
    2021-02-22 18:53:09.238147: I tensorflow/stream_executor/platform/default/dso_loader.cc:49] Successfully opened dynamic library libcudart.so.10.2
    1
    

    CXX ABIはすべてCXX11 ABIであることが確認できた。

    事前にInstall dependenciesにあるソフトウェアをインストール。

    メモリを確保するため、CUIモードで作業。
    (open3d) $ sudo systemctl set-default multi-user.target
    (open3d) $ sudo reboot

    あとは、ビルドするだけ。
    CMakeのオプションで注意する点は以下。
    • BUILD_CUDA_MODULEをON
    • GLIBCXX_USE_CXX11_ABIをON
    • BUNDLE_OPEN3D_MLをONにして、OPEN3D_ML_ROOTにOpen3D-MLのパスを指定
    • BUILD_TENSORFLOW_OPS、BUILD_PYTORCH_OPSをON
    • make pip-packageする前にyapfパッケージをpipでインストールする
      (なぜかmakeで失敗する。たぶん、requirements.txtに必要?)
    $ workon open3d
    (open3d) $ git clone --recursive https://github.com/intel-isl/Open3D
    (open3d) $ git clone https://github.com/intel-isl/Open3D-ML.git
    (open3d) $ cd Open3D/
    (open3d) $ mkdir build && cd build
    (open3d) $ cmake \
        -DPYTHON_EXECUTABLE=$(which python3) \
        -DBUILD_SHARED_LIBS=ON \
        -DBUILD_BENCHMARKS=ON \
        -DBUILD_CUDA_MODULE=ON \
        -DBUILD_CACHED_CUDA_MANAGER=ON \
        -DBUILD_GUI=ON \
        -DGLIBCXX_USE_CXX11_ABI=ON \
        -DBUILD_RPC_INTERFACE=ON \
        -DBUILD_TENSORFLOW_OPS=ON \
        -DBUILD_PYTORCH_OPS=ON \
        -DBUNDLE_OPEN3D_ML=ON \
        -DOPEN3D_ML_ROOT=../../Open3D-ML \
        -DCMAKE_BUILD_TYPE=Release \
        ..
    (open3d) $ make -j 3 
    (open3d) $ sudo make install
    (open3d) $ pip install yapf
    (open3d) $ sudo make pip-package
    (open3d) $ pip install /home/jetson/Open3D/build/lib/python_package/pip_package/open3d-0.12.0+408d9d0a-cp36-cp36m-linux_aarch64.whl
    


    確認


    GUIモードに戻して、Window managerをLXDEに変更する(使えるメモリを増やすため)。
    $ sudo systemctl set-default graphical.target
    $ sudo reboot

    その後、Open3D-MLのサンプルを動作させてみる。

    ただ、Jetson Nanoのメモリ(4GB)では不足しているので
    • モデルはKPConvのみをロード
    • データも1種類(000700)だけロード
    するように変更して実行する。



    表示まで1、2分待ってなんとか動いた〜😅
    (サンプルはPyTorchのモデルを実行するみたい。TensorFlowはどうだろうか?)

    Jetson AGX XavierやJetson Xavier NXとかだとフルで動かせるのかな?

    Open3DをUSE_SYSTEM_LIBREALSENSE(インストール済みライブラリをリンク)でビルドする

     目的


    Open3DはRealSense SDK(librealsense)が組み込まれている。

    ソースビルドした際、デフォルトではlibrealsenseをローカルでビルドし、静的リンクしている。Open3DのビルドオプションはFORCE_RSUSB_BACKEND=ONであったりするため、できればpre-install済みのバイナリを使いたい場合もある。

    ビルド時に「USE_SYSTEM_LIBREALSENSE」を指定すればpre-install済みのバイナリをリンクするはずなのだが、実際には動作していないことがわかった。

    このため、CMakeを修正し、「USE_SYSTEM_LIBREALSENSE」でpre-install済みのlibrealsenseをリンクするように対応する。


    動機


    前回のブログ「Jetson Nano(JetPack 4.5)でlibrealsenseをソースビルドする」でRealSense SDKをソースビルドしてインストールした。

    このlibrealsenseを使ってOpen3DのRealSense IFを使ってみたかった。


    リファレンス




    手順


    Open3Dに出したPull requestはマージされたのでcommit 41fcfdc 以降でビルドすればOK。

    前回のブログのJetson Nano(librealsenseをソースビルドしてインストール)でビルドした(x86のUbuntuでも確認済み)。

    Jetson Nanoの場合は、ARM supportの手順に従ってビルドする。
    cmakeの際に
    • 「BUILD_LIBREALSENSE」と「USE_SYSTEM_LIBREALSENSE」をONにする。
    • 「GLIBCXX_USE_CXX11_ABI」をONにする。
      フラグをOFFにするとOpen3DとlibrealsenseのC++ ABIの違いで#2985の問題が発生する。
      このため、GLIBCXX_USE_CXX11_ABI=OFFを指定するとUSE_SYSTEM_LIBREALSENSEはOFFにしている。

    $ git clone --recursive https://github.com/intel-isl/Open3D
    $ cd Open3D
    $ mkdir build && cd build
    $ cmake \
        -DCMAKE_BUILD_TYPE=Release \
        -DBUILD_SHARED_LIBS=ON \
        -DBUILD_CUDA_MODULE=OFF \
        -DBUILD_GUI=ON \
        -DPYTHON_EXECUTABLE=$(which python3) \
        -DBUILD_LIBREALSENSE=ON \
        -DUSE_SYSTEM_LIBREALSENSE=ON \
        -DGLIBCXX_USE_CXX11_ABI=ON
        ..
    $ make -j3
    $ sudo make install
    $ sudo make install-pip-package
    


    動作確認


    Jetson Nanoで確認。

    Pythonで接続したRealSense(L515)を認識していること。
    $ python
    Python 3.6.9 (default, Oct  8 2020, 12:12:24) 
    [GCC 8.4.0] on linux
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import open3d as o3d
    >>> o3d.t.io.RealSenseSensor.list_devices()
    [Open3D INFO] [0] Intel RealSense L515: f0220613
    [Open3D INFO] 	depth_resolution: [320,240]
    [Open3D INFO] 	depth_format: [RS2_FORMAT_Z16]
    [Open3D INFO] 	visual_preset: [RS2_L500_VISUAL_PRESET_CUSTOM | RS2_L500_VISUAL_PRESET_DEFAULT | RS2_L500_VISUAL_PRESET_LOW_AMBIENT | RS2_L500_VISUAL_PRESET_MAX_RANGE | RS2_L500_VISUAL_PRESET_NO_AMBIENT | RS2_L500_VISUAL_PRESET_SHORT_RANGE]
    [Open3D INFO] 	color_fps: [15 | 30 | 6]
    [Open3D INFO] 	depth_fps: [30]
    [Open3D INFO] 	color_resolution: [640,480]
    [Open3D INFO] 	color_format: [RS2_FORMAT_BGR8 | RS2_FORMAT_BGRA8 | RS2_FORMAT_RGB8 | RS2_FORMAT_RGBA8 | RS2_FORMAT_Y16 | RS2_FORMAT_YUYV]
    [Open3D INFO] Open3D only supports synchronized color and depth capture (color_fps = depth_fps).
    True
    >>> 
    

    RealSenseRecorderのサンプルが動作すること。

    やった〜!
    PRもマージされて、Open3DのContributorになったぞ〜!!

    2021年2月21日日曜日

    Jetson Nano(JetPack 4.5)でlibrealsenseをソースビルドする

    目的


    NVIDIA Jetson NanoでIntel RealSenseをソースビルド(Native Backend)する。

    RealSenseのSDK(librealsense)でNative Backendを使うには、カーネルにパッチを当てたうえでソースビルドが必要。
    しかし、librealsenseのJetson用のパッチはJetPack 4.3用のため、JetPack4.5ではパッチがエラーとなってしまう。
    このため、パッチをJetPack 4.5に対応してビルドする。


    注意事項


    2021.2.21時点
    • 公式のリポジトリ(librealsense)が対応した場合、この内容は古くなってしまうため、必ず最新情報を確認すること。
    • パッチの内容について誤りがある可能性があること(公式の対応でないため)。


    リファレンス



    リポジトリ


    librealsenseをforkしたリポジトリを用意した。



    手順


    カーネルのパッチ適用&ビルド


    JetPack 4.5を書き込んだJetson Nanoを用意する。
    あとは公式の「Building from Source using Native Backend」と同じ手順で問題ない。
    途中でCloneしたカーネルソースのtag を求められるので「tegra-l4t-r32.5」を入力する。

    $ sudo apt update
    $ sudo apt upgrade
    
    $ git clone -b jetson_l4t-r32.5-4.9 https://github.com/NobuoTsukamoto/librealsense.git
    $ cd librealsense
    $ ./scripts/patch-realsense-ubuntu-L4T.sh
    
    ~~~~~~~~~~
    Create the sandbox - NVidia L4T source tree(s)
    Downloading default kernel/kernel-4.9 source...
    Cloning into '/home/jetson/librealsense/Tegra/sources/kernel/kernel-4.9'...
    remote: Enumerating objects: 5207472, done.
    remote: Counting objects: 100% (5207472/5207472), done.
    remote: Compressing objects: 100% (833434/833434), done.
    remote: Total 5207472 (delta 4367040), reused 5173766 (delta 4333423)
    Receiving objects: 100% (5207472/5207472), 943.55 MiB | 1.03 MiB/s, done.
    Resolving deltas: 100% (4367040/4367040), done.
    The default kernel/kernel-4.9 source is downloaded in: /home/jetson/librealsense/Tegra/sources/kernel/kernel-4.9
    Please enter a tag to sync /home/jetson/librealsense/Tegra/sources/kernel/kernel-4.9 source to
    (enter nothing to skip): 
    

    ここで、「tegra-l4t-r32.5」入力してEner。あとはビルドが終わるのを待つ。

    ~~~~~~~~~~
    Copying the patched modules to (~/)
    ~/librealsense
    Move the modified modules into the modules tree
    Insert the modified kernel modules
    Replacing uvcvideo  -
            Applying the patched module ...  succeeded
    Replacing hid_sensor_accel_3d  -
            Applying the patched module ...  succeeded
    Replacing hid_sensor_gyro_3d  -
            Applying the patched module ...  succeeded
    Replacing hid_sensor_trigger  -
            Applying the patched module ...  succeeded
    Replacing hid_sensor_iio_common  -
            Module hid_sensor_iio_common  is used by hid_sensor_trigger
            Unloading dependency hid_sensor_trigger
            Module is resident, unloading ...  succeeded.
            Applying the patched module ...  succeeded      Reloading dependent kernel module hid_sensor_trigger ...  succeeded.
    
    
    Script has completed. Please consult the installation guide for further instruction.
    


    librealsenseのビルド


    あとはlibrealsenseのビルドを行う。
    念のため再起動してcloneしたlibrealsenseディレクトリに移動。

    $ mkdir build && cd build
    $ export PATH=${PATH}:/usr/local/cuda/bin
    $ cmake \
      -DBUILD_WITH_CUDA=ON \
      -DBUILD_WITH_OPENMP=ON \
      -DBUILD_PYTHON_BINDINGS=ON \
      -DCMAKE_BUILD_TYPE=Release \
      ..
    $ make -j$(($(nproc)-1))
    $ sudo make install
    

    Pythonラッパーを使う場合は、/usr/lib/python3/dist-packages/pyrealsense2/にパスを通しておく。

    $ export PYTHONPATH=$PYTHONPATH:/usr/lib/python3/dist-packages/pyrealsense2/


    確認


    realsense-viewerを起動してFrame Metadataが正しそうなことを確認する。


    できたー!

    2021年2月7日日曜日

    Raspberry Pi 4の64bit OSでlibrealsenseをビルドする

    (2021.2.9 Pythonラッパー(pyrealsense2)を使うを追記)

     目的


    Raspberry Pi で RealSense (L515)を扱いたい。
    できるならmatadata, 加速度・ジャイロセンサーも使いたい(UVC Backendでなくて)。
    このため、Raspberry Piのkernelにpatchを適用・ビルドし、RealSenseが動作する(realsense-viewerが実行できる)ところまでを確認した。

    このブログでは、ビルド手順以外でつまったところ、補足的な内容を残す。


    リファレンス


    以下を参考にした。
    1.はRaspberry Piのインストールガイドであるが、UVC_BACKENDでの手順。

    2, 4, 5.はRaspberry Pi のkernelにpatchを適用するものだが、当時のkernel バージョンは4.x系で、現在のバージョン(5.x系)ではうまくいかない。


    ビルド


    ビルド手順については、Githubのリポジトリにアップしたのでそちらを参照。




    つまったこと


    とくにつまったことを記載する。


    kernel pathの作成


    librealsenseにあるpatchは以下だが、そのままRaspberry Piのkernel(5.10.13)には適用できなかった。
    おそらく、最新のkernel ソースの変更に伴うものであると推測。
    このため、上記のpatchをもとにRaspberry Piのkernelに適用できるpatchを作成した。


    Raspberry Pi OS 64 bitのkernel ビルド


    最初、Raspberry Pi上でのkernelのソースビルドを実行しようとした。
    以下は公式ドキュメントの手順。
    しかし、いざビルドを行うとエラーとなって実行できない。。。
    どうやら、Raspberry Pi OS 64 bitでのkernel ビルドはできないとのこと。
    (公式ドキュメントもよく読むとクロスコンパイルの手順はあるけど、64 bitのRaspberry Pi上でのビルド手順はない。。。)
    このため、Host PCでのクロスコンパイルを行うこととした。


    WSL(Windows Subsystem for Linux)でビルドするとSDカードに書き込みできない...


    Raspberry PiのkernelはWSLのUbuntu上でクロスコンパイルが可能(実際できた)。
    しかしながら、SDカードへ書き込む際に問題が発生する。
    rootsf(ext4)への書き込みが必要だが、Windowsが認識できないためマウントできず書き込めない。。。
    結局、Fedora 33(のvirt-managerで動かしているUbuntu)から書き込みを行った。

    ただ、WSL2ではext4もマウントできるようなので、上記は私の認識不足かもしれない。。。


    librealsenseのビルド


    依存関係のあるライブラリの一つにlibapriltag(オプション)がある。
    これをインストールしてlibrealsenseをビルドするとビルドエラーとなる。このため、インストールせずにビルドした。
    /usr/bin/ld: CMakeFiles/rs-pose-apriltag.dir/rs-pose-apriltag.cpp.o: in function `apriltag_manager::apriltag_pose_destroy(apriltag_pose_t*)':
    /home/pi/librealsense-2.41.0/examples/pose-apriltag/rs-pose-apriltag.cpp:106: undefined reference to `matd_destroy'
    /usr/bin/ld: /home/pi/librealsense-2.41.0/examples/pose-apriltag/rs-pose-apriltag.cpp:106: undefined reference to `matd_destroy'
    /usr/bin/ld: CMakeFiles/rs-pose-apriltag.dir/rs-pose-apriltag.cpp.o: in function `main':
    /home/pi/librealsense-2.41.0/examples/pose-apriltag/rs-pose-apriltag.cpp:76: undefined reference to `tag36h11_create()'
    /usr/bin/ld: /home/pi/librealsense-2.41.0/examples/pose-apriltag/rs-pose-apriltag.cpp:92: undefined reference to `tag36h11_destroy(apriltag_family*)'
    /usr/bin/ld: CMakeFiles/rs-pose-apriltag.dir/rs-pose-apriltag.cpp.o: in function `apriltag_manager::detect(unsigned char*, rs2_pose const*) const':
    /home/pi/librealsense-2.41.0/examples/pose-apriltag/rs-pose-apriltag.cpp:123: undefined reference to `estimate_pose_for_tag_homography(apriltag_detection_info_t*, apriltag_pose_t*)'
    /usr/bin/ld: /home/pi/librealsense-2.41.0/examples/pose-apriltag/rs-pose-apriltag.cpp:161: undefined reference to `matd_create'
    collect2: error: ld returned 1 exit status
    make[2]: *** [examples/pose-apriltag/CMakeFiles/rs-pose-apriltag.dir/build.make:92: examples/pose-apriltag/rs-pose-apriltag] エラー 1
    make[1]: *** [CMakeFiles/Makefile2:1919: examples/pose-apriltag/CMakeFiles/rs-pose-apriltag.dir/all] エラー 2
    make[1]: *** 未完了のジョブを待っています....
    


    32 bit版(Raspberry Pi OS)は?


    おそらく、kernelビルドもうまくいくはずだが、試していない。
    余力があれば試してみる。


    Pythonラッパー(pyrealsense2)を使う(2021.2.9追記)


    Pythonでpyrealsense2はimportできるのだが、いざAPIを呼び出すとエラーになることが分かった。


    $ python3
    Python 3.7.3 (default, Jul 25 2020, 13:03:44)
    [GCC 8.3.0] on linux
    Type "help", "copyright", "credits" or "license" for more information.
    <<< import pyrealsense2 as rs
    <<< pipeline = rs.pipeline()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    AttributeError: module 'pyrealsense2' has no attribute 'pipeline'
    <<< quit()
    

    原因はライブラリへのPathが通っていないと推測。
    /usr/lib/python3/dist-packages/pyrealsense2/配下にある
    • pybackend2.cpython-37m-aarch64-linux-gnu.so
    • pyrealsense2.cpython-37m-aarch64-linux-gnu.so
    が、Pathが通っていないためと推測。

    このため、.bashrcにPYTHONPATHを追加することで無事呼び出せることが確認できた。
    export PYTHONPATH=$PYTHONPATH:/usr/lib/python3/dist-packages/pyrealsense2/
    

    2021年1月31日日曜日

    MetadataをTensorFlow Lite モデルに追加してTensorFlow Lite Support Task Libraryで推論する

     目的


    TensorFlow Lite SupportTFLite Model Metadataを使ってTensorFlow Lite モデルにMetadataを追加する。Metadataを追加したモデルでTensorFlow Lite Support Task Libraryで推論してみる。


    前回まで


    前回のブログ「Raspberry PiでTensorFlow Lite Support Task Libraryをやってみる。」ではTensorFlow Lite Support Task Library (C++)をつかってRaspberry Pi 4で動くカメラキャプチャのサンプルを作った。

    このときに使ったTensorFlow Lite モデル(TF-Lite モデル)はmetadataが追加されたモデルを使用した(TensorFlow Hubから入手したモデル)。

    今回はTF-Lite モデルにmetadataを自分で追加して、TensorFlow Lite Support Task Library(TF Lite Support Task Library)で推論することをやってみる。


    Metadataとは?


    公式の「Adding metadata to TensorFlow Lite models」を参照。
    既にあるTF-Lite モデルに補足の情報を追加することができる。


    追加できる情報


    以下の情報が追加できる。
    • モデル全体の説明(概要、著作権、作成者などの情報)
    • 入力の説明(画像フォーマット、正規化、入力幅の情報)
    • 出力の説明とラベル(説明やラベルとのマッピング)

    追加した情報は「Netron」や「AndroidStudio」で参照できる。


    Metaデータを追加する利点


    • 配布するモデルファイルの作成者、著作権を明示できる。
      TF-Lite モデルは端末にダウンロードが前提。
      公開・非公開に関わらず情報があるとありがたい。
    • TF Lite Support Task Libraryを使うと入力、出力情報から必要な前・後処理を行ってくれる。
      • 前処理: リサイズ、正規化、モデルのInput(Float, Int)
      • 後処理: ラベルとのマッピング
    • 推論コードのラッパーを自動生成してくれる。
      TensorFlowのドキュメント「メタデータを使用してモデルインターフェイスを生成する
      (まだよく理解していないので後で試す)


    Medadataを追加するには?


    TF Lite SupportのAPI(Python)を利用する。
    Pythonのpipパッケージはtflite-supportが利用できる。


    Object detectionモデルにmetadataを組み込む


    TensorFlow 1 Detection Model Zooのpre-trainedモデル「ssd_mobiledet_cpu_coco」にMetadataを追加する。
    このモデルはFloatモデルで、InputもFloat32である。

    なお、Metadataを追加しない状態でTF Lite Support Task Libraryで推論するとエラーとなってしまう。
    これは、TF Lite Support Task LibraryがInputの正規化するための情報が無いため。

    $ ./bazel-bin/tensorflow_lite_support/examples/task/vision/pi/object_detector_capture \
        --model_path=/home/pi/ssdlite_mobiledet_cpu.tflite \
        --num_thread=4 --score_threshold=0.5
    Detection failed: Input tensor has type kTfLiteFloat32: it requires specifying NormalizationOptions metadata to preprocess input images.
    

    モデルにmetadataを追加して推論ができることまで確認する。


    参考のコード・サンプル


    Metadetaを追加するライブラリはここで実装。

    MetadataはFlatBuffersのスキーマで定義。

    よく使われるモデルのラッパーの定義。
    (Image classification、Object detection、Image segmentation)
    使い方はドキュメントはテストコードを参照。


    作成したサンプル


    Object detectionモデルにmetadataを書き込むサンプルを作成した。

    前回のtflite-supportのforkリポジトリに追加。



    実装


    Pythonでの実装の概要を説明。

    必要なimport
    from tensorflow_lite_support.metadata import metadata_schema_py_generated as _metadata_fb
    from tensorflow_lite_support.metadata.python.metadata_writers import metadata_info
    from tensorflow_lite_support.metadata.python.metadata_writers import object_detector
    from tensorflow_lite_support.metadata.python.metadata_writers import writer_utils
    

    サンプルではMetadataPopulatorForObjectDetectorクラスの_create_metadataメソッドでmetadataを生成。

    metadata_info.GeneralMdでモデル全体の情報を生成。
        # Creates model info.
        self.general_md = metadata_info.GeneralMd(
          name=self.model_info.name,
          version=self.model_info.version,
          description=("Identify which of a known set of objects might be present "
                       "and provide information about their positions within the "
                       "given image or a video stream."),
          author="Test",
          licenses=("Apache License. Version 2.0 "
                     "http://www.apache.org/licenses/LICENSE-2.0.")
        )
    

    metadata_info.InputImageTensorMdでモデルの入力を生成。
    • norm_mean、norm_stdで正規化のパラメータを指定。
    • tensor_typeは入力モデルから取得(writer_utils.get_input_tensor_types)。
    • モデルはtensorflow.python.platform.resource_loaderを使って読み込み。
        # Load model to buffer.
        self.model_buffer = self._load_file(self.model_file_path)
    
        # Creates input info.
        self.input_md = metadata_info.InputImageTensorMd(
          name="normalized_input_image_tensor",
          description=("Input image to be classified. The expected image is {0} x {1}, with "
                       "three channels (red, blue, and green) per pixel. Each value in the "
                       "tensor is a single byte between {2} and {3}.".format(
                         self.model_info.image_width, self.model_info.image_height,
                         self.model_info.image_min, self.model_info.image_max)),
            norm_mean=self.model_info.mean,
            norm_std=self.model_info.std,
            color_space_type=_metadata_fb.ColorSpaceType.RGB,
            tensor_type=writer_utils.get_input_tensor_types(self.model_buffer)[0])
    

    metadata_info.CategoryTensorMdでモデルの出力を生成。
    • ラベルファイルのパスを渡してあげると、ラベルも一緒に追加してくれる。
        # Creates output info.
        self.output_category_md = metadata_info.CategoryTensorMd(
            name="category",
            description="The categories of the detected boxes.",
            label_files=[
                metadata_info.LabelFileMd(file_path=file_path)
                for file_path in self.label_file_path
            ])
    

    object_detector.MetadataWriter.create_from_metadata_infoで生成したMetadataをモデルに追加する。
    戻り値のMetadataWriterのpopulateメソッドを呼び出すことでMetadataを追加したモデルを得ることができる。あとはバイナリファイルに書き込むだけ。
        self.writer = object_detector.MetadataWriter.create_from_metadata_info(
            model_buffer=self.model_buffer, general_md=self.general_md,
            input_md=self.input_md, output_category_md=self.output_category_md)
        model_with_metadata = self.writer.populate()
    
        with open(self.export_model_path, "wb") as f:
          f.write(model_with_metadata)
    

    ラッパーを使っているので簡単にmetadataを追加できる。

    また、MetadataWriterのget_metadata_jsonメソッドで追加したMetadataをJSONフォーマットで得ることができる。
      def get_metadata_json(self):
        return self.writer.get_metadata_json()
    


    環境の準備


    ホストPCでMetadataを書き込む(Windows、LinuxどちらもOK)。
    今回はWindowsで実施。

    TF Lite Support Task LibraryのPythonパッケージは0.1.0が公開されている(2021.01.30時点)。
    しかし、metadata_writersのラッパーは0.1.0には含まれていないため、tflite-support-nightlyを使う。
    TensorFlowはCPUのみで問題ない。

    $ pip install tflite-support-nightly
    $ pip install tensorflow
    


    Metadataを組み込むモデル、ラベルファイル


    モデル


    ssd_mobiledet_cpu_coco」をダウンロードして目的のTF-Liteモデルを得る。
    model.tfliteをssdlite_mobiledet_cpu.tfliteにリネームして使用。
    $ wget http://download.tensorflow.org/models/object_detection/ssdlite_mobiledet_cpu_320x320_coco_2020_05_19.tar.gz
    $ tar xf ssdlite_mobiledet_cpu_320x320_coco_2020_05_19.tar.gz
    $ mv ssdlite_mobiledet_cpu_320x320_coco_2020_05_19/model.tflite ssdlite_mobiledet_cpu.tflite
    

    ラベル


    coco datasetsのラベルを記載したファイル(labelmap.txt)を用意する。
    今回はTF Lite Supportのテストデータを使用する。


    Metadataを組み込む


    リポジトリをclone後、サンプルのスクリプトを実行する。
    引数は追加するモデル、ラベルファイル、出力ディレクトリ。
    $ git clone https://github.com/NobuoTsukamoto/tflite-support.git
    $ cd tensorflow_lite_support\examples\metadata
    $ mkdir model_with_metadata
    $ python metadata_writer_for_object_detection.py \
        --model_file=PATH_TO\ssdlite_mobiledet_cpu.tflite \
        --label_file=PATH_TO\labelmap.txt \
        --export_directory=.\model_with_metadata
    

    model_with_metadataディレクトリに以下が生成される。
    • ssdlite_mobiledet_cpu.tflite 👈 metadataを追加したモデル
    • ssdlite_mobiledet_cpu.json 👈 追加したmetadataのJSONファイル


    Metadataを確認


    Netronと生成したJSONファイルを確認。

    Netron


    Input(normalized_input_image_tensor)を選択すると追加したmetadataの情報が表示される。
    Metadataを追加したモデル

    追加前と比べるとよくわかる。
    Metadataを追加する前のオリジナルのモデル



    JSON


    出力したmetadataのJSON。
    Netronでは表示できない内容も確認できる。
    {
      "name": "SSDLite with MobileDet-CPU",
      "description": "Identify which of a known set of objects might be present and provide information about their positions within the given image or a video stream.",
      "version": "v1",
      "subgraph_metadata": [
        {
          "input_tensor_metadata": [
            {
              "name": "normalized_input_image_tensor",
              "description": "Input image to be classified. The expected image is 320 x 320, with three channels (red, blue, and green) per pixel. Each value in the tensor is a single byte between 0 and 255.",
              "content": {
                "content_properties_type": "ImageProperties",
                "content_properties": {
                  "color_space": "RGB"
                }
              },
              "process_units": [
                {
                  "options_type": "NormalizationOptions",
                  "options": {
                    "mean": [
                      127.5
                    ],
                    "std": [
                      127.5
                    ]
                  }
                }
              ],
              "stats": {
                "max": [
                  1.0
                ],
                "min": [
                  -1.0
                ]
              }
            }
          ],
          "output_tensor_metadata": [
            {
              "name": "location",
              "description": "The locations of the detected boxes.",
              "content": {
                "content_properties_type": "BoundingBoxProperties",
                "content_properties": {
                  "index": [
                    1,
                    0,
                    3,
                    2
                  ],
                  "type": "BOUNDARIES"
                },
                "range": {
                  "min": 2,
                  "max": 2
                }
              },
              "stats": {
              }
            },
            {
              "name": "category",
              "description": "The categories of the detected boxes.",
              "content": {
                "content_properties_type": "FeatureProperties",
                "content_properties": {
                },
                "range": {
                  "min": 2,
                  "max": 2
                }
              },
              "stats": {
              },
              "associated_files": [
                {
                  "name": "labelmap.txt",
                  "description": "Labels for categories that the model can recognize.",
                  "type": "TENSOR_VALUE_LABELS"
                }
              ]
            },
            {
              "name": "score",
              "description": "The scores of the detected boxes.",
              "content": {
                "content_properties_type": "FeatureProperties",
                "content_properties": {
                },
                "range": {
                  "min": 2,
                  "max": 2
                }
              },
              "stats": {
              }
            },
            {
              "name": "number of detections",
              "description": "The number of the detected boxes.",
              "content": {
                "content_properties_type": "FeatureProperties",
                "content_properties": {
                }
              },
              "stats": {
              }
            }
          ],
          "output_tensor_groups": [
            {
              "name": "detection_result",
              "tensor_names": [
                "location",
                "category",
                "score"
              ]
            }
          ]
        }
      ],
      "author": "Test",
      "license": "Apache License. Version 2.0 http://www.apache.org/licenses/LICENSE-2.0."
    }
    

    Metadataを組み込んだモデルを使ってみる


    前回のブログで使ったサンプルプログラム(Object Detector)を使って推論してみる。
    モデルをRaspberry Pi 4に転送して推論する。
    $ ./bazel-bin/tensorflow_lite_support/examples/task/vision/pi/object_detector_capture \
        --model_path=/home/pi/ssdlite_mobiledet_cpu.tflite \
        --num_thread=4 --score_threshold=0.5
    Detection failed: Input tensor has type kTfLiteFloat32: it requires specifying NormalizationOptions metadata to preprocess input images.
    

    今度はエラーがなく、推論できる👍


    感想


    推論のコードが変更せずに利用できることはとても良いことだと思う。
    (ただ、個人で使う場合、metadataを追加するコストを考えるとあまりメリットがない気も、、、Input, Outputを統一してしまえばいいし、、、)
    次は「メタデータを使用してモデルインターフェイスを生成する」を使ってAndroidアプリを試してみよう。