#include <stdio.h>
#include <stdlib.h>
#include <string>
#include "tensorflow/c/c_api.h"
/*
* Super basic example of using google tensorflow directly from C
*
*/
// Using stack input data nothing to free
void tensor_free_none(void * data, size_t len, void* arg) {
}
TF_Operation * PlaceHolder(TF_Graph * graph, TF_Status * status, TF_DataType dtype, const char * name) {
TF_OperationDescription * desc = TF_NewOperation(graph, "Placeholder", name);
TF_SetAttrType(desc, "dtype", TF_FLOAT);
return TF_FinishOperation(desc, status);
}
TF_Operation * Const(TF_Graph * graph, TF_Status * status, TF_Tensor * tensor, const char * name) {
TF_OperationDescription * desc = TF_NewOperation(graph, "Const", name);
TF_SetAttrTensor(desc, "value", tensor, status);
TF_SetAttrType(desc, "dtype", TF_TensorType(tensor));
return TF_FinishOperation(desc, status);
}
TF_Operation * Add(TF_Graph * graph, TF_Status * status, TF_Operation * one, TF_Operation * two, const char * name) {
TF_OperationDescription * desc = TF_NewOperation(graph, "AddN", name);
TF_Output add_inputs[2] = {{one, 0}, {two, 0}};
TF_AddInputList(desc, add_inputs, 2);
return TF_FinishOperation(desc, status);
}
int main() {
printf("TensorFlow C library version: %s\n", TF_Version());
//test();
TF_Graph * graph = TF_NewGraph();
TF_SessionOptions * options = TF_NewSessionOptions();
TF_Status * status = TF_NewStatus();
TF_Session * session = TF_NewSession(graph, options, status);
float in_val_one = 4.0f;
float const_two = 2.0f;
TF_Tensor * tensor_in = TF_NewTensor(TF_FLOAT, NULL, 0, &in_val_one, sizeof(float), tensor_free_none, NULL);
TF_Tensor * tensor_out = NULL; // easy access after this is allocated by TF_SessionRun
TF_Tensor * tensor_const_two = TF_NewTensor(TF_FLOAT, NULL, 0, &const_two, sizeof(float), tensor_free_none, NULL);
// Operations
TF_Operation * feed = PlaceHolder(graph, status, TF_FLOAT, "feed");
TF_Operation * two = Const(graph, status, tensor_const_two, "const");
TF_Operation * add = Add(graph, status, feed, two, "add");
// Session Inputs
TF_Output input_operations[] = { feed, 0 };
TF_Tensor ** input_tensors = {&tensor_in};
// Session Outputs
TF_Output output_operations[] = { add, 0 };
TF_Tensor ** output_tensors = {&tensor_out};
TF_SessionRun(session, NULL,
// Inputs
input_operations, input_tensors, 1,
// Outputs
output_operations, output_tensors, 1,
// Target operations
NULL, 0, NULL,
status);
printf("Session Run Status: %d - %s\n", TF_GetCode(status), TF_Message(status) );
printf("Output Tensor Type: %d\n", TF_TensorType(tensor_out));
float * outval = (float*)TF_TensorData(tensor_out);
printf("Output Tensor Value: %.2f\n", *outval);
TF_CloseSession(session, status);
TF_DeleteSession(session, status);
TF_DeleteSessionOptions(options);
TF_DeleteGraph(graph);
TF_DeleteTensor(tensor_in);
TF_DeleteTensor(tensor_out);
TF_DeleteTensor(tensor_const_two);
TF_DeleteStatus(status);
return 0;
}
I am trying to set a special flag in the "const" tensor.
The program allocates a TF_Tensor for this const_two float variable.
TF_Tensor * tensor_const_two = TF_NewTensor(TF_FLOAT, NULL, 0, &const_two, sizeof(float), tensor_free_none, NULL);
But is this TF_Tensor the one that linked with the graph?
Similar to C++ interface, C code also needs to build operation (add node to the graph).
TF_Operation * Const(TF_Graph * graph, TF_Status * status, TF_Tensor * tensor, const char * name) {
TF_OperationDescription * desc = TF_NewOperation(graph, "Const", name);
TF_SetAttrTensor(desc, "value", tensor, status);
TF_SetAttrType(desc, "dtype", TF_TensorType(tensor));
return TF_FinishOperation(desc, status);
}
TF_SetAttrTensor(desc, "value", tensor, status); is where sends the tensor value into the operation.
In tensorflow/c/c_api.cc:
void TF_SetAttrTensor(TF_OperationDescription* desc, const char* attr_name,
TF_Tensor* value, TF_Status* status) {
Tensor t;
status->status = TF_TensorToTensor(value, &t);
if (status->status.ok()) desc->node_builder.Attr(attr_name, t);
}
Basically, TF_TensorToTensor is a copy function, allocate a new tensor, and add this newly allocated one into the graph.
So, if I set some flag in the tensor, here is where I need to add code.
Status TF_TensorToTensor(const TF_Tensor* src, Tensor* dst) {
if (src->dtype == TF_RESOURCE) {
if (src->shape.dims() != 0) {
return InvalidArgument(
"Malformed TF_RESOURCE tensor: expected a scalar, got a tensor with "
"shape ",
src->shape.DebugString());
}
*dst = Tensor(DT_RESOURCE, src->shape);
if (!dst->scalar<ResourceHandle>()().ParseFromString(
string(static_cast<const char*>(TF_TensorData(src)),
TF_TensorByteSize(src)))) {
return InvalidArgument(
"Malformed TF_RESOUCE tensor: unable to parse resource handle");
}
return Status::OK();
}
if (src->dtype != TF_STRING) {
*dst = TensorCApi::MakeTensor(src->dtype, src->shape, src->buffer);
return Status::OK();
}
// TF_STRING tensors require copying since Tensor class expects a sequence of
// string objects.
const tensorflow::int64 num_elements = src->shape.num_elements();
const char* input = reinterpret_cast<const char*>(TF_TensorData(src));
const size_t src_size = TF_TensorByteSize(src);
if (static_cast<tensorflow::int64>(src_size / sizeof(tensorflow::uint64)) <
num_elements) {
return InvalidArgument(
"Malformed TF_STRING tensor; too short to hold number of elements");
}
const char* data_start = input + sizeof(tensorflow::uint64) * num_elements;
const char* limit = input + src_size;
*dst = Tensor(static_cast<DataType>(src->dtype), src->shape);
auto dstarray = dst->flat<string>();
for (tensorflow::int64 i = 0; i < num_elements; ++i) {
tensorflow::uint64 offset =
reinterpret_cast<const tensorflow::uint64*>(input)[i];
if (static_cast<ptrdiff_t>(offset) >= (limit - data_start)) {
return InvalidArgument("Malformed TF_STRING tensor; element ", i,
" out of range");
}
size_t len;
const char* p;
const char* srcp = data_start + offset;
Status status = TF_StringDecode_Impl(srcp, limit - srcp, &p, &len);
if (!status.ok()) return status;
dstarray(i).assign(p, len);
}
return Status::OK();
}
没有评论:
发表评论