[
  {
    "path": ".flake8",
    "content": "[flake8]\nignore = F401, F841, E402, E722, E999\nmax-line-length = 128\nmax-complexity=18\nformat=pylint\nshow_source = True\nstatistics = True\ncount = True\nexclude = tests,ret_benchmark/modeling/backbone"
  },
  {
    "path": ".gitignore",
    "content": "resource\nbuild\n*.pyc\n*.zip\n*/__pycache__\n__pycache__\n\n# Package Files #\n*.pkl\n*.log\n*.jar\n*.war\n*.nar\n*.ear\n*.zip\n*.tar.gz\n*.rar\n*.egg-info\n\n#some local files\n*/.settings/\n*/.DS_Store\n.DS_Store\n*/.idea/\n.idea/\ngradlew\ngradlew.bat\nunused.txt\noutput/\n*.egg-info/"
  },
  {
    "path": "LICENSE",
    "content": "Creative Commons Attribution-NonCommercial 4.0 International (CC-BY-NC-4.0)\nPublic License\n\nFor Multi-Similarity Loss for Deep Metric Learning (MS-Loss)\n\nCopyright (c) 2014-present, Malong Technologies Co., Ltd. All rights reserved.\n\n\nBy exercising the Licensed Rights (defined below), You accept and agree\nto be bound by the terms and conditions of this Creative Commons\nAttribution-NonCommercial 4.0 International Public License (\"Public\nLicense\"). To the extent this Public License may be interpreted as a\ncontract, You are granted the Licensed Rights in consideration of Your\nacceptance of these terms and conditions, and the Licensor grants You\nsuch rights in consideration of benefits the Licensor receives from\nmaking the Licensed Material available under these terms and\nconditions.\n\n\nSection 1 -- Definitions.\n\n  a. Adapted Material means material subject to Copyright and Similar\n     Rights that is derived from or based upon the Licensed Material\n     and in which the Licensed Material is translated, altered,\n     arranged, transformed, or otherwise modified in a manner requiring\n     permission under the Copyright and Similar Rights held by the\n     Licensor. For purposes of this Public License, where the Licensed\n     Material is a musical work, performance, or sound recording,\n     Adapted Material is always produced where the Licensed Material is\n     synched in timed relation with a moving image.\n\n  b. Adapter's License means the license You apply to Your Copyright\n     and Similar Rights in Your contributions to Adapted Material in\n     accordance with the terms and conditions of this Public License.\n\n  c. Copyright and Similar Rights means copyright and/or similar rights\n     closely related to copyright including, without limitation,\n     performance, broadcast, sound recording, and Sui Generis Database\n     Rights, without regard to how the rights are labeled or\n     categorized. For purposes of this Public License, the rights\n     specified in Section 2(b)(1)-(2) are not Copyright and Similar\n     Rights.\n  d. Effective Technological Measures means those measures that, in the\n     absence of proper authority, may not be circumvented under laws\n     fulfilling obligations under Article 11 of the WIPO Copyright\n     Treaty adopted on December 20, 1996, and/or similar international\n     agreements.\n\n  e. Exceptions and Limitations means fair use, fair dealing, and/or\n     any other exception or limitation to Copyright and Similar Rights\n     that applies to Your use of the Licensed Material.\n\n  f. Licensed Material means the artistic or literary work, database,\n     or other material to which the Licensor applied this Public\n     License.\n\n  g. Licensed Rights means the rights granted to You subject to the\n     terms and conditions of this Public License, which are limited to\n     all Copyright and Similar Rights that apply to Your use of the\n     Licensed Material and that the Licensor has authority to license.\n\n  h. Licensor means the individual(s) or entity(ies) granting rights\n     under this Public License.\n\n  i. NonCommercial means not primarily intended for or directed towards\n     commercial advantage or monetary compensation. For purposes of\n     this Public License, the exchange of the Licensed Material for\n     other material subject to Copyright and Similar Rights by digital\n     file-sharing or similar means is NonCommercial provided there is\n     no payment of monetary compensation in connection with the\n     exchange.\n\n  j. Share means to provide material to the public by any means or\n     process that requires permission under the Licensed Rights, such\n     as reproduction, public display, public performance, distribution,\n     dissemination, communication, or importation, and to make material\n     available to the public including in ways that members of the\n     public may access the material from a place and at a time\n     individually chosen by them.\n\n  k. Sui Generis Database Rights means rights other than copyright\n     resulting from Directive 96/9/EC of the European Parliament and of\n     the Council of 11 March 1996 on the legal protection of databases,\n     as amended and/or succeeded, as well as other essentially\n     equivalent rights anywhere in the world.\n\n  l. You means the individual or entity exercising the Licensed Rights\n     under this Public License. Your has a corresponding meaning.\n\n\nSection 2 -- Scope.\n\n  a. License grant.\n\n       1. Subject to the terms and conditions of this Public License,\n          the Licensor hereby grants You a worldwide, royalty-free,\n          non-sublicensable, non-exclusive, irrevocable license to\n          exercise the Licensed Rights in the Licensed Material to:\n\n            a. reproduce and Share the Licensed Material, in whole or\n               in part, for NonCommercial purposes only; and\n\n            b. produce, reproduce, and Share Adapted Material for\n               NonCommercial purposes only.\n\n       2. Exceptions and Limitations. For the avoidance of doubt, where\n          Exceptions and Limitations apply to Your use, this Public\n          License does not apply, and You do not need to comply with\n          its terms and conditions.\n\n       3. Term. The term of this Public License is specified in Section\n          6(a).\n\n       4. Media and formats; technical modifications allowed. The\n          Licensor authorizes You to exercise the Licensed Rights in\n          all media and formats whether now known or hereafter created,\n          and to make technical modifications necessary to do so. The\n          Licensor waives and/or agrees not to assert any right or\n          authority to forbid You from making technical modifications\n          necessary to exercise the Licensed Rights, including\n          technical modifications necessary to circumvent Effective\n          Technological Measures. For purposes of this Public License,\n          simply making modifications authorized by this Section 2(a)\n          (4) never produces Adapted Material.\n\n       5. Downstream recipients.\n\n            a. Offer from the Licensor -- Licensed Material. Every\n               recipient of the Licensed Material automatically\n               receives an offer from the Licensor to exercise the\n               Licensed Rights under the terms and conditions of this\n               Public License.\n\n            b. No downstream restrictions. You may not offer or impose\n               any additional or different terms or conditions on, or\n               apply any Effective Technological Measures to, the\n               Licensed Material if doing so restricts exercise of the\n               Licensed Rights by any recipient of the Licensed\n               Material.\n\n       6. No endorsement. Nothing in this Public License constitutes or\n          may be construed as permission to assert or imply that You\n          are, or that Your use of the Licensed Material is, connected\n          with, or sponsored, endorsed, or granted official status by,\n          the Licensor or others designated to receive attribution as\n          provided in Section 3(a)(1)(A)(i).\n\n  b. Other rights.\n\n       1. Moral rights, such as the right of integrity, are not\n          licensed under this Public License, nor are publicity,\n          privacy, and/or other similar personality rights; however, to\n          the extent possible, the Licensor waives and/or agrees not to\n          assert any such rights held by the Licensor to the limited\n          extent necessary to allow You to exercise the Licensed\n          Rights, but not otherwise.\n\n       2. Patent and trademark rights are not licensed under this\n          Public License.\n\n       3. To the extent possible, the Licensor waives any right to\n          collect royalties from You for the exercise of the Licensed\n          Rights, whether directly or through a collecting society\n          under any voluntary or waivable statutory or compulsory\n          licensing scheme. In all other cases the Licensor expressly\n          reserves any right to collect such royalties, including when\n          the Licensed Material is used other than for NonCommercial\n          purposes.\n\n\nSection 3 -- License Conditions.\n\nYour exercise of the Licensed Rights is expressly made subject to the\nfollowing conditions.\n\n  a. Attribution.\n\n       1. If You Share the Licensed Material (including in modified\n          form), You must:\n\n            a. retain the following if it is supplied by the Licensor\n               with the Licensed Material:\n\n                 i. identification of the creator(s) of the Licensed\n                    Material and any others designated to receive\n                    attribution, in any reasonable manner requested by\n                    the Licensor (including by pseudonym if\n                    designated);\n\n                ii. a copyright notice;\n\n               iii. a notice that refers to this Public License;\n\n                iv. a notice that refers to the disclaimer of\n                    warranties;\n\n                 v. a URI or hyperlink to the Licensed Material to the\n                    extent reasonably practicable;\n\n            b. indicate if You modified the Licensed Material and\n               retain an indication of any previous modifications; and\n\n            c. indicate the Licensed Material is licensed under this\n               Public License, and include the text of, or the URI or\n               hyperlink to, this Public License.\n\n       2. You may satisfy the conditions in Section 3(a)(1) in any\n          reasonable manner based on the medium, means, and context in\n          which You Share the Licensed Material. For example, it may be\n          reasonable to satisfy the conditions by providing a URI or\n          hyperlink to a resource that includes the required\n          information.\n\n       3. If requested by the Licensor, You must remove any of the\n          information required by Section 3(a)(1)(A) to the extent\n          reasonably practicable.\n\n       4. If You Share Adapted Material You produce, the Adapter's\n          License You apply must not prevent recipients of the Adapted\n          Material from complying with this Public License.\n\n\nSection 4 -- Sui Generis Database Rights.\n\nWhere the Licensed Rights include Sui Generis Database Rights that\napply to Your use of the Licensed Material:\n\n  a. for the avoidance of doubt, Section 2(a)(1) grants You the right\n     to extract, reuse, reproduce, and Share all or a substantial\n     portion of the contents of the database for NonCommercial purposes\n     only;\n\n  b. if You include all or a substantial portion of the database\n     contents in a database in which You have Sui Generis Database\n     Rights, then the database in which You have Sui Generis Database\n     Rights (but not its individual contents) is Adapted Material; and\n\n  c. You must comply with the conditions in Section 3(a) if You Share\n     all or a substantial portion of the contents of the database.\n\nFor the avoidance of doubt, this Section 4 supplements and does not\nreplace Your obligations under this Public License where the Licensed\nRights include other Copyright and Similar Rights.\n\n\nSection 5 -- Disclaimer of Warranties and Limitation of Liability.\n\n  a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE\n     EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS\n     AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF\n     ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,\n     IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,\n     WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR\n     PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,\n     ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT\n     KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT\n     ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.\n\n  b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE\n     TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,\n     NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,\n     INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,\n     COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR\n     USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN\n     ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR\n     DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR\n     IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.\n\n  c. The disclaimer of warranties and limitation of liability provided\n     above shall be interpreted in a manner that, to the extent\n     possible, most closely approximates an absolute disclaimer and\n     waiver of all liability.\n\n\nSection 6 -- Term and Termination.\n\n  a. This Public License applies for the term of the Copyright and\n     Similar Rights licensed here. However, if You fail to comply with\n     this Public License, then Your rights under this Public License\n     terminate automatically.\n\n  b. Where Your right to use the Licensed Material has terminated under\n     Section 6(a), it reinstates:\n\n       1. automatically as of the date the violation is cured, provided\n          it is cured within 30 days of Your discovery of the\n          violation; or\n\n       2. upon express reinstatement by the Licensor.\n\n     For the avoidance of doubt, this Section 6(b) does not affect any\n     right the Licensor may have to seek remedies for Your violations\n     of this Public License.\n\n  c. For the avoidance of doubt, the Licensor may also offer the\n     Licensed Material under separate terms or conditions or stop\n     distributing the Licensed Material at any time; however, doing so\n     will not terminate this Public License.\n\n  d. Sections 1, 5, 6, 7, and 8 survive termination of this Public\n     License.\n\n\nSection 7 -- Other Terms and Conditions.\n\n  a. The Licensor shall not be bound by any additional or different\n     terms or conditions communicated by You unless expressly agreed.\n\n  b. Any arrangements, understandings, or agreements regarding the\n     Licensed Material not stated herein are separate from and\n     independent of the terms and conditions of this Public License.\n\n\nSection 8 -- Interpretation.\n\n  a. For the avoidance of doubt, this Public License does not, and\n     shall not be interpreted to, reduce, limit, restrict, or impose\n     conditions on any use of the Licensed Material that could lawfully\n     be made without permission under this Public License.\n\n  b. To the extent possible, if any provision of this Public License is\n     deemed unenforceable, it shall be automatically reformed to the\n     minimum extent necessary to make it enforceable. If the provision\n     cannot be reformed, it shall be severed from this Public License\n     without affecting the enforceability of the remaining terms and\n     conditions.\n\n  c. No term or condition of this Public License will be waived and no\n     failure to comply consented to unless expressly agreed to by the\n     Licensor.\n\n  d. Nothing in this Public License constitutes or may be interpreted\n     as a limitation upon, or waiver of, any privileges and immunities\n     that apply to the Licensor or You, including from the legal\n     processes of any jurisdiction or authority."
  },
  {
    "path": "README.md",
    "content": "[![License: CC BY-NC 4.0](https://licensebuttons.net/l/by-nc/4.0/80x15.png)](https://creativecommons.org/licenses/by-nc/4.0/)\n\n\n# Multi-Similarity Loss for Deep Metric Learning (MS-Loss)\n\nCode for the CVPR 2019 paper [Multi-Similarity Loss with General Pair Weighting for Deep Metric Learning](http://openaccess.thecvf.com/content_CVPR_2019/papers/Wang_Multi-Similarity_Loss_With_General_Pair_Weighting_for_Deep_Metric_Learning_CVPR_2019_paper.pdf)\n\n<img src=\"misc/ms_loss.png\" width=\"65%\" height=\"65%\"> \n\n### Performance compared with SOTA methods on CUB-200-2011\n\n|Rank@K | 1 | 2 | 4 | 8 | 16 | 32 |\n |:---  |:-:|:-:|:-:|:-:|:-: |:-: |\n|Clustering<sup>64</sup> | 48.2 | 61.4 | 71.8 | 81.9 | - | - |\n|ProxyNCA<sup>64</sup> | 49.2 | 61.9 | 67.9 | 72.4 | - | - |\n|Smart Mining<sup>64</sup> | 49.8 | 62.3 | 74.1 | 83.3 | - |\n|Our MS-Loss<sup>64</sup>| **57.4** |**69.8** |**80.0** |**87.8** |93.2 |96.4|\n|HTL<sup>512</sup> | 57.1| 68.8| 78.7| 86.5| 92.5| 95.5 | \n|ABIER<sup>512</sup> |57.5 |68.7 |78.3 |86.2 |91.9 |95.5 |\n|Our MS-Loss<sup>512</sup>|**65.7** |**77.0** |**86.3**|**91.2** |**95.0** |**97.3**| \n\n\n### Prepare the data and the pretrained model \n\nThe following script will prepare the [CUB](http://www.vision.caltech.edu.s3-us-west-2.amazonaws.com/visipedia-data/CUB-200-2011/CUB_200_2011.tgz) dataset for training by downloading to the ./resource/datasets/ folder; which will then build the data list (train.txt test.txt):\n\n```bash\n./scripts/prepare_cub.sh\n```\n\nDownload the imagenet pretrained model of \n[bninception](http://data.lip6.fr/cadene/pretrainedmodels/bn_inception-52deb4733.pth) and put it in the folder:  ~/.torch/models/.\n\n\n### Installation\n\n```bash\npip install -r requirements.txt\npython setup.py develop build\n```\n###  Train and Test on CUB200-2011 with MS-Loss\n\n```bash\n./scripts/run_cub.sh\n```\nTrained models will be saved in the ./output/ folder if using the default config.\n\nBest recall@1 higher than 66 (65.7 in the paper).\n\n### Contact\n\nFor any questions, please feel free to reach \n```\ngithub@malongtech.com\n```\n\n### Citation\n\nIf you use this method or this code in your research, please cite as:\n\n    @inproceedings{wang2019multi,\n    title={Multi-Similarity Loss with General Pair Weighting for Deep Metric Learning},\n    author={Wang, Xun and Han, Xintong and Huang, Weilin and Dong, Dengke and Scott, Matthew R},\n    booktitle={Proceedings of the IEEE Conference on Computer Vision and Pattern Recognition},\n    pages={5022--5030},\n    year={2019}\n    }\n\n## License\n\nMS-Loss is CC-BY-NC 4.0 licensed, as found in the [LICENSE](LICENSE) file. It is released for academic research / non-commercial use only. If you wish to use for commercial purposes, please contact sales@malongtech.com.\n\n"
  },
  {
    "path": "ThirdPartyNotices.txt",
    "content": "THIRD PARTY SOFTWARE NOTICES AND INFORMATION\n\nDo Not Translate or Localize\n\nThis software incorporates material from the following third parties. \n\n_____\n\nCadene/pretrained-models.pytorch\n\nBSD 3-Clause License\n\nCopyright (c) 2017, Remi Cadene\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n_____\n\nfacebookresearch/maskrcnn-benchmark\n\nMIT License\n\nCopyright (c) 2018 Facebook\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE."
  },
  {
    "path": "configs/example.yaml",
    "content": "# Copyright (c) Malong Technologies Co., Ltd.\n# All rights reserved.\n#\n# Contact: github@malong.com\n#\n# This source code is licensed under the LICENSE file in the root directory of this source tree.\n\nMODEL:\n  BACKBONE:\n    NAME: bninception\n\nSOLVER:\n  MAX_ITERS: 3000\n  STEPS: [1200, 2400]\n  OPTIMIZER_NAME: Adam\n  BASE_LR: 0.00003\n  WARMUP_ITERS: 0\n  WEIGHT_DECAY: 0.0005\n  \nDATA:\n  TRAIN_IMG_SOURCE: resource/datasets/CUB_200_2011/train.txt\n  TEST_IMG_SOURCE: resource/datasets/CUB_200_2011/test.txt\n  TRAIN_BATCHSIZE: 80\n  TEST_BATCHSIZE: 256\n  NUM_WORKERS: 8\n  NUM_INSTANCES: 5\n\nVALIDATION:\n  VERBOSE: 200"
  },
  {
    "path": "configs/example_margin.yaml",
    "content": "# Copyright (c) Malong Technologies Co., Ltd.\n# All rights reserved.\n#\n# Contact: github@malong.com\n#\n# This source code is licensed under the LICENSE file in the root directory of this source tree.\n\nMODEL:\n  BACKBONE:\n    NAME: bninception\n\nLOSSES:\n  NAME: margin_loss\n  MARGIN_LOSS:\n    N_CLASSES: 100\n    BETA_CONSTANT: False # if False (i.e. class specific beta) train.txt should have labels 0 .... N_CLASSES -1\n\nSOLVER:\n  MAX_ITERS: 3000\n  STEPS: [1200, 2400]\n  OPTIMIZER_NAME: Adam\n  BASE_LR: 0.00003\n  WARMUP_ITERS: 0\n  WEIGHT_DECAY: 0.0005\n  \nDATA:\n  TRAIN_IMG_SOURCE: resource/datasets/CUB_200_2011/train.txt\n  TEST_IMG_SOURCE:  resource/datasets/CUB_200_2011/test.txt\n  TRAIN_BATCHSIZE: 120\n  TEST_BATCHSIZE: 256\n  NUM_WORKERS: 8\n  NUM_INSTANCES: 5\n\nVALIDATION:\n  VERBOSE: 200\n\nSAVE_DIR: output_margin\n\n"
  },
  {
    "path": "configs/example_resnet50.yaml",
    "content": "# Copyright (c) Malong Technologies Co., Ltd.\n# All rights reserved.\n#\n# Contact: github@malong.com\n#\n# This source code is licensed under the LICENSE file in the root directory of this source tree.\n\nMODEL:\n  BACKBONE:\n    NAME: resnet50\n\nINPUT:\n   MODE: 'RGB'\n   PIXEL_MEAN: [0.485, 0.456, 0.406]\n   PIXEL_STD: [0.229, 0.224, 0.225]\n\nSOLVER:\n  MAX_ITERS: 3000\n  STEPS: [1200, 2400]\n  OPTIMIZER_NAME: Adam\n  BASE_LR: 0.00003\n  WARMUP_ITERS: 0\n  WEIGHT_DECAY: 0.0005\n  \nDATA:\n  TRAIN_IMG_SOURCE: resource/datasets/CUB_200_2011/train.txt\n  TEST_IMG_SOURCE: resource/datasets/CUB_200_2011/test.txt\n  TRAIN_BATCHSIZE: 80\n  TEST_BATCHSIZE: 256\n  NUM_WORKERS: 8\n  NUM_INSTANCES: 5\n\nVALIDATION:\n  VERBOSE: 200\n"
  },
  {
    "path": "requirements.txt",
    "content": "torch==1.1.0\nnumpy==1.15.4\nyacs==0.1.4\nsetuptools==40.6.2\npytest==4.4.0\nPillow==8.3.2\ntorchvision==0.3.0\n"
  },
  {
    "path": "ret_benchmark/config/__init__.py",
    "content": "# Copyright (c) Malong Technologies Co., Ltd.\n# All rights reserved.\n#\n# Contact: github@malong.com\n#\n# This source code is licensed under the LICENSE file in the root directory of this source tree.\n\nfrom .defaults import _C as cfg\n"
  },
  {
    "path": "ret_benchmark/config/defaults.py",
    "content": "# Copyright (c) Malong Technologies Co., Ltd.\n# All rights reserved.\n#\n# Contact: github@malong.com\n#\n# This source code is licensed under the LICENSE file in the root directory of this source tree.\n\nfrom yacs.config import CfgNode as CN\nfrom .model_path import MODEL_PATH\n\n# -----------------------------------------------------------------------------\n# Config definition\n# -----------------------------------------------------------------------------\n\n_C = CN()\n\n_C.MODEL = CN()\n_C.MODEL.DEVICE = \"cuda\"\n\n_C.MODEL.BACKBONE = CN()\n_C.MODEL.BACKBONE.NAME = \"bninception\"\n\n_C.MODEL.PRETRAIN = 'imagenet'\n_C.MODEL.PRETRIANED_PATH = MODEL_PATH\n\n_C.MODEL.HEAD = CN()\n_C.MODEL.HEAD.NAME = \"linear_norm\"\n_C.MODEL.HEAD.DIM = 512\n\n_C.MODEL.WEIGHT = \"\"\n\n# Checkpoint save dir\n_C.SAVE_DIR = 'output'\n\n# Loss\n_C.LOSSES = CN()\n_C.LOSSES.NAME = 'ms_loss'\n\n# ms loss\n_C.LOSSES.MULTI_SIMILARITY_LOSS = CN()\n_C.LOSSES.MULTI_SIMILARITY_LOSS.SCALE_POS = 2.0\n_C.LOSSES.MULTI_SIMILARITY_LOSS.SCALE_NEG = 40.0\n_C.LOSSES.MULTI_SIMILARITY_LOSS.HARD_MINING = True\n\n# margin loss\n_C.LOSSES.MARGIN_LOSS = CN()    \n_C.LOSSES.MARGIN_LOSS.BETA_CONSTANT = False\n_C.LOSSES.MARGIN_LOSS.N_CLASSES = 100\n_C.LOSSES.MARGIN_LOSS.BETA_CONSTANT = False\n_C.LOSSES.MARGIN_LOSS.CUTOFF = 0.5\n_C.LOSSES.MARGIN_LOSS.UPPER_CUTOFF = 1.4\n\n# Data option\n_C.DATA = CN()\n_C.DATA.TRAIN_IMG_SOURCE = 'resource/datasets/CUB_200_2011/train.txt'\n_C.DATA.TEST_IMG_SOURCE = 'resource/datasets/CUB_200_2011/test.txt'\n_C.DATA.TRAIN_BATCHSIZE = 70\n_C.DATA.TEST_BATCHSIZE = 256\n_C.DATA.NUM_WORKERS = 8\n_C.DATA.NUM_INSTANCES = 5\n\n# Input option\n_C.INPUT = CN()\n\n# INPUT CONFIG\n_C.INPUT.MODE = 'BGR'\n_C.INPUT.PIXEL_MEAN = [104. / 255, 117. / 255, 128. / 255]\n_C.INPUT.PIXEL_STD = 3 * [1. / 255]\n\n_C.INPUT.FLIP_PROB = 0.5\n_C.INPUT.ORIGIN_SIZE = 256\n_C.INPUT.CROP_SCALE = [0.16, 1]\n_C.INPUT.CROP_SIZE = 227\n\n# SOLVER\n_C.SOLVER = CN()\n_C.SOLVER.IS_FINETURN = False\n_C.SOLVER.FINETURN_MODE_PATH = ''\n_C.SOLVER.MAX_ITERS = 4000\n_C.SOLVER.STEPS = [1000, 2000, 3000]\n_C.SOLVER.OPTIMIZER_NAME = 'SGD'\n_C.SOLVER.BASE_LR = 0.01\n_C.SOLVER.BIAS_LR_FACTOR = 1\n_C.SOLVER.WEIGHT_DECAY = 0.0005\n_C.SOLVER.WEIGHT_DECAY_BIAS = 0.0005\n_C.SOLVER.MOMENTUM = 0.9\n_C.SOLVER.GAMMA = 0.1\n_C.SOLVER.WARMUP_FACTOR = 0.01\n_C.SOLVER.WARMUP_ITERS = 200\n_C.SOLVER.WARMUP_METHOD = 'linear'\n_C.SOLVER.CHECKPOINT_PERIOD = 200\n_C.SOLVER.RNG_SEED = 1\n\n# Logger\n_C.LOGGER = CN()\n_C.LOGGER.LEVEL = 20\n_C.LOGGER.STREAM = 'stdout'\n\n# Validation\n_C.VALIDATION = CN()\n_C.VALIDATION.VERBOSE = 200\n_C.VALIDATION.IS_VALIDATION = True\n"
  },
  {
    "path": "ret_benchmark/config/model_path.py",
    "content": "# Copyright (c) Malong Technologies Co., Ltd.\n# All rights reserved.\n#\n# Contact: github@malong.com\n#\n# This source code is licensed under the LICENSE file in the root directory of this source tree.\n\n# -----------------------------------------------------------------------------\n# Config definition of imagenet pretrained model path\n# -----------------------------------------------------------------------------\n\n\nfrom yacs.config import CfgNode as CN\n\nMODEL_PATH = {\n    'bninception': \"~/.torch/models/bn_inception-52deb4733.pth\",\n    'resnet50': \"~/.torch/models/resnet50-19c8e357.pth\",\n}\n\nMODEL_PATH = CN(MODEL_PATH)\n"
  },
  {
    "path": "ret_benchmark/data/__init__.py",
    "content": "# Copyright (c) Malong Technologies Co., Ltd.\n# All rights reserved.\n#\n# Contact: github@malong.com\n#\n# This source code is licensed under the LICENSE file in the root directory of this source tree.\n\nfrom .build import build_data\n"
  },
  {
    "path": "ret_benchmark/data/build.py",
    "content": "# Copyright (c) Malong Technologies Co., Ltd.\n# All rights reserved.\n#\n# Contact: github@malong.com\n#\n# This source code is licensed under the LICENSE file in the root directory of this source tree.\n\nfrom torch.utils.data import DataLoader\n\nfrom .collate_batch import collate_fn\nfrom .datasets import BaseDataSet\nfrom .samplers import RandomIdentitySampler\nfrom .transforms import build_transforms\n\n\ndef build_data(cfg, is_train=True):\n    transforms = build_transforms(cfg, is_train=is_train)\n    if is_train:\n        dataset = BaseDataSet(cfg.DATA.TRAIN_IMG_SOURCE, transforms=transforms, mode=cfg.INPUT.MODE)\n        sampler = RandomIdentitySampler(dataset=dataset,\n                                        batch_size=cfg.DATA.TRAIN_BATCHSIZE,\n                                        num_instances=cfg.DATA.NUM_INSTANCES,\n                                        max_iters=cfg.SOLVER.MAX_ITERS\n                                        )\n        data_loader = DataLoader(dataset,\n                                 collate_fn=collate_fn,\n                                 batch_sampler=sampler,\n                                 num_workers=cfg.DATA.NUM_WORKERS,\n                                 pin_memory=True\n                                 )\n    else:\n        dataset = BaseDataSet(cfg.DATA.TEST_IMG_SOURCE, transforms=transforms, mode=cfg.INPUT.MODE)\n        data_loader = DataLoader(dataset,\n                                 collate_fn=collate_fn,\n                                 shuffle=False,\n                                 batch_size=cfg.DATA.TEST_BATCHSIZE,\n                                 num_workers=cfg.DATA.NUM_WORKERS\n                                 )\n    return data_loader\n"
  },
  {
    "path": "ret_benchmark/data/collate_batch.py",
    "content": "# Copyright (c) Malong Technologies Co., Ltd.\n# All rights reserved.\n#\n# Contact: github@malong.com\n#\n# This source code is licensed under the LICENSE file in the root directory of this source tree.\n\nimport torch\n\n\ndef collate_fn(batch):\n    imgs, labels = zip(*batch)\n    labels = [int(k) for k in labels]\n    labels = torch.tensor(labels, dtype=torch.int64)\n    return torch.stack(imgs, dim=0), labels\n"
  },
  {
    "path": "ret_benchmark/data/datasets/__init__.py",
    "content": "# Copyright (c) Malong Technologies Co., Ltd.\n# All rights reserved.\n#\n# Contact: github@malong.com\n#\n# This source code is licensed under the LICENSE file in the root directory of this source tree.\n\nfrom .base_dataset import BaseDataSet\n"
  },
  {
    "path": "ret_benchmark/data/datasets/base_dataset.py",
    "content": "# Copyright (c) Malong Technologies Co., Ltd.\n# All rights reserved.\n#\n# Contact: github@malong.com\n#\n# This source code is licensed under the LICENSE file in the root directory of this source tree.\n\nimport os\nimport re\nfrom collections import defaultdict\n\nfrom torch.utils.data import Dataset\nfrom ret_benchmark.utils.img_reader import read_image\n\n\nclass BaseDataSet(Dataset):\n    \"\"\"\n    Basic Dataset read image path from img_source\n    img_source: list of img_path and label\n    \"\"\"\n\n    def __init__(self, img_source, transforms=None, mode=\"RGB\"):\n        self.mode = mode\n        self.transforms = transforms\n        self.root = os.path.dirname(img_source)\n        assert os.path.exists(img_source), f\"{img_source} NOT found.\"\n        self.img_source = img_source\n\n        self.label_list = list()\n        self.path_list = list()\n        self._load_data()\n        self.label_index_dict = self._build_label_index_dict()\n\n    def __len__(self):\n        return len(self.label_list)\n\n    def __repr__(self):\n        return self.__str__()\n\n    def __str__(self):\n        return f\"| Dataset Info |datasize: {self.__len__()}|num_labels: {len(set(self.label_list))}|\"\n\n    def _load_data(self):\n        with open(self.img_source, 'r') as f:\n            for line in f:\n                _path, _label = re.split(r\",| \", line.strip())\n                self.path_list.append(_path)\n                self.label_list.append(_label)\n\n    def _build_label_index_dict(self):\n        index_dict = defaultdict(list)\n        for i, label in enumerate(self.label_list):\n            index_dict[label].append(i)\n        return index_dict\n\n    def __getitem__(self, index):\n        path = self.path_list[index]\n        img_path = os.path.join(self.root, path)\n        label = self.label_list[index]\n\n        img = read_image(img_path, mode=self.mode)\n        if self.transforms is not None:\n            img = self.transforms(img)\n        return img, label\n"
  },
  {
    "path": "ret_benchmark/data/evaluations/__init__.py",
    "content": "# Copyright (c) Malong Technologies Co., Ltd.\n# All rights reserved.\n#\n# Contact: github@malong.com\n#\n# This source code is licensed under the LICENSE file in the root directory of this source tree.\n\nfrom .ret_metric import RetMetric\n"
  },
  {
    "path": "ret_benchmark/data/evaluations/ret_metric.py",
    "content": "# Copyright (c) Malong Technologies Co., Ltd.\n# All rights reserved.\n#\n# Contact: github@malong.com\n#\n# This source code is licensed under the LICENSE file in the root directory of this source tree.\n\nimport numpy as np\n\n\nclass RetMetric(object):\n    def __init__(self, feats, labels):\n\n        if len(feats) == 2 and type(feats) == list:\n            \"\"\"\n            feats = [gallery_feats, query_feats]\n            labels = [gallery_labels, query_labels]\n            \"\"\"\n            self.is_equal_query = False\n\n            self.gallery_feats, self.query_feats = feats\n            self.gallery_labels, self.query_labels = labels\n\n        else:\n            self.is_equal_query = True\n            self.gallery_feats = self.query_feats = feats\n            self.gallery_labels = self.query_labels = labels\n\n        self.sim_mat = np.matmul(self.query_feats, np.transpose(self.gallery_feats))\n\n    def recall_k(self, k=1):\n        m = len(self.sim_mat)\n\n        match_counter = 0\n\n        for i in range(m):\n            pos_sim = self.sim_mat[i][self.gallery_labels == self.query_labels[i]]\n            neg_sim = self.sim_mat[i][self.gallery_labels != self.query_labels[i]]\n\n            thresh = np.sort(pos_sim)[-2] if self.is_equal_query else np.max(pos_sim)\n\n            if np.sum(neg_sim > thresh) < k:\n                match_counter += 1\n        return float(match_counter) / m\n"
  },
  {
    "path": "ret_benchmark/data/samplers/__init__.py",
    "content": "# Copyright (c) Malong Technologies Co., Ltd.\n# All rights reserved.\n#\n# Contact: github@malong.com\n#\n# This source code is licensed under the LICENSE file in the root directory of this source tree.\n\nfrom .random_identity_sampler import RandomIdentitySampler\n"
  },
  {
    "path": "ret_benchmark/data/samplers/random_identity_sampler.py",
    "content": "# Copyright (c) Malong Technologies Co., Ltd.\n# All rights reserved.\n#\n# Contact: github@malong.com\n#\n# This source code is licensed under the LICENSE file in the root directory of this source tree.\n\nimport copy\nimport random\nfrom collections import defaultdict\n\nimport numpy as np\nimport torch\nfrom torch.utils.data.sampler import Sampler\n\n\nclass RandomIdentitySampler(Sampler):\n    \"\"\"\n    Randomly sample N identities, then for each identity,\n    randomly sample K instances, therefore batch size is N*K.\n    Args:\n    - dataset (BaseDataSet).\n    - num_instances (int): number of instances per identity in a batch.\n    - batch_size (int): number of examples in a batch.\n    \"\"\"\n\n    def __init__(self, dataset, batch_size, num_instances, max_iters):\n        self.label_index_dict = dataset.label_index_dict\n        self.batch_size = batch_size\n        self.K = num_instances\n        self.num_labels_per_batch = self.batch_size // self.K\n        self.max_iters = max_iters\n        self.labels = list(self.label_index_dict.keys())\n\n    def __len__(self):\n        return self.max_iters\n\n    def __repr__(self):\n        return self.__str__()\n\n    def __str__(self):\n        return f\"|Sampler| iters {self.max_iters}| K {self.K}| M {self.batch_size}|\"\n\n    def _prepare_batch(self):\n        batch_idxs_dict = defaultdict(list)\n\n        for label in self.labels:\n            idxs = copy.deepcopy(self.label_index_dict[label])\n            if len(idxs) < self.K:\n                idxs.extend(np.random.choice(idxs, size=self.K - len(idxs), replace=True))\n            random.shuffle(idxs)\n\n            batch_idxs_dict[label] = [idxs[i * self.K: (i + 1) * self.K] for i in range(len(idxs) // self.K)]\n\n        avai_labels = copy.deepcopy(self.labels)\n        return batch_idxs_dict, avai_labels\n\n    def __iter__(self):\n        batch_idxs_dict, avai_labels = self._prepare_batch()\n        for _ in range(self.max_iters):\n            batch = []\n            if len(avai_labels) < self.num_labels_per_batch:\n                batch_idxs_dict, avai_labels = self._prepare_batch()\n\n            selected_labels = random.sample(avai_labels, self.num_labels_per_batch)\n            for label in selected_labels:\n                batch_idxs = batch_idxs_dict[label].pop(0)\n                batch.extend(batch_idxs)\n                if len(batch_idxs_dict[label]) == 0:\n                    avai_labels.remove(label)\n            yield batch\n"
  },
  {
    "path": "ret_benchmark/data/transforms/__init__.py",
    "content": "# Copyright (c) Malong Technologies Co., Ltd.\n# All rights reserved.\n#\n# Contact: github@malong.com\n#\n# This source code is licensed under the LICENSE file in the root directory of this source tree.\n\nfrom .build import build_transforms\n"
  },
  {
    "path": "ret_benchmark/data/transforms/build.py",
    "content": "# Copyright (c) Malong Technologies Co., Ltd.\n# All rights reserved.\n#\n# Contact: github@malong.com\n#\n# This source code is licensed under the LICENSE file in the root directory of this source tree.\n\nimport torchvision.transforms as T\n\n\ndef build_transforms(cfg, is_train=True):\n    normalize_transform = T.Normalize(mean=cfg.INPUT.PIXEL_MEAN,\n                                      std=cfg.INPUT.PIXEL_STD)\n    if is_train:\n        transform = T.Compose([\n            T.Resize(size=cfg.INPUT.ORIGIN_SIZE),\n            T.RandomResizedCrop(\n                scale=cfg.INPUT.CROP_SCALE,\n                size=cfg.INPUT.CROP_SIZE\n            ),\n            T.RandomHorizontalFlip(p=cfg.INPUT.FLIP_PROB),\n            T.ToTensor(),\n            normalize_transform,\n        ])\n    else:\n        transform = T.Compose([\n            T.Resize(size=cfg.INPUT.ORIGIN_SIZE),\n            T.CenterCrop(cfg.INPUT.CROP_SIZE),\n            T.ToTensor(),\n            normalize_transform\n        ])\n    return transform\n"
  },
  {
    "path": "ret_benchmark/engine/__init__.py",
    "content": "# Copyright (c) Malong Technologies Co., Ltd.\n# All rights reserved.\n#\n# Contact: github@malong.com\n#\n# This source code is licensed under the LICENSE file in the root directory of this source tree.\n\nfrom .trainer import do_train\n"
  },
  {
    "path": "ret_benchmark/engine/trainer.py",
    "content": "# Copyright (c) Malong Technologies Co., Ltd.\n# All rights reserved.\n#\n# Contact: github@malong.com\n#\n# This source code is licensed under the LICENSE file in the root directory of this source tree.\n\nimport datetime\nimport time\n\nimport numpy as np\nimport torch\n\nfrom ret_benchmark.data.evaluations import RetMetric\nfrom ret_benchmark.utils.feat_extractor import feat_extractor\nfrom ret_benchmark.utils.freeze_bn import set_bn_eval\nfrom ret_benchmark.utils.metric_logger import MetricLogger\n\n\ndef do_train(\n        cfg,\n        model,\n        train_loader,\n        val_loader,\n        optimizer,\n        scheduler,\n        criterion,\n        checkpointer,\n        device,\n        checkpoint_period,\n        arguments,\n        logger\n):\n    logger.info(\"Start training\")\n    meters = MetricLogger(delimiter=\"  \")\n    max_iter = len(train_loader)\n\n    start_iter = arguments[\"iteration\"]\n    best_iteration = -1\n    best_recall = 0\n\n    start_training_time = time.time()\n    end = time.time()\n    for iteration, (images, targets) in enumerate(train_loader, start_iter):\n\n        if iteration % cfg.VALIDATION.VERBOSE == 0 or iteration == max_iter:\n            model.eval()\n            logger.info('Validation')\n            labels = val_loader.dataset.label_list\n            labels = np.array([int(k) for k in labels])\n            feats = feat_extractor(model, val_loader, logger=logger)\n\n            ret_metric = RetMetric(feats=feats, labels=labels)\n            recall_curr = ret_metric.recall_k(1)\n\n            if recall_curr > best_recall:\n                best_recall = recall_curr\n                best_iteration = iteration\n                logger.info(f'Best iteration {iteration}: recall@1: {best_recall:.3f}')\n                checkpointer.save(f\"best_model\")\n            else:\n                logger.info(f'Recall@1 at iteration {iteration:06d}: {recall_curr:.3f}')\n\n        model.train()\n        model.apply(set_bn_eval)\n\n        data_time = time.time() - end\n        iteration = iteration + 1\n        arguments[\"iteration\"] = iteration\n\n        scheduler.step()\n\n        images = images.to(device)\n        targets = torch.stack([target.to(device) for target in targets])\n\n        feats = model(images)\n        loss = criterion(feats, targets)\n        optimizer.zero_grad()\n        loss.backward()\n        optimizer.step()\n\n        batch_time = time.time() - end\n        end = time.time()\n        meters.update(time=batch_time, data=data_time, loss=loss.item())\n\n        eta_seconds = meters.time.global_avg * (max_iter - iteration)\n        eta_string = str(datetime.timedelta(seconds=int(eta_seconds)))\n\n        if iteration % 20 == 0 or iteration == max_iter:\n            logger.info(\n                meters.delimiter.join(\n                    [\n                        \"eta: {eta}\",\n                        \"iter: {iter}\",\n                        \"{meters}\",\n                        \"lr: {lr:.6f}\",\n                        \"max mem: {memory:.1f} GB\",\n                    ]\n                ).format(\n                    eta=eta_string,\n                    iter=iteration,\n                    meters=str(meters),\n                    lr=optimizer.param_groups[0][\"lr\"],\n                    memory=torch.cuda.max_memory_allocated() / 1024.0 / 1024.0 / 1024.0,\n                )\n            )\n\n        if iteration % checkpoint_period == 0:\n            checkpointer.save(\"model_{:06d}\".format(iteration))\n\n    total_training_time = time.time() - start_training_time\n    total_time_str = str(datetime.timedelta(seconds=total_training_time))\n    logger.info(\n        \"Total training time: {} ({:.4f} s / it)\".format(\n            total_time_str, total_training_time / (max_iter)\n        )\n    )\n\n    logger.info(f\"Best iteration: {best_iteration :06d} | best recall {best_recall} \")\n"
  },
  {
    "path": "ret_benchmark/losses/__init__.py",
    "content": "# Copyright (c) Malong Technologies Co., Ltd.\n# All rights reserved.\n#\n# Contact: github@malong.com\n#\n# This source code is licensed under the LICENSE file in the root directory of this source tree.\n\nfrom .build import build_loss\n"
  },
  {
    "path": "ret_benchmark/losses/build.py",
    "content": "# Copyright (c) Malong Technologies Co., Ltd.\n# All rights reserved.\n#\n# Contact: github@malong.com\n#\n# This source code is licensed under the LICENSE file in the root directory of this source tree.\n\nfrom .multi_similarity_loss import MultiSimilarityLoss\nfrom .margin_loss import MarginLoss\nfrom .registry import LOSS\n\n\ndef build_loss(cfg):\n    loss_name = cfg.LOSSES.NAME\n    assert loss_name in LOSS, \\\n        f'loss name {loss_name} is not registered in registry :{LOSS.keys()}'\n    return LOSS[loss_name](cfg)\n"
  },
  {
    "path": "ret_benchmark/losses/margin_loss.py",
    "content": "import numpy as np\nimport torch\nfrom torch import nn\nimport torch.nn.functional as F\n\nfrom ret_benchmark.losses.registry import LOSS\n\n\nclass DistanceWeightedSampling(object):\n    \"\"\"\n    \"\"\"\n    def __init__(self, cfg):\n        super(DistanceWeightedSampling, self).__init__()\n        self.cutoff = cfg.LOSSES.MARGIN_LOSS.CUTOFF\n        self.upper_cutoff = cfg.LOSSES.MARGIN_LOSS.UPPER_CUTOFF\n\n    def sample(self, batch, labels):\n\n        if isinstance(labels, torch.Tensor):\n            labels = labels.detach().cpu().numpy()\n        bs = batch.shape[0]\n        distances = self.p_dist(batch.detach()).clamp(min=self.cutoff)\n\n        positives, negatives = [], []\n\n        for i in range(bs):\n            pos = labels == labels[i]\n            q_d_inv = self.inverse_sphere_distances(batch, distances[i], labels, labels[i])\n            # sample positives randomly\n            pos[i] = 0\n            positives.append(np.random.choice(np.where(pos)[0]))\n            # sample negatives by distance\n            negatives.append(np.random.choice(bs, p=q_d_inv))\n\n        sampled_triplets = [[a, p, n] for a, p, n in zip(list(range(bs)), positives, negatives)]\n        return sampled_triplets\n\n    @staticmethod\n    def p_dist(A, eps=1e-4):\n        prod = torch.mm(A, A.t())\n        norm = prod.diag().unsqueeze(1).expand_as(prod)\n        res = (norm + norm.t() - 2 * prod).clamp(min=0)\n        return res.clamp(min=eps).sqrt()\n\n    def inverse_sphere_distances(self, batch, dist, labels, anchor_label):\n        bs, dim = len(dist), batch.shape[-1]\n        # negated log-distribution of distances of unit sphere in dimension <dim>\n        log_q_d_inv = ((2.0 - float(dim)) * torch.log(dist) - (float(dim-3) / 2)\n                       * torch.log(1.0 - 0.25 * (dist.pow(2))))\n        # set sampling probabilities of positives to zero\n        log_q_d_inv[np.where(labels == anchor_label)[0]] = 0\n\n        q_d_inv = torch.exp(log_q_d_inv - torch.max(log_q_d_inv))  # - max(log) for stability\n        # set sampling probabilities of positives to zero\n        q_d_inv[np.where(labels == anchor_label)[0]] = 0\n\n        # NOTE: Cutting of values with high distances made the results slightly worse.\n        # q_d_inv[np.where(dist > self.upper_cutoff)[0]] = 0\n\n        q_d_inv = q_d_inv/q_d_inv.sum()\n        return q_d_inv.detach().cpu().numpy()\n\n\n@LOSS.register(\"margin_loss\")\nclass MarginLoss(nn.Module):\n    \"\"\"Margin based loss with DistanceWeightedSampling\n    \"\"\"\n    def __init__(self, cfg):\n        super(MarginLoss, self).__init__()\n        self.beta_val = 1.2\n        self.margin = 0.2\n        self.nu = 0.0\n        self.n_classes = cfg.LOSSES.MARGIN_LOSS.N_CLASSES\n        self.beta_constant = cfg.LOSSES.MARGIN_LOSS.BETA_CONSTANT\n        if self.beta_constant:\n            self.beta = self.beta_val\n        else:\n            self.beta = torch.nn.Parameter(torch.ones(self.n_classes)*self.beta_val)\n        self.sampler = DistanceWeightedSampling(cfg)\n\n    def forward(self, batch, labels):\n        if isinstance(labels, torch.Tensor):\n            labels = labels.detach().cpu().numpy()\n        sampled_triplets = self.sampler.sample(batch, labels)\n\n        # compute distances between anchor-positive and anchor-negative.\n        d_ap, d_an = [], []\n        for triplet in sampled_triplets:\n            train_triplet = {'Anchor': batch[triplet[0], :],\n                             'Positive': batch[triplet[1], :], 'Negative': batch[triplet[2]]}\n            pos_dist = ((train_triplet['Anchor']-train_triplet['Positive']).pow(2).sum()+1e-8).pow(1/2)\n            neg_dist = ((train_triplet['Anchor']-train_triplet['Negative']).pow(2).sum()+1e-8).pow(1/2)\n\n            d_ap.append(pos_dist)\n            d_an.append(neg_dist)\n        d_ap, d_an = torch.stack(d_ap), torch.stack(d_an)\n\n        # group betas together by anchor class in sampled triplets (as each beta belongs to one class).\n        if self.beta_constant:\n            beta = self.beta\n        else:\n            beta = torch.stack([self.beta[labels[triplet[0]]] for\n                                triplet in sampled_triplets]).type(torch.cuda.FloatTensor)\n        # compute actual margin positive and margin negative loss\n        pos_loss = F.relu(d_ap-beta+self.margin)\n        neg_loss = F.relu(beta-d_an+self.margin)\n\n        # compute normalization constant\n        pair_count = torch.sum((pos_loss > 0.)+(neg_loss > 0.)).type(torch.cuda.FloatTensor)\n        # actual Margin Loss\n        loss = torch.sum(pos_loss+neg_loss) if pair_count == 0. else torch.sum(pos_loss+neg_loss)/pair_count\n\n        # (Optional) Add regularization penalty on betas.\n        # if self.nu: loss = loss + beta_regularisation_loss.type(torch.cuda.FloatTensor)\n        return loss\n"
  },
  {
    "path": "ret_benchmark/losses/multi_similarity_loss.py",
    "content": "# Copyright (c) Malong Technologies Co., Ltd.\n# All rights reserved.\n#\n# Contact: github@malong.com\n#\n# This source code is licensed under the LICENSE file in the root directory of this source tree.\n\nimport torch\nfrom torch import nn\n\nfrom ret_benchmark.losses.registry import LOSS\n\n\n@LOSS.register('ms_loss')\nclass MultiSimilarityLoss(nn.Module):\n    def __init__(self, cfg):\n        super(MultiSimilarityLoss, self).__init__()\n        self.thresh = 0.5\n        self.margin = 0.1\n\n        self.scale_pos = cfg.LOSSES.MULTI_SIMILARITY_LOSS.SCALE_POS\n        self.scale_neg = cfg.LOSSES.MULTI_SIMILARITY_LOSS.SCALE_NEG\n\n    def forward(self, feats, labels):\n        assert feats.size(0) == labels.size(0), \\\n            f\"feats.size(0): {feats.size(0)} is not equal to labels.size(0): {labels.size(0)}\"\n        batch_size = feats.size(0)\n        sim_mat = torch.matmul(feats, torch.t(feats))\n\n        epsilon = 1e-5\n        loss = list()\n\n        for i in range(batch_size):\n            pos_pair_ = sim_mat[i][labels == labels[i]]\n            pos_pair_ = pos_pair_[pos_pair_ < 1 - epsilon]\n            neg_pair_ = sim_mat[i][labels != labels[i]]\n\n            neg_pair = neg_pair_[neg_pair_ + self.margin > min(pos_pair_)]\n            pos_pair = pos_pair_[pos_pair_ - self.margin < max(neg_pair_)]\n\n            if len(neg_pair) < 1 or len(pos_pair) < 1:\n                continue\n\n            # weighting step\n            pos_loss = 1.0 / self.scale_pos * torch.log(\n                1 + torch.sum(torch.exp(-self.scale_pos * (pos_pair - self.thresh))))\n            neg_loss = 1.0 / self.scale_neg * torch.log(\n                1 + torch.sum(torch.exp(self.scale_neg * (neg_pair - self.thresh))))\n            loss.append(pos_loss + neg_loss)\n\n        if len(loss) == 0:\n            return torch.zeros([], requires_grad=True)\n\n        loss = sum(loss) / batch_size\n        return loss\n"
  },
  {
    "path": "ret_benchmark/losses/registry.py",
    "content": "# Copyright (c) Malong Technologies Co., Ltd.\n# All rights reserved.\n#\n# Contact: github@malong.com\n#\n# This source code is licensed under the LICENSE file in the root directory of this source tree.\n\nfrom ret_benchmark.utils.registry import Registry\n\nLOSS = Registry()\n"
  },
  {
    "path": "ret_benchmark/modeling/__init__.py",
    "content": "# Copyright (c) Malong Technologies Co., Ltd.\n# All rights reserved.\n#\n# Contact: github@malong.com\n#\n# This source code is licensed under the LICENSE file in the root directory of this source tree.\n\nfrom .backbone import build_backbone\nfrom .build import build_model\nfrom .heads import build_head\nfrom .registry import BACKBONES, HEADS\n"
  },
  {
    "path": "ret_benchmark/modeling/backbone/__init__.py",
    "content": "from .build import build_backbone\n"
  },
  {
    "path": "ret_benchmark/modeling/backbone/bninception.py",
    "content": "from __future__ import absolute_import, division, print_function\n\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\n\nfrom ret_benchmark.modeling import registry\n\n@registry.BACKBONES.register('bninception')\nclass BNInception(nn.Module):\n\n    def __init__(self):\n        super(BNInception, self).__init__()\n        inplace = True\n        self.conv1_7x7_s2 = nn.Conv2d(3, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3))\n        self.conv1_7x7_s2_bn = nn.BatchNorm2d(64, affine=True)\n        self.conv1_relu_7x7 = nn.ReLU(inplace)\n        self.pool1_3x3_s2 = nn.MaxPool2d((3, 3), stride=(2, 2), dilation=(1, 1), ceil_mode=True)\n        self.conv2_3x3_reduce = nn.Conv2d(64, 64, kernel_size=(1, 1), stride=(1, 1))\n        self.conv2_3x3_reduce_bn = nn.BatchNorm2d(64, affine=True)\n        self.conv2_relu_3x3_reduce = nn.ReLU(inplace)\n        self.conv2_3x3 = nn.Conv2d(64, 192, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n        self.conv2_3x3_bn = nn.BatchNorm2d(192, affine=True)\n        self.conv2_relu_3x3 = nn.ReLU(inplace)\n        self.pool2_3x3_s2 = nn.MaxPool2d((3, 3), stride=(2, 2), dilation=(1, 1), ceil_mode=True)\n        self.inception_3a_1x1 = nn.Conv2d(192, 64, kernel_size=(1, 1), stride=(1, 1))\n        self.inception_3a_1x1_bn = nn.BatchNorm2d(64, affine=True)\n        self.inception_3a_relu_1x1 = nn.ReLU(inplace)\n        self.inception_3a_3x3_reduce = nn.Conv2d(192, 64, kernel_size=(1, 1), stride=(1, 1))\n        self.inception_3a_3x3_reduce_bn = nn.BatchNorm2d(64, affine=True)\n        self.inception_3a_relu_3x3_reduce = nn.ReLU(inplace)\n        self.inception_3a_3x3 = nn.Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n        self.inception_3a_3x3_bn = nn.BatchNorm2d(64, affine=True)\n        self.inception_3a_relu_3x3 = nn.ReLU(inplace)\n        self.inception_3a_double_3x3_reduce = nn.Conv2d(192, 64, kernel_size=(1, 1), stride=(1, 1))\n        self.inception_3a_double_3x3_reduce_bn = nn.BatchNorm2d(64, affine=True)\n        self.inception_3a_relu_double_3x3_reduce = nn.ReLU(inplace)\n        self.inception_3a_double_3x3_1 = nn.Conv2d(64, 96, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n        self.inception_3a_double_3x3_1_bn = nn.BatchNorm2d(96, affine=True)\n        self.inception_3a_relu_double_3x3_1 = nn.ReLU(inplace)\n        self.inception_3a_double_3x3_2 = nn.Conv2d(96, 96, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n        self.inception_3a_double_3x3_2_bn = nn.BatchNorm2d(96, affine=True)\n        self.inception_3a_relu_double_3x3_2 = nn.ReLU(inplace)\n        self.inception_3a_pool = nn.AvgPool2d(3, stride=1, padding=1, ceil_mode=True, count_include_pad=True)\n        self.inception_3a_pool_proj = nn.Conv2d(192, 32, kernel_size=(1, 1), stride=(1, 1))\n        self.inception_3a_pool_proj_bn = nn.BatchNorm2d(32, affine=True)\n        self.inception_3a_relu_pool_proj = nn.ReLU(inplace)\n        self.inception_3b_1x1 = nn.Conv2d(256, 64, kernel_size=(1, 1), stride=(1, 1))\n        self.inception_3b_1x1_bn = nn.BatchNorm2d(64, affine=True)\n        self.inception_3b_relu_1x1 = nn.ReLU(inplace)\n        self.inception_3b_3x3_reduce = nn.Conv2d(256, 64, kernel_size=(1, 1), stride=(1, 1))\n        self.inception_3b_3x3_reduce_bn = nn.BatchNorm2d(64, affine=True)\n        self.inception_3b_relu_3x3_reduce = nn.ReLU(inplace)\n        self.inception_3b_3x3 = nn.Conv2d(64, 96, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n        self.inception_3b_3x3_bn = nn.BatchNorm2d(96, affine=True)\n        self.inception_3b_relu_3x3 = nn.ReLU(inplace)\n        self.inception_3b_double_3x3_reduce = nn.Conv2d(256, 64, kernel_size=(1, 1), stride=(1, 1))\n        self.inception_3b_double_3x3_reduce_bn = nn.BatchNorm2d(64, affine=True)\n        self.inception_3b_relu_double_3x3_reduce = nn.ReLU(inplace)\n        self.inception_3b_double_3x3_1 = nn.Conv2d(64, 96, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n        self.inception_3b_double_3x3_1_bn = nn.BatchNorm2d(96, affine=True)\n        self.inception_3b_relu_double_3x3_1 = nn.ReLU(inplace)\n        self.inception_3b_double_3x3_2 = nn.Conv2d(96, 96, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n        self.inception_3b_double_3x3_2_bn = nn.BatchNorm2d(96, affine=True)\n        self.inception_3b_relu_double_3x3_2 = nn.ReLU(inplace)\n        self.inception_3b_pool = nn.AvgPool2d(3, stride=1, padding=1, ceil_mode=True, count_include_pad=True)\n        self.inception_3b_pool_proj = nn.Conv2d(256, 64, kernel_size=(1, 1), stride=(1, 1))\n        self.inception_3b_pool_proj_bn = nn.BatchNorm2d(64, affine=True)\n        self.inception_3b_relu_pool_proj = nn.ReLU(inplace)\n        self.inception_3c_3x3_reduce = nn.Conv2d(320, 128, kernel_size=(1, 1), stride=(1, 1))\n        self.inception_3c_3x3_reduce_bn = nn.BatchNorm2d(128, affine=True)\n        self.inception_3c_relu_3x3_reduce = nn.ReLU(inplace)\n        self.inception_3c_3x3 = nn.Conv2d(128, 160, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1))\n        self.inception_3c_3x3_bn = nn.BatchNorm2d(160, affine=True)\n        self.inception_3c_relu_3x3 = nn.ReLU(inplace)\n        self.inception_3c_double_3x3_reduce = nn.Conv2d(320, 64, kernel_size=(1, 1), stride=(1, 1))\n        self.inception_3c_double_3x3_reduce_bn = nn.BatchNorm2d(64, affine=True)\n        self.inception_3c_relu_double_3x3_reduce = nn.ReLU(inplace)\n        self.inception_3c_double_3x3_1 = nn.Conv2d(64, 96, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n        self.inception_3c_double_3x3_1_bn = nn.BatchNorm2d(96, affine=True)\n        self.inception_3c_relu_double_3x3_1 = nn.ReLU(inplace)\n        self.inception_3c_double_3x3_2 = nn.Conv2d(96, 96, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1))\n        self.inception_3c_double_3x3_2_bn = nn.BatchNorm2d(96, affine=True)\n        self.inception_3c_relu_double_3x3_2 = nn.ReLU(inplace)\n        self.inception_3c_pool = nn.MaxPool2d((3, 3), stride=(2, 2), dilation=(1, 1), ceil_mode=True)\n        self.inception_4a_1x1 = nn.Conv2d(576, 224, kernel_size=(1, 1), stride=(1, 1))\n        self.inception_4a_1x1_bn = nn.BatchNorm2d(224, affine=True)\n        self.inception_4a_relu_1x1 = nn.ReLU(inplace)\n        self.inception_4a_3x3_reduce = nn.Conv2d(576, 64, kernel_size=(1, 1), stride=(1, 1))\n        self.inception_4a_3x3_reduce_bn = nn.BatchNorm2d(64, affine=True)\n        self.inception_4a_relu_3x3_reduce = nn.ReLU(inplace)\n        self.inception_4a_3x3 = nn.Conv2d(64, 96, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n        self.inception_4a_3x3_bn = nn.BatchNorm2d(96, affine=True)\n        self.inception_4a_relu_3x3 = nn.ReLU(inplace)\n        self.inception_4a_double_3x3_reduce = nn.Conv2d(576, 96, kernel_size=(1, 1), stride=(1, 1))\n        self.inception_4a_double_3x3_reduce_bn = nn.BatchNorm2d(96, affine=True)\n        self.inception_4a_relu_double_3x3_reduce = nn.ReLU(inplace)\n        self.inception_4a_double_3x3_1 = nn.Conv2d(96, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n        self.inception_4a_double_3x3_1_bn = nn.BatchNorm2d(128, affine=True)\n        self.inception_4a_relu_double_3x3_1 = nn.ReLU(inplace)\n        self.inception_4a_double_3x3_2 = nn.Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n        self.inception_4a_double_3x3_2_bn = nn.BatchNorm2d(128, affine=True)\n        self.inception_4a_relu_double_3x3_2 = nn.ReLU(inplace)\n        self.inception_4a_pool = nn.AvgPool2d(3, stride=1, padding=1, ceil_mode=True, count_include_pad=True)\n        self.inception_4a_pool_proj = nn.Conv2d(576, 128, kernel_size=(1, 1), stride=(1, 1))\n        self.inception_4a_pool_proj_bn = nn.BatchNorm2d(128, affine=True)\n        self.inception_4a_relu_pool_proj = nn.ReLU(inplace)\n        self.inception_4b_1x1 = nn.Conv2d(576, 192, kernel_size=(1, 1), stride=(1, 1))\n        self.inception_4b_1x1_bn = nn.BatchNorm2d(192, affine=True)\n        self.inception_4b_relu_1x1 = nn.ReLU(inplace)\n        self.inception_4b_3x3_reduce = nn.Conv2d(576, 96, kernel_size=(1, 1), stride=(1, 1))\n        self.inception_4b_3x3_reduce_bn = nn.BatchNorm2d(96, affine=True)\n        self.inception_4b_relu_3x3_reduce = nn.ReLU(inplace)\n        self.inception_4b_3x3 = nn.Conv2d(96, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n        self.inception_4b_3x3_bn = nn.BatchNorm2d(128, affine=True)\n        self.inception_4b_relu_3x3 = nn.ReLU(inplace)\n        self.inception_4b_double_3x3_reduce = nn.Conv2d(576, 96, kernel_size=(1, 1), stride=(1, 1))\n        self.inception_4b_double_3x3_reduce_bn = nn.BatchNorm2d(96, affine=True)\n        self.inception_4b_relu_double_3x3_reduce = nn.ReLU(inplace)\n        self.inception_4b_double_3x3_1 = nn.Conv2d(96, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n        self.inception_4b_double_3x3_1_bn = nn.BatchNorm2d(128, affine=True)\n        self.inception_4b_relu_double_3x3_1 = nn.ReLU(inplace)\n        self.inception_4b_double_3x3_2 = nn.Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n        self.inception_4b_double_3x3_2_bn = nn.BatchNorm2d(128, affine=True)\n        self.inception_4b_relu_double_3x3_2 = nn.ReLU(inplace)\n        self.inception_4b_pool = nn.AvgPool2d(3, stride=1, padding=1, ceil_mode=True, count_include_pad=True)\n        self.inception_4b_pool_proj = nn.Conv2d(576, 128, kernel_size=(1, 1), stride=(1, 1))\n        self.inception_4b_pool_proj_bn = nn.BatchNorm2d(128, affine=True)\n        self.inception_4b_relu_pool_proj = nn.ReLU(inplace)\n        self.inception_4c_1x1 = nn.Conv2d(576, 160, kernel_size=(1, 1), stride=(1, 1))\n        self.inception_4c_1x1_bn = nn.BatchNorm2d(160, affine=True)\n        self.inception_4c_relu_1x1 = nn.ReLU(inplace)\n        self.inception_4c_3x3_reduce = nn.Conv2d(576, 128, kernel_size=(1, 1), stride=(1, 1))\n        self.inception_4c_3x3_reduce_bn = nn.BatchNorm2d(128, affine=True)\n        self.inception_4c_relu_3x3_reduce = nn.ReLU(inplace)\n        self.inception_4c_3x3 = nn.Conv2d(128, 160, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n        self.inception_4c_3x3_bn = nn.BatchNorm2d(160, affine=True)\n        self.inception_4c_relu_3x3 = nn.ReLU(inplace)\n        self.inception_4c_double_3x3_reduce = nn.Conv2d(576, 128, kernel_size=(1, 1), stride=(1, 1))\n        self.inception_4c_double_3x3_reduce_bn = nn.BatchNorm2d(128, affine=True)\n        self.inception_4c_relu_double_3x3_reduce = nn.ReLU(inplace)\n        self.inception_4c_double_3x3_1 = nn.Conv2d(128, 160, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n        self.inception_4c_double_3x3_1_bn = nn.BatchNorm2d(160, affine=True)\n        self.inception_4c_relu_double_3x3_1 = nn.ReLU(inplace)\n        self.inception_4c_double_3x3_2 = nn.Conv2d(160, 160, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n        self.inception_4c_double_3x3_2_bn = nn.BatchNorm2d(160, affine=True)\n        self.inception_4c_relu_double_3x3_2 = nn.ReLU(inplace)\n        self.inception_4c_pool = nn.AvgPool2d(3, stride=1, padding=1, ceil_mode=True, count_include_pad=True)\n        self.inception_4c_pool_proj = nn.Conv2d(576, 128, kernel_size=(1, 1), stride=(1, 1))\n        self.inception_4c_pool_proj_bn = nn.BatchNorm2d(128, affine=True)\n        self.inception_4c_relu_pool_proj = nn.ReLU(inplace)\n        self.inception_4d_1x1 = nn.Conv2d(608, 96, kernel_size=(1, 1), stride=(1, 1))\n        self.inception_4d_1x1_bn = nn.BatchNorm2d(96, affine=True)\n        self.inception_4d_relu_1x1 = nn.ReLU(inplace)\n        self.inception_4d_3x3_reduce = nn.Conv2d(608, 128, kernel_size=(1, 1), stride=(1, 1))\n        self.inception_4d_3x3_reduce_bn = nn.BatchNorm2d(128, affine=True)\n        self.inception_4d_relu_3x3_reduce = nn.ReLU(inplace)\n        self.inception_4d_3x3 = nn.Conv2d(128, 192, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n        self.inception_4d_3x3_bn = nn.BatchNorm2d(192, affine=True)\n        self.inception_4d_relu_3x3 = nn.ReLU(inplace)\n        self.inception_4d_double_3x3_reduce = nn.Conv2d(608, 160, kernel_size=(1, 1), stride=(1, 1))\n        self.inception_4d_double_3x3_reduce_bn = nn.BatchNorm2d(160, affine=True)\n        self.inception_4d_relu_double_3x3_reduce = nn.ReLU(inplace)\n        self.inception_4d_double_3x3_1 = nn.Conv2d(160, 192, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n        self.inception_4d_double_3x3_1_bn = nn.BatchNorm2d(192, affine=True)\n        self.inception_4d_relu_double_3x3_1 = nn.ReLU(inplace)\n        self.inception_4d_double_3x3_2 = nn.Conv2d(192, 192, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n        self.inception_4d_double_3x3_2_bn = nn.BatchNorm2d(192, affine=True)\n        self.inception_4d_relu_double_3x3_2 = nn.ReLU(inplace)\n        self.inception_4d_pool = nn.AvgPool2d(3, stride=1, padding=1, ceil_mode=True, count_include_pad=True)\n        self.inception_4d_pool_proj = nn.Conv2d(608, 128, kernel_size=(1, 1), stride=(1, 1))\n        self.inception_4d_pool_proj_bn = nn.BatchNorm2d(128, affine=True)\n        self.inception_4d_relu_pool_proj = nn.ReLU(inplace)\n        self.inception_4e_3x3_reduce = nn.Conv2d(608, 128, kernel_size=(1, 1), stride=(1, 1))\n        self.inception_4e_3x3_reduce_bn = nn.BatchNorm2d(128, affine=True)\n        self.inception_4e_relu_3x3_reduce = nn.ReLU(inplace)\n        self.inception_4e_3x3 = nn.Conv2d(128, 192, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1))\n        self.inception_4e_3x3_bn = nn.BatchNorm2d(192, affine=True)\n        self.inception_4e_relu_3x3 = nn.ReLU(inplace)\n        self.inception_4e_double_3x3_reduce = nn.Conv2d(608, 192, kernel_size=(1, 1), stride=(1, 1))\n        self.inception_4e_double_3x3_reduce_bn = nn.BatchNorm2d(192, affine=True)\n        self.inception_4e_relu_double_3x3_reduce = nn.ReLU(inplace)\n        self.inception_4e_double_3x3_1 = nn.Conv2d(192, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n        self.inception_4e_double_3x3_1_bn = nn.BatchNorm2d(256, affine=True)\n        self.inception_4e_relu_double_3x3_1 = nn.ReLU(inplace)\n        self.inception_4e_double_3x3_2 = nn.Conv2d(256, 256, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1))\n        self.inception_4e_double_3x3_2_bn = nn.BatchNorm2d(256, affine=True)\n        self.inception_4e_relu_double_3x3_2 = nn.ReLU(inplace)\n        self.inception_4e_pool = nn.MaxPool2d((3, 3), stride=(2, 2), dilation=(1, 1), ceil_mode=True)\n        self.inception_5a_1x1 = nn.Conv2d(1056, 352, kernel_size=(1, 1), stride=(1, 1))\n        self.inception_5a_1x1_bn = nn.BatchNorm2d(352, affine=True)\n        self.inception_5a_relu_1x1 = nn.ReLU(inplace)\n        self.inception_5a_3x3_reduce = nn.Conv2d(1056, 192, kernel_size=(1, 1), stride=(1, 1))\n        self.inception_5a_3x3_reduce_bn = nn.BatchNorm2d(192, affine=True)\n        self.inception_5a_relu_3x3_reduce = nn.ReLU(inplace)\n        self.inception_5a_3x3 = nn.Conv2d(192, 320, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n        self.inception_5a_3x3_bn = nn.BatchNorm2d(320, affine=True)\n        self.inception_5a_relu_3x3 = nn.ReLU(inplace)\n        self.inception_5a_double_3x3_reduce = nn.Conv2d(1056, 160, kernel_size=(1, 1), stride=(1, 1))\n        self.inception_5a_double_3x3_reduce_bn = nn.BatchNorm2d(160, affine=True)\n        self.inception_5a_relu_double_3x3_reduce = nn.ReLU(inplace)\n        self.inception_5a_double_3x3_1 = nn.Conv2d(160, 224, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n        self.inception_5a_double_3x3_1_bn = nn.BatchNorm2d(224, affine=True)\n        self.inception_5a_relu_double_3x3_1 = nn.ReLU(inplace)\n        self.inception_5a_double_3x3_2 = nn.Conv2d(224, 224, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n        self.inception_5a_double_3x3_2_bn = nn.BatchNorm2d(224, affine=True)\n        self.inception_5a_relu_double_3x3_2 = nn.ReLU(inplace)\n        self.inception_5a_pool = nn.AvgPool2d(3, stride=1, padding=1, ceil_mode=True, count_include_pad=True)\n        self.inception_5a_pool_proj = nn.Conv2d(1056, 128, kernel_size=(1, 1), stride=(1, 1))\n        self.inception_5a_pool_proj_bn = nn.BatchNorm2d(128, affine=True)\n        self.inception_5a_relu_pool_proj = nn.ReLU(inplace)\n        self.inception_5b_1x1 = nn.Conv2d(1024, 352, kernel_size=(1, 1), stride=(1, 1))\n        self.inception_5b_1x1_bn = nn.BatchNorm2d(352, affine=True)\n        self.inception_5b_relu_1x1 = nn.ReLU(inplace)\n        self.inception_5b_3x3_reduce = nn.Conv2d(1024, 192, kernel_size=(1, 1), stride=(1, 1))\n        self.inception_5b_3x3_reduce_bn = nn.BatchNorm2d(192, affine=True)\n        self.inception_5b_relu_3x3_reduce = nn.ReLU(inplace)\n        self.inception_5b_3x3 = nn.Conv2d(192, 320, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n        self.inception_5b_3x3_bn = nn.BatchNorm2d(320, affine=True)\n        self.inception_5b_relu_3x3 = nn.ReLU(inplace)\n        self.inception_5b_double_3x3_reduce = nn.Conv2d(1024, 192, kernel_size=(1, 1), stride=(1, 1))\n        self.inception_5b_double_3x3_reduce_bn = nn.BatchNorm2d(192, affine=True)\n        self.inception_5b_relu_double_3x3_reduce = nn.ReLU(inplace)\n        self.inception_5b_double_3x3_1 = nn.Conv2d(192, 224, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n        self.inception_5b_double_3x3_1_bn = nn.BatchNorm2d(224, affine=True)\n        self.inception_5b_relu_double_3x3_1 = nn.ReLU(inplace)\n        self.inception_5b_double_3x3_2 = nn.Conv2d(224, 224, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n        self.inception_5b_double_3x3_2_bn = nn.BatchNorm2d(224, affine=True)\n        self.inception_5b_relu_double_3x3_2 = nn.ReLU(inplace)\n        self.inception_5b_pool = nn.MaxPool2d((3, 3), stride=(1, 1), padding=(1, 1), dilation=(1, 1), ceil_mode=True)\n        self.inception_5b_pool_proj = nn.Conv2d(1024, 128, kernel_size=(1, 1), stride=(1, 1))\n        self.inception_5b_pool_proj_bn = nn.BatchNorm2d(128, affine=True)\n        self.inception_5b_relu_pool_proj = nn.ReLU(inplace)\n\n    def features(self, input):\n        conv1_7x7_s2_out = self.conv1_7x7_s2(input)\n        conv1_7x7_s2_bn_out = self.conv1_7x7_s2_bn(conv1_7x7_s2_out)\n        conv1_relu_7x7_out = self.conv1_relu_7x7(conv1_7x7_s2_bn_out)\n        pool1_3x3_s2_out = self.pool1_3x3_s2(conv1_relu_7x7_out)\n        conv2_3x3_reduce_out = self.conv2_3x3_reduce(pool1_3x3_s2_out)\n        conv2_3x3_reduce_bn_out = self.conv2_3x3_reduce_bn(conv2_3x3_reduce_out)\n        conv2_relu_3x3_reduce_out = self.conv2_relu_3x3_reduce(conv2_3x3_reduce_bn_out)\n        conv2_3x3_out = self.conv2_3x3(conv2_relu_3x3_reduce_out)\n        conv2_3x3_bn_out = self.conv2_3x3_bn(conv2_3x3_out)\n        conv2_relu_3x3_out = self.conv2_relu_3x3(conv2_3x3_bn_out)\n        pool2_3x3_s2_out = self.pool2_3x3_s2(conv2_relu_3x3_out)\n        inception_3a_1x1_out = self.inception_3a_1x1(pool2_3x3_s2_out)\n        inception_3a_1x1_bn_out = self.inception_3a_1x1_bn(inception_3a_1x1_out)\n        inception_3a_relu_1x1_out = self.inception_3a_relu_1x1(inception_3a_1x1_bn_out)\n        inception_3a_3x3_reduce_out = self.inception_3a_3x3_reduce(pool2_3x3_s2_out)\n        inception_3a_3x3_reduce_bn_out = self.inception_3a_3x3_reduce_bn(inception_3a_3x3_reduce_out)\n        inception_3a_relu_3x3_reduce_out = self.inception_3a_relu_3x3_reduce(inception_3a_3x3_reduce_bn_out)\n        inception_3a_3x3_out = self.inception_3a_3x3(inception_3a_relu_3x3_reduce_out)\n        inception_3a_3x3_bn_out = self.inception_3a_3x3_bn(inception_3a_3x3_out)\n        inception_3a_relu_3x3_out = self.inception_3a_relu_3x3(inception_3a_3x3_bn_out)\n        inception_3a_double_3x3_reduce_out = self.inception_3a_double_3x3_reduce(pool2_3x3_s2_out)\n        inception_3a_double_3x3_reduce_bn_out = self.inception_3a_double_3x3_reduce_bn(\n            inception_3a_double_3x3_reduce_out)\n        inception_3a_relu_double_3x3_reduce_out = self.inception_3a_relu_double_3x3_reduce(\n            inception_3a_double_3x3_reduce_bn_out)\n        inception_3a_double_3x3_1_out = self.inception_3a_double_3x3_1(inception_3a_relu_double_3x3_reduce_out)\n        inception_3a_double_3x3_1_bn_out = self.inception_3a_double_3x3_1_bn(inception_3a_double_3x3_1_out)\n        inception_3a_relu_double_3x3_1_out = self.inception_3a_relu_double_3x3_1(inception_3a_double_3x3_1_bn_out)\n        inception_3a_double_3x3_2_out = self.inception_3a_double_3x3_2(inception_3a_relu_double_3x3_1_out)\n        inception_3a_double_3x3_2_bn_out = self.inception_3a_double_3x3_2_bn(inception_3a_double_3x3_2_out)\n        inception_3a_relu_double_3x3_2_out = self.inception_3a_relu_double_3x3_2(inception_3a_double_3x3_2_bn_out)\n        inception_3a_pool_out = self.inception_3a_pool(pool2_3x3_s2_out)\n        inception_3a_pool_proj_out = self.inception_3a_pool_proj(inception_3a_pool_out)\n        inception_3a_pool_proj_bn_out = self.inception_3a_pool_proj_bn(inception_3a_pool_proj_out)\n        inception_3a_relu_pool_proj_out = self.inception_3a_relu_pool_proj(inception_3a_pool_proj_bn_out)\n        inception_3a_output_out = torch.cat(\n            [inception_3a_relu_1x1_out, inception_3a_relu_3x3_out, inception_3a_relu_double_3x3_2_out,\n             inception_3a_relu_pool_proj_out], 1)\n        inception_3b_1x1_out = self.inception_3b_1x1(inception_3a_output_out)\n        inception_3b_1x1_bn_out = self.inception_3b_1x1_bn(inception_3b_1x1_out)\n        inception_3b_relu_1x1_out = self.inception_3b_relu_1x1(inception_3b_1x1_bn_out)\n        inception_3b_3x3_reduce_out = self.inception_3b_3x3_reduce(inception_3a_output_out)\n        inception_3b_3x3_reduce_bn_out = self.inception_3b_3x3_reduce_bn(inception_3b_3x3_reduce_out)\n        inception_3b_relu_3x3_reduce_out = self.inception_3b_relu_3x3_reduce(inception_3b_3x3_reduce_bn_out)\n        inception_3b_3x3_out = self.inception_3b_3x3(inception_3b_relu_3x3_reduce_out)\n        inception_3b_3x3_bn_out = self.inception_3b_3x3_bn(inception_3b_3x3_out)\n        inception_3b_relu_3x3_out = self.inception_3b_relu_3x3(inception_3b_3x3_bn_out)\n        inception_3b_double_3x3_reduce_out = self.inception_3b_double_3x3_reduce(inception_3a_output_out)\n        inception_3b_double_3x3_reduce_bn_out = self.inception_3b_double_3x3_reduce_bn(\n            inception_3b_double_3x3_reduce_out)\n        inception_3b_relu_double_3x3_reduce_out = self.inception_3b_relu_double_3x3_reduce(\n            inception_3b_double_3x3_reduce_bn_out)\n        inception_3b_double_3x3_1_out = self.inception_3b_double_3x3_1(inception_3b_relu_double_3x3_reduce_out)\n        inception_3b_double_3x3_1_bn_out = self.inception_3b_double_3x3_1_bn(inception_3b_double_3x3_1_out)\n        inception_3b_relu_double_3x3_1_out = self.inception_3b_relu_double_3x3_1(inception_3b_double_3x3_1_bn_out)\n        inception_3b_double_3x3_2_out = self.inception_3b_double_3x3_2(inception_3b_relu_double_3x3_1_out)\n        inception_3b_double_3x3_2_bn_out = self.inception_3b_double_3x3_2_bn(inception_3b_double_3x3_2_out)\n        inception_3b_relu_double_3x3_2_out = self.inception_3b_relu_double_3x3_2(inception_3b_double_3x3_2_bn_out)\n        inception_3b_pool_out = self.inception_3b_pool(inception_3a_output_out)\n        inception_3b_pool_proj_out = self.inception_3b_pool_proj(inception_3b_pool_out)\n        inception_3b_pool_proj_bn_out = self.inception_3b_pool_proj_bn(inception_3b_pool_proj_out)\n        inception_3b_relu_pool_proj_out = self.inception_3b_relu_pool_proj(inception_3b_pool_proj_bn_out)\n        inception_3b_output_out = torch.cat(\n            [inception_3b_relu_1x1_out, inception_3b_relu_3x3_out, inception_3b_relu_double_3x3_2_out,\n             inception_3b_relu_pool_proj_out], 1)\n        inception_3c_3x3_reduce_out = self.inception_3c_3x3_reduce(inception_3b_output_out)\n        inception_3c_3x3_reduce_bn_out = self.inception_3c_3x3_reduce_bn(inception_3c_3x3_reduce_out)\n        inception_3c_relu_3x3_reduce_out = self.inception_3c_relu_3x3_reduce(inception_3c_3x3_reduce_bn_out)\n        inception_3c_3x3_out = self.inception_3c_3x3(inception_3c_relu_3x3_reduce_out)\n        inception_3c_3x3_bn_out = self.inception_3c_3x3_bn(inception_3c_3x3_out)\n        inception_3c_relu_3x3_out = self.inception_3c_relu_3x3(inception_3c_3x3_bn_out)\n        inception_3c_double_3x3_reduce_out = self.inception_3c_double_3x3_reduce(inception_3b_output_out)\n        inception_3c_double_3x3_reduce_bn_out = self.inception_3c_double_3x3_reduce_bn(\n            inception_3c_double_3x3_reduce_out)\n        inception_3c_relu_double_3x3_reduce_out = self.inception_3c_relu_double_3x3_reduce(\n            inception_3c_double_3x3_reduce_bn_out)\n        inception_3c_double_3x3_1_out = self.inception_3c_double_3x3_1(inception_3c_relu_double_3x3_reduce_out)\n        inception_3c_double_3x3_1_bn_out = self.inception_3c_double_3x3_1_bn(inception_3c_double_3x3_1_out)\n        inception_3c_relu_double_3x3_1_out = self.inception_3c_relu_double_3x3_1(inception_3c_double_3x3_1_bn_out)\n        inception_3c_double_3x3_2_out = self.inception_3c_double_3x3_2(inception_3c_relu_double_3x3_1_out)\n        inception_3c_double_3x3_2_bn_out = self.inception_3c_double_3x3_2_bn(inception_3c_double_3x3_2_out)\n        inception_3c_relu_double_3x3_2_out = self.inception_3c_relu_double_3x3_2(inception_3c_double_3x3_2_bn_out)\n        inception_3c_pool_out = self.inception_3c_pool(inception_3b_output_out)\n        inception_3c_output_out = torch.cat(\n            [inception_3c_relu_3x3_out, inception_3c_relu_double_3x3_2_out, inception_3c_pool_out], 1)\n        inception_4a_1x1_out = self.inception_4a_1x1(inception_3c_output_out)\n        inception_4a_1x1_bn_out = self.inception_4a_1x1_bn(inception_4a_1x1_out)\n        inception_4a_relu_1x1_out = self.inception_4a_relu_1x1(inception_4a_1x1_bn_out)\n        inception_4a_3x3_reduce_out = self.inception_4a_3x3_reduce(inception_3c_output_out)\n        inception_4a_3x3_reduce_bn_out = self.inception_4a_3x3_reduce_bn(inception_4a_3x3_reduce_out)\n        inception_4a_relu_3x3_reduce_out = self.inception_4a_relu_3x3_reduce(inception_4a_3x3_reduce_bn_out)\n        inception_4a_3x3_out = self.inception_4a_3x3(inception_4a_relu_3x3_reduce_out)\n        inception_4a_3x3_bn_out = self.inception_4a_3x3_bn(inception_4a_3x3_out)\n        inception_4a_relu_3x3_out = self.inception_4a_relu_3x3(inception_4a_3x3_bn_out)\n        inception_4a_double_3x3_reduce_out = self.inception_4a_double_3x3_reduce(inception_3c_output_out)\n        inception_4a_double_3x3_reduce_bn_out = self.inception_4a_double_3x3_reduce_bn(\n            inception_4a_double_3x3_reduce_out)\n        inception_4a_relu_double_3x3_reduce_out = self.inception_4a_relu_double_3x3_reduce(\n            inception_4a_double_3x3_reduce_bn_out)\n        inception_4a_double_3x3_1_out = self.inception_4a_double_3x3_1(inception_4a_relu_double_3x3_reduce_out)\n        inception_4a_double_3x3_1_bn_out = self.inception_4a_double_3x3_1_bn(inception_4a_double_3x3_1_out)\n        inception_4a_relu_double_3x3_1_out = self.inception_4a_relu_double_3x3_1(inception_4a_double_3x3_1_bn_out)\n        inception_4a_double_3x3_2_out = self.inception_4a_double_3x3_2(inception_4a_relu_double_3x3_1_out)\n        inception_4a_double_3x3_2_bn_out = self.inception_4a_double_3x3_2_bn(inception_4a_double_3x3_2_out)\n        inception_4a_relu_double_3x3_2_out = self.inception_4a_relu_double_3x3_2(inception_4a_double_3x3_2_bn_out)\n        inception_4a_pool_out = self.inception_4a_pool(inception_3c_output_out)\n        inception_4a_pool_proj_out = self.inception_4a_pool_proj(inception_4a_pool_out)\n        inception_4a_pool_proj_bn_out = self.inception_4a_pool_proj_bn(inception_4a_pool_proj_out)\n        inception_4a_relu_pool_proj_out = self.inception_4a_relu_pool_proj(inception_4a_pool_proj_bn_out)\n        inception_4a_output_out = torch.cat(\n            [inception_4a_relu_1x1_out, inception_4a_relu_3x3_out, inception_4a_relu_double_3x3_2_out,\n             inception_4a_relu_pool_proj_out], 1)\n        inception_4b_1x1_out = self.inception_4b_1x1(inception_4a_output_out)\n        inception_4b_1x1_bn_out = self.inception_4b_1x1_bn(inception_4b_1x1_out)\n        inception_4b_relu_1x1_out = self.inception_4b_relu_1x1(inception_4b_1x1_bn_out)\n        inception_4b_3x3_reduce_out = self.inception_4b_3x3_reduce(inception_4a_output_out)\n        inception_4b_3x3_reduce_bn_out = self.inception_4b_3x3_reduce_bn(inception_4b_3x3_reduce_out)\n        inception_4b_relu_3x3_reduce_out = self.inception_4b_relu_3x3_reduce(inception_4b_3x3_reduce_bn_out)\n        inception_4b_3x3_out = self.inception_4b_3x3(inception_4b_relu_3x3_reduce_out)\n        inception_4b_3x3_bn_out = self.inception_4b_3x3_bn(inception_4b_3x3_out)\n        inception_4b_relu_3x3_out = self.inception_4b_relu_3x3(inception_4b_3x3_bn_out)\n        inception_4b_double_3x3_reduce_out = self.inception_4b_double_3x3_reduce(inception_4a_output_out)\n        inception_4b_double_3x3_reduce_bn_out = self.inception_4b_double_3x3_reduce_bn(\n            inception_4b_double_3x3_reduce_out)\n        inception_4b_relu_double_3x3_reduce_out = self.inception_4b_relu_double_3x3_reduce(\n            inception_4b_double_3x3_reduce_bn_out)\n        inception_4b_double_3x3_1_out = self.inception_4b_double_3x3_1(inception_4b_relu_double_3x3_reduce_out)\n        inception_4b_double_3x3_1_bn_out = self.inception_4b_double_3x3_1_bn(inception_4b_double_3x3_1_out)\n        inception_4b_relu_double_3x3_1_out = self.inception_4b_relu_double_3x3_1(inception_4b_double_3x3_1_bn_out)\n        inception_4b_double_3x3_2_out = self.inception_4b_double_3x3_2(inception_4b_relu_double_3x3_1_out)\n        inception_4b_double_3x3_2_bn_out = self.inception_4b_double_3x3_2_bn(inception_4b_double_3x3_2_out)\n        inception_4b_relu_double_3x3_2_out = self.inception_4b_relu_double_3x3_2(inception_4b_double_3x3_2_bn_out)\n        inception_4b_pool_out = self.inception_4b_pool(inception_4a_output_out)\n        inception_4b_pool_proj_out = self.inception_4b_pool_proj(inception_4b_pool_out)\n        inception_4b_pool_proj_bn_out = self.inception_4b_pool_proj_bn(inception_4b_pool_proj_out)\n        inception_4b_relu_pool_proj_out = self.inception_4b_relu_pool_proj(inception_4b_pool_proj_bn_out)\n        inception_4b_output_out = torch.cat(\n            [inception_4b_relu_1x1_out, inception_4b_relu_3x3_out, inception_4b_relu_double_3x3_2_out,\n             inception_4b_relu_pool_proj_out], 1)\n        inception_4c_1x1_out = self.inception_4c_1x1(inception_4b_output_out)\n        inception_4c_1x1_bn_out = self.inception_4c_1x1_bn(inception_4c_1x1_out)\n        inception_4c_relu_1x1_out = self.inception_4c_relu_1x1(inception_4c_1x1_bn_out)\n        inception_4c_3x3_reduce_out = self.inception_4c_3x3_reduce(inception_4b_output_out)\n        inception_4c_3x3_reduce_bn_out = self.inception_4c_3x3_reduce_bn(inception_4c_3x3_reduce_out)\n        inception_4c_relu_3x3_reduce_out = self.inception_4c_relu_3x3_reduce(inception_4c_3x3_reduce_bn_out)\n        inception_4c_3x3_out = self.inception_4c_3x3(inception_4c_relu_3x3_reduce_out)\n        inception_4c_3x3_bn_out = self.inception_4c_3x3_bn(inception_4c_3x3_out)\n        inception_4c_relu_3x3_out = self.inception_4c_relu_3x3(inception_4c_3x3_bn_out)\n        inception_4c_double_3x3_reduce_out = self.inception_4c_double_3x3_reduce(inception_4b_output_out)\n        inception_4c_double_3x3_reduce_bn_out = self.inception_4c_double_3x3_reduce_bn(\n            inception_4c_double_3x3_reduce_out)\n        inception_4c_relu_double_3x3_reduce_out = self.inception_4c_relu_double_3x3_reduce(\n            inception_4c_double_3x3_reduce_bn_out)\n        inception_4c_double_3x3_1_out = self.inception_4c_double_3x3_1(inception_4c_relu_double_3x3_reduce_out)\n        inception_4c_double_3x3_1_bn_out = self.inception_4c_double_3x3_1_bn(inception_4c_double_3x3_1_out)\n        inception_4c_relu_double_3x3_1_out = self.inception_4c_relu_double_3x3_1(inception_4c_double_3x3_1_bn_out)\n        inception_4c_double_3x3_2_out = self.inception_4c_double_3x3_2(inception_4c_relu_double_3x3_1_out)\n        inception_4c_double_3x3_2_bn_out = self.inception_4c_double_3x3_2_bn(inception_4c_double_3x3_2_out)\n        inception_4c_relu_double_3x3_2_out = self.inception_4c_relu_double_3x3_2(inception_4c_double_3x3_2_bn_out)\n        inception_4c_pool_out = self.inception_4c_pool(inception_4b_output_out)\n        inception_4c_pool_proj_out = self.inception_4c_pool_proj(inception_4c_pool_out)\n        inception_4c_pool_proj_bn_out = self.inception_4c_pool_proj_bn(inception_4c_pool_proj_out)\n        inception_4c_relu_pool_proj_out = self.inception_4c_relu_pool_proj(inception_4c_pool_proj_bn_out)\n        inception_4c_output_out = torch.cat(\n            [inception_4c_relu_1x1_out, inception_4c_relu_3x3_out, inception_4c_relu_double_3x3_2_out,\n             inception_4c_relu_pool_proj_out], 1)\n        inception_4d_1x1_out = self.inception_4d_1x1(inception_4c_output_out)\n        inception_4d_1x1_bn_out = self.inception_4d_1x1_bn(inception_4d_1x1_out)\n        inception_4d_relu_1x1_out = self.inception_4d_relu_1x1(inception_4d_1x1_bn_out)\n        inception_4d_3x3_reduce_out = self.inception_4d_3x3_reduce(inception_4c_output_out)\n        inception_4d_3x3_reduce_bn_out = self.inception_4d_3x3_reduce_bn(inception_4d_3x3_reduce_out)\n        inception_4d_relu_3x3_reduce_out = self.inception_4d_relu_3x3_reduce(inception_4d_3x3_reduce_bn_out)\n        inception_4d_3x3_out = self.inception_4d_3x3(inception_4d_relu_3x3_reduce_out)\n        inception_4d_3x3_bn_out = self.inception_4d_3x3_bn(inception_4d_3x3_out)\n        inception_4d_relu_3x3_out = self.inception_4d_relu_3x3(inception_4d_3x3_bn_out)\n        inception_4d_double_3x3_reduce_out = self.inception_4d_double_3x3_reduce(inception_4c_output_out)\n        inception_4d_double_3x3_reduce_bn_out = self.inception_4d_double_3x3_reduce_bn(\n            inception_4d_double_3x3_reduce_out)\n        inception_4d_relu_double_3x3_reduce_out = self.inception_4d_relu_double_3x3_reduce(\n            inception_4d_double_3x3_reduce_bn_out)\n        inception_4d_double_3x3_1_out = self.inception_4d_double_3x3_1(inception_4d_relu_double_3x3_reduce_out)\n        inception_4d_double_3x3_1_bn_out = self.inception_4d_double_3x3_1_bn(inception_4d_double_3x3_1_out)\n        inception_4d_relu_double_3x3_1_out = self.inception_4d_relu_double_3x3_1(inception_4d_double_3x3_1_bn_out)\n        inception_4d_double_3x3_2_out = self.inception_4d_double_3x3_2(inception_4d_relu_double_3x3_1_out)\n        inception_4d_double_3x3_2_bn_out = self.inception_4d_double_3x3_2_bn(inception_4d_double_3x3_2_out)\n        inception_4d_relu_double_3x3_2_out = self.inception_4d_relu_double_3x3_2(inception_4d_double_3x3_2_bn_out)\n        inception_4d_pool_out = self.inception_4d_pool(inception_4c_output_out)\n        inception_4d_pool_proj_out = self.inception_4d_pool_proj(inception_4d_pool_out)\n        inception_4d_pool_proj_bn_out = self.inception_4d_pool_proj_bn(inception_4d_pool_proj_out)\n        inception_4d_relu_pool_proj_out = self.inception_4d_relu_pool_proj(inception_4d_pool_proj_bn_out)\n        inception_4d_output_out = torch.cat(\n            [inception_4d_relu_1x1_out, inception_4d_relu_3x3_out, inception_4d_relu_double_3x3_2_out,\n             inception_4d_relu_pool_proj_out], 1)\n        inception_4e_3x3_reduce_out = self.inception_4e_3x3_reduce(inception_4d_output_out)\n        inception_4e_3x3_reduce_bn_out = self.inception_4e_3x3_reduce_bn(inception_4e_3x3_reduce_out)\n        inception_4e_relu_3x3_reduce_out = self.inception_4e_relu_3x3_reduce(inception_4e_3x3_reduce_bn_out)\n        inception_4e_3x3_out = self.inception_4e_3x3(inception_4e_relu_3x3_reduce_out)\n        inception_4e_3x3_bn_out = self.inception_4e_3x3_bn(inception_4e_3x3_out)\n        inception_4e_relu_3x3_out = self.inception_4e_relu_3x3(inception_4e_3x3_bn_out)\n        inception_4e_double_3x3_reduce_out = self.inception_4e_double_3x3_reduce(inception_4d_output_out)\n        inception_4e_double_3x3_reduce_bn_out = self.inception_4e_double_3x3_reduce_bn(\n            inception_4e_double_3x3_reduce_out)\n        inception_4e_relu_double_3x3_reduce_out = self.inception_4e_relu_double_3x3_reduce(\n            inception_4e_double_3x3_reduce_bn_out)\n        inception_4e_double_3x3_1_out = self.inception_4e_double_3x3_1(inception_4e_relu_double_3x3_reduce_out)\n        inception_4e_double_3x3_1_bn_out = self.inception_4e_double_3x3_1_bn(inception_4e_double_3x3_1_out)\n        inception_4e_relu_double_3x3_1_out = self.inception_4e_relu_double_3x3_1(inception_4e_double_3x3_1_bn_out)\n        inception_4e_double_3x3_2_out = self.inception_4e_double_3x3_2(inception_4e_relu_double_3x3_1_out)\n        inception_4e_double_3x3_2_bn_out = self.inception_4e_double_3x3_2_bn(inception_4e_double_3x3_2_out)\n        inception_4e_relu_double_3x3_2_out = self.inception_4e_relu_double_3x3_2(inception_4e_double_3x3_2_bn_out)\n        inception_4e_pool_out = self.inception_4e_pool(inception_4d_output_out)\n        inception_4e_output_out = torch.cat(\n            [inception_4e_relu_3x3_out, inception_4e_relu_double_3x3_2_out, inception_4e_pool_out], 1)\n        inception_5a_1x1_out = self.inception_5a_1x1(inception_4e_output_out)\n        inception_5a_1x1_bn_out = self.inception_5a_1x1_bn(inception_5a_1x1_out)\n        inception_5a_relu_1x1_out = self.inception_5a_relu_1x1(inception_5a_1x1_bn_out)\n        inception_5a_3x3_reduce_out = self.inception_5a_3x3_reduce(inception_4e_output_out)\n        inception_5a_3x3_reduce_bn_out = self.inception_5a_3x3_reduce_bn(inception_5a_3x3_reduce_out)\n        inception_5a_relu_3x3_reduce_out = self.inception_5a_relu_3x3_reduce(inception_5a_3x3_reduce_bn_out)\n        inception_5a_3x3_out = self.inception_5a_3x3(inception_5a_relu_3x3_reduce_out)\n        inception_5a_3x3_bn_out = self.inception_5a_3x3_bn(inception_5a_3x3_out)\n        inception_5a_relu_3x3_out = self.inception_5a_relu_3x3(inception_5a_3x3_bn_out)\n        inception_5a_double_3x3_reduce_out = self.inception_5a_double_3x3_reduce(inception_4e_output_out)\n        inception_5a_double_3x3_reduce_bn_out = self.inception_5a_double_3x3_reduce_bn(\n            inception_5a_double_3x3_reduce_out)\n        inception_5a_relu_double_3x3_reduce_out = self.inception_5a_relu_double_3x3_reduce(\n            inception_5a_double_3x3_reduce_bn_out)\n        inception_5a_double_3x3_1_out = self.inception_5a_double_3x3_1(inception_5a_relu_double_3x3_reduce_out)\n        inception_5a_double_3x3_1_bn_out = self.inception_5a_double_3x3_1_bn(inception_5a_double_3x3_1_out)\n        inception_5a_relu_double_3x3_1_out = self.inception_5a_relu_double_3x3_1(inception_5a_double_3x3_1_bn_out)\n        inception_5a_double_3x3_2_out = self.inception_5a_double_3x3_2(inception_5a_relu_double_3x3_1_out)\n        inception_5a_double_3x3_2_bn_out = self.inception_5a_double_3x3_2_bn(inception_5a_double_3x3_2_out)\n        inception_5a_relu_double_3x3_2_out = self.inception_5a_relu_double_3x3_2(inception_5a_double_3x3_2_bn_out)\n        inception_5a_pool_out = self.inception_5a_pool(inception_4e_output_out)\n        inception_5a_pool_proj_out = self.inception_5a_pool_proj(inception_5a_pool_out)\n        inception_5a_pool_proj_bn_out = self.inception_5a_pool_proj_bn(inception_5a_pool_proj_out)\n        inception_5a_relu_pool_proj_out = self.inception_5a_relu_pool_proj(inception_5a_pool_proj_bn_out)\n        inception_5a_output_out = torch.cat(\n            [inception_5a_relu_1x1_out, inception_5a_relu_3x3_out, inception_5a_relu_double_3x3_2_out,\n             inception_5a_relu_pool_proj_out], 1)\n        inception_5b_1x1_out = self.inception_5b_1x1(inception_5a_output_out)\n        inception_5b_1x1_bn_out = self.inception_5b_1x1_bn(inception_5b_1x1_out)\n        inception_5b_relu_1x1_out = self.inception_5b_relu_1x1(inception_5b_1x1_bn_out)\n        inception_5b_3x3_reduce_out = self.inception_5b_3x3_reduce(inception_5a_output_out)\n        inception_5b_3x3_reduce_bn_out = self.inception_5b_3x3_reduce_bn(inception_5b_3x3_reduce_out)\n        inception_5b_relu_3x3_reduce_out = self.inception_5b_relu_3x3_reduce(inception_5b_3x3_reduce_bn_out)\n        inception_5b_3x3_out = self.inception_5b_3x3(inception_5b_relu_3x3_reduce_out)\n        inception_5b_3x3_bn_out = self.inception_5b_3x3_bn(inception_5b_3x3_out)\n        inception_5b_relu_3x3_out = self.inception_5b_relu_3x3(inception_5b_3x3_bn_out)\n        inception_5b_double_3x3_reduce_out = self.inception_5b_double_3x3_reduce(inception_5a_output_out)\n        inception_5b_double_3x3_reduce_bn_out = self.inception_5b_double_3x3_reduce_bn(\n            inception_5b_double_3x3_reduce_out)\n        inception_5b_relu_double_3x3_reduce_out = self.inception_5b_relu_double_3x3_reduce(\n            inception_5b_double_3x3_reduce_bn_out)\n        inception_5b_double_3x3_1_out = self.inception_5b_double_3x3_1(inception_5b_relu_double_3x3_reduce_out)\n        inception_5b_double_3x3_1_bn_out = self.inception_5b_double_3x3_1_bn(inception_5b_double_3x3_1_out)\n        inception_5b_relu_double_3x3_1_out = self.inception_5b_relu_double_3x3_1(inception_5b_double_3x3_1_bn_out)\n        inception_5b_double_3x3_2_out = self.inception_5b_double_3x3_2(inception_5b_relu_double_3x3_1_out)\n        inception_5b_double_3x3_2_bn_out = self.inception_5b_double_3x3_2_bn(inception_5b_double_3x3_2_out)\n        inception_5b_relu_double_3x3_2_out = self.inception_5b_relu_double_3x3_2(inception_5b_double_3x3_2_bn_out)\n        inception_5b_pool_out = self.inception_5b_pool(inception_5a_output_out)\n        inception_5b_pool_proj_out = self.inception_5b_pool_proj(inception_5b_pool_out)\n        inception_5b_pool_proj_bn_out = self.inception_5b_pool_proj_bn(inception_5b_pool_proj_out)\n        inception_5b_relu_pool_proj_out = self.inception_5b_relu_pool_proj(inception_5b_pool_proj_bn_out)\n        inception_5b_output_out = torch.cat(\n            [inception_5b_relu_1x1_out, inception_5b_relu_3x3_out, inception_5b_relu_double_3x3_2_out,\n             inception_5b_relu_pool_proj_out], 1)\n        return inception_5b_output_out\n\n    def logits(self, features):\n        x = F.adaptive_max_pool2d(features, output_size=1)\n        x = x.view(x.size(0), -1)\n        return x\n\n    def forward(self, input):\n        x = self.features(input)\n        x = self.logits(x)\n        return x\n\n    def load_param(self, model_path):\n        param_dict = torch.load(model_path)\n        for i in param_dict:\n            if 'last_linear' in i:\n                continue\n            self.state_dict()[i].copy_(param_dict[i])\n"
  },
  {
    "path": "ret_benchmark/modeling/backbone/build.py",
    "content": "from ret_benchmark.modeling.registry import BACKBONES\n\nfrom .bninception import BNInception\nfrom .resnet import ResNet50\n\n\ndef build_backbone(cfg):\n    assert cfg.MODEL.BACKBONE.NAME in BACKBONES, \\\n        f\"backbone {cfg.MODEL.BACKBONE} is not registered in registry : {BACKBONES.keys()}\"\n    return BACKBONES[cfg.MODEL.BACKBONE.NAME]()\n"
  },
  {
    "path": "ret_benchmark/modeling/backbone/resnet.py",
    "content": "from __future__ import absolute_import, division, print_function\n\nimport torch\nimport torch.nn as nn\nimport torchvision.models as models\nfrom ret_benchmark.modeling import registry\n\n\n@registry.BACKBONES.register('resnet50')\nclass ResNet50(nn.Module):\n\n    def __init__(self):\n        super(ResNet50, self).__init__()\n        self.model = models.resnet50(pretrained=True)\n\n        for module in filter(lambda m: type(m) == nn.BatchNorm2d, self.model.modules()):\n            module.eval()\n            module.train = lambda _: None\n\n    def forward(self, x):\n        x = self.model.conv1(x)\n        x = self.model.bn1(x)\n        x = self.model.relu(x)\n        x = self.model.maxpool(x)\n\n        x = self.model.layer1(x)\n        x = self.model.layer2(x)\n        x = self.model.layer3(x)\n        x = self.model.layer4(x)\n\n        x = self.model.avgpool(x)\n        x = x.view(x.size(0), -1)\n        # x = self.model.fc(x)  --remove\n        return x\n\n    def load_param(self, model_path):\n        param_dict = torch.load(model_path)\n        for i in param_dict:\n            if 'last_linear' in i:\n                continue\n            self.model.state_dict()[i].copy_(param_dict[i])\n\n"
  },
  {
    "path": "ret_benchmark/modeling/build.py",
    "content": "# Copyright (c) Malong Technologies Co., Ltd.\n# All rights reserved.\n#\n# Contact: github@malong.com\n#\n# This source code is licensed under the LICENSE file in the root directory of this source tree.\n\n\nimport os\nfrom collections import OrderedDict\n\nimport torch\nfrom torch.nn.modules import Sequential\n\nfrom .backbone import build_backbone\nfrom .heads import build_head\n\n\ndef build_model(cfg):\n    backbone = build_backbone(cfg)\n    head = build_head(cfg)\n\n    model = Sequential(OrderedDict([\n        ('backbone', backbone),\n        ('head', head)\n    ]))\n\n    if cfg.MODEL.PRETRAIN == 'imagenet':\n        print('Loading imagenet pretrianed model ...')\n        pretrained_path = os.path.expanduser(cfg.MODEL.PRETRIANED_PATH[cfg.MODEL.BACKBONE.NAME])\n        model.backbone.load_param(pretrained_path)\n    elif os.path.exists(cfg.MODEL.PRETRAIN):\n        ckp = torch.load(cfg.MODEL.PRETRAIN)\n        model.load_state_dict(ckp['model'])\n    return model\n"
  },
  {
    "path": "ret_benchmark/modeling/heads/__init__.py",
    "content": "# Copyright (c) Malong Technologies Co., Ltd.\n# All rights reserved.\n#\n# Contact: github@malong.com\n#\n# This source code is licensed under the LICENSE file in the root directory of this source tree.\n\nfrom .build import build_head\n"
  },
  {
    "path": "ret_benchmark/modeling/heads/build.py",
    "content": "# Copyright (c) Malong Technologies Co., Ltd.\n# All rights reserved.\n#\n# Contact: github@malong.com\n#\n# This source code is licensed under the LICENSE file in the root directory of this source tree.\n\nfrom ret_benchmark.modeling.registry import HEADS\n\nfrom .linear_norm import LinearNorm\n\n\ndef build_head(cfg):\n    assert cfg.MODEL.HEAD.NAME in HEADS, f\"head {cfg.MODEL.HEAD.NAME} is not defined\"\n    return HEADS[cfg.MODEL.HEAD.NAME](cfg, in_channels=1024 if cfg.MODEL.BACKBONE.NAME == 'bninception' else 2048)\n\n"
  },
  {
    "path": "ret_benchmark/modeling/heads/linear_norm.py",
    "content": "# Copyright (c) Malong Technologies Co., Ltd.\n# All rights reserved.\n#\n# Contact: github@malong.com\n#\n# This source code is licensed under the LICENSE file in the root directory of this source tree.\n\nimport torch\nfrom torch import nn\n\nfrom ret_benchmark.modeling.registry import HEADS\nfrom ret_benchmark.utils.init_methods import weights_init_kaiming\n\n\n@HEADS.register('linear_norm')\nclass LinearNorm(nn.Module):\n    def __init__(self, cfg, in_channels):\n        super(LinearNorm, self).__init__()\n        self.fc = nn.Linear(in_channels, cfg.MODEL.HEAD.DIM)\n        self.fc.apply(weights_init_kaiming)\n\n    def forward(self, x):\n        x = self.fc(x)\n        x = nn.functional.normalize(x, p=2, dim=1)\n        return x\n"
  },
  {
    "path": "ret_benchmark/modeling/registry.py",
    "content": "# Copyright (c) Malong Technologies Co., Ltd.\n# All rights reserved.\n#\n# Contact: github@malong.com\n#\n# This source code is licensed under the LICENSE file in the root directory of this source tree.\n\n\nfrom ret_benchmark.utils.registry import Registry\n\nBACKBONES = Registry()\nHEADS = Registry()\n"
  },
  {
    "path": "ret_benchmark/modeling/xbm.py",
    "content": "# Copyright (c) Malong Technologies Co., Ltd.\n# All rights reserved.\n#\n# Contact: github@malong.com\n#\n# This source code is licensed under the LICENSE file in the root directory of this source tree.\n\nimport torch\nimport tqdm\nfrom ret_benchmark.data.build import build_memory_data\n\n\nclass XBM:\n    def __init__(self, cfg, model):\n        self.ratio = cfg.MEMORY.RATIO\n        # init memory\n        self.feats = list()\n        self.labels = list()\n        self.indices = list()\n        model.train()\n        for images, labels, indices in build_memory_data(cfg):\n            with torch.no_grad():\n                feat = model(images.cuda())\n                self.feats.append(feat)\n                self.labels.append(labels.cuda())\n                self.indices.append(indices.cuda())\n        self.feats = torch.cat(self.feats, dim=0)\n        self.labels = torch.cat(self.labels, dim=0)\n        self.indices = torch.cat(self.indices, dim=0)\n        # if memory_ratio != 1.0 -> random sample init queue_mask to mimic fixed queue size\n        if self.ratio != 1.0:\n            rand_init_idx = torch.randperm(int(self.indices.shape[0] * self.ratio)).cuda()\n            self.queue_mask = self.indices[rand_init_idx]\n\n    def enqueue_dequeue(self, feats, indices):\n        self.feats.data[indices] = feats\n        if self.ratio != 1.0:\n            # enqueue\n            self.queue_mask = torch.cat((self.queue_mask, indices.cuda()), dim=0)\n            # dequeue\n            self.queue_mask = self.queue_mask[-int(self.indices.shape[0] * self.ratio):]\n\n    def get(self):\n        if self.ratio != 1.0:\n            return self.feats[self.queue_mask], self.labels[self.queue_mask]\n        else:\n            return self.feats, self.labels\n"
  },
  {
    "path": "ret_benchmark/solver/__init__.py",
    "content": "# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.\nfrom .build import build_optimizer\nfrom .build import build_lr_scheduler\nfrom .lr_scheduler import WarmupMultiStepLR\n"
  },
  {
    "path": "ret_benchmark/solver/build.py",
    "content": "import torch\n\nfrom .lr_scheduler import WarmupMultiStepLR\n\n\ndef build_optimizer(cfg, model):\n    params = []\n    for key, value in model.named_parameters():\n        if not value.requires_grad:\n            continue\n        lr_mul = 1.0\n        if \"backbone\" in key:\n            lr_mul = 0.1\n        params += [{\"params\": [value], \"lr_mul\": lr_mul}]\n    optimizer = getattr(torch.optim, cfg.SOLVER.OPTIMIZER_NAME)(params,\n                                                                lr=cfg.SOLVER.BASE_LR,\n                                                                weight_decay=cfg.SOLVER.WEIGHT_DECAY)\n    return optimizer\n\n\ndef build_lr_scheduler(cfg, optimizer):\n    return WarmupMultiStepLR(\n        optimizer,\n        cfg.SOLVER.STEPS,\n        cfg.SOLVER.GAMMA,\n        warmup_factor=cfg.SOLVER.WARMUP_FACTOR,\n        warmup_iters=cfg.SOLVER.WARMUP_ITERS,\n        warmup_method=cfg.SOLVER.WARMUP_METHOD,\n    )\n"
  },
  {
    "path": "ret_benchmark/solver/lr_scheduler.py",
    "content": "from bisect import bisect_right\n\nimport torch\n\n\nclass WarmupMultiStepLR(torch.optim.lr_scheduler._LRScheduler):\n    def __init__(\n            self,\n            optimizer,\n            milestones,\n            gamma=0.1,\n            warmup_factor=1.0 / 3,\n            warmup_iters=500,\n            warmup_method=\"linear\",\n            last_epoch=-1,\n    ):\n        if not list(milestones) == sorted(milestones):\n            raise ValueError(\n                \"Milestones should be a list of\" \" increasing integers. Got {}\",\n                milestones,\n            )\n\n        if warmup_method not in (\"constant\", \"linear\"):\n            raise ValueError(\n                \"Only 'constant' or 'linear' warmup_method accepted\"\n                \"got {}\".format(warmup_method)\n            )\n        self.milestones = milestones\n        self.gamma = gamma\n        self.warmup_factor = warmup_factor\n        self.warmup_iters = warmup_iters\n        self.warmup_method = warmup_method\n        super(WarmupMultiStepLR, self).__init__(optimizer, last_epoch)\n\n    def get_lr(self):\n        warmup_factor = 1\n        if self.last_epoch < self.warmup_iters:\n            if self.warmup_method == \"constant\":\n                warmup_factor = self.warmup_factor\n            elif self.warmup_method == \"linear\":\n                alpha = float(self.last_epoch) / self.warmup_iters\n                warmup_factor = self.warmup_factor * (1 - alpha) + alpha\n        return [\n            base_lr * warmup_factor * self.gamma ** bisect_right(\n                self.milestones,\n                self.last_epoch\n            )\n            for base_lr in self.base_lrs\n        ]\n"
  },
  {
    "path": "ret_benchmark/utils/checkpoint.py",
    "content": "# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.\nimport logging\nimport os\n\nimport torch\nfrom ret_benchmark.utils.model_serialization import load_state_dict\n\n\nclass Checkpointer(object):\n    def __init__(\n        self,\n        model,\n        optimizer=None,\n        scheduler=None,\n        save_dir=\"\",\n        save_to_disk=None,\n        logger=None,\n    ):\n        self.model = model\n        self.optimizer = optimizer\n        self.scheduler = scheduler\n        self.save_dir = save_dir\n        self.save_to_disk = save_to_disk\n        if logger is None:\n            logger = logging.getLogger(__name__)\n        self.logger = logger\n\n    def save(self, name):\n        if not self.save_dir:\n            return\n\n        data = {}\n        data[\"model\"] = self.model.state_dict()\n        if self.optimizer is not None:\n            data[\"optimizer\"] = self.optimizer.state_dict()\n        if self.scheduler is not None:\n            data[\"scheduler\"] = self.scheduler.state_dict()\n\n        save_file = os.path.join(self.save_dir, \"{}.pth\".format(name))\n        self.logger.info(\"Saving checkpoint to {}\".format(save_file))\n        torch.save(data, save_file)\n\n    def load(self, f=None):\n        if self.has_checkpoint():\n            # override argument with existing checkpoint\n            f = self.get_checkpoint_file()\n        if not f:\n            # no checkpoint could be found\n            self.logger.info(\"No checkpoint found. Initializing model from scratch\")\n            return {}\n        self.logger.info(\"Loading checkpoint from {}\".format(f))\n        checkpoint = self._load_file(f)\n        self._load_model(checkpoint)\n        if \"optimizer\" in checkpoint and self.optimizer:\n            self.logger.info(\"Loading optimizer from {}\".format(f))\n            self.optimizer.load_state_dict(checkpoint.pop(\"optimizer\"))\n        if \"scheduler\" in checkpoint and self.scheduler:\n            self.logger.info(\"Loading scheduler from {}\".format(f))\n            self.scheduler.load_state_dict(checkpoint.pop(\"scheduler\"))\n\n        # return any further checkpoint data\n        return checkpoint\n\n    def has_checkpoint(self):\n        save_file = os.path.join(self.save_dir, \"last_checkpoint\")\n        return os.path.exists(save_file)\n\n    def get_checkpoint_file(self):\n        save_file = os.path.join(self.save_dir, \"last_checkpoint\")\n        try:\n            with open(save_file, \"r\") as f:\n                last_saved = f.read()\n                last_saved = last_saved.strip()\n        except IOError:\n            # if file doesn't exist, maybe because it has just been\n            # deleted by a separate process\n            last_saved = \"\"\n        return last_saved\n\n    def tag_last_checkpoint(self, last_filename):\n        save_file = os.path.join(self.save_dir, \"last_checkpoint\")\n        with open(save_file, \"w\") as f:\n            f.write(last_filename)\n\n    def _load_file(self, f):\n        return torch.load(f, map_location=torch.device(\"cpu\"))\n\n    def _load_model(self, checkpoint):\n        load_state_dict(self.model, checkpoint.pop(\"model\"))\n"
  },
  {
    "path": "ret_benchmark/utils/config_util.py",
    "content": "from __future__ import (absolute_import, division, print_function,\n                        unicode_literals)\n\nimport copy\nimport os\n\nfrom ret_benchmark.config import cfg as g_cfg\n\n\ndef get_config_root_path():\n    ''' Path to configs for unit tests '''\n    # cur_file_dir is root/tests/env_tests\n    cur_file_dir = os.path.dirname(os.path.abspath(os.path.realpath(__file__)))\n    ret = os.path.dirname(os.path.dirname(cur_file_dir))\n    ret = os.path.join(ret, \"configs\")\n    return ret\n\n\ndef load_config(rel_path):\n    ''' Load config from file path specified as path relative to config_root '''\n    cfg_path = os.path.join(get_config_root_path(), rel_path)\n    return load_config_from_file(cfg_path)\n\n\ndef load_config_from_file(file_path):\n    ''' Load config from file path specified as absolute path '''\n    ret = copy.deepcopy(g_cfg)\n    ret.merge_from_file(file_path)\n    return ret\n"
  },
  {
    "path": "ret_benchmark/utils/feat_extractor.py",
    "content": "# Copyright (c) Malong Technologies Co., Ltd.\n# All rights reserved.\n#\n# Contact: github@malong.com\n#\n# This source code is licensed under the LICENSE file in the root directory of this source tree.\n\nimport torch\nimport numpy as np\n\n\ndef feat_extractor(model, data_loader, logger=None):\n    model.eval()\n    feats = list()\n\n    for i, batch in enumerate(data_loader):\n        imgs = batch[0].cuda()\n\n        with torch.no_grad():\n            out = model(imgs).data.cpu().numpy()\n            feats.append(out)\n\n        if logger is not None and (i + 1) % 100 == 0:\n            logger.debug(f'Extract Features: [{i + 1}/{len(data_loader)}]')\n        del out\n    feats = np.vstack(feats)\n    return feats\n"
  },
  {
    "path": "ret_benchmark/utils/freeze_bn.py",
    "content": "# Copyright (c) Malong Technologies Co., Ltd.\n# All rights reserved.\n#\n# Contact: github@malong.com\n#\n# This source code is licensed under the LICENSE file in the root directory of this source tree.\n\n# Batch Norm Freezer\n# Note: adds an additional 2% improvement on CUB (on others benchmarks, it brings no effect)\n\ndef set_bn_eval(m):\n    classname = m.__class__.__name__\n    if classname.find('BatchNorm') != -1:\n        m.eval()\n"
  },
  {
    "path": "ret_benchmark/utils/img_reader.py",
    "content": "import os.path as osp\nfrom PIL import Image\n\n\ndef read_image(img_path, mode='RGB'):\n    \"\"\"Keep reading image until succeed.\n    This can avoid IOError incurred by heavy IO process.\"\"\"\n    got_img = False\n    if not osp.exists(img_path):\n        raise IOError(f\"{img_path} does not exist\")\n    while not got_img:\n        try:\n            img = Image.open(img_path).convert(\"RGB\")\n            if mode == \"BGR\":\n                r, g, b = img.split()\n                img = Image.merge(\"RGB\", (b, g, r))\n            got_img = True\n        except IOError:\n            print(f\"IOError incurred when reading '{img_path}'. Will redo.\")\n            pass\n    return img\n"
  },
  {
    "path": "ret_benchmark/utils/init_methods.py",
    "content": "# Copyright (c) Malong Technologies Co., Ltd.\n# All rights reserved.\n#\n# Contact: github@malong.com\n#\n# This source code is licensed under the LICENSE file in the root directory of this source tree.\n\nimport torch\nfrom torch import nn\n\n\ndef weights_init_kaiming(m):\n    classname = m.__class__.__name__\n    if classname.find('Linear') != -1:\n        nn.init.kaiming_normal_(m.weight, a=0, mode='fan_out')\n        nn.init.constant_(m.bias, 0.0)\n    elif classname.find('Conv') != -1:\n        nn.init.kaiming_normal_(m.weight, a=0, mode='fan_in')\n        if m.bias is not None:\n            nn.init.constant_(m.bias, 0.0)\n    elif classname.find('BatchNorm') != -1:\n        if m.affine:\n            nn.init.constant_(m.weight, 1.0)\n            nn.init.constant_(m.bias, 0.0)\n\n\ndef weights_init_classifier(m):\n    classname = m.__class__.__name__\n    if classname.find('Linear') != -1:\n        nn.init.normal_(m.weight, std=0.001)\n        if m.bias is not None:\n            nn.init.constant_(m.bias, 0.0)\n"
  },
  {
    "path": "ret_benchmark/utils/logger.py",
    "content": "# Copyright (c) Malong Technologies Co., Ltd.\n# All rights reserved.\n#\n# Contact: github@malong.com\n#\n# This source code is licensed under the LICENSE file in the root directory of this source tree.\n\nimport os\nimport sys\nimport logging\n\n_streams = {\n    \"stdout\": sys.stdout\n}\n\n\ndef setup_logger(name: str, level: int, stream: str = \"stdout\") -> logging.Logger:\n    global _streams\n    if stream not in _streams:\n        log_folder = os.path.dirname(stream)\n        os.makedirs(log_folder, exist_ok=True)\n        _streams[stream] = open(stream, 'w')\n    logger = logging.getLogger(name)\n    logger.propagate = False\n    logger.setLevel(level)\n\n    sh = logging.StreamHandler(stream=_streams[stream])\n    sh.setLevel(level)\n    formatter = logging.Formatter(\"%(asctime)s %(name)s %(levelname)s: %(message)s\")\n    sh.setFormatter(formatter)\n    logger.addHandler(sh)\n    return logger\n"
  },
  {
    "path": "ret_benchmark/utils/metric_logger.py",
    "content": "# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.\nfrom collections import defaultdict\nfrom collections import deque\n\nimport torch\n\n\nclass SmoothedValue(object):\n    \"\"\"Track a series of values and provide access to smoothed values over a\n    window or the global series average.\n    \"\"\"\n\n    def __init__(self, window_size=20):\n        self.deque = deque(maxlen=window_size)\n        self.series = []\n        self.total = 0.0\n        self.count = 0\n\n    def update(self, value):\n        self.deque.append(value)\n        self.series.append(value)\n        self.count += 1\n        self.total += value\n\n    @property\n    def median(self):\n        d = torch.tensor(list(self.deque))\n        return d.median().item()\n\n    @property\n    def avg(self):\n        d = torch.tensor(list(self.deque))\n        return d.mean().item()\n\n    @property\n    def global_avg(self):\n        return self.total / self.count\n\n\nclass MetricLogger(object):\n    def __init__(self, delimiter=\"\\t\"):\n        self.meters = defaultdict(SmoothedValue)\n        self.delimiter = delimiter\n\n    def update(self, **kwargs):\n        for k, v in kwargs.items():\n            if isinstance(v, torch.Tensor):\n                v = v.item()\n            assert isinstance(v, (float, int))\n            self.meters[k].update(v)\n\n    def __getattr__(self, attr):\n        if attr in self.meters:\n            return self.meters[attr]\n        if attr in self.__dict__:\n            return self.__dict__[attr]\n        raise AttributeError(\"'{}' object has no attribute '{}'\".format(\n            type(self).__name__, attr))\n\n    def __str__(self):\n        loss_str = []\n        for name, meter in self.meters.items():\n            loss_str.append(\n                \"{}: {:.4f} ({:.4f})\".format(name, meter.median, meter.global_avg)\n            )\n        return self.delimiter.join(loss_str)\n"
  },
  {
    "path": "ret_benchmark/utils/model_serialization.py",
    "content": "# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.\nfrom collections import OrderedDict\nimport logging\n\nimport torch\n\n\ndef align_and_update_state_dicts(model_state_dict, loaded_state_dict):\n    \"\"\"\n    Strategy: suppose that the models that we will create will have prefixes appended\n    to each of its keys, for example due to an extra level of nesting that the original\n    pre-trained weights from ImageNet won't contain. For example, model.state_dict()\n    might return backbone[0].body.res2.conv1.weight, while the pre-trained model contains\n    res2.conv1.weight. We thus want to match both parameters together.\n    For that, we look for each model weight, look among all loaded keys if there is one\n    that is a suffix of the current weight name, and use it if that's the case.\n    If multiple matches exist, take the one with longest size\n    of the corresponding name. For example, for the same model as before, the pretrained\n    weight file can contain both res2.conv1.weight, as well as conv1.weight. In this case,\n    we want to match backbone[0].body.conv1.weight to conv1.weight, and\n    backbone[0].body.res2.conv1.weight to res2.conv1.weight.\n    \"\"\"\n    current_keys = sorted(list(model_state_dict.keys()))\n    loaded_keys = sorted(list(loaded_state_dict.keys()))\n    # get a matrix of string matches, where each (i, j) entry correspond to the size of the\n    # loaded_key string, if it matches\n    match_matrix = [\n        len(j) if i.endswith(j) else 0 for i in current_keys for j in loaded_keys\n    ]\n    match_matrix = torch.as_tensor(match_matrix).view(\n        len(current_keys), len(loaded_keys)\n    )\n    max_match_size, idxs = match_matrix.max(1)\n    # remove indices that correspond to no-match\n    idxs[max_match_size == 0] = -1\n\n    # used for logging\n    max_size = max([len(key) for key in current_keys]) if current_keys else 1\n    max_size_loaded = max([len(key) for key in loaded_keys]) if loaded_keys else 1\n    log_str_template = \"{: <{}} loaded from {: <{}} of shape {}\"\n    logger = logging.getLogger(__name__)\n    for idx_new, idx_old in enumerate(idxs.tolist()):\n        if idx_old == -1:\n            continue\n        key = current_keys[idx_new]\n        key_old = loaded_keys[idx_old]\n        model_state_dict[key] = loaded_state_dict[key_old]\n        logger.info(\n            log_str_template.format(\n                key,\n                max_size,\n                key_old,\n                max_size_loaded,\n                tuple(loaded_state_dict[key_old].shape),\n            )\n        )\n\n\ndef strip_prefix_if_present(state_dict, prefix):\n    keys = sorted(state_dict.keys())\n    if not all(key.startswith(prefix) for key in keys):\n        return state_dict\n    stripped_state_dict = OrderedDict()\n    for key, value in state_dict.items():\n        stripped_state_dict[key.replace(prefix, \"\")] = value\n    return stripped_state_dict\n\n\ndef load_state_dict(model, loaded_state_dict):\n    model_state_dict = model.state_dict()\n    # if the state_dict comes from a model that was wrapped in a\n    # DataParallel or DistributedDataParallel during serialization,\n    # remove the \"module\" prefix before performing the matching\n    loaded_state_dict = strip_prefix_if_present(loaded_state_dict, prefix=\"module.\")\n    align_and_update_state_dicts(model_state_dict, loaded_state_dict)\n\n    # use strict loading\n    model.load_state_dict(model_state_dict)\n"
  },
  {
    "path": "ret_benchmark/utils/registry.py",
    "content": "# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.\n\n\ndef _register_generic(module_dict, module_name, module):\n    assert module_name not in module_dict\n    module_dict[module_name] = module\n\n\nclass Registry(dict):\n    '''\n    A helper class for managing registering modules, it extends a dictionary\n    and provides a register functions.\n\n    Eg. creeting a registry:\n        some_registry = Registry({\"default\": default_module})\n\n    There're two ways of registering new modules:\n    1): normal way is just calling register function:\n        def foo():\n            ...\n        some_registry.register(\"foo_module\", foo)\n    2): used as decorator when declaring the module:\n        @some_registry.register(\"foo_module\")\n        @some_registry.register(\"foo_modeul_nickname\")\n        def foo():\n            ...\n\n    Access of module is just like using a dictionary, eg:\n        f = some_registry[\"foo_modeul\"]\n    '''\n\n    def __init__(self, *args, **kwargs):\n        super(Registry, self).__init__(*args, **kwargs)\n\n    def register(self, module_name, module=None):\n        # used as function call\n        if module is not None:\n            _register_generic(self, module_name, module)\n            return\n\n        # used as decorator\n        def register_fn(fn):\n            _register_generic(self, module_name, fn)\n            return fn\n\n        return register_fn\n"
  },
  {
    "path": "scripts/prepare_cub.sh",
    "content": "#!/bin/bash\nset -e\n\nCUB_ROOT='resource/datasets/CUB_200_2011/'\nCUB_DATA='http://www.vision.caltech.edu.s3-us-west-2.amazonaws.com/visipedia-data/CUB-200-2011/CUB_200_2011.tgz'\n\n\nif [[ ! -d \"${CUB_ROOT}\" ]]; then\n    mkdir -p resource/datasets\n    pushd resource/datasets\n    echo \"Downloading CUB_200_2011 data-set...\"\n    wget ${CUB_DATA}\n    tar -zxf CUB_200_2011.tgz\n    popd\nfi\n# Generate train.txt and test.txt splits\necho \"Generating the train.txt/test.txt split files\"\npython scripts/split_cub_for_ms_loss.py\n\n\n"
  },
  {
    "path": "scripts/run_cub.sh",
    "content": "#!/bin/bash\n\nOUT_DIR=\"output\"\nif [[ ! -d \"${OUT_DIR}\" ]]; then\n    echo \"Creating output dir for training : ${OUT_DIR}\"\n    mkdir ${OUT_DIR}\nfi\nCUDA_VISIBLE_DEVICES=0 python3.6 tools/main.py --cfg configs/example.yaml\n"
  },
  {
    "path": "scripts/run_cub_margin.sh",
    "content": "#!/bin/bash\n\nOUT_DIR=\"output_margin\"\nif [[ ! -d \"${OUT_DIR}\" ]]; then\n    echo \"Creating output dir for training : ${OUT_DIR}\"\n    mkdir ${OUT_DIR}\nfi\nCUDA_VISIBLE_DEVICES=0 python3.6 tools/main.py --cfg configs/example_margin.yaml\n"
  },
  {
    "path": "scripts/split_cub_for_ms_loss.py",
    "content": "\ncub_root = 'resource/datasets/CUB_200_2011/'\nimages_file = cub_root + 'images.txt'\ntrain_file = cub_root + 'train.txt'\ntest_file = cub_root + 'test.txt'\n\n\ndef main():\n    train = []\n    test = []\n    with open(images_file) as f_img:\n        for l_img in f_img:\n            i, fname = l_img.split()\n            label = int(fname.split('.', 1)[0])\n            if label <= 100:\n                train.append((fname, label - 1)) # labels 0 ... 99 (0-based labels for margin_loss)\n            else:\n                test.append((fname, label - 1))  # labels 100 ... 199\n\n    for f, v in [(train_file, train), (test_file, test)]:\n        with open(f, 'w') as tf:\n            for fname, label in v:\n                print(\"images/{},{}\".format(fname, label), file=tf)\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "setup.py",
    "content": "# Copyright (c) Malong Technologies Co., Ltd.\n# All rights reserved.\n#\n# Contact: github@malong.com\n#\n# This source code is licensed under the LICENSE file in the root directory of this source tree.\n\n\nimport torch\nfrom setuptools import find_packages, setup\nfrom torch.utils.cpp_extension import CppExtension\n\n\nrequirements = [\"torch\", \"torchvision\"]\n\nsetup(\n    name=\"ret_benchmark\",\n    version=\"0.1\",\n    author=\"Malong Technologies\",\n    url=\"https://github.com/MalongTech/research-ms-loss\",\n    description=\"ms-loss\",\n    packages=find_packages(exclude=(\"configs\", \"tests\")),\n    install_requires=requirements,\n    cmdclass={\"build_ext\": torch.utils.cpp_extension.BuildExtension},\n)\n"
  },
  {
    "path": "tools/main.py",
    "content": "# Copyright (c) Malong Technologies Co., Ltd.\n# All rights reserved.\n#\n# Contact: github@malong.com\n#\n# This source code is licensed under the LICENSE file in the root directory of this source tree.\n\nimport argparse\nimport torch\n\nfrom ret_benchmark.config import cfg\nfrom ret_benchmark.data import build_data\nfrom ret_benchmark.engine.trainer import do_train\nfrom ret_benchmark.losses import build_loss\nfrom ret_benchmark.modeling import build_model\nfrom ret_benchmark.solver import build_lr_scheduler, build_optimizer\nfrom ret_benchmark.utils.logger import setup_logger\nfrom ret_benchmark.utils.checkpoint import Checkpointer\n\n\ndef train(cfg):\n    logger = setup_logger(name='Train', level=cfg.LOGGER.LEVEL)\n    logger.info(cfg)\n    model = build_model(cfg)\n    device = torch.device(cfg.MODEL.DEVICE)\n    model.to(device)\n\n    criterion = build_loss(cfg)\n\n    optimizer = build_optimizer(cfg, model)\n    scheduler = build_lr_scheduler(cfg, optimizer)\n\n    train_loader = build_data(cfg, is_train=True)\n    val_loader = build_data(cfg, is_train=False)\n\n    logger.info(train_loader.dataset)\n    logger.info(val_loader.dataset)\n\n    arguments = dict()\n    arguments[\"iteration\"] = 0\n\n    checkpoint_period = cfg.SOLVER.CHECKPOINT_PERIOD\n    checkpointer = Checkpointer(model, optimizer, scheduler, cfg.SAVE_DIR)\n\n    do_train(\n        cfg,\n        model,\n        train_loader,\n        val_loader,\n        optimizer,\n        scheduler,\n        criterion,\n        checkpointer,\n        device,\n        checkpoint_period,\n        arguments,\n        logger\n    )\n\n\ndef parse_args():\n    \"\"\"\n  Parse input arguments\n  \"\"\"\n    parser = argparse.ArgumentParser(description='Train a retrieval network')\n    parser.add_argument(\n        '--cfg',\n        dest='cfg_file',\n        help='config file',\n        default=None,\n        type=str)\n    return parser.parse_args()\n\n\nif __name__ == '__main__':\n    args = parse_args()\n    cfg.merge_from_file(args.cfg_file)\n    train(cfg)\n"
  }
]