相同的Tensorflow模型在Android和Python上提供不同的结果

时间:2017-08-30 13:29:14

标签: android python machine-learning tensorflow

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

该模型是一个简单的连续CNN,用于识别字符,与this number plate recognition network非常相似,减去窗口,因为我的模型已将字符裁剪到位。

我有:

  • 保存在protobuf(.pb)文件中的模型 - 在Python / Linux + GPU上用Keras建模和训练
  • 推理是在纯Tensorflow上的另一台计算机上测试的,以确保Keras不是罪魁祸首。在这里,结果如预期。
  • Tensorflow 1.3.0正在Python和Android上使用。在PIP上安装Python和jcenter在Android上。
  • 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);

非常感谢任何帮助!

1 个答案:

答案 0 :(得分:3)

一个问题在于:

    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之间的浮点值的分割也可能会产生问题,因为值不像投影空间(0..1)那样分布在Natura。为了解释这一点:传感器域中的值255(例如,R值)意味着测量信号的自然值落在“255”桶中的某处,这是整个能量/强度范围/等。将此值映射到1.0很可能会减少其范围的一半,因为后续计算可能会在1.0的最大乘数处饱和,这实际上只是+ - 1/256桶的中点。因此,转换可能更准确地映射到0..1范围的256桶分区的中点:

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

但这只是我身边的猜测。