Apa itu tfcompile?
tfcompile
adalah alat mandiri yang ahead-of-time (AOT) mengompilasi grafik TensorFlow menjadi kode yang dapat dieksekusi. Hal ini dapat mengurangi total ukuran biner, dan juga menghindari
beberapa overhead runtime. Kasus penggunaan standar tfcompile
adalah mengompilasi
grafik inferensi menjadi kode yang dapat dieksekusi untuk perangkat seluler.
Grafik TensorFlow biasanya dijalankan oleh runtime TensorFlow. Hal ini menimbulkan
beberapa overhead runtime untuk eksekusi setiap node dalam grafik. Hal ini juga menyebabkan total ukuran biner yang lebih besar, karena kode untuk runtime TensorFlow harus tersedia, selain grafik itu sendiri. Kode yang dapat dieksekusi yang dihasilkan oleh tfcompile
tidak menggunakan runtime TensorFlow, dan hanya memiliki dependensi pada kernel yang benar-benar digunakan dalam komputasi.
Compiler dibuat di atas framework XLA. Kode yang menjembatani TensorFlow ke framework XLA berada di tensorflow/compiler.
Apa yang dilakukan tfcompile?
tfcompile
mengambil subgrafik, yang diidentifikasi oleh konsep TensorFlow terkait feed dan pengambilan, lalu menghasilkan fungsi yang menerapkan subgrafik tersebut.
feeds
adalah argumen input untuk fungsi, dan fetches
adalah
argumen output untuk fungsi. Semua input harus ditentukan sepenuhnya oleh
feed; subgrafik yang dipangkas yang dihasilkan tidak boleh berisi node Placeholder
atau Variabel. Menentukan semua Placeholder dan Variabel sebagai feed adalah hal yang umum dilakukan, yang
memastikan subgrafik yang dihasilkan tidak lagi berisi node ini. Fungsi yang dihasilkan
dikemas sebagai cc_library
, dengan file header yang mengekspor
tanda tangan fungsi, dan file objek yang berisi implementasi. Pengguna menulis kode untuk memanggil fungsi yang dihasilkan sebagaimana mestinya.
Menggunakan tfcompile
Bagian ini menjelaskan langkah-langkah tingkat tinggi untuk menghasilkan biner yang dapat dieksekusi dengan tfcompile
dari subgrafik TensorFlow. Langkah-langkahnya adalah:
- Langkah 1: Konfigurasi subgrafik untuk dikompilasi
- Langkah 2: Gunakan makro build
tf_library
untuk mengompilasi subgrafik - Langkah 3: Tulis kode untuk memanggil subgrafik
- Langkah 4: Buat biner akhir
Langkah 1: Konfigurasi subgrafik untuk dikompilasi
Identifikasi feed dan pengambilan yang sesuai dengan argumen input dan output
untuk fungsi yang dihasilkan. Kemudian, konfigurasikan feeds
dan fetches
dalam proto
tensorflow.tf2xla.Config
.
# 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" }
}
Langkah 2: Gunakan makro build tf_library untuk mengompilasi subgrafik
Langkah ini mengonversi grafik menjadi cc_library
menggunakan makro build
tf_library
. cc_library
terdiri dari file objek yang berisi kode yang dihasilkan
dari grafik, beserta file header yang memberikan akses ke kode
yang dihasilkan. tf_library
menggunakan tfcompile
untuk mengompilasi grafik TensorFlow menjadi kode yang dapat dieksekusi.
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",
)
Untuk membuat proto GraphDef (test_graph_tfmatmul.pb) untuk contoh ini, jalankan make_test_graphs.py dan tentukan lokasi output dengan tanda --out_dir.
Grafik standar berisi Variables
yang mewakili bobot yang dipelajari melalui pelatihan, tetapi tfcompile
tidak dapat
mengompilasi subgrafik yang berisi Variables
. Alat
freeze_graph.py
mengonversi variabel menjadi konstanta, menggunakan nilai yang disimpan dalam file
checkpoint. Untuk memudahkan, makro tf_library
mendukung argumen freeze_checkpoint
, yang menjalankan alat tersebut. Untuk contoh lainnya, lihat
tensorflow/compiler/aot/tests/BUILD.
Konstanta yang muncul dalam subgrafik yang dikompilasi dikompilasi langsung ke dalam kode yang dihasilkan. Untuk meneruskan konstanta ke dalam fungsi yang dihasilkan, daripada mengompilasinya, cukup teruskan konstanta sebagai feed.
Untuk mengetahui detail tentang makro build tf_library
, lihat
tfcompile.bzl.
Untuk mengetahui detail tentang alat tfcompile
yang mendasarinya, lihat
tfcompile_main.cc.
Langkah 3: Tulis kode untuk memanggil subgrafik
Langkah ini menggunakan file header (test_graph_tfmatmul.h
) yang dihasilkan oleh
makro build tf_library
di langkah sebelumnya untuk memanggil kode yang dihasilkan. File
header terletak di direktori bazel-bin
yang sesuai dengan
paket build, dan diberi nama berdasarkan atribut nama yang ditetapkan pada makro build
tf_library
. Misalnya, header yang dihasilkan untuk test_graph_tfmatmul
akan menjadi test_graph_tfmatmul.h
. Berikut adalah versi singkat dari apa yang
dihasilkan. File yang dihasilkan, di bazel-bin
, berisi komentar tambahan
yang berguna.
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
Class C++ yang dihasilkan disebut MatMulComp
dalam namespace foo::bar
,
karena itu adalah cpp_class
yang ditentukan dalam makro tf_library
. Semua
class yang dihasilkan memiliki API serupa, dengan satu-satunya perbedaan adalah metode
untuk menangani buffer argumen dan hasil. Metode tersebut berbeda berdasarkan jumlah dan
jenis buffer, yang ditentukan oleh argumen feed
dan fetch
ke makro tf_library
.
Ada tiga jenis buffer yang dikelola dalam class yang dihasilkan: args
yang mewakili input, results
yang mewakili output, dan temps
yang mewakili buffer sementara yang digunakan secara internal untuk melakukan komputasi. Secara
default, setiap instance dari class yang dihasilkan mengalokasikan dan mengelola semua
buffer ini untuk Anda. Argumen konstruktor AllocMode
dapat digunakan untuk mengubah perilaku ini. Semua buffer diselaraskan dengan batas 64 byte.
Class C++ yang dihasilkan hanyalah wrapper di sekitar kode tingkat rendah yang dihasilkan oleh XDLA.
Contoh pemanggilan fungsi yang dihasilkan berdasarkan tfcompile_test.cc
:
#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;
}
Langkah 4: Buat biner akhir
Langkah ini menggabungkan library yang dihasilkan oleh tf_library
pada langkah 2 dan kode
yang ditulis pada langkah 3 untuk membuat biner akhir. Di bawah ini adalah contoh file
BUILD bazel
.
# 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",
]
)