使用VSCode 调试tensorflow c lib的简单方法

原创文章,转载请注明: 转载自慢慢的回味

本文链接地址: 使用VSCode 调试tensorflow c lib的简单方法


回目录

编写测试程序

编写测试程序TensorflowTest.cpp,放到目录tensorflow/c下面。

//============================================================================
// Name        : TensorflowTest.cpp
// Author      : 
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================
 
#include <iostream>
#include "c_api.h"
#include "c_api_experimental.h"
#include "c_test_util.h"
 
#include <algorithm>
#include <cstddef>
#include <iterator>
#include <memory>
#include <vector>
#include <string.h>
 
using namespace std;
 
int main() {
	cout << "!!!Hello World!!!" << endl; // prints !!!Hello World!!!
	cout << "Hello from TensorFlow C library version" << TF_Version() << endl;
 
	TF_Status* s = TF_NewStatus();
	TF_Graph* graph = TF_NewGraph();
 
	// Construct the graph: A + 2 + B
	TF_Operation* a = Placeholder(graph, s, "A");
	cout << TF_Message(s);
 
	TF_Operation* b = Placeholder(graph, s, "B");
	cout << TF_Message(s);
 
	TF_Operation* one = ScalarConst(1, graph, s, "kone");
	cout << TF_Message(s);
 
	TF_Operation* two = ScalarConst(2, graph, s, "ktwo");
	cout << TF_Message(s);
 
	TF_Operation* three = Add(one, two, graph, s, "kthree");
	cout << TF_Message(s);
 
	TF_Operation* plus2 = Add(a, two, graph, s, "plus2");
	cout << TF_Message(s);
 
	TF_Operation* plusB = Add(plus2, b, graph, s, "plusB");
	cout << TF_Message(s);
 
	TF_Operation* plusC = Add(plusB, three, graph, s, "plusC");
	cout << TF_Message(s);
 
	// Setup a session and a partial run handle.  The partial run will allow
	// computation of A + 2 + B in two phases (calls to TF_SessionPRun):
	// 1. Feed A and get (A+2)
	// 2. Feed B and get (A+2)+B
	TF_SessionOptions* opts = TF_NewSessionOptions();
	TF_EnableXLACompilation(opts, true);
	TF_Session* sess = TF_NewSession(graph, opts, s);
	TF_DeleteSessionOptions(opts);
 
	TF_Output feeds[] = { TF_Output { a, 0 }, TF_Output { b, 0 } };
	TF_Output fetches[] = { TF_Output { plus2, 0 }, TF_Output { plusB, 0 }, TF_Output { plusC, 0 }  };
 
	const char* handle = nullptr;
	TF_SessionPRunSetup(sess, feeds, TF_ARRAYSIZE(feeds), fetches,
			TF_ARRAYSIZE(fetches), NULL, 0, &handle, s);
	cout << TF_Message(s);
 
	// Feed A and fetch A + 2.
	TF_Output feeds1[] = { TF_Output { a, 0 }, TF_Output { b, 0 } };
	TF_Output fetches1[] = { TF_Output { plus2, 0 }, TF_Output { plusB, 0 }, TF_Output { plusC, 0 } };
	TF_Tensor* feedValues1[] = { Int32Tensor(1), Int32Tensor(3) };
	TF_Tensor* fetchValues1[3];
	TF_SessionPRun(sess, handle, feeds1, feedValues1, 2, fetches1, fetchValues1,
			3, NULL, 0, s);
	cout << TF_Message(s);
	cout << *(static_cast<int*>(TF_TensorData(fetchValues1[0]))) << endl;
	cout << *(static_cast<int*>(TF_TensorData(fetchValues1[1]))) << endl;
	cout << *(static_cast<int*>(TF_TensorData(fetchValues1[2]))) << endl;
 
	// Clean up.
	TF_DeletePRunHandle(handle);
	TF_DeleteSession(sess, s);
	cout << TF_Message(s);
	TF_DeleteGraph(graph);
	TF_DeleteStatus(s);
	return 0;
}
添加Bazel build配置

修改tensorflow/c/BUILD文件:
替换

load("//tensorflow:tensorflow.bzl", "tf_cuda_cc_test")

load("//tensorflow:tensorflow.bzl", "tf_cuda_cc_test", "tf_cc_binary")

添加

tf_cc_binary(
    name = "TensorflowTest",
    testonly = 1,
    srcs = [
        "TensorflowTest.cpp",
    ],
    deps = [
        ":c_api_experimental",
        ":c_test_util",
        ":c_api",
    ],
)
编译测试程序
bazel build -s --config=dbg --config=noaws --config=nogcp --config=nohdfs --config=nonccl --config=xla //tensorflow/c:TensorflowTest --verbose_failures
VSCode Debug

启动VSCode,打开Tensorflow源代码根目录。
添加CPP插件

配置Debug,弹出菜单中选择gdb。
然后修改program参数,然后即可在代码上打断点调试
本作品采用知识共享署名 4.0 国际许可协议进行许可。

TensorFlow计算图的创建

原创文章,转载请注明: 转载自慢慢的回味

本文链接地址: TensorFlow计算图的创建


回目录
Tensorflow机器学习任务的核心就是根据用户定义的图graph模型以及参数求解方式进行抽象之后,生成一个由节点和有向边组成,可以确定一个唯一的计算逻辑用有向无环图,称之为计算图。它定义了数据的流转方式,数据的计算方式,以及各种计算之间的相互依赖关系等。节点包括计算节点(Operation)、存储节点(Variable)和数据节点(Placeholder)3类,用于计算数据和存储数据。有向边表示数据的流转方式和依赖。

创建计算图

direct_session.cc中的方法CreateGraphs进行计算图的创建。它调用BuildGraph进行图的创建,调用Partition方法进行图的分区,调用ConvertGraphDefToGraph完成用户图向计算图的转换。

继续阅读“TensorFlow计算图的创建”本作品采用知识共享署名 4.0 国际许可协议进行许可。

TensorFlow计算图的优化

原创文章,转载请注明: 转载自慢慢的回味

本文链接地址: TensorFlow计算图的优化

Tensorflow计算图的优化相当重要,通过对其优化可以显著降低无用代码对计算资源的消耗,尤其在深度学习时,每一此迭代时间的缩短可以大大加速整个学习结果的求解,降低的资源消耗又可以容纳更多的输入并行计算。常见的优化有常量折叠,公共表达式折叠,内联函数展开,算数优化,修剪不可达节点,调试代码去除,自动并行计算,循环优化,内存优化等。
比如如下的图模型,通过算数优化里的FoldMultiplyIntoConv(折叠乘法进卷积),当weighs和scale都是常量的时候,那么可以修改左图到右图,这样就减掉了一个复杂的标量和矩阵的相乘,而仅仅多了一个简单的标量和标量相乘,大大降低了计算量,特别时input非常巨大的时候。

//         Conv2D                             Conv2D
//        /      \                           /      \
//    Transpose  weights*       ->     Transpose    Mul
//       |                                |        /   \
//      Mul                               |    weights  scale
//     /   \                              |
//   input  scale**                     input
//
//  *) weights must be a const
// **) scale must be a const scalar

比如说常量折叠里面的1 * y => y,0 + y => y,0 – y => Neg(y),1 / y => Reciprocal(y)等,这些替代可以减少节点的创建,从而缩减了资源使用。


回目录

计算图分析测试程序

假设我们有以下的tensorflow程序:
程序中,两个Input tensor A和B,一个常量tensor 2,两个计算Operation Plus2和PlusB。
程序计算A+2的结果。
继续阅读“TensorFlow计算图的优化”本作品采用知识共享署名 4.0 国际许可协议进行许可。

TensorFlow Session的Setup

原创文章,转载请注明: 转载自慢慢的回味

本文链接地址: TensorFlow Session的Setup

TensorFlow Session的Setup完成整个Session的创建,设置输入数据类型(feeds)和输出数据类型(fetches)。然后利用图Graph创建基于Session的基本图,开启线程器(Exectors)等待Session开始。


回目录

SessionPRunSetup

主程序调用c_api.cc中的TF_SessionPRunSetup完成Session的Setup。

	TF_SessionPRunSetup(sess, feeds, TF_ARRAYSIZE(feeds), fetches,
			TF_ARRAYSIZE(fetches), NULL, 0, &handle, s);
 
void TF_SessionPRunSetup(TF_Session* session, const TF_Output* inputs,
                         int ninputs, const TF_Output* outputs, int noutputs,
                         const TF_Operation* const* target_opers, int ntargets,
                         const char** handle, TF_Status* status) {
  *handle = nullptr;
 
  if (session->extend_before_run &&
      !ExtendSessionGraphHelper(session, status)) {
    return;
  }
 
  std::vector<string> input_names(ninputs);
  for (int i = 0; i < ninputs; ++i) {
    input_names[i] = OutputName(inputs[i]);
  }
 
  std::vector<string> output_names(noutputs);
  for (int i = 0; i < noutputs; ++i) {
    output_names[i] = OutputName(outputs[i]);
  }
 
  std::vector<string> target_names(ntargets);
  for (int i = 0; i < ntargets; ++i) {
    target_names[i] = target_opers[i]->node.name();
  }
 
  string new_handle;
  status->status = session->session->PRunSetup(input_names, output_names,
                                               target_names, &new_handle);
  if (TF_GetCode(status) == TF_OK) {
    char* buf = new char[new_handle.size() + 1];
    memcpy(buf, new_handle.c_str(), new_handle.size() + 1);
    *handle = buf;
  }
}

继续阅读“TensorFlow Session的Setup”本作品采用知识共享署名 4.0 国际许可协议进行许可。

TensorFlow Executor的创建

原创文章,转载请注明: 转载自慢慢的回味

本文链接地址: TensorFlow Executor的创建


回目录
Session中的Executeors是一个线程池,用来执行每个节点Node的计算。在上一篇Session的setup中,其中调用了GetOrCreateExecutors类创建Executeors。
direct_session.cc中的GetOrCreateExecutors方法用于获取设置callable_options的inputs,fetches,target,然后继续调用CreateExecutors方法创建executors。
继续阅读“TensorFlow Executor的创建”本作品采用知识共享署名 4.0 国际许可协议进行许可。