【问题标题】:tensorflow lite model gives very different accuracy value compared to python model与 python 模型相比,tensorflow lite 模型给出了非常不同的准确度值
【发布时间】:2019-02-03 01:38:43
【问题描述】:

我正在使用 tensorflow 1.10 Python 3.6

我的代码基于 TensorFlow 提供的预制 iris classification model。这意味着,我使用的是 Tensorflow DNN 预制分类器,有以下区别:

  • 10 个功能而不是 4 个。
  • 5 类而不是 3 个。

测试和训练文件可以从以下链接下载: https://www.dropbox.com/sh/nmu8i2i8xe6hvfq/AADQEOIHH8e-kUHQf8zmmDMDa?dl=0

我已经编写了一个代码来将此分类器导出为 tflite 格式,但是在 python 模型中的准确度高于 75%,但是当导出时准确度下降到大约 45%,这意味着大约 30% 的准确度丢失(这是太多了)。 我已经尝试了具有不同数据集的代码,并且在所有这些代码中,导出后的准确性都下降了很多! 这让我觉得 TocoConverter 函数出了点问题,或者我可能错误地导出到 tflite,缺少参数或类似的东西。

这是我生成模型的方式:

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")

这是我用来转换为 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()

我分享了完整的代码,其中我还计算了生成的 .tflite 文件的准确性。

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 restore weights
        sess.run(tf.global_variables_initializer())
        latest_checkpoint_path = classifier.latest_checkpoint()
        saver = tf.train.import_meta_graph(latest_checkpoint_path + '.meta')
        saver.restore(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)

我希望你们中的一些人能找出错误,或给出可能的解决方案

【问题讨论】:

  • 豪尔赫·希门尼斯,我们遇到了同样的问题。转换后的 tflite 模型的性能与冻结的 pb 模型不同。 tflite 的精度低于 pb 文件。有什么建议吗?
  • 您面临的精度差异有多大?您正在使用哪个函数 tf.contrib.lite.TocoConverter.from_frozen_graph?还是 tf.contrib.lite.TocoConverter.from_saved_model?
  • 当我使用 TensorFlow 1.10 在 Python 3.6 virtualenv 上运行您提供的代码时,出现错误“ValueError: Please freeze the graph using freeze_graph.py”。当我用from_saved_model(传入input_arrays、output_arrays和input_shapes)替换对from_frozen_graph的调用时,我能够运行并产生0.5045045045045045的精度。你用的是哪个功能?我建议尝试将 tflite_diff 与 .pb 和 .tflite 文件一起使用,以确保相同的输入存在错误。随意创建一个 GitHub 问题,以便更深入地研究该问题。
  • 您好,感谢您抽出宝贵时间运行代码!是的,这几乎是我达到的最高准确度(51.05),我真的不知道发生了什么,我认为这是预制分类器或转换函数中的一些错误
  • 你能告诉我你是如何使用“来自保存的模型”方法的吗,每次我使用时,我都会发现一些运算符尚未实现:这是一个运算符列表您将需要自定义实现:AsString、ParseExample stackoverflow.com/questions/51845395/… 我已经在 github 中创建了一个问题:github.com/tensorflow/tensorflow/issues/…

标签: python python-3.x tensorflow tensorflow-lite


【解决方案1】:

这个问题已回答here 可能会有所帮助。

正如回答分享中提到的,做一些

预处理

在图像被送入“interpreter.invoke()”之前解决问题,如果这首先是问题的话。

要详细说明,这里是共享链接的块引用:

你看到的下面的代码就是我所说的预处理:

test_image = cv2.imread(file_name)

test_image = cv2.resize(test_image,(299,299),cv2.INTER_AREA)

test_image = np.expand_dims((test_image)/255,axis=0).astype(np.float32)

interpreter.set_tensor(input_tensor_index, test_image)

interpreter.invoke()

digit = np.argmax(output()[0])

#print(digit)

prediction = result[digit]

如您所见,有两个关键的命令/预处理完成 使用“imread()”读取图像后:

i) 图像应调整为“input_height”的大小 和使用的输入图像/张量的“input_width”值 在训练期间。就我而言(inception-v3),这两个都是 299 “输入高度”和“输入宽度”。 (阅读模型的文档 获取此值或在您使用过的文件中查找此变量 训练或重新训练模型)

ii) 上面代码中的下一条命令是:

test_image = np.expand_dims((test_image)/255,axis=0).astype(np.float32)

我从“公式”/型号代码中得到这个:

test_image = np.expand_dims((test_image - input_mean)/input_std, axis=0).astype(np.float32)

阅读文档发现对于我的架构 input_mean = 0 和 input_std = 255。

希望这会有所帮助。

【讨论】:

    【解决方案2】:

    我遇到了同样的问题。在我看来,准确性问题主要是由于未能检测到重叠对象造成的。我无法弄清楚代码的哪一部分是错误的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-08
      • 2020-03-06
      • 1970-01-01
      • 1970-01-01
      • 2019-07-18
      • 1970-01-01
      相关资源
      最近更新 更多