2017-08-30 51 views
2

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

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

我:

  • 模型保存在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个字符)。

我用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

'(val&0xff)/ 255'等表达式是否真的会产生浮点结果?根据我的理解,分配的右侧将产生一个整数,即每次都为0。 – Vroomfondel

+1

哦,哇,你是对的!我非常关注事物的Tensorflow方面,我完全错过了这一点。它仍然没有给我正确的结果,但是这绝对让我有一个开始的地方! – rednuht

+0

@Vroomfondel - 如果您想将您的评论添加为问题的答案,我会很乐意接受这个答案。我得到了很多改进的结果,我认为有些差异可归因于精度问题。 – rednuht

回答

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) 

但这只是从我身边一个猜测。

相关问题