0

My tensorflow model for this example is simple and has been successfully loaded. My question is, to run inference, what do I pass the tf::Session? How do I create the feedDict mentioned here and what are my "outputOps"?

Here's the model in python:

model = tf.keras.Sequential([
tf.keras.layers.Convolution2D(filters, (5, 5), input_shape=(BoardDepth, BoardLength, BoardLength), data_format='channels_first', name='Input'),
tf.keras.layers.Activation('relu', name='Relu'),
tf.keras.layers.MaxPooling2D(pool_size=(2,2), name='Pool'),
tf.keras.layers.Flatten(name="Flatten"),
tf.keras.layers.Dense(BoardSize, activation='softmax', name='Output'),
])

optimizer = tf.train.AdamOptimizer(learning_rate=0.0018)

model.compile(optimizer=optimizer, loss='categorical_crossentropy', metrics=['accuracy']) 

Here's the method used to train the model which uses a generator to feed images in:

earlyExit = keras.callbacks.EarlyStopping(monitor='val_acc', min_delta=0, patience=0)

# Train the model
history = model.fit_generator(generator=gen.generator(),
                steps_per_epoch=gen.stepsPerEpoch(),
                validation_data=valGen.generator(),
                validation_steps=valGen.stepsPerEpoch(),
                epochs=numEpochs, 
                verbose=2, workers=1, callbacks=[earlyExit])

And here's the method used to save the model:

K.set_learning_phase(0)
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    saver = tf.train.Saver(tf.trainable_variables())
    saver.save(sess, './models/test/latestModel')

In case you didn't follow the link above inference is supposed to be done with something like this:

// and run the inference to your liking
auto feedDict = ...
auto outputOps = ...
std::vector<tensorflow::Tensor> outputTensors;
status = session->Run(feedDict, outputOps, {}, &outputTensors);

I've tried following the example here but cannot seem to figure out what I need to pass as outputOps. Do I need to only pass the name of the output node, or do I need to pass every single operation in the model? The different configurations I've tried so far haven't worked.

My code so far looks something like this:

auto shape = tf::TensorShape({ BoardDepth, BoardSize, BoardSize});

// Placeholder until we're using actual input data
float inData[inputSize] = { 0.0 };

tf::Tensor input(tf::DT_FLOAT, shape);
std::copy_n(inData, inputSize, input.flat<float>().data());

std::vector<std::pair<std::string, tf::Tensor>> inputs = {
    { "Input/Conv2D", input },
};

std::vector<std::string> outOps = { "Output/bias:0"};

std::vector<tf::Tensor> outputs;

status = session->Run(inputs, outOps, {}, &outputs);

The input/output names are just set to names I could find that don't throw errors. I really don't know what I'm supposed to be setting them to in order for the model to function as it was trained.

Max C
  • 369
  • 5
  • 16
  • Where is your tf.placeholder? Where is keras.compile? Essentially you only need to pass the output tensor name. – Patwie Jun 19 '18 at 04:12
  • What do I need the tf.placeholder for? I added keras's compile and the code used to save the model to the above python code. I've tried setting outOps = {"Output"} (the name of the last layer) but that didn't work and gave an error "FetchOutputs node Output: not found" – Max C Jun 19 '18 at 04:47
  • 1
    The C++ code you are showing here looks correct to me. At least it is pretty much the same as I am using. Only difference I see so far is, that I do not add the ":0" to any node names. The node that you are supposed to hand over as output node is definitely just the final one. Are you absolutely sure your graph was loaded correctly? Maybe it would help to save the graph as text for ones, so you can inspect, if it saves what you expect, and search for the exact name of the output node. You can do that using tf.train.write_graph(..., as_text=True). – mäggy Jun 19 '18 at 09:14
  • There must be some way to feed data into your graph. The most simple way is using `tf.placeholder`. The trick is just to use `whatever_tensor.name` to get the tensor name and use this in `feed_dict` and `output` – Patwie Jun 19 '18 at 11:30
  • @Patwie, right now I'm using model.fit_generator() to feed data into the model and do not have a tf.placeholder. Is there a way to use that, or to find the input tensor's name? – Max C Jun 19 '18 at 20:03

2 Answers2

1

It works exactly like the given example.py from the repository.

In python you write:

import tensorflow as tf
import numpy as np
sess = tf.Session()

from keras import backend as K
K.set_session(sess)

img = tf.placeholder(tf.float32, shape=(None, 2), name='input_plhdr')

model = tf.keras.Sequential([
    tf.keras.layers.Dense(10, activation='relu', name='Intermediate'),
    tf.keras.layers.Dense(2, activation='softmax', name='Output'),
])

M = model(img)
print('input', img.name)
print('output', M.name)
sess.run(tf.global_variables_initializer())
print('result', sess.run(M, {img: np.array([[42, 43.]], dtype=np.float32)}))

saver = tf.train.Saver(tf.global_variables())
saver.save(sess, './exported/my_model')
tf.train.write_graph(sess.graph, '.', "./exported/graph.pb", as_text=False)

The

print('input', img.name)  # ('input', u'input_plhdr:0')
print('output', M.name)   # ('output', u'sequential/Output_1/Softmax:0')

tells you the name of the input and output. Adapting the inference_cc.cc you just need to fill in the correct names:

// same as in python file
auto data_ = data.flat<float>().data();
data_[0] = 42;
data_[1] = 43;

tensor_dict feed_dict = {
  { "input_plhdr", data },
};

std::vector<tensorflow::Tensor> outputs;
TF_CHECK_OK(sess->Run(feed_dict, {"sequential/Output_1/Softmax:0"}, {}, &outputs));

std::cout << "input           " << data.DebugString() << std::endl;
std::cout << "output          " << outputs[0].DebugString() << std::endl;

In Python I get

Using TensorFlow backend.
('input', u'input_plhdr:0')
('output', u'sequential/Output_1/Softmax:0')
('result', array([[1.0000000e+00, 1.8979743e-11]], dtype=float32))

And C++ returns

input           Tensor<type: float shape: [1,2] values: [42 43]>
output          Tensor<type: float shape: [1,2] values: [1 1.89797431e-11]>
Patwie
  • 4,360
  • 1
  • 21
  • 41
  • So as of now I'm using keras.fit_generator() to feed images to my model, is there a way I can integrate the tf.placeholder with that? Or is it necessary? – Max C Jun 19 '18 at 19:56
  • I've added the current method used to train the model to the code in my example for clarity. – Max C Jun 19 '18 at 20:09
  • I am not that familiar with keras. Any chance to create a full working gist? – Patwie Jun 19 '18 at 20:34
  • I actually just found the input tensors naming scheme keras uses. Thanks for the help with the output tensors name! Unfortunately now I'm running into CUDNN errors – Max C Jun 19 '18 at 20:37
0

Printing out the Output tensors name as Patwie's answer shows how to fix half the problem. The input tensors name for keras seems to be your first layer's name + _input, so in my case my input name was Input_input.

Max C
  • 369
  • 5
  • 16