Análisis de sentimientos en datos cifrados con cifrado homomórfico

'Sentiment analysis on encrypted data with homomorphic encryption'

Es bien sabido que un modelo de análisis de sentimientos determina si un texto es positivo, negativo o neutral. Sin embargo, este proceso generalmente requiere acceso a texto sin cifrar, lo que puede plantear preocupaciones de privacidad.

El cifrado homomórfico es un tipo de cifrado que permite realizar cálculos en datos cifrados sin necesidad de descifrarlos primero. Esto lo hace adecuado para aplicaciones donde los datos personales y potencialmente sensibles de los usuarios están en riesgo (por ejemplo, análisis de sentimientos de mensajes privados).

Esta publicación de blog utiliza la biblioteca Concrete-ML, que permite a los científicos de datos utilizar modelos de aprendizaje automático en entornos de cifrado homomórfico completo (FHE) sin ningún conocimiento previo de criptografía. Proporcionamos un tutorial práctico sobre cómo utilizar la biblioteca para construir un modelo de análisis de sentimientos en datos cifrados.

La publicación cubre:

  • transformadores
  • cómo utilizar transformadores con XGBoost para realizar análisis de sentimientos
  • cómo hacer el entrenamiento
  • cómo utilizar Concrete-ML para convertir predicciones en predicciones sobre datos cifrados
  • cómo implementar en la nube utilizando un protocolo cliente/servidor

Por último, pero no menos importante, terminaremos con una demostración completa en Hugging Face Spaces para mostrar esta funcionalidad en acción.

Configurar el entorno

Primero asegúrese de que su pip y setuptools estén actualizados ejecutando:

pip install -U pip setuptools

Ahora podemos instalar todas las bibliotecas requeridas para este blog con el siguiente comando.

pip install concrete-ml transformers datasets

Usar un conjunto de datos público

El conjunto de datos que utilizamos en este cuaderno se puede encontrar aquí.

Para representar el texto para el análisis de sentimientos, elegimos usar una representación oculta del transformador, ya que ofrece una alta precisión para el modelo final de manera muy eficiente. Para una comparación de esta representación con un procedimiento más común como el enfoque TF-IDF, consulte este cuaderno completo.

Podemos comenzar abriendo el conjunto de datos y visualizando algunas estadísticas.

from datasets import load_datasets
train = load_dataset("osanseviero/twitter-airline-sentiment")["train"].to_pandas()
text_X = train['text']
y = train['airline_sentiment']
y = y.replace(['negative', 'neutral', 'positive'], [0, 1, 2])
pos_ratio = y.value_counts()[2] / y.value_counts().sum()
neg_ratio = y.value_counts()[0] / y.value_counts().sum()
neutral_ratio = y.value_counts()[1] / y.value_counts().sum()
print(f'Proporción de ejemplos positivos: {round(pos_ratio * 100, 2)}%')
print(f'Proporción de ejemplos negativos: {round(neg_ratio * 100, 2)}%')
print(f'Proporción de ejemplos neutrales: {round(neutral_ratio * 100, 2)}%')

La salida se verá así:

Proporción de ejemplos positivos: 16.14%
Proporción de ejemplos negativos: 62.69%
Proporción de ejemplos neutrales: 21.17%

La proporción de ejemplos positivos y neutrales es bastante similar, aunque tenemos significativamente más ejemplos negativos. Tengamos esto en cuenta para seleccionar la métrica de evaluación final.

Ahora podemos dividir nuestro conjunto de datos en conjuntos de entrenamiento y prueba. Utilizaremos una semilla para este código para asegurarnos de que sea perfectamente reproducible.

from sklearn.model_selection import train_test_split
text_X_train, text_X_test, y_train, y_test = train_test_split(text_X, y,
    test_size=0.1, random_state=42)

Representación de texto utilizando un transformador

Los transformadores son redes neuronales entrenadas a menudo para predecir las siguientes palabras que aparecerán en un texto (esta tarea se llama comúnmente aprendizaje auto-supervisado). También se pueden ajustar para tareas específicas de subprocesos de tal manera que se especialicen y obtengan mejores resultados en un problema dado.

Son herramientas poderosas para todo tipo de tareas de procesamiento del lenguaje natural. De hecho, podemos aprovechar su representación para cualquier texto y alimentarla a un modelo de aprendizaje automático más adecuado para el cifrado homomórfico para la clasificación. En este cuaderno, utilizaremos XGBoost.

Comenzamos importando los requisitos para los transformadores. Aquí, utilizamos la biblioteca popular de Hugging Face para obtener rápidamente un transformador.

El modelo que hemos elegido es un transformador BERT, ajustado en el conjunto de datos del Stanford Sentiment Treebank.

import torch
from transformers import AutoModelForSequenceClassification, AutoTokenizer
device = "cuda:0" if torch.cuda.is_available() else "cpu"
# Cargar el tokenizer (convierte el texto en tokens)
tokenizer = AutoTokenizer.from_pretrained("cardiffnlp/twitter-roberta-base-sentiment-latest")

# Cargar el modelo pre-entrenado
transformer_model = AutoModelForSequenceClassification.from_pretrained(
   "cardiffnlp/twitter-roberta-base-sentiment-latest"
)

Esto debería descargar el modelo, que ahora está listo para ser utilizado.

Usar la representación oculta para algún texto puede ser complicado al principio, principalmente porque podríamos abordar esto con muchos enfoques diferentes. A continuación se muestra el enfoque que elegimos.

Primero, tokenizamos el texto. Tokenizar significa dividir el texto en tokens (una secuencia de caracteres específicos que también pueden ser palabras) y reemplazar cada uno con un número. Luego, enviamos el texto tokenizado al modelo transformador, que produce una representación oculta (salida de las capas de autoatención que a menudo se utilizan como entrada para las capas de clasificación) para cada palabra. Finalmente, promediamos las representaciones de cada palabra para obtener una representación a nivel de texto.

El resultado es una matriz de forma (número de ejemplos, tamaño oculto). El tamaño oculto es el número de dimensiones en la representación oculta. Para BERT, el tamaño oculto es 768. La representación oculta es un vector de números que representa el texto y se puede utilizar para muchas tareas diferentes. En este caso, lo utilizaremos para la clasificación con XGBoost posteriormente.

import numpy as np
import tqdm
# Función que transforma una lista de textos en su representación
# aprendida por el modelo transformador.
def texto_a_tensor(
   lista_texto_X_train: list,
   modelo_transformador: AutoModelForSequenceClassification,
   tokenizer: AutoTokenizer,
   dispositivo: str,
) -> np.ndarray:
   # Tokenizar cada texto de la lista uno por uno
   texto_tokenizado_X_train_split = []
   texto_tokenizado_X_train_split = [
       tokenizer.encode(texto_x_train, return_tensors="pt")
       for texto_x_train in lista_texto_X_train
   ]

   # Enviar el modelo al dispositivo
   modelo_transformador = modelo_transformador.to(dispositivo)
   output_hidden_states_list = [None] * len(texto_tokenizado_X_train_split)

   for i, tokenized_x in enumerate(tqdm.tqdm(texto_tokenizado_X_train_split)):
       # Pasar los tokens a través del modelo transformador y obtener los estados ocultos
       # Solo mantener el último estado de la capa oculta por ahora
       output_hidden_states = modelo_transformador(tokenized_x.to(dispositivo), output_hidden_states=True)[
           1
       ][-1]
       # Promediar sobre el eje de los tokens para obtener una representación a nivel de texto.
       output_hidden_states = output_hidden_states.mean(dim=1)
       output_hidden_states = output_hidden_states.detach().cpu().numpy()
       output_hidden_states_list[i] = output_hidden_states

   return np.concatenate(output_hidden_states_list, axis=0)

# Vectoricemos el texto utilizando el modelo transformador
lista_texto_X_train = texto_X_train.tolist()
lista_texto_X_test = texto_X_test.tolist()

X_train_transformador = texto_a_tensor(lista_texto_X_train, transformer_model, tokenizer, dispositivo)
X_test_transformador = texto_a_tensor(lista_texto_X_test, transformer_model, tokenizer, dispositivo)

Esta transformación del texto (de texto a representación del transformador) debe ser ejecutada en la máquina del cliente, ya que el cifrado se realiza sobre la representación del transformador.

Clasificación con XGBoost

Ahora que tenemos nuestros conjuntos de entrenamiento y prueba correctamente construidos para entrenar un clasificador, a continuación viene el entrenamiento de nuestro modelo FHE. Aquí será muy sencillo, utilizando una herramienta de ajuste de hiperparámetros como GridSearch de scikit-learn.

from concrete.ml.sklearn import XGBClassifier
from sklearn.model_selection import GridSearchCV
# Construyamos nuestro modelo
modelo = XGBClassifier()

# Una búsqueda en cuadrícula para encontrar los mejores parámetros
parametros = {
    "n_bits": [2, 3],
    "max_depth": [1],
    "n_estimators": [10, 30, 50],
    "n_jobs": [-1],
}

# Ahora que tenemos una representación para cada tweet, podemos entrenar un modelo con esto.
grid_search = GridSearchCV(modelo, parametros, cv=5, n_jobs=1, scoring="accuracy")
grid_search.fit(X_train_transformador, y_train)

# Verificar la precisión del mejor modelo
print(f"Mejor puntuación: {grid_search.best_score_}")

# Verificar los mejores hiperparámetros
print(f"Mejores parámetros: {grid_search.best_params_}")

# Extraer el mejor modelo
mejor_modelo = grid_search.best_estimator_

El resultado es el siguiente:

Mejor puntuación: 0.8378111718275654
Mejores parámetros: {'max_depth': 1, 'n_bits': 3, 'n_estimators': 50, 'n_jobs': -1}

Ahora, veamos cómo se desempeña el modelo en el conjunto de prueba.

from sklearn.metrics import ConfusionMatrixDisplay
# Calcular las métricas en el conjunto de prueba
y_pred = best_model.predict(X_test_transformer)
y_proba = best_model.predict_proba(X_test_transformer)

# Calcular y graficar la matriz de confusión
matrix = confusion_matrix(y_test, y_pred)
ConfusionMatrixDisplay(matrix).plot()

# Calcular la precisión
accuracy_transformer_xgboost = np.mean(y_pred == y_test)
print(f"Precisión: {accuracy_transformer_xgboost:.4f}")

Con la siguiente salida:

Precisión: 0.8504

Predicción sobre datos encriptados

Ahora vamos a predecir sobre texto encriptado. La idea aquí es que en lugar de encriptar el texto en sí, encriptaremos la representación dada por el transformador. En Concrete-ML, puedes hacer esto rápidamente configurando el parámetro execute_in_fhe=True en la función de predicción. Esta es solo una característica para desarrolladores (principalmente utilizada para verificar el tiempo de ejecución del modelo FHE). Veremos cómo hacer que esto funcione en un entorno de implementación más adelante.

import time
# Compilar el modelo para obtener el motor de inferencia FHE
# (esto puede llevar unos minutos dependiendo del modelo seleccionado)
start = time.perf_counter()
best_model.compile(X_train_transformer)
end = time.perf_counter()
print(f"Tiempo de compilación: {end - start:.4f} segundos")

# Vamos a escribir un ejemplo personalizado y predecir en FHE
tested_tweet = ["AirFrance es increíble, ¡casi tanto como Zama!"]
X_tested_tweet = text_to_tensor(tested_tweet, transformer_model, tokenizer, device)
clear_proba = best_model.predict_proba(X_tested_tweet)

# Ahora vamos a predecir con FHE sobre un solo tweet e imprimir el tiempo que lleva
start = time.perf_counter()
decrypted_proba = best_model.predict_proba(X_tested_tweet, execute_in_fhe=True)
end = time.perf_counter()
fhe_exec_time = end - start
print(f"Tiempo de inferencia FHE: {fhe_exec_time:.4f} segundos")

La salida es:

Tiempo de compilación: 9.3354 segundos
Tiempo de inferencia FHE: 4.4085 segundos

También es necesario comprobar que las predicciones FHE sean iguales a las predicciones claras.

print(f"Probabilidades de la inferencia FHE: {decrypted_proba}")
print(f"Probabilidades del modelo claro: {clear_proba}")

Esta salida muestra:

Probabilidades de la inferencia FHE: [[0.08434131 0.05571389 0.8599448 ]]
Probabilidades del modelo claro: [[0.08434131 0.05571389 0.8599448 ]]

Implementación

En este punto, nuestro modelo está completamente entrenado y compilado, listo para ser implementado. En Concrete-ML, puedes utilizar una API de implementación para hacer esto fácilmente:

# Guardemos el modelo para ser enviado a un servidor más tarde
from concrete.ml.deployment import FHEModelDev
fhe_api = FHEModelDev("sentiment_fhe_model", best_model)
fhe_api.save()

Estas pocas líneas son suficientes para exportar todos los archivos necesarios tanto para el cliente como para el servidor. Puedes consultar el cuaderno que explica esta API de implementación en detalle aquí .

Ejemplo completo en un espacio de Hugging Face

También puedes echar un vistazo a la aplicación final en Hugging Face Space . La aplicación del cliente fue desarrollada con Gradio mientras que el servidor se ejecuta con Uvicorn y fue desarrollado con FastAPI .

El proceso es el siguiente:

  • El usuario genera una nueva clave privada/pública

  • El usuario escribe un mensaje que será codificado, cuantificado y encriptado

  • El servidor recibe los datos encriptados y comienza la predicción sobre los datos encriptados, utilizando la clave de evaluación pública
  • El servidor devuelve las predicciones encriptadas y el cliente puede desencriptarlas utilizando su clave privada

Conclusión

Hemos presentado una forma de aprovechar el poder de los transformadores, donde la representación se utiliza para:

  1. entrenar un modelo de aprendizaje automático para clasificar tweets, y
  2. predecir sobre datos encriptados utilizando este modelo con FHE.

El modelo final (representación de transformadores + XGBoost) tiene una precisión final del 85%, que está por encima de la precisión del transformador en sí mismo con un 80% de precisión (consulte este cuaderno para ver las comparaciones).

El tiempo de ejecución de FHE por ejemplo es de 4.4 segundos en una CPU de 16 núcleos.

Los archivos para el despliegue se utilizan para una aplicación de análisis de sentimientos que permite a un cliente solicitar predicciones de análisis de sentimientos a un servidor mientras mantiene sus datos encriptados a lo largo de la cadena de comunicación.

Concrete-ML (¡No te olvides de estrellarnos en Github ⭐️💛) permite construir modelos de aprendizaje automático de manera sencilla y convertirlos al equivalente de FHE para poder predecir sobre datos encriptados.

¡Esperamos que hayas disfrutado de esta publicación y déjanos saber tus pensamientos/comentarios!

Y un agradecimiento especial a Abubakar Abid por su consejo anterior sobre cómo construir nuestro primer Hugging Face Space!

We will continue to update Zepes; if you have any questions or suggestions, please contact us!

Share:

Was this article helpful?

93 out of 132 found this helpful

Discover more

Inteligencia Artificial

Cómo Reveal's Logikcull utilizó Amazon Comprehend para detectar y redactar información de identificación personal (PII) de documentos legales a gran escala.

Hoy en día, la información personal identificable (PII) está en todas partes. La PII se encuentra en correos electrón...

Inteligencia Artificial

La GPU NVIDIA H100 Tensor Core utilizada en la nueva serie de máquinas virtuales de Microsoft Azure ya está disponible de forma general

Los usuarios de Microsoft Azure ahora pueden recurrir a la última tecnología de computación acelerada de NVIDIA para ...

Inteligencia Artificial

Aterrizaje de Chandrayaan 3 Cómo la IA y los sensores ayudaron en la épica empresa lunar de la ISRO.

En la fascinante expansión de la exploración espacial, cada misión es una apuesta cósmica, cada una un lanzamiento de...

Inteligencia Artificial

Confrontación de modelos de chat GPT-4 vs GPT-3.5 vs LLaMA-2 en un debate simulado - Parte 1

Con Meta revelando recientemente planes para construir un modelo de chat que competirá con GPT-4, y el lanzamiento de...

Inteligencia Artificial

Conoce al Omnívoro Startup desarrolla aplicación que permite a los usuarios convertir objetos en modelos 3D con solo un teléfono inteligente.

Nota del editor: Esta publicación forma parte de nuestra serie Meet the Omnivore, que presenta a creadores y desarrol...

Inteligencia Artificial

Analizar la infestación de roedores utilizando las capacidades geoespaciales de Amazon SageMaker

Los roedores como las ratas y los ratones están asociados con varios riesgos para la salud y se sabe que transmiten m...