Comprendre les entrées et les sorties pour obtenir des explications

Avant de demander des explications, vous devez envoyer un fichier de métadonnées d'explication pour configurer votre requête d'explications. Ce fichier de métadonnées doit inclure les entrées et les sorties de votre modèle. Il comprend également des paramètres facultatifs, tels que les références en entrée et les paramètres de visualisation des données d'image.

La spécification des entrées et des sorties de votre modèle vous permet de sélectionner des caractéristiques particulières pour votre requête d'explications, sans avoir à modifier votre modèle. Vous pouvez utiliser le SDK Explainable AI pour effectuer cette opération automatiquement lorsque vous créez un modèle. Si vous n'utilisez pas le SDK Explainable AI, vous devez identifier manuellement vos entrées et sorties.

Ce guide explique comment identifier manuellement les Tensors d'entrée et de sortie afin de vous aider à préparer votre fichier de métadonnées d'explication.

Entrées et sorties dans les métadonnées d'explications

Pour préparer vos métadonnées d'explications, vous devez spécifier les entrées et les sorties de votre modèle dans un fichier nommé explanation_metadata.json :

{
  "inputs": {
    string <input feature key>: {
      "input_tensor_name": string,
  },
  "outputs": {
    string <output value key>:  {
      "output_tensor_name": string
    },
  },
  "framework": "tensorflow"
}

Dans les objets inputs et outputs du fichier, vous devez spécifier les noms des Tensors d'entrée et de sortie pour votre requête d'explications.

  • Les clés de chaque entrée et sortie ("input feature key" et "output value key" dans l'exemple précédent) vous permettent d'attribuer des noms explicites à chaque Tensor. Dans l'exemple ci-dessous, la clé de caractéristique d'entrée est degrees_celsius et la clé de valeur de sortie est probabilities.
  • Pour les valeurs de chaque métadonnée input et output, vous devez spécifier le nom réel du Tensor en tant que input_tensor_name ou output_tensor_name. Dans l'exemple ci-dessous, la valeur de input_tensor_name est x:0 et celle de output_tensor_name est dense/Softmax:0.
{
    "inputs": {
      "degrees_celsius": {
        "input_tensor_name": "x:0",
      }
    },
    "outputs": {
      "probabilities": {
        "output_tensor_name": "dense/Softmax:0"
      }
    },
  "framework": "tensorflow"
}

Les noms réels des Tensors sont au format name:index.

Rechercher des Tensors d'entrée et de sortie

Après avoir entraîné un modèle TensorFlow, exportez-le en tant que modèle SavedModel. Le modèle TensorFlow SavedModel contient votre modèle TensorFlow entraîné, ainsi que des signatures sérialisées, des variables et d'autres éléments nécessaires à l'exécution du graphe. Chaque valeur SignatureDef identifie une fonction dans votre graphe qui accepte les entrées de Tensor et produit des sorties de Tensor. De la même manière, votre fichier de métadonnées d'explications définit les entrées et les sorties du graphe pour votre requête d'attribution de caractéristiques envoyée à AI Explanations.

Il arrive souvent que les Tensors d'entrée et de sortie que vous spécifiez dans votre fichier de métadonnées d'explications correspondent exactement aux signatures que vous définissez lorsque vous enregistrez votre modèle. Si c'est le cas, la recherche des noms de vos Tensors d'entrée et de sortie est assez simple. Cependant, dans certains cas, les entrées ou les sorties que vous souhaitez expliquer peuvent être différentes de celles que vous définissez lorsque vous enregistrez le modèle.

Vos entrées et vos sorties d'explications sont identiques à celles que vous avez définies dans votre inférence SignatureDef si :

  • vos entrées ne sont pas sérialisées ;
  • chaque entrée de SignatureDef contient directement la valeur de la caractéristique. Il peut s'agir de valeurs numériques ou de chaînes ;
  • les sorties sont des valeurs numériques, traitées comme des données numériques. Cela exclut les identifiants de classe, qui sont considérés comme des données catégorielles.

Dans ce cas, vous pouvez obtenir les noms des Tensors d'entrée et de sortie au moment de la création du modèle. Vous pouvez également les obtenir en inspectant le paramètre SignatureDef de votre modèle SavedModel à l'aide de la CLI SavedModel.

Dans les cas qui ne correspondent pas aux critères précédents, il existe d'autres approches pour trouver les Tensors d'entrée et de sortie corrects.

Obtenir les noms de Tensor pendant l'entraînement

Il est plus facile d'accéder aux noms de Tensor d'entrée et de sortie lors de l'entraînement. Vous pouvez enregistrer ces valeurs dans votre fichier de métadonnées d'explications pendant que votre programme ou votre environnement a encore accès aux variables que vous avez définies lors de la création du modèle. Dans cet exemple, le champ name de la couche Keras produit le nom du Tensor sous-jacent dont vous avez besoin pour vos métadonnées d'explications :

bow_inputs = tf.keras.layers.Input(shape=(2000,))
merged_layer = tf.keras.layers.Dense(256, activation="relu")(bow_inputs)
predictions = tf.keras.layers.Dense(10, activation="sigmoid")(merged_layer)
model = keras.Model(inputs=bow_inputs, outputs=predictions)
print('input_tensor_name:', bow_inputs.name)
print('output_tensor_name:', predictions.name)
input_tensor_name: input_1:0
output_tensor_name: dense_1/Sigmoid:0

Pour accéder à un exemple fonctionnel complet, reportez-vous aux exemples de notebooks.

Obtenir les noms de Tensor à partir des définitions de signature

Comme les valeurs SignatureDef et les métadonnées d'explications identifient les entrées et les sorties de Tensor, vous pouvez utiliser le paramètre SignatureDef pour préparer votre fichier de métadonnées d'explications, à condition de respecter les critères mentionnés précédemment.

Prenons l'exemple SignatureDef suivant :

The given SavedModel SignatureDef contains the following input(s):
  inputs['my_numpy_input'] tensor_info:
      dtype: DT_FLOAT
      shape: (-1, 1)
      name: x:0
The given SavedModel SignatureDef contains the following output(s):
  outputs['probabilities'] tensor_info:
      dtype: DT_FLOAT
      shape: (-1, 1)
      name: dense/Softmax:0
Method name is: tensorflow/serving/predict

Le graphe présente un Tensor d'entrée nommé x:0 et un Tensor de sortie nommé dense/Softmax:0. Les deux Tensors possèdent également un nom explicite, respectivement my_numpy_input et probabilities. Pour demander des explications sur les probabilities par rapport à my_numpy_input, vous pouvez créer un fichier de métadonnées d'explications comme suit :

{
    "inputs": {
      "my_numpy_input": {
        "input_tensor_name": "x:0",
      }
    },
    "outputs": {
      "probabilities": {
        "output_tensor_name": "dense/Softmax:0"
      }
    },
  "framework": "tensorflow"
}

Pour inspecter le paramètre SignatureDef de votre modèle SavedModel, vous pouvez utiliser la CLI SavedModel. Découvrez en détail comment utiliser la CLI SavedModel.

Gérer les écarts d'entrée et de sortie

Il existe des cas où les Tensors d'entrée et de sortie de vos métadonnées d'explications ne doivent pas être identiques à ceux de votre inférence SignatureDef :

  • vous avez des entrées sérialisées ;
  • votre graphe inclut des opérations de prétraitement ;
  • vos résultats d'inférence ne sont pas des probabilités, des fonctions logit ou d'autres types de Tensors à virgule flottante.

Dans ces cas, vous devez utiliser différentes approches pour trouver les Tensors d'entrée et de sortie corrects. L'objectif général est de trouver les Tensors correspondant aux valeurs de caractéristique que vous souhaitez expliquer pour les entrées, ainsi que les Tensors correspondant aux fonctions logit (préactivation), aux probabilités (postactivation) ou à toute autre représentation des résultats.

Écarts d'entrée

Les entrées de vos métadonnées d'explications diffèrent de celles de votre inférence SignatureDef si vous utilisez une entrée sérialisée pour alimenter le modèle, ou si votre graphe inclut des opérations de prétraitement.

Entrées sérialisées

Les modèles TensorFlow SavedModel acceptent diverses entrées complexes, y compris les suivantes :

  • Messages tf.Example sérialisés
  • Chaînes JSON
  • Chaînes encodées en base64 (pour représenter les données d'image)

Si votre modèle accepte des entrées sérialisées comme celles-ci, l'utilisation directe de ces Tensors pour vos explications ne fonctionnera pas ou produira des résultats absurdes. Vous devez plutôt rechercher les Tensors d'entrée suivants qui alimentent les colonnes de caractéristiques de votre modèle.

Lorsque vous exportez votre modèle, vous pouvez ajouter une opération d'analyse à votre graphe TensorFlow en appelant une fonction d'analyse dans la fonction d'entrée d'inférence. Les fonctions d'analyse sont répertoriées dans le module tf.io. Ces fonctions d'analyse renvoient généralement des Tensors en tant que réponse. Ces Tensors constituent les meilleurs choix pour vos métadonnées d'explications.

Par exemple, vous pouvez utiliser la fonction tf.parse_example() lors de l'exportation de votre modèle. La fonction utilise un message tf.Example sérialisé et génère un dictionnaire de Tensors qui alimentent les colonnes de caractéristiques. Vous pouvez utiliser la sortie pour renseigner vos métadonnées d'explications. Si certaines de ces sorties sont tf.SparseTensor, qui est un tuple nommé composé de trois Tensors, vous devez obtenir les noms des indices, des valeurs et des Tensors dense_shape, ainsi que renseigner les champs correspondants dans les métadonnées.

L'exemple suivant montre comment obtenir le nom du Tensor d'entrée après une opération de décodage :

float_pixels = tf.map_fn(
    lambda img_string: tf.io.decode_image(
        img_string,
        channels=color_depth,
        dtype=tf.float32
    ),
    features,
    dtype=tf.float32,
    name='input_convert'
  )

print(float_pixels.name)

Prétraiter les entrées

Si le graphe de votre modèle contient des opérations de prétraitement, vous pouvez obtenir des explications sur les Tensors après l'étape de prétraitement. Dans ce cas, les noms de ces Tensors sont obtenus en utilisant la propriété name de tf.Tensor et en les insérant dans les métadonnées d'explications :

item_one_hot = tf.one_hot(item_indices, depth,
    on_value=1.0, off_value=0.0,
    axis=-1, name="one_hot_items:0")
print(item_one_hot.name)

Le nom du Tensor décodé devient input_pixels:0.

Écarts de sortie

Dans la plupart des cas, les sorties de votre inférence SignatureDef sont des probabilités ou des fonctions logit.

Si votre modèle attribue des probabilités, mais que vous souhaitez plutôt expliquer les valeurs logit, vous devez trouver les noms de Tensor de sortie appropriés qui correspondent aux valeurs logit.

Si votre inférence SignatureDef comporte des résultats qui ne sont pas des probabilités ni des valeurs logit, vous devez vous référer à l'opération de probabilités dans le graphe d'entraînement. Ce scénario est peu probable pour les modèles Keras. Si tel est le cas, vous pouvez utiliser TensorBoard (ou d'autres outils de visualisation graphique) pour localiser les noms de Tensor de sortie corrects.

Autres considérations sur les gradients intégrés

AI Explanations propose deux méthodes d'attribution de caractéristiques : l'échantillonnage des valeurs de Shapley et les gradients intégrés. Avec la méthode des gradients intégrés, vous devez vous assurer que vos entrées peuvent être différenciées par rapport à la sortie. Vous devez donc garder ceci à l'esprit lorsque vous préparez vos métadonnées d'explications. La vérification de la différenciabilité des entrées n'est pas nécessaire si vous utilisez la méthode d'attribution des caractéristiques par échantillonnage des valeurs de Shapley. Documentez-vous sur les méthodes d'attribution de caractéristiques compatibles avec AI Explanations.

Les métadonnées d'explications séparent logiquement les caractéristiques d'un modèle de ses entrées. Lorsque vous utilisez des gradients intégrés avec un Tensor d'entrée non différenciable par rapport au Tensor de sortie, vous devez également fournir la version encodée (et différenciable) de la caractéristique concernée.

Utilisez l'approche suivante si vous avez des Tensors d'entrée non différenciables, ou si des opérations non différenciables sont présentes dans votre graphe :

  • Encodez les entrées non différenciables comme entrées différenciables.
  • Définissez la valeur input_tensor_name sur le nom du Tensor non différenciable d'origine, et définissez la valeur encoded_tensor_name sur le nom de sa version encodable et différenciable.

Fichier de métadonnées d'explications avec encodage

Prenons l'exemple d'un modèle qui possède une caractéristique de catégorie avec un Tensor d'entrée nommé zip_codes:0. Comme les données d'entrée incluent des codes postaux en tant que chaînes, le Tensor d'entrée zip_codes:0 n'est pas différenciable. Si le modèle prétraite également ces données pour obtenir une représentation des codes postaux par encodage one-hot, le Tensor d'entrée après les opérations de prétraitement est différenciable. Pour le distinguer du Tensor d'entrée d'origine, vous pouvez le nommer zip_codes_embedding:0.

Pour utiliser les données des deux Tensors d'entrée dans votre requête d'explications, définissez les métadonnées inputs comme suit :

  • Attribuez un nom explicite à la clé de la caractéristique d'entrée, par exemple zip_codes.
  • Définissez input_tensor_name sur le nom du Tensor d'origine, zip_codes:0.
  • Définissez encoded_tensor_name sur le nom du Tensor après encodage one-hot, zip_codes_embedding:0.
  • Définissez encoding sur combined_embedding.
{
    "inputs": {
      "zip_codes": {
        "input_tensor_name": "zip_codes:0",
        "encoded_tensor_name": "zip_codes_embedding:0",
        "encoding": "combined_embedding"
      }
    },
    "outputs": {
      "probabilities": {
        "output_tensor_name": "dense/Softmax:0"
      }
    },
  "framework": "tensorflow"
}

Vous pouvez également définir input_tensor_name sur le nom du Tensor d'entrée encodé et différenciable, et omettre le Tensor non différenciable d'origine. Spécifier deux Tensors permet d'effectuer les attributions sur chaque valeur de code postal plutôt que sur leur représentation après encodage one-hot. Dans cet exemple, vous devez exclure le Tensor d'origine (zip_codes:0) et définir input_tensor_name sur zip_codes_embedding:0. Cette approche n'est pas recommandée, car les attributions de caractéristiques qui en résultent sont difficiles à interpréter.

Encodage

Pour activer l'encodage dans votre requête d'explications, spécifiez les paramètres d'encodage comme indiqué dans l'exemple précédent.

La fonctionnalité d'encodage permet d'inverser le processus des données encodées vers les données d'entrée pour les attributions, ce qui évite les opérations manuelles de post-traitement des attributions renvoyées. Actuellement, AI Explanations accepte les opérations combined_embedding, où une caractéristique de longueur variable est combinée dans un élément intégré. L'opération tf.nn.embedding_lookup_sparse est un exemple d'opération combined_embedding.

Dans le cas d'une opération combined_embedding :

Le Tensor d'entrée est encodé dans un tableau 1D. Exemple :

  • Entrée : ["This", "is", "a", "test"]
  • Encodé : [0.1, 0.2, 0.3, 0.4]

Étape suivante