Visualizza su TensorFlow.org | Esegui in Google Colab | Visualizza la fonte su GitHub | Scarica il taccuino |
introduzione
È possibile integrare MinDiff direttamente nell'implementazione del modello. Nel farlo non ha la comodità di usare MinDiffModel
, questa opzione offre il più alto livello di controllo che può essere particolarmente utile quando il modello è una sottoclasse di tf.keras.Model
.
Questa guida spiega come è possibile integrare MinDiff direttamente nella realizzazione di un modello personalizzato aggiungendo alla train_step
metodo.
Impostare
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
Innanzitutto, scarica i dati. Per brevità, la logica preparazione ingresso è stato fattorizzato nella helper funzioni come descritto nella guida di preparazione ingresso . Puoi leggere la guida completa per i dettagli su questo processo.
# 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))
Personalizzazioni del modello personalizzato originale
tf.keras.Model
è progettato per essere facilmente personalizzabile tramite sottoclassi. Questo di solito comporta cambiare ciò che accade nella chiamata per fit
come descritto qui .
Questa guida utilizza un'implementazione personalizzata dove il train_step
ricorda da vicino il default tf.keras.Model.train_step
. Normalmente, non ci sarebbe alcun vantaggio nel farlo, ma qui aiuterà a dimostrare come integrare 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}
Addestrare il modello come se fosse un tipico Model
utilizzando l'API funzionale.
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
Integrare MinDiff direttamente nel tuo modello
Aggiunta MinDiff al train_step
Per integrare MinDiff, è necessario aggiungere alcune righe alla CustomModel
che viene rinominato qui come CustomModelWithMinDiff
.
Per chiarezza, questa guida utilizza un flag booleano chiamato apply_min_diff
. Tutto il codice rilevante per MinDiff verrà eseguito solo se è impostata su True
. Se impostato su False
allora il modello si comporterebbe esattamente come 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}
L'addestramento con questo modello ha lo stesso aspetto del precedente, ad eccezione del set di dati utilizzato.
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
Rimodellare il tuo input (opzionale)
Dato che questo approccio fornisce il pieno controllo, puoi cogliere questa opportunità per rimodellare l'input in una forma leggermente più pulita. Quando si utilizza MinDiffModel
, il min_diff_data
deve essere confezionato in primo componente di ogni lotto. Questo è il caso del train_with_min_diff_ds
set di dati.
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 questo requisito sollevato, puoi riorganizzare i dati in una struttura leggermente più intuitiva con i dati originali e MinDiff separati in modo pulito.
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)
Questo passaggio è del tutto facoltativo ma può essere utile per organizzare al meglio i dati. In tal caso, l'unica differenza nel modo in cui si sceglie di implementare CustomModelWithMinDiff
sarà come si estrae data
all'inizio.
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 quest'ultimo passaggio, puoi controllare completamente sia il formato di input che come viene utilizzato all'interno del modello per applicare MinDiff.
Risorse addizionali
- Per una discussione approfondita sulla valutazione congruità vedere la guida Fairness Indicatori
- Per informazioni di carattere generale su Risanamento e MinDiff, vedere la panoramica di bonifica .
- Per i dettagli sui requisiti che circondano MinDiff vedere questa guida .
- Per vedere un tutorial end-to-end sull'utilizzo MinDiff in Keras, consultare questo tutorial .