การรวม MinDiff โดยไม่มี MinDiffModel

บทนำ

เป็นไปได้ที่จะรวม MinDiff เข้ากับการใช้งานโมเดลของคุณโดยตรง ในขณะที่การทำเช่นนั้นไม่ได้มีความสะดวกสบายของการใช้ MinDiffModel ตัวเลือกนี้จะมีระดับสูงสุดของการควบคุมซึ่งจะเป็นประโยชน์อย่างยิ่งเมื่อรูปแบบของคุณเป็น subclass ของ tf.keras.Model

คู่มือนี้จะแสดงให้เห็นถึงวิธีการที่คุณสามารถบูรณาการ MinDiff โดยตรงในการดำเนินการตามรูปแบบที่กำหนดเองโดยการเพิ่มความ train_step วิธี

ติดตั้ง

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

ขั้นแรกให้ดาวน์โหลดข้อมูล สำหรับความกะทัดรัดตรรกะการเตรียมการป้อนข้อมูลที่ได้รับปัจจัยออกไปในฟังก์ชั่นผู้ช่วยที่อธิบายไว้ใน คู่มือการเตรียมการป้อนข้อมูล คุณสามารถอ่านคู่มือฉบับเต็มสำหรับรายละเอียดเกี่ยวกับกระบวนการนี้

# 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 ถูกออกแบบมาเพื่อปรับแต่งได้อย่างง่ายดายผ่านทาง subclassing นี้มักจะเกี่ยวข้องกับการเปลี่ยนแปลงสิ่งที่เกิดขึ้นในการเรียกร้องให้ fit ตามที่อธิบายไว้ ที่นี่

คู่มือนี้จะใช้ดำเนินการเองที่ train_step คล้ายเริ่มต้น tf.keras.Model.train_step โดยปกติ การทำเช่นนี้จะไม่มีประโยชน์ แต่ในที่นี้ จะช่วยสาธิตวิธีการผสานรวม 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}

การฝึกอบรมรุ่นที่คุณจะเป็นปกติ Model โดยใช้ API ของฟังก์ชั่น

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

การรวม MinDiff เข้ากับโมเดลของคุณโดยตรง

เพิ่ม MinDiff ไป train_step

เพื่อบูรณาการ MinDiff คุณจะต้องเพิ่มบรรทัดบางอย่างเพื่อ CustomModel ซึ่งมีการเปลี่ยนชื่อที่นี่เช่น CustomModelWithMinDiff

เพื่อความชัดเจนคู่มือนี้ใช้เป็นธงบูลีนที่เรียกว่า apply_min_diff ทั้งหมดของรหัสที่เกี่ยวข้องกับ MinDiff จะได้รับการทำงานถ้ามีการตั้งค่า True ถ้าตั้งค่าเป็น False แล้วแบบจะทำตัวเหมือนกับ 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}

การฝึกด้วยโมเดลนี้มีลักษณะเหมือนกันทุกประการกับรุ่นก่อน ยกเว้นชุดข้อมูลที่ใช้

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

การปรับรูปร่างอินพุตของคุณใหม่ (ไม่บังคับ)

เนื่องจากวิธีการนี้ให้การควบคุมอย่างสมบูรณ์ คุณจึงสามารถใช้โอกาสนี้เพื่อเปลี่ยนรูปแบบการป้อนข้อมูลให้อยู่ในรูปแบบที่สะอาดขึ้นเล็กน้อย เมื่อใช้ MinDiffModel ที่ min_diff_data จะต้องมีการบรรจุลงในองค์ประกอบแรกของทุกชุด นี่คือกรณีที่มี train_with_min_diff_ds ชุด

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'>

เมื่อยกเลิกข้อกำหนดนี้ คุณสามารถจัดระเบียบข้อมูลใหม่ในโครงสร้างที่เข้าใจง่ายขึ้นเล็กน้อยโดยแยกข้อมูลดั้งเดิมและข้อมูล MinDiff ออกจากกันอย่างหมดจด

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)

ขั้นตอนนี้เป็นทางเลือกอย่างสมบูรณ์ แต่จะมีประโยชน์ในการจัดระเบียบข้อมูลให้ดีขึ้น ถ้าคุณทำเช่นนั้นที่แตกต่างในวิธีที่คุณใช้ CustomModelWithMinDiff จะเป็นวิธีการที่คุณแกะ data ที่จุดเริ่มต้น

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)

    ...

ด้วยขั้นตอนสุดท้ายนี้ คุณสามารถควบคุมทั้งรูปแบบอินพุตและวิธีการใช้ MinDiff ภายในโมเดลได้อย่างเต็มที่

แหล่งข้อมูลเพิ่มเติม