とあるエンジニアのプログラミング

画像処理、DeepLearning、プログラミング全般の備忘録を残します。

2018年05月

ここでJetsonTX2にKeras(Tensorflow)環境を構築したので、試しにMask-RCNNを動かした。
Jetsonは組み込みPCであるのにもかかわらずソースコードの一切の改変無く動作した。

Screenshot from 2018-05-19 14-25-19


◯環境構築
ここを参考にあらかじめpython3.5のvirtualenv環境を作成しておく。
"keras"という名前のvirtualenvを作成した。

virtualenvのkerasを起動
$workon keras
必要なライブラリをpip installする。
$ pip install numpy
$ pip install jupyter
$ pip install scikit-image
$ pip install Cython
$ pip install pycocotools
# imreadやimresize関連処理が動かない以下のように場合バージョン指定す # $ pip install Pillow==4.3.0

◯git-hubのMask-RCNNをクローンし実行する。
1.Mask R-CNNのダウンロード

2. 学習済みモデルのダウンロード
mask_rcnn_coco.h5


◯実行
$ workon keras
$ jupyter notebook

demo.ipynbを実行する。

モデルの読み込み等に時間が掛かるが、一度読み込んでしまえば
認識時間は、2s程度であった。
手元のGTX1070で0.5s程度、非GPUなノートPC(Core i5)で12s程度なので、
非GPUのPCより爆速で実行することができている。

後にベンチマークをとった。
条件は100回認識かけたときの1回あたりの時間とした。
JetsonTX2: 2.828sec
GTX1070: 0.4556sec
おおよそGTX1070の6.2倍の時間がかかることがわかった。

昨年末にNVIDIAのPrivate ConferenceであるGTC Japan 2017に参加した際にJetson TX2が破格の値段で販売されていたため購入した。

20171213_201123


JetsonとはNVIDIAが満を持して投入した組み込み型PCである。
GPUを搭載しているのにもかかわらず名刺サイズと非常に小さく、
Ubuntuが動作するので開発も容易に行うことが出来る。
サイズとは裏腹にGPUメモリは8GBありGTX1080と同等、電力効率はそれを凌駕するという。
さらに、大抵のDeep Learningコードは改変無く動く。
実際、Keras(Tensorflow)でMask-RCNNを動かしたが特に改変無く動作した。

JetsonTX2にDeep Learning環境を構築したのでその備忘録を残しておく。
なお、Python2.7環境であればググればTensorflowのwhlが落ちているのでそれを探したほうが早い。



◯環境
Jetson TX2
Jetpack3.2
Python3.5

◯セットアップ内容
buzel 0.13.0
Tensorflow 1.8
Keras xxx

◯導入
1. virtualenvによる仮想環境作成
ここを参照
workon で作成した有効化しておく

2. Javaインストール
$ sudo apt-get install openjdk-8-jdk

3. 関連ソフトウェアインストール
$ sudo apt-get install python3-numpy swig python3-dev python3-pip python3-wheel -y

4. Bazel(コンパイル用ツール)インストール。バージョンは0.13で動作確認済み
$ wget --no-check-certificate https://github.com/bazelbuild/bazel/releases/download/0.13.0/bazel-0.13.0-dist.zip
$ unzip bazel-0.13.0-dist.zip -d bazel-0.13.0-dist $ cd bazel-0.13.0-dist $ ./compile.sh $ cp output/bazel /usr/local/bin
5. スワップ領域の確保
コンパイル時にメモリが足りずに落ちるのでスワップ領域を確保する。
$ fallocate -l 8G swapfile
$ chmod 600 swapfile
$ mkswap swapfile
$ sudo swapon swapfile
$ swapon -s

6. tensorflowのインストール
・gitからダウンロード
$ git clone https://github.com/tensorflow/tensorflow

・ tensorflowの設定
$ cd tensorflow
$ ./configure
以下のように設定した。
You have bazel 0.13.0- (@non-git) installed.
Please specify the location of python. [Default is .virtualenv/py35]:


Found possible Python library paths:
  /usr/local/lib/python3.5/dist-packages
  /usr/lib/python3/dist-packages
Please input the desired Python library path to use.  Default is [/usr/local/lib/python3.5/dist-packages]

Do you wish to build TensorFlow with jemalloc as malloc support? [Y/n]: 
jemalloc as malloc support will be enabled for TensorFlow.

Do you wish to build TensorFlow with Google Cloud Platform support? [Y/n]: n
No Google Cloud Platform support will be enabled for TensorFlow.

Do you wish to build TensorFlow with Hadoop File System support? [Y/n]: n
No Hadoop File System support will be enabled for TensorFlow.

Do you wish to build TensorFlow with Amazon S3 File System support? [Y/n]: n
No Amazon S3 File System support will be enabled for TensorFlow.

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

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

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

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

Do you wish to build TensorFlow with OpenCL SYCL support? [y/N]: 
No OpenCL SYCL 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.

Please specify the CUDA SDK version you want to use, e.g. 7.0. [Leave empty to default to CUDA 9.0]: 


Please specify the location where CUDA 9.0 toolkit is installed. Refer to README.md for more details. [Default is /usr/local/cuda]:


Please specify the cuDNN version you want to use. [Leave empty to default to cuDNN 7.0]: 


Please specify the location where cuDNN 7 library is installed. Refer to README.md for more details. [Default is /usr/local/cuda-9.0]:


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

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.
Please note that each additional compute capability significantly increases your build time and binary size. [Default is: 3.5,5.2]


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]: 


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

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


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 tools/bazel.rc for more details.
	--config=mkl         	# Build with MKL support.
	--config=monolithic  	# Config for mostly static monolithic build.
	--config=tensorrt    	# Build with TensorRT support.
Configuration finished

・tensorflowのソース書き換え
/tensorflow/tensorflow/contrib/lite/kernels/internal/Build内で-mfpu=neonを探し、コメントアウトする。
具体的には21行目辺りを以下のように修正。
NEON_FLAGS_IF_APPLICABLE = select({
    ":arm": [
        "-O3",
        "-mfpu=neon",
    ],
    ":armeabi-v7a": [
        "-O3",
        "-mfpu=neon",
    ],
    ":armv7a": [
        "-O3",
        "-mfpu=neon",
    ],
    "//conditions:default": [
        "-O3",
    ],
})

7. whlのビルド
$ bazel build --config=opt --config=cuda //tensorflow/tools/pip_package:build_pip_package

8. whlの生成
bazel-bin/tensorflow/tools/pip_package/build_pip_package /tmp/tensorflow_pkg #put the whl in /tmp/tensorflow_pkg

9. whlのインストール
pip3 install /tmp/tensorflow_pkg/tensorflow-1.6.0rc0-cp35-cp35m-linux_aarch64.whl #depending on your tensorflow/python
(一度whlを作れば使い回せるのでバックアップしておくほうが良い。)

10. スワップ領域を開放しておく
$ sudo swapoff swapfile
$ rm swapfile
11. Kerasのインストール
$ sudo apt-get install keras

動作確認
$ python

import keras

なお、以下も参考に。
Keras(Tensorflow)でMask-RCNNを動かした

WindowsではAnacondaを使用すると複数のPython環境を容易に切り替えることが出来る。
Ubuntuで同様のことをしようとしていくつか方法を試してみたところ、
VirtualenvとそのラッパーのVirtualenvwrapperを利用する方法が一番使い勝手が良かった。
これらの環境管理方法についての備忘録を残しておく。

◯Virtualenv
Pythonのバージョン・環境の管理、切り替えを行うツール。
基本的にはユーザが指定したパスに仮想環境を構築し、それらを呼び出す。

◯Virtualenvwrapper
Virtualenvの補助ツール。環境の切り替えが用意になる。

◯導入
パッケージのダウンロード
$ pip install irtualenv
$ pip install virtualenvwrapper


bashrcに環境を追加する。
$ gedit ~/.bashrc
source /usr/local/bin/virtualenvwrapper.sh
export WORKON_HOME=/.virtualenvs

◯仮想環境用のpythonのバージョンをダウンロードする。
あらかじめ必要なpythonバージョンをダウンロードしておく
$ pyenv install 3.5

◯仮想環境を作る
mkvirtualenv -p バージョン 名前
$ mkvirtualenv -p python35 py35

◯仮想環境有効化
$ workon py35

◯仮想環境無効化
$ deactivate

◯仮想環境一覧の表示
$ workon

以上で一通りの仮想環境の管理を行うことができる。

3次元データを扱う上で可視化は必要不可欠である。
C++のOpenCV環境にはVizという可視化ツールがあり、
簡単にPointCloudやデプスマップを3D表示して確認することが出来る。
しかしながらpython環境では利用できなかった。

OpenCVのVizと類似した機能を持つライブラリがpythonにもいくつかあるようだが、
この中でもJupyter環境でインタラクティブに3D表示ができる機能を持ったライブラリは
非常に容易に使うことができた。
ただし、開発途上のようでリファレンスが不親切なのでここに使い方の備忘録を残しておく。

名称未設定-2


◯ライブラリ
Pyntcloud
https://github.com/daavoo/pyntcloud
http://pyntcloud.readthedocs.io/en/latest/index.html

点群処理も実装されているが、ここでは表示のために使う。

◯導入
pip install git+https://github.com/daavoo/pyntcloud

◯使い方
・import
from pyntcloud import PyntCloud

・plyファイルの読み込み
cloud = PyntCloud.from_file("sample.ply")
・plyファイルの表示
cloud.plot()
主に以下のオプションが使える。サンプルは一番下にソースを載せておいた。
point_size:点群のサイズ(単位不明)
opacity:透過度
polylines:任意の線(axisなどを表示できる)

なお、カメラ位置や視線方向の引数はなく、デフォルトで点群の中心方向を最遠点方向から見るようになっている。
pyntcloud/pyntcloud/plot/points.pyを改変すれば容易に任意方向から見るように修正できるが、特に不便を感じないのでこのまま使う。

・任意のCloud生成
PyntCloudのコンストラクタに点群データを渡せば良い。
点群データとはpandasに格納したindex名が['x','y','z']の点群データのことである。
色を付ける場合にはindex名が['red','green','blue']値も合わせて格納しておけば良い。
サンプルコードは以下。

◯サンプル
TUMのRGBDデータセットのdepthmap
https://vision.in.tum.de/data/datasets/rgbd-dataset/download
を表示するサンプルをここに残しておく。

from pyntcloud import PyntCloud
import numpy as np
import pandas as pd
import cv2

fx = 525
fy = 525
cx = 319.5
cy = 239.5
width = 640
height = 480

def depthToPoint3d(depth):
    xx, yy = np.meshgrid(np.arange(0, width), np.arange(0, height))
    x = (xx - cx) / fx
    y = (yy - cy) / fy
    pos3d = np.dstack((x * depth, y * depth, depth, np.ones([height, width]))).transpose(2,0,1).reshape(4, width*height)
    return pos3d[0:3,:]

def generatePyntCloud(color, depth):
    point3d = depthToPoint3d(depth).T / 1000 #[m]
    cloud_data = np.concatenate((point3d, color.reshape(width*height,3)),axis=1)
    points = pd.DataFrame(cloud_data)
    points.columns = ['x', 'y', 'z', 'blue', 'green', 'red']
    cloud = PyntCloud(points)
    return cloud

def axisPyntCloud(scale):
    # color, [vertexes]
    lines = {
        '0xFF0000': [[0, 0, 0], [scale, 0, 0]],
        '0x00FF00': [[0, 0, 0], [0, scale, 0]],
        '0x0000FF': [[0, 0, 0], [0, 0, scale]]
    }
    return lines

color = cv2.imread('color.png')
depth = cv2.imread('depth.png', cv2.IMREAD_UNCHANGED) / 5 #[mm]
cloud = generatePointCloud(color, depth)
cloud.plot(point_size=0.01, opacity=1.0, polylines=axisPyntCloud(0.5))








Deep Leraningで線画抽出をする方法として有名なHEDという論文がある。
ネットワークの中間層で抽出したエッジを、さらに多階層分合わせることで精度良くエッジを抽出する手法である。
線画抽出として使えそうなため試してみた。
オリジナルのCaffe版は、Caffe自体を改造する必要があるため動かすのに苦労したが、
最近有志が実装したKerasコードは簡単に動作させることができた。
動かしてみた際の備忘録をここに残しておく。


002



○論文
https://arxiv.org/abs/1504.06375

○リポジトリ
https://github.com/lc82111/Keras_HED

○導入
1.HED_KERASのリポジトリをダウンロード
https://github.com/lc82111/Keras_HED

2.VGG16のモデルをダウンロード
https://github.com/MinerKasch/applied_deep_learning/blob/master/vgg16_weights_tf_dim_ordering_tf_kernels_notop.h5
または
https://github.com/fchollet/deep-learning-models/releases/download/v0.1/vgg16_weights_tf_dim_ordering_tf_kernels_notop.h5

3. BSDSのデータセットのダウンロード
http://vcl.ucsd.edu/hed/HED-BSDS

4. ソースコード修正
i) src/networks/hed.py 67行目
VGG16の重みファイルパスを修正(例)
filepath = 'D:/dataset/VGG16/vgg16_weights_tf_dim_ordering_tf_kernels_notop.h5'

ii) src/utils/HED_data_parser.py 27行目~
BSDSデータセットへのパスを修正(例)
self.train_file = os.path.join('D:/dataset/HED-BSDS/', 'train_pair.lst')
self.train_data_dir = 'D:/dataset/HED-BSDS/'

iii) main_segmentation.py 56行目
エポックが大きすぎて終わらないので30程度にしておく。
epochs = 30

5. 学習
main_segmentation.py を実行

6. 結果(自前画像)

002

001

003

004


7. 結果の確認用コード
テストデータで確認する場合



%matplotlib inline
from __future__ import print_function
import os
from src.utils.HED_data_parser import DataParser
from src.networks.hed import hed
from keras.utils import plot_model
from keras import backend as K
from keras import callbacks
import numpy as np
import pdb
from matplotlib import pyplot as plt
import cv2

def generate_minibatches(dataParser, train=True):
    #pdb.set_trace()
    while True:
        if train:
            batch_ids = np.random.choice(dataParser.training_ids, dataParser.batch_size_train)
        else:
            batch_ids = np.random.choice(dataParser.validation_ids, dataParser.batch_size_train*2)
        ims, ems, _ = dataParser.get_batch(batch_ids)
        yield(ims, [ems, ems, ems, ems, ems, ems])

# params
model_name = 'HEDSeg'
model_dir     = os.path.join('checkpoints', model_name)
batch_size = 10

# environment
K.set_image_data_format('channels_last')
K.image_data_format()
os.environ["CUDA_VISIBLE_DEVICES"]= '0'
if not os.path.isdir(model_dir): os.makedirs(model_dir)

# prepare data
dataParser = DataParser(batch_size)

# model
model = hed()
model.load_weights('checkpoints/HEDSeg/checkpoint.24-0.12.hdf5')

    
def show_edge_image(ed):
    plt.gray()
    plt.imshow(ed)
    plt.show()

def show_test_image(im):
    plt.imshow((im + np.array([103.939, 116.779,123.68]))[..., ::-1].astype(np.uint8))
    plt.show()
    
def show_edge_image(ed):
    plt.gray()
    plt.imshow(ed)
    plt.show()

batch_ids = np.random.choice(dataParser.validation_ids, 1)
ims, ems, _ = dataParser.get_batch(batch_ids)

est = labels = model.predict(ims)

show_test_image(ims[0])
show_edge_image(ems[0].reshape(480,480))
show_edge_image(est[0][0].reshape(480,480))
show_edge_image(est[1][0].reshape(480,480))
show_edge_image(est[2][0].reshape(480,480))
show_edge_image(est[3][0].reshape(480,480))
show_edge_image(est[4][0].reshape(480,480))
show_edge_image(est[5][0].reshape(480,480))

自前のデータで試す場合
def generate_batch(im):
    ims = cv2.resize(im, (480, 480)).reshape(1, 480, 480, 3)
    ims = np.array(ims, dtype=np.float32)
    ims[..., 0] -= 103.939
    ims[..., 1] -= 116.779
    ims[..., 2] -= 123.68
    shape = im.shape[:2][::-1]
    return ims, shape

def show_edge_image_resize(im, shape):
    plt.imshow(cv2.resize(im.reshape(480,480), shape[:2]))
    plt.show()

im = cv2.imread('001.jpg')
ims, shape = generate_batch(im)
est = labels = model.predict(ims)    

plt.imshow(im[..., ::-1])
plt.show()
plt.gray()
show_edge_image_resize(est[0][0].reshape(480,480), shape)
show_edge_image_resize(est[1][0].reshape(480,480), shape)
show_edge_image_resize(est[2][0].reshape(480,480), shape)
show_edge_image_resize(est[3][0].reshape(480,480), shape)
show_edge_image_resize(est[4][0].reshape(480,480), shape)
show_edge_image_resize(est[5][0].reshape(480,480), shape)






このページのトップヘ