Vengineerの戯言

人生は短いけど、長いです。人生を楽しみましょう!

Tensor Comprehensions、メモ

 

2018年3月18日に作成したメモですが、「Tensor Comprehensions」の活動がほぼ止まっているので、公開しときます。

 

Facebook AI Researchが公開したTensor Comprehensions 

 

ソースコードを調べているのですが、なかなか手ごわいです。

 

とりあえず、ソースコードを調査結果をまとめる前に、

 

 

Facebook AI Researchが2018年2月14日、バレンタイン・ディに公開した「Tensor Comprehensions」ついてのちょっとした概要をスライドにしてみました。

 

また、Twitterにツイートしたものをメモとしてまとめておきます。

 

  Tensor Comprehensions の特徴。
    カスタムレイヤーへの入力テンソルのサイズは、パラメータ化するのではなく、
    決まったサイズとして扱うことで、最適化を図るというもの。
    Poolingも、2x2 や 3x3 とかもそれぞれ別のレイヤーとしている。

  基本的には、カスタムレイヤーを作るための道具。。
  なので、PyTorchやCaffe2だけでなく、
  他のMLフレームワークでも利用可能だと。
  現時点では、CUDA 専用って感じだけど。

 

  Tensor Comprehensionsのレイヤー例

    Max Poolingは、

      def maxpool(float(B, C, H, W) input) -> (output) {{
        output(b, c, h, w) max= input(b, c, h * {sH} + kh, w * {sW} + kw) where kh in 0:{kH}, kw in 0:{kW}
      }}

   のように定義するけど、使うときに、kHとkWが決まって、最適化する

 

    matmul = tc.define(lang, name="matmul")
    
   を定義し、

   mat1, mat2 = torch.randn(3, 4).cuda(), torch.randn(4, 5).cuda()

   にて、CUDA用のTensor (入力)を宣言

   out = matmul(mat1, mat2)

  にて、out (出力)を計算する。

 

   Range Inference とは、入力テンソルから出力テンソルを求めるときの範囲(二次元なら、i, j の範囲)。
   Specialization とは、入力テンソルのサイズを決める。

 

  lang = """
    def matmul(float(M,N) A, float(N,K) B) -> (output) {
    output(i, j) +=! A(i, kk) * B(kk, j)
  }
  """

  から Halide IR に変換し、Range Inference and Specialization を行う。

 

  Tensor Comprehensionsの目的は、

    カスタムレイヤーをかける人が限られているので、
    それを普通の人でもある程度の性能が出るようにするための道具。
    だと思う。

 

  Tensor Comprehensions の autotuner は基本的には、遺伝的アルゴリズム。
  その最適化を選び出すための候補は、違うものを使って求めている。

 

  TensorFlow XLAやNNVMのようなグラフ最適化(複数レイヤー間の最適化)をするようなものではない。

 

  Autotuner は、

    matmul = tc.define(lang, name="matmul")
    mat1, mat2 = torch.randn(100, 400).cuda(), torch.randn(400, 500).cuda()
    matmul.autotune(mat1, mat2, **tc.autotuner_settings)
    out = matmul(mat1, mat2)

  のように、関数を実行する前に、autotune すればいい。

    out1 = matmul(mat1, mat2, cache=cache_file)
    # the second time we run the kernel, we skip the compilation since it was
    # already compiled earlier
    out2 = matmul(mat1, mat2)

   ということで、cache引数に、キャッシュファイル名を指定できる

 

  matmul = tc.define(lang, name="matmul")
  matmul.autotune((3, 4), (4, 5), cache=True, **tc.small_sizes_autotuner_settings)
  matmul.autotune((100, 400), (400, 500), cache=True, **tc.autotuner_settings)

  の入力テンソルのサイズを分けて、autotune すればいい。

 

  matmul = tc.define(lang, name="matmul")
  matmul.autotune((3, 4), (4, 5), cache=cache, **tc.small_sizes_autotuner_settings)
  tc.decode(cache + ".options")

  キャッシュしてファイルは、tc.decode にて、デコードできる。

 

  tc.GlobalDebugInit(["--dump_cuda=true"])

  matmul = tc.define(tc.database['matmul']['lang'], name='matmul')
  mat1, mat2 = torch.randn(3, 4).cuda(), torch.randn(4, 5).cuda()
  out = matmul(mat1, mat2)

  -dump_cuda=true で生成されたCUDAコードが表示される

 

  Caffe2との統合は、推論のみ。

  The integration with Caffe2 is very basic at the moment. 
  We do not provide autotuner support for Caffe2 and welcome contributions from community.

  ということで、Caffe2との統合はまだまだだと。

 

  今気づいたんだけど、Tensor Comprehensionsの Andre Adams さん

  https://andrew.adams.pub/ 

  GoogleからFacebookに移っていたんですね。。

 

  Tesor Comprehenstionsは、PYBIND11を使って、C++の世界をPythonに取り込んでいる。