自訂 MinDiffModel

簡介

在大多數情況下,直接使用 MinDiffModel (如「將 MinDiff 與 MinDiffModel 整合」指南所述) 就已足夠。但是,您可能需要自訂行為。主要有兩個原因:

  • 您使用的 keras.Model 具有您想要保留的自訂行為。
  • 您希望 MinDiffModel 的行為與預設行為不同。

在上述任一種情況下,您都需要子類別化 MinDiffModel 才能達到理想結果。

設定

pip install --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

首先,下載資料。為了簡潔起見,輸入準備邏輯已分解成輔助函式,如輸入準備指南中所述。您可以閱讀完整指南,以瞭解此程序的詳細資訊。

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

保留原始模型自訂項目

tf.keras.Model 的設計旨在透過子類別化輕鬆自訂,如此處所述。如果您的模型具有您希望在套用 MinDiff 時保留的自訂實作項目,則需要子類別化 MinDiffModel

原始自訂模型

若要瞭解如何保留自訂項目,請建立一個自訂模型,當呼叫其自訂 train_step 時,該模型會將屬性設為 True。這不是有用的自訂項目,但可用於說明行為。

class CustomModel(tf.keras.Model):

  # Customized train_step
  def train_step(self, *args, **kwargs):
    self.used_custom_train_step = True  # Marker that we can check for.
    return super(CustomModel, self).train_step(*args, **kwargs)

訓練這類模型看起來會與一般 Sequential 模型相同。

model = tutorials_utils.get_uci_model(model_class=CustomModel)  # Use CustomModel.

model.compile(optimizer='adam', loss='binary_crossentropy')

_ = model.fit(train_ds.take(1), epochs=1, verbose=0)

# Model has used the custom train_step.
print('Model used the custom train_step:')
print(hasattr(model, 'used_custom_train_step'))  # True

子類別化 MinDiffModel

如果您嘗試直接使用 MinDiffModel,模型將不會使用自訂 train_step

model = tutorials_utils.get_uci_model(model_class=CustomModel)
model = min_diff.keras.MinDiffModel(model, min_diff.losses.MMDLoss())

model.compile(optimizer='adam', loss='binary_crossentropy')

_ = model.fit(train_with_min_diff_ds.take(1), epochs=1, verbose=0)

# Model has not used the custom train_step.
print('Model used the custom train_step:')
print(hasattr(model, 'used_custom_train_step'))  # False

為了使用正確的 train_step 方法,您需要一個同時子類別化 MinDiffModelCustomModel 的自訂類別。

class CustomMinDiffModel(min_diff.keras.MinDiffModel, CustomModel):
  pass  # No need for any further implementation.

訓練此模型將會使用來自 CustomModeltrain_step

model = tutorials_utils.get_uci_model(model_class=CustomModel)

model = CustomMinDiffModel(model, min_diff.losses.MMDLoss())

model.compile(optimizer='adam', loss='binary_crossentropy')

_ = model.fit(train_with_min_diff_ds.take(1), epochs=1, verbose=0)

# Model has used the custom train_step.
print('Model used the custom train_step:')
print(hasattr(model, 'used_custom_train_step'))  # True

自訂 MinDiffModel 的預設行為

在其他情況下,您可能想要變更 MinDiffModel 的特定預設行為。最常見的用途是變更預設解壓縮行為,以便在您未使用 pack_min_diff_data 的情況下正確處理您的資料。

將資料封裝成自訂格式時,可能會如下所示。

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)

  return ({
      'min_diff_data': min_diff_data,
      'original_inputs': original_inputs}, original_labels)

customized_train_with_min_diff_ds = train_with_min_diff_ds.map(_reformat_input)

customized_train_with_min_diff_ds 資料集傳回由元組 (x, y) 組成的批次,其中 x 是包含 min_diff_dataoriginal_inputs 的字典,而 y 則是 original_labels

for x, _ in customized_train_with_min_diff_ds.take(1):
  print('Type of x:', type(x))  # dict
  print('Keys of x:', x.keys())  # 'min_diff_data', 'original_inputs'

此資料格式不是 MinDiffModel 預設預期的格式,將 customized_train_with_min_diff_ds 傳遞給它會導致非預期的行為。若要修正此問題,您需要建立自己的子類別。

class CustomUnpackingMinDiffModel(min_diff.keras.MinDiffModel):

  def unpack_min_diff_data(self, inputs):
    return inputs['min_diff_data']

  def unpack_original_inputs(self, inputs):
    return inputs['original_inputs']

使用此子類別,您可以像其他範例一樣進行訓練。

model = tutorials_utils.get_uci_model()
model = CustomUnpackingMinDiffModel(model, min_diff.losses.MMDLoss())

model.compile(optimizer='adam', loss='binary_crossentropy')

_ = model.fit(customized_train_with_min_diff_ds, epochs=1)

自訂 MinDiffModel 的限制

建立自訂 MinDiffModel 為更複雜的用途提供了極大的彈性。但是,仍有一些邊緣情況是其無法支援的。

call 之前預先處理或驗證輸入

子類別化 MinDiffModel 的最大限制是,它需要輸入資料的 x 元件 (亦即 tf.data.Dataset 傳回的批次中的第一個或唯一元素) 直接傳遞至 call,而無需預先處理或驗證。

這很簡單,因為 min_diff_data 已封裝到輸入資料的 x 元件中。任何預先處理或驗證都不會預期包含 min_diff_data 的額外結構,而且可能會中斷。

如果預先處理或驗證很容易自訂 (例如分解成自己的方法),則可以輕鬆地透過覆寫來解決此問題,以確保其正確處理額外結構。

具有驗證的範例可能如下所示

class CustomMinDiffModel(min_diff.keras.MinDiffModel, CustomModel):

  # Override so that it correctly handles additional `min_diff_data`.
  def validate_inputs(self, inputs):
    original_inputs = self.unpack_original_inputs(inputs)
    ...  # Optionally also validate min_diff_data
    # Call original validate method with correct inputs
    return super(CustomMinDiffModel, self).validate(original_inputs)

如果預先處理或驗證不容易自訂,則使用 MinDiffModel 可能不適用於您,而且您需要整合 MinDiff 而不使用它,如本指南中所述。

方法名稱衝突

您的模型可能具有方法,其名稱與 MinDiffModel 中實作的方法名稱衝突 (請參閱API 文件中的完整公開方法清單)。

只有在這些方法將在模型執行個體上呼叫時,才會出現問題 (而不是在某些其他方法中內部呼叫)。雖然機率很低,但如果您遇到這種情況,則必須覆寫和重新命名某些方法,或者,如果不可能,您可能需要考慮整合 MinDiff 而不使用 MinDiffModel,如關於此主題的指南中所述。

其他資源

  • 如需深入瞭解公平性評估的討論,請參閱Fairness Indicators 指南
  • 如需關於修正和 MinDiff 的一般資訊,請參閱修正總覽
  • 如需關於 MinDiff 相關需求的詳細資訊,請參閱本指南
  • 若要查看關於在 Keras 中使用 MinDiff 的端對端教學課程,請參閱本教學課程