دمج MinDiff بدون MinDiffModel

مقدمة

من الممكن دمج MinDiff مباشرة في تنفيذ النموذج الخاص بك. عند القيام بذلك لا يكون للراحة من استخدام MinDiffModel هذا الخيار، ويقدم أعلى مستوى من الرقابة التي يمكن أن تكون مفيدة بشكل خاص عند النموذج الخاص بك هو فئة فرعية من 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 تم تصميمه ليتم تخصيصها بسهولة عبر شاء subclasses ترث. هذا وعادة ما ينطوي تغيير ما يحدث في استدعاء 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.

مصادر إضافية