Home

Awesome

PiRank: Learning to Rank via Differentiable Sorting

This repository provides a reference implementation for learning PiRank-based models as described in the paper:

PiRank: Learning to Rank via Differentiable Sorting
Robin Swezey, Aditya Grover, Bruno Charron and Stefano Ermon.
Paper: https://arxiv.org/abs/2012.06731

Requirements

The codebase is implemented in Python 3.7. To install the necessary base requirements, run the following commands:

pip install -r requirements.txt

If you intend to use a GPU, modify requirements.txt to install tensorflow-gpu instead of tensorflow.

You will also need the NeuralSort implementation available here. Make sure it is added to your PYTHONPATH.

Datasets

PiRank was tested on the two following datasets:

Additionally, the code is expected to work with any dataset stored in the standard LibSVM format used for LTR experiments.

Scripts

There are two scripts for the code:

Options

Options are handled by Sacred (see Examples section below).

pirank_simple.py and pirank_deep.py

PiRank-related:

ParameterDefault ValueDescription
loss_fnpirank_simple_lossThe loss function to use (either a TFR RankingLossKey, or loss function from the script)
steFalseWhether to use the Straight-Through Estimator
ndcg_k15NDCG@k cutoff when using NS-NDCG loss

NeuralSort-related:

ParameterDefault ValueDescription
tau5Temperature
taustar1e-10Temperature for trues and straight-through estimation.

TensorFlow-Ranking and architecture-related:

ParameterDefault ValueDescription
hidden_layers"256,tanh,128,tanh,64,tanh"Hidden layers for an example-wise feedforward network in the format size,activation,...,size,activation
num_features136Number of features per document. The default value is for MSLR and depends on the dataset (e.g. for Yahoo!, please change to 700).
list_size100List size used for training
group_size1Group size used in score function

Training-related:

ParameterDefault ValueDescription
train_path"/data/MSLR-WEB30K/Fold*/train.txt"Input file path used for training
vali_path"/data/MSLR-WEB30K/Fold*/vali.txt"Input file path used for validation
test_path"/data/MSLR-WEB30K/Fold*/test.txt"Input file path used for testing
model_dirNoneOutput directory for models
num_epochs200Number of epochs to train, set 0 to just test
lr1e-4initial learning rate
batch_size32The batch size for training
num_train_stepsNoneNumber of steps for training
num_vali_stepsNoneNumber of steps for validation
num_test_stepsNoneNumber of steps for testing
learning_rate0.01Learning rate for optimizer
dropout_rate0.5The dropout rate before output layer
optimizerAdagradThe optimizer for gradient descent

Sacred:

In addition, you can use regular parameters from Sacred (such as -m for logging the experiment to MongoDB).

pirank_deep.py only

ParameterDefault ValueDescription
merge_block_sizeNoneBlock size used if merging, None if not merging
top_kNoneUse a different Top-k for merging than final NDCG@k for loss
straight_backpropFalseBackpropagate on scores only through NS operator
full_lossFalseUse the complete loss at the end of merge
tau_schemeNoneWhich scheme to use for temperature going deeper (default: constant)
data_generatorNoneData generator (default: TFR\s libsvm); use this for synthetic generation
num_queries30000Number of queries for synthetic data generator
num_query_features10Number of columns used as factors for each query by synthetic data generator
actual_list_sizeNoneSize of actual list per query in synthetic data generation
train_path"/data/MSLR-WEB30K/Fold*/train.txt"Input file path used for training; alternatively value of seed if using data generator
vali_path"/data/MSLR-WEB30K/Fold*/vali.txt"Input file path used for validation; alternatively value of seed if using data generator
test_path"/data/MSLR-WEB30K/Fold*/test.txt"Input file path used for testing; alternatively value of seed if using data generator
with_opaTrueInclude pairwise metric OPA

Examples

Run the benchmark experiment of section 4.1 with PiRank simple loss on MSLR-WEB30K

cd pirank
python3 pirank_simple.py with loss_fn=pirank_simple_loss \
    ndcg_k=10 \
    tau=5 \
    list_size=80 \
    hidden_layers=256,relu,256,relu,128,relu,64,relu \
    train_path=/data/MSLR-WEB30K/Fold1/train.txt \
    vali_path=/data/MSLR-WEB30K/Fold1/vali.txt \
    test_path=/data/MSLR-WEB30K/Fold1/test.txt \
    num_features=136 \
    optimizer=Adam \
    learning_rate=0.00001 \
    num_epochs=100 \
    batch_size=16 \
    model_dir=/tmp/model

Run the benchmark experiment of section 4.1 with PiRank simple loss on Yahoo! C14

cd pirank
python3 pirank_simple.py with loss_fn=pirank_simple_loss \
    ndcg_k=10 \
    tau=5 \
    list_size=80 \
    hidden_layers=256,relu,256,relu,128,relu,64,relu \
    train_path=/data/YAHOO/set1.train.txt \
    vali_path=/data/YAHOO/set1.valid.txt \
    test_path=/data/YAHOO/set1.test.txt \
    num_features=700 \
    optimizer=Adam \
    learning_rate=0.00001 \
    num_epochs=100 \
    batch_size=16 \
    model_dir=/tmp/model

Run the benchmark experiment of section 4.1 with classic LambdaRank on MSLR-WEB30K

cd pirank
python3 pirank_simple.py with loss_fn=lambda_rank_loss \
    ndcg_k=10 \
    tau=5 \
    list_size=80 \
    hidden_layers=256,relu,256,relu,128,relu,64,relu \
    train_path=/data/MSLR-WEB30K/Fold1/train.txt \
    vali_path=/data/MSLR-WEB30K/Fold1/vali.txt \
    test_path=/data/MSLR-WEB30K/Fold1/test.txt \
    num_features=136 \
    optimizer=Adam \
    learning_rate=0.00001 \
    num_epochs=100 \
    batch_size=16 \
    model_dir=/tmp/model

Run the scaling ablation experiment of section 4.2.3 using synthetic data generation (d=2)

cd pirank
python3 pirank_deep.py with loss_fn=pirank_deep_loss \
    ndcg_k=10 \
    ste=True \
    merge_block_size=100 \
    tau=5 \
    taustar=1e-10 \
    tau_scheme=square \
    data_generator=synthetic_data_generator \
    actual_list_size=1000 \
    list_size=1000 \
    vali_list_size=1000 \
    test_list_size=1000 \
    full_loss=False \
    train_path=0 \
    vali_path=1 \
    test_path=2 \
    num_queries=1000 \
    num_features=25 \
    num_query_features=5 \
    hidden_layers=256,relu,256,relu,128,relu,128,relu,64,relu,64,relu \
    optimizer=Adam \
    learning_rate=0.00001 \
    num_epochs=100 \
    batch_size=16

Help

If you need help, reach out to Robin Swezey or raise an issue.

Citing

If you find PiRank useful in your research, please consider citing the following paper:

@inproceedings{
swezey2020pirank,
title={PiRank: Learning to Rank via Differentiable Sorting},
author={Robin Swezey and Aditya Grover and Bruno Charron and Stefano Ermon},
year={2020},
url={},
}