Introducción
Es posible integrar MinDiff directamente en la implementación de su modelo. Al hacerlo no tiene la conveniencia de utilizar MinDiffModel
, esta opción ofrece el más alto nivel de control que puede ser particularmente útil cuando el modelo es una subclase de tf.keras.Model
.
Esta guía muestra cómo se puede integrar directamente en MinDiff aplicación de un modelo personalizado añadiendo a la train_step
método.
Configuración
pip install -q --upgrade tensorflow-model-remediation
import tensorflow as tf
tf.get_logger().setLevel('ERROR') # Avoid TF warnings.
from tensorflow_model_remediation import min_diff
from tensorflow_model_remediation.tools.tutorials_utils import uci as tutorials_utils
Primero, descargue los datos. Por concisión, la lógica de preparación de entrada ha sido factorizada hacia helper funciones como se describe en la guía de preparación de entrada . Puede leer la guía completa para obtener detalles sobre este proceso.
# Original Dataset for training, sampled at 0.3 for reduced runtimes.
train_df = tutorials_utils.get_uci_data(split='train', sample=0.3)
train_ds = tutorials_utils.df_to_dataset(train_df, batch_size=128)
# Dataset needed to train with MinDiff.
train_with_min_diff_ds = (
tutorials_utils.get_uci_with_min_diff_dataset(split='train', sample=0.3))
Personalizaciones del modelo personalizado original
tf.keras.Model
está diseñado para personalizar fácilmente a través de la subclasificación. Esto generalmente implica cambiar lo que sucede en la llamada a fit
como se describe aquí .
Esta guía utiliza una implementación personalizada donde el train_step
parece mucho a la forma predeterminada tf.keras.Model.train_step
. Normalmente, no habría ningún beneficio al hacerlo, pero aquí, ayudará a demostrar cómo integrar MinDiff.
class CustomModel(tf.keras.Model):
def train_step(self, data):
# Unpack the data.
x, y, sample_weight = tf.keras.utils.unpack_x_y_sample_weight(data)
with tf.GradientTape() as tape:
y_pred = self(x, training=True) # Forward pass.
loss = self.compiled_loss(
y, y_pred, sample_weight, regularization_losses=self.losses)
# Compute the loss value.
loss = self.compiled_loss(
y, y_pred, sample_weight, regularization_losses=self.losses)
# Compute gradients and update weights.
self.optimizer.minimize(loss, self.trainable_variables, tape=tape)
# Update and return metrics.
self.compiled_metrics.update_state(y, y_pred, sample_weight)
return {m.name: m.result() for m in self.metrics}
Entrenar el modelo como lo haría un típico Model
uso de la API funcional.
model = tutorials_utils.get_uci_model(model_class=CustomModel) # Use CustomModel.
model.compile(optimizer='adam', loss='binary_crossentropy')
_ = model.fit(train_ds, epochs=1)
77/77 [==============================] - 3s 22ms/step - loss: 0.7273
Integrando MinDiff directamente en su modelo
Adición de MinDiff a la train_step
Para integrar MinDiff, tendrá que añadir algunas líneas a la CustomModel
que se renombró aquí como CustomModelWithMinDiff
.
Para mayor claridad, esta guía utiliza una bandera booleana llamada apply_min_diff
. Todo el código correspondiente a MinDiff sólo se ejecutan si se establece en True
. Si se establece en False
entonces el modelo se comportaría exactamente el mismo que CustomModel
.
min_diff_loss_fn = min_diff.losses.MMDLoss() # Hard coded for convenience.
min_diff_weight = 2 # Arbitrary number for example, hard coded for convenience.
apply_min_diff = True # Flag to help show where the additional lines are.
class CustomModelWithMinDiff(tf.keras.Model):
def train_step(self, data):
# Unpack the data.
x, y, sample_weight = tf.keras.utils.unpack_x_y_sample_weight(data)
# Unpack the MinDiff data.
if apply_min_diff:
min_diff_data = min_diff.keras.utils.unpack_min_diff_data(x)
min_diff_x, membership, min_diff_sample_weight = (
tf.keras.utils.unpack_x_y_sample_weight(min_diff_data))
x = min_diff.keras.utils.unpack_original_inputs(x)
with tf.GradientTape() as tape:
y_pred = self(x, training=True) # Forward pass.
loss = self.compiled_loss(
y, y_pred, sample_weight, regularization_losses=self.losses)
# Compute the loss value.
loss = self.compiled_loss(
y, y_pred, sample_weight, regularization_losses=self.losses)
# Calculate and add the min_diff_loss. This must be done within the scope
# of tf.GradientTape().
if apply_min_diff:
min_diff_predictions = self(min_diff_x, training=True)
min_diff_loss = min_diff_weight * min_diff_loss_fn(
min_diff_predictions, membership, min_diff_sample_weight)
loss += min_diff_loss
# Compute gradients and update weights.
self.optimizer.minimize(loss, self.trainable_variables, tape=tape)
# Update and return metrics.
self.compiled_metrics.update_state(y, y_pred, sample_weight)
return {m.name: m.result() for m in self.metrics}
El entrenamiento con este modelo se ve exactamente igual que con el anterior, con la excepción del conjunto de datos utilizado.
model = tutorials_utils.get_uci_model(model_class=CustomModelWithMinDiff)
model.compile(optimizer='adam', loss='binary_crossentropy')
_ = model.fit(train_with_min_diff_ds, epochs=1)
77/77 [==============================] - 4s 30ms/step - loss: 0.7799
Remodelación de su entrada (opcional)
Dado que este enfoque proporciona un control total, puede aprovechar esta oportunidad para remodelar la entrada en una forma un poco más limpia. Cuando se utiliza MinDiffModel
, la min_diff_data
se debe estar lleno en el primer componente de cada lote. Este es el caso de la train_with_min_diff_ds
conjunto de datos.
for x, y in train_with_min_diff_ds.take(1):
print('Type of x:', type(x)) # MinDiffPackedInputs
print('Type of y:', type(y)) # Tensor (original labels)
Type of x: <class 'tensorflow_model_remediation.min_diff.keras.utils.input_utils.MinDiffPackedInputs'> Type of y: <class 'tensorflow.python.framework.ops.EagerTensor'>
Con este requisito eliminado, puede reorganizar los datos en una estructura un poco más intuitiva con los datos originales y MinDiff claramente separados.
def _reformat_input(inputs, original_labels):
min_diff_data = min_diff.keras.utils.unpack_min_diff_data(inputs)
original_inputs = min_diff.keras.utils.unpack_original_inputs(inputs)
original_data = (original_inputs, original_labels)
return {
'min_diff_data': min_diff_data,
'original_data': original_data}
customized_train_with_min_diff_ds = train_with_min_diff_ds.map(_reformat_input)
Este paso es completamente opcional pero puede ser útil para organizar mejor los datos. Si lo hace, la única diferencia en cómo se implementa CustomModelWithMinDiff
será cómo desembalar data
al principio.
class CustomModelWithMinDiff(tf.keras.Model):
def train_step(self, data):
# Unpack the MinDiff data from the custom structure.
if apply_min_diff:
min_diff_data = data['min_diff_data']
min_diff_x, membership, min_diff_sample_weight = (
tf.keras.utils.unpack_x_y_sample_weight(min_diff_data))
data = data['original_data']
... # possible preprocessing or validation on data before unpacking.
x, y, sample_weight = tf.keras.utils.unpack_x_y_sample_weight(data)
...
Con este último paso, puede controlar completamente tanto el formato de entrada como cómo se usa dentro del modelo para aplicar MinDiff.
Recursos adicionales
- Para una discusión a fondo sobre la evaluación de la equidad ver la orientación Indicadores Fairness
- Para obtener información general sobre rehabilitación y MinDiff, consulte la descripción general de remediación .
- Para más detalles sobre los requisitos que rodean MinDiff ver esta guía .
- Para ver un tutorial de extremo a extremo en el uso de MinDiff en Keras, consulte este tutorial .