如何将Bitmap传入TensorFlow Mobile模型?推理异常求助
Let's break down why your Android app is giving wrong predictions—since your model works perfectly on desktop, the issue almost certainly lies in mismatched image preprocessing between your training/desktop inference and Android code. Here are the key areas to check and fix:
1. Verify Input Channel Order & Dimension Layout
TensorFlow models can use two common dimension formats:
- NHWC (batch, height, width, channel): This is Keras/TensorFlow's default for most pre-trained models like InceptionV3
- NCHW (batch, channel, height, width): Less common in Keras, but possible if you modified the model or conversion process
How to Check:
Use TensorFlow's saved_model_cli tool on your PB model to confirm input shape:
saved_model_cli show --dir path/to/your/pb_model --all
Fix If NCHW is Required:
Your current code assumes NHWC, but if the model expects NCHW, you need to reorder your pixel array to group all R, G, B pixels together:
public float[] normalizeBitmap(Bitmap source,int size,float mean,float std){ float[] output = new float[3 * size * size]; int[] intValues = new int[source.getHeight() * source.getWidth()]; source.getPixels(intValues, 0, source.getWidth(), 0, 0, source.getWidth(), source.getHeight()); int pixelCount = size * size; for (int i = 0; i < intValues.length; ++i) { final int val = intValues[i]; // Group all R pixels first, then G, then B output[i] = (((val >> 16) & 0xFF) - mean)/std; // R channel output[i + pixelCount] = (((val >> 8) & 0xFF) - mean)/std; // G channel output[i + 2 * pixelCount] = ((val & 0xFF) - mean)/std; // B channel } return output; }
And update the feed call to match the NCHW shape:
inferenceInterface.feed(INPUT_NODE, imageValuesFloat, 1, 3, 128, 128);
2. Match Training-Time Image Resizing/Cropping Logic
If your training data used center-cropping instead of direct stretching, your Android code must replicate this exactly. Stretching images to 128x128 distorts proportions and will confuse the model.
Add Cropping Logic to Android:
public Bitmap cropAndResizeBitmap(Bitmap source, int targetSize) { int width = source.getWidth(); int height = source.getHeight(); int cropSize = Math.min(width, height); // Crop the center square of the image int xOffset = (width - cropSize) / 2; int yOffset = (height - cropSize) / 2; Bitmap croppedBitmap = Bitmap.createBitmap(source, xOffset, yOffset, cropSize, cropSize); // Resize to target dimension return Bitmap.createScaledBitmap(croppedBitmap, targetSize, targetSize, true); }
Use this function to generate your resized_image instead of direct scaling.
3. Validate Normalization Accuracy
Double-check that your Android normalization matches exactly what you did during training. Print pixel values from both Python and Android to compare:
Python Test Code:
from PIL import Image import numpy as np img = Image.open("A.png").resize((128,128)) img_array = np.array(img) normalized = (img_array - 127.5) / 1.0 print("Python normalized pixel (0,0):", normalized[0][0])
Android Debug Code:
float[] normalized = normalizeBitmap(resized_image, 128, 127.5f, 1.0f); Log.d("Preprocessing", "Android normalized pixel (0,0): " + normalized[0] + ", " + normalized[1] + ", " + normalized[2]);
If values don't match, check if your Bitmap is using a different color format (e.g., grayscale instead of RGB) or if you accidentally swapped R/B channels.
4. Fix Output Node Execution
Ensure you're passing an array of output nodes to the run method—single strings can cause silent failures:
String[] OUTPUT_NODES = new String[]{OUTPUT_NODE}; inferenceInterface.run(OUTPUT_NODES);
5. Confirm Model Load Success
Add logging to make sure your model loads without errors:
try { inferenceInterface = new TensorFlowInferenceInterface(getAssets(), "your_model.pb"); Log.d("TFModel", "Model loaded successfully"); } catch (IOException e) { Log.e("TFModel", "Failed to load model", e); }
Most Likely Culprits:
- Mismatched dimension layout (NHWC vs NCHW)
- Inconsistent image cropping/resizing between training and Android
- Accidental channel swapping (R/B) in preprocessing
内容的提问来源于stack exchange,提问作者Yusuf

