Modelos interpretables con Python SHAPEnrique Blanco 27 abril, 2021 Recientemente se publicó en este blog un interesante artículo sobre la interpretabilidad de modelos de Machine Learning. Los modelos de inteligencia artificial se han vuelto complejos, en especial con el auge del Deep Learning. Este es un problema grave, especialmente cuando los humanos son responsables de las decisiones basadas en soluciones digitales. El objetivo de hacer que los algoritmos sean accesibles, entendible e interpretables es fundamental para lo que se conoce como «Inteligencia Artificial Explicable (XAI)«, y en los últimos tres años se ha convertido en un área de investigación muy activa. En este post vamos a realizar un ejemplo simple de cómo dotar de explicabilidad e interpretabilidad a un modelo de análisis de sentimiento de regresión logística lineal usando la librería de Python Shap. Tomando como ejemplo un análisis típico de sentimiento sobre un dataset de críticas de películas, veremos cómo los valores SHAP de cada palabra nos permitirán entender cuáles son las más importantes a la hora de tomar la decisión de si esa crítica es buena o mala.Con un modelo lineal el valor SHAP para la característica para la predicción (asumiendo que las características son independientes) es simplemente: Dado que estamos explicando un modelo de regresión logística, las unidades de los valores SHAP estarán en el espacio log-odds.No nos vamos a complicar para realizar esta prueba de usabilidad; el conjunto de datos que utilizamos es el conjunto de datos clásico de IMDB de este enlace. Para empezar a usar la librería, dentro de nuestro entorno virtual de Python, simplemente hay que ejecutar el siguiente comando en un terminal: pip install shap Importando librerías Para esta rápida prueba, vamos a usar scikit-learn como librería desde la que haremos uso de las funciones necesarias. import sklearn from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.model_selection import train_test_split from sklearn.metrics import classification_report import numpy as np import shap from gensim.parsing.preprocessing import remove_stopwords shap.initjs() Cargando y procesando en IMDB dataset corpus, y = shap.datasets.imdb() Como ejemplo, tenemos la siguiente reseña: corpus[10] This film is one giant pant load. Paul Schrader is utterly lost in his own bad screenplay. And his directing is about as comatose as it can be without his actually having been sleepwalking during the process. <br /><br />The worst though is Woody Harrelson, whom I ordinarily like when he's properly cast... Estamos manejando un dataset perfectamente balanceado, con 12500 reseñas positivas y el mismo número de reseñas negativas. print('Posibles etiquetas para el dataset: ', np.unique(y, return_counts=True)) Posibles etiquetas para el dataset: (array([False, True]), array([12500, 12500])) Antes de empezar con la tokenización de las palabras que componen las reseñas de las películas, debemos eliminar las stopwords de nuestro dataset, sobre lo que ya hablamos con anterioridad en este blog. Estas palabras no añaden información válida a la reseña y son muy frecuentes (conjunciones, preposiciones, pronombres, verbos auxiliares, etc.) Este paso se puede abordar con un simple bucle para todas las reseñas: corpus_cleaned = list() for review in corpus: corpus_cleaned.append(remove_stopwords(review).replace('</br>', '')) Por ejemplo, la reseña corpus[10] queda de la siguiente manera: corpus_cleaned[10] This film giant pant load. Paul Schrader utterly lost bad screenplay. And directing comatose actually having sleepwalking process. </></>The worst Woody Harrelson, I ordinarily like he\'s properly cast... Partición train-test del dataset Una vez nuestro dataset está limpio de stopwords, se debe realizar la partición entrenamiento-testeo (vamos a elegir una razón 80%-20%) y se procede a su transformación TF-IDF con la TfidfVectorizer de sklearn. corpus_train, corpus_test, y_train, y_test = train_test_split(corpus_cleaned, y, test_size=0.2, random_state=42) vectorizer = TfidfVectorizer(min_df=10) X_train = vectorizer.fit_transform(corpus_train).toarray() # sparse also works but Explanation slicing is not yet supported X_test = vectorizer.transform(corpus_test).toarray() Con este paso ya tenemos la partición train-test realizada con 20,000 muestras de entrenamiento y 5,000 muestras de testeo. Cada una de esas muestras o arrays tiene 16,364 elementos. print(X_train.shape) print(X_test.shape) (20000, 16364) (5000, 16364) Entrenando un algoritmo de Regresión Logística model = sklearn.linear_model.LogisticRegression(penalty="l2", C=0.1) model.fit(X_train, y_train) LogisticRegression(C=0.1, class_weight=None, dual=False, fit_intercept=True, intercept_scaling=1, l1_ratio=None, max_iter=100, multi_class='auto', n_jobs=None, penalty='l2', random_state=None, solver='lbfgs', tol=0.0001, verbose=0, warm_start=False) Tras este rápido entrenamiento, el comportamiento de nuestro modelo es aceptable. Se consiguen unas precisiones y recalls en el intervalo 0.82-0.88 para los datos de validación. Para esta partición, el comportamiento es muy similar al obtenido en el train dataset. print(classification_report(y_test, model.predict(X_test))) precision recall f1-score support False 0.88 0.82 0.85 2515 True 0.83 0.88 0.85 2485 accuracy 0.85 5000 macro avg 0.85 0.85 0.85 5000 weighted avg 0.85 0.85 0.85 5000 Ahora bien, ¿en qué palabras se está fijando nuestro sencillo modelo de regresión logística para determinar si una secuencia de palabras pertenece a una reseña buena o mala? Con SHAP, visualizar esta información es muy sencillo. Explicación de nuestro modelo lineal explainer = shap.Explainer(model, X_train, feature_names=vectorizer.get_feature_names()) shap_values = explainer(X_test) Resumen de la contribución de todas las características Para obtener una descripción general de qué características son más importantes para un modelo, se pueden trazar los valores SHAP de cada característica para cada muestra. El gráfico siguiente clasifica las características por la suma de las magnitudes de los valores SHAP en todas las muestras y usa los valores SHAP para mostrar la distribución de los impactos que cada característica tiene en la salida del modelo. El color representa el valor de la característica (rojo alto, azul bajo). shap.plots.beeswarm(shap_values) Figura 1. Beeswarm summary plot de la contribución de las características más relevantes para el modelo. Podemos observar cómo altos valores de frecuencias en palabras como bad o worst tienen un impacto negativo importante en la toma de decisiones del modelo. Si esas palabras aparecen en una reseña, es bastante probable que la misma sea mala. Por el contrario, palabras como great, best o love son indicativos de que la reseña tiene altas probabilidades de ser positivas. Al final, el criterio de nuestro modelo de clasificación termina siendo bastante simple y fácilmente interpretable. Explicación de la predicción del sentimiento de la segunda reseña ind = 1 print("Reseña Positiva" if y_test[ind] else "Reseña Negativa") print(corpus_test[ind]) Reseña Positiva The idea ia short film lot information. Interesting, entertaining leaves viewer wanting more. The producer produced short film excellent quality compared short film I seen. I rated film highest possible rating. I recommend shown office managers ... Otra forma de visualizar la contribución de cada componente a la decisión final del modelo sobre una secuencia de muestra es el force plot (descrito en el paper Nature BME paper): shap.plots.force(shap_values[ind]) Figura 2. Force plot de la contribución de las palabras más relevantes a la toma de decisión. Otra librería similar es LIME, la cual es capaz de explicar cualquier clasificador, con dos o más clases. Todo lo que necesitamos es que el clasificador implemente una función que tome texto sin formato o una matriz numérica y genere una probabilidad para cada clase, también integrado para clasificadores de scikit-learn. Jugaremos con esta librería en próximos posts. Para mantenerte al día con el área de Internet of Things de Telefónica visita nuestra página web o síguenos en Twitter, LinkedIn y YouTube Deep Learning para predecir la calidad del aire¿Qué se trazó en Blockchain antes: el huevo o la gallina?
Víctor Vallejo Carballo AI of Things (V): Recomendación y optimización de contenido publicitario en pantallas inteligentes Conoce los beneficios que tecnologías como las pantallas inteligentes y el Big Data ofrecen al sector de la publicidad exterior
Telefónica Tech Boletín semanal de ciberseguridad, 7—13 de mayo Vulnerabilidad en BIG-IP explotada para el borrado de información El pasado 4 de mayo F5 corregía entre otras, una vulnerabilidad que afectaba a dispositivos BIG-IP (CVE-2022-1388 CVSSv3 9.8), que podría...
Santiago Morante La Inteligencia Artificial en las películas de ciencia ficción: un patrón recurrente de fascinación y terror Así retrata Hollywood los avances en Inteligencia Artificial: descubre qué es el "patrón R.U.R" y por qué lo aplican muchas películas de ciencia ficción
Sandra Tello Hernández Las empresas de tecnología buscan mujeres STEM para impulsar el crecimiento del sector Por qué aumentar la presencia de mujeres en carreras STEM supone una oportunidad de crecimiento para el sector tecnológico
Juan Elosua Tomé Shadow: tecnología de protección contra filtraciones de documentos Shadow, de Telefónica Tech, es una tecnología que permite identificar el origen de una fuga de información como la sucedida recientemente en EE UU
David García El nuevo final de las contraseñas Password, contraseña, clave, frase de paso… ¿Cuántos puedes recordar si no usas un gestor de contraseñas? Es más ¿Usas un gestor?