tfcompile چیست؟
tfcompile
یک ابزار مستقل که جلوتر از زمان (AOT) کامپایل می TensorFlow نمودار به کد اجرایی است. این می تواند اندازه کل باینری را کاهش دهد و همچنین از برخی هزینه های سربار زمان اجرا جلوگیری کند. معمولی مورد استفاده از tfcompile
این است که تدوین یک گراف استنتاج به کد اجرایی برای دستگاه های تلفن همراه.
نمودار TensorFlow معمولاً توسط زمان اجرا TensorFlow اجرا می شود. این مقداری سربار زمان اجرا را برای اجرای هر گره در گراف متحمل می شود. این همچنین منجر به یک اندازه باینری کل بزرگتر می شود، زیرا کد مربوط به زمان اجرا TensorFlow، علاوه بر خود نمودار، باید در دسترس باشد. کد اجرایی تولید شده توسط tfcompile
کند زمان اجرا TensorFlow استفاده نمی کند، و فقط وابستگی در دانه است که در واقع در محاسبه استفاده می شود.
کامپایلر در بالای چارچوب XLA ساخته شده است. کد پل زدن TensorFlow به منزلگه چارچوب XLA تحت tensorflow / کامپایلر .
tfcompile چه کاری انجام می دهد؟
tfcompile
طول می کشد یک زیرگراف، مشخص شده توسط مفاهیم TensorFlow از خوراک و بازخوانی، و تولید یک تابع است که پیاده سازی است که گراف. feeds
استدلال ورودی برای تابع، و fetches
استدلال خروجی تابع هستند. تمام ورودی ها باید به طور کامل توسط فیدها مشخص شوند. زیرگراف هرس شده به دست آمده نمی تواند حاوی گره های Placeholder یا Variable باشد. معمول است که همه مکانها و متغیرها را بهعنوان فید مشخص کنید، که تضمین میکند زیرگراف حاصل دیگر حاوی این گرهها نیست. تابع تولید می شود به عنوان یک بسته بندی cc_library
، با یک فایل هدر صادرات امضای تابع، و یک فایل حاوی شی پیاده سازی. کاربر کد می نویسد تا تابع تولید شده را در صورت لزوم فراخوانی کند.
با استفاده از tfcompile
این بخش به شرح مراحل سطح بالا برای ایجاد یک باینری اجرایی با tfcompile
از یک زیرگراف TensorFlow. مراحل عبارتند از:
- مرحله 1: زیرگراف را برای کامپایل پیکربندی کنید
- مرحله 2: با استفاده از
tf_library
ساخت ماکرو برای کامپایل گراف - مرحله 3: برای فراخوانی زیرگراف کد بنویسید
- مرحله 4: باینری نهایی را ایجاد کنید
مرحله 1: زیرگراف را برای کامپایل پیکربندی کنید
فیدها و واکشی هایی را که با آرگومان های ورودی و خروجی تابع تولید شده مطابقت دارند، شناسایی کنید. سپس پیکربندی feeds
و fetches
در یک 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" }
}
مرحله 2: از ماکرو ساخت tf_library برای کامپایل زیرگراف استفاده کنید
این مرحله تبدیل به یک نمودار cc_library
با استفاده از tf_library
کلان ساخت. cc_library
شامل یک فایل شی حاوی کد تولید شده از نمودار، همراه با یک فایل هدر که به دسترسی به کد تولید می شود. tf_library
با بهره گیری tfcompile
به کامپایل نمودار TensorFlow به کد اجرایی.
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",
)
برای تولید پروتو GraphDef (test_graph_tfmatmul.pb) برای این مثال، اجرا make_test_graphs.py و مشخص کردن محل خروجی با پرچم --out_dir.
نمودار نمونه حاوی Variables
به نمایندگی از وزن است که از طریق آموزش به دست، اما tfcompile
می توانید یک زیرگراف که حاوی کامپایل نمی Variables
. freeze_graph.py ابزار متغیر تبدیل به ثابت، با استفاده از مقادیر ذخیره شده در یک فایل پاسگاه. به عنوان یک راحتی، tf_library
ماکرو پشتیبانی از freeze_checkpoint
استدلال، اجرا می شود که از ابزار است. برای مثال بیشتر ببینید tensorflow / کامپایلر / AOT / آزمون / BUILD .
ثابت هایی که در زیرگراف کامپایل شده نشان داده می شوند مستقیماً در کد تولید شده کامپایل می شوند. برای ارسال ثابت ها به تابع تولید شده، به جای کامپایل کردن آنها، به سادگی آنها را به عنوان فید ارسال کنید.
برای جزئیات در مورد tf_library
کلان ساخت، و tfcompile.bzl .
برای جزئیات بیشتر در زمینه tfcompile
ابزار، و tfcompile_main.cc .
مرحله 3: برای فراخوانی زیرگراف کد بنویسید
این مرحله با استفاده از فایل هدر ( test_graph_tfmatmul.h
) تولید شده توسط tf_library
کلان ساخت در مرحله قبل به استناد کد تولید می شود. فایل هدر در واقع bazel-bin
دایرکتوری مربوط به بسته ساخت، و بر اساس مجموعه ای نام مشخصه در نام tf_library
کلان ساخت. به عنوان مثال، هدر تولید شده برای test_graph_tfmatmul
خواهد بود test_graph_tfmatmul.h
. در زیر یک نسخه اختصاری از آنچه تولید شده است. فایل تولید شده، در bazel-bin
، شامل نظرات مفید دیگر.
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
تولید C ++ کلاس فراخوانی می شود MatMulComp
در foo::bar
فضای نام، چرا که این بود cpp_class
مشخص شده در tf_library
ماکرو. همه کلاس های تولید شده دارای یک API مشابه هستند، تنها تفاوت آنها در روش های مدیریت بافرهای arg و نتیجه است. این روش تفاوت در تعداد و نوع بافرها، که توسط مشخص شد بر اساس feed
و fetch
استدلال به tf_library
ماکرو.
سه نوع بافر موفق در درون طبقه تولید شده وجود دارد: args
به نمایندگی از ورودی ها، results
به نمایندگی از خروجی ها، و temps
نمایندگی بافر موقت مورد استفاده قرار داخلی برای انجام محاسبات. به طور پیش فرض، هر نمونه از کلاس تولید شده، تمام این بافرها را برای شما تخصیص و مدیریت می کند. AllocMode
استدلال سازنده ممکن است برای تغییر این رفتار. همه بافرها با مرزهای 64 بایتی تراز شده اند.
کلاس C++ تولید شده فقط یک بسته بندی در اطراف کد سطح پایین تولید شده توسط XLA است.
به عنوان مثال از فراخوانی تابع تولید شده بر اساس tfcompile_test.cc
:
#define EIGEN_USE_THREADS
#define EIGEN_USE_CUSTOM_THREAD_POOL
#include <iostream>
#include "third_party/eigen3/unsupported/Eigen/CXX11/Tensor"
#include "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: باینری نهایی را ایجاد کنید
این مرحله ترکیبی از کتابخانه های تولید شده توسط tf_library
در مرحله 2 و کد نوشته شده در مرحله 3 ایجاد یک فایل باینری نهایی. در زیر یک مثال است 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",
]
)