【问题标题】:Same Tensorflow model giving different results on Android and Python相同的 TensorFlow 模型在 Android 和 Python 上给出不同的结果
【发布时间】:2017-08-30 13:29:14
【问题描述】:

我正在尝试在我的 Android 应用程序上运行 Tensorflow 模型,但与在桌面上的 Python 上运行时相比,相同的训练模型给出了不同的结果(错误推理)。

该模型是一个简单的序列 CNN 来识别字符,很像 this number plate recognition network,减去窗口,因为我的模型已经将字符裁剪到位。

我有:

  • 模型保存在 protobuf (.pb) 文件中 - 在 Python/Linux + GPU 上的 Keras 中建模和训练
  • 在另一台计算机上的纯 Tensorflow 上对该推理进行了测试,以确保 Keras 不是罪魁祸首。在这里,结果符合预期。
  • Tensorflow 1.3.0 正在 Python 和 Android 上使用。从 Python 上的 PIP 和 Android 上的 jcenter 安装。
  • Android 上的结果与预期结果不符。
  • 输入是 129*45 RGB 图像,因此是 129*45*3 数组,输出是 4*36 数组(代表 0-9 和 a-z 的 4 个字符)。

我使用this code 将 Keras 模型保存为 .pb 文件。

Python 代码,按预期工作:

test_image = [ndimage.imread("test_image.png", mode="RGB").astype(float)/255]

imTensor = np.asarray(test_image)

def load_graph(model_file):
  graph = tf.Graph()
  graph_def = tf.GraphDef()

  with open(model_file, "rb") as f:
    graph_def.ParseFromString(f.read())
  with graph.as_default():
    tf.import_graph_def(graph_def)

  return graph

graph=load_graph("model.pb")
with tf.Session(graph=graph) as sess:

    input_operation = graph.get_operation_by_name("import/conv2d_1_input")
    output_operation = graph.get_operation_by_name("import/output_node0")

    results = sess.run(output_operation.outputs[0],
                  {input_operation.outputs[0]: imTensor})

Android 代码,基于this example;这给出了看似随机的结果:

Bitmap bitmap;
try {
    InputStream stream = getAssets().open("test_image.png");
    bitmap = BitmapFactory.decodeStream(stream);
} catch (IOException e) {
    e.printStackTrace();
}

inferenceInterface = new TensorFlowInferenceInterface(context.getAssets(), "model.pb");
int[] intValues = new int[129*45];
float[] floatValues = new float[129*45*3];
String outputName = "output_node0";
String[] outputNodes = new String[]{outputName};
float[] outputs = new float[4*36];

bitmap.getPixels(intValues, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());
for (int i = 0; i < intValues.length; ++i) {
    final int val = intValues[i];
    floatValues[i * 3 + 0] = ((val >> 16) & 0xFF) / 255;
    floatValues[i * 3 + 1] = ((val >> 8) & 0xFF) / 255;
    floatValues[i * 3 + 2] = (val & 0xFF) / 255;
}

inferenceInterface.feed("conv2d_1_input", floatValues, 1, 45, 129, 3);
inferenceInterface.run(outputNodes, false);
inferenceInterface.fetch(outputName, outputs);

非常感谢任何帮助!

【问题讨论】:

  • (val &amp; 0xff) / 255 等表达式真的会给出浮点结果吗?根据我有限的理解,分配的右侧将产生一个整数,即每次 0。
  • 哇哦,你是对的!我非常专注于 Tensorflow 方面的事情,以至于我完全错过了这一点。它仍然没有给我正确的结果,但这绝对给了我一个开始的地方!
  • @Vroomfondel - 如果您想添加您的评论作为问题的答案,我很乐意接受它作为答案。我的结果得到了很大改善,我认为有些差异可能是由于精度问题。

标签: android python machine-learning tensorflow


【解决方案1】:

有一个问题:

    floatValues[i * 3 + 0] = ((val >> 16) & 0xFF) / 255;
    floatValues[i * 3 + 1] = ((val >> 8) & 0xFF) / 255;
    floatValues[i * 3 + 2] = (val & 0xFF) / 255;

其中 RGB 值除以一个整数,从而产生一个整数结果(即每次都为 0)。

此外,除法,即使使用255.0 执行产生介于 0 和 1.0 之间的浮点数,也可能会产生问题,因为这些值不会像在 Natura 中那样分布在投影空间 (0..1) 中.为了解释这一点:传感器域中的 255 值(例如 R 值)意味着测量信号的自然值落在“255”桶中的某个位置,这是整个能量/强度/等范围。将此值映射到 1.0 很可能会减少其范围的一半,因为后续计算可能会在最大乘数 1.0 处饱和,这实际上只是 +- 1/256 桶的中点。所以也许转换会更正确地映射到 0..1 范围的 256 桶划分的中点:

((val & 0xff) / 256.0) + (0.5/256.0)

但这只是我的猜测。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-08-08
    • 1970-01-01
    • 2021-10-30
    • 2019-03-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多