Search code examples
pythontensorflowdeep-learningnlpnlp-question-answering

How to build input to predict with saved model for BERT SQuAD2.0 with tensorflow


I am trying to build the input for the saved model from BERT-SQuAD given that I have got all the elements for the input.

I fine-tuned a question answering model by running of run_squad.py in Google bert, then I exported the model with export_saved_model. Now when I have a new context and question, I can't build the correct input that can get return output from the model.

Code to export the model:

#export the model
    def serving_input_receiver_fn():
      feature_spec = {
            "unique_ids": tf.FixedLenFeature([], tf.int64),
            "input_ids": tf.FixedLenFeature([FLAGS.max_seq_length], tf.int64),
            "input_mask": tf.FixedLenFeature([FLAGS.max_seq_length], tf.int64),
            "segment_ids": tf.FixedLenFeature([FLAGS.max_seq_length], tf.int64),
      }

      serialized_tf_example = tf.placeholder(dtype=tf.string,
                               shape=FLAGS.predict_batch_size,
                               name='input_example_tensor')
      receiver_tensors = {'examples': serialized_tf_example}
      features = tf.parse_example(serialized_tf_example, feature_spec)
      return tf.estimator.export.ServingInputReceiver(features, receiver_tensors)

    estimator = tf.contrib.tpu.TPUEstimator(
      use_tpu=FLAGS.use_tpu,
      model_fn=model_fn,
      config=run_config,
      train_batch_size=FLAGS.train_batch_size,
      predict_batch_size=FLAGS.predict_batch_size)

    estimator._export_to_tpu = False  ## !!important to add this
    estimator.export_saved_model(
        export_dir_base ="C:/Users/ZitongZhou/Desktop/qa/bert_squad/servemodel",
        serving_input_receiver_fn = serving_input_receiver_fn)

The way I loaded the model:

export_dir = 'servemodel'
subdirs = [x for x in Path(export_dir).iterdir()
           if x.is_dir() and 'temp' not in str(x)]
latest = str(sorted(subdirs)[-1])

predict_fn = predictor.from_saved_model(latest)

I got the eval_features from the run_squad.py. The way I tried to build the input:

feature_spec = {
        "unique_ids": np.asarray(eval_features[0].unique_id).tolist(),
        "input_ids": np.asarray(eval_features[0].input_ids).tolist(),
        "input_mask": np.asarray(eval_features[0].input_mask).tolist(),
        "segment_ids": np.asarray(eval_features[0].segment_ids).tolist()
    }
serialized_tf_example = tf.placeholder(dtype=tf.string,
                           shape=[1],
                           name='input_example_tensor')
receiver_tensors = {'examples': serialized_tf_example}
features = tf.parse_example(serialized_tf_example, feature_spec)
out = predict_fn({'examples':[str(feature_spec)]})

I expect to get a prediction 'out' so I can extract the answer to the question from it.

The traceback I got:

Traceback (most recent call last):

  File "<ipython-input-51-0c3b618a8f48>", line 11, in <module>
    features = tf.parse_example(serialized_tf_example, feature_spec)

  File "C:\Users\ZitongZhou\Anaconda3\envs\nlp\lib\site-packages\tensorflow
\python\ops\parsing_ops.py", line 580, in parse_example
    return parse_example_v2(serialized, features, example_names, name)

  File "C:\Users\ZitongZhou\Anaconda3\envs\nlp\lib\site-packages\tensorflow
\python\ops\parsing_ops.py", line 803, in parse_example_v2
    [VarLenFeature, SparseFeature, FixedLenFeature, FixedLenSequenceFeature])

  File "C:\Users\ZitongZhou\Anaconda3\envs\nlp\lib\site-packages\tensorflow
\python\ops\parsing_ops.py", line 299, in _features_to_raw_params
    raise ValueError("Invalid feature %s:%s." % (key, feature))

ValueError: Invalid feature input_ids:[101, 1005, 2129, 2214, 2003, 19523, 
6562, 1005, 102, 1005, 19523, 11233, 2003, 2274, 2086, 2214, 1005, 102,
 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0].

Solution

  • I figured it out, I need to use tf.train.Example function:

    def create_int_feature(values):
        f = tf.train.Feature(int64_list=tf.train.Int64List(value=list(values)))
        return f
    
    inputs = collections.OrderedDict()
    inputs["input_ids"] = create_int_feature(features[0].input_ids)
    inputs["input_mask"] = create_int_feature(features[0].input_mask)
    inputs["segment_ids"] = create_int_feature(features[0].segment_ids)
    inputs["unique_ids"] = create_int_feature([features[0].unique_id])
    
    tf_example = tf.train.Example(features=tf.train.Features(feature=inputs))
    out = predict_fn({'examples':[tf_example.SerializeToString()]})