vai_q_tensorflowをソースからビルドできない問題

vai_q_tensorflowGithubリポジトリが公開されており,ビルド方法もREADME.mdに記されているが,実行したところBUILDファイルが見つからないと怒られる.vai_q_tensorflowTensorflow r1.15からのフォークであり,これと同様にbazelを用いてビルドするがレシピであるBUILDファイルがなぜか見当たらない..gitignoreを参照したところ,どうやら間違って一部のBUILDファイルを含めないよう設定されているようだ(適当すぎる...).そこでフォーク元のtensorflowからBUILDファイルを取得し配置する必要があった.その他にも問題が複数発生したので対処法を記す.
↓修正済みのリポジトリ github.com

手順1

tensorflowgit pull.vai_q_tensorflowと同階層のディレクトリに配置する.その後tensorflowのブランチをr1.15checkoutしておく.

手順2

次のシェルを実行する

refer my blog

手順3

私の環境では次のエラーも発生した.これはフォーク元のtensorflow側の問題の様だ.それぞれTensorflowGithubに同様のissueが存在した.

#34197

github.com 3つのソースを書き替える必要がある.

#41061

github.com 上記のissueで述べられているが,次の変更を加えることでコンパイルが成功する. github.com

RT(TTU)コアの処理内容・内部構造の調査

patents.google.com

patents.google.com

図などは上記の明細書を参考のこと
TTU - Tree Traversal Unit (nVidiaのTuringコアアーキテクチャから採用された"RTコア"の開発名)
レイトレーシング(Ray Tracing)において、1つの光線毎に、nのプリミティブ(オブジェクトの最小単位,たいてい三角形)への衝突判定を行う必要があるが、愚直に計算するのは非効率.
処理数の削減を行うためにBVH(Bounding Volume Hierarchy)と呼ばれる木構造が導入される.下記のサイトを参照.
shinjiogaki.github.io TTUは,BVHを辿る処理(AABB (Axis Aligned Bounding Box) への衝突判定を含む,数千命令に相当)をハードウェアで実現する.

TTUの具体的処理

用語

SM - Streaming Multi-processor
Compression Block - BVHの部分木に対応するデータブロック

処理

  1. SMから,対象のRay,Compression Blockへのポインタを含んだ命令を受け取る.

  2. Schudulerに命令本体が転送される.Ray,Compression Blockへのポインタはそれぞれ別のLocal Storageに保管される.

  3. Setup Unitに命令本体とCompression Blockへのポインタが転送される.

  4. Setup Unitは、受け取った命令を基にLocal Storageに保存されたRayの情報と,受け取ったCompression Blockへのポインタを基にメモリから取得(キャッシュがヒットすれば即座に取得できる)したCompression Blockのデータを取得する.

  5. Setup Unitは、各Traversal UnitにRayとCompression Blockを送信しCompression Block毎に並列に処理を実行する.疑似コードのOuter Loopに相当するLoopを回す.

  6. Traversal Unitは、処理が完了するとStack Management Unit内部のResultキューにRayが衝突する可能性のあるプリミティブへのポインタを入れる.疑似コードのInner Loopに相当するLoopを回す.後述するがTraversal UnitはAABBへの衝突判定は行うがプリミティブへの衝突判定は行わない.プリミティブへの衝突判定は別のハードウェアで実現する.Resultキューに入ったプリミティブ(へのポインタ)は,プリミティブ専用の衝突判定処理を待機する.

  7. Stack Management Unitは、処理が完了したTraversal Unitが有り,Local StorageにCompression Blockが存在するならばSchedulerにTraversal Unitが再度処理可能であることを通知する.

疑似コード

procedure outerTraversal(Ray, *bvhRoot)
  traversalStack
  traversalStack.push(bvhRoot)
  while traversalStack is not empty do
    *node = traversalStack.pop
    intersectedExternalNodes = innerTraversal(ray,node)
    traversalStack.push(intersectedExternalNodes)
  end do
end
procedure innerTraversal(Ray, *blockRoot)
  intersectedExternalNodes
  localStack.push(blockRoot)
  while localStack is not empty do
    *node = localStack.pop()
    if ray intersects node then
      addToResultQueue(node)
    end
    else if node is TransitionNode then
      intersectedExternalNodes.add(node.externalNodePointer)
    end
    else then
      childNodes = node.childNodes
      sort childNodes
      localStack.push(childNodes)
    end
  return intersectedExternalNodes
  end do
end

内部データ構造

やや具体的な話、実装によって多少変わってくると思う.

Compression Blockのアラインメントの例

struct Compression_Block{ // is restricted to Cache Size
  struct Node nodes[N];
};

Nodeのアラインメントの例

// double fixedは2ワード長の固定小数点型を想定
struct Node{ // Root Node
  char type_id : 2;
  char AABB_Bitmask : 6;
  double x_1; // 2word floating point data
  double x_2;
  double y_1;
  double y_2;
  double z_1;
  double z_2;
  struct Compression_Block *child_ptr;
};
struct Node{ // Internal/Leaf Node
  char type_id : 2;
  char AABB_Bitmask : 6;
  char x_1; // 1Byte=256 step data
  char y_1;
  char y_2;
  struct Compression_Block *child_ptr;
};

nodes 各ノードのデータ,連続配置される.順番は深さ優先,幅優先どちらでもよい.

type_id ノードの種別(root,leaf,transition)を表す

  • transition Compression Blockの境界となるノード,一方のleafノードであり,もう一方のrootとなるようなノード

  • leaf 葉ノード

  • root 根ノード

AABB_Bitmask 後述

x_1,x_2,y_1...等 座標の数値

child_ptr 葉ノードでなければ子ノードへのポインタ,葉ノードであればプリミティブへのポインタ(メモリ上を指す)

各ノードはAABBの情報(3次元直交座標系でおいては2つのベクトル,つまり6つの数値)を持つ.このうち,BVH全体のrootノードは全体座標系(Global Coordinate)における6つの数値を必ず持つ.しかしその子孫であれば,親ノードからの相対座標(Local Coordinate)で指定できる.さらに親ノードの数値を継承する場合、省略することが出来る.これらの工夫により数値の表現に必要なビット数が節約できる.上の構造体を模した疑似コードにおいて,AABB_Bitmaskは親ノードの数値を引き継ぐので省略する座標をビットマスクで表現している.

疲れたのでここまで