Una demostración simple lo lleva a convertir el modelo keras personalizado de tensorflow2.x al formato tflite e implementarlo en Android.

ambiente:

ventanas 10

CUDA 10.1

oculto 7.6.4

tensorflow-gpu 2.1

Androidestudio 3.6

Básicamente es un entorno relativamente nuevo en la actualidad.

Porque después de tensorflow 2.0, me gusta especialmente usar keras para personalizar modelos, por lo que quiero encontrar una manera de guardar el modelo para su implementación. No entiendo muy bien qué método del modelo en formato pb se guarda, o si se guardan todos los métodos, por lo que no consideraré usar la implementación del modelo pb por el momento. tflite es mucho más simple y solo guarda el proceso bajo el método de llamada. El proceso de conversión es bastante sencillo, basta con ir directamente al tema.

 

Primero la parte de Python:

1. Personalice un modelo simple con múltiples entradas y múltiples salidas.

class test_model2(tf.keras.Model):
    def __init__(self, name="test_model2"):
        super(test_model2, self).__init__(name=name)
        self.conv1 = tf.keras.layers.Conv2D(filters=1, kernel_size=2, kernel_initializer=tf.ones, name=self.name + "/conv1")

    @tf.function
    def call(self, inputs):
        output1 = self.conv1(inputs[0])
        output1 = tf.squeeze(output1)
        output1 = tf.reshape(output1, (1,))
        output2 = self.conv1(inputs[1])
        output2 = tf.squeeze(output2)
        output2 = tf.reshape(output2, (1,))
        return output1, output2
model = test_model2()
test_input1 = tf.ones((1, 2, 2, 1))
test_input2 = tf.zeros((1, 2, 2, 1))
input_list = [test_input1, test_input2]
test_output1, test_output2 = model(input_list)
print(test_output1)
print(test_output2)

se imprimirá después de ejecutar

tf.Tensor([4.], shape=(1,), dtype=float32)
tf.Tensor([0.], shape=(1,), dtype=float32)

Este es un modelo bastante simple.

2. El siguiente es el modelo de conversión al formato tflite:

Si utiliza un bucle de entrenamiento personalizado en lugar de utilizar la función fit(), deberá configurar manualmente el tamaño de entrada del modelo. En este ejemplo, lo consideramos como un proceso de capacitación personalizado y simplemente configuramos el tamaño de entrada una vez. El valor de entrada puede ser aleatorio, principalmente si la forma coincide. Debido a que la función de llamada se convierte de forma predeterminada, si el entrenamiento y las pruebas no pasan por una función, se recomienda que la función de entrenamiento no tenga el mismo nombre que la llamada.

test_input1 = tf.ones((1, 2, 2, 1))
test_input2 = tf.zeros((1, 2, 2, 1))
input_list = [test_input1, test_input2]
model._set_inputs(input_list)

Finalmente convierta y guarde el modelo:

converter = tf.lite.TFLiteConverter.from_keras_model(model)
tflite_model = converter.convert()
open("./save/converted_model.tflite", "wb").write(tflite_model)

Ahora puede encontrar el archivo tflite guardado en la carpeta de guardar.

 

Después viene la parte de AndroidStudio:

1. Crea un nuevo proyecto

2. Modifique build.gradle y agregue el siguiente contenido

android {
    ...
    defaultConfig {
        ...
        ndk {
            abiFilters 'armeabi-v7a', 'arm64-v8a'
        }
        ...
    }
    aaptOptions {
        noCompress "tflite"
    }
    ...
}
dependencies {
    ...
    implementation 'org.tensorflow:tensorflow-lite:2.1.0'
}

3.Introduzca el archivo tflite y léalo.

Cree una carpeta de activos en app\src\main y coloque convert_model.tflite en ella. Esta ruta de archivo no es única, se coloca en activos solo para facilitar la lectura.

El código de lectura se ve así:

String MODEL_FILE = "converted_model.tflite";
Interpreter tfLite = null;
try {
    tfLite = new Interpreter(loadModelFile(getAssets(), MODEL_FILE));
}catch(IOException e){
    e.printStackTrace();
}

La función loadModelFile es:

MappedByteBuffer loadModelFile(AssetManager assets, String modelFilename)
            throws IOException {
        AssetFileDescriptor fileDescriptor = assets.openFd(modelFilename);
        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);
    }

4. Crear tensor de entrada

La entrada de tflite está en formato ByteBuffer:

int net_input_sz = 2;

ByteBuffer inputData1;
inputData1 = ByteBuffer.allocateDirect(net_input_sz * net_input_sz * 4);//4表示一个浮点占4byte
inputData1.order(ByteOrder.nativeOrder());
inputData1.rewind();
inputData1.putFloat(1.0f);
inputData1.putFloat(1.0f);
inputData1.putFloat(1.0f);
inputData1.putFloat(1.0f);

ByteBuffer inputData2;
inputData2 = ByteBuffer.allocateDirect(net_input_sz * net_input_sz * 4);//4表示一个浮点占4byte
inputData2.order(ByteOrder.nativeOrder());
inputData2.rewind();
inputData2.putFloat(0.0f);
inputData2.putFloat(0.0f);
inputData2.putFloat(0.0f);
inputData2.putFloat(0.0f);

Object[] inputArray = {inputData1, inputData2};
 

El tamaño del espacio abierto por ByteBuffer es la suma del tamaño de entrada de la red multiplicada por los bytes ocupados por la precisión. Por ejemplo, la forma de entrada establecida en este ejemplo es 1x2x2x1, por lo que es 4 y el número de punto flotante ocupa 4 bytes. , por lo que tiene un tamaño de 4x4.

5. Construir tensor de salida

float[] output1, output2;
output1 = new float[1];
output2 = new float[1];
Map<Integer, Object> outputMap = new HashMap<>();
outputMap.put(0, output1);
outputMap.put(1, output2);

En nuestro ejemplo, la forma de salida de la red es [1,], por lo que aquí podemos construir directamente una matriz de punto flotante de tamaño 1. Si hay una salida bidimensional o incluso tridimensional, como [2,3,4], es necesario construir una matriz multidimensional nueva flotante [2] [3] [4]. Sin embargo, no me gusta el método de construir matrices multidimensionales porque es inconveniente pasarlo a la capa nativa para su procesamiento, por lo que generalmente modifico (output_tensor, [-1]) la salida.

6. Realizar inferencias e imprimir resultados.

tfLite.runForMultipleInputsOutputs(inputArray, outputMap);
Log.e("1111","output1:" + output1[0]);
Log.e("1111","output2:" + output2[0]);

Una frase puede resolverlo. Puede obtener el siguiente resultado

2020-02-25 16:27:55.569 22585-22585/com.stars.tflite_test E/1111: output1:4.0
2020-02-25 16:27:55.569 22585-22585/com.stars.tflite_test E/1111: output2:0.0

 

En este punto, se completa la conversión e implementación de todo el modelo.

Oye, ¿no es bastante sencillo?

 

Adjunto está el nombre del paquete de mi parte de Java. Olvidé cuáles son necesarios, así que los agregaré todos:

package com.stars.tflite_test;

import android.content.res.AssetFileDescriptor;
import android.content.res.AssetManager;
import android.os.Bundle;

import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.snackbar.Snackbar;

import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;

import android.util.Log;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;

import org.tensorflow.lite.Interpreter;

import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.util.HashMap;
import java.util.Map;

Pozos encontrados:

1. No pude transferir la capa BN oficial a tflite (no sé por qué), así que modifiqué mágicamente una capa BN de la capa BN oficial a una capa BN sin tantas funciones y la convertí con éxito a tflite.

2. El resultado obtenido al ejecutar el modelo tflite convertido en la GPU es incorrecto. No sé cómo solucionarlo. He planteado una pregunta en github, pero aún no he obtenido respuesta. La dirección del problema es https://github.com/tensorflow/tensorflow/issues/38825 . Si sabes algo al respecto, puedes decirme. Probé el modelo escrito en modo sesión para obtener resultados correctos en la GPU, pero usando 2. Los modelos escritos en modo x no funcionarán.

 

Supongo que te gusta

Origin blog.csdn.net/qq_19313495/article/details/104498442
Recomendado
Clasificación