Usa TensorFlow con Explainable AI de Vertex

Cuando trabajas con modelos de TensorFlow de entrenamiento personalizados, hay información específica que necesitas para guardar tu modelo y configurar explicaciones.

Si quieres usar una Vertex Explainable AI con un modelo tabular de AutoML, no es necesario que realices ninguna configuración. Vertex AI configura automáticamente el modelo para Vertex Explainable AI. Omite este documento y lee Obtén explicaciones.

Esta guía `proporciona la información que necesitas cuando entrenas un modelo de TensorFlow para asegurarte de que puedas usarlo con Vertex Explainable AI. En específico, en la guía se abarcan los siguientes temas:

  • Busca los nombres de tensores de entrada y salida durante el entrenamiento que debes especificar cuando configuras un recurso Model para la Vertex Explainable AI. Esto incluye la creación y la búsqueda de los tensores apropiados para Vertex Explainable AI en casos especiales cuando los típicos no funcionan.

  • Exportar tu modelo de TensorFlow como un modelo guardado de TensorFlow que es compatible con Vertex Explainable AI.

  • Encontrar los nombres de tensores de entrada y salida de un modelo guardado de TensorFlow que ya se exportó Esto puede ser útil si no tienes acceso al código de entrenamiento para el modelo.

Encuentra nombres de tensores de entrada y salida durante el entrenamiento

Cuando usas un contenedor de TensorFlow compilado con anterioridad para entregar predicciones, debes conocer los nombres de los tensores de entrada y el de salida de tu modelo. Especificas estos nombres como parte de un mensaje ExplanationMetadata cuando configuras un Model para Vertex Explainable AI.

Si tu modelo de TensorFlow cumple con los siguientes criterios, puedes usar el “método básico” que se describe en la siguiente sección para determinar estos nombres de tensores durante el entrenamiento:

  • Las entradas no están en forma serializada
  • Cada entrada al SignatureDef del modelo contiene directamente el valor de la función (pueden ser valores numéricos o strings).
  • 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.

Si tu modelo no cumple con estos criterios, lee la sección Ajusta el código de entrenamiento y encuentra nombres de tensores en casos especiales.

El método básico

Durante el entrenamiento, imprime el atributo name de los tensores de entrada del modelo y los tensores de salida. En el siguiente ejemplo, el campo name de la capa Keras produce el nombre del tensor subyacente que necesitas para tu ExplanationMetadata:

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 = tf.keras.Model(inputs=bow_inputs, outputs=predictions)
print('input_tensor_name:', bow_inputs.name)
print('output_tensor_name:', predictions.name)

Cuando se ejecuta este código de Python, se muestra el siguiente resultado:

input_tensor_name: input_1:0
output_tensor_name: dense_1/Sigmoid:0

Luego, puedes usar input_1:0 como el nombre del tensor de entrada y dense_1/Sigmod:0 como el nombre del tensor de salida cuando configuras tu Model para obtener explicaciones.

Ajusta el código de entrenamiento y encuentra nombres de tensores en casos especiales

Existen algunos casos habituales en los que los tensores de entrada y salida para tu ExplanationMetadata no deben ser iguales a los de tu SignatureDef de entrega:

  • 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.

Casos especiales para tensores 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.

Casos especiales para tensores 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 especiales para los gradientes integrados

Si deseas usar el método de atribución de atributos de gradientes integrados de Vertex Explainable AI, debes asegurarte de que las entradas sean diferenciables con respecto a la salida.

Los metadatos de explicación 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:

  1. Codifica las entradas no diferenciables como entradas diferenciables.
  2. 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 ExplanationMetadata de la siguiente manera cuando configures Model para explicaciones:

  • Configura la clave de 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.
  • Establece encoding en 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"
      }
    }
}

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

A fin de habilitar la codificación para tu Model, 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. Consulta la lista de codificaciones compatibles con Vertex Explainable AI.

Para la codificación COMBINED_EMBEDDING, el tensor de entrada está codificado en un array 1D.

Por ejemplo:

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

Exporta SavedModels de TensorFlow para Vertex Explainable AI

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 en el modelo guardado identifica una función en el grafo que acepta entradas de tensor y produce salidas de tensor.

Para asegurarte de que tu modelo guardado sea compatible con Vertex Explainable AI, sigue las instrucciones de una de las siguientes secciones, según si usas TensorFlow 2 o TensorFlow 1.

TensorFlow 2

Si estás trabajando con TensorFlow 2.x, usa tf.saved_model.save para guardar tu modelo. Puedes especificar firmas de entrada cuando guardas el modelo. Si tienes una firma de entrada, Vertex Explainable AI usa la función de entrega predeterminada para las solicitudes de explicaciones. Si tienes más de una firma de entrada, debes especificar la firma de tu función predeterminada de entrega cuando guardas tu modelo:

tf.saved_model.save(m, model_dir, signatures={
    'serving_default': serving_fn,
    'xai_model': model_fn # Required for XAI
    })

En este caso, Vertex Explainable AI usa la firma de la función de modelo que guardaste con la clave xai_model para tu solicitud de explicaciones. Usa la string exacta xai_model para la clave.

Si usas una función de procesamiento previo, también debes especificar las firmas para tu función de procesamiento previo y tu función de modelo. Debes usar las strings exactas xai_preprocess y xai_model como claves:

tf.saved_model.save(m, model_dir, signatures={
    'serving_default': serving_fn,
    'xai_preprocess': preprocess_fn, # Required for XAI
    'xai_model': model_fn # Required for XAI
    })

En este caso, Vertex Explainable AI usa la función de procesamiento previo y la función de modelo para tus solicitudes de explicación. Asegúrate de que el resultado de tu función de procesamiento previo coincida con la entrada que espera la función del modelo.

Obtén más información sobre cómo especificar firmas de entrega en TensorFlow.

TensorFlow 1.15

Si estás trabajando con TensorFlow 1.15, no uses tf.saved_model.save. Vertex Explainable AI no es compatible con los modelos de TensorFlow 1 guardados con este método

Si compilas y entrenas el modelo en Keras, debes convertirlo en un Estimador de TensorFlow y, luego, exportarlo a un modelo guardado. En esta sección, nos enfocamos en cómo guardar un modelo.

Después de compilar, compilar, entrenar y evaluar el modelo de Keras, debes hacer lo siguiente:

  • Convertir el modelo de Keras en un Estimador de TensorFlow mediante tf.keras.estimator.model_to_estimator
  • Proporcionar una función de entrada de entrega mediante tf.estimator.export.build_raw_serving_input_receiver_fn
  • Exportar el modelo como modelo guardado mediante tf.estimator.export_saved_model
# Build, compile, train, and evaluate your Keras model
model = tf.keras.Sequential(...)
model.compile(...)
model.fit(...)
model.predict(...)

## Convert your Keras model to an Estimator
keras_estimator = tf.keras.estimator.model_to_estimator(keras_model=model, model_dir='export')

## Define a serving input function appropriate for your model
def serving_input_receiver_fn():
  ...
  return tf.estimator.export.ServingInputReceiver(...)

## Export the SavedModel to Cloud Storage, using your serving input function
export_path = keras_estimator.export_saved_model(
  'gs://' + 'YOUR_BUCKET_NAME',
  serving_input_receiver_fn
).decode('utf-8')

print("Model exported to: ", export_path)

Obtén nombres de tensores a partir de SignatureDef del modelo guardado

Puedes usar SignatureDef de un modelo guardado de TensorFlow para preparar los metadatos de explicaciones, siempre que cumplan con los criterios del “método básico” que se describió en una sección anterior. Esto podría ser útil si no tienes acceso al código de entrenamiento que produjo el modelo.

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.

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. Cuando configures Model para explicaciones, usa x:0 como el nombre del tensor de entrada y dense/Softmax:0 como el nombre del tensor de salida en el mensaje ExplanationMetadata.

¿Qué sigue?