1

我有一个训练有素的神经网络 (Alexnet) 作为 Keras 模型,应该用于 android 分类应用程序。首先,我将模型转换为 TensorFlow.pb文件:

class Model2Graph(object):
    @staticmethod
    def Convert(ModelPath, OutputPath = "output"):

        print("[INFO] Converting model '{}' into TensorFlow graph...".format(ModelPath))

        # Get the model name
        ModelName = os.path.splitext(ModelPath)[0].rsplit(os.path.sep, 1)[-1]

        # Load the model from file
        Model = load_model(filepath = ModelPath)

        Backend.set_learning_phase(0)
        Session = Backend.get_session()

        OutputCount = len(Model.outputs)
        Temp = [None] * OutputCount
        NodeNames = [None] * OutputCount
        for i in range(OutputCount):
            NodeNames[i] = "output_node" + str(i)
            Temp[i] = tf.identity(Model.outputs[i], name = NodeNames[i])

        constant_graph = graph_util.convert_variables_to_constants(Session, Session.graph.as_graph_def(), NodeNames)    
        graph_io.write_graph(constant_graph, OutputPath, ModelName + ".pb", as_text = False)

此图(带有Labels.txt文件)放置在我的 android 应用程序的 assets 文件夹中。

现在我将图像加载为 JPG 文件。我将其调整IrfanView为 227x227 图像(我的网络的输入大小并忽略纵横比)并使用我的应用程序加载此图像(该图像称为1.jpg)。

在此处输入图像描述

应用程序开始对该图像进行分类(此代码基于 TensorFlow 示例):

public List<Float> Classify(Bitmap InputImage)
    {
        float[] Results = new float[_mClassLabels.size()];
        float[] Output = new float[_mWidth * _mHeight * 3];
        int[] intValues = new int[InputImage.getHeight() * InputImage.getWidth()];
        InputImage.getPixels(intValues, 0, InputImage.getWidth(), 0, 0, InputImage.getWidth(), InputImage.getHeight());

        for (int i = 0; i < intValues.length; ++i)
        {
            final int val = intValues[i];
            Output[i * 3] = ((val >> 16) & 0xFF) / 255.0f;
            Output[i * 3 + 1] = ((val >> 8) & 0xFF) / 255.0f;
            Output[i * 3 + 2] = (val & 0xFF) / 255.0f;
        }

        _mTensorFlowInterface.feed("conv2d_1_input", Output, 1L, _mWidth, _mHeight, 3);
        _mTensorFlowInterface.run(_mOutputName, false);
        _mTensorFlowInterface.fetch(_mOutputName[0], Results);

        // Convert the results into a list
        List<Float> Result = new ArrayList<Float>(Results.length);
        for(float f : Results)
        {
            Result.add(f);
        }

        return Result;
    }

我的 android 应用程序给了我以下分类结果:

  • 0.8430(猫)
  • 0.1569(狗)

但是当我使用我的 Python 应用程序和 Keras 模型时,我得到了不同的结果。Python 应用程序给出以下结果:

  • 0.2255(猫)
  • 0.7744(狗)

现在我想知道为什么同一个网络会在两个应用程序中产生不同的结果。这里出了什么问题?

我的 Android / Java 不太好,所以我不确定预测代码是否正确。将 Keras 模型转换.pb为 TensorFlow 文件也是如此。

4

1 回答 1

0

抱歉回复晚了。我为它创建了一个新帖子,因为我想分享解决方案。感谢@Steven。您对 TensorFlow lite 的提示非常好。所以我将 Keras 模型转换为 TensorFlow lite 图

Converter = lite.TFLiteConverter.from_keras_model_file(ModelPath)
open(OutputPath + os.path.sep + ModelName + ".tflite" , "wb") .write(Converter.convert())

现在可以使用 TensorFlow lite 加载此图:

private Interpreter _mTfLite;
private Interpreter.Options _mTfliteOptions = new Interpreter.Options();

private MappedByteBuffer loadModelFile(AssetManager Manager, String Path) throws IOException
{
    AssetFileDescriptor fileDescriptor = Manager.openFd(Path);
    FileInputStream inputStream = new 
    FileInputStream(fileDescriptor.getFileDescriptor());
    FileChannel fileChannel = inputStream.getChannel();
    long startOffset = fileDescriptor.getStartOffset();
    long declaredLength = fileDescriptor.getDeclaredLength();
    return fileChannel.map(FileChannel.MapMode.READ_ONLY, startOffset, declaredLength);
}

_mTfLite = new Interpreter(loadModelFile(_mAssetManager, Path), _mTfliteOptions.setNumThreads(1));

现在您可以在位图上运行预测:

private ByteBuffer _mInput;
private float[][] _mOutput;

public float[] Classify(Bitmap InputImage)
{
    _mInput.rewind();
    int width = InputImage.getWidth();
    int height = InputImage.getHeight();
    int[] pixels = new int[width * height];
    InputImage.getPixels(pixels, 0, width, 0, 0, width, height);

    int j = 0;
    for(int i = 0; i < pixels.length * 3; i = i + 3)
    {
        final int Pixel = pixels[j];

        _mInput.putFloat((((Pixel >> 16) & 0xFF)) / 1.0f);
        _mInput.putFloat((((Pixel >> 8) & 0xFF)) / 1.0f);
        _mInput.putFloat(((Pixel & 0xFF)) / 1.0f);

        j++;
    }

    _mTfLite.run(_mInput, _mOutput);

    return _mOutput[0];
}

但是你需要添加

aaptOptions {
    noCompress "tflite"
    noCompress "lite"
}

到你的build.gradle文件。否则,您的模型将在构建过程中被压缩,从而导致模型加载错误。

在此处输入图像描述

于 2019-07-23T19:22:14.080 回答