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

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

То, как студент пришел к своему выводу, можно легко обосновать, если третье лицо имеет доступ к «модели» и необходимым переменным.

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

Алгоритм

Построение дерева решений выполняется как рекурсивный процесс.

  1. Оцените, какая переменная дает наибольший информационный поток. Прирост информации - это уменьшение энтропии зависимой переменной, когда состояние независимой переменной известно.
    Там много громких слов.
    По сути, это измеряет, насколько более организована независимая переменная, когда мы разбиваем ее на группы в соответствии со значением зависимой переменной.
  2. Выбирается зависимая переменная, которая обеспечивает наибольший рост организации, и набор данных разделяется в соответствии с этой переменной.
  3. На этом этапе должно выполняться одно из трех:
    - Теперь зависимая переменная принимает только одно значение. В этом случае ветвь дерева завершена, и мы достигли «решения».
    - Зависимая переменная принимает ›1 значение. Здесь мы просто возвращаемся к шагу 1 и пытаемся сузить его еще больше.
    -Зависимая переменная принимает ›1 значение, но у нас больше нет независимых переменных, по которым можно разделить данные. Здесь мы просто говорим, какие значения может принимать решение, и оцениваем вероятность для каждого в соответствии с относительными пропорциями каждого варианта.

Расчет прироста информации

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

На следующей диаграмме показано, как энтропия Y (где Y имеет два состояния) изменяется с вероятностью каждого состояния. Поскольку вероятность одного состояния равна 0, энтропия также равна 0, поскольку в этом случае Y наиболее организован, в то время как когда Y равномерно разделен между двумя состояниями, энтропия максимальна.

Расширяя это, чтобы добавить эффект знания независимой переменной X на энтропию:

Прирост информации теперь выражается как разница между энтропией, когда мы знаем X, и когда нет.

Дай мне код!

Некоторые функции для вычисления энтропии и создания графики сюда не включены.

def decide(Y, X_dict, previous_node):
    #Calc info gain for each X
    max_IG = 0
    var_to_split = None
#Calculate information gain to find out which variable to split on
    for x in X_dict.keys():
        IG = InfoGain(Y, X_dict[x])
        if IG > max_IG:
            max_IG = IG
            var_to_split = x
#See if all variables have been used and none are left.
    if var_to_split == None:
        Y_options = list(set(Y))
        tot = float(len(Y))
        count = [0 for _ in range(len(Y_options))]
for op in range(len(Y_options)):
            for i in range(len(Y)):
                if Y[i] == op:
                    count[op] += 1
        #Format Node label
        Prob = ""
        for op in range(len(Y_options) - 1):
            Prob += "P("
            Prob += str(Y_options[op]) + ")-> "
            P = float(count[op]) / tot
            Prob += "{0:.2f}".format(P)
        #Make a new node
        nodename = node(Prob, color = "orange")
        edge(previous_node, nodename)
    else:
        print("Splitting on {0}".format(var_to_split))
        X_options = list(set(X_dict[var_to_split]))
        #Make decision variable node
        Var_nodename = node(var_to_split, color = "red")
        edge(previous_node, Var_nodename)
        #Init new data for each new branch of the tree
        for X_option in X_options:
            X_nodename = node(str(X_option))
            edge(Var_nodename, X_nodename)
            New_X_dict = {}
            #get remaining variables
            for key in X_dict.keys():
                if key != var_to_split:
                    New_X_dict[key] = []
            New_Y = []
            #Populate
            for i in range(len(Y)):
                if X_dict[var_to_split][i] == X_option:
                    New_Y.append(Y[i])
                    for key in New_X_dict.keys():
                        New_X_dict[key].append(X_dict[key][i])
#Check if this is a terminal node:
            if len(set(New_Y)) == 1:
                nodename = node(str(New_Y[0]), color = "green")
                edge(X_nodename, nodename)
            else:
                #No terminal node, so try again
                decide(New_Y, New_X_dict, X_nodename)
Y, X_dict =  import_golf('golf.csv') #import data
root_node = node("root", color = "blue") #Create the first node
decide(Y, X_dict, root_node) #start the tree

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