Construye aplicaciones de chatbot personalizadas utilizando modelos OpenChatkit en Amazon SageMaker.

Build custom chatbot applications using OpenChatkit models on Amazon SageMaker.

Los modelos de lenguaje grandes de código abierto (LLM) se han vuelto populares, permitiendo que investigadores, desarrolladores y organizaciones accedan a estos modelos para fomentar la innovación y experimentación. Esto fomenta la colaboración de la comunidad de código abierto para contribuir al desarrollo y mejora de los LLM. Los LLM de código abierto proporcionan transparencia a la arquitectura del modelo, al proceso de entrenamiento y a los datos de entrenamiento, lo que permite a los investigadores comprender cómo funciona el modelo e identificar posibles sesgos y abordar preocupaciones éticas. Estos LLM de código abierto están democratizando la IA generativa al hacer que la tecnología avanzada de procesamiento de lenguaje natural (NLP) esté disponible para una amplia gama de usuarios para construir aplicaciones comerciales críticas. GPT-NeoX, LLaMA, Alpaca, GPT4All, Vicuna, Dolly y OpenAssistant son algunos de los LLM de código abierto populares.

OpenChatKit es un LLM de código abierto utilizado para construir aplicaciones de chatbot de propósito general y especializadas, lanzado por Together Computer en marzo de 2023 bajo la licencia Apache-2.0. Este modelo permite a los desarrolladores tener más control sobre el comportamiento del chatbot y adaptarlo a sus aplicaciones específicas. OpenChatKit proporciona un conjunto de herramientas, un bot base y bloques de construcción para construir chatbots completamente personalizados y potentes. Los componentes clave son los siguientes:

  • Un LLM ajustado a las instrucciones para el chat de GPT-NeoX-20B de EleutherAI con más de 43 millones de instrucciones en un 100% de carbono negativo. El modelo GPT-NeoXT-Chat-Base-20B se basa en el modelo GPT-NeoX de EleutherAI, y se ajusta con datos enfocados en interacciones de estilo de diálogo.
  • Recetas de personalización para ajustar el modelo y lograr alta precisión en sus tareas.
  • Un sistema de recuperación extensible que le permite aumentar las respuestas del bot con información de un repositorio de documentos, API u otra fuente de información de actualización en tiempo real en el momento de la inferencia.
  • Un modelo de moderación, ajustado desde GPT-JT-6B, diseñado para filtrar a qué preguntas responde el bot.

La creciente escala y tamaño de los modelos de aprendizaje profundo presentan obstáculos para implementar con éxito estos modelos en aplicaciones de IA generativa. Para cumplir con las demandas de baja latencia y alta capacidad de procesamiento, se vuelve esencial emplear métodos sofisticados como el paralelismo del modelo y la cuantificación. La falta de habilidad en la aplicación de estos métodos hace que numerosos usuarios encuentren dificultades para iniciar el alojamiento de modelos de gran tamaño para casos de uso de IA generativa.

En esta publicación, mostramos cómo desplegar modelos OpenChatKit (GPT-NeoXT-Chat-Base-20B y GPT-JT-Moderation-6B) en Amazon SageMaker usando DJL Serving y bibliotecas de paralelismo de modelo de código abierto como DeepSpeed y Hugging Face Accelerate. Usamos DJL Serving, que es una solución universal de alto rendimiento para servir modelos impulsada por la Biblioteca de Java Profundo (DJL) que es agnóstica en lenguaje de programación. Demostramos cómo la biblioteca Hugging Face Accelerate simplifica la implementación de modelos grandes en múltiples GPUs, reduciendo así la carga de ejecutar LLM de manera distribuida. ¡Empecemos!

Sistema de recuperación extensible

Un sistema de recuperación extensible es uno de los componentes clave de OpenChatKit. Permite personalizar la respuesta del bot en función de una base de conocimientos de dominio cerrado. Aunque los LLM pueden retener conocimientos factuales en sus parámetros de modelo y pueden lograr un rendimiento notable en tareas de NLP cuando se ajustan, su capacidad para acceder y predecir con precisión el conocimiento de dominios cerrados sigue siendo limitada. Por lo tanto, cuando se presentan con tareas intensivas en conocimientos, su rendimiento se ve afectado en comparación con arquitecturas específicas de la tarea. Puede utilizar el sistema de recuperación OpenChatKit para aumentar el conocimiento en sus respuestas desde fuentes de conocimiento externas como Wikipedia, repositorios de documentos, API y otras fuentes de información.

El sistema de recuperación permite al chatbot acceder a información actual obteniendo detalles pertinentes en respuesta a una consulta específica, suministrando así el contexto necesario para que el modelo genere respuestas. Para ilustrar la funcionalidad de este sistema de recuperación, brindamos soporte para un índice de artículos de Wikipedia y ofrecemos código de ejemplo que demuestra cómo invocar una API de búsqueda web para la recuperación de información. Siguiendo la documentación proporcionada, puede integrar el sistema de recuperación con cualquier conjunto de datos o API durante el proceso de inferencia, permitiendo que el chatbot incorpore datos actualizados dinámicamente en sus respuestas.

Modelo de moderación

Los modelos de moderación son importantes en las aplicaciones de chatbot para hacer cumplir el filtrado de contenido, el control de calidad, la seguridad del usuario y razones legales y de cumplimiento. La moderación es una tarea difícil y subjetiva, y depende mucho del dominio de la aplicación de chatbot. OpenChatKit proporciona herramientas para moderar la aplicación del chatbot y monitorear las entradas de texto para detectar cualquier contenido inapropiado. El modelo de moderación proporciona una buena línea de base que se puede adaptar y personalizar a diversas necesidades.

OpenChatKit cuenta con un modelo de moderación de 6 mil millones de parámetros, GPT-JT-Moderation-6B, que puede moderar el chatbot para limitar las entradas a los temas moderados. Aunque el modelo en sí mismo tiene algo de moderación incorporada, TogetherComputer entrenó un modelo GPT-JT-Moderation-6B con el conjunto de datos de moderación de Ontocord.ai OIG. Este modelo se ejecuta junto al chatbot principal para comprobar que tanto la entrada del usuario como la respuesta del bot no contengan resultados inapropiados. También se puede utilizar para detectar cualquier pregunta fuera del dominio del chatbot y anular cuando la pregunta no forma parte del dominio del chatbot.

El siguiente diagrama ilustra el flujo de trabajo de OpenChatKit.

Casos de uso de sistemas de recuperación extensibles

Aunque podemos aplicar esta técnica en varias industrias para construir aplicaciones de IA generativas, para esta publicación discutimos casos de uso en la industria financiera. La generación aumentada de recuperación se puede emplear en la investigación financiera para generar automáticamente informes de investigación sobre empresas específicas, industrias o productos financieros. Al recuperar información relevante de bases de conocimientos internas, archivos financieros, artículos de noticias e investigaciones, se pueden generar informes exhaustivos que resuman las ideas clave, las métricas financieras, las tendencias del mercado y las recomendaciones de inversión. Se puede utilizar esta solución para monitorear y analizar noticias financieras, sentimiento del mercado y tendencias.

Descripción general de la solución

Los siguientes pasos están involucrados en la construcción de un chatbot utilizando los modelos de OpenChatKit y desplegarlos en SageMaker:

  1. Descargar el modelo base de chat GPT-NeoXT-Chat-Base-20B y empaquetar los artefactos del modelo para ser cargados en Amazon Simple Storage Service (Amazon S3).
  2. Utilizar un contenedor de inferencia de modelo grande de SageMaker, configurar las propiedades y configurar el código de inferencia personalizado para implementar este modelo.
  3. Configurar técnicas de paralelización de modelos y utilizar bibliotecas de optimización de inferencia en las propiedades del servicio DJL. Utilizaremos Hugging Face Accelerate como motor para DJL Serving. Además, definimos configuraciones paralelas de tensor para particionar el modelo.
  4. Crear una configuración de modelo de SageMaker y un punto de enlace de configuración, y desplegar el punto de enlace de SageMaker.

Puedes seguir los pasos siguiendo el cuaderno en el repositorio de GitHub.

Descargar el modelo de OpenChatKit

Primero, descargamos el modelo base de OpenChatKit. Utilizamos huggingface_hub y utilizamos snapshot_download para descargar el modelo, que descarga un repositorio completo en una revisión determinada. Las descargas se realizan en paralelo para acelerar el proceso. Consulta el siguiente código:

from huggingface_hub import snapshot_download
from pathlib import Path
import os
# - Esto descargará el modelo en el directorio actual donde se esté ejecutando el cuaderno de Jupyter
local_model_path = Path("./openchatkit")
local_model_path.mkdir(exist_ok=True)
model_name = "togethercomputer/GPT-NeoXT-Chat-Base-20B"
# Solo descargar archivos de puntos de control pytorch
allow_patterns = ["*.json", "*.pt", "*.bin", "*.txt", "*.model"]
# - Aproveche la biblioteca de instantáneas para descargar el modelo ya que el modelo se almacena en el repositorio usando LFS
chat_model_download_path = snapshot_download(
    repo_id=model_name,#Un nombre de usuario o un nombre de repositorio de una organización
    cache_dir=local_model_path, #Ruta a la carpeta donde se almacenan los archivos en caché.
    allow_patterns=allow_patterns, #solo se descargan archivos coincidentes con al menos un patrón.
)

Propiedades de DJL Serving

Puedes utilizar contenedores de SageMaker LMI para alojar modelos de IA generativos grandes con código de inferencia personalizado sin proporcionar tu propio código de inferencia. Esto es extremadamente útil cuando no hay un preprocesamiento personalizado de los datos de entrada o un posprocesamiento de las predicciones del modelo. También puedes implementar un modelo utilizando un código de inferencia personalizado. En esta publicación, demostramos cómo implementar modelos de OpenChatKit con código de inferencia personalizado.

SageMaker espera los artefactos del modelo en formato tar. Creamos cada modelo de OpenChatKit con los siguientes archivos: serving.properties y model.py.

El archivo de configuración serving.properties indica a DJL Serving qué paralelización de modelos y bibliotecas de optimización de inferencia desea utilizar. A continuación se muestra una lista de configuraciones que utilizamos en este archivo de configuración:

openchatkit/serving.properties
engine = Python
option.tensor_parallel_degree = 4
option.s3url = {{s3url}}

Esto contiene los siguientes parámetros:

  • motor – El motor que DJL usará.
  • option.entryPoint – El archivo o módulo Python de entrada. Esto debe estar alineado con el motor que se está utilizando.
  • option.s3url – Establezca esto en la URI del bucket de S3 que contiene el modelo.
  • option.modelid – Si desea descargar el modelo de huggingface.co, puede establecer option.modelid en el ID del modelo de un modelo preentrenado alojado dentro de un repositorio de modelos en huggingface.co (https://huggingface.co/models). El contenedor utiliza este ID de modelo para descargar el repositorio de modelos correspondiente en huggingface.co.
  • option.tensor_parallel_degree – Establezca esto en el número de dispositivos GPU sobre los cuales DeepSpeed necesita particionar el modelo. Este parámetro también controla el número de trabajadores por modelo que se iniciarán cuando DJL Serving se ejecute. Por ejemplo, si tenemos una máquina de 8 GPU y estamos creando ocho particiones, entonces tendremos un trabajador por modelo para atender las solicitudes. Es necesario ajustar el grado de paralelismo e identificar el valor óptimo para una determinada arquitectura de modelo y plataforma de hardware. Llamamos a esta capacidad paralelismo adaptado a la inferencia.

Consulte Configuraciones y ajustes para obtener una lista exhaustiva de opciones.

Modelos OpenChatKit

La implementación del modelo base OpenChatKit tiene los siguientes cuatro archivos:

  • model.py – Este archivo implementa la lógica de manejo para el modelo principal OpenChatKit GPT-NeoX. Recibe la solicitud de entrada de inferencia, carga el modelo, carga el índice de Wikipedia y sirve la respuesta. Consulte model.py (creado como parte del cuaderno) para obtener detalles adicionales. model.py utiliza las siguientes clases clave:
    • OpenChatKitService – Esto maneja el paso de datos entre el modelo GPT-NeoX, la búsqueda Faiss y el objeto de conversación. Los objetos WikipediaIndex y Conversation se inicializan y se envían las conversaciones de chat de entrada al índice para buscar contenido relevante de Wikipedia. Esto también genera un ID único para cada invocación si no se suministra con el propósito de almacenar las sugerencias en Amazon DynamoDB.
    • ChatModel – Esta clase carga el modelo y el tokenizador y genera la respuesta. Maneja la partición del modelo en múltiples GPU utilizando tensor_parallel_degree, y configura los dtypes y device_map. Las sugerencias se pasan al modelo para generar respuestas. Se configura un criterio de detención StopWordsCriteria para la generación para producir solo la respuesta del bot en inferencia.
    • ModerationModel – Usamos dos modelos de moderación en la clase ModerationModel: el modelo de entrada para indicar al modelo de chat que la entrada es inapropiada para anular el resultado de la inferencia, y el modelo de salida para anular el resultado de la inferencia. Clasificamos la sugerencia de entrada y la respuesta de salida con las siguientes etiquetas posibles:
      • casual
      • necesita precaución
      • necesita intervención (esto se marca para ser moderado por el modelo)
      • posiblemente necesita precaución
      • probablemente necesita precaución
  • wikipedia_prepare.py – Este archivo maneja la descarga y preparación del índice de Wikipedia. En esta publicación, utilizamos un índice de Wikipedia proporcionado en Hugging Face datasets. Para buscar los documentos de Wikipedia para obtener texto relevante, es necesario descargar el índice de Hugging Face porque no está empaquetado en otro lugar. El archivo wikipedia_prepare.py es responsable de manejar la descarga cuando se importa. Solo un proceso en los múltiples que se ejecutan para la inferencia puede clonar el repositorio. El resto espera hasta que los archivos estén presentes en el sistema de archivos local.
  • wikipedia.py – Este archivo se utiliza para buscar el índice de Wikipedia para documentos contextualmente relevantes. La consulta de entrada se tokeniza y se crean incrustaciones utilizando mean_pooling. Calculamos métricas de distancia de similitud de coseno entre la incrustación de consulta y el índice de Wikipedia para recuperar oraciones de Wikipedia contextualmente relevantes. Consulte wikipedia.py para obtener detalles de implementación.

#función para crear la incrustación de oraciones usando mean_pooling
def mean_pooling(token_embeddings, mask):
    token_embeddings = token_embeddings.masked_fill(~mask[..., None].bool(), 0.0)
    sentence_embeddings = token_embeddings.sum(dim=1) / mask.sum(dim=1)[..., None]
    return sentence_embeddings

#función para calcular la distancia de similitud coseno entre 2 incrustaciones
def cos_sim_2d(x, y):
    norm_x = x / np.linalg.norm(x, axis=1, keepdims=True)
    norm_y = y / np.linalg.norm(y, axis=1, keepdims=True)
    return np.matmul(norm_x, norm_y.T)
  • conversation.py – Este archivo se utiliza para almacenar y recuperar el hilo de conversación en DynamoDB para pasar al modelo y al usuario. conversation.py está adaptado del repositorio de código abierto OpenChatKit. Este archivo es responsable de definir el objeto que almacena los turnos de conversación entre el humano y el modelo. Con esto, el modelo es capaz de retener una sesión para la conversación, lo que permite al usuario hacer referencia a mensajes anteriores. Debido a que las invocaciones de los puntos finales de SageMaker no tienen estado, esta conversación debe almacenarse en una ubicación externa a las instancias de puntos finales. Al iniciarse, la instancia crea una tabla DynamoDB si no existe. Todas las actualizaciones en la conversación se almacenan en DynamoDB según la clave session_id, que es generada por el punto final. Cualquier invocación con un ID de sesión recuperará la cadena de conversación asociada y la actualizará según sea necesario.

Construir un contenedor de inferencia LMI con dependencias personalizadas

La búsqueda de índice utiliza la biblioteca Faiss de Facebook para realizar la búsqueda de similitud. Como esto no está incluido en la imagen base de LMI, es necesario adaptar el contenedor para instalar esta biblioteca. El siguiente código define un Dockerfile que instala Faiss desde la fuente junto con otras bibliotecas necesarias para el punto final del bot. Usamos la utilidad sm-docker para crear y enviar la imagen a Amazon Elastic Container Registry (Amazon ECR) desde Amazon SageMaker Studio. Consulte Uso de la CLI de creación de imágenes de contenedor de Amazon SageMaker Studio para crear imágenes de contenedor desde sus blocs de notas de Studio para obtener más detalles.

El contenedor DJL no tiene Conda instalado, por lo que es necesario clonar y compilar Faiss desde la fuente. Para instalar Faiss, deben instalarse las dependencias para usar las API de BLAS y el soporte de Python. Después de instalar estos paquetes, se configura Faiss para usar AVX2 y CUDA antes de ser compilado con las extensiones de Python instaladas.

Después se instalan pandas, fastparquet, boto3 y git-lfs porque son necesarios para descargar y leer los archivos de índice.

FROM 763104351884.dkr.ecr.us-east-1.amazonaws.com/djl-inference:0.21.0-deepspeed0.8.0-cu117
ARG FAISS_URL=https://github.com/facebookresearch/faiss.git
RUN apt-get update && apt-get install -y git-lfs wget cmake pkg-config build-essential apt-utils
RUN apt search openblas && apt-get install -y libopenblas-dev swig
RUN git clone $FAISS_URL && \
cd faiss && \
cmake -B build . -DFAISS_OPT_LEVEL=avx2 -DCMAKE_CUDA_ARCHITECTURES="86" && \
make -C build -j faiss && \
make -C build -j swigfaiss && \
make -C build -j swigfaiss_avx2 && \
(cd build/faiss/python && python -m pip install )

RUN pip install pandas fastparquet boto3 && \
git lfs install --skip-repo && \
apt-get clean all

Crear el modelo

Ahora que tenemos la imagen Docker en Amazon ECR, podemos proceder a crear el objeto modelo de SageMaker para los modelos OpenChatKit. Desplegamos los modelos de moderación de entrada y salida GPT-NeoXT-Chat-Base-20B utilizando GPT-JT-Moderation-6B. Consulte create_model para obtener más detalles.

from sagemaker.utils import name_from_base

chat_model_name = name_from_base(f"gpt-neoxt-chatbase-ds")
print(chat_model_name)

create_model_response = sm_client.create_model(
    ModelName=chat_model_name,
    ExecutionRoleArn=role,
    PrimaryContainer={
        "Image": chat_inference_image_uri,
        "ModelDataUrl": s3_code_artifact,
    },
)
chat_model_arn = create_model_response["ModelArn"]

print(f"Created Model: {chat_model_arn}")

Configurar el punto final

A continuación, definimos la configuración del punto final para los modelos de OpenChatKit. Desplegamos los modelos usando el tipo de instancia ml.g5.12xlarge. Consulte create_endpoint_config para obtener más detalles.

chat_endpoint_config_name = f"{chat_model_name}-config"
chat_endpoint_name = f"{chat_model_name}-endpoint"

chat_endpoint_config_response = sm_client.create_endpoint_config(
    EndpointConfigName=chat_endpoint_config_name,
    ProductionVariants=[
        {
            "VariantName": "variant1",
            "ModelName": chat_model_name,
            "InstanceType": "ml.g5.12xlarge",
            "InitialInstanceCount": 1,
            "ContainerStartupHealthCheckTimeoutInSeconds": 3600,
        },
    ],
)

Desplegar el punto final

Por último, creamos un punto final utilizando el modelo y la configuración de punto final que definimos en los pasos anteriores:

chat_create_endpoint_response = sm_client.create_endpoint(
EndpointName=f"{chat_endpoint_name}", EndpointConfigName=chat_endpoint_config_name
)
print(f"Created Endpoint: {chat_create_endpoint_response['EndpointArn']},")

Ejecutar inferencias desde los modelos de OpenChatKit

Ahora es el momento de enviar solicitudes de inferencia al modelo y obtener las respuestas. Pasamos el texto de entrada y los parámetros del modelo, como temperature, top_k y max_new_tokens. La calidad de las respuestas del chatbot se basa en los parámetros especificados, por lo que se recomienda medir el rendimiento del modelo contra estos parámetros para encontrar la configuración óptima para su caso de uso. El texto de entrada se envía primero al modelo de moderación de entrada, y la salida se envía a ChatModel para generar las respuestas. Durante este paso, el modelo utiliza el índice de Wikipedia para recuperar secciones contextualmente relevantes al modelo como indicador para obtener respuestas específicas del dominio del modelo. Finalmente, la respuesta del modelo se envía al modelo de moderación de salida para verificar la clasificación y luego se devuelven las respuestas. Vea el siguiente código:

def chat(prompt, session_id=None, **kwargs):
    if session_id:
        chat_response_model = smr_client.invoke_endpoint(
            EndpointName=chat_endpoint_name,
            Body=json.dumps(
                {
                    "inputs": prompt,
                    "parameters": {
                        "temperature": 0.6,
                        "top_k": 40,
                        "max_new_tokens": 512,
                        "session_id": session_id,
                        "no_retrieval": True,
                    },
                }
            ),
            ContentType="application/json",
        )
    else:
        chat_response_model = smr_client.invoke_endpoint(
            EndpointName=chat_endpoint_name,
            Body=json.dumps(
                {
                    "inputs": prompt,
                    "parameters": {
                        "temperature": 0.6,
                        "top_k": 40,
                        "max_new_tokens": 512,
                    },
                }
            ),
            ContentType="application/json",
        )
    response = chat_response_model["Body"].read().decode("utf8")
    return response
prompts = "¿Qué hace un ingeniero de datos?"
chat(prompts)

Consulte las siguientes interacciones de chat de muestra.

Limpieza

Siga las instrucciones en la sección de limpieza para eliminar los recursos provistos como parte de esta publicación y evitar cargos innecesarios. Consulte Amazon SageMaker Pricing para obtener detalles sobre el costo de las instancias de inferencia.

Conclusión

En esta publicación, discutimos la importancia de los modelos de LLM de código abierto y cómo desplegar un modelo de OpenChatKit en SageMaker para construir aplicaciones de chatbot de próxima generación. Discutimos varios componentes de los modelos de OpenChatKit, modelos de moderación y cómo usar una fuente de conocimiento externa como Wikipedia para flujos de trabajo de generación aumentada de recuperación (RAG). Puede encontrar instrucciones paso a paso en el cuaderno de GitHub . Cuéntenos sobre las increíbles aplicaciones de chatbot que está construyendo. ¡Salud!