AOT derlemesini kullanma

tfder nedir?

tfcompile, erken aşamada (AOT) TensorFlow grafiklerini yürütülebilir kod halinde derleyen bağımsız bir araçtır. Toplam ikili program boyutunu azaltabilir ve bazı çalışma zamanı ek yüklerini önleyebilir. tfcompile işlevinin tipik bir kullanım alanı, çıkarım grafiğini mobil cihazlar için yürütülebilir kod halinde derlemektir.

TensorFlow grafiği normalde TensorFlow çalışma zamanı tarafından çalıştırılır. Bu durum, grafikteki her bir düğümün yürütülmesi için bir miktar çalışma zamanı ek yüküne neden olur. Grafiğin kendisine ek olarak TensorFlow çalışma zamanı kodunun da kullanılabilir olması gerektiğinden, bu durum daha büyük bir toplam ikili program boyutuna da yol açar. tfcompile tarafından oluşturulan yürütülebilir kod, TensorFlow çalışma zamanını kullanmaz ve yalnızca hesaplamada kullanılan çekirdeklere bağımlıdır.

Derleyici, XLA çerçevesinin üzerine oluşturulur. TensorFlow'u XLA çerçevesine bağlayan kod, tensorflow/compiler altında bulunur.

tfder ne işe yarar?

tfcompile, TensorFlow'un feed ve getirme kavramlarıyla tanımlanan bir alt grafiği alır ve bu alt grafiği uygulayan bir işlev oluşturur. feeds, işlevin giriş bağımsız değişkenleridir. fetches ise işlevin çıkış bağımsız değişkenleridir. Tüm girişler, feed'ler tarafından tamamen belirtilmelidir. Ortaya çıkan ayıklanan alt grafik, Yer Tutucu veya Değişken düğümleri içeremez. Tüm Yer Tutucu ve Değişkenlerin feed olarak belirtilmesi yaygın bir uygulamadır. Bu da, elde edilen alt grafiğin artık bu düğümleri içermemesini sağlar. Oluşturulan işlev, işlev imzasını dışa aktaran bir üstbilgi dosyası ve uygulamayı içeren bir nesne dosyasıyla cc_library olarak paketlenir. Kullanıcı, oluşturulan işlevi uygun şekilde çağırmak için kod yazar.

tfder kullanma

Bu bölümde, bir TensorFlow alt grafiğinden tfcompile ile yürütülebilir bir ikili program oluşturmak için üst düzey adımlar açıklanmaktadır. Adımlar aşağıdaki gibidr:

  • 1. adım: Derlenecek alt grafiği yapılandırın
  • 2. Adım: Alt grafiği derlemek için tf_library oluşturma makrosunu kullanın
  • 3. Adım: Alt grafiği çağırmak için kod yazın
  • 4. Adım: Son ikili dosyayı oluşturma

1. adım: Derlenecek alt grafiği yapılandırın

Oluşturulan işlevin giriş ve çıkış bağımsız değişkenlerine karşılık gelen feed'leri ve getirmeleri tanımlayın. Ardından bir tensorflow.tf2xla.Config protokolünde feeds ve fetches özelliklerini yapılandırın.

# Each feed is a positional input argument for the generated function.  The order
# of each entry matches the order of each input argument.  Here “x_hold” and “y_hold”
# refer to the names of placeholder nodes defined in the graph.
feed {
  id { node_name: "x_hold" }
  shape {
    dim { size: 2 }
    dim { size: 3 }
  }
}
feed {
  id { node_name: "y_hold" }
  shape {
    dim { size: 3 }
    dim { size: 2 }
  }
}

# Each fetch is a positional output argument for the generated function.  The order
# of each entry matches the order of each output argument.  Here “x_y_prod”
# refers to the name of a matmul node defined in the graph.
fetch {
  id { node_name: "x_y_prod" }
}

2. Adım: Alt grafiği derlemek için tf_library derleme makrosu kullanın

Bu adım, tf_library derleme makrosunu kullanarak grafiği bir cc_library biçimine dönüştürür. cc_library, grafikten oluşturulan kodu içeren bir nesne dosyasından ve oluşturulan koda erişim sağlayan bir başlık dosyasından oluşur. tf_library, TensorFlow grafiğini yürütülebilir kodda derlemek için tfcompile kullanır.

load("//tensorflow/compiler/aot:tfcompile.bzl", "tf_library")

# Use the tf_library macro to compile your graph into executable code.
tf_library(
    # name is used to generate the following underlying build rules:
    # <name>           : cc_library packaging the generated header and object files
    # <name>_test      : cc_test containing a simple test and benchmark
    # <name>_benchmark : cc_binary containing a stand-alone benchmark with minimal deps;
    #                    can be run on a mobile device
    name = "test_graph_tfmatmul",
    # cpp_class specifies the name of the generated C++ class, with namespaces allowed.
    # The class will be generated in the given namespace(s), or if no namespaces are
    # given, within the global namespace.
    cpp_class = "foo::bar::MatMulComp",
    # graph is the input GraphDef proto, by default expected in binary format.  To
    # use the text format instead, just use the ‘.pbtxt’ suffix.  A subgraph will be
    # created from this input graph, with feeds as inputs and fetches as outputs.
    # No Placeholder or Variable ops may exist in this subgraph.
    graph = "test_graph_tfmatmul.pb",
    # config is the input Config proto, by default expected in binary format.  To
    # use the text format instead, use the ‘.pbtxt’ suffix.  This is where the
    # feeds and fetches were specified above, in the previous step.
    config = "test_graph_tfmatmul.config.pbtxt",
)

Bu örnekte GraphDef protosunu (test_graph_tfmatmul.pb) oluşturmak için make_test_graphs.py komutunu çalıştırın ve --out_dir işaretiyle çıkış konumunu belirtin.

Tipik grafikler, eğitim aracılığıyla öğrenilen ağırlıkları temsil eden Variables içerir ancak tfcompile, Variables içeren bir alt grafiği derleyemez. freeze_graph.py aracı, bir kontrol noktası dosyasında depolanan değerleri kullanarak değişkenleri sabit değerlere dönüştürür. Kolaylık olması açısından tf_library makrosu, aracı çalıştıran freeze_checkpoint bağımsız değişkenini destekler. Daha fazla örnek için tensorflow/compiler/aot/tests/BUILD sayfasına bakın.

Derlenen alt grafikte gösterilen sabitler, doğrudan oluşturulan kodda derlenir. Sabit değerleri derlenmek yerine, oluşturulan işleve geçirmek için feed olarak iletmeniz yeterlidir.

tf_library derleme makrosu ile ilgili ayrıntılar için tfcompile.bzl adresini inceleyin.

Temel tfcompile aracıyla ilgili ayrıntılar için tfcompile_main.cc sayfasına göz atın.

3. Adım: Alt grafiği çağırmak için kod yazın

Bu adım, oluşturulan kodu çağırmak için önceki adımda tf_library derleme makrosu tarafından oluşturulan başlık dosyasını (test_graph_tfmatmul.h) kullanır. Başlık dosyası, derleme paketine karşılık gelen bazel-bin dizininde bulunur ve tf_library derleme makrosunda ayarlanan ad özelliğine göre adlandırılır. Örneğin, test_graph_tfmatmul için oluşturulan üst bilgi test_graph_tfmatmul.h olur. Oluşturulanların kısaltılmış bir versiyonunu aşağıda bulabilirsiniz. Oluşturulan bazel-bin dosyasında faydalı ek yorumlar yer alıyor.

namespace foo {
namespace bar {

// MatMulComp represents a computation previously specified in a
// TensorFlow graph, now compiled into executable code.
class MatMulComp {
 public:
  // AllocMode controls the buffer allocation mode.
  enum class AllocMode {
    ARGS_RESULTS_AND_TEMPS,  // Allocate arg, result and temp buffers
    RESULTS_AND_TEMPS_ONLY,  // Only allocate result and temp buffers
  };

  MatMulComp(AllocMode mode = AllocMode::ARGS_RESULTS_AND_TEMPS);
  ~MatMulComp();

  // Runs the computation, with inputs read from arg buffers, and outputs
  // written to result buffers. Returns true on success and false on failure.
  bool Run();

  // Arg methods for managing input buffers. Buffers are in row-major order.
  // There is a set of methods for each positional argument.
  void** args();

  void set_arg0_data(float* data);
  float* arg0_data();
  float& arg0(size_t dim0, size_t dim1);

  void set_arg1_data(float* data);
  float* arg1_data();
  float& arg1(size_t dim0, size_t dim1);

  // Result methods for managing output buffers. Buffers are in row-major order.
  // Must only be called after a successful Run call. There is a set of methods
  // for each positional result.
  void** results();


  float* result0_data();
  float& result0(size_t dim0, size_t dim1);
};

}  // end namespace bar
}  // end namespace foo

Oluşturulan C++ sınıfı, tf_library makrosunda belirtilen cpp_class olduğundan foo::bar ad alanında MatMulComp olarak adlandırılır. Oluşturulan tüm sınıflarda benzer bir API bulunur. Tek fark, bağımsız değişken ve sonuç arabelleklerini işleme yöntemleridir. Bu yöntemler, tf_library makrosuna yönelik feed ve fetch bağımsız değişkenleri tarafından belirtilen tamponların sayısına ve türlerine göre farklılık gösterir.

Oluşturulan sınıfta yönetilen üç tür tampon vardır: Girişleri temsil eden args, çıkışları temsil eden results ve hesaplamayı gerçekleştirmek için dahili olarak kullanılan geçici arabellekleri temsil eden temps. Varsayılan olarak, oluşturulan sınıfın her örneği bu arabelleklerin tamamını sizin için ayırır ve yönetir. Bu davranışı değiştirmek için AllocMode kurucu bağımsız değişkeni kullanılabilir. Tüm arabellekler 64 baytlık sınırlara hizalanmıştır.

Oluşturulan C++ sınıfı, XLA tarafından oluşturulan alt düzey kodun etrafında bulunan bir sarmalayıcıdır.

tfcompile_test.cc temel alınarak oluşturulan işlevi çağırma örneği:

#define EIGEN_USE_THREADS
#define EIGEN_USE_CUSTOM_THREAD_POOL

#include <iostream>
#include "third_party/eigen3/unsupported/Eigen/CXX11/Tensor"
#include "third_party/tensorflow/compiler/aot/tests/test_graph_tfmatmul.h" // generated

int main(int argc, char** argv) {
  Eigen::ThreadPool tp(2);  // Size the thread pool as appropriate.
  Eigen::ThreadPoolDevice device(&tp, tp.NumThreads());


  foo::bar::MatMulComp matmul;
  matmul.set_thread_pool(&device);

  // Set up args and run the computation.
  const float args[12] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
  std::copy(args + 0, args + 6, matmul.arg0_data());
  std::copy(args + 6, args + 12, matmul.arg1_data());
  matmul.Run();

  // Check result
  if (matmul.result0(0, 0) == 58) {
    std::cout << "Success" << std::endl;
  } else {
    std::cout << "Failed. Expected value 58 at 0,0. Got:"
              << matmul.result0(0, 0) << std::endl;
  }

  return 0;
}

4. Adım: Son ikili dosyayı oluşturma

Bu adım, 2. adımda tf_library tarafından oluşturulan kitaplıkla 3. adımda yazılan kodu birleştirerek nihai bir ikili program oluşturur. Aşağıda örnek bir bazel DERLEME dosyası gösterilmektedir.

# Example of linking your binary
# Also see //tensorflow/compiler/aot/tests/BUILD
load("//tensorflow/compiler/aot:tfcompile.bzl", "tf_library")

# The same tf_library call from step 2 above.
tf_library(
    name = "test_graph_tfmatmul",
    ...
)

# The executable code generated by tf_library can then be linked into your code.
cc_binary(
    name = "my_binary",
    srcs = [
        "my_code.cc",  # include test_graph_tfmatmul.h to access the generated header
    ],
    deps = [
        ":test_graph_tfmatmul",  # link in the generated object file
        "//third_party/eigen3",
    ],
    linkopts = [
          "-lpthread",
    ]
)