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

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

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

Интерпретируемость модели ML с использованием SHAP

Несмотря на то, что за прошедшие годы появилось несколько пакетов, помогающих интерпретировать модели, наиболее популярным среди активного сообщества для экосистемы на основе Python является пакет SHAP Скотта Лундберга (GitHub Link). SHAP (Shapley Additive ExPlanations) использует теоретико-игровой подход для объяснения прогнозов, сделанных моделями машинного обучения. Он основан на идее значений Шепли, которые представляют собой способ определить вклад каждой функции в прогноз модели для данной выборки. По словам автора, это связывает оптимальное распределение кредитов с локальными объяснениями с использованием классических значений Шепли из теории игр и связанных с ними расширений.

SHAP — это простая библиотека для внедрения и адаптации для решения быстрых сценариев использования для исследований и разработок и анализа. Здесь — краткое руководство по началу работы.

Присущая SHAP проблема масштабируемости

Как видно, пакет SHAP представляет собой реализацию Python, созданную для работы на одной машине (многопоточный подход достигается только за счет вычислений на GPU).

К сожалению, бесплатных обедов не бывает! Хотя SHAP имеет множество преимуществ, он по своей природе медленный и часто борется с большими объемами данных. Масштабируемость является проблемой, когда речь заходит об этом замечательном пакете интерпретируемых моделей ML. Вот фрагмент статьи о масштабируемости от создателя SHAP на странице выпуска их официального репозитория Github (slunderberg — это дескриптор GitHub автора):

Тем не менее, масштабируемость является важным фактором в любом рабочем процессе машинного обучения в производственной среде. Наборы данных могут расти вертикально (добавляются новые данные для обучения моделей машинного обучения) или горизонтально (добавляются новые функции в существующую модель машинного обучения), чтобы лучше предсказывать «будущее» на основе «настоящего времени». доступные данные. И поскольку это такой стабильный пакет с активным сообществом вокруг него, должно быть решение проблемы масштабируемости, верно?

Решение для масштабируемости

Абсолютно! Вот некоторые потенциальные решения, предложенные автором для ускорения интерпретации модели с помощью пакета SHAP:

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

Здесь мы пытаемся распараллелить процесс. Как только мы поймем, что происходит внутри, мы будем стремиться использовать устоявшиеся методы распределенной обработки для достижения желаемой скорости в масштабе.

ШАП — под капотом

SHAP (Shapley Additive exPlanations) — это инструмент, который помогает объяснить результаты моделей машинного обучения, определяя вклад каждой функции в прогноз. Он основан на принципах теории игр и может применяться к любой модели машинного обучения. SHAP может определить функции, которые оказывают наибольшее влияние на прогноз модели, и количественно оценить их влияние. Чтобы полностью понять SHAP, необходимо хорошо знать математику. Есть много доступных заметок о математике, стоящей за этим удивительным. (Нажмите здесь для моего любимого).

Но с точки зрения использования это намного проще. Вот наглядная карта всего процесса:

Глядя на это, мы можем легко понять, что узкое место в этом процессе. Это вычисление значения SHAP для каждого предоставленного наблюдения.

Достижение масштабируемости с помощью Spark

Здесь на помощь приходит Apache Spark. Все, что нам нужно сделать, это распределить процесс расчета значения SHAP между узлами-последователями в кластере Spark и создать графики объяснимости на узле-драйвере. Это визуальная карта масштабируемого процесса:

Масштабируемая реализация Pyspark

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

#  ##  load the data to interpret
df = spark.read.load(<<data-path>>, 
                      format="csv", 
                      sep=",",
                      schema=<<data-schema-path>>)

# ##  load the TRAINED ML (tree-based model) to the explainer
#         NOTE: model is the trained model already loaded in-memory
explainer_spark = shap.TreeExplainer(model) 

#  ##  record the default parallelism in the cluster for this job
pd_grp_cnt = spark.sparkContext.defaultParallelism

#  ##  assign random group number to each row in data for parallel grouping
df = df\
      .withColumn('shap_val_calc_grp', F.round(F.rand()*pd_grp_cnt))

#  ##  create a PANDAS UDF for calculating SHAP Values for each group
#        in parallel
@pandas_udf(feature_schema_out, functionType=PandasUDFType.GROUPED_MAP)
def shap_calculations(grp_df):
    """
    Calculates the shap values across input features and returns 
    a grouped dataframe with shap values
    args:
        grp_df: a pandas dataframe grouped by some group column
    returns:
        shap_pdf: a dataframe with shap values
    """
    pdf = grp_df.drop(['shap_val_calc_grp'], axis=1)
    shap_values = explainer_spark.shap_values(pdf)
    shap_pdf = pd.DataFrame(shap_values, columns=pdf.columns)
    return(shap_pdf)

#  ##  calculate SHAP Values for each group in parallel
df_shap_values = df.groupby('shap_val_calc_grp').apply(shap_calculations)

#  ##  initialize the SHAP Explainer for blazing fast interpretability
shap_explainer = shap.Explanation(
            values=df_shap_values.values,
            data=df.drop("shap_val_calc_grp").values,
            feature_names= <<list-containing-feature-names>>
        )


# ## sample SHAP Graph Plotting using the calculated SHAP Values
#      similarly other graphs can be plotted
shap.summary_plot(df_shap_values, df, plot_type="bar") # feature importance

Основная идея приведенного выше кода заключается в следующем:

  1. Загрузите обученную модель машинного обучения в объяснитель SHAP
  2. Назначьте номер ограниченной группы каждому наблюдению в наборе данных для пояснения. Например, если есть 5 групп, вычисление значения искры будет происходить параллельно для 5 разных фрагментов данных. В приведенном выше коде я попытался добиться максимально возможного параллелизма в кластере (используя паралеллизм по умолчанию в Spark).
  3. Рассчитайте значения SHAP параллельно, используя UDF Pandas
  4. Используйте рассчитанные значения SHAP для построения графика объяснимости

Эксперименты на AWS SageMaker

Я провел несколько экспериментов, чтобы понять преимущества предлагаемой реализации PySpark перед реализацией Python в официальном руководстве по SHAP (здесь). Я использовал задания обработки AWS Sagemaker для запуска заданий Spark в распределенном кластере. Таким образом, я мог легко проверить эффект увеличения кластера по горизонтали (добавление большего количества машин одного типа) и по вертикали (добавление более мощных машин с точки зрения ОЗУ или объема памяти). Я также попытался увеличить набор данных как по горизонтали (добавляя больше функций), так и по вертикали (добавляя больше наблюдений), чтобы понять последствия использования подхода Spark по мере роста набора данных. Вот результаты:

Очевидно, что предлагаемый подход к реализации PySpark имеет значительные преимущества масштабируемости по сравнению с исходной реализацией на основе Python с одним узлом. Из экспериментов 9 и 10 видно, что увеличение кластера по горизонтали значительно сокращает время выполнения. Это то, чего мы хотели бы добиться от распределенной системы — более быстрой обработки за счет добавления большего количества машин.

Это самый быстрый способ масштабировать модуль интерпретации моделей машинного обучения уже сегодня!