3次元データへの深層学習の適用
2017/06/21
  • このエントリーをはてなブックマークに追加

はじめに


カブクで深層学習を用いたプロダクト開発をしている大串正矢です。今回は3次元データの検索エンジン作成のために用いた手法であるVoxNetについて書きます。


背景


弊社はお客様から図面のデータを3次元図面で頂く場合があります。その時に図面データだけを入力して過去の情報と照らし合わせることができれば図面のデータに対する知識の度合いに関わらず対応できます。このようなスキル差を埋めて欲しいニーズがあるため3次元データの検索エンジンを作成しています。3次元データの検索エンジンの一部のモジュールにVoxNetで作成した深層学習モデルを使用しています。

VoxNet


VoxNetとは、3次元データをサイズが限定されたx-y-z空間上に写像し(ボクセル化)、その3次元情報を3次元CNNの入力として学習させる方法です。ここでは”Voxnet: A 3d convolutional neural network for real-time object recognition”に記載のサイズである32*32*32のボクセルを採用しています。


画像は下記論文から引用しています。

Maturana, Daniel, and Sebastian Scherer. "Voxnet: A 3d convolutional neural network for real-time object recognition." Intelligent Robots and Systems (IROS), 2015 IEEE/RSJ International Conference on. IEEE, 2015.

ボクセル化の手順



1. 各軸の最長距離(最大値と最小値の差)を求める。
2. 中央値が0になるよう各点を移動する。
3. 最長距離を分割したい数から4引いた数(今回は28)で割った値を算出する。(※ボクセルの両端を0でpaddingし、さらに少数の丸め誤差を考慮にいれ、分割数から4を引いている)
4. 3で算出した値で各点を割る。これで各点は(-15, 15)の範囲の値になる。
5. 各点を最も近い整数に丸める。これで各点は[-15, 15]の範囲の整数になる。
6. 各点が全て正の整数になるよう移動。これで各点は[0, 30]の範囲の整数になる。
7. 30*30*30のデータセットに対し、点が存在する場合は1、存在しない場合は0を入力する。(※ここではさらに、点が存在しても20%の確率で0とし、データにノイズを加え、汎用性を上げている)
8. 32*32*32のデータセットの両端の点を0にして残りの座標に先ほど作成したデータセットを代入。これで両端が0でpaddingされたボクセルデータが完成する。

下記のコードで上記手順を実現しています。


import numpy as np
import sys

TINY_NUMBER=sys.float_info.epsilon
max_dist = 0.0
for it in range(0, 3):
   # find min max & distance in current direction
   min = np.amin(np_pc[:, it])
   max = np.amax(np_pc[:, it])
   dist = max - min

   # find maximum distance
   if dist > max_dist:
       max_dist = dist

   # set middle to 0,0,0
   np_pc[:, it] = np_pc[:, it] - dist / 2 - min

   # covered cells
   covered_cells = 29

   # find voxel edge size
   vox_sz = dist / (covered_cells - 1)

   # if 0 divid
   if vox_sz == 0:
       vox_sz = TINY_NUMBER

   # render pc to size 30x30x30 from middle
   np_pc[:, it] = np_pc[:, it] / vox_sz

for it in range(0, 3):
   np_pc[:, it] = np_pc[:, it] + (covered_cells - 1) / 2

# round to integer array
np_pc = np.rint(np_pc).astype(np.uint32)

# fill voxel arrays
vox = np.zeros([30, 30, 30])
for (pc_x, pc_y, pc_z) in np_pc:
   if random.randint(0, 100) < 80:
       vox[pc_x, pc_y, pc_z] = 1.0

np_vox = np.zeros([1, 32, 32, 32])
np_vox[0, 1:-1, 1:-1, 1:-1] = vox


VoxNetを選んだ理由


  • 計算コスト、メモリの使用コストが少ない

  • 3次元データの場合、2次元画像に比べると情報量が多くなります。理論上学習できるとしても計算量やリソースの問題でそもそも使えないということが問題になります。VoxNetはその点をクリアしているためシングルGPUでも現実的な時間で学習できるようになっています。

  • コードが公開されている

  • 独自の深層学習モデルをゼロから全て実装するには試行錯誤の時間も含めて多大な時間を要するため、すでに研究・実装されているコードを探して、その中から選択することにしました。
    今回はKerasを選択しました。実装コストが少なく、チューニングが必要になった場合はTensorFlowへの移行が比較的容易と考えKerasを採用しました。

    参考にさせて頂いたコードは下記
    Deep-3D-Obj-Recognition

    3次元CNNとは


    Kerasの場合は2次元のCNNは入力層が4次元(データ数、x座標データ、y座標データ、画素数)になります。3次元のデータの場合は5次元となり(データ数、x座標データ、y座標データ、z座標データ、画素数)が入力層に入ります。
    データの並び順はKerasがバックエンドとしてサポートするTensorFlowとTheanoで異なるので注意が必要です。(※ここではTensorFlowを利用する場合を例にしています)

    下記の動画は次元が時間軸の3次元データですが、3次元CNNの分かりやすい解説になっています。前半は2次元画像のCNNについての説明で、82秒からが3次元CNNの説明です。


    今回使用した深層学習モデルのグラフ


    次の図はTensroBoardを使用して実装したVoxNetのモデルを表示しています。TensorBoardは使用しているモデルの構造の関係が分かり、知識共有に有用になるのでオススメです。また、OptimizerにAdamを適用しました。


    工夫した点


    カリキュラムラーニング


    学習データの難易度をData augmentationの手法とパラメータでコントロール可能であると仮説をたて、その場合に有用な手法として知られているカリキュラムラーニングを適用しました。
    後述の通り、カリキュラムラーニングは最終的には採用しませんでした。
    カリキュラムラーニングを行う際により各カリキュラムにおいて学習速度を上げるため幾つかのOptimizerを試しました。ロス率が設定したしきい値を下回った時に次のカリキュラムに進めるようにしました。次の7つのOptimizerを試しました。

  • SGD
  • SGD nest
  • SGD HD
  • Adam
  • NAdam
  • Adam HD
  • Adadelta

  • SGDは学習速度が遅く、かつ、ロス率がしきい値以下で収束しませんでした。
    SGD HD とAdam HD は学習率αを自動で調整する手法になります。カリキュラムラーニングではカリキュラムが進むごとに学習データが異なるため、学習率が適応的に変更される必要があると考え、この2手法に注目しました。Adam HDは学習速度が非常に速いのですが、しきい値以上のロス率で収束する傾向がありました。試行錯誤の結果、カリキュラムラーニングではバランスの取れたSGD HDを採用しました。

    SGD HD と Adam HDについては下記の論文を参考にして実装しました。興味のある方は下記の論文をご参照ください。
    Baydin, Atilim Gunes, et al. "Online Learning Rate Adaptation with Hypergradient Descent." arXiv preprint arXiv:1703.04782 (2017).

    前処理、特徴量抽出処理毎にデータをファイルで保存


    前処理や特徴量抽出は処理時間がかかります。この処理は一度行ったらファイルとして保存して再利用することで無駄な処理時間を削減しました。これによりトライアンドエラーの回数を増やせるので必須の処理になります。

    転移学習


    学習済みのモデルが公開されていたのでそのモデルのデータを使用しました。転移学習には下記のメリットがあります。

  • 学習時間が少なくて済む
  • 良い初期値を与えているため精度が高くなる

  • Data augmentation


    2次元のData augmentationを3次元データにも適用できるように修正しました。学習データによって汎化性能を上げるアプローチが可能になるため選択肢が広がります。またモデル自身の汎化性能を向上させるアプローチとは違い、期待できる効果がある程度明確なため、事前の仮説が立てやすくなります。

    Data augmentationの例(左からフリップ、シェア、ローテーションをかけています。)


    計算速度向上


    深層学習は失敗する回数が多い手法なのでいかに早く失敗するかが重要になります。今回行った学習速度向上の工夫は下記です。
    TensorFlowのコードをソースコードからビルドしCPU最適化オプションをつけました。ただし計算機の環境によって動作しないオプションもあります。またTensorflowのバージョンは1.0.1になります。
    どのオプションが使用可能かはTensorflowのwarningで確認できます。ソースからビルドせずにpipでインストールした場合に発生するオプションの例です。

    
    W tensorflow/core/platform/cpu_feature_guard.cc:45] The TensorFlow library wasn't compiled to use SSE4.1 instructions, but these are available on your machine and could speed up CPU computations.
    W tensorflow/core/platform/cpu_feature_guard.cc:45] The TensorFlow library wasn't compiled to use SSE4.2 instructions, but these are available on your machine and could speed up CPU computations.
    W tensorflow/core/platform/cpu_feature_guard.cc:45] The TensorFlow library wasn't compiled to use AVX instructions, but these are available on your machine and could speed up CPU computations.
    W tensorflow/core/platform/cpu_feature_guard.cc:45] The TensorFlow library wasn't compiled to use AVX2 instructions, but these are available on your machine and could speed up CPU computations.
    W tensorflow/core/platform/cpu_feature_guard.cc:45] The TensorFlow library wasn't compiled to use FMA instructions, but these are available on your machine and could speed up CPU computations.
    

    上記の警告で示された命令オプションがCPUで使用可能な命令オプションで使用していないものになります。

    SSE (Streaming SIMD Extensions)

    4個の32ビット単精度浮動小数点データを一本のレジスタに格納し、同一の命令を一括処理することが出来る処理です。(Wikipedia参照)

    SSE4.1
    SSE4.2

    AVX (Advanced Vector Extensions)

    浮動小数点演算の演算幅がSSEの2倍の256ビットとなり、1命令で8つの単精度浮動小数点演算もしくは4つの倍精度浮動小数点演算を実行することができます。(Wikipedia参照)

    AVX
    AVX2

    FMA

    x86プロセッサにおいて積和演算を実現するための拡張命令がFMAです。(Wikipedia参照)
    FMA

    下記でオプションをかけたビルドを実行します。
    copt={設定したいCPU命令オプション}
    bazelでビルドする場合の例

    
    bazel build -c opt --copt=-mavx --copt=-mavx2 --copt=-mfma
    

    他の速度向上策としてData augmentationの処理をマルチスレッドで並列実行をかけました。これはバッチサイズに依存するのでそれほど効果が大きくはありませんでした。

    Data augmentationを学習データにかけているためCPU処理周りの最適化とマルチスレッドの並列実行は学習の高速化に効果を発揮しました。これらの処理により学習速度は約2倍程度向上しました。

    クラス重み

    今回使用したデータは分類されたデータ数のバランスが良くないため、バリデーションデータにおける性能が良くありませんでした。そこでデータ数の逆数をクラス重みとして与えて学習させてアンバランスなデータにも適用できるようにしました。

    工夫したがあまり効果が見られなかった点


  • カリキュラムラーニング

  • 今回はData augmentationの種類に合わせてカリキュラムを組み実行しました。手法自体は優秀だと思いますがリソースの問題と高速にトライアンドエラーを何回も行うことに向いておらず、途中から方法を変更しました。

  • ResNet

  • 計算リソースを多く割いたため、そもそも学習ができませんでした。

  • X-rayモデル

  • 同じく計算リソースを多く割いたため、そもそも学習ができませんでした。

    使用したデータ


    下記の3次元データを使用しました。10クラスのデータと40クラスのデータは簡単に取得できますが、全クラスの3次元データの場合は申請が必要になります。

    下記のサイトから取得できます。

    PRINCETON MODELNET

    ModelNet


  • 10クラス

  • Download 10-Class Orientation-aligned Subset

  • 40クラス

  • Download 40-Class Subset

    フルのデータセットが必要な場合は下記のサイトからShuran Songさんへメールで申請するとダウンロードするためのMatlabプログラムが頂けます。

    PRINCETON MODELNET

    結果


    Machineのスペック:
    CPU: Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz 8コア
    メモリ: 32GB
    GPU: GeForce GTX 1080

    各結果の精度です。
    ModelNetの40クラスのデータを使用しています。

    TenosorBoardで確認した学習データとValidationデータの学習曲線です。
    TenosrBoardの仕様上(バグ?)、Validationデータの精度が見切れているものがあったので拡大している部分(Validation Accuracy Zoom)も載せています。
    画素の問題で数字が見えない点、学習を途中で終了させているため不揃いな点はご了承ください。




    Method(図上の手法の名前)説明Training data (accuracy)Validation data (accuracy)
    Base line何もなし90%79%
    Shift_x_yData augmentation(x-shift, y-shift)80%80%
    Shift_x_y_biasData augmentation(x-shift, y-shift) +
    クラス重み
    80%83%
    Add_shift_x_y_biasData augmentation(x-shift, y-shift) +
    クラス重み + データ追加(x-shift, y-shift)
    85%85%

    今回のアプローチで特徴的なのはモデルを変えずにデータを加工したり、データの特性を考慮して汎用性を上げている点です。モデルは性能の向上幅が未知数であったり、優秀なモデルでもリソースを大量に消費するため、モデルを改良するというアプローチ行っておりません。


    今後


    独自の深層学習モデルの検討、図面などの別データへの深層学習の適用、転移学習、Data augmentationを用いて限られた教師データに対して効果的な学習を行う予定です。

    最後に


    今回、紹介した手法をさらに高度にして世界でも珍しい3次元データの検索エンジンの性能向上したいエンジニアがいらっしゃれば絶賛採用中なので是非、弊社へ応募してください。

    参考


    Maturana, Daniel, and Sebastian Scherer. "Voxnet: A 3d convolutional neural network for real-time object recognition." Intelligent Robots and Systems (IROS), 2015 IEEE/RSJ International Conference on. IEEE, 2015.

    Baydin, Atilim Gunes, et al. "Online Learning Rate Adaptation with Hypergradient Descent." arXiv preprint arXiv:1703.04782 (2017).

    Bengio, Yoshua, et al. "Curriculum learning." Proceedings of the 26th annual international conference on machine learning. ACM, 2009.


    3D CNN-Action Recognition Part-1

    Keras: Deep Learning for Python

    ModelNet

    3D Object Recognition with Deep Networks

    Building powerful image classification models using very little data
    Streaming SIMD Extensions