- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我正在尝试使用 C API 加载和运行 TensorFlow 图形(我需要在 TensorFlow 项目之外构建,最好不使用 Bazel,所以不能使用 C++)。
该图是一个 3 层 LSTM-RNN,它将 3 个元素的特征向量分类为 9 个类别之一。该图是用 Python 构建和训练的,我已经用 Python 和 C++ 对其进行了测试。
到目前为止,我已经加载了图表,但是在加载图表后我无法运行 session 。我已经进行了相当多的挖掘,但我只找到了一个使用 C API ( here ) 的示例,并且不包括运行图形。
我已经设法将以下内容放在一起,但它会产生段错误(如果我注释掉 TF_SessionRun() 调用,我可以成功运行代码,但当包含 TF_SessionRun() 时我会遇到段错误)。这是代码:
#include "tensorflow/c/c_api.h"
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <string.h>
#include <assert.h>
#include <vector>
#include <algorithm>
#include <iterator>
TF_Buffer* read_file(const char* file);
void free_buffer(void* data, size_t length) {
free(data);
}
static void Deallocator(void* data, size_t length, void* arg) {
free(data);
}
int main() {
// Use read_file to get graph_def as TF_Buffer*
TF_Buffer* graph_def = read_file("tensorflow_model/constant_graph_weights.pb");
TF_Graph* graph = TF_NewGraph();
// Import graph_def into graph
TF_Status* status = TF_NewStatus();
TF_ImportGraphDefOptions* graph_opts = TF_NewImportGraphDefOptions();
TF_GraphImportGraphDef(graph, graph_def, graph_opts, status);
if (TF_GetCode(status) != TF_OK) {
fprintf(stderr, "ERROR: Unable to import graph %s", TF_Message(status));
return 1;
}
else {
fprintf(stdout, "Successfully imported graph\n");
}
// Configure input & provide dummy values
const int num_bytes = 3 * sizeof(float);
const int num_bytes_out = 9 * sizeof(int);
int64_t dims[] = {3};
int64_t out_dims[] = {9};
float values[3] = {-1.04585315e+03, 1.25702492e+02, 1.11165466e+02};
// Setup graph inputs
std::vector<TF_Tensor*> input_values;
TF_Operation* input_op = TF_GraphOperationByName(graph, "lstm_1_input");
TF_Output inputs = {input_op, 0};
TF_Tensor* input = TF_NewTensor(TF_FLOAT, dims, 1, &values, num_bytes, &Deallocator, 0);
input_values.push_back(input);
// Setup graph outputs
TF_Operation* output_op = TF_GraphOperationByName(graph, "output_node0");
TF_Output outputs = {output_op, 0};
std::vector<TF_Tensor*> output_values(9, nullptr);
// Run graph
fprintf(stdout, "Running session...\n");
TF_SessionOptions* sess_opts = TF_NewSessionOptions();
TF_Session* session = TF_NewSession(graph, sess_opts, status);
assert(TF_GetCode(status) == TF_OK);
TF_SessionRun(session, nullptr,
&inputs, &input_values[0], 3,
&outputs, &output_values[0], 9,
nullptr, 0, nullptr, status);
fprintf(stdout, "Successfully run session\n");
TF_CloseSession(session, status);
TF_DeleteSession(session, status);
TF_DeleteSessionOptions(sess_opts);
TF_DeleteImportGraphDefOptions(graph_opts);
TF_DeleteGraph(graph);
TF_DeleteStatus(status);
return 0;
}
TF_Buffer* read_file(const char* file) {
FILE *f = fopen(file, "rb");
fseek(f, 0, SEEK_END);
long fsize = ftell(f);
fseek(f, 0, SEEK_SET);
void* data = malloc(fsize);
fread(data, fsize, 1, f);
fclose(f);
TF_Buffer* buf = TF_NewBuffer();
buf->data = data;
buf->length = fsize;
buf->data_deallocator = free_buffer;
return buf;
}
我不确定 TF_SessionRun 到底哪里出错了,所以非常感谢任何帮助!
更新:我在 gdb 中的 TF_SessionRun 调用处设置了一个断点,当我单步执行它时,我首先得到:线程 1 收到信号 SIGSEGV,段错误。
其次是:
0x0000000100097650 在 ?? ()“找不到当前函数的边界”
我最初认为这是因为 TensorFlow 库未使用调试符号编译,但此后使用调试符号对其进行编译并在 gdb 中获得相同的输出。
自从我的原始帖子以来,我找到了一个 TensorFlow C 示例 here (但是作者指出它未经测试)。因此,我已经根据他们的示例重写了我的代码,并使用 TensorFlow 的 c_api.h 头文件仔细检查了所有内容。我现在还从 C++ 文件中调用 C API(正如上例中所做的那样)。尽管如此,我仍然从 gdb 获得相同的输出。
更新 2:为确保我的图形正确加载,我使用了 C API 中的一些 TF_Operation 函数(TF_GraphNextOperation() 和 TF_OperationName())来检查图形操作,并将这些与在 Python 中加载图形时的操作进行了比较。输出看起来是正确的,而且我可以从操作中检索属性(例如使用 TF_OperationNumOutputs()),所以看起来图表确实加载正确。
如果有使用 TensorFlow 的 C API 经验的人提供建议,我们将不胜感激。
最佳答案
在尝试 C api 中的函数并密切关注占位符的维度后,我设法解决了这个问题。我最初的段错误是由于将错误的操作名称字符串传递给 TF_GraphOperationByName()
而导致的,但是段错误只发生在 TF_SeesionRun()
处,因为这是它尝试的第一个地方访问该操作。对于面临相同问题的任何人,这是我解决问题的方法:
首先,检查您的操作以确保它们被正确分配。在我的例子中,由于在 Python 中获取操作名称时出错,我提供给 input_op
的操作名称不正确。我从 Python 获得的错误操作名称是“lstm_4_input”。通过使用 C API 在加载的图形上运行以下命令,我发现这是不正确的:
n_ops = 700
for (int i=0; i<n_ops; i++)
{
size_t pos = i;
std::cout << "Input: " << TF_OperationName(TF_GraphNextOperation(graph, &pos)) << "\n";
}
其中 n_ops
是图中的操作数。这将打印出您的操作名称;在这种情况下,我可以看到没有“lstm_4_input”,但有一个“lstm_1_input”,所以我相应地更改了值。此外,它验证了我的输出操作“output_node0”是正确的。
一旦我解决了段错误,还有一些其他问题变得清晰,所以这里是完整的工作代码,带有详细注释,供遇到类似问题的任何人使用:
#include "tensorflow/c/c_api.h"
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <string.h>
#include <assert.h>
#include <vector>
#include <algorithm>
#include <iterator>
#include <iostream>
TF_Buffer* read_file(const char* file);
void free_buffer(void* data, size_t length) {
free(data);
}
static void Deallocator(void* data, size_t length, void* arg) {
free(data);
// *reinterpret_cast<bool*>(arg) = true;
}
int main() {
// Use read_file to get graph_def as TF_Buffer*
TF_Buffer* graph_def = read_file("tensorflow_model/constant_graph_weights.pb");
TF_Graph* graph = TF_NewGraph();
// Import graph_def into graph
TF_Status* status = TF_NewStatus();
TF_ImportGraphDefOptions* graph_opts = TF_NewImportGraphDefOptions();
TF_GraphImportGraphDef(graph, graph_def, graph_opts, status);
if (TF_GetCode(status) != TF_OK) {
fprintf(stderr, "ERROR: Unable to import graph %s", TF_Message(status));
return 1;
}
else {
fprintf(stdout, "Successfully imported graph\n");
}
// Create variables to store the size of the input and output variables
const int num_bytes_in = 3 * sizeof(float);
const int num_bytes_out = 9 * sizeof(float);
// Set input dimensions - this should match the dimensionality of the input in
// the loaded graph, in this case it's three dimensional.
int64_t in_dims[] = {1, 1, 3};
int64_t out_dims[] = {1, 9};
// ######################
// Set up graph inputs
// ######################
// Create a variable containing your values, in this case the input is a
// 3-dimensional float
float values[3] = {-1.04585315e+03, 1.25702492e+02, 1.11165466e+02};
// Create vectors to store graph input operations and input tensors
std::vector<TF_Output> inputs;
std::vector<TF_Tensor*> input_values;
// Pass the graph and a string name of your input operation
// (make sure the operation name is correct)
TF_Operation* input_op = TF_GraphOperationByName(graph, "lstm_1_input");
TF_Output input_opout = {input_op, 0};
inputs.push_back(input_opout);
// Create the input tensor using the dimension (in_dims) and size (num_bytes_in)
// variables created earlier
TF_Tensor* input = TF_NewTensor(TF_FLOAT, in_dims, 3, values, num_bytes_in, &Deallocator, 0);
input_values.push_back(input);
// Optionally, you can check that your input_op and input tensors are correct
// by using some of the functions provided by the C API.
std::cout << "Input op info: " << TF_OperationNumOutputs(input_op) << "\n";
std::cout << "Input data info: " << TF_Dim(input, 0) << "\n";
// ######################
// Set up graph outputs (similar to setting up graph inputs)
// ######################
// Create vector to store graph output operations
std::vector<TF_Output> outputs;
TF_Operation* output_op = TF_GraphOperationByName(graph, "output_node0");
TF_Output output_opout = {output_op, 0};
outputs.push_back(output_opout);
// Create TF_Tensor* vector
std::vector<TF_Tensor*> output_values(outputs.size(), nullptr);
// Similar to creating the input tensor, however here we don't yet have the
// output values, so we use TF_AllocateTensor()
TF_Tensor* output_value = TF_AllocateTensor(TF_FLOAT, out_dims, 2, num_bytes_out);
output_values.push_back(output_value);
// As with inputs, check the values for the output operation and output tensor
std::cout << "Output: " << TF_OperationName(output_op) << "\n";
std::cout << "Output info: " << TF_Dim(output_value, 0) << "\n";
// ######################
// Run graph
// ######################
fprintf(stdout, "Running session...\n");
TF_SessionOptions* sess_opts = TF_NewSessionOptions();
TF_Session* session = TF_NewSession(graph, sess_opts, status);
assert(TF_GetCode(status) == TF_OK);
// Call TF_SessionRun
TF_SessionRun(session, nullptr,
&inputs[0], &input_values[0], inputs.size(),
&outputs[0], &output_values[0], outputs.size(),
nullptr, 0, nullptr, status);
// Assign the values from the output tensor to a variable and iterate over them
float* out_vals = static_cast<float*>(TF_TensorData(output_values[0]));
for (int i = 0; i < 9; ++i)
{
std::cout << "Output values info: " << *out_vals++ << "\n";
}
fprintf(stdout, "Successfully run session\n");
// Delete variables
TF_CloseSession(session, status);
TF_DeleteSession(session, status);
TF_DeleteSessionOptions(sess_opts);
TF_DeleteImportGraphDefOptions(graph_opts);
TF_DeleteGraph(graph);
TF_DeleteStatus(status);
return 0;
}
TF_Buffer* read_file(const char* file) {
FILE *f = fopen(file, "rb");
fseek(f, 0, SEEK_END);
long fsize = ftell(f);
fseek(f, 0, SEEK_SET); //same as rewind(f);
void* data = malloc(fsize);
fread(data, fsize, 1, f);
fclose(f);
TF_Buffer* buf = TF_NewBuffer();
buf->data = data;
buf->length = fsize;
buf->data_deallocator = free_buffer;
return buf;
}
注意:在我之前的尝试中,我使用“3”和“9”作为 的
,认为这些与我的输入和输出张量的长度有关(我将 3 维特征分类为 9 个类之一)。事实上,这些只是输入/输出张量的数量,因为张量的维数在它们被实例化时会提前处理。在这里使用 .size() 成员函数很容易(当使用 ninputs
和 noutputs
参数TF_SessionRun()std::vector
来保存 TF_Output
时)。
希望这是有道理的,并有助于为将来发现自己处于类似情况的任何人理清流程!
关于c - 使用 TF_SessionRun 在 C(而非 C++)中运行 TensorFlow 图形时出现段错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44305647/
#include using namespace std; class C{ private: int value; public: C(){ value = 0;
这个问题已经有答案了: What is the difference between char a[] = ?string?; and char *p = ?string?;? (8 个回答) 已关闭
关闭。此题需要details or clarity 。目前不接受答案。 想要改进这个问题吗?通过 editing this post 添加详细信息并澄清问题. 已关闭 7 年前。 此帖子已于 8 个月
除了调试之外,是否有任何针对 c、c++ 或 c# 的测试工具,其工作原理类似于将独立函数复制粘贴到某个文本框,然后在其他文本框中输入参数? 最佳答案 也许您会考虑单元测试。我推荐你谷歌测试和谷歌模拟
我想在第二台显示器中移动一个窗口 (HWND)。问题是我尝试了很多方法,例如将分辨率加倍或输入负值,但它永远无法将窗口放在我的第二台显示器上。 关于如何在 C/C++/c# 中执行此操作的任何线索 最
我正在寻找 C/C++/C## 中不同类型 DES 的现有实现。我的运行平台是Windows XP/Vista/7。 我正在尝试编写一个 C# 程序,它将使用 DES 算法进行加密和解密。我需要一些实
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 1
有没有办法强制将另一个 窗口置于顶部? 不是应用程序的窗口,而是另一个已经在系统上运行的窗口。 (Windows, C/C++/C#) 最佳答案 SetWindowPos(that_window_ha
假设您可以在 C/C++ 或 Csharp 之间做出选择,并且您打算在 Windows 和 Linux 服务器上运行同一服务器的多个实例,那么构建套接字服务器应用程序的最明智选择是什么? 最佳答案 如
你们能告诉我它们之间的区别吗? 顺便问一下,有什么叫C++库或C库的吗? 最佳答案 C++ 标准库 和 C 标准库 是 C++ 和 C 标准定义的库,提供给 C++ 和 C 程序使用。那是那些词的共同
下面的测试代码,我将输出信息放在注释中。我使用的是 gcc 4.8.5 和 Centos 7.2。 #include #include class C { public:
很难说出这里问的是什么。这个问题是含糊的、模糊的、不完整的、过于宽泛的或修辞性的,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开它,visit the help center 。 已关
我的客户将使用名为 annoucement 的结构/类与客户通信。我想我会用 C++ 编写服务器。会有很多不同的类继承annoucement。我的问题是通过网络将这些类发送给客户端 我想也许我应该使用
我在 C# 中有以下函数: public Matrix ConcatDescriptors(IList> descriptors) { int cols = descriptors[0].Co
我有一个项目要编写一个函数来对某些数据执行某些操作。我可以用 C/C++ 编写代码,但我不想与雇主共享该函数的代码。相反,我只想让他有权在他自己的代码中调用该函数。是否可以?我想到了这两种方法 - 在
我使用的是编写糟糕的第 3 方 (C/C++) Api。我从托管代码(C++/CLI)中使用它。有时会出现“访问冲突错误”。这使整个应用程序崩溃。我知道我无法处理这些错误[如果指针访问非法内存位置等,
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。 关闭 7 年前。
已关闭。此问题不符合Stack Overflow guidelines 。目前不接受答案。 要求我们推荐或查找工具、库或最喜欢的场外资源的问题对于 Stack Overflow 来说是偏离主题的,因为
我有一些 C 代码,将使用 P/Invoke 从 C# 调用。我正在尝试为这个 C 函数定义一个 C# 等效项。 SomeData* DoSomething(); struct SomeData {
这个问题已经有答案了: Why are these constructs using pre and post-increment undefined behavior? (14 个回答) 已关闭 6
我是一名优秀的程序员,十分优秀!