# FairGrad: Fairness Aware Gradient Descent
[![Documentation Status](https://readthedocs.org/projects/pip/badge/)](https://fairgrad.readthedocs.io/en/latest/)
[![PyPI version](https://badge.fury.io/py/fairgrad.svg)](https://badge.fury.io/py/fairgrad)
<a href="https://arxiv.org/abs/2206.10923"><img src="http://img.shields.io/badge/Paper-PDF-red.svg"></a>

FairGrad, is an easy to use general purpose approach to enforce fairness for gradient descent based methods. 

# Getting started: 
You can get ```fairgrad``` from pypi, which means it can be easily installed via ```pip```:
```
pip install fairgrad
```

# Documentation
The documenation can be found at [read the docs](https://fairgrad.readthedocs.io/en/latest/index.html)

# Example usage 
To use fairgrad simply replace your pytorch cross entropy loss with fairgrad cross entropy loss. 
Alongside, regular pytorch cross entropy arguments, it expects following extra arguments.

```
y_train (np.asarray[int], Tensor, optional): All train example's corresponding label
s_train (np.asarray[int], Tensor, optional): All train example's corresponding sensitive attribute. This means if there
        are 2 sensitive attributes, with each of them being binary. For instance gender - (male and female) and
        age (above 45, below 45). Total unique sentive attributes are 4.
fairness_measure (string): Currently we support "equal_odds", "equal_opportunity", and "accuracy_parity".
epsilon (float, optional): The slack which is allowed for the final fairness level.
fairness_rate (float, optional): Parameter which intertwines current fairness weights with sum of previous fairness rates.
```

```python
# Note this is short snippet. One still needs to models and iterators.
# Full worked out example is available here - @TODO

from fairgrad.torch import CrossEntropyLoss

# define cross entropy loss 
criterion = CrossEntropyLoss(fairness_related_meta_data=fairness_related_meta_data)

# Train loop

for inputs, labels, protected_attributes in train_iterator:
    model.train()
    optimizer.zero_grad()
    output = model(inputs)
    loss = criterion(output, labels, protected_attributes, mode='train')
    loss.backward()
    optimizer.step()
```

# Citation
```
@article{maheshwari2022fairgrad,
  title={FairGrad: Fairness Aware Gradient Descent},
  author={Maheshwari, Gaurav and Perrot, Micha{\"e}l},
  journal={arXiv preprint arXiv:2206.10923},
  year={2022}
}
```
