Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"Hello TensorFlow!" using the C API

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

like image 301
Antonio Linares Cañas Avatar asked Jun 05 '17 22:06

Antonio Linares Cañas


2 Answers

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.

like image 178
Antonio Linares Cañas Avatar answered Nov 17 '22 03:11

Antonio Linares Cañas


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.

like image 1
ash Avatar answered Nov 17 '22 02:11

ash