Autocompletar

Ver en TensorFlow.org

Introducción

Los modelos de lenguaje grande (LLM) son una clase de modelos de aprendizaje automático que están entrenados para generar texto basado en grandes conjuntos de datos. Se pueden utilizar para tareas de procesamiento del lenguaje natural (PLN), incluida la generación de texto, la respuesta a preguntas y la traducción automática. Se basan en la arquitectura Transformer y están entrenados con cantidades masivas de datos de texto, que a menudo involucran miles de millones de palabras. Incluso los LLM de menor escala, como GPT-2, pueden tener un rendimiento impresionante. Convertir los modelos de TensorFlow a un modelo más liviano, más rápido y de bajo consumo nos permite ejecutar modelos de IA generativos en el dispositivo, con los beneficios de una mejor seguridad del usuario porque los datos nunca saldrán de su dispositivo.

Este runbook le muestra cómo crear una aplicación de Android con TensorFlow Lite para ejecutar un LLM de Keras y proporciona sugerencias para la optimización del modelo mediante técnicas de cuantificación, que de otro modo requerirían una cantidad mucho mayor de memoria y mayor potencia computacional para ejecutarse.

Hemos abierto el marco de nuestra aplicación de Android al que se puede conectar cualquier LLM de TFLite compatible. Aquí hay dos demostraciones:

  • En la Figura 1, utilizamos un modelo Keras GPT-2 para realizar tareas de finalización de texto en el dispositivo.
  • En la Figura 2, convertimos una versión del modelo PaLM ajustado por instrucciones (1,5 mil millones de parámetros) a TFLite y lo ejecutamos a través del tiempo de ejecución de TFLite.

Autocompletar con PaLM
Figura 1: Ejemplo de ejecución del modelo Keras GPT-2 (convertido de este Codelab ) en un dispositivo para completar texto en Pixel 7. La demostración muestra la latencia real sin aceleración.

Autocompletar con PaLM

Figura 2: Ejemplo de ejecución de una versión del modelo PaLM con 1,5 mil millones de parámetros. La demostración se graba en Pixel 7 Pro sin aceleración de reproducción.

Guías

Autoría de modelos

Para esta demostración, usaremos KerasNLP para obtener el modelo GPT-2. KerasNLP es una biblioteca que contiene modelos previamente entrenados de última generación para tareas de procesamiento del lenguaje natural y puede ayudar a los usuarios durante todo el ciclo de desarrollo. Puedes ver la lista de modelos disponibles en el repositorio de KerasNLP . Los flujos de trabajo se construyen a partir de componentes modulares que tienen arquitecturas y pesos preestablecidos de última generación cuando se usan de forma inmediata y se pueden personalizar fácilmente cuando se necesita más control. La creación del modelo GPT-2 se puede realizar con los siguientes pasos:

gpt2_tokenizer = keras_nlp.models.GPT2Tokenizer.from_preset("gpt2_base_en")

gpt2_preprocessor = keras_nlp.models.GPT2CausalLMPreprocessor.from_preset(
    "gpt2_base_en",
    sequence_length=256,
    add_end_token=True,
)

gpt2_lm =
keras_nlp.models.GPT2CausalLM.from_preset(
"gpt2_base_en",
preprocessor=gpt2_preprocessor
)

Un punto en común entre estas tres líneas de código es el método from_preset() , que creará una instancia de la parte de la API de Keras a partir de una arquitectura y/o pesos preestablecidos, cargando así el modelo previamente entrenado. En este fragmento de código, también notará tres componentes modulares:

  1. Tokenizer : convierte una entrada de cadena sin formato en ID de token enteros adecuados para una capa de incrustación de Keras. GPT-2 utiliza específicamente el tokenizador de codificación de pares de bytes (BPE).

  2. Preprocesador : capa para tokenizar y empaquetar entradas que se introducirán en un modelo de Keras. Aquí, el preprocesador rellenará el tensor de ID de token hasta una longitud especificada (256) después de la tokenización.

  3. Backbone : Modelo de Keras que sigue la arquitectura backbone del transformador SoTA y tiene los pesos preestablecidos.

Además, puede consultar la implementación completa del modelo GPT-2 en GitHub .

Conversión de modelo

TensorFlow Lite es una biblioteca móvil para implementar métodos en dispositivos móviles, microcontroladores y otros dispositivos perimetrales. El primer paso es convertir un modelo de Keras a un formato TensorFlow Lite más compacto usando el convertidor TensorFlow Lite y luego usar el intérprete TensorFlow Lite, que está altamente optimizado para dispositivos móviles, para ejecutar el modelo convertido.

Comience con la función generate() de GPT2CausalLM que realiza la conversión. Envuelva la función generate() para crear una función TensorFlow concreta:

@tf.function
def generate(prompt, max_length):
    """
    Args:
        prompt: input prompt to the LLM in string format
        max_length: the max length of the generated tokens
    """
    return gpt2_lm.generate(prompt, max_length)

concrete_func = generate.get_concrete_function(tf.TensorSpec([], tf.string), 100)

Tenga en cuenta que también puede utilizar from_keras_model() de TFLiteConverter para realizar la conversión.

Ahora defina una función auxiliar que ejecutará la inferencia con una entrada y un modelo TFLite. Las operaciones de texto de TensorFlow no son operaciones integradas en el tiempo de ejecución de TFLite, por lo que deberá agregar estas operaciones personalizadas para que el intérprete pueda hacer inferencias en este modelo. Esta función auxiliar acepta una entrada y una función que realiza la conversión, es decir, la función generator() definida anteriormente.

def run_inference(input, generate_tflite):
    interp = interpreter.InterpreterWithCustomOps(
        model_content=generate_tflite,
        custom_op_registerers=
            tf_text.tflite_registrar.SELECT_TFTEXT_OPS
    )

    interp.get_signature_list()

    generator = interp.get_signature_runner('serving_default')
    output = generator(prompt=np.array([input]))

Puedes convertir el modelo ahora:

gpt2_lm.jit_compile = False
converter = tf.lite.TFLiteConverter.from_concrete_functions(
    [concrete_func],
    gpt2_lm)

converter.target_spec.supported_ops = [
    tf.lite.OpsSet.TFLITE_BUILTINS, # enable TFLite ops
    tf.lite.OpsSet.SELECT_TF_OPS, # enable TF ops
]
converter.allow_custom_ops = True
converter.target_spec.experimental_select_user_tf_ops = [
    "UnsortedSegmentJoin",
    "UpperBound"
]
converter._experimental_guarantee_all_funcs_one_use = True
generate_tflite = converter.convert()
run_inference("I'm enjoying a", generate_tflite)

Cuantización

TensorFlow Lite ha implementado una técnica de optimización llamada cuantificación que puede reducir el tamaño del modelo y acelerar la inferencia. A través del proceso de cuantificación, los flotantes de 32 bits se asignan a enteros más pequeños de 8 bits, lo que reduce el tamaño del modelo en un factor de 4 para una ejecución más eficiente en hardware moderno. Hay varias formas de realizar la cuantización en TensorFlow. Puede visitar las páginas de optimización del modelo TFLite y kit de herramientas de optimización del modelo TensorFlow para obtener más información. Los tipos de cuantificaciones se explican brevemente a continuación.

Aquí, utilizará la cuantificación del rango dinámico posterior al entrenamiento en el modelo GPT-2 configurando el indicador de optimización del convertidor en tf.lite.Optimize.DEFAULT , y el resto del proceso de conversión es el mismo que se detalló anteriormente. Probamos que con esta técnica de cuantificación la latencia es de alrededor de 6,7 segundos en Pixel 7 con una longitud de salida máxima establecida en 100.

gpt2_lm.jit_compile = False
converter = tf.lite.TFLiteConverter.from_concrete_functions(
    [concrete_func],
    gpt2_lm)

converter.target_spec.supported_ops = [
    tf.lite.OpsSet.TFLITE_BUILTINS, # enable TFLite ops
    tf.lite.OpsSet.SELECT_TF_OPS, # enable TF ops
]
converter.allow_custom_ops = True
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.target_spec.experimental_select_user_tf_ops = [
    "UnsortedSegmentJoin",
    "UpperBound"
]
converter._experimental_guarantee_all_funcs_one_use = True
quant_generate_tflite = converter.convert()
run_inference("I'm enjoying a", quant_generate_tflite)

Gama dinámica

La cuantificación del rango dinámico es el punto de partida recomendado para optimizar los modelos en el dispositivo. Puede lograr una reducción de aproximadamente 4 veces el tamaño del modelo y es un punto de partida recomendado, ya que proporciona un uso reducido de memoria y un cálculo más rápido sin tener que proporcionar un conjunto de datos representativo para la calibración. Este tipo de cuantificación cuantifica estáticamente sólo los pesos desde punto flotante hasta entero de 8 bits en el momento de la conversión.

FP16

Los modelos de coma flotante también se pueden optimizar cuantificando los pesos al tipo float16. Las ventajas de la cuantificación float16 son reducir el tamaño del modelo hasta a la mitad (ya que todos los pesos llegan a ser la mitad de su tamaño), causar una pérdida mínima de precisión y admitir delegados de GPU que pueden operar directamente con datos float16 (lo que resulta en un cálculo más rápido que en float32). datos). Un modelo convertido a pesos float16 aún puede ejecutarse en la CPU sin modificaciones adicionales. Los pesos float16 se muestrean a float32 antes de la primera inferencia, lo que permite una reducción en el tamaño del modelo a cambio de un impacto mínimo en la latencia y la precisión.

Cuantización entera completa

La cuantificación de enteros completos convierte los números de punto flotante de 32 bits, incluidos los pesos y las activaciones, a los enteros de 8 bits más cercanos. Este tipo de cuantificación da como resultado un modelo más pequeño con mayor velocidad de inferencia, lo cual es increíblemente valioso cuando se utilizan microcontroladores. Este modo se recomienda cuando las activaciones son sensibles a la cuantización.

Integración de aplicaciones de Android

Puede seguir este ejemplo de Android para integrar su modelo TFLite en una aplicación de Android.

Requisitos previos

Si aún no lo has hecho, instala Android Studio , siguiendo las instrucciones del sitio web.

  • Android Studio 2022.2.1 o superior.
  • Un dispositivo Android o emulador de Android con más de memoria 4G

Construyendo y ejecutando con Android Studio

  • Abra Android Studio y, en la pantalla de bienvenida, seleccione Abrir un proyecto de Android Studio existente .
  • Desde la ventana Abrir archivo o proyecto que aparece, navegue y seleccione el directorio lite/examples/generative_ai/android desde donde clonó el repositorio de GitHub de muestra de TensorFlow Lite.
  • Es posible que también necesites instalar varias plataformas y herramientas según los mensajes de error.
  • Cambie el nombre del modelo .tflite convertido a autocomplete.tflite y cópielo en la carpeta app/src/main/assets/ .
  • Seleccione el menú Construir -> Crear proyecto para construir la aplicación. (Ctrl+F9, dependiendo de su versión).
  • Haga clic en el menú Ejecutar -> Ejecutar 'aplicación' . (Shift+F10, dependiendo de su versión)

Alternativamente, también puedes usar el contenedor Gradle para compilarlo en la línea de comando. Consulte la documentación de Gradle para obtener más información.

(Opcional) Generar el archivo .aar

De forma predeterminada, la aplicación descarga automáticamente los archivos .aar necesarios. Pero si desea crear el suyo propio, cambie a la carpeta app/libs/build_aar/ y ejecute ./build_aar.sh . Este script obtendrá las operaciones necesarias de TensorFlow Text y creará el aar para los operadores Select TF.

Después de la compilación, se genera un nuevo archivo tftext_tflite_flex.aar . Reemplace el archivo .aar en la carpeta app/libs/ y reconstruya la aplicación.

Tenga en cuenta que aún debe incluir el aar tensorflow-lite estándar en su archivo gradle.

Tamaño de la ventana de contexto

La aplicación tiene un parámetro modificable 'tamaño de ventana de contexto', que es necesario porque los LLM hoy en día generalmente tienen un tamaño de contexto fijo que limita la cantidad de palabras/tokens que se pueden introducir en el modelo como 'mensaje' (tenga en cuenta que 'palabra' no es necesariamente equivalente a 'token' en este caso, debido a diferentes métodos de tokenización). Este número es importante porque:

  • Si es demasiado pequeño, el modelo no tendrá suficiente contexto para generar resultados significativos.
  • Si lo configura demasiado grande, el modelo no tendrá suficiente espacio para trabajar (ya que la secuencia de salida incluye el mensaje)

Puedes experimentar con él, pero configurarlo en ~50% de la longitud de la secuencia de salida es un buen comienzo.

Seguridad e IA responsable

Como se señaló en el anuncio original de OpenAI GPT-2 , existen advertencias y limitaciones notables con el modelo GPT-2. De hecho, los LLM hoy en día generalmente enfrentan algunos desafíos bien conocidos, como alucinaciones, equidad y prejuicios; Esto se debe a que estos modelos se basan en datos del mundo real, lo que los hace reflejar problemas del mundo real.

Este codelab se creó únicamente para demostrar cómo crear una aplicación impulsada por LLM con herramientas de TensorFlow. El modelo producido en este codelab tiene fines educativos únicamente y no está destinado a uso en producción.

El uso de producción de LLM requiere una selección cuidadosa de conjuntos de datos de capacitación y mitigaciones de seguridad integrales. Una de esas funciones que se ofrece en esta aplicación de Android es el filtro de malas palabras, que rechaza las malas entradas del usuario o las salidas del modelo. Si se detecta algún lenguaje inapropiado, la aplicación a cambio rechazará esa acción. Para obtener más información sobre la IA responsable en el contexto de los LLM, asegúrese de ver la sesión técnica Desarrollo seguro y responsable con modelos de lenguaje generativo en Google I/O 2023 y consulte el kit de herramientas de IA responsable .