Ejemplo de optimización restringida de TensorFlow con el conjunto de datos CelebA

Ver en TensorFlow.org Ejecutar en Google Colab Ver en GitHub Descargar cuaderno

Este cuaderno demuestra una manera fácil de crear y optimizar problemas restringidos utilizando la biblioteca TFCO. Este método puede ser útil en la mejora de los modelos cuando nos encontramos con que no está realizando igualmente bien a través de diferentes rebanadas de nuestros datos, que podemos identificar el uso de indicadores Equidad . El segundo de los principios de IA de Google establece que nuestra tecnología debe evitar crear o reforzar un sesgo injusto, y creemos que esta técnica puede ayudar a mejorar la imparcialidad del modelo en algunas situaciones. En particular, este cuaderno:

  • Capacitar a un simple, modelo de red neuronal sin restricciones para detectar la sonrisa de una persona en imágenes utilizando tf.keras y los CelebFaces a gran escala Atributos ( CelebA ) del conjunto de datos.
  • Evalúe el rendimiento del modelo en comparación con una métrica de equidad de uso común en todos los grupos de edad, utilizando indicadores de equidad.
  • Configure un problema de optimización restringido simple para lograr un rendimiento más justo en todos los grupos de edad.
  • Volver a entrenar el modelo hasta ahora restringido y evaluar el desempeño de nuevo, asegurando que nuestra métrica equidad elegido ha mejorado.

Última actualización: 3/11 de febrero de 2020

Instalación

Este cuaderno fue creado en Colaboratorio , conectado a la Python 3 backend Google Compute Engine. Si desea alojar este portátil en un entorno diferente, no debería experimentar ningún problema importante siempre que incluya todos los paquetes necesarios en las celdas a continuación.

Tenga en cuenta que la primera vez que ejecuta las instalaciones de pip, es posible que se le solicite que reinicie el tiempo de ejecución debido a paquetes obsoletos preinstalados. Una vez que lo haga, se utilizarán los paquetes correctos.

instalaciones pip

Tenga en cuenta que, dependiendo de cuándo ejecute la siguiente celda, es posible que reciba una advertencia sobre la versión predeterminada de TensorFlow en Colab que cambiará pronto a TensorFlow 2.X. Puede ignorar esa advertencia con seguridad, ya que este portátil fue diseñado para ser compatible con TensorFlow 1.X y 2.X.

Importar módulos

Además, agregamos algunas importaciones que son específicas de los indicadores de equidad que usaremos para evaluar y visualizar el rendimiento del modelo.

Si bien TFCO es compatible con la ejecución ansiosa y gráfica, este cuaderno asume que la ejecución ansiosa está habilitada de manera predeterminada, como lo está en TensorFlow 2.x. Para asegurarse de que nada se rompa, la ejecución ansiosa se habilitará en la celda a continuación.

Habilitar la ejecución ansiosa y las versiones de impresión

Eager execution enabled by default.
TensorFlow 2.8.0-rc0
TFMA 0.36.0
TFDS 4.4.0
FI 0.36.0

Conjunto de datos de CelebA

CelebA es una cara de gran escala atributos conjunto de datos con más de 200.000 imágenes de famosos, cada uno con 40 anotaciones de atributos (como el tipo de cabello, accesorios de moda, rasgos faciales, etc.) y lugares emblemáticos 5 (ojos, boca y nariz posiciones). Para más detalles ver el documento . Con el permiso de los propietarios, hemos guardado este conjunto de datos en Google Cloud Storage y sobre todo acceder a él a través de TensorFlow conjuntos de datos ( tfds ) .

En este cuaderno:

  • Nuestro modelo intentará clasificar a si el sujeto de la imagen está sonriendo, representado por el "sonriendo" atributo *.
  • Las imágenes cambiarán de tamaño de 218x178 a 28x28 para reducir el tiempo de ejecución y la memoria durante el entrenamiento.
  • El rendimiento de nuestro modelo se evaluará en todos los grupos de edad, utilizando el atributo binario "Joven". Llamaremos a este "grupo de edad" en este cuaderno.

* Aunque hay poca información disponible acerca de la metodología de caracterizar el conjunto de datos, vamos a suponer que el atributo "Sonreír" fue determinada por una expresión de satisfacción, especie, o divertida en la cara del sujeto. A los efectos de este estudio de caso, tomaremos estas etiquetas como datos básicos.

gcs_base_dir = "gs://celeb_a_dataset/"
celeb_a_builder = tfds.builder("celeb_a", data_dir=gcs_base_dir, version='2.0.0')

celeb_a_builder.download_and_prepare()

num_test_shards_dict = {'0.3.0': 4, '2.0.0': 2} # Used because we download the test dataset separately
version = str(celeb_a_builder.info.version)
print('Celeb_A dataset version: %s' % version)
Celeb_A dataset version: 2.0.0

Probar las funciones auxiliares del conjunto de datos

Advertencias

Antes de seguir adelante, hay varias consideraciones a tener en cuenta al usar CelebA:

  • Aunque en principio este cuaderno podría usar cualquier conjunto de datos de imágenes de rostros, se eligió CelebA porque contiene imágenes de dominio público de figuras públicas.
  • Todas las anotaciones de atributos en CelebA se operacionalizan como categorías binarias. Por ejemplo, el atributo "Joven" (según lo determinado por los etiquetadores del conjunto de datos) se indica como presente o ausente en la imagen.
  • Las categorizaciones de CelebA no reflejan la diversidad humana real de atributos.
  • A los efectos de este cuaderno, la entidad que contiene el atributo "Joven" se denomina "grupo de edad", donde la presencia del atributo "Joven" en una imagen se etiqueta como miembro del grupo de edad "Joven" y la la ausencia del atributo "Joven" se etiqueta como miembro del grupo de edad "No joven". Estos son suposiciones hechas ya que esta información no se menciona en el documento original .
  • Como tal, el desempeño en los modelos entrenados en este cuaderno está ligado a las formas en que los atributos han sido operacionalizados y anotados por los autores de CelebA.
  • Este modelo no debe utilizarse para fines comerciales como que violaría acuerdo de investigación no comercial de CelebA .

Configuración de funciones de entrada

Las celdas posteriores ayudarán a optimizar la canalización de entrada y a visualizar el rendimiento.

Primero definimos algunas variables relacionadas con los datos y definimos una función de preprocesamiento necesaria.

Definir Variables

Definir funciones de preprocesamiento

Luego, construimos las funciones de datos que necesitamos en el resto de la colaboración.

# Train data returning either 2 or 3 elements (the third element being the group)
def celeb_a_train_data_wo_group(batch_size):
  celeb_a_train_data = celeb_a_builder.as_dataset(split='train').shuffle(1024).repeat().batch(batch_size).map(preprocess_input_dict)
  return celeb_a_train_data.map(get_image_and_label)
def celeb_a_train_data_w_group(batch_size):
  celeb_a_train_data = celeb_a_builder.as_dataset(split='train').shuffle(1024).repeat().batch(batch_size).map(preprocess_input_dict)
  return celeb_a_train_data.map(get_image_label_and_group)

# Test data for the overall evaluation
celeb_a_test_data = celeb_a_builder.as_dataset(split='test').batch(1).map(preprocess_input_dict).map(get_image_label_and_group)
# Copy test data locally to be able to read it into tfma
copy_test_files_to_local()

Construya un modelo DNN simple

Debido a que este cuaderno se centra en TFCO, vamos a montar un sencillo, sin restricciones tf.keras.Sequential modelo.

Es posible que podamos mejorar en gran medida el rendimiento del modelo agregando algo de complejidad (por ejemplo, capas más densamente conectadas, explorando diferentes funciones de activación, aumentando el tamaño de la imagen), pero eso puede distraernos del objetivo de demostrar lo fácil que es aplicar la biblioteca TFCO. al trabajar con Keras. Por esa razón, el modelo se mantendrá simple, pero anímate a explorar este espacio.

def create_model():
  # For this notebook, accuracy will be used to evaluate performance.
  METRICS = [
    tf.keras.metrics.BinaryAccuracy(name='accuracy')
  ]

  # The model consists of:
  # 1. An input layer that represents the 28x28x3 image flatten.
  # 2. A fully connected layer with 64 units activated by a ReLU function.
  # 3. A single-unit readout layer to output real-scores instead of probabilities.
  model = keras.Sequential([
      keras.layers.Flatten(input_shape=(IMAGE_SIZE, IMAGE_SIZE, 3), name='image'),
      keras.layers.Dense(64, activation='relu'),
      keras.layers.Dense(1, activation=None)
  ])

  # TFCO by default uses hinge loss — and that will also be used in the model.
  model.compile(
      optimizer=tf.keras.optimizers.Adam(0.001),
      loss='hinge',
      metrics=METRICS)
  return model

También definimos una función para establecer semillas para garantizar resultados reproducibles. Tenga en cuenta que esta colaboración está pensada como una herramienta educativa y no tiene la estabilidad de un canal de producción ajustado con precisión. Ejecutar sin establecer una semilla puede conducir a resultados variados.

def set_seeds():
  np.random.seed(121212)
  tf.compat.v1.set_random_seed(212121)

Indicadores de equidad Funciones auxiliares

Antes de entrenar nuestro modelo, definimos una serie de funciones auxiliares que nos permitirán evaluar el rendimiento del modelo a través de indicadores de equidad.

Primero, creamos una función auxiliar para guardar nuestro modelo una vez que lo entrenamos.

def save_model(model, subdir):
  base_dir = tempfile.mkdtemp(prefix='saved_models')
  model_location = os.path.join(base_dir, subdir)
  model.save(model_location, save_format='tf')
  return model_location

A continuación, definimos funciones utilizadas para preprocesar los datos para pasarlos correctamente a TFMA.

Funciones de preprocesamiento de datos para

Finalmente, definimos una función que evalúa los resultados en TFMA.

def get_eval_results(model_location, eval_subdir):
  base_dir = tempfile.mkdtemp(prefix='saved_eval_results')
  tfma_eval_result_path = os.path.join(base_dir, eval_subdir)

  eval_config_pbtxt = """
        model_specs {
          label_key: "%s"
        }
        metrics_specs {
          metrics {
            class_name: "FairnessIndicators"
            config: '{ "thresholds": [0.22, 0.5, 0.75] }'
          }
          metrics {
            class_name: "ExampleCount"
          }
        }
        slicing_specs {}
        slicing_specs { feature_keys: "%s" }
        options {
          compute_confidence_intervals { value: False }
          disabled_outputs{values: "analysis"}
        }
      """ % (LABEL_KEY, GROUP_KEY)

  eval_config = text_format.Parse(eval_config_pbtxt, tfma.EvalConfig())

  eval_shared_model = tfma.default_eval_shared_model(
        eval_saved_model_path=model_location, tags=[tf.saved_model.SERVING])

  schema_pbtxt = """
        tensor_representation_group {
          key: ""
          value {
            tensor_representation {
              key: "%s"
              value {
                dense_tensor {
                  column_name: "%s"
                  shape {
                    dim { size: 28 }
                    dim { size: 28 }
                    dim { size: 3 }
                  }
                }
              }
            }
          }
        }
        feature {
          name: "%s"
          type: FLOAT
        }
        feature {
          name: "%s"
          type: FLOAT
        }
        feature {
          name: "%s"
          type: BYTES
        }
        """ % (IMAGE_KEY, IMAGE_KEY, IMAGE_KEY, LABEL_KEY, GROUP_KEY)
  schema = text_format.Parse(schema_pbtxt, schema_pb2.Schema())
  coder = tf_example_record.TFExampleBeamRecord(
      physical_format='inmem', schema=schema,
      raw_record_column_name=tfma.ARROW_INPUT_COLUMN)
  tensor_adapter_config = tensor_adapter.TensorAdapterConfig(
    arrow_schema=coder.ArrowSchema(),
    tensor_representations=coder.TensorRepresentations())
  # Run the fairness evaluation.
  with beam.Pipeline() as pipeline:
    _ = (
          tfds_as_pcollection(pipeline, 'celeb_a', 'test')
          | 'ExamplesToRecordBatch' >> coder.BeamSource()
          | 'ExtractEvaluateAndWriteResults' >>
          tfma.ExtractEvaluateAndWriteResults(
              eval_config=eval_config,
              eval_shared_model=eval_shared_model,
              output_path=tfma_eval_result_path,
              tensor_adapter_config=tensor_adapter_config)
    )
  return tfma.load_eval_result(output_path=tfma_eval_result_path)

Entrenar y evaluar modelo sin restricciones

Con el modelo ahora definido y la canalización de entrada en su lugar, ahora estamos listos para entrenar nuestro modelo. Para reducir la cantidad de memoria y tiempo de ejecución, entrenaremos el modelo dividiendo los datos en lotes pequeños con solo unas pocas iteraciones repetidas.

Tenga en cuenta que la ejecución de este cuaderno en TensorFlow <2.0.0 puede resultar en una advertencia para la desaprobación np.where . Segura ignorar esta advertencia como TensorFlow aborda esto en 2.X mediante el uso de tf.where en lugar de np.where .

BATCH_SIZE = 32

# Set seeds to get reproducible results
set_seeds()

model_unconstrained = create_model()
model_unconstrained.fit(celeb_a_train_data_wo_group(BATCH_SIZE), epochs=5, steps_per_epoch=1000)
Epoch 1/5
1000/1000 [==============================] - 12s 6ms/step - loss: 0.5038 - accuracy: 0.7733
Epoch 2/5
1000/1000 [==============================] - 7s 7ms/step - loss: 0.3800 - accuracy: 0.8301
Epoch 3/5
1000/1000 [==============================] - 6s 6ms/step - loss: 0.3598 - accuracy: 0.8427
Epoch 4/5
1000/1000 [==============================] - 25s 25ms/step - loss: 0.3435 - accuracy: 0.8474
Epoch 5/5
1000/1000 [==============================] - 5s 5ms/step - loss: 0.3402 - accuracy: 0.8479
<keras.callbacks.History at 0x7f0f5c476350>

La evaluación del modelo en los datos de prueba debería dar como resultado una puntuación de precisión final de poco más del 85 %. No está mal para un modelo simple sin ajustes finos.

print('Overall Results, Unconstrained')
celeb_a_test_data = celeb_a_builder.as_dataset(split='test').batch(1).map(preprocess_input_dict).map(get_image_label_and_group)
results = model_unconstrained.evaluate(celeb_a_test_data)
Overall Results, Unconstrained
19962/19962 [==============================] - 50s 2ms/step - loss: 0.2125 - accuracy: 0.8636

Sin embargo, el desempeño evaluado en todos los grupos de edad puede revelar algunas deficiencias.

Para explorar esto más a fondo, evaluamos el modelo con indicadores de equidad (a través de TFMA). En particular, estamos interesados ​​en ver si existe una brecha significativa en el rendimiento entre las categorías "Joven" y "No joven" cuando se evalúan en la tasa de falsos positivos.

Se produce un error de falso positivo cuando el modelo predice incorrectamente la clase positiva. En este contexto, se produce un resultado falso positivo cuando la verdad fundamental es una imagen de una celebridad que "no sonríe" y el modelo predice que "sonríe". Por extensión, la tasa de falsos positivos, que se utiliza en la visualización anterior, es una medida de la precisión de una prueba. Si bien este es un error relativamente mundano en este contexto, los errores de falso positivo a veces pueden causar comportamientos más problemáticos. Por ejemplo, un error de falso positivo en un clasificador de spam podría hacer que un usuario pierda un correo electrónico importante.

model_location = save_model(model_unconstrained, 'model_export_unconstrained')
eval_results_unconstrained = get_eval_results(model_location, 'eval_results_unconstrained')
2022-01-07 18:46:05.881112: W tensorflow/python/util/util.cc:368] Sets are not currently considered sequences, but this may change in the future, so consider avoiding using them.
INFO:tensorflow:Assets written to: /tmp/saved_modelswhxcqdry/model_export_unconstrained/assets
INFO:tensorflow:Assets written to: /tmp/saved_modelswhxcqdry/model_export_unconstrained/assets
WARNING:apache_beam.runners.interactive.interactive_environment:Dependencies required for Interactive Beam PCollection visualization are not available, please use: `pip install apache-beam[interactive]` to install necessary dependencies to enable all data visualization features.
WARNING:root:Make sure that locally built Python SDK docker image has Python 3.7 interpreter.
WARNING:apache_beam.io.tfrecordio:Couldn't find python-snappy so the implementation of _TFRecordUtil._masked_crc32c is not as fast as it could be.
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow_model_analysis/writers/metrics_plots_and_validations_writer.py:107: tf_record_iterator (from tensorflow.python.lib.io.tf_record) is deprecated and will be removed in a future version.
Instructions for updating:
Use eager execution and: 
`tf.data.TFRecordDataset(path)`
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow_model_analysis/writers/metrics_plots_and_validations_writer.py:107: tf_record_iterator (from tensorflow.python.lib.io.tf_record) is deprecated and will be removed in a future version.
Instructions for updating:
Use eager execution and: 
`tf.data.TFRecordDataset(path)`

Como se mencionó anteriormente, nos estamos concentrando en la tasa de falsos positivos. La versión actual de Fairness Indicators (0.1.2) selecciona la tasa de falsos negativos de forma predeterminada. Después de ejecutar la siguiente línea, anule la selección de false_negative_rate y seleccione false_positive_rate para ver la métrica que nos interesa.

tfma.addons.fairness.view.widget_view.render_fairness_indicator(eval_results_unconstrained)
FairnessIndicatorViewer(slicingMetrics=[{'sliceValue': 'Young', 'slice': 'Young:Young', 'metrics': {'example_c…

Como muestran los resultados más arriba, vemos una desproporción entre el "joven" y "No categorías jóvenes".

Aquí es donde TFCO puede ayudar al restringir la tasa de falsos positivos para que esté dentro de un criterio más aceptable.

Configuración del modelo restringido

Como se documenta en la biblioteca de TFCO , hay varios ayudantes que harán que sea más fácil para limitar el problema:

  1. tfco.rate_context() - Esto es lo que va a ser utilizado en la construcción de una restricción para cada categoría de edad.
  2. tfco.RateMinimizationProblem() - La expresión de la velocidad a minimizarse aquí será la tasa de falsos positivos sometidos a grupo de edad. En otras palabras, el rendimiento ahora se evaluará en función de la diferencia entre las tasas de falsos positivos del grupo de edad y la del conjunto de datos general. Para esta demostración, se establecerá como restricción una tasa de falsos positivos menor o igual al 5%.
  3. tfco.ProxyLagrangianOptimizerV2() - Este es el ayudante que realmente va a resolver el problema de restricción de velocidad.

La siguiente celda llamará a estos ayudantes para configurar el entrenamiento modelo con la restricción de equidad.

# The batch size is needed to create the input, labels and group tensors.
# These tensors are initialized with all 0's. They will eventually be assigned
# the batch content to them. A large batch size is chosen so that there are
# enough number of "Young" and "Not Young" examples in each batch.
set_seeds()
model_constrained = create_model()
BATCH_SIZE = 32

# Create input tensor.
input_tensor = tf.Variable(
    np.zeros((BATCH_SIZE, IMAGE_SIZE, IMAGE_SIZE, 3), dtype="float32"),
    name="input")

# Create labels and group tensors (assuming both labels and groups are binary).
labels_tensor = tf.Variable(
    np.zeros(BATCH_SIZE, dtype="float32"), name="labels")
groups_tensor = tf.Variable(
    np.zeros(BATCH_SIZE, dtype="float32"), name="groups")

# Create a function that returns the applied 'model' to the input tensor
# and generates constrained predictions.
def predictions():
  return model_constrained(input_tensor)

# Create overall context and subsetted context.
# The subsetted context contains subset of examples where group attribute < 1
# (i.e. the subset of "Not Young" celebrity images).
# "groups_tensor < 1" is used instead of "groups_tensor == 0" as the former
# would be a comparison on the tensor value, while the latter would be a
# comparison on the Tensor object.
context = tfco.rate_context(predictions, labels=lambda:labels_tensor)
context_subset = context.subset(lambda:groups_tensor < 1)

# Setup list of constraints.
# In this notebook, the constraint will just be: FPR to less or equal to 5%.
constraints = [tfco.false_positive_rate(context_subset) <= 0.05]

# Setup rate minimization problem: minimize overall error rate s.t. constraints.
problem = tfco.RateMinimizationProblem(tfco.error_rate(context), constraints)

# Create constrained optimizer and obtain train_op.
# Separate optimizers are specified for the objective and constraints
optimizer = tfco.ProxyLagrangianOptimizerV2(
      optimizer=tf.keras.optimizers.Adam(learning_rate=0.001),
      constraint_optimizer=tf.keras.optimizers.Adam(learning_rate=0.001),
      num_constraints=problem.num_constraints)

# A list of all trainable variables is also needed to use TFCO.
var_list = (model_constrained.trainable_weights + list(problem.trainable_variables) +
            optimizer.trainable_variables())

El modelo ahora está configurado y listo para ser entrenado con la restricción de tasa de falsos positivos en todo el grupo de edad.

Ahora, debido a que la última iteración del modelo restringido puede no ser necesariamente el modelo con mejor comportamiento en términos de la restricción definida, la biblioteca TFCO viene equipado con tfco.find_best_candidate_index() que la ayuda pueda elegir el mejor iterate de los que se encuentran después de cada época. Piense en tfco.find_best_candidate_index() como una heurística añadido que ocupa cada uno de los resultados basados en la precisión y la restricción de equidad (en este caso, tasa de falsos positivos en todo grupo de edad) por separado con respecto a los datos de entrenamiento. De esa manera, puede buscar una mejor compensación entre la precisión general y la restricción de equidad.

Las siguientes celdas comenzarán el entrenamiento con restricciones y al mismo tiempo encontrarán el modelo de mejor rendimiento por iteración.

# Obtain train set batches.

NUM_ITERATIONS = 100  # Number of training iterations.
SKIP_ITERATIONS = 10  # Print training stats once in this many iterations.

# Create temp directory for saving snapshots of models.
temp_directory = tempfile.mktemp()
os.mkdir(temp_directory)

# List of objective and constraints across iterations.
objective_list = []
violations_list = []

# Training iterations.
iteration_count = 0
for (image, label, group) in celeb_a_train_data_w_group(BATCH_SIZE):
  # Assign current batch to input, labels and groups tensors.
  input_tensor.assign(image)
  labels_tensor.assign(label)
  groups_tensor.assign(group)

  # Run gradient update.
  optimizer.minimize(problem, var_list=var_list)

  # Record objective and violations.
  objective = problem.objective()
  violations = problem.constraints()

  sys.stdout.write(
      "\r Iteration %d: Hinge Loss = %.3f, Max. Constraint Violation = %.3f"
      % (iteration_count + 1, objective, max(violations)))

  # Snapshot model once in SKIP_ITERATIONS iterations.
  if iteration_count % SKIP_ITERATIONS == 0:
    objective_list.append(objective)
    violations_list.append(violations)

    # Save snapshot of model weights.
    model_constrained.save_weights(
        temp_directory + "/celeb_a_constrained_" +
        str(iteration_count / SKIP_ITERATIONS) + ".h5")

  iteration_count += 1
  if iteration_count >= NUM_ITERATIONS:
    break

# Choose best model from recorded iterates and load that model.
best_index = tfco.find_best_candidate_index(
    np.array(objective_list), np.array(violations_list))

model_constrained.load_weights(
    temp_directory + "/celeb_a_constrained_" + str(best_index) + ".0.h5")

# Remove temp directory.
os.system("rm -r " + temp_directory)
Iteration 100: Hinge Loss = 0.614, Max. Constraint Violation = 0.268
0

Después de haber aplicado la restricción, evaluamos los resultados nuevamente usando Indicadores de Equidad.

model_location = save_model(model_constrained, 'model_export_constrained')
eval_result_constrained = get_eval_results(model_location, 'eval_results_constrained')
INFO:tensorflow:Assets written to: /tmp/saved_modelsbztxt9fy/model_export_constrained/assets
INFO:tensorflow:Assets written to: /tmp/saved_modelsbztxt9fy/model_export_constrained/assets
WARNING:root:Make sure that locally built Python SDK docker image has Python 3.7 interpreter.

Al igual que la vez anterior, usamos indicadores de equidad, anule la selección de tasa_negativa_falsa y seleccione tasa_positiva_falsa para ver la métrica que nos interesa.

Tenga en cuenta que para comparar de manera justa las dos versiones de nuestro modelo, es importante usar umbrales que establezcan que la tasa general de falsos positivos sea aproximadamente igual. Esto asegura que estamos viendo un cambio real en lugar de solo un cambio en el modelo equivalente a simplemente mover el límite del umbral. En nuestro caso, comparar el modelo sin restricciones en 0,5 y el modelo restringido en 0,22 proporciona una comparación justa de los modelos.

eval_results_dict = {
    'constrained': eval_result_constrained,
    'unconstrained': eval_results_unconstrained,
}
tfma.addons.fairness.view.widget_view.render_fairness_indicator(multi_eval_results=eval_results_dict)
FairnessIndicatorViewer(evalName='constrained', evalNameCompare='unconstrained', slicingMetrics=[{'sliceValue'…

Con la capacidad de TFCO de expresar un requisito más complejo como una restricción de tasa, ayudamos a este modelo a lograr un resultado más deseable con poco impacto en el rendimiento general. Por supuesto, todavía hay espacio para mejorar, pero al menos TFCO pudo encontrar un modelo que se acerca a satisfacer la restricción y reduce la disparidad entre los grupos tanto como sea posible.