Usar o TensorFlow para explicações

Quando você trabalha com modelos treinados do TensorFlow, há informações específicas que são necessárias para salvar seu modelo e configurar explicações.

Se você quiser usar o Vertex Explainable AI com um modelo tabular do AutoML, não será necessário realizar nenhuma configuração. O Vertex AI configura automaticamente o modelo para o Vertex Explainable AI. Pule este documento e leia Como receber explicações.

Neste guia, você verá as informações necessárias para treinar um modelo do TensorFlow e usá-lo com o Vertex Explainable AI. Especificamente, ele abrange os seguintes tópicos:

  • Encontrar os nomes dos tensores de entrada e saída durante o treinamento que você precisa especificar ao configurar um recurso Model para o Vertex Explainable AI. Isso inclui a criação e a localização dos tensores apropriados para o Vertex Explainable AI em casos especiais em que os típicos não funcionam.

  • Como exportar o modelo do TensorFlow como um SavedModel do TensorFlow compatível com o Vertex Explainable AI.

  • Encontrar os nomes do tensor de entrada e saída de um SavedModel do TensorFlow que já foi exportado. Isso poderá ser útil se você não tiver acesso ao código de treinamento do modelo.

Encontrar nomes de tensores de entrada e saída durante o treinamento

Ao usar um contêiner pré-criado do TensorFlow para exibir predições, é preciso saber os nomes dos tensores de entrada e o tensor de saída do modelo. Você especifica esses nomes como parte de uma mensagem ExplanationMetadata ao configurar um Model para Vertex Explainable AI

Se o modelo do TensorFlow atender aos seguintes critérios, será possível usar o "método básico" descrito na próxima seção para determinar esses nomes de tensores durante o treinamento:

  • suas entradas não estão em formato serializado;
  • Cada entrada para o SignatureDef do modelo contém o valor do recurso diretamente (pode ser valores numéricos ou strings).
  • as saídas são valores numéricos, tratados como dados numéricos. Isso exclui os IDs de classe, que são considerados dados categorizados.

Se o modelo não atender a esses critérios, leia a seção Como ajustar o código de treinamento e encontrando nomes de tensores em casos especiais.

O método básico

Durante o treinamento, imprima o atributo name dos tensores de entrada do seu modelo e dos tensores de saída. No exemplo a seguir, o campo name da camada Keras produz o nome do tensor subjacente de que você precisa para seu 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)

A execução deste código Python imprime a seguinte saída:

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

É possível usar input_1:0 como o nome do tensor de entrada e dense_1/Sigmod:0 como o nome do tensor de saída ao configurar seu Model para explicações.

Ajustar o código de treinamento e encontrar nomes de tensores em casos especiais

Há alguns casos comuns em que os tensores de entrada e saída do ExplanationMetadata não devem ser os mesmos de SignatureDef na exibição:

  • você inseriu entradas em série;
  • seu gráfico inclui operações de pré-processamento;
  • suas saídas de exibição não são probabilidades, logits ou outros tipos de tensores de ponto flutuante.

Nesses casos, use abordagens diferentes para encontrar os tensores de entrada e saída corretos. A meta geral é encontrar os tensores pertencentes aos valores de atributos que você quer explicar para entradas e tensores relativos a logits (pré-ativação), probabilidades (pós-ativação) ou qualquer outra representação para saídas.

Casos especiais de tensores de entrada

As entradas nos seus metadados de explicação diferem daquelas na sua exibição SignatureDef se você usar uma entrada serializada para alimentar o modelo ou se o gráfico incluir operações de pré-processamento.

Entradas serializadas

Os SavedModels do TensorFlow podem aceitar uma variedade de entradas complexas, incluindo:

  • Mensagens serializadas tf.Example
  • Strings JSON
  • Strings Base64 codificadas (para representar dados de imagem)

Se o modelo aceitar entradas serializadas como essas, usar esses tensores diretamente como entrada para suas explicações não funcionará ou poderá produzir resultados sem sentido. Em vez disso, localize os tensores de entrada subsequentes que estão alimentando as colunas de recurso no seu modelo.

Ao exportar o modelo, é possível adicionar uma operação de análise ao gráfico do TensorFlow chamando uma função de análise na função de entrada de exibição. Encontre funções de análise listadas no módulo tf.io (em inglês). Essas funções de análise geralmente retornam tensores como uma resposta, e eles são as melhores opções para os metadados de explicação.

Por exemplo, é possível usar tf.parse_example() (em inglês) ao exportar seu modelo. Ele recebe uma mensagem serializada tf.Example e gera um dicionário de alimentadores de tensores para apresentar colunas. Use a saída para preencher os metadados de explicação. Se algumas dessas saídas forem tf.SparseTensor (uma tupla nomeada que consiste em três tensores), você precisa dos nomes de índices, valores e tensores dense_shape. Também é preciso preencher os campos correspondentes nos metadados.

O exemplo a seguir mostra como conseguir o nome do tensor de entrada após uma operação de decodificação:

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 de pré-processamento

Se o gráfico de modelo contiver algumas operações de pré-processamento, convém conseguir explicações sobre os tensores após a etapa de pré-processamento. Nesse caso, é possível conseguir os nomes desses tensores usando a propriedade name de tf.Tensor e colocando-os nos metadados de explicação:

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)

O nome do tensor decodificado torna-se input_pixels:0.

Casos especiais de tensores de saída

Na maioria dos casos, os resultados em SignatureDef de exibição são probabilidades ou logits.

Se o modelo estiver atribuindo probabilidades, mas você quiser explicar os valores de logit, será preciso encontrar os nomes de tensores de saída apropriados que correspondem aos logits.

Se SignatureDef de exibição tiver saídas que não sejam probabilidades ou logits, consulte a operação de probabilidades no gráfico de treinamento. Este cenário é improvável para os modelos Keras. Se isso acontecer, use o TensorBoard (em inglês), ou outras ferramentas de visualização de gráfico, para ajudar a localizar os nomes de tensores de saída corretos.

Considerações especiais para gradientes integrados

Se você quiser usar o método de atribuição de recursos de gradientes integrados da Vertex Explainable AI, é preciso garantir que suas entradas sejam diferenciáveis em relação à saída.

Os metadados de explicação separam logicamente os recursos de um modelo de suas entradas. Ao usar gradientes integrados com um tensor de entrada que não é diferenciável em relação ao tensor de saída, você precisa fornecer a versão codificada (e diferenciável) desse recurso também.

Use a abordagem a seguir se você tiver tensores de entrada não diferenciáveis ou se tiver operações não diferenciáveis em seu gráfico:

  1. Codifique as entradas não diferenciáveis como entradas diferenciáveis.
  2. Defina input_tensor_name ao nome do tensor de entrada não-diferenciável original e defina encoded_tensor_name ao nome de versão codificada e diferenciável.

Explicação do arquivo de metadados com codificação

Por exemplo, considere um modelo que tenha um recurso categórico com um tensor de entrada denominado zip_codes:0. Como os dados de entrada incluem códigos postais como strings, o tensor de entrada zip_codes:0 não é diferenciável. Se o modelo também pré-processar esses dados para conseguir uma representação de codificação one-hot dos códigos postais, o tensor de entrada após o pré-processamento é diferenciável. Para diferenciá-lo do tensor de entrada original, seria possível nomeá-lo zip_codes_embedding:0.

Para usar os dados de ambos os tensores de entrada na sua solicitação de explicações, defina ExplanationMetadata da seguinte maneira quando configurar o Model para explicações:

  • Defina a chave de recurso de entrada para um nome significativo, como zip_codes.
  • Defina input_tensor_name como o nome do tensor original, zip_codes:0.
  • Defina encoded_tensor_name como o nome do tensor após a codificação, zip_codes_embedding:0.
  • Defina 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"
      }
    }
}

Como alternativa, defina input_tensor_name ao nome do tensor de entrada codificado e diferenciável e omita o tensor não diferenciável original. A vantagem de fornecer ambos os tensores é que as atribuições podem ser feitas para valores de CEP individuais, em vez da representação de codificação one-hot. Neste exemplo, exclua o tensor original (zip_codes:0) e defina input_tensor_name para zip_codes_embedding:0. Essa abordagem não é recomendada, porque as atribuições de recursos resultantes seriam difíceis de considerar.

Codificação

Para ativar a codificação de Model, especifique as configurações de codificação conforme mostrado no exemplo anterior.

O recurso de codificação ajuda a reverter o processo de dados codificados para dados de entrada para atribuições, o que elimina a necessidade de pós-processamento manual das atribuições retornadas. Consulte a lista de codificações compatíveis com a Vertex Explainable AI.

Para a codificação COMBINED_EMBEDDING, o tensor de entrada é codificado em uma matriz 1D.

Exemplo:

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

Exportar SavedModels do TensorFlow para Vertex Explainable AI

Depois de treinar um modelo do TensorFlow, exporte-o como um SavedModel. O SavedModel do TensorFlow contém o modelo do TensorFlow que você treinou, junto às assinaturas serializadas, variáveis e outros recursos necessários para executar o gráfico. Cada SignatureDef no SavedModel identifica uma função no gráfico que aceita entradas de tensor e produz saídas dele.

Para garantir que o SavedModel seja compatível com a Vertex Explainable AI, siga as instruções em uma das seções a seguir, dependendo se você estiver usando o TensorFlow 2 ou o TensorFlow 1.

TensorFlow 2

Se você estiver trabalhando com o TensorFlow 2.x, use tf.saved_model.save para salvar seu modelo. É possível especificar assinaturas de entrada ao salvar seu modelo. Se você tem uma assinatura de entrada, a Vertex Explainable AI usa a função de disponibilização padrão para as solicitações de explicação. Se você tiver mais de uma assinatura de entrada, especifique a assinatura da função padrão de exibição ao salvar o modelo:

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

Nesse caso, a Vertex Explainable AI usa a assinatura da função de modelo que você salvou com a chave xai_model para sua solicitação de explicações. Use a string exata xai_model para a chave.

Se você usar uma função de pré-processamento, também precisará especificar as assinaturas das funções de pré-processamento e de modelo. É necessário usar as strings exatas xai_preprocess e xai_model como as chaves:

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
    })

Nesse caso, a Vertex Explainable AI usa sua função de pré-processamento e a função de modelo para as solicitações de explicação. Verifique se o resultado da função de pré-processamento corresponde à entrada que a função do modelo espera.

Saiba mais sobre como especificar assinaturas de exibição no TensorFlow.

TensorFlow 1.15

Se você estiver trabalhando com o TensorFlow 1.15, não use tf.saved_model.save. A Vertex Explainable AI não é compatível com modelos do TensorFlow 1 salvos com este método

Se você criar e treinar seu modelo no Keras, será necessário convertê-lo em um Estimator do TensorFlow e, em seguida, exportá-lo para um SavedModel. Nesta seção, nos concentramos em salvar um modelo.

Depois de criar, compilar, treinar e avaliar seu modelo Keras, será necessário seguir estas etapas:

  • Converta o modelo Keras em um Estimator do TensorFlow usando tf.keras.estimator.model_to_estimator.
  • Forneça uma função de entrada de exibição usando tf.estimator.export.build_raw_serving_input_receiver_fn.
  • Exporte o modelo como SavedModel, usando 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)

Conseguir os nomes de tensores por meio do SignatureDef de um SavedModel

Use o SignatureDef de um SavedModel do TensorFlow para preparar seus metadados de explicação, desde que ele atenda aos critérios do "método básico" descritos em uma seção anterior. Isso pode ser útil se você não tiver acesso ao código de treinamento que produziu o modelo.

Para inspecionar o SignatureDef do SavedModel, use a CLI SavedModel. Saiba mais sobre como usar a CLI SavedModel.

Veja o exemplo a seguir 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

O gráfico tem um tensor de entrada denominado x:0 e um tensor de saída denominado dense/Softmax:0. Ao configurar o Model para explicações, use x:0 como o nome do tensor de entrada e dense/Softmax:0 como o nome do tensor de saída na mensagem ExplanationMetadata.

A seguir