2017-08-30 27 views
2

私はAndroidアプリケーションでTensorflowモデルを実行しようとしていますが、同じ訓練モデルでデスクトップ上のPython上で実行されるときとは異なる結果(誤った推論)を示します。AndroidとPythonで異なる結果をもたらす同じTensorflowモデル

モデルは文字を認識するためのシンプルなシーケンシャルCNNで、this number plate recognition networkと同じように、私のモデルには文字が既に切り取られているため、ウィンドウがありません。

は私が持っている:いるProtobuf(.pb)ファイルに保存されて

  • モデル - パイソン/ Linuxの+ GPU
  • 推論に、純粋なTensorflow上の別のコンピュータ上でテストした上でKerasでモデル化し、訓練を受けました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

一つの問題は、行にある:RGB値がこのように整数の結果(すなわち0度に)得整数で割る

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

また、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) 

が、これはちょうど私の側からの推測です。

関連する問題