Xamarin tf.lite входные объекты - PullRequest
       20

Xamarin tf.lite входные объекты

0 голосов
/ 19 октября 2018

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

    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 в строке истолкователя. Запуск (imgData, выходные данные); как я могу преобразовать float [] [] [] [] в Java.Lang.Object или где я могу найти тензор потока lite с примерами xamarin.

1 Ответ

0 голосов
/ 09 августа 2019

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

...