1
votes

i want to try a code structure:

  • train_input_fn_try(): generate data, return feature dict and label; the data will produce from tf.data.Dataset.from_tensor_slices((tf.random_uniform([100,5]),tf.random_uniform([100],maxval=4,dtype=tf.int32)));
  • in main func: i called tf.estimator.DNNClassifier to get classifier, then called classifier.train(input_fn=lambda :train_input_fn_try(batch_size=3),steps=6) to train.

but, i found that i must called sess.run(iterator.initializer) before iterator.get_next().

I don't know where sess.run(iterator.initializer) should be called without destroying the code structure? in main func or in train_input_fn_try func? and how to do?

Here is an example of code that can't work:

def train_input_fn_try(batch_size=2,epoch=1,shuffle=True):
    dataset=tf.data.Dataset.from_tensor_slices((tf.random_uniform([100,5]),tf.random_uniform([100],maxval=4,dtype=tf.int32)))
    if shuffle:
        dataset=dataset.shuffle(10000)
    dataset=dataset.repeat(epoch)
    dataset=dataset.batch(batch_size)
    iterator=dataset.make_initializable_iterator()
    with tf.Session() as sess:
        sess.run(iterator.initializer)
    text,label=iterator.get_next()
    return {"text":text},label

with tf.Session() as sess:
    my_feature_columns=[]
    my_feature_columns.append(tf.feature_column.numeric_column(key="text",shape=[5]))
    clf=tf.estimator.DNNClassifier(feature_columns=my_feature_columns,
                                   hidden_units=[10,10],n_classes=4)
    clf.train(input_fn=lambda :train_input_fn_try(batch_size=3),steps=6)

the runtime error is:

FailedPreconditionError (see above for traceback): GetNext() failed because the iterator has not been initialized. Ensure that you have run the initializer operation for this iterator before getting the next element. [[Node: IteratorGetNext = IteratorGetNextoutput_shapes=[[?,5], [?]], output_types=[DT_FLOAT, DT_INT32], _device="/job:localhost/replica:0/task:0/device:CPU:0"]] [[Node: dnn/head/assert_range/assert_less/Assert/Assert/_106 = _Recvclient_terminated=false, recv_device="/job:localhost/replica:0/task:0/device:GPU:0", send_device="/job:localhost/replica:0/task:0/device:CPU:0", send_device_incarnation=1, tensor_name="edge_83_dnn/head/assert_range/assert_less/Assert/Assert", tensor_type=DT_FLOAT, _device="/job:localhost/replica:0/task:0/device:GPU:0"]]

1
If you don't need the initializing feature of the make_initializable_iterator(), I encourage you to use make_one_shot_iterator(). If you really rely on the initialization feature, you could try to encapsulate your iterator in an object to have the possibility to access it outside of the scope of the training function.Lescurel

1 Answers

1
votes

Setting aside @Lescurel's very on-point comment, the problem you have is that you initialize the iterator in a different session than the one you then try to train:

def train_input_fn_try(batch_size=2,epoch=1,shuffle=True):
    # [...]
    with tf.Session() as sess: # <<<<<<<<<<<<<<<<<<<<<<< This session...
        sess.run(iterator.initializer)
    text,label=iterator.get_next()
    return {"text":text},label

with tf.Session() as sess: # <<<<<<<<<<<<<<<<<<<<<<<<<<< ...is NOT the same as this one!
    # [...]

The with tf.Session() as sess: statement creates a new instance of a session and assigns it to sess and that session is cosed once you exit the with statement.

For your code, the best solution is to just use a one-shot iterator, but if you really want to use the initializable one, pass sess as a parameter to train_input_fn_try and remove the with statement inside the function:

def train_input_fn_try(sess,batch_size=2,epoch=1,shuffle=True):
    # [...]
    sess.run(iterator.initializer)
    # [...]

Update: why this still doesn't work (with Estimators)

The way the Estimator framework works is approximately:

  • Make new graph
  • call input_fn to set up the input pipeline in the new graph
  • call model_fn to set up the model in the new graph
  • make a Session and start a training loopp

When you make the lambda, the sess you pass is not the one that will be used by the estimator, so this won't work for you I'm afraid. I am not aware at the moment of ways to use other types of iterators with Estimators, you might have to stick to one-shot iterators.