应用反事实逻辑配对 (Counterfactual Logit Pairing, CLP) 来评估和改善模型的公平性需要一个反事实数据集。你可以通过复制现有数据集并修改新数据集以添加、删除或修改身份术语来创建反事实数据集。本教程介绍了为现有文本数据集创建反事实数据集的方法和技巧。
你可以通过创建一个名为 CounterfactualPackedInputs 的新数据对象将反事实数据集与 CLP 技术结合使用,该对象包含 original_input(原始输入)和 counterfactual_data(反事实数据),其结构如下:
CounterfactualPackedInputs 结构如下:
CounterfactualPackedInputs(
original_input=(x, y, sample_weight),
counterfactual_data=(original_x, counterfactual_x,
counterfactual_sample_weight)
)
original_input 应该是用于训练 Keras 模型的原始数据集。counterfactual_data 应为一个 tf.data.Dataset,其中包含原始 x 值、对应的 counterfactual_x 值以及 counterfactual_sample_weight。counterfactual_x 值与原始值几乎相同,但删除或替换了一个或多个属性。该数据集用于配对原始值和反事实值的损失函数,旨在确保当敏感属性发生变化时,模型的预测结果不会改变。original_input 和 counterfactual_data 的形状必须相同。你可以复制 counterfactual_data 中的值,使其元素数量与 original_input 相同。
counterfactual_data 的属性
- 所有
original_x值都需要引用一个身份组 - 每个
counterfactual_x值与原始值相同,但删除或替换了一个或多个属性 - 与原始输入具有相同的形状(你可以通过复制值使其形状一致)
counterfactual_data 不需要:
- 与原始输入中的数据有重叠
- 拥有真值标签 (Ground truth labels)
以下是一个示例,展示了如果你移除“gay”(同性恋)一词,counterfactual_data 会是什么样子。
original_x: “I am a gay man”
counterfactual_x: “I am a man”
counterfactual_sample_weight”: 1
如果你拥有一个文本分类器,可以使用 build_counterfactual_data 来帮助创建反事实数据集。对于所有其他数据类型,你需要直接提供一个反事实数据集。
设置
首先,你需要安装 TensorFlow Model Remediation。
pip install --upgrade tensorflow-model-remediationimport tensorflow as tf
from tensorflow_model_remediation import counterfactual
2024-07-19 09:53:41.340953: E external/local_xla/xla/stream_executor/cuda/cuda_fft.cc:485] Unable to register cuFFT factory: Attempting to register factory for plugin cuFFT when one has already been registered 2024-07-19 09:53:41.361880: E external/local_xla/xla/stream_executor/cuda/cuda_dnn.cc:8454] Unable to register cuDNN factory: Attempting to register factory for plugin cuDNN when one has already been registered 2024-07-19 09:53:41.368395: E external/local_xla/xla/stream_executor/cuda/cuda_blas.cc:1452] Unable to register cuBLAS factory: Attempting to register factory for plugin cuBLAS when one has already been registered
创建一个简单的数据集
为了演示目的,我们将使用 build_counterfactual_dataset 从原始输入创建反事实数据。请注意,你也可以使用未标记的数据构建反事实数据(而不是从原始输入构建)。你将创建一个包含一个句子的简单数据集:“i am a gay man”,它将作为 original_input。
构建反事实数据集
由于这是一个文本分类器,你可以通过两种方式使用 build_counterfactual_data 创建反事实数据集:
- 删除术语:使用
build_counterfactual_data传入一个单词列表,这些单词将通过tf.strings.regex_replace从数据集中删除。 - 替换术语:创建一个自定义函数并传给
build_counterfactual_data。这可能包括使用更具体的正则表达式函数来替换原始数据集中的单词,或者支持非文本特征。
build_counterfactual_dataset 接收 original_input,并根据你传递的可选参数删除或替换术语。在大多数情况下,删除术语(选项 1)足以运行 CLP,但传递自定义函数(选项 2)可以对反事实值进行更精确的控制。
选项 1:要删除的单词列表
传入一个与性别相关的术语列表,以便使用 build_counterfactual_data 进行删除。
当使用简单的正则表达式创建反事实数据集时,请记住这可能会影响到不应该被更改的单词。检查在 orginal_x 值的上下文中对 counterfactual_x 值所做的更改是否有意义,是一种良好的实践。此外,build_counterfactual_dataset 将仅返回包含反事实实例的值。这可能会导致数据集的形状与 orginal_input 不同,但在传递给 pack_counterfactual_data 时会被调整大小。
simple_dataset_x = tf.constant(
["I am a gay man" + str(i) for i in range(10)] +
["I am a man" + str(i) for i in range(10)])
print("Length of starting values: " + str(len(simple_dataset_x)))
simple_dataset = tf.data.Dataset.from_tensor_slices(
(simple_dataset_x, None, None))
counterfactual_data = counterfactual.keras.utils.build_counterfactual_data(
original_input=simple_dataset,
sensitive_terms_to_remove=['gay'])
# Inspect the content of the TF Counterfactual Dataset
for original_value, counterfactual_value, _ in counterfactual_data.take(1):
print("original: ", original_value)
print("counterfactual: ", counterfactual_value)
print("Length of dataset after build_counterfactual_data: " +
str(len(list(counterfactual_data))))
Length of starting values: 20 original: tf.Tensor(b'I am a gay man0', shape=(), dtype=string) counterfactual: tf.Tensor(b'I am a man0', shape=(), dtype=string) Length of dataset after build_counterfactual_data: 10 WARNING: All log messages before absl::InitializeLog() is called are written to STDERR I0000 00:00:1721382824.212840 23039 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355 I0000 00:00:1721382824.216631 23039 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355 I0000 00:00:1721382824.220305 23039 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355 I0000 00:00:1721382824.225695 23039 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355 I0000 00:00:1721382824.237536 23039 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355 I0000 00:00:1721382824.240949 23039 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355 I0000 00:00:1721382824.244491 23039 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355 I0000 00:00:1721382824.247862 23039 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355 I0000 00:00:1721382824.251348 23039 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355 I0000 00:00:1721382824.254836 23039 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355 I0000 00:00:1721382824.258211 23039 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355 I0000 00:00:1721382824.261555 23039 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355 I0000 00:00:1721382825.510650 23039 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355 I0000 00:00:1721382825.512802 23039 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355 I0000 00:00:1721382825.514940 23039 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355 I0000 00:00:1721382825.517172 23039 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355 I0000 00:00:1721382825.519339 23039 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355 I0000 00:00:1721382825.521281 23039 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355 I0000 00:00:1721382825.523290 23039 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355 I0000 00:00:1721382825.525275 23039 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355 I0000 00:00:1721382825.527328 23039 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355 I0000 00:00:1721382825.529283 23039 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355 I0000 00:00:1721382825.531324 23039 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355 I0000 00:00:1721382825.533303 23039 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355 I0000 00:00:1721382825.572780 23039 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355 I0000 00:00:1721382825.574793 23039 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355 I0000 00:00:1721382825.576887 23039 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355 I0000 00:00:1721382825.578906 23039 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355 I0000 00:00:1721382825.581059 23039 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355 I0000 00:00:1721382825.582998 23039 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355 I0000 00:00:1721382825.584991 23039 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355 I0000 00:00:1721382825.586968 23039 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355 I0000 00:00:1721382825.588999 23039 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355 I0000 00:00:1721382825.591422 23039 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355 I0000 00:00:1721382825.593838 23039 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355 I0000 00:00:1721382825.596178 23039 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
选项 2:自定义函数
为了在修改原始数据集的方式上获得更大的灵活性,你可以改为将自定义函数传递给 build_counterfactual_data。
在该示例中,你可以考虑将引用男性的身份术语替换为引用女性的术语。这可以通过编写一个替换单词字典的函数来实现。
请注意,对自定义函数的唯一限制是它必须是一个可调用对象,以接收并返回 Model.fit 所使用格式的元组,并且应删除不包含任何更改的值(可以通过将术语传递给 sensitive_terms_to_remove 来完成)。
words_to_replace = {"man": "woman"}
print("Length of starting values: " + str(len(simple_dataset_x)))
def replace_words(original_batch):
original_x, _, original_sample_weight = (
tf.keras.utils.unpack_x_y_sample_weight(original_batch))
for word in words_to_replace:
counterfactual_x = tf.strings.regex_replace(
original_x, f'{word}', words_to_replace[word])
return tf.keras.utils.pack_x_y_sample_weight(
original_x, counterfactual_x, sample_weight=original_sample_weight)
counterfactual_data = counterfactual.keras.utils.build_counterfactual_data(
original_input=simple_dataset,
sensitive_terms_to_remove=['gay'],
custom_counterfactual_function=replace_words)
# Inspect the content of the TF Counterfactual Dataset
for original_value, counterfactual_value in counterfactual_data.take(1):
print("original: ", original_value)
print("counterfactual: ", counterfactual_value)
print("Length of dataset after build_counterfactual_data: " +
str(len(list(counterfactual_data))))
Length of starting values: 20 original: tf.Tensor(b'I am a gay man0', shape=(), dtype=string) counterfactual: tf.Tensor(b'I am a gay man0', shape=(), dtype=string) Length of dataset after build_counterfactual_data: 10
要了解更多信息,请参阅 build_counterfactual_data 的 API 文档。
在 TensorFlow.org 上查看
在 Google Colab 中运行
在 GitHub 上查看源码
下载笔记本