For learning purposes, how to code this Python example using the TensorFlow C API ?
import tensorflow as tf
hello = tf.constant("hello TensorFlow!")
sess=tf.Session()
print(sess.run(hello))
I have tried it this way:
#include <string.h>
#include <iostream.h>
#include "c_api.h"
int main( int argc, char ** argv )
{
TF_Graph * graph = TF_NewGraph();
TF_SessionOptions * options = TF_NewSessionOptions();
TF_Status * status = TF_NewStatus();
TF_Session * session = TF_NewSession( graph, options, status );
char hello[] = "Hello TensorFlow!";
TF_Tensor * tensor = TF_AllocateTensor( TF_STRING, 0, 0, 8 + TF_StringEncodedSize( strlen( hello ) ) );
TF_OperationDescription * operationDescription = TF_NewOperation( graph, "Const", "hello" );
TF_Operation * operation;
struct TF_Output * output;
TF_StringEncode( hello, strlen( hello ), 8 + ( char * ) TF_TensorData( tensor ), TF_StringEncodedSize( strlen( hello ) ), status );
TF_SetAttrTensor( operationDescription, "value", tensor, status );
TF_SetAttrType( operationDescription, "dtype", TF_TensorType( tensor ) );
operation = TF_FinishOperation( operationDescription, status );
output->oper = operation;
output->index = 0;
TF_SessionRun( session, 0,
0, 0, 0, // Inputs
output, &tensor, 1, // Outputs
&operation, 1, // Operations
0, status );
printf( "%i", TF_GetCode( status ) );
TF_CloseSession( session, status );
TF_DeleteSession( session, status );
TF_DeleteStatus( status );
TF_DeleteSessionOptions( options );
return 0;
}
I am testing it on Windows using the TensorFlow.dll
from:
http://ci.tensorflow.org/view/Nightly/job/nightly-libtensorflow-windows/lastSuccessfulBuild/artifact/lib_package/libtensorflow-cpu-windows-x86_64.zip
The above code GPFs on the TF_SessionRun()
call. Once we find a solution for that, how to retrieve the output ? Should a different tensor be used for the
output ? The above code reuses it in both the output and the operation.
many thanks
There was a bug to solve beside the offset initialization. This version seems to work fine:
#include <iostream.h>
#include "c_api.h"
int main( int argc, char ** argv )
{
TF_Graph * graph = TF_NewGraph();
TF_SessionOptions * options = TF_NewSessionOptions();
TF_Status * status = TF_NewStatus();
TF_Session * session = TF_NewSession( graph, options, status );
char hello[] = "Hello TensorFlow!";
TF_Tensor * tensor = TF_AllocateTensor( TF_STRING, 0, 0, 8 + TF_StringEncodedSize( strlen( hello ) ) );
TF_Tensor * tensorOutput;
TF_OperationDescription * operationDescription = TF_NewOperation( graph, "Const", "hello" );
TF_Operation * operation;
struct TF_Output output;
TF_StringEncode( hello, strlen( hello ), 8 + ( char * ) TF_TensorData( tensor ), TF_StringEncodedSize( strlen( hello ) ), status );
memset( TF_TensorData( tensor ), 0, 8 );
TF_SetAttrTensor( operationDescription, "value", tensor, status );
TF_SetAttrType( operationDescription, "dtype", TF_TensorType( tensor ) );
operation = TF_FinishOperation( operationDescription, status );
output.oper = operation;
output.index = 0;
TF_SessionRun( session, 0,
0, 0, 0, // Inputs
&output, &tensorOutput, 1, // Outputs
&operation, 1, // Operations
0, status );
printf( "status code: %i\n", TF_GetCode( status ) );
printf( "%s\n", ( ( char * ) TF_TensorData( tensorOutput ) ) + 9 );
TF_CloseSession( session, status );
TF_DeleteSession( session, status );
TF_DeleteStatus( status );
TF_DeleteSessionOptions( options );
return 0;
}
Do we have to delete the tensorOutput ? Not sure why we have to add 9 (instead of 8) to get the beginning of the string.
TF_STRING
tensors are encoded using the format described here. In your code, you accounted for space (8 bytes) to encode the one offset, but didn't actually initialize it. To do that, you'd want to add something like:
memset(TF_TensorData(tensor), 0, 8);
Before the call to TF_SetAttrTensor
, as that will set the "offset" of the string element to 0 (which the where you're encoding the one string value).
To your second question: You aren't actually re-using the same tensor
pointer. The comments for TF_SessionRun
suggest that TF_SessionRun
is allocating a new TF_Tensor
object that the caller takes ownership of. So, in your code snippet, the tensor
variable is being overwritten to point to a newly allocated tensor.
Hope that helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With