Zum Inhalt springen

Erklärbare AI: Integrated Gradients

Integrated Gradients ermöglicht es die Inputs eines Deep Learning Modells auf ihre Wichtigkeit für die Ausgabe hin zu untersuchen. Ein großer Kritikpunkt an tiefen Neuronalen Netzwerken ist die fehlende Interpretierbarkeit, wie wir sie beispielsweise von einer Linearen Regression kennen. Dort können wir anhand der Gewichtungen relativ genau sagen, wie sehr eine unabhängige Variable den Wert der Vorhersage beeinflusst.

Die Hidden Layer des Neuronalen Netzwerkes lassen diese Beziehung zwischen Eingabe und Ausgabe jedoch stark verschwimmen, da es keine direkte Verknüpfung zwischen Input und Output Layer gibt. In einem Modell mit hundert Neuronen ist es bereits nicht mehr praktikabel, den Weg eines Datensatzes durch das Netzwerk zu verfolgen, um so vielleicht die Funktionsweise des Modells interpretieren zu können.

Wie funktioniert Integrated Gradient?

Integrated Gradients wurden erstmal im Jahr 2017 in dem Paper Axiomatic Attribution for Deep Networks eingeführt und getestet. Darin wird versucht jedem Inputwert einen Attributionswert zuzuordnen. Dieser sagt aus, wie stark die Eingabe zur Vorhersage beigetragen hat. Dieser Ansatz kann für Klassifizierungsmodelle, beispielsweise im Bereich Natural Language Processing (NLP) oder beim Labeln von Bildern, genutzt werden. Wir werden uns in diesem Artikel auf Sentiment Analysen im Bereich des NLP beschränken, da unser folgendes Codebeispiel darauf basiert. Für die Klassifizierung von Bildern funktioniert der Algorithmus in leicht abgewandelter Form.

In einem Beispiel wollen wir anhand eines Satzes oder einer Sequenz entscheiden, ob es sich um eine positive oder negative Bewertung handelt. Die Integrated Gradients Methode startet mit der sogenannten Baseline, also einem Ausgangspunkt, der keine Information enthält für die Modellvorhersage. In unserem Fall ist das der Satz ausschließlich mit dem Anfangs- und Endtoken. Diese markieren nur den Anfang und das Ende eines Satzes oder Abschnittes und geben keine Aussage darüber, ob die Bewertung positiv oder negativ ist.

Wir definieren eine gewisse Anzahl an Schritten, die bestimmt, in wie vielen Stufen wir von der Baseline zum eigentlichen Input des Modells gelangen. Laut dem ursprünglichen Paper sollte die Anzahl an Schritten zwischen 20 und 300 liegen. Bildlich und stark vereinfacht kann man sich das in etwa so vorstellen, als würden wir den Satz Stück für Stück zusammenbauen und in jedem Schritt das nächste Token der Baseline hinzufügen.

In jedem dieser Schritte würden wir uns dann vom Modell eine Vorhersage berechnen lassen. Dadurch bekommen wir für jedes Input Feature einen Attributionswert, der aussagt wie stark das Feature das Gesamtergebnis beeinflusst hat. Wenn wir beispielsweise der Baseline das Token für das Wort „gut“ hinzufügen, werden wir wahrscheinlich einen Anstieg der Vorhersage beobachten, da der Outputwert 1 des Models für eine positive Bewertung steht. Den Attributionswert für das Token „gut“ können wir explizit berechnen, indem wir den Gradienten des Modells mit Bezug auf das Input Feature „gut“ berechnen.

Warum funktioniert die Integrated Gradients Methode?

Wenn wir versuchen solche Einflussfaktoren zu ermitteln, stehen wir vor dem Problem, dass wir im Nachhinein nicht beurteilen können, ob ein falscher Attributionswert auf einem Fehler des Modells oder der Attributionsmethode beruht. Deshalb werden in der Literatur zwei Grundprinzipien genannt, die eine Attributionsmethode erfüllen muss, um zuverlässig gute Ergebnisse zu liefern. Im Paper Axiomatic Attribution for Deep Networks können die Autoren zeigen, dass Integrated Gradients die beiden folgenden Prinzipien erfüllen und somit eine gute Attributionsmethode darstellen:

  1. Sensitivität: Wenn ein Input Feature die Klassifizierung in irgendeiner Weise verändert, sollte diese Eingabe einen Attributionswert ungleich 0 haben.
  2. Implentierungsinvarianz: Das Ergebnis der Attribution darf nicht vom Aufbau und der Struktur des Neuronalen Netzwerkes abhängen. Wenn also zwei unterschiedliche Neuronale Netze für gleiche Inputs die gleiche Vorhersage liefern, sollen deren Attributionswerte auch identisch sein.

Integrated Gradients am Beispiel einer Sentiment Analyse

Da es in diesem Beitrag vor allem um die Erklärung von Integrated Gradients gehen soll, nutzen wir ein vortrainiertes BERT Modell für unsere Sentiment Analyse und trainieren dieses nicht noch zusätzlich. Das sparen wir uns für einen eigenen Beitrag auf.

# Necessary Imports
import tensorflow as tf
import numpy as np
import pandas as pd
import re
from alibi.explainers import IntegratedGradients
import matplotlib as mpl

# Preprocess and clean texts
def preprocess_reviews(reviews):

    REPLACE_NO_SPACE = re.compile("[.;:,!\'?\"()\[\]]")
    REPLACE_WITH_SPACE = re.compile("(<br\s*/><br\s*/>)|(\-)|(\/)")

    reviews = [REPLACE_NO_SPACE.sub("", line.lower()) for line in reviews]
    reviews = [REPLACE_WITH_SPACE.sub(" ", line) for line in reviews]

    return reviews

# Tokenize text
def process_sentences(sentence,
 tokenizer,
 max_len):
    z = tokenizer(sentence,
                  add_special_tokens = False,
                  padding = 'max_length',
                  max_length = max_len,
                  truncation = True,
                  return_token_type_ids=True,
                  return_attention_mask = True,
                  return_tensors = 'np')
    return z

# Load pretrained BERT Model from Transformers Library
from transformers import TFAutoModelForSequenceClassification, AutoTokenizer
model_name = "distilbert-base-uncased-finetuned-sst-2-english"
auto_model_bert = TFAutoModelForSequenceClassification.from_pretrained(model_name)
tokenizer = AutoTokenizer.from_pretrained(model_name)

Für unser Beispiel laden wir das Distilbert Modell in englischer Sprache. Das Modell wurde auf dem Datensatz Stanford Sentiment Treebank (SST) für eine Sentiment Analyse trainiert. Wenn wir diese Art von Modellen nutzen, können wir keinen Klartext als Input nutzen, sondern müssen diesen in sogenannte Tokens aufsplitten und diese wiederum als Zahlen repräsentieren. Deshalb benötigen wir die Funktionen „process_reviews“ und „process_sentences“.

Damit wir das geladene Modell auch selbst nutzen können, definieren wir einen Wrapper mithilfe dessen wir Sentiment Vorhersagen machen können.

class AutoModelWrapper(tf.keras.Model):

    def __init__(self, model_bert, **kwargs):
        super().__init__()
        self.model_bert = model_bert

# Apply softmax function to logits
    def call(self, inputs, attention_mask=None):
        out = self.model_bert(inputs,
                              attention_mask=attention_mask)
        return tf.nn.softmax(out.logits)

    def get_config(self):
        return {}

    @classmethod
    def from_config(cls, config):
        return cls(**config)

auto_model = AutoModelWrapper(auto_model_bert)

# Define the maximum length of the sequence
max_len = 20

Nun können wir uns endlich den Integrated Gradients und deren Berechnung widmen. Dazu definieren wir den Beispielssatz „I love you, but I also kind of dislike you“, der vielleicht etwas komisch klingen mag, aber nachher gut zeigen wird, welche Worte eher auf ein positives Sentiment und welche auf ein negatives Sentiment hindeuten. Diesen Satz müssen wir natürlich auch erst entsprechend tokenizen, bevor wir eine Vorhersage mit dem Modell machen können.

z_test_sample = ['I love you, but I also kind of dislike you.']
z_test_sample = preprocess_reviews(z_test_sample)
z_test_sample = process_sentences(z_test_sample,
 tokenizer,
 max_len)

# We need only the input ids for the classification
x_test_sample = z_test_sample['input_ids']

# Preparation of Attention Masks
kwargs = {k: tf.constant(v) for k,v in z_test_sample.items() if k ==
'attention_mask'}

Für die Integrated Gradients benötigen wir nur die Embedding Layer, also den Transformer Block.

#  Extracting the first transformer block
bl = auto_model.layers[0].layers[0].transformer.layer[1]

Nun können wir den Algorithmus und dessen Hyperparameter definieren. Neben der Anzahl der Schritte, können wir auch die Methode definieren und eine Batch Size vergeben.

n_steps = 20
method = "gausslegendre"
internal_batch_size = 5
ig  = IntegratedGradients(auto_model,
                          layer=bl,
                          n_steps=n_steps,
                          method=method,
                          internal_batch_size=internal_batch_size)

Jetzt kommt der eigentlich spannende Teil dieses Beitrags. Wir lassen erst unser ursprüngliches Klassifizierungsmodell den vollständigen Satz klassifizieren. Auf dieses Ergebnis wenden wir dann die Integrated Gradients Methode an. Wir definieren keine explizite Baseline, sondern nutzen den Default Value.

predictions = auto_model(x_test_sample, **kwargs).numpy().argmax(axis=1)
explanation = ig.explain(x_test_sample,
                         forward_kwargs=kwargs,
                         baselines=None,
                         target=predictions)

Von diesem Modell können wir die Attributionswerte einfach extrahieren. Die Werte in jedem Schritt addieren wir zusammen, sodass wir anschließend für jede der 20 Stufen einen Wert übrig haben.

attrs = explanation.attributions[0]
attrs = attrs.sum(axis=2)
print('Attributions shape:', attrs.shape)

Out:
Attributions shape: (1, 20)

Wir definieren nun zwei Funktionen, um uns das Ergebnis der Integrated Gradient Methode auch graphisch aufzeigen zu können und für jedes Wort mit grün und rot farblich erkennen können, wie es zum Sentiment beigetragen hat.

from IPython.display import HTML
# Return HTML markup which highlights the text with a desired color.
def  hlstr(string, color='white'):
    return f"<mark style=background-color:{color}>{string} </mark>"

# Calculates color based on attribution values
def colorize(attrs, cmap='PiYG'):
    cmap_bound = np.abs(attrs).max()
    norm = mpl.colors.Normalize(vmin=-cmap_bound, vmax=cmap_bound)
    cmap = mpl.cm.get_cmap(cmap)

    colors = list(map(lambda x: mpl.colors.rgb2hex(cmap(norm(x))), attrs))
    return colors

Damit wir ein Ergebnis als Klartext erhalten müssen wir die Tokens wieder zurück in Wörter übersetzen. Die Funktion „colorize“ können wir zusätzlich nutzen, um den Attributionswerten die entsprechenden Farbtöne zuzuordnen.

words = tokenizer.decode(x_test_sample[0]).split()
colors = colorize(attrs[0])

Das Sentiment unseres Satzes klassifiziert das vortrainierte Modell als positiv.

print('Predicted label =  {}: {}'.format(pred))

Out:
Predicted label =  1 # Positive Review

Die grün unterlegten Wörter zeigen uns nun, welche Wörter das Modell zu einer positiven Bewertung geführt haben und die roten Wörter hingegen, welche für eine negative Bewertung gesprochen haben.

HTML("".join(list(map(hlstr, words, colors))))
Das Bild zeigt den Output eines Jupyter Notebooks für das Integrated Gradient Verfahren.
Ergebnis Integrated Gradient Verfahren

Wir sehen, dass das Wort „love“ mit Abstand den größten Einfluss auf das positive Sentiment des ganzen Satzes hatte. „Dislike“ hingegen hat für eine negative Bewertung des Satzes gesprochen, war aber nicht stark genug, um „love“ auszugleichen. Mit einem philosophischeren Satz kann man doch diesen technischen Beitrag nicht beenden.

Das solltest Du mitnehmen

  • Die Integrated Gradients Methode ist eine Möglichkeit, um ein Klassifizierungsmodell interpretierbar zu machen.
  • Es wird eine Baseline definiert, die keine Auswirkung auf das Klassifizierungsergebnis hat. Anschließend werden in einigen Schritten Interpolationen an das Modell gegeben und über den Gradient bestimmt, welche Einfluss die einzelnen Inputs auf das Ergebnis haben.

Andere Beiträge zum Thema Integrated Gradients

  • Das Paper „Axiomatic Attribution for Deep Networks“ findest Du hier.
  • Das Beispiel findest Du in leicht abgewandelter Form hier.
close
Das Logo zeigt einen weißen Hintergrund den Namen "Data Basecamp" mit blauer Schrift. Im rechten unteren Eck wird eine Bergsilhouette in Blau gezeigt.

Verpass keine neuen Beiträge!

Wir versenden keinen Spam! Lies die Details gerne in unserer Datenschutzrichtlinie nach.

Cookie Consent mit Real Cookie Banner