Skip to content
This repository has been archived by the owner on Dec 16, 2022. It is now read-only.

Bias Mitigation and Direction Methods #5130

Merged
merged 25 commits into from
May 11, 2021
Merged
Changes from 1 commit
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
79c6c33
added linear and hard debiasers
Apr 13, 2021
e23057c
worked on documentation
Apr 14, 2021
fcc3d34
committing changes before branch switch
Apr 14, 2021
7d00910
committing changes before switching branch
Apr 15, 2021
668a513
finished bias direction, linear and hard debiasers, need to write tests
Apr 15, 2021
91029ef
finished bias direction test
Apr 15, 2021
396b245
Commiting changes before switching branch
Apr 16, 2021
a8c22a1
finished hard and linear debiasers
Apr 16, 2021
ef6a062
finished OSCaR
Apr 17, 2021
2c873cb
bias mitigators tests and bias metrics remaining
Apr 17, 2021
d97a526
added bias mitigator tests
Apr 18, 2021
8460281
added bias mitigator tests
Apr 18, 2021
5a76922
finished tests for bias mitigation methods
Apr 19, 2021
85cb107
Merge remote-tracking branch 'origin/main' into arjuns/post-processin…
Apr 19, 2021
8e55f28
fixed gpu issues
Apr 19, 2021
b42b73a
fixed gpu issues
Apr 19, 2021
37d8e33
fixed gpu issues
Apr 20, 2021
31b1d2c
resolve issue with count_nonzero not being differentiable
Apr 20, 2021
a1f4f2a
merged main into post-processing-debiasing
Apr 21, 2021
36cebe3
added more references
Apr 21, 2021
88c083b
Merge branch 'main' of https://github.com/allenai/allennlp into arjun…
Apr 28, 2021
7269c1d
Merge branch 'main' into arjuns/post-processing-debiasing
schmmd May 6, 2021
24ce58f
Merge branch 'main' into arjuns/post-processing-debiasing
AkshitaB May 7, 2021
4495627
responded to Akshita's comments
May 9, 2021
1182b10
Merge branch 'arjuns/post-processing-debiasing' of https://github.com…
May 9, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
finished hard and linear debiasers
  • Loading branch information
Arjun Subramonian authored and Arjun Subramonian committed Apr 16, 2021
commit a8c22a19202857dea27055f56874489008e7e415
110 changes: 94 additions & 16 deletions allennlp/fairness/debiasers.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,27 +37,92 @@ class HardDebiaser(Debiaser):
ArXiv, abs/2104.02797.
"""

def forward(self, embeddings: torch.Tensor, bias_direction: torch.Tensor):
def forward(
self,
evaluation_embeddings: torch.Tensor,
bias_direction: torch.Tensor,
equalize_embeddings1: torch.Tensor,
equalize_embeddings2: torch.Tensor,
):
"""

# Parameters

embeddings : `torch.Tensor`
A tensor of size (batch_size, ..., dim).
evaluation_embeddings : `torch.Tensor`
A tensor of size (evaluation_batch_size, ..., dim) of embeddings to debias.
bias_direction : `torch.Tensor`
A unit tensor of size (dim, ) representing the concept subspace.
A unit tensor of size (dim, ) representing the concept subspace. The words
that are used to define the bias direction are considered definitionally
gendered and not modified.
equalize_embeddings1: `torch.Tensor`
A tensor of size (equalize_batch_size, ..., dim) containing equalize word
embeddings related to a group from the concept represented by bias_direction.
For example, if the concept is gender, equalize_embeddings1 could contain embeddings
for "boy", "man", "dad", "brother", etc.
equalize_embeddings2: `torch.Tensor`
A tensor of size (equalize_batch_size, ..., dim) containing equalize word
embeddings related to a different group for the same concept. For example,
equalize_embeddings2 could contain embeddings for "girl", "woman", "mom",
"sister", etc.

!!! Note
The embeddings at the same positions in each of equalize_embeddings1 and
equalize_embeddings2 are expected to form equalize word pairs. For example, if the concept
is gender, the embeddings for ("boy", "girl"), ("man", "woman"), ("dad", "mom"),
("brother", "sister"), etc. should be at the same positions in equalize_embeddings1
and equalize_embeddings2.

!!! Note
evaluation_embeddings, equalize_embeddings1, and equalize_embeddings2 must have same size
except for 0th dim (i.e. batch dimension).

!!! Note
Please ensure that the words in evaluation_embeddings, equalize_embeddings1, and
equalize_embeddings2 and those used to compute bias_direction are disjoint.

# Returns

debiased_embeddings : `torch.Tensor`
A tensor of the same size as embeddings. debiased_embeddings do not contain a component
in bias_direction.
A tensor of the same size as evaluation_embeddings, equalize_embeddings1, and equalize_embeddings2
(in this order) stacked.
"""

# Some sanity checks
if equalize_embeddings1.size() != equalize_embeddings2.size():
raise ConfigurationError(
"equalize_embeddings1 and equalize_embeddings2 must be the same size."
)
if equalize_embeddings1.ndim < 2:
raise ConfigurationError(
"equalize_embeddings1 and equalize_embeddings2 must have at least two dimensions."
)
if evaluation_embeddings.ndim < 2:
raise ConfigurationError("evaluation_embeddings must have at least two dimensions.")
if evaluation_embeddings.size()[1:] != equalize_embeddings1.size()[1:]:
raise ConfigurationError(
"evaluation_embeddings, equalize_embeddings1, and equalize_embeddings2 must have same size \
except for 0th dim (i.e. batch dimension)."
)
if bias_direction.ndim != 1:
raise ConfigurationError("bias_direction must be one-dimensional.")
if evaluation_embeddings.size(-1) != bias_direction.size(-1):
raise ConfigurationError(
"All embeddings and bias_direction must have the same dimensionality."
)

with torch.set_grad_enabled(self.requires_grad):
return embeddings - torch.matmul(
embeddings, bias_direction.reshape(-1, 1)
) * bias_direction / torch.dot(bias_direction, bias_direction)
debiased_embeddings = self._remove_component(evaluation_embeddings, bias_direction)

mean_equalize_embeddings = (equalize_embeddings1 + equalize_embeddings2) / 2
y = self._remove_component(mean_equalize_embeddings, bias_direction)
z = torch.sqrt(1 - torch.square(torch.linalg.norm(y)))
z[torch.matmul(equalize_embeddings1 - equalize_embeddings2, bias_direction) < 0] *= -1
return torch.cat([debiased_embeddings, z * bias_direction + y, -z * bias_direction + y])

def _remove_component(embeddings: torch.Tensor, bias_direction: torch.Tensor):
return embeddings - torch.matmul(
embeddings, bias_direction.reshape(-1, 1)
) * bias_direction / torch.dot(bias_direction, bias_direction)


class LinearDebiaser(Debiaser):
Expand All @@ -77,24 +142,37 @@ class LinearDebiaser(Debiaser):
Option to enable gradient calculation.
"""

def forward(self, embeddings: torch.Tensor, bias_direction: torch.Tensor):
def forward(self, evaluation_embeddings: torch.Tensor, bias_direction: torch.Tensor):
"""

# Parameters

embeddings : `torch.Tensor`
A tensor of size (batch_size, ..., dim).
evaluation_embeddings : `torch.Tensor`
A tensor of size (batch_size, ..., dim) of embeddings to debias.
bias_direction : `torch.Tensor`
A unit tensor of size (dim, ) representing the concept subspace.

# Returns

debiased_embeddings : `torch.Tensor`
A tensor of the same size as embeddings. debiased_embeddings do not contain a component
in bias_direction.
A tensor of the same size as evaluation_embeddings.
"""
# Some sanity checks
if evaluation_embeddings.ndim < 2:
raise ConfigurationError("evaluation_embeddings must have at least two dimensions.")
if bias_direction.ndim != 1:
raise ConfigurationError("bias_direction must be one-dimensional.")
if evaluation_embeddings.size(-1) != bias_direction.size(-1):
raise ConfigurationError(
"All embeddings and bias_direction must have the same dimensionality."
)

with torch.set_grad_enabled(self.requires_grad):
return (
embeddings
- torch.matmul(embeddings, bias_direction.reshape(-1, 1)) * bias_direction
evaluation_embeddings
- torch.matmul(evaluation_embeddings, bias_direction.reshape(-1, 1))
* bias_direction
)

class Oscar(Debiaser):