Tích hợp MinDiff mà không cần MinDiffModel

Giới thiệu

Có thể tích hợp MinDiff trực tiếp vào việc triển khai mô hình của bạn. Trong khi làm như vậy không có sự tiện lợi của việc sử dụng MinDiffModel , tùy chọn này cung cấp mức cao nhất của điều khiển mà có thể đặc biệt hữu ích khi mô hình của bạn là một lớp con của tf.keras.Model .

Hướng dẫn này cho thấy làm thế nào bạn có thể tích hợp MinDiff trực tiếp vào thực hiện mô hình tùy chỉnh bằng cách thêm vào train_step phương pháp.

Thành lập

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

Đầu tiên, tải xuống dữ liệu. Đối với tính cô đọng, logic chuẩn bị đầu vào đã được yếu tố ra thành các hàm helper như mô tả trong hướng dẫn chuẩn bị đầu vào . Bạn có thể đọc hướng dẫn đầy đủ để biết chi tiết về quy trình này.

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

Tùy chỉnh mô hình tùy chỉnh ban đầu

tf.keras.Model được thiết kế để dễ dàng tùy chỉnh thông qua subclassing. Điều này thường liên quan đến việc thay đổi những gì xảy ra trong cuộc gọi để fit như đã mô tả ở đây .

Hướng dẫn này sử dụng một cài đặt tùy chỉnh nơi train_step gần giống với mặc định tf.keras.Model.train_step . Thông thường, sẽ không có lợi gì khi làm như vậy, nhưng ở đây, nó sẽ giúp chứng minh cách tích hợp 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}

Đào tạo các mô hình như bạn sẽ một điển hình Model sử dụng API chức năng.

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

Tích hợp MinDiff trực tiếp vào mô hình của bạn

Thêm MinDiff đến train_step

Thực hiện lồng ghép MinDiff, bạn sẽ cần phải thêm một số dòng cho CustomModel được đổi tên ở đây như CustomModelWithMinDiff .

Để rõ ràng, hướng dẫn này sử dụng một lá cờ boolean gọi apply_min_diff . Tất cả các mã liên quan đến MinDiff sẽ chỉ được chạy nếu nó được thiết lập để True . Nếu thiết lập để False thì mô hình sẽ hành xử giống hệt như 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}

Huấn luyện với mô hình này trông giống hệt như với mô hình trước, ngoại trừ tập dữ liệu được sử dụng.

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

Định hình lại đầu vào của bạn (tùy chọn)

Do cách tiếp cận này cung cấp toàn quyền kiểm soát, bạn có thể tận dụng cơ hội này để định hình lại đầu vào thành một biểu mẫu gọn gàng hơn một chút. Khi sử dụng MinDiffModel , các min_diff_data cần phải được đóng gói vào các thành phần đầu tiên của mỗi đợt. Đây là trường hợp với train_with_min_diff_ds tập dữ liệu.

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

Khi yêu cầu này được dỡ bỏ, bạn có thể sắp xếp lại dữ liệu theo cấu trúc trực quan hơn một chút với dữ liệu gốc và dữ liệu MinDiff được phân tách rõ ràng.

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)

Bước này là hoàn toàn tùy chọn nhưng có thể hữu ích để tổ chức dữ liệu tốt hơn. Nếu bạn làm như vậy, sự khác biệt duy nhất trong cách bạn thực hiện CustomModelWithMinDiff sẽ làm thế nào bạn giải nén data ngay từ đầu.

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)

    ...

Với bước cuối cùng này, bạn có thể kiểm soát hoàn toàn cả định dạng đầu vào và cách nó được sử dụng trong mô hình để áp dụng MinDiff.

Tài nguyên bổ sung