2017-08-30 79 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) 

但這只是從我身邊一個猜測。

相關問題