ensorflow模型在Android和Python上给出不同的

ensorflow模型在Android和Python上给出不同的

本文介绍了相同的Tensorflow模型在Android和Python上给出不同的结果的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图在我的Android应用程序上运行Tensorflow模型,但是与在桌面上的Python上运行时相比,经过训练的模型给出了不同的结果(错误的推论).

I am trying to run a Tensorflow model on my Android application, but the same trained model gives different results (wrong inference) compared to when it is run on Python on desktop.

该模型是一个可识别字符的简单连续CNN,非常类似于此数字板识别网络,减去窗口,因为我的模型中的字符已经被裁剪到位.

The model is a simple sequential CNN to recognize characters, much like this number plate recognition network, minus the windowing, as my model has the characters already cropped into place.

我有:

  • 保存在protobuf(.pb)文件中的模型-在Keras上的Python/Linux + GPU上进行建模和训练
  • 在纯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个字符).

我使用此代码将Keras模型保存为.pb文件.

I used this code to save the Keras model as a .pb file.

Python代码,它可以按预期工作:

Python code, this works as expected:

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代码,基于此示例;这给出了看似随机的结果:

Android code, based on this example; this gives seemingly random results:

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

任何帮助将不胜感激!

推荐答案

以下是一个问题:

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

where the RGB values are divided by an integer, thus yielding an integer result (namely 0 every time).

此外,除法,即使使用255.0执行除法也会产生介于0和1.0之间的浮点数,也可能会带来问题,因为这些值不会像在Natura中那样分布在投影空间(0..1)中.对此进行解释:在传感器域中值为255(例如,R值)表示被测信号的自然值落在"255"桶中的某个位置,该桶是能量/强度/等的整个范围.将该值映射到1.0很有可能会削减其范围的一半,因为随后的计算可能会以最大乘数1.0达到饱和,而这实际上只是+/- 1/256存储桶的中点.因此,转换可能更正确地映射到0..1范围的256桶除法的中点:

Moreover, the division, even if executed with a 255.0 yielding a float between 0 and 1.0 may pose a problem, as the values aren't distributed in the projection space (0..1) like they were in Natura. To explain this: a value of 255 in the sensor domain (i.e. the R value for example) means that the natural value of the measured signal fell somewhere in the "255" bucket which is a whole range of energies/intensities/etc. Mapping this value to 1.0 will most likely cut half of its range, as subsequent calculations could saturate at a maximum multiplicator of 1.0 which really is only the midpoint of a +- 1/256 bucket. So maybe the transformation would be more correctly a mapping to the midpoints of a 256-bucket division of the 0..1 range:

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

但这只是我的猜测.

这篇关于相同的Tensorflow模型在Android和Python上给出不同的结果的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-29 12:05