Интерпретируемость модели

Завоюйте доверие к своей модели и генерируйте объяснения с помощью LIME и SHAP

Использование машинного обучения для автоматизации процессов широко применяется во многих организациях по всему миру. Как часть команды Data Science Factory в Dell, мы работаем с различными бизнес-подразделениями над созданием инновационных решений на основе данных для оптимизации существующих процессов.

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

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

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

Это сообщение в блоге будет охватывать следующее:

1. SHAP & LIME- фон

2. Примеры

3. Резюме

4. Дополнительная литература

1. ФОРМА И ИЗВЕСТЬ - Предпосылки

LIME (Локальные интерпретируемые независимые от модели объяснения) предоставляет местные объяснения; это может помочь объяснить, почему одна точка данных была отнесена к определенному классу. LIME рассматривает модель как черный ящик; он не делает различий между случайным лесом, деревом решений или нейронными сетями. Он использует линейные модели для локального объяснения. Основная концепция LIME заключается в том, что даже несмотря на то, что линейные модели не могут хорошо объяснить сложные данные / модель, при попытке объяснить наблюдение на местном уровне они могут предоставить адекватное объяснение. Ниже вы можете увидеть рисунок, объясняющий интуицию вокруг LIME. это было взято из газеты: Почему я должен тебе доверять? Объясняя предсказания любого классификатора ».

LIME предлагает три разных объяснения: табличное объяснение (на котором мы остановимся), объяснение изображений и объяснение текста для обработки различных типов данных.

SHAP (Аддитивные объяснения Шэпли) призван объяснить прогнозирование отдельной точки данных путем вычисления вклада каждой функции в прогноз. Сгенерированное объяснение основано на вычислении значений Шепли из коалиционной теории игр (подробнее об этом вы можете прочитать здесь). Он основан на следующем сценарии: допустим, вы играете в определенную игру в составе группы, группа выигрывает и в результате зарабатывает деньги (выплаты). Как лучше всего разделить выплату между игроками, чтобы лучше всего отразить вклад каждого игрока в игру? В нашем случае мы хотели бы понять, как разделить прогноз (выплату) между различными функциями (игроками) в модели, чтобы наилучшим образом отразить вклад каждой из функций.

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

Описанный процесс может быть дорогостоящим в вычислительном отношении, плюс запуск модели без определенной функции создает совершенно новую модель, которую мы не хотим объяснять / понимать (вы можете услышать об этом больше в этой замечательной лекции, прочитанной Ади Ватцман) . К счастью, SHAP использует различные приближения и оптимизации, которые преодолевают эти трудности.

SHAP предоставляет три разных объяснения: KernalSHAP, который, как и LIME, не зависит от модели, TreeSHAP, который оптимизирован для моделей с древовидной структурой, и DeepSHAP, который представляет собой высокоскоростной алгоритм аппроксимации значений SHAP в моделях глубокого обучения.

В этом посте я сосредоточусь на объяснении дерева, поскольку мы использовали древовидную модель в своем проекте.

2. Примеры

Переходим к некоторым примерам, основанным на нашем сценарии использования с использованием LIME и SHAP.

ЛАЙМ

Чтобы дать объяснение, сначала мы должны создать объяснитель. Объясняющий должен получить следующее:

  • Мы должны указать, имеем ли мы дело с регрессионной или классификационной моделью.
  • Мы должны передать наши обучающие данные, имена функций и имена классов (это необязательно, по умолчанию 0 и 1).
  • Подробно - указывает, хотим ли мы представить дополнительные детали вместе с нашим объяснением.
  • Поскольку в этом процессе присутствует некоторая случайность, чтобы можно было воспроизвести результаты, вам также следует установить переменную random_state.
from lime.lime_tabular import LimeTabularExplainer
lime_explainer = LimeTabularExplainer(train_data.values, 
mode = ’classification’, feature_names = new_feature_names, class_names = [‘Deny’, ’Approve’], verbose=True, 
random_state = 42)

Примечание относительно категориальных функций: если ваша модель содержит категориальные переменные, это немного усложняет ситуацию. Вот краткое объяснение: чтобы предоставить объяснения, LIME использует исходный набор данных для выборки точек данных вокруг наблюдения, которое мы хотели бы объяснить. Если мы предоставим данные, в которых категориальные переменные представлены в одном формате горячего кодирования, в процессе выборки могут быть созданы образцы, которые вряд ли появятся в данных, и сгенерированное объяснение не будет представлять фактические данные. Чтобы преодолеть это, категориальные функции должны быть преобразованы в целочисленные метки. Чтобы узнать больше о том, как использовать LIME с категориальными функциями, я рекомендую вам посмотреть отличную лекцию, прочитанную Кевином Лемагненом, или посетить его страницу GitHub.

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

  • Пример, который вы хотите объяснить.
  • Функция, которая генерирует вероятности (в случае моделей классификации), или функция, которая прогнозирует (в случае регрессионных моделей) для нашего набора данных (в нашем случае - pred_proba).
  • Вы также можете указать максимальное количество функций, которые вы хотели бы использовать для построения локальной линейной модели, в настоящее время мы используем значение по умолчанию, равное 10.
exp = lime_explainer.explain_instance(instance, trained_model.predict_proba)
exp.show_in_notebook(show_table=True)

Затем давайте рассмотрим вывод:

Вверху представлен пересечение линейной модели, созданной LIME, за которым следует локальный прогноз, сгенерированный линейной моделью, и фактический прогноз нашей модели (это результат установки подробного объяснения в значение True). Как видите, прогноз, созданный линейной моделью, и результат, созданный нашей моделью, довольно близки. Затем вы можете увидеть вероятности для каждого класса, как и предполагала исходная модель.

Справа вы можете увидеть значения каждой функции для конкретного наблюдения. Функции имеют цветовую кодировку в зависимости от класса, в который они внесли свой вклад; элементы, окрашенные в оранжевый цвет, способствовали одобрению сделки, в то время как элементы, окрашенные в синий цвет, способствовали отказу от сделки. Кроме того, они отсортированы по их влиянию на прогноз, причем наиболее сильно повлиявшая функция находится наверху. На средней диаграмме вы также можете увидеть величину каждой функции в каждом классе. Также важно понимать, что для того, чтобы LIME предоставляла более интуитивные объяснения, числовые значения делятся на несколько групп, поэтому на средней диаграмме характеристики представлены вдоль определенного диапазона. Это значение по умолчанию в LIME, и его можно изменить, установив для переменной dicretize_continuous значение false.

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

print(‘R²: ‘+str(exp.score))

Это даст нам R в квадрате нашей локальной модели, мы можем использовать оценку, чтобы решить, можем ли мы доверять определенному объяснению или нет.

Кроме того, вы можете получить доступ к весу, присвоенному каждой функции в модели, с помощью следующего кода:

exp.local_exp

Суммирование весов и перехвата приведет к локальному прогнозу, сгенерированному LIME.

exp.intercept[1] + sum([weight[1] for weight in exp.local_exp[1]])

SHAP

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

Во-первых, как и в случае с LIME, мы должны импортировать SHAP, создать объяснитель и передать обученную модель:

import shap
shap.initjs() #This is for us to be able to see the visualizations 
explainer = shap.TreeExplainer(trained_model)

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

Чтобы вычислить значения SHAP для экземпляра, который мы хотим объяснить, вы должны предоставить сам экземпляр, а для создания графика вы должны предоставить следующее:

  • Ожидаемое значение, генерируемое объяснителем, которое, по сути, является средним прогнозом на обучающем наборе, также отмечается как базовое значение.
  • Затем вы должны предоставить значения SHAP, рассчитанные в предыдущей строке (это вклад каждой функции в прогноз модели).
  • Экземпляр, который вы хотите объяснить, и названия функций ».
shap_values = explainer.shap_values(instance)
shap.force_plot(base_value=explainer.expected_value[1], shap_values[1], features=instance, feature_names=new_feature_names)

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

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

TreeSHAP использует структуру дерева и может вычислять точные значения, а не приближение. Суммирование ожидаемого / базового значения даст точный прогноз, как вы можете видеть ниже.

explainer.expected_value[1] + sum(shap_values[1])

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

test_shap_values = explainer.shap_values(test_data.values)
shap.summary_plot(shap_values[1], test_data.values)

Давайте рассмотрим различные аспекты диаграммы:

  • Ось x представляет вклад в прогноз, это значения SHAP.
  • Ось Y слева отображает наиболее важные функции (вы можете указать количество функций, которые хотите отобразить - значение по умолчанию - 20). Функции отсортированы по их влиянию на прогноз, при этом наиболее важные из них находятся вверху.
  • Ось Y справа указывает, как интерпретировать исходные значения для каждого объекта. В каждой строке точки данных окрашены в синий или красный цвет, синий указывает на низкие значения функции, а красный указывает на высокие значения функции.
  • График разделен горизонтальной линией, где с правой стороны вы можете увидеть точки данных, способствовавшие одобрению сделки, а с левой стороны вы можете увидеть точки данных, которые способствовали отказу от сделки.
  • Например, низкие значения в функции x_29 будут вносить вклад в класс утверждения, а высокие значения будут вносить вклад в класс отказа.

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

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

3. Резюме

В этом сообщении блога я поделился с вами своей мотивацией использования инструментов для объяснения моделей машинного обучения, мы рассмотрели основы LIME и SHAP с примерами, основанными на нашем варианте использования.

Оглядываясь на проделанную нами работу, я чувствую, что использование этих инструментов вызвало доверие среди наших деловых партнеров, что привело к более плавному внедрению модели, которую мы построили. Кроме того, использование этих инструментов помогло нам выявить некоторые проблемы, связанные с данными, которые впоследствии были исправлены.

LIME и SHAP - отличные инструменты, которые вы можете использовать для создания доверия, а также для объяснения определенного решения, которое было принято. Когда мы исследовали их на одном и том же экземпляре, мы заметили, что большинство влияющих переменных практически одинаковы как в LIME, так и в SHAP. Однако порядок между ними немного отличается.

Основное преимущество LIME в том, что он быстрее (по крайней мере, для табличных данных), а способ его работы довольно интуитивно понятен. Однако сгенерированное объяснение иногда может быть ненадежным, и для его использования необходимо выполнить некоторую предварительную обработку. SHAP прост в использовании, а также может предоставить общее представление о функциях и о том, как их значения влияют на прогнозы модели. Кроме того, TreeSHAP использует структуру дерева и вычисляет точные значения, а не приближение, однако он менее интуитивно понятен с точки зрения объяснения бизнес-партнерам.

Если вы хотите узнать больше об одном из инструментов, я рекомендую вам проверить ссылки, встроенные в сообщение, а также ссылки ниже.

4. Дополнительная литература

Вот несколько дополнительных рекомендаций по чтению:

  1. Объясните свою модель с помощью значений SHAP - отличное сообщение в блоге, в котором, помимо прочего, SHAP объясняется на числовом примере.
  2. Руководство по объяснению моделей черного ящика - содержит подробные описания интерпретируемых моделей, LIME, SHAP и многого другого!
  3. Local Interpretable Model-Agnostic Explanations (LIME): An Introduction - сообщение в блоге, написанное авторами LIME.

Особая благодарность Ор Херману-Саффару и Идану Ричману-Гошену за обзор и ценные отзывы об этом сообщении в блоге.