El modelo Tensorflow Lite proporciona un valor de precisión muy diferente en comparación con el modelo Python.

Estoy usando tensorflow 1.10 Python 3.6

Mi código se basa en el modelo de clasificación de iris prefabricado proporcionado por TensorFlow. Esto significa que estoy usando un clasificador premade Tensorflow DNN, con la siguiente diferencia:

  • 10 características en lugar de 4.
  • 5 clases en lugar de 3.

Los archivos de prueba y entrenamiento se pueden descargar desde el siguiente enlace: https://www.dropbox.com/sh/nmu8i2i8xe6hvfq/AADQEOIHH8e-kUHQf8zmmDMDa?dl=0

He creado un código para exportar este clasificador a un formato tflite; sin embargo, la precisión en el modelo de Python es superior al 75%, pero cuando se exporta, la precisión disminuye aproximadamente al 45%, lo que significa que se pierde aproximadamente el 30% de precisión (esto es demasiado) . He probado el código con un conjunto diferente de datos y en todos ellos, la precisión después de la exportación disminuye mucho. Esto me hizo pensar que algo va mal con la función TocoConverter o que tal vez estoy exportando a tflite incorrectamente, faltando un parámetro o algo así.

Así es como genero el modelo:

    classifier = tf.estimator.DNNClassifier( feature_columns=my_feature_columns, hidden_units=[100, 500], optimizer=tf.train.AdagradOptimizer(learning_rate=0.003), n_classes=num_labels, model_dir="myModel") 

    Y esta es la función que estoy usando para convertir a tflite:

     converter = tf.contrib.lite.TocoConverter.from_frozen_graph(final_model_path, input_arrays, output_arrays, input_shapes={"dnn/input_from_feature_columns/input_layer/concat": [1, 10]}) tflite_model = converter.convert() 

    Comparto el código completo en el que también calculo la precisión del archivo .tflite resultante.

     import argparse import tensorflow as tf import pandas as pd import csv from tensorflow.python.tools import freeze_graph from tensorflow.python.tools import optimize_for_inference_lib import numpy as np parser = argparse.ArgumentParser() parser.add_argument('--batch_size', default=100, type=int, help='batch size') parser.add_argument('--train_steps', default=1000, type=int, help='number of training steps') features_global = None feature_spec = None MODEL_NAME = 'myModel' def load_data(train_path, test_path): """Returns the iris dataset as (train_x, train_y), (test_x, test_y).""" with open(train_path, newline='') as f: reader = csv.reader(f) column_names = next(reader) y_name = column_names[-1] train = pd.read_csv(train_path, names=column_names, header=0) train_x, train_y = train, train.pop(y_name) test = pd.read_csv(test_path, names=column_names, header=0) test_x, test_y = test, test.pop(y_name) return (train_x, train_y), (test_x, test_y) def train_input_fn(features, labels, batch_size): """An input function for training""" # Convert the inputs to a Dataset. dataset = tf.data.Dataset.from_tensor_slices((dict(features), labels)) # Shuffle, repeat, and batch the examples. dataset = dataset.shuffle(1000).repeat().batch(batch_size) # Return the dataset. return dataset def eval_input_fn(features, labels, batch_size): """An input function for evaluation or prediction""" features=dict(features) if labels is None: # No labels, use only features. inputs = features else: inputs = (features, labels) # Convert the inputs to a Dataset. dataset = tf.data.Dataset.from_tensor_slices(inputs) # Batch the examples assert batch_size is not None, "batch_size must not be None" dataset = dataset.batch(batch_size) # Return the dataset. return dataset def main(argv): args = parser.parse_args(argv[1:]) train_path = "trainData.csv" test_path = "testData.csv" # Fetch the data (train_x, train_y), (test_x, test_y) = load_data(train_path, test_path) # Load labels num_labels = 5 # Feature columns describe how to use the input. my_feature_columns = [] for key in train_x.keys(): my_feature_columns.append(tf.feature_column.numeric_column(key=key)) # Build 2 hidden layer DNN classifier = tf.estimator.DNNClassifier( feature_columns=my_feature_columns, hidden_units=[100, 500], optimizer=tf.train.AdagradOptimizer(learning_rate=0.003), # The model must choose between 'num_labels' classes. n_classes=num_labels, model_dir="myModel") # Train the Model classifier.train( input_fn=lambda:train_input_fn(train_x, train_y, args.batch_size), steps=args.train_steps) # Evaluate the model. eval_result = classifier.evaluate( input_fn=lambda:eval_input_fn(test_x, test_y, args.batch_size)) print('\nTest set accuracy: {accuracy:0.3f}\n'.format(**eval_result)) # Export model feature_spec = tf.feature_column.make_parse_example_spec(my_feature_columns) serve_input_fun = tf.estimator.export.build_parsing_serving_input_receiver_fn(feature_spec) saved_model_path = classifier.export_savedmodel( export_dir_base="out", serving_input_receiver_fn=serve_input_fun, as_text=True, checkpoint_path=classifier.latest_checkpoint(), ) tf.reset_default_graph() var = tf.Variable(0) with tf.Session() as sess: # First let's load meta graph and restre weights sess.run(tf.global_variables_initializer()) latest_checkpoint_path = classifier.latest_checkpoint() saver = tf.train.import_meta_graph(latest_checkpoint_path + '.meta') saver.restre(sess, latest_checkpoint_path) input_arrays = ["dnn/input_from_feature_columns/input_layer/concat"] output_arrays = ["dnn/logits/BiasAdd"] frozen_graph_def = tf.graph_util.convert_variables_to_constants( sess, sess.graph_def, output_node_names=["dnn/logits/BiasAdd"]) frozen_graph = "out/frozen_graph.pb" with tf.gfile.FastGFile(frozen_graph, "wb") as f: f.write(frozen_graph_def.SerializeToString()) # save original graphdef to text file with open("estimator_graph.pbtxt", "w") as fp: fp.write(str(sess.graph_def)) # save frozen graph def to text file with open("estimator_frozen_graph.pbtxt", "w") as fp: fp.write(str(frozen_graph_def)) input_node_names = input_arrays output_node_name = output_arrays output_graph_def = optimize_for_inference_lib.optimize_for_inference( frozen_graph_def, input_node_names, output_node_name, tf.float32.as_datatype_enum) final_model_path = 'out/opt_' + MODEL_NAME + '.pb' with tf.gfile.FastGFile(final_model_path, "wb") as f: f.write(output_graph_def.SerializeToString()) tflite_file = "out/iris.tflite" converter = tf.contrib.lite.TocoConverter.from_frozen_graph(final_model_path, input_arrays, output_arrays, input_shapes={"dnn/input_from_feature_columns/input_layer/concat": [1, 10]}) tflite_model = converter.convert() open(tflite_file, "wb").write(tflite_model) interpreter = tf.contrib.lite.Interpreter(model_path=tflite_file) interpreter.allocate_tensors() # Get input and output tensors. input_details = interpreter.get_input_details() output_details = interpreter.get_output_details() # Test model on random input data. input_shape = input_details[0]['shape'] # change the following line to feed into your own data. input_data = np.array(np.random.random_sample(input_shape), dtype=np.float32) resultlist = list() df = pd.read_csv(test_path) expected = df.iloc[:, -1].values.tolist() with open(test_path, newline='') as f: reader = csv.reader(f) column_names = next(reader) for x in range(0, len(expected)): linea = next(reader) linea = linea[:len(linea) - 1] input_data2 = np.array(linea, dtype=np.float32) interpreter.set_tensor(input_details[0]['index'], [input_data2]) interpreter.invoke() output_data = interpreter.get_tensor(output_details[0]['index']) #print(output_data) max = 0; longitud = len(output_data[0]) for k in range(0, longitud): if (output_data[0][k] > output_data[0][max]): max = k resultlist.append(max) print(resultlist) coincidences = 0 for pred_dict, expec in zip(resultlist, expected): if pred_dict == expec: coincidences = coincidences + 1 print("tflite Accuracy: " + str(coincidences / len(expected))) if __name__ == '__main__': tf.logging.set_verbosity(tf.logging.INFO) tf.app.run(main) 

    Espero que algunos de ustedes puedan identificar el error, o dar una posible solución.

    Me he encontrado con el mismo problema. Me parece que el problema de precisión se debe principalmente a una falla en la detección de objetos superpuestos. Aunque no pude averiguar qué parte del código es incorrecta.