Объекты ввода Xamarin tf.lite

Я пытаюсь воспроизвести обнаружение объекта тензорного потока на xamarin.

    private MappedByteBuffer LoadModelFile()
    {
        AssetFileDescriptor fileDescriptor = Assets.OpenFd("detect.tflite");           
        FileInputStream inputStream = new FileInputStream(fileDescriptor.FileDescriptor);
        FileChannel fileChannel = inputStream.Channel;
        long startOffset = fileDescriptor.StartOffset;
        long declaredLength = fileDescriptor.DeclaredLength;
        return fileChannel.Map(FileChannel.MapMode.ReadOnly, startOffset, declaredLength);
    }

        View view = (View) sender;

        MappedByteBuffer buffer = LoadModelFile();

        Interpreter interpreter = new Interpreter(buffer);

        var sr = new StreamReader(Assets.Open("labels.txt"));

        var labels = sr.ReadToEnd()
            .Split('\n')
            .Select(s => s.Trim())
            .Where(s => !string.IsNullOrEmpty(s))
            .ToList();

        var bitmap =  BitmapFactory.DecodeResource(Resources, 2130837608);
        var resizedBitmap = Bitmap.CreateScaledBitmap(bitmap, 1000, 750, false)
            .Copy(Bitmap.Config.Argb8888, false);

        float[][][][] imgData = null;

        imgData  = new float[1][][][];
        imgData[0] = new float[1000][][];

        for (int i = 0; i < imgData[0].Length; i++)
        {
            imgData[0][i] = new float[750][];
            for (int j = 0; j < imgData[0][i].Length; j++)
            {
                imgData[0][i][j] = new float[3];
            }
        }
        var intValuess = new int[1000 * 750];
        resizedBitmap.GetPixels(intValuess, 0, 1000, 0, 0, 1000, 750);

        int pixels = 0;
        for (int i = 0; i < imgData[0].Length; i++)
        {
            for (int j = 0; j < imgData[0][i].Length; j++)
            {
                var val = intValuess[pixels++];
                imgData[0][i][j][0] = (float)((val >> 16) & 0xFF);
                imgData[0][i][j][1] = (float)((val >> 8) & 0xFF);
                imgData[0][i][j][2] = (float)(val & 0xFF);
            }
        }

        var outputs = new float[labels.Count];

        interpreter.Run(imgData, outputs);

но у меня ошибка "не удается преобразовать float[][][][] в Java.Lang.Object в интерпретаторе строки.Run(imgData, outputs); Как я могу преобразовать float[][][][] в Java.Lang .Object или где я могу найти tensorflow lite с примерами xamarin.


person temiklis    schedule 19.10.2018    source источник


Ответы (1)


Я знаю, что прошло некоторое время с тех пор, как вы задали этот вопрос, но, возможно, мой ответ может быть кому-то полезен. Я также пытаюсь использовать Xamarin с tflite для запуска простого CNN. Вот мой код:

private MappedByteBuffer LoadModelFile()
{
    var assets = Application.Context.Assets;
    AssetFileDescriptor fileDescriptor = assets.OpenFd("seed_model_no_qt.tflite");
    FileInputStream inputStream = new FileInputStream(fileDescriptor.FileDescriptor);
    FileChannel fileChannel = inputStream.Channel;
    long startOffset = fileDescriptor.StartOffset;
    long declaredLength = fileDescriptor.DeclaredLength;
    return fileChannel.Map(FileChannel.MapMode.ReadOnly, startOffset, declaredLength);
}

private string Classify(MediaFile mediaFile)
{
    var assets = Application.Context.Assets;

    Bitmap bp = BitmapFactory.DecodeStream(mediaFile.GetStream());
    var resizedBitmap = Bitmap.CreateScaledBitmap(bp, 1280, 1280, false).Copy(Bitmap.Config.Argb8888, false);

    var bufint = new int[1280 * 1280];
    resizedBitmap.GetPixels(bufint, 0, 1280, 0, 0, 1280, 1280);
    int pixels = 0;
    var input_buffer = new byte[4 * 1280 * 1280 * 3];            
    for(int i = 0; i < 1280; i++)
    {
        for(int k = 0; k < 1280; k++)
        {
            int val = bufint[pixels++];
            Array.Copy(BitConverter.GetBytes(((val >> 16) & 0xFF) * (1f / 255f)), 0, input_buffer, (i * 1280 + k) * 12, 4);
            Array.Copy(BitConverter.GetBytes(((val >> 8) & 0xFF) * (1f / 255f)), 0, input_buffer, (i * 1280 + k) * 12 + 4, 4);
            Array.Copy(BitConverter.GetBytes((val & 0xFF) * (1f / 255f)), 0, input_buffer, (i * 1280 + k) * 12 + 8, 4);
        }
    }
    var bytebuffer = Java.Nio.ByteBuffer.Wrap(input_buffer);
    var output = Java.Nio.ByteBuffer.AllocateDirect(4*160*160);
    interpreter.Run(bytebuffer, output);

    var buffer = new byte[4 * 160 * 160];

    Marshal.Copy(output.GetDirectBufferAddress(), buffer, 0, 4 * 160 * 160);

    float sum = 0.0f;
    for(int i = 0; i < 160*160; i++)
    {
        sum += BitConverter.ToSingle(buffer, i * 4);
    }

    return "Count : " + ((int)(sum/255)).ToString();
}

Я повторно использовал вашу функцию LoadModelFile() как есть. Код берет изображение из медиафайла (с камеры телефона), затем изменяет его размер до изображения 1280x1280 rgb, прежде чем передать его в CNN в виде массива значений float32. Ваша проблема с float[][][][] to Java.Lang.Object возникла из-за метода интерпретатора.Run(), ожидающего объект Java. Некоторые люди в Интернете решают эту проблему, передавая Java.Nio.ByteBuffer в качестве параметра вместо массива. Это подразумевает некоторые побитовые манипуляции, но метод Run принимает объект ByteBuffer. При заполнении ByteBuffer я советую вам не использовать его методы, такие как PutFloat(), а заполнять буфер byte[], а затем использовать метод Java.Nio.ByteBuffer.Wrap(), как это сделал я. Использование методов ByteBuffer, казалось, в моем случае означало большие проблемы с производительностью. То же самое происходит при манипулировании выводом моего CNN (тепловая карта 160x160 значений float32). Использование метода ByteBuffer.Get() для доступа к значениям было очень медленным. Вместо этого используйте Marshal.Copy для сохранения значений в массив байтов, а затем возвращайте значения с плавающей запятой с помощью BitConverter.ToSingle.

person Louis    schedule 09.08.2019