TensorFlow圖的構建

本文連結地址:

「連結」

本文就來分析tensorflow圖的構建,以及執行圖的裝置和執行緒池的建立。TensorFlow使用資料流圖將計算表示為獨立的指令之間的依賴關係,資料流是一種用於平行計算的常用程式設計模型。在資料流圖中,節點表示計算單元,邊緣表示計算使用或產生的資料。

資料流可以為TensorFlow提供多項優勢:

並行處理:透過使用明確的邊緣來表示操作之間的依賴關係,系統可以輕鬆識別能夠並行執行的操作。

分散式執行:透過使用明確的邊緣來表示操作之間流動的值,TensorFlow 可以將您的程式劃分到連線至不同機器的多臺裝置上(CPU、GPU 和 TPU)。

編譯:TensorFlow 的 XLA 編譯器可以使用資料流圖中的資訊生成更快的程式碼。

可移植性:資料流圖是一種不依賴於語言的模型程式碼表示法。您可以使用 Python 構建資料流圖,將其儲存在 SavedModel 中,並使用 C++ 程式進行恢復,從而實現低延遲的推理。

TensorFlow圖的構建

回目錄

類TensorfowTest。cc中有如下程式碼,它呼叫c api完成一個圖的建立:

TF_Graph* graph = TF_NewGraph();

在檔案c_api。cc中有TF_Graph::TF_Graph建構函式:

graph的型別為Graph,refiner的型別為ShapeRefiner。

TF_Graph::TF_Graph() : graph(tensorflow::OpRegistry::Global()), refiner(graph。versions()。producer(), graph。op_registry()), delete_requested(false), parent(nullptr), parent_inputs(nullptr) { // Tell the shape refiner to also run shape inference on functions。 refiner。set_function_library_for_shape_inference(&graph。flib_def());} TF_Graph* TF_NewGraph() { return new TF_Graph; }

在graph。cc檔案中,建構函式Graph::Graph建立了一個底層的Graph例項。由於是空圖,所以需要新增一個開始節點_SOURCE即後面的root節點和一個最終節點_SINK。

Graph::Graph(const OpRegistryInterface* ops) : ops_(ops, FunctionDefLibrary()), versions_(new VersionDef), arena_(8 << 10 /* 8kB */) { versions_->set_producer(TF_GRAPH_DEF_VERSION); versions_->set_min_consumer(TF_GRAPH_DEF_VERSION_MIN_CONSUMER); // Initialize the name interning table for assigned_device_name。 device_names_。push_back(“”); DCHECK_EQ(0, InternDeviceName(“”)); // Source and sink have no endpoints, just control edges。 NodeDef def; def。set_name(“_SOURCE”); def。set_op(“NoOp”); Status status; Node* source = AddNode(def, &status); TF_CHECK_OK(status); CHECK_EQ(source->id(), kSourceId); def。set_name(“_SINK”); Node* sink = AddNode(def, &status); TF_CHECK_OK(status); CHECK_EQ(sink->id(), kSinkId); AddControlEdge(source, sink);}

在graph。cc檔案中,Graph::AddNode方法完成節點的建立。先透過ops_。LookUpOpDef查詢op型別的定義,然後透過構造引數NodeProperties完成Node的例項化。

Node* Graph::AddNode(NodeDef node_def, Status* status) { const OpDef* op_def; status->Update(ops_。LookUpOpDef(node_def。op(), &op_def)); if (!status->ok()) return nullptr; DataTypeVector inputs; DataTypeVector outputs; status->Update(InOutTypesForNode(node_def, *op_def, &inputs, &outputs)); if (!status->ok()) { *status = AttachDef(*status, node_def); return nullptr; } Node* node = AllocateNode(std::make_shared( op_def, std::move(node_def), inputs, outputs), nullptr); return node;}

透過shape_refiner。cc中的ShapeRefiner::ShapeRefiner和graph_runner。cc中的GraphRunner::GraphRunner生成graph_runner_物件,graph_runner_負責建立執行緒執行裝置:

ShapeRefiner::ShapeRefiner(int graph_def_version, const OpRegistryInterface* ops) : graph_def_version_(graph_def_version), ops_registry_(ops), graph_runner_(Env::Default()) {} GraphRunner::GraphRunner(Env* env) : device_deleter_(NewSingleThreadedCpuDevice(env)), device_(device_deleter_。get()) {}

檔案single_threaded_cpu_device。cc中建立一個單執行緒的執行緒池,這個執行緒只會處理一些簡單的圖的計算,Eigen是一個矩陣運算的庫:

Device* NewSingleThreadedCpuDevice(Env* env) { return new SingleThreadedCpuDevice(env);}class SingleThreadedCpuDevice : public Device { public: explicit SingleThreadedCpuDevice(Env* env) : Device(env, Device::BuildDeviceAttributes(“/device:CPU:0”, DEVICE_CPU, Bytes(256 << 20), DeviceLocality())) { eigen_worker_threads_。num_threads = kNumThreads; eigen_worker_threads_。workers = GraphRunnerThreadPool(); eigen_device_。reset(new Eigen::ThreadPoolDevice( eigen_worker_threads_。workers->AsEigenThreadPool(), eigen_worker_threads_。num_threads)); set_tensorflow_cpu_worker_threads(&eigen_worker_threads_); set_eigen_cpu_device(eigen_device_。get()); }