PyTorch Implementation for Deep Metric Learning Pipelines

Overview

Easily Extendable Basic Deep Metric Learning Pipeline

Karsten Roth ([email protected]), Biagio Brattoli ([email protected])

When using this repo in any academic work, please provide a reference to

@misc{roth2020revisiting,
    title={Revisiting Training Strategies and Generalization Performance in Deep Metric Learning},
    author={Karsten Roth and Timo Milbich and Samarth Sinha and Prateek Gupta and Björn Ommer and Joseph Paul Cohen},
    year={2020},
    eprint={2002.08473},
    archivePrefix={arXiv},
    primaryClass={cs.CV}
}

Based on an extendend version of this repo, we have created a thorough comparison and evaluation of Deep Metric Learning:

https://arxiv.org/abs/2002.08473

The newly released code can be found here: https://github.com/Confusezius/Revisiting_Deep_Metric_Learning_PyTorch

It contains more criteria, miner, metrics and logging options!


For usage, go to section 3 - for results to section 4

1. Overview

This repository contains a full, easily extendable pipeline to test and implement current and new deep metric learning methods. For referencing and testing, this repo contains implementations/dataloaders for:

Loss Functions

Sampling Methods

Datasets

Architectures

NOTE: PKU Vehicle-ID is (optional) because there is no direct way to download the dataset, as it requires special licensing. However, if this dataset becomes available (in the structure shown in part 2.2), it can be used directly.


1.1 Related Repos:


2. Repo & Dataset Structure

2.1 Repo Structure

Repository
│   ### General Files
│   README.md
│   requirements.txt    
│   installer.sh
|
|   ### Main Scripts
|   Standard_Training.py     (main training script)
|   losses.py   (collection of loss and sampling impl.)
│   datasets.py (dataloaders for all datasets)
│   
│   ### Utility scripts
|   auxiliaries.py  (set of useful utilities)
|   evaluate.py     (set of evaluation functions)
│   
│   ### Network Scripts
|   netlib.py       (contains impl. for ResNet50)
|   googlenet.py    (contains impl. for GoogLeNet)
│   
│   
└───Training Results (generated during Training)
|    │   e.g. cub200/Training_Run_Name
|    │   e.g. cars196/Training_Run_Name
|
│   
└───Datasets (should be added, if one does not want to set paths)
|    │   cub200
|    │   cars196
|    │   online_products
|    │   in-shop
|    │   vehicle_id

2.2 Dataset Structures

CUB200-2011/CARS196

cub200/cars196
└───images
|    └───001.Black_footed_Albatross
|           │   Black_Footed_Albatross_0001_796111
|           │   ...
|    ...

Online Products

online_products
└───images
|    └───bicycle_final
|           │   111085122871_0.jpg
|    ...
|
└───Info_Files
|    │   bicycle.txt
|    │   ...

In-Shop Clothes

in-shop
└─img
|    └─MEN
|         └─Denim
|               └─id_00000080
|                  │   01_1_front.jpg
|                  │   ...
|               ...
|         ...
|    ...
|
└─Eval
|  │   list_eval_partition.txt

PKU Vehicle ID

vehicle_id
└───image
|     │   <img>.jpg
|     |   ...
|     
└───train_test_split
|     |   test_list_800.txt
|     |   ...

3. Using the Pipeline

[1.] Requirements

The pipeline is build around Python3 (i.e. by installing Miniconda https://conda.io/miniconda.html') and Pytorch 1.0.0/1. It has been tested around cuda 8 and cuda 9.

To install the required libraries, either directly check requirements.txt or create a conda environment:

conda create -n <Env_Name> python=3.6

Activate it

conda activate <Env_Name>

and run

bash installer.sh

Note that for kMeans- and Nearest Neighbour Computation, the library faiss is used, which can allow to move these computations to GPU if speed is desired. However, in most cases, faiss is fast enough s.t. the computation of evaluation metrics is no bottleneck.
NOTE: If one wishes not to use faiss but standard sklearn, simply use auxiliaries_nofaiss.py to replace auxiliaries.py when importing the libraries.

[2.] Exemplary Runs

The main script is Standard_Training.py. If running without input arguments, training of ResNet50 on CUB200-2011 with Marginloss and Distance-sampling is performed.
Otherwise, the following flags suffice to train with different losses, sampling methods, architectures and datasets:

python Standard_Training.py --dataset <dataset> --loss <loss> --sampling <sampling> --arch <arch> --k_vals <k_vals> --embed_dim <embed_dim>

The following flags are available:

  • <dataset> <- cub200, cars196, online_products, in-shop, vehicle_id
  • <loss> <- marginloss, triplet, npair, proxynca
  • <sampling> <- distance, semihard, random, npair
  • <arch> <- resnet50, googlenet
  • <k_vals> <- List of Recall @ k values to evaluate on, e.g. 1 2 4 8
  • <embed_dim> <- Network embedding dimension. Default: 128 for ResNet50, 512 for GoogLeNet.

For all other training-specific arguments (e.g. batch-size, num. training epochs., ...), simply refer to the input arguments in Standard_Training.py.

NOTE: If one wishes to use a different learning rate for the final linear embedding layer, the flag --fc_lr_mul needs to be set to a value other than zero (i.e. 10 as is done in various implementations).

Finally, to decide the GPU to use and the name of the training folder in which network weights, sample recoveries and metrics are stored, set:

python Standard_Training.py --gpu <gpu_id> --savename <name_of_training_run>

If --savename is not set, a default name based on the starting date will be chosen.

If one wishes to simply use standard parameters and wants to get close to literature results (more or less, depends on seeds and overall training scheduling), refer to sample_training_runs.sh, which contains a list of executable one-liners.

[3.] Implementation Notes regarding Extendability:

To extend or test other sampling or loss methods, simply do:

For Batch-based Sampling:
In losses.py, add the sampling method, which should act on a batch (and the resp. set of labels), e.g.:

def new_sampling(self, batch, label, **additional_parameters): ...

This function should, if it needs to run with existing losses, a list of tuples containing indexes with respect to the batch, e.g. for sampling methods returning triplets:

return [(anchor_idx, positive_idx, negative_idx) for anchor_idx, positive_idx, negative_idx in zip(anchor_idxs, positive_idxs, negative_idxs)]

Also, don't forget to add a handle in Sampler.__init__().

For Data-specific Sampling:
To influence the data samples used to generate the batches, in datasets.py edit BaseTripletDataset.

For New Loss Functions:
Simply add a new class inheriting from torch.nn.Module. Refer to other loss variants to see how to do so. In general, include an instance of the Sampler-class, which will provide sampled data tuples during a forward()-pass, by calling self.sampler_instance.give(batch, labels, **additional_parameters).
Finally, include the loss function in the loss_select()-function. Parameters can be passed through the dictionary-notation (see other examples) and if learnable parameters are added, include them in the to_optim-list.

[4.] Stored Data:

By default, the following files are saved:

Name_of_Training_Run
|  checkpoint.pth.tar   -> Contains network state-dict.
|  hypa.pkl             -> Contains all network parameters as pickle.
|                          Can be used directly to recreate the network.
| log_train_Base.csv    -> Logged training data as CSV.                      
| log_val_Base.csv      -> Logged test metrics as CSV.                    
| Parameter_Info.txt    -> All Parameters stored as readable text-file.
| InfoPlot_Base.svg     -> Graphical summary of training/testing metrics progression.
| sample_recoveries.png -> Sample recoveries for best validation weights.
|                          Acts as a sanity test.

Sample Recoveries Note: Red denotes query images, while green show the resp. nearest neighbours.

Sample Recoveries Note: The header in the summary plot shows the best testing metrics over the whole run.

[5.] Additional Notes:

To finalize, several flags might be of interest when examining the respective runs:

--dist_measure: If set, the ratio of mean intraclass-distances over mean interclass distances
                (by measure of center-of-mass distances) is computed after each epoch and stored/plotted.
--grad_measure: If set, the average (absolute) gradients from the embedding layer to the last
                conv. layer are stored in a Pickle-File. This can be used to examine the change of features during each iteration.

For more details, refer to the respective classes in auxiliaries.py.


4. Results

These results are supposed to be performance estimates achieved by running the respective commands in sample_training_runs.sh. Note that the learning rate scheduling might not be fully optimised, so these values should only serve as reference/expectation, not what can be ultimately achieved with more tweaking.

Note also that there is a not insignificant dependency on the used seed.

CUB200

Architecture Loss/Sampling NMI F1 Recall @ 1 -- 2 -- 4 -- 8
ResNet50 Margin/Distance 68.2 38.7 63.4 -- 74.9 -- 86.0 -- 90.4
ResNet50 Triplet/Softhard 66.2 35.5 61.2 -- 73.2 -- 82.4 -- 89.5
ResNet50 NPair/None 65.4 33.8 59.0 -- 71.3 -- 81.1 -- 88.8
ResNet50 ProxyNCA/None 68.1 38.1 64.0 -- 75.4 -- 84.2 -- 90.5

Cars196

Architecture Loss/Sampling NMI F1 Recall @ 1 -- 2 -- 4 -- 8
ResNet50 Margin/Distance 67.2 37.6 79.3 -- 87.1 -- 92.1 -- 95.4
ResNet50 Triplet/Softhard 64.4 32.4 75.4 -- 84.2 -- 90.1 -- 94.1
ResNet50 NPair/None 62.3 30.1 69.5 -- 80.2 -- 87.3 -- 92.1
ResNet50 ProxyNCA/None 66.3 35.8 80.0 -- 87.2 -- 91.8 -- 95.1

Online Products

Architecture Loss/Sampling NMI F1 Recall @ 1 -- 10 -- 100 -- 1000
ResNet50 Margin/Distance 89.6 34.9 76.1 -- 88.7 -- 95.1 -- 98.3
ResNet50 Triplet/Softhard 89.1 33.7 74.3 -- 87.6 -- 94.9 -- 98.5
ResNet50 NPair/None 88.8 31.1 70.9 -- 85.2 -- 93.8 -- 98.2

In-Shop Clothes

Architecture Loss/Sampling NMI F1 Recall @ 1 -- 10 -- 20 -- 30 -- 50
ResNet50 Margin/Distance 88.2 27.7 84.5 -- 96.1 -- 97.4 -- 97.9 -- 98.5
ResNet50 Triplet/Semihard 89.0 30.8 83.9 -- 96.3 -- 97.6 -- 98.4 -- 98.8
ResNet50 NPair/None 88.0 27.6 80.9 -- 95.0 -- 96.6 -- 97.5 -- 98.2

NOTE:

  1. Regarding Vehicle-ID: Due to the number of test sets, size of the training set and little public accessibility, results are not included for the time being.
  2. Regarding ProxyNCA for Online Products and In-Shop Clothes: Due to the high number of classes, the number of proxies required is too high for useful training (>10000 proxies).

ToDO:

  • Fix Version in requirements.txt
  • Add Results for Implementations
  • Finalize Comments
  • Add Inception-BN
  • Add Lifted Structure Loss
Comments
  • How to save and evaluate model after training ?

    How to save and evaluate model after training ?

    I wanted to know how we could save the model weights and use it for inference on some test data ? I tried using torch.save() and torch.load() after all completion of all epochs, but the results are not similar as to automatic eval on test split and quite bad. Could you please provide some inputs on this ?

    opened by dnaveenr 7
  • Question on Proxy-NCA

    Question on Proxy-NCA

    Hi, thanks for the nice code. I noticed that your re-implementation of the Proxy-NCA is much higher than that from their original paper on CUB-200, e.g. R@1= 64.0 vs R@1= 49.

    I understand that the original paper uses Inception, and you train a ResNet50, are the performance boost all from architecture ? Or is there any other implementation differences ?

    opened by WeidiXie 3
  • question about code in

    question about code in "googlenet.py"

    opened by kdwonn 2
  • RuntimeError: CUDA out of memory.

    RuntimeError: CUDA out of memory.

    I cloned the repo, ran the install.sh script and tried running the Standard_Training.py file, but as soon as the network starts training, I get the error

    RuntimeError: CUDA out of memory. Tried to allocate 42.88 MiB (GPU 0; 7.79 GiB total capacity; 6.35 GiB already allocated; 46.38 MiB free; 601.50 KiB cached)

    I am using a 2070 Super GPU with 8 GB of vram. Is this too little to run the baseline, or do you think there is some other problem?

    Thank you in advance

    opened by martinper 2
  • is the file 'pretrainedmodels.py' missing?

    is the file 'pretrainedmodels.py' missing?

    File "Deep-Metric-Learning-Baselines/netlib.py", line 21, in <module> import pretrainedmodels as ptm ModuleNotFoundError: No module named 'pretrainedmodels'

    I run the code then get the problem, Thank you very much for your help.

    opened by zhweiGuo 2
  • Issue when loading In-Shop Clothes Dataset

    Issue when loading In-Shop Clothes Dataset

    Hi, @Confusezius ,

    Thanks for your excellent code and for sharing it!

    When running

    python3.6 Standard_Training.py --gpu 0 --savename resnet_inshop_margin_dist  --dataset in-shop --n_epochs 40 --tau 25 --loss marginloss --sampling distance
    

    the following issue raises and I've put the dataset under Datasets directory and the data is fine.

    Getting pretrained weights...
    Done.
    MARGINLOSS Setup for RESNET50 with DISTANCE sampling on IN-SHOP complete with #weights: 23770304
    Traceback (most recent call last):
      File "Standard_Training.py", line 161, in <module>
        dataloaders      = data.give_dataloaders(opt.dataset, opt)
      File "/home/code/Deep-Metric-Learning-Baselines/datasets.py", line 50, in give_dataloaders
        datasets = give_InShop_datasets(opt)
      File "/home/code/Deep-Metric-Learning-Baselines/datasets.py", line 280, in give_InShop_datasets
        train_dataset     = BaseTripletDataset(train_image_dict, opt,   samples_per_class=opt.samples_per_class)
      File "/home/code/Deep-Metric-Learning-Baselines/datasets.py", line 398, in __init__
        transforms.RandomHorizontalFlip(0.5)])
    TypeError: object() takes no parameters
    

    So, could u shed me some light? Thanks!

    opened by stoneyang 2
  • resizing images to 256x256

    resizing images to 256x256

    https://github.com/Confusezius/Deep-Metric-Learning-Baselines/blob/dbcd5abe2966c3398b893664bba2d61075b628d9/datasets.py#L397

    I believe there's a bug in BaseTripletDataset.transform: during training, images are not resized to 256x256 before taking crops.

    Interestingly, this did not seem to affect results by much, at least when I tested it in Online Products with Margin loss...

    opened by kunhe 2
  • Sampler --> TripletSampler?

    Sampler --> TripletSampler?

    https://github.com/Confusezius/Deep-Metric-Learning-Baselines/blob/6b0b617c02d3303c285eb52495ce5716b57425d8/losses.py#L73

    Minor suggestion: renaming Sampler to TripletSampler (or TupleSampler, etc.), so that it will not be confused with torch.utils.data.Sampler :)

    opened by kunhe 2
  • learning rate for embedding layer (last_linear)

    learning rate for embedding layer (last_linear)

    It seems common practice to multiply the learning rate of the embedding layer by 10x or so in the literature. I do not see that in the code - maybe I missed it?

    opened by kunhe 2
  • If I understand your code correctly...

    If I understand your code correctly...

    Hello sir,

    In the file 'auxiliaries.py', line 391:

    sample_idxs = np.random.choice(np.arange(len(gallery_feature_matrix_all)), n_image_samples)

    If I understand your code correctly, should 'gallery_feature_matrix_all' be 'query_feature_matrix_all'?

    Thanks

    opened by chengchu88 2
  • about the organization of Cars196

    about the organization of Cars196

    hello, I want to reproduce your result on Cars196, but when i download the dataset from the official website, the organization of the dataset doesn't like the one you provide in the readme. Could you please provide a hint or the code of how to handle these data. Thanks :)

    opened by czzerone 1
  • How to make it an inference model?

    How to make it an inference model?

    Hi Author, May I know which part I should look into if I want to make this an inference mode?

    I can modify the code myself. Hope to get some guidance in terms of the part /modules to look into . I'm a bit confused because the whole module is complex.

    Use Case: Input 2 similar / different images, output similarity score or a MATCH/Not MATCH result.

    Regards, Alex

    opened by alextaymx 0
  • Error while training

    Error while training

    Hi there, I'm new in this field and I tried to use my own dataset similar to the CAR dataset structure. I'm running on Windows 10 and I couldn't install faiss , i tried using auxiliaries_nofaiss.py for all the imports, is there any solution to this? the model is able to run for 1 epoch, however, the evaluation part is taking very long time, the report is saying 119 GB, and giving me the error as below:

    Any help from anyone would be appreciated. Thanks a lot.

    GPU:0, dataset:rp2k, arch:resnet50, embed_dim:128, embed_init:default loss:fastap, sampling:None, samples_per_class:0, resize256:False bs:32, lr:1e-05, fc_lr_mul:0, decay:0.0004, gamma:0.3, tau:[20], bnft:False Running with learning rates 1e-05... Epoch (Train) 0: Mean Loss [0.0136]: 100%|█████████████████████████████████████████| 4605/4605 [27:19<00:00, 2.92it/s] Computing Evaluation Metrics...: 100%|█████████████████████████████████████████████| 5585/5585 [07:55<00:00, 13.33it/s] Traceback (most recent call last): File "Standard_Training.py", line 365, in main() File "Standard_Training.py", line 344, in main eval.evaluate(opt.dataset, LOG, save=True, **eval_params) File "C:\Users\user\Documents\DeepMetricLearningBaselines\evaluate.py", line 57, in evaluate ret = evaluate_one_dataset(LOG, **kwargs) File "C:\Users\user\Documents\DeepMetricLearningBaselines\evaluate.py", line 279, in evaluate_one_dataset F1, NMI, recall_at_ks, feature_matrix_all = aux.eval_metrics_one_dataset(model, dataloader, device=opt.device, k_vals=opt.k_vals, opt=opt) File "C:\Users\user\Documents\DeepMetricLearningBaselines\auxiliaries_nofaiss.py", line 239, in eval_metrics_one_dataset k_closest_points = squareform(pdist(feature_coll)).argsort(1)[:, :int(np.max(k_vals)+1)] File "C:\Users\user\anaconda3\envs\kunhe\lib\site-packages\scipy\spatial\distance.py", line 1985, in pdist dm = np.empty((m * (m - 1)) // 2, dtype=np.double) MemoryError: Unable to allocate 119. GiB for an array with shape (15967113051,) and data type float64

    @ Screenshot 2021-01-29 022502

    opened by alextaymx 0
Owner
Karsten Roth
PhD (IMPRS-IS, ELLIS) EML Tuebingen | prev. @VectorInstitute, @mila-iqia and @aws.
Karsten Roth
[ICCV 2021] Official PyTorch implementation for Deep Relational Metric Learning.

Deep Relational Metric Learning This repository is the official PyTorch implementation of Deep Relational Metric Learning. Framework Datasets CUB-200-

Borui Zhang 39 Dec 10, 2022
A Pytorch implementation of "Manifold Matching via Deep Metric Learning for Generative Modeling" (ICCV 2021)

Manifold Matching via Deep Metric Learning for Generative Modeling A Pytorch implementation of "Manifold Matching via Deep Metric Learning for Generat

null 69 Dec 10, 2022
Unofficial implementation of Proxy Anchor Loss for Deep Metric Learning

Proxy Anchor Loss for Deep Metric Learning Unofficial pytorch, tensorflow and mxnet implementations of Proxy Anchor Loss for Deep Metric Learning. Not

Geonmo Gu 3 Jun 9, 2021
Official PyTorch Implementation of Embedding Transfer with Label Relaxation for Improved Metric Learning, CVPR 2021

Embedding Transfer with Label Relaxation for Improved Metric Learning Official PyTorch implementation of CVPR 2021 paper Embedding Transfer with Label

Sungyeon Kim 37 Dec 6, 2022
Dogs classification with Deep Metric Learning using some popular losses

Tsinghua Dogs classification with Deep Metric Learning 1. Introduction Tsinghua Dogs dataset Tsinghua Dogs is a fine-grained classification dataset fo

QuocThangNguyen 45 Nov 9, 2022
Towards Interpretable Deep Metric Learning with Structural Matching

DIML Created by Wenliang Zhao*, Yongming Rao*, Ziyi Wang, Jiwen Lu, Jie Zhou This repository contains PyTorch implementation for paper Towards Interpr

Wenliang Zhao 75 Nov 11, 2022
GeDML is an easy-to-use generalized deep metric learning library

GeDML is an easy-to-use generalized deep metric learning library

Borui Zhang 32 Dec 5, 2022
Near-Duplicate Video Retrieval with Deep Metric Learning

Near-Duplicate Video Retrieval with Deep Metric Learning This repository contains the Tensorflow implementation of the paper Near-Duplicate Video Retr

null 2 Jan 24, 2022
PyTorch implementation of MSBG hearing loss model and MBSTOI intelligibility metric

PyTorch implementation of MSBG hearing loss model and MBSTOI intelligibility metric This repository contains the implementation of MSBG hearing loss m

BUT Speech@fit 9 Nov 8, 2022
A Python Automated Machine Learning tool that optimizes machine learning pipelines using genetic programming.

Master status: Development status: Package information: TPOT stands for Tree-based Pipeline Optimization Tool. Consider TPOT your Data Science Assista

Epistasis Lab at UPenn 8.9k Dec 30, 2022
Metric learning algorithms in Python

metric-learn: Metric Learning in Python metric-learn contains efficient Python implementations of several popular supervised and weakly-supervised met

null 1.3k Dec 28, 2022
Code reproduce for paper "Vehicle Re-identification with Viewpoint-aware Metric Learning"

VANET Code reproduce for paper "Vehicle Re-identification with Viewpoint-aware Metric Learning" Introduction This is the implementation of article VAN

EMDATA-AILAB 23 Dec 26, 2022
Paper: Cross-View Kernel Similarity Metric Learning Using Pairwise Constraints for Person Re-identification

Cross-View Kernel Similarity Metric Learning Using Pairwise Constraints for Person Re-identification T M Feroz Ali, Subhasis Chaudhuri, ICVGIP-20-21

T M Feroz Ali 3 Jun 17, 2022
Negative Sample Matters: A Renaissance of Metric Learning for Temporal Grounding

2D-TAN (Optimized) Introduction This is an optimized re-implementation repository for AAAI'2020 paper: Learning 2D Temporal Localization Networks for

Joya Chen 112 Dec 31, 2022
A machine learning library for spiking neural networks. Supports training with both torch and jax pipelines, and deployment to neuromorphic hardware.

Rockpool Rockpool is a Python package for developing signal processing applications with spiking neural networks. Rockpool allows you to build network

SynSense 21 Dec 14, 2022
PHOTONAI is a high level python API for designing and optimizing machine learning pipelines.

PHOTONAI is a high level python API for designing and optimizing machine learning pipelines. We've created a system in which you can easily select and

Medical Machine Learning Lab - University of Münster 57 Nov 12, 2022
UNION: An Unreferenced Metric for Evaluating Open-ended Story Generation

UNION Automatic Evaluation Metric described in the paper UNION: An UNreferenced MetrIc for Evaluating Open-eNded Story Generation (EMNLP 2020). Please

null 50 Dec 30, 2022
Auto Seg-Loss: Searching Metric Surrogates for Semantic Segmentation

Auto-Seg-Loss By Hao Li, Chenxin Tao, Xizhou Zhu, Xiaogang Wang, Gao Huang, Jifeng Dai This is the official implementation of the ICLR 2021 paper Auto

null 61 Dec 21, 2022