Prepara los metadatos para Explicaciones de IA

Las atribuciones de las funciones de Explicaciones de IA demuestran cómo influyen los atributos de entrada en la salida de un modelo. Cuando las solicitas con AI Platform Prediction, debes enviar un archivo de metadatos de explicaciones para identificar las entradas y las salidas del modelo de TensorFlow. Esto te permite seleccionar funciones específicas para la solicitud de explicaciones, sin necesidad de modificar el modelo.

En esta guía, se describen varias formas de identificar los nombres de los tensores de entrada y salida para ayudarte a preparar el archivo de metadatos de explicaciones.

Antes de comenzar

Los notebooks de ejemplo demuestran cómo realizar todos estos pasos.

Entradas y salidas en los metadatos de explicaciones

Para preparar los metadatos de explicaciones, debes especificar las entradas y las salidas del modelo en un archivo llamado explanation_metadata.json:

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

Dentro de los objetos de inputs y outputs del archivo, debes proporcionar los nombres de los tensores de entrada y salida para la solicitud de explicaciones.

  • Las claves para cada entrada y salida (“input feature key” y “output value key” en el ejemplo anterior) te permiten asignar nombres significativos a cada tensor. En el siguiente ejemplo, la clave del atributo de entrada es degrees_celsius y la clave del valor de salida es probabilities.
  • Para los valores de cada input y output de los metadatos, debes proporcionar el nombre real del tensor como output_tensor_name o input_tensor_name. En el ejemplo a continuación, el input_tensor_name es x:0 y el output_tensor_name es dense/Softmax:0.
{
    "inputs": {
      "degrees_celsius": {
        "input_tensor_name": "x:0",
      }
    },
    "outputs": {
      "probabilities": {
        "output_tensor_name": "dense/Softmax:0"
      }
    },
  "framework": "tensorflow"
}

Los nombres reales de los tensores tienen el formato name:index.

Encuentra tensores de entrada y salida

Después de entrenar un modelo de TensorFlow, expórtalo como un modelo guardado. El modelo guardado de TensorFlow contiene el modelo entrenado de TensorFlow, junto con firmas serializadas, variables y otros elementos necesarios para ejecutar el grafo. Cada SignatureDef identifica una función en el grafo que acepta entradas de tensor y produce salidas de tensor. De manera similar, el archivo de metadatos de explicaciones define las entradas y las salidas del grafo para la solicitud de atribución de las funciones a Explicaciones de IA.

A menudo, los tensores de entrada y salida que especificas en el archivo de metadatos de explicaciones se asignan con precisión a las firmas que defines cuando guardas el modelo. Si esto sucede, encontrar los nombres de tensores de entrada y salida es bastante sencillo. Sin embargo, en algunos casos, las entradas o las salidas que deseas explicar pueden ser diferentes de las que defines cuando guardas el modelo.

Las entradas y las salidas para las explicaciones son las mismas que configuraste en la entrega SignatureDef si sucede lo siguiente:

  • Las entradas no están en forma serializada.
  • Cada entrada a SignatureDef contiene directamente el valor de la función (pueden ser strings o valores numéricos).
  • Las salidas son valores numéricos, que se toman como datos numéricos. Esto excluye los ID de clase, que se consideran datos categóricos.

En estos casos, puedes obtener los nombres de los tensores de entrada y salida mientras compilas el modelo. Como alternativa, puedes inspeccionar el SignatureDef del modelo guardado con la CLI del modelo guardado para encontrar los nombres de los tensores de entrada y salida.

Para cualquier caso que no se ajuste a los criterios anteriores, hay otros enfoques que puedes adoptar para encontrar los tensores de entrada y salida correctos.

Obtén nombres de tensores durante el entrenamiento

Es más fácil acceder a los nombres de los tensores de entrada y salida durante el entrenamiento. Puedes guardar estos valores en el archivo de metadatos de explicaciones, mientras el programa o el entorno aún tiene acceso a las variables que configuraste cuando compilaste el modelo. En este ejemplo, el campo name de la capa Keras produce el nombre del tensor subyacente que necesitas para los metadatos de explicaciones:

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

Para obtener un ejemplo funcional completo, consulta los notebooks de ejemplo.

Obtén nombres de tensores a partir de definiciones de firmas

Dado que los metadatos de SignatureDef y la explicación identifican entradas y salidas de tensores, puedes usar SignatureDef para preparar el archivo de metadatos de explicaciones, siempre que cumpla con los criterios mencionados con anterioridad.

Considera el ejemplo siguiente de SignatureDef:

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

El grafo tiene un tensor de entrada llamado x:0 y uno de salida llamado dense/Softmax:0. Ambos tensores también tienen nombres significativos: my_numpy_input y probabilities, respectivamente. Para solicitar explicaciones de probabilities con respecto a my_numpy_input, puedes crear un archivo de metadatos de explicaciones de la siguiente manera:

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

Para inspeccionar la SignatureDef del modelo guardado, puedes usar la CLI del modelo guardado. Obtén más información sobre cómo usar la CLI de los modelos guardados.

Maneja las discrepancias de entrada y salida

Hay algunos casos comunes en los que los tensores de entrada y salida en los metadatos de explicaciones no deben ser los mismos que en la entrega SignatureDef:

  • Tienes entradas serializadas.
  • El grafo incluye operaciones de procesamiento previo.
  • Las salidas de entrega no son probabilidades, logits ni otros tipos de tensores de punto flotante.

En estos casos, debes usar enfoques diferentes para encontrar los tensores de entrada y salida adecuados. El objetivo general es encontrar los tensores correspondientes a los valores de las funciones que deseas explicar para las entradas y tensores correspondientes a logits (activación previa), probabilidades (activación posterior) o cualquier otra representación de las salidas.

Discrepancias de entrada

Las entradas en los metadatos de explicaciones difieren de las de la entrega SignatureDef si usas una entrada serializada para ingresar en el modelo o si el grafo incluye operaciones de procesamiento previo.

Entradas serializadas

Los modelos guardados de TensorFlow pueden aceptar una variedad de entradas complejas, como las siguientes:

  • Mensajes tf.Example serializados
  • Strings de JSON
  • Strings en Base64 codificadas (para representar datos de imágenes)

Si el modelo acepta entradas serializadas como estas, usar estos tensores directamente como entrada para las explicaciones no será efectivo o podría producir resultados sin sentido. En cambio, recomendamos ubicar los tensores de entrada subsiguientes que se ingresan en columnas de atributos dentro del modelo.

Cuando exportas el modelo, puedes agregar una operación de análisis al grafo de TensorFlow mediante una llamada a la función de análisis en tu función de entrada de entrega. Puedes encontrar las funciones de análisis enumeradas en el módulo tf.io. Estas funciones de análisis suelen mostrar tensores como respuesta y estos son mejores selecciones para los metadatos de explicaciones.

Por ejemplo, puedes usar tf.parse_example() cuando exportas el modelo. Este método toma un mensaje tf.Example serializado y muestra como resultado un diccionario de los tensores para las columnas de atributos. Puedes usar el resultado para completar los metadatos de explicaciones. Si alguno de estos resultados es tf.SparseTensor, que es una tupla con nombre que consta de 3 tensores, deberías obtener los nombres de los índices, los valores y los tensores dense_shape y llenar los campos correspondientes en los metadatos.

En el siguiente ejemplo, se muestra cómo obtener el nombre del tensor de entrada después de una operación de decodificación:

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)

Entradas con procesamiento previo

Si el grafo del modelo contiene algunas operaciones de procesamiento previo, es recomendable obtener explicaciones sobre los tensores después del paso de procesamiento previo. En este caso, puedes obtener los nombres de esos tensores mediante la propiedad name de tf.Tensor y colocarlos en los metadatos de explicaciones:

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)

El nombre del tensor decodificado se convierte en input_pixels:0.

Discrepancias de salida

En la mayoría de los casos, las salidas en la entrega SignatureDef son probabilidades o logits.

Si el modelo atribuye probabilidades, pero deseas explicar los valores de logit, debes encontrar los nombres de los tensores de salida apropiados que correspondan con los logits.

Si la entrega SignatureDef tiene salidas que no son probabilidades ni logits, debes consultar la operación de probabilidades en el grafo de entrenamiento. Este caso es poco probable para los modelos de Keras. Pero, si sucede, puedes usar TensorBoard (o cualquier otra herramienta de visualización de grafos) para encontrar los nombres de los tensores de salida correctos.

Consideraciones adicionales para los gradientes integrados

Explicaciones de IA proporciona dos métodos de atribución de funciones: Shapley de muestra y los gradientes integrados. Para usar el método de gradientes integrados, debes asegurarte de que las entradas sean diferenciables con respecto a la salida, por lo que debes tener esto en cuenta cuando prepares los metadatos de explicaciones. No es necesario asegurar que las entradas sean diferenciables si usas el método de atribución de funciones Shapley de muestra. Obtén más información sobre los métodos de atribución de funciones compatibles con Explicaciones de IA.

Los metadatos de explicaciones separan de forma lógica los atributos de un modelo de sus entradas. Cuando se usan gradientes integrados a un tensor de entrada que no es diferenciable con respecto al tensor de salida, también debes proporcionar la versión codificada (y diferenciable) de esa función.

Usa el siguiente enfoque si tienes tensores de entrada no diferenciables o si tienes operaciones no diferenciables en el grafo:

  • Codifica las entradas no diferenciables como entradas diferenciables.
  • Configura input_tensor_name con el nombre del tensor de entrada no diferenciable original y configura encoded_tensor_name con el nombre de la versión codificada diferenciable.

Archivo de metadatos de explicaciones con codificación

Por ejemplo, considera un modelo que tiene un atributo categórico con un tensor de entrada llamado zip_codes:0. Debido a que los datos de entrada incluyen códigos postales como strings, el tensor de entrada zip_codes:0 no es diferenciable. Si el modelo también procesa estos datos de forma previa para obtener una representación de codificación one-hot de los códigos postales, entonces el tensor de entrada es diferenciable después del procesamiento previo. Para distinguirlo del tensor de entrada original, puedes ponerle el nombre zip_codes_embedding:0.

Para usar los datos de ambos tensores de entrada en la solicitud de explicaciones, configura las inputs de los metadatos de la siguiente manera:

  • Configura la clave del atributo de entrada con un nombre significativo, como zip_codes.
  • Configura input_tensor_name con el nombre del tensor original: zip_codes:0.
  • Configura encoded_tensor_name con el nombre del tensor después de la codificación one-hot: zip_codes_embedding:0.
  • Configura encoding como 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"
}

Como alternativa, puedes configurar input_tensor_name como el nombre del tensor de entrada diferenciable codificado y omitir el tensor no diferenciable original. La ventaja de proporcionar ambos tensores es que se pueden realizar las atribuciones en valores de código postal individuales en lugar de hacerlo en la representación de codificación one-hot. En este ejemplo, excluirías el tensor original (zip_codes:0) y establecerías input_tensor_name como zip_codes_embedding:0. Este enfoque no se recomienda, ya que las atribuciones de las funciones resultantes serían difíciles de deducir.

Codificación

Para habilitar la codificación en la solicitud de explicaciones, especifica la configuración de codificación como se muestra en el ejemplo anterior.

El atributo de codificación ayuda a revertir el proceso de datos codificados a datos de entrada para atribuciones, por lo que ya no hay necesidad de procesar de manera posterior las atribuciones que se muestran de forma manual. Por el momento, Explicaciones de IA es compatible con combined_embedding, en la que un atributo de longitud variable se combina en una incorporación. Un ejemplo de operación que coincide con esta combined_embedding es tf.nn.embedding_lookup_sparse.

Con combined_embedding sucede lo siguiente:

El tensor de entrada está codificado en un arreglo 1D. Por ejemplo:

  • Entrada: ["This", "is", "a", "test"]
  • Codificado: [0.1, 0.2, 0.3, 0.4]

Próximos pasos