Развитие интуиции для использования LIME для интерпретации графических и текстовых моделей

Часть 1. Построение интуиции

Часть 2. Известь для интерпретации модели изображения и текста

Прежде чем мы начнем изучать, как использовать LIME для объяснения модели изображения и текста, давайте быстро рассмотрим интуицию LIME, представленную в Part. 1 . (пожалуйста, поймите интуицию части 1, чтобы лучше читать)

LIME Intuition Обзор

Обычно LIME создает суррогатную модель линейной регрессии для аппроксимации прогнозов черного ящика для одного наблюдения и окрестности наблюдения.

Итак, чтобы обучить суррогатную модель линейной регрессии, нам нужно создать обучающий набор данных, с обучающим набором данных, мы можем разрешить суррогатную модель линейной регрессии. Затем мы можем использовать коэффициенты линейной регрессии для объяснения предсказания черного ящика.

При применении LIME к табличным данным, изображениям или тексту существуют разные методы построения обучающего набора данных для суррогатной модели линейной регрессии, и эта история будет сосредоточена на объяснении этих методов.

LIME для модели классификации изображений

Сравните с табличным набором данных (часть 1 имеет интуицию), в области изображений единственное отличие состоит в построении обучающего набора данных, поэтому давайте начнем с него.

Создание набора данных обучения суррогатной регрессии для модели изображения

Предположим, у нас есть обученная модель f для распознавания животных по изображению.

Первый шаг - нам нужно сегментировать изображение на разные области, ниже показан пример сегментации изображения.

На изображении выше есть 53 сегментных области, и каждый сегмент будет рассматриваться как элемент, а каждый элемент представляет собой соответствующую сегментированную область. Разное изображение может иметь разное количество сегментов, и для реализации сегментации изображения можно использовать библиотеку python skimage.

Затем мы создаем обучающий набор данных Z ', Z', имеющий 53 функции, соответствующие 53 сегментам, и для каждого наблюдения в Z ' , мы случайным образом устанавливаем значение каждой функции как 0 или 1, например, одно наблюдение в Z ' может быть (x 1 = 0 , x 2 = 1 , x 3 = 1 , x 4 = 0``, x 53 = 1)

Чтобы получить целевые значения для обучающего набора Z ', сначала нам нужно сопоставить каждый экземпляр Z' с изображением, предположим, что Z ' сопоставлен с Z. Правило сопоставления: Z ' значение свойства 1, сопоставляется с соответствующей областью сегмента исходного изображения, но если 0, то мы устанавливаем соответствующие пиксели области сегмента - 0 на отображенном изображении.

Наконец, мы можем ввести Z (набор сопоставленных изображений) в обученную модель f, чтобы получить целевые значения f (Z).

Выше показано, как мы получаем обучающий набор для разрешения суррогатной регрессии, остальные шаги LIME такие же, как и обработка табличных данных, см. Часть. 1 для подробностей.

Примеры классификации изображений

В примере используется предварительно обученная модель CNN inception_v3 для распознавания изображения.

import keras
import skimage.io 
import skimage.segmentation
import matplotlib.pyplot as plt
import numpy as np
from keras.applications import inception_v3 as inc_net
from keras.preprocessing import image
from keras.applications.imagenet_utils import decode_predictions
%matplotlib inline
def transform_img_fn(path_list):
    out = []
    for img_path in path_list:
        img = image.load_img(img_path, target_size=(299, 299))
        x = image.img_to_array(img)
        x = np.expand_dims(x, axis=0)
        x = inc_net.preprocess_input(x)
        out.append(x)
    return np.vstack(out)
images = transform_img_fn(['Border collie.jpg'])
plt.imshow(images[0] / 2 + 0.5)
inet_model = inc_net.InceptionV3()
preds = inet_model.predict(images)
for x in decode_predictions(preds)[0]:
    print(x)
# Print Output as Below
#('n02106166', 'Border_collie', 0.8173037)
#('n02106030', 'collie', 0.07861717)
#('n02085782', 'Japanese_spaniel', 0.006248728)
#('n02086910', 'papillon', 0.005507174)
#('n02105412', 'kelpie', 0.0031061282)

Затем необходимо создать объяснитель LIME и запустить объяснение для модели inet_model и изображения.

from lime import lime_image
explainer = lime_image.LimeImageExplainer()
explanation = explainer.explain_instance(
    images[0].astype('double'), 
    inet_model.predict, 
    top_labels=5, 
    hide_color=0, 
    num_samples=1000)

Объяснение экземпляра, num_features = 5 означает, что мы хотим выделить 5 основных характеристик (сегментированных областей), которые больше всего способствуют прогнозированию животного (Border_collie), другими словами, наш режим сильно зависит от 5 сегментированных областей распознают Border_collie на изображении.

temp, mask = explanation.get_image_and_mask(
    explanation.top_labels[0], 
    positive_only=True, 
    num_features=5, 
    hide_rest=True)
plt.imshow(skimage.segmentation.mark_boundaries(temp / 2 + 0.5, mask))

Мы также можем отобразить вклады всех сегментов (53 сегмента в примере), как показано ниже, вклады фактически являются коэффициентами признаков суррогатной линейной регрессии.

#Select the same class explained on the figures above.
ind =  explanation.top_labels[0]
#Map each explanation weight to the corresponding superpixel
dict_heatmap = dict(explanation.local_exp[ind])
heatmap = np.vectorize(dict_heatmap.get)(explanation.segments) 
#Plot. The visualization makes more sense if a symmetrical colorbar is used.
plt.imshow(heatmap, cmap = 'RdBu', vmin  = -heatmap.max(), vmax = heatmap.max())
plt.colorbar()

LIME для модели классификации текста

Из опыта использования LIME для объяснения модели изображения мы знаем, что создание набора данных обучения суррогатной регрессии является ключевым, поэтому давайте рассмотрим, как мы можем создать набор данных обучения для текста.

Интуиция для создания набора данных для обучения суррогатной регрессии для модели классификации текста

В классической разработке функций NLP мы используем вектор Bag-of-Words или вектор TF-IDF для представления предложения, и таким образом текст преобразуется в числовой вектор, который может быть введен в классификатор ML.

Например, предположим, что у нас есть целевое предложение из 5 слов и его вектор TF-IDF, как показано ниже, каждый элемент в векторе является значением TF-IDF слова. Обратите внимание, что длина вектора зависит от количества уникальных слов во всей коллекции предложений.

(0.1, 0.2, 0.3, 0.4, 0.5, 0, 0, , , 0)

Давайте создадим набор обучающих данных Z ’, и каждый экземпляр в Z’ будет выглядеть так, как показано ниже.

(0, 1, 0, 1, 0, 0, 0,,, 0) или (1, 0, 1, 0, 1, 0, 0,, , 0), для элементов, соответствующих целевым словам предложения, мы случайным образом устанавливаем значение 0 или 1.

Следующее сопоставление Z ' с Z, аналогично табличным данным и данным изображения, если 1, то сопоставление со значением TF-IDF целевого слова предложения, 0 сопоставление с 0, например

Z ' (0, 1, 0, 1, 0, 0, 0,,, 0) сопоставляется с Z (0 , 0,2, 0, 0,3, 0, 0, 0,,, 0)

Z ' (1, 0, 1, 0, 1, 0, 0,,, 0) сопоставляется с Z (0,1 , 0, 0,3, 0, 0,4, 0, 0,,, 0)

Получив сопоставленный набор данных Z, мы можем получить прогноз модели, введя Z в модель f (Z).

Итак, мы получаем как независимые (Z ’), так и целевые значения (f (Z)) для обучения суррогатной линейной регрессии.

Вообще говоря, мы просто случайным образом удаляем несколько слов из целевого предложения, чтобы сгенерировать набор обучающих данных.

Что касается веса экземпляра, мы можем использовать расстояние между Z ’ и вектором целевого предложения, чтобы получить его.

Примеры классификации текста

Ниже приведен пример из учебника LIME. Базовое использование, двухклассное. Мы объясняем случайные лесные классификаторы .

Модель представляет собой обученный RandomForestClassifier, а текстовая функция - это текстовый вектор TF-IDF, модель предназначена для классификации введенного предложения на атеизм или христианство.

import lime
import sklearn
import numpy as np
import sklearn
import sklearn.ensemble
import sklearn.metrics
from sklearn.datasets import fetch_20newsgroups
categories = ['alt.atheism', 'soc.religion.christian']
newsgroups_train = fetch_20newsgroups(subset='train', categories=categories)
newsgroups_test = fetch_20newsgroups(subset='test', categories=categories)
class_names = ['atheism', 'christian']
vectorizer = sklearn.feature_extraction.text.TfidfVectorizer(lowercase=False)
train_vectors = vectorizer.fit_transform(newsgroups_train.data)
test_vectors = vectorizer.transform(newsgroups_test.data)
rf = sklearn.ensemble.RandomForestClassifier(n_estimators=500)
rf.fit(train_vectors, newsgroups_train.target)
pred = rf.predict(test_vectors)
sklearn.metrics.f1_score(newsgroups_test.target, pred, average='binary')
# Model Testing F1 Score 0.9198606271777003

Создайте поясняющий текст LIME и объясните классификацию модели в 10-м предложении в тестовом наборе данных. Объяснение текста найдет первые 6 слов, которые в основном побуждают модель принимать решение о классификации.

from lime import lime_text
from sklearn.pipeline import make_pipeline
from lime.lime_text import LimeTextExplainer
c = make_pipeline(vectorizer, rf)
explainer = LimeTextExplainer(class_names=class_names)
idx = 10
exp = explainer.explain_instance(
    newsgroups_test.data[idx], 
    c.predict_proba, 
    num_features=6)
print('Document id: %d' % idx)
print('Local Regression Intercept = ', exp.intercept[1])
print('Local Regression Predict = ', exp.local_pred[0])
print('Mode Predict =', c.predict_proba([newsgroups_test.data[idx]])[0,1])
print('True class: %s' % class_names[newsgroups_test.target[idx]])
#Document id: 10
#Local Regression Intercept =  0.7921681682318993
#Local Regression Predict =  0.8715259570414554
#Mode Predict = 0.878
#True class: christian

В приведенном выше примере прогнозируемое значение модели 0,878 и прогнозное значение локальной регрессии 0,8715 очень близки, хорошо аппроксимируются.

Верхние 6 слов и их вклад, как показано ниже, вклад - это коэффициент слова в приближенной суррогатной модели линейной регрессии, поэтому, если мы просуммируем все коэффициенты 6 слов плюс Перехват локальной регрессии, результат будет близок к прогнозу локальной регрессии 0,8715.

exp.as_list()
#[('rutgers', 0.04181413557926221),
# ('athos', 0.026596442528658143),
# ('1993', 0.021911045116494124),
# ('Christ', 0.021213631348501898),
# ('thing', -0.01908916240276232),
# ('Re', -0.016375794316893184)]

LIME также предоставляет хорошее графическое изображение для объяснения прогноза, как показано ниже.

exp.show_in_notebook(text=True)

Резюме

В этой истории основное внимание уделяется интуиции в использовании LIME для моделей изображений и текста, а ключевыми знаниями, которыми можно поделиться, является то, как LIME создает набор данных для обучения суррогатной модели для изображения и текста. Надеюсь, вам понравится история.

ИСПОЛЬЗОВАННАЯ ЛИТЕРАТУРА

  1. Интерпретируемое машинное обучение: https://christophm.github.io/interpretable-ml-book/shap.html
  2. Почему я должен вам доверять?
    Объяснение прогнозов любого классификатора: https://arxiv.org/pdf/1602.04938.pdf
  3. Наука за InterpretML: LIME https://www.youtube.com/watch?v=g2WtL45-PFQ&feature=emb_rel_end
  4. Интерпретируемое машинное обучение с использованием платформы LIME - Касия Кульма (доктор философии) https://www.youtube.com/watch?v=CY3t11vuuOM&t=888s
  5. Понимание того, как LIME объясняет прогнозы https://towardsdatascience.com/understanding-how-lime-explains-predictions-d404e5d1829c
  6. Https://github.com/marcotcr/lime
  7. Https://data4oughtt.com/lime-of-words.html
  8. Https://www.analyticsvidhya.com/blog/2020/02/quick-introduction-bag-of-words-bow-tf-idf/