├── LICENSE ├── README.md ├── annotate_with_clip.py ├── assets.py ├── config ├── afhq_clip.yaml ├── cars3d.yaml ├── dsprites.yaml ├── ffhq_clip.yaml ├── shapes3d.yaml ├── smallnorb.yaml └── stanfordcars_clip.yaml ├── data.py ├── evaluation ├── classifier.py ├── dci.py ├── mig.py └── sap.py ├── img ├── animals │ ├── a │ │ ├── arctic_fox.jpg │ │ ├── boerboel.jpg │ │ ├── bombay_cat.jpg │ │ ├── cheetah.jpg │ │ ├── chihuahua.jpg │ │ ├── husky.jpg │ │ ├── input.jpg │ │ ├── jaguar.jpg │ │ ├── labradoodle.jpg │ │ └── shiba_inu.jpg │ ├── b │ │ ├── arctic_fox.jpg │ │ ├── boerboel.jpg │ │ ├── bombay_cat.jpg │ │ ├── cheetah.jpg │ │ ├── chihuahua.jpg │ │ ├── husky.jpg │ │ ├── input.jpg │ │ ├── jaguar.jpg │ │ ├── labradoodle.jpg │ │ └── shiba_inu.jpg │ ├── c │ │ ├── arctic_fox.jpg │ │ ├── boerboel.jpg │ │ ├── bombay_cat.jpg │ │ ├── cheetah.jpg │ │ ├── chihuahua.jpg │ │ ├── husky.jpg │ │ ├── input.jpg │ │ ├── jaguar.jpg │ │ ├── labradoodle.jpg │ │ └── shiba_inu.jpg │ ├── d │ │ ├── arctic_fox.jpg │ │ ├── boerboel.jpg │ │ ├── bombay_cat.jpg │ │ ├── cheetah.jpg │ │ ├── chihuahua.jpg │ │ ├── husky.jpg │ │ ├── input.jpg │ │ ├── jaguar.jpg │ │ ├── labradoodle.jpg │ │ └── shiba_inu.jpg │ ├── e │ │ ├── arctic_fox.jpg │ │ ├── boerboel.jpg │ │ ├── bombay_cat.jpg │ │ ├── cheetah.jpg │ │ ├── chihuahua.jpg │ │ ├── husky.jpg │ │ ├── input.jpg │ │ ├── jaguar.jpg │ │ ├── labradoodle.jpg │ │ └── shiba_inu.jpg │ ├── f │ │ ├── arctic_fox.jpg │ │ ├── boerboel.jpg │ │ ├── bombay_cat.jpg │ │ ├── cheetah.jpg │ │ ├── chihuahua.jpg │ │ ├── husky.jpg │ │ ├── input.jpg │ │ ├── jaguar.jpg │ │ ├── labradoodle.jpg │ │ └── shiba_inu.jpg │ ├── g │ │ ├── arctic_fox.jpg │ │ ├── boerboel.jpg │ │ ├── bombay_cat.jpg │ │ ├── cheetah.jpg │ │ ├── chihuahua.jpg │ │ ├── husky.jpg │ │ ├── input.jpg │ │ ├── jaguar.jpg │ │ ├── labradoodle.jpg │ │ └── shiba_inu.jpg │ ├── h │ │ ├── arctic_fox.jpg │ │ ├── boerboel.jpg │ │ ├── bombay_cat.jpg │ │ ├── cheetah.jpg │ │ ├── chihuahua.jpg │ │ ├── husky.jpg │ │ ├── input.jpg │ │ ├── jaguar.jpg │ │ ├── labradoodle.jpg │ │ └── shiba_inu.jpg │ ├── i │ │ ├── arctic_fox.jpg │ │ ├── boerboel.jpg │ │ ├── bombay_cat.jpg │ │ ├── cheetah.jpg │ │ ├── chihuahua.jpg │ │ ├── husky.jpg │ │ ├── input.jpg │ │ ├── jaguar.jpg │ │ ├── labradoodle.jpg │ │ └── shiba_inu.jpg │ ├── j │ │ ├── arctic_fox.jpg │ │ ├── boerboel.jpg │ │ ├── bombay_cat.jpg │ │ ├── cheetah.jpg │ │ ├── chihuahua.jpg │ │ ├── husky.jpg │ │ ├── input.jpg │ │ ├── jaguar.jpg │ │ ├── labradoodle.jpg │ │ └── shiba_inu.jpg │ └── k │ │ ├── arctic_fox.jpg │ │ ├── boerboel.jpg │ │ ├── bombay_cat.jpg │ │ ├── cheetah.jpg │ │ ├── chihuahua.jpg │ │ ├── husky.jpg │ │ ├── input.jpg │ │ ├── jaguar.jpg │ │ ├── labradoodle.jpg │ │ └── shiba_inu.jpg ├── cars │ ├── a │ │ ├── black.jpg │ │ ├── blue.jpg │ │ ├── family.jpg │ │ ├── input.jpg │ │ ├── jeep.jpg │ │ ├── red.jpg │ │ ├── sports.jpg │ │ ├── white.jpg │ │ └── yellow.jpg │ ├── aa │ │ ├── black.jpg │ │ ├── blue.jpg │ │ ├── family.jpg │ │ ├── input.jpg │ │ ├── jeep.jpg │ │ ├── red.jpg │ │ ├── sports.jpg │ │ ├── white.jpg │ │ └── yellow.jpg │ ├── b │ │ ├── black.jpg │ │ ├── blue.jpg │ │ ├── family.jpg │ │ ├── input.jpg │ │ ├── jeep.jpg │ │ ├── red.jpg │ │ ├── sports.jpg │ │ ├── white.jpg │ │ └── yellow.jpg │ ├── c │ │ ├── black.jpg │ │ ├── blue.jpg │ │ ├── family.jpg │ │ ├── input.jpg │ │ ├── jeep.jpg │ │ ├── red.jpg │ │ ├── sports.jpg │ │ ├── white.jpg │ │ └── yellow.jpg │ ├── d │ │ ├── black.jpg │ │ ├── blue.jpg │ │ ├── family.jpg │ │ ├── input.jpg │ │ ├── jeep.jpg │ │ ├── red.jpg │ │ ├── sports.jpg │ │ ├── white.jpg │ │ └── yellow.jpg │ ├── e │ │ ├── black.jpg │ │ ├── blue.jpg │ │ ├── family.jpg │ │ ├── input.jpg │ │ ├── jeep.jpg │ │ ├── red.jpg │ │ ├── sports.jpg │ │ ├── white.jpg │ │ └── yellow.jpg │ ├── ee │ │ ├── black.jpg │ │ ├── blue.jpg │ │ ├── family.jpg │ │ ├── input.jpg │ │ ├── jeep.jpg │ │ ├── red.jpg │ │ ├── sports.jpg │ │ ├── white.jpg │ │ └── yellow.jpg │ ├── ee2 │ │ ├── black.jpg │ │ ├── blue.jpg │ │ ├── family.jpg │ │ ├── input.jpg │ │ ├── jeep.jpg │ │ ├── red.jpg │ │ ├── sports.jpg │ │ ├── white.jpg │ │ └── yellow.jpg │ ├── f │ │ ├── black.jpg │ │ ├── blue.jpg │ │ ├── family.jpg │ │ ├── input.jpg │ │ ├── jeep.jpg │ │ ├── red.jpg │ │ ├── sports.jpg │ │ ├── white.jpg │ │ └── yellow.jpg │ ├── g │ │ ├── black.jpg │ │ ├── blue.jpg │ │ ├── family.jpg │ │ ├── input.jpg │ │ ├── jeep.jpg │ │ ├── red.jpg │ │ ├── sports.jpg │ │ ├── white.jpg │ │ └── yellow.jpg │ ├── gg │ │ ├── black.jpg │ │ ├── blue.jpg │ │ ├── family.jpg │ │ ├── input.jpg │ │ ├── jeep.jpg │ │ ├── red.jpg │ │ ├── sports.jpg │ │ ├── white.jpg │ │ └── yellow.jpg │ ├── h │ │ ├── black.jpg │ │ ├── blue.jpg │ │ ├── family.jpg │ │ ├── input.jpg │ │ ├── jeep.jpg │ │ ├── red.jpg │ │ ├── sports.jpg │ │ ├── white.jpg │ │ └── yellow.jpg │ ├── i │ │ ├── black.jpg │ │ ├── blue.jpg │ │ ├── family.jpg │ │ ├── input.jpg │ │ ├── jeep.jpg │ │ ├── red.jpg │ │ ├── sports.jpg │ │ ├── white.jpg │ │ └── yellow.jpg │ ├── k │ │ ├── black.jpg │ │ ├── blue.jpg │ │ ├── family.jpg │ │ ├── input.jpg │ │ ├── jeep.jpg │ │ ├── red.jpg │ │ ├── sports.jpg │ │ ├── white.jpg │ │ └── yellow.jpg │ ├── l │ │ ├── black.jpg │ │ ├── blue.jpg │ │ ├── family.jpg │ │ ├── input.jpg │ │ ├── jeep.jpg │ │ ├── red.jpg │ │ ├── sports.jpg │ │ ├── white.jpg │ │ └── yellow.jpg │ └── p │ │ ├── black.jpg │ │ ├── blue.jpg │ │ ├── family.jpg │ │ ├── input.jpg │ │ ├── jeep.jpg │ │ ├── red.jpg │ │ ├── sports.jpg │ │ ├── white.jpg │ │ └── yellow.jpg ├── faces │ ├── a │ │ ├── asian.jpg │ │ ├── beard.jpg │ │ ├── blond_hair.jpg │ │ ├── eyeglasses.jpg │ │ ├── female.jpg │ │ ├── input.jpg │ │ ├── kid.jpg │ │ ├── makeup.jpg │ │ ├── male.jpg │ │ ├── red_hair.jpg │ │ ├── sunglasses.jpg │ │ └── teenager.jpg │ ├── b │ │ ├── asian.jpg │ │ ├── beard.jpg │ │ ├── blond_hair.jpg │ │ ├── eyeglasses.jpg │ │ ├── female.jpg │ │ ├── input.jpg │ │ ├── kid.jpg │ │ ├── male.jpg │ │ ├── red_hair.jpg │ │ ├── sunglasses.jpg │ │ └── teenager.jpg │ ├── c │ │ ├── asian.jpg │ │ ├── beard.jpg │ │ ├── blond_hair.jpg │ │ ├── eyeglasses.jpg │ │ ├── female.jpg │ │ ├── input.jpg │ │ ├── kid.jpg │ │ ├── male.jpg │ │ ├── red_hair.jpg │ │ ├── sunglasses.jpg │ │ └── teenager.jpg │ ├── d │ │ ├── asian.jpg │ │ ├── beard.jpg │ │ ├── blond_hair.jpg │ │ ├── eyeglasses.jpg │ │ ├── female.jpg │ │ ├── input.jpg │ │ ├── kid.jpg │ │ ├── male.jpg │ │ ├── red_hair.jpg │ │ ├── sunglasses.jpg │ │ └── teenager.jpg │ ├── e │ │ ├── asian.jpg │ │ ├── beard.jpg │ │ ├── blond_hair.jpg │ │ ├── eyeglasses.jpg │ │ ├── female.jpg │ │ ├── input.jpg │ │ ├── kid.jpg │ │ ├── male.jpg │ │ ├── red_hair.jpg │ │ ├── sunglasses.jpg │ │ └── teenager.jpg │ ├── f │ │ ├── asian.jpg │ │ ├── beard.jpg │ │ ├── blond_hair.jpg │ │ ├── eyeglasses.jpg │ │ ├── female.jpg │ │ ├── input.jpg │ │ ├── kid.jpg │ │ ├── male.jpg │ │ ├── red_hair.jpg │ │ ├── sunglasses.jpg │ │ └── teenager.jpg │ ├── g │ │ ├── asian.jpg │ │ ├── beard.jpg │ │ ├── blond_hair.jpg │ │ ├── eyeglasses.jpg │ │ ├── female.jpg │ │ ├── input.jpg │ │ ├── kid.jpg │ │ ├── male.jpg │ │ ├── red_hair.jpg │ │ ├── sunglasses.jpg │ │ └── teenager.jpg │ └── h │ │ ├── asian.jpg │ │ ├── beard.jpg │ │ ├── blond_hair.jpg │ │ ├── eyeglasses.jpg │ │ ├── female.jpg │ │ ├── input.jpg │ │ ├── kid.jpg │ │ ├── male.jpg │ │ ├── red_hair.jpg │ │ ├── sunglasses.jpg │ │ └── teenager.jpg ├── huji-logo.png └── thumbnails │ ├── zerodim-01.png │ ├── zerodim-02.png │ ├── zerodim-03.png │ ├── zerodim-04.png │ ├── zerodim-05.png │ ├── zerodim-06.png │ ├── zerodim-07.png │ ├── zerodim-08.png │ └── zerodim-09.png ├── main.py └── network ├── modules.py ├── training.py └── utils.py /LICENSE: -------------------------------------------------------------------------------- 1 | SOFTWARE RESEARCH LICENSE 2 | 3 | 4 | I. DEFINITIONS. 5 | 6 | "Licensee" means You and any other party that has entered into and has 7 | in effect a version of this License. 8 | 9 | "Modifications" means any (a) change or addition to the Technology or 10 | (b) new source or object code implementing any portion of the Technology. 11 | 12 | "Yissum" means Yissum Research Development Company Of The Hebrew University of Jerusalem Ltd., 13 | its successors and assignees. 14 | 15 | "Research Use" means research, evaluation, or development for the 16 | purpose of advancing knowledge, teaching, learning, or customizing the 17 | Technology or Modifications for personal use. Research Use expressly 18 | excludes use or distribution for direct or indirect commercial 19 | (including strategic) gain or advantage. 20 | 21 | "Technology" means the source code, object code and specifications of 22 | the technology made available by Yissum pursuant to this License. 23 | 24 | "Technology Site" means the website designated for accessing the Technology. 25 | 26 | "You" means the individual executing this License or the legal entity or 27 | entities represented by the individual executing this License. 28 | 29 | II. PURPOSE. 30 | 31 | Yissum is licensing the Technology under this Software Research License (the "License") 32 | to promote research, education, innovation, and development using the Technology. 33 | 34 | COMMERCIAL USE AND DISTRIBUTION OF TECHNOLOGY AND MODIFICATIONS IS 35 | PERMITTED ONLY UNDER A YISSUM COMMERCIAL LICENSE. 36 | 37 | III. RESEARCH USE RIGHTS. 38 | 39 | A. License Grant. Subject to the conditions contained herein, Yissum 40 | grants to You a non-exclusive, non-transferable, worldwide, and 41 | royalty-free license to do the following for Your Research Use only: 42 | 43 | 1. Reproduce, create Modifications of, and use the Technology alone, 44 | or with Modifications; 45 | 46 | 2. Share source code of the Technology alone, or with Modifications, 47 | with other Licensees; and 48 | 49 | 3. Distribute object code of the Technology, alone, or with 50 | Modifications, to any third parties for Research Use only, under a 51 | license of Your choice that is consistent with this License; and publish 52 | papers and books discussing the Technology which may include relevant 53 | excerpts that do not in the aggregate constitute a significant portion 54 | of the Technology. 55 | 56 | B. Residual Rights. You may use any information in intangible form 57 | that you remember after accessing the Technology, except when such use 58 | violates Yissum's copyrights or patent rights. 59 | 60 | C. No Implied Licenses. Other than the rights granted herein, Yissum 61 | retains all rights, title, and interest in Technology, and You retain 62 | all rights, title, and interest in Your Modifications and associated 63 | specifications, subject to the terms of this License. 64 | 65 | D. Open Source Licenses. Portions of the Technology may be provided 66 | with notices and open source licenses from open source communities and 67 | third parties that govern the use of those portions, and any licenses 68 | granted hereunder do not alter any rights and obligations you may have 69 | under such open source licenses, however, the disclaimer of warranty and 70 | limitation of liability provisions in this License will apply to all 71 | Technology in this distribution. 72 | 73 | IV. INTELLECTUAL PROPERTY REQUIREMENTS 74 | 75 | As a condition to Your License, You agree to comply with the following 76 | restrictions and responsibilities: 77 | 78 | A. License and Copyright Notices. You must include a copy of this 79 | Software Research License in a Readme file for any Technology or 80 | Modifications you distribute. You must also include the following 81 | statement, "Use and distribution of this technology is subject to the 82 | Software Research License included herein", (a) once prominently in the 83 | source code tree and/or specifications for Your source code 84 | distributions, and (b) once in the same file as Your copyright or 85 | proprietary notices for Your binary code distributions. You must cause 86 | any files containing Your Modification to carry prominent notice stating 87 | that You changed the files. You must not remove or alter any copyright 88 | or other proprietary notices in the Technology. 89 | 90 | B. Licensee Exchanges. Any Technology and Modifications You 91 | receive from any Licensee are governed by this License. 92 | 93 | V. GENERAL TERMS. 94 | 95 | A. Disclaimer Of Warranties. 96 | 97 | THE TECHNOLOGY IS PROVIDED "AS IS", WITHOUT WARRANTIES OF ANY KIND, 98 | EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT 99 | THE TECHNOLOGY IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR 100 | PURPOSE, OR NON-INFRINGING OF THIRD PARTY RIGHTS. YOU AGREE THAT YOU 101 | BEAR THE ENTIRE RISK IN CONNECTION WITH YOUR USE AND DISTRIBUTION OF ANY 102 | AND ALL TECHNOLOGY UNDER THIS LICENSE. 103 | 104 | B. Infringement; Limitation Of Liability. 105 | 106 | 1. If any portion of, or functionality implemented by, the Technology 107 | becomes the subject of a claim or threatened claim of infringement 108 | ("Affected Materials"), Yissum may, in its unrestricted discretion, suspend 109 | Your rights to use and distribute the Affected Materials under this 110 | License. Such suspension of rights will be effective immediately upon 111 | the posting of notice of suspension on the Technology Site. 112 | 113 | 2. IN NO EVENT WILL YISSUM BE LIABLE FOR ANY DIRECT, INDIRECT, PUNITIVE, 114 | SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES IN CONNECTION WITH OR 115 | ARISING OUT OF THIS LICENSE (INCLUDING, WITHOUT LIMITATION, LOSS OF 116 | PROFITS, USE, DATA, OR ECONOMIC ADVANTAGE OF ANY SORT), HOWEVER IT 117 | ARISES AND ON ANY THEORY OF LIABILITY (including negligence), WHETHER OR 118 | NOT YISSUM HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. LIABILITY 119 | UNDER THIS SECTION V.B.2 SHALL BE SO LIMITED AND EXCLUDED, 120 | NOTWITHSTANDING FAILURE OF THE ESSENTIAL PURPOSE OF ANY REMEDY. 121 | 122 | C. Termination. 123 | 124 | 1. You may terminate this License at any time by notifying Yissum in writing. 125 | 126 | 2. All Your rights will terminate under this License if You fail to 127 | comply with any of its material terms or conditions and do not cure such 128 | failure within thirty (30) days after becoming aware of such noncompliance. 129 | 130 | 3. Upon termination, You must discontinue all uses and distribution 131 | of the Technology, and all provisions of this Section V ("General Terms") 132 | shall survive termination. 133 | 134 | D. Miscellaneous. 135 | 136 | 1. Use of Names. Except as expressly provided in this License, 137 | You may not use the names of Yissum or the Hebrew University of Jerusalem 138 | except for the limited purpose of identifying the source of the Technology. 139 | 140 | 2. Integration. This License represents the complete agreement of 141 | the parties concerning the subject matter hereof. 142 | 143 | 3. Severability. If any provision of this License is held 144 | unenforceable, such provision shall be reformed to the extent necessary 145 | to make it enforceable unless to do so would defeat the intent of the 146 | parties, in which case, this License shall terminate. 147 | 148 | 4. Governing Law. This License is governed by the laws of the 149 | State of Israel as applied to contracts entered into and performed in 150 | Israel between Israeli residents. In no event shall this License 151 | be construed against the drafter. 152 | 153 | 5. Export Control. You agree to comply with all relevant export controls 154 | and trade laws that apply to Technology and Modifications. 155 | 156 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ZeroDIM - Official PyTorch Implementation 2 | > [An Image is Worth More Than a Thousand Words: Towards Disentanglement in the Wild](http://www.vision.huji.ac.il/zerodim) 3 | > Aviv Gabbay, Niv Cohen and Yedid Hoshen 4 | > Neural Information Processing Systems (NeurIPS), 2021. 5 | 6 | > **Abstract:** Unsupervised disentanglement has been shown to be theoretically impossible without inductive biases on the models and the data. As an alternative approach, recent methods rely on limited supervision to disentangle the factors of variation and allow their identifiability. While annotating the true generative factors is only required for a limited number of observations, we argue that it is infeasible to enumerate all the factors of variation that describe a real-world image distribution. To this end, we propose a method for disentangling a set of factors which are only partially labeled, as well as separating the complementary set of residual factors that are never explicitly specified. Our success in this challenging setting, demonstrated on synthetic benchmarks, gives rise to leveraging off-the-shelf image descriptors to partially annotate a subset of attributes in real image domains (e.g. of human faces) with minimal manual effort. Specifically, we use a recent language-image embedding model (CLIP) to annotate a set of attributes of interest in a zero-shot manner and demonstrate state-of-the-art disentangled image manipulation results. 7 | 8 | 9 | 10 | ## Results 11 | 12 | ### Human Face Manipulation (FFHQ) 13 | 14 | | Input | Kid | Asian | Gender | Red Hair | 15 | |:---:|:---:|:---:|:---:|:---:| 16 | |||||| 17 | |||||| 18 | |||||| 19 | |||||| 20 | |||||| 21 | 22 | ### Animal Species Translation (AFHQ) 23 | 24 | | Input | Labradoodle | Husky | Chihuahua | Jaguar | Bombay Cat | 25 | |:---:|:---:|:---:|:---:|:---:|:---:| 26 | ||||||| 27 | ||||||| 28 | ||||||| 29 | ||||||| 30 | ||||||| 31 | 32 | ### Car Type and Color Manipulation (Stanford Cars) 33 | | Input | Jeep | Sports | Family | White | Red | 34 | |:---:|:---:|:---:|:---:|:---:|:---:| 35 | ||||||| 36 | ||||||| 37 | ||||||| 38 | ||||||| 39 | ||||||| 40 | 41 | 42 | ## Requirements 43 | ![python 3.7](https://img.shields.io/badge/python-3.7-blue.svg) 44 | ![pytorch 1.3](https://img.shields.io/badge/pytorch-1.3-orange.svg) 45 | ![cuda 10.1](https://img.shields.io/badge/cuda-10.1-green.svg) 46 | 47 | This repository imports modules from the StyleGAN2 architecture (**not pretrained**). 48 | Clone the following repository: 49 | ``` 50 | git clone https://github.com/rosinality/stylegan2-pytorch 51 | ``` 52 | Add the local StyleGAN2 project to PYTHONPATH. For bash users: 53 | ``` 54 | export PYTHONPATH= 55 | ``` 56 | 57 | ## Training 58 | In order to train a model from scratch, do the following preprocessing and training steps. 59 | First, create a directory (can be specified by `--base-dir` or set to current working directory by default) for the training artifacts (preprocessed data, models, training logs, etc). 60 | 61 | ### Synthetic Benchmarks 62 | For each of the synthetic benchmarks (Shapes3d, Cars3d, dSprites, SmallNorb), download the dataset from the original source to a new local directory (e.g. `shapes3d-dataset`) and apply the following preprocessing: 63 | ``` 64 | python main.py preprocess --dataset-id shapes3d --dataset-path shapes3d-dataset --out-data-name shapes3d-x64 65 | ``` 66 | As an alternative, we provide the preprocessed datasets for the synthetic benchmarks evaluated in the paper. You can download the files directly and place them under `/cache/preprocess`: [Shapes3d](https://drive.google.com/file/d/1DCtk9v8U9Dlxzb7lOqYNTRoDkQzZxLrT/view?usp=sharing), [Cars3d](https://drive.google.com/file/d/1ZOcs2Kzt1R3vZVaeemMkXZAuIMrDq-hO/view?usp=sharing), [dSprites](https://drive.google.com/file/d/1TswTN9-nOMXS0ZkrZFxWOg56q3TXLDig/view?usp=sharing), [SmallNorb](https://drive.google.com/file/d/1FzLBSBMPyCc2xV2snXc1WuzM6GOgfDwb/view?usp=sharing). 67 | 68 | The models can then be trained as follows: 69 | ``` 70 | python main.py train --config shapes3d --data-name shapes3d-x64 --model-name zerodim-shapes3d-x64 71 | ``` 72 | 73 | Evaluation of DCI, SAP and MIG is stored under `/eval//`. 74 | 75 | ### Zero-shot Disentangled Image Manipulation 76 | For training a model on real images, without any manual annotations, first prepare an unlabeled image dataset. E.g. for FFHQ, download the [FFHQ dataset](https://github.com/NVlabs/ffhq-dataset), create a local directory named `ffhq-dataset` with all the png images placed in a single `imgs` subdir, and apply the following preprocessing: 77 | ``` 78 | python main.py preprocess --dataset-id ffhq --dataset-path ffhq-dataset --out-data-name ffhq-x256 79 | ``` 80 | 81 | The images are then annotated in a zero-shot manner using [CLIP](https://github.com/openai/CLIP). Clone the external repository and add to your local path: 82 | ``` 83 | git clone https://github.com/openai/CLIP 84 | export PYTHONPATH= 85 | ``` 86 | 87 | For example, human face images can be annotated as follows: 88 | ``` 89 | python annotate_with_clip.py --data-name ffhq-x256 --K 1000 90 | ``` 91 | 92 | The model can then be trained as follows: 93 | ``` 94 | python main.py train --config ffhq_clip --data-name ffhq-x256 --model-name zerodim-ffhq-x256 95 | ``` 96 | 97 | #### Resources 98 | The training automatically detects all the available gpus and applies multi-gpu mode if available. 99 | 100 | #### Logs 101 | During training, loss metrics and translation visualizations are logged with tensorboard and can be viewed by: 102 | ``` 103 | tensorboard --logdir /cache/tensorboard --load_fast true 104 | ``` 105 | 106 | ## Pretrained Models 107 | We provide a model pretrained on human face images ([FFHQ](https://github.com/NVlabs/ffhq-dataset)), with partial annotations obtained in a zero-shot manner using [CLIP](https://github.com/openai/CLIP) for the following attributes: `age, gender, ethnicity, hair_color, beard, glasses`. Download the entire model directory from [zerodim-ffhq-x256](https://drive.google.com/drive/folders/1RXqLyo43uhRx5laTlEHQtnpZssotPPQK?usp=sharing) and place it under `/cache/models`. 108 | 109 | ## Inference 110 | Given a trained model (either pretrained or trained from scratch), a test image can be manipulated as follows: 111 | ``` 112 | python main.py manipulate --model-name zerodim-ffhq-x256 --factor-name gender --img face.png --output face_in_all_genders.png 113 | ``` 114 | 115 | **Note:** Face manipulation models are very sensitive to the face alignment. The target face should be aligned exactly as done in the pipeline which CelebA-HQ and FFHQ were created by. Use the alignment method implemented [here](https://github.com/Puzer/stylegan-encoder/blob/master/align_images.py) before applying any of the human face manipulation models on external images. 116 | 117 | ## Citation 118 | ``` 119 | @inproceedings{gabbay2021zerodim, 120 | author = {Aviv Gabbay and Niv Cohen and Yedid Hoshen}, 121 | title = {An Image is Worth More Than a Thousand Words: Towards Disentanglement in the Wild}, 122 | booktitle = {Neural Information Processing Systems (NeurIPS)}, 123 | year = {2021} 124 | } 125 | ``` 126 | -------------------------------------------------------------------------------- /annotate_with_clip.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | from tqdm import tqdm 3 | 4 | import numpy as np 5 | import torch 6 | import torchvision.transforms as transforms 7 | import faiss 8 | 9 | import clip 10 | from clip.simple_tokenizer import SimpleTokenizer 11 | 12 | from assets import AssetManager 13 | 14 | 15 | def annotate_with_clip(args): 16 | assets = AssetManager(args.base_dir) 17 | data = np.load(assets.get_preprocess_file_path(args.data_name)) 18 | imgs = data['imgs'] 19 | 20 | att_names = ["age","gender","ethnicity","hair_color","beard","glasses"] 21 | values_names = [["a kid","a teenager","an adult","an old person"], 22 | ["a male","a female"], 23 | ["a black person","a white person","an asian person"], 24 | ["brunette hair","blond hair","bald","red hair","black hair", "white hair"], 25 | ["a person with a beard","a person with a mustache","a person with a goatee","a shaved person"], 26 | ["a person with glasses","a person with shades","a person without glasses"]] 27 | 28 | model, preprocess = clip.load("ViT-B/32", device="cuda") 29 | model.eval() 30 | 31 | print("Model parameters:", f"{np.sum([int(np.prod(p.shape)) for p in model.parameters()]):,}") 32 | print("Context length:", model.context_length) 33 | print("Vocab size:", model.vocab_size) 34 | 35 | ENC_LEN = 512 36 | 37 | transform = transforms.Compose([ 38 | transforms.ToTensor(), 39 | transforms.Resize(224), 40 | transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) 41 | ]) 42 | 43 | def get_emb(imgs, batch_size=32): 44 | set_length = len(imgs) 45 | img_enc = torch.zeros((set_length,ENC_LEN)) 46 | 47 | run_ind = 0 48 | 49 | with torch.no_grad(): 50 | for i in tqdm(range(int(np.ceil(set_length/batch_size)))): 51 | inputs = imgs[run_ind : run_ind + batch_size] 52 | inputs = [transform(img) for img in inputs] 53 | inputs = torch.stack(inputs) 54 | 55 | image_features = model.encode_image(inputs.cuda()) 56 | img_enc[run_ind : run_ind + batch_size] = image_features.cpu() 57 | run_ind = run_ind + batch_size 58 | 59 | return img_enc 60 | 61 | img_enc = get_emb(imgs) 62 | img_enc /= img_enc.norm(dim=-1, keepdim=True) 63 | 64 | img_feat = img_enc.numpy() 65 | index = faiss.IndexFlatL2(img_feat.shape[1]) 66 | index.add(np.ascontiguousarray(img_feat.astype('float32'))) 67 | 68 | tokenizer = SimpleTokenizer() 69 | sot_token = tokenizer.encoder['<|startoftext|>'] 70 | eot_token = tokenizer.encoder['<|endoftext|>'] 71 | 72 | values_list = np.full((len(att_names), img_feat.shape[0]), fill_value=-1) 73 | 74 | for i in range(len(att_names)): 75 | att = att_names[i] 76 | used_values = np.zeros(img_feat.shape[0]) # number of values assigned for an image (to prevent image having more than one value for an attribute) 77 | 78 | for j in range(len(values_names[i])): 79 | value = values_names[i][j] 80 | text_descriptions = f"%s"%(value) 81 | text_tokens = [[sot_token] + tokenizer.encode(text_descriptions) + [eot_token]] 82 | text_input = torch.zeros(len(text_tokens), model.context_length, dtype=torch.long) 83 | for k, tokens in enumerate(text_tokens): 84 | text_input[k, :len(tokens)] = torch.tensor(tokens) 85 | 86 | text_input = text_input.cuda() 87 | 88 | with torch.no_grad(): 89 | text_features = model.encode_text(text_input).float() 90 | text_features /= text_features.norm(dim=-1, keepdim=True) 91 | 92 | text_features = text_features.cpu().numpy() 93 | 94 | # find most compatible images 95 | D, I = index.search(np.ascontiguousarray(text_features.astype('float32')), args.K) 96 | I = list(I[0]) 97 | I.sort() 98 | 99 | values_list[i, I] = j 100 | used_values[I] = used_values[I] + 1 101 | 102 | values_list[i, np.where(used_values>1)[0]] = -1 # ignore image attributes which were assigned with more than 1 value 103 | 104 | factors = values_list.T.astype(np.int64) 105 | 106 | np.savez( 107 | file=assets.get_preprocess_file_path(args.data_name), 108 | imgs=imgs, 109 | factors=factors, 110 | factor_sizes=[np.unique(factors[:, f]).size - 1 for f in range(factors.shape[1])], 111 | factor_names=att_names 112 | ) 113 | 114 | 115 | def main(): 116 | parser = argparse.ArgumentParser() 117 | parser.add_argument('-bd', '--base-dir', type=str, default='.') 118 | 119 | parser.add_argument('-dn', '--data-name', type=str, required=True) 120 | parser.add_argument('--K', type=int, default=1000) 121 | 122 | args = parser.parse_args() 123 | annotate_with_clip(args) 124 | 125 | if __name__ == '__main__': 126 | main() 127 | -------------------------------------------------------------------------------- /assets.py: -------------------------------------------------------------------------------- 1 | import os 2 | import shutil 3 | 4 | 5 | class AssetManager: 6 | 7 | def __init__(self, base_dir): 8 | self.__base_dir = base_dir 9 | 10 | self.__cache_dir = os.path.join(self.__base_dir, 'cache') 11 | if not os.path.exists(self.__cache_dir): 12 | os.mkdir(self.__cache_dir) 13 | 14 | self.__preprocess_dir = os.path.join(self.__cache_dir, 'preprocess') 15 | if not os.path.exists(self.__preprocess_dir): 16 | os.mkdir(self.__preprocess_dir) 17 | 18 | self.__models_dir = os.path.join(self.__cache_dir, 'models') 19 | if not os.path.exists(self.__models_dir): 20 | os.mkdir(self.__models_dir) 21 | 22 | self.__tensorboard_dir = os.path.join(self.__cache_dir, 'tensorboard') 23 | if not os.path.exists(self.__tensorboard_dir): 24 | os.mkdir(self.__tensorboard_dir) 25 | 26 | self.__eval_dir = os.path.join(self.__base_dir, 'eval') 27 | if not os.path.exists(self.__eval_dir): 28 | os.mkdir(self.__eval_dir) 29 | 30 | def get_preprocess_file_path(self, data_name): 31 | return os.path.join(self.__preprocess_dir, data_name + '.npz') 32 | 33 | def get_model_dir(self, model_name): 34 | return os.path.join(self.__models_dir, model_name) 35 | 36 | def recreate_model_dir(self, model_name): 37 | model_dir = self.get_model_dir(model_name) 38 | 39 | self.__recreate_dir(model_dir) 40 | return model_dir 41 | 42 | def get_tensorboard_dir(self, data_name, model_name): 43 | return os.path.join(self.__tensorboard_dir, data_name, model_name) 44 | 45 | def recreate_tensorboard_dir(self, data_name, model_name): 46 | tensorboard_dir = self.get_tensorboard_dir(data_name, model_name) 47 | 48 | self.__recreate_dir(tensorboard_dir) 49 | return tensorboard_dir 50 | 51 | def get_eval_dir(self, data_name, model_name): 52 | return os.path.join(self.__eval_dir, data_name, model_name) 53 | 54 | def recreate_eval_dir(self, data_name, model_name): 55 | eval_dir = self.get_eval_dir(data_name, model_name) 56 | 57 | self.__recreate_dir(eval_dir) 58 | return eval_dir 59 | 60 | @staticmethod 61 | def __recreate_dir(path): 62 | if os.path.exists(path): 63 | shutil.rmtree(path) 64 | 65 | os.makedirs(path) 66 | -------------------------------------------------------------------------------- /config/afhq_clip.yaml: -------------------------------------------------------------------------------- 1 | arch_betavae: False 2 | loss_reconstruction: perceptual 3 | 4 | factor_names: 5 | - species 6 | 7 | factor_dim: 256 8 | residual_dim: 64 9 | 10 | residual_std: 0 11 | 12 | perceptual_loss: 13 | - 2 14 | - 7 15 | - 12 16 | - 21 17 | - 30 18 | 19 | train: 20 | batch_size: 32 21 | n_epochs: 100 22 | n_epochs_between_evals: 50 23 | n_epochs_between_visualizations: 1 24 | n_epochs_before_entropy: 10 25 | 26 | learning_rate: 27 | latent: 0.01 28 | classifier: 0.0001 29 | generator: 0.001 30 | min: 0.0001 31 | 32 | loss_weights: 33 | reconstruction: 1 34 | residual_decay: 0.001 35 | 36 | entropy: 0.01 37 | classification: 0.01 38 | supervised: 1 39 | 40 | amortization: 41 | batch_size: 64 42 | n_epochs: 50 43 | n_epochs_between_evals: 50 44 | n_epochs_between_visualizations: 5 45 | 46 | learning_rate: 47 | max: 0.001 48 | min: 0.00001 49 | 50 | synthesis: 51 | batch_size: 32 52 | n_epochs: 100 53 | n_epochs_between_evals: 50 54 | n_epochs_between_visualizations: 1 55 | 56 | adversarial: True 57 | 58 | learning_rate: 59 | generator: 0.0001 60 | discriminator: 0.0001 61 | 62 | loss_weights: 63 | reconstruction: 1 64 | latent: 10 65 | adversarial: 1 66 | 67 | gt_labels: False 68 | -------------------------------------------------------------------------------- /config/cars3d.yaml: -------------------------------------------------------------------------------- 1 | arch_betavae: True 2 | loss_reconstruction: mse 3 | 4 | factor_names: 5 | - elevation 6 | - azimuth 7 | 8 | train_size: 17568 9 | n_labels_per_factor: 1000 10 | 11 | factor_dim: 1 12 | residual_dim: 8 13 | 14 | residual_std: 1 15 | 16 | train: 17 | batch_size: 128 18 | n_epochs: 200 19 | n_epochs_between_evals: 50 20 | n_epochs_between_visualizations: 10 21 | n_epochs_before_entropy: 20 22 | 23 | learning_rate: 24 | latent: 0.01 25 | classifier: 0.0001 26 | generator: 0.001 27 | min: 0.0001 28 | 29 | loss_weights: 30 | reconstruction: 1 31 | residual_decay: 0.00001 32 | 33 | entropy: 0.001 34 | classification: 0.001 35 | supervised: 10 36 | 37 | amortization: 38 | batch_size: 128 39 | n_epochs: 50 40 | n_epochs_between_evals: 25 41 | n_epochs_between_visualizations: 10 42 | 43 | learning_rate: 44 | max: 0.001 45 | min: 0.00001 46 | 47 | synthesis: 48 | batch_size: 128 49 | n_epochs: 50 50 | n_epochs_between_evals: 25 51 | n_epochs_between_visualizations: 10 52 | 53 | adversarial: False 54 | 55 | learning_rate: 56 | generator: 0.0001 57 | 58 | loss_weights: 59 | reconstruction: 1 60 | latent: 10 61 | 62 | gt_labels: True 63 | -------------------------------------------------------------------------------- /config/dsprites.yaml: -------------------------------------------------------------------------------- 1 | arch_betavae: True 2 | loss_reconstruction: bce 3 | 4 | factor_names: 5 | - scale 6 | - x 7 | - y 8 | 9 | train_size: 50000 10 | n_labels_per_factor: 1000 11 | 12 | factor_dim: 1 13 | residual_dim: 7 14 | 15 | residual_std: 1 16 | 17 | train: 18 | batch_size: 128 19 | n_epochs: 200 20 | n_epochs_between_evals: 200 21 | n_epochs_between_visualizations: 10 22 | n_epochs_before_entropy: 20 23 | 24 | learning_rate: 25 | latent: 0.01 26 | classifier: 0.0001 27 | generator: 0.001 28 | min: 0.0001 29 | 30 | loss_weights: 31 | reconstruction: 1 32 | residual_decay: 0.00001 33 | 34 | entropy: 0.001 35 | classification: 0.001 36 | supervised: 10 37 | 38 | amortization: 39 | batch_size: 128 40 | n_epochs: 200 41 | n_epochs_between_evals: 50 42 | n_epochs_between_visualizations: 10 43 | 44 | learning_rate: 45 | max: 0.001 46 | min: 0.00001 47 | 48 | synthesis: 49 | batch_size: 128 50 | n_epochs: 200 51 | n_epochs_between_evals: 50 52 | n_epochs_between_visualizations: 10 53 | 54 | adversarial: False 55 | 56 | learning_rate: 57 | generator: 0.0001 58 | 59 | loss_weights: 60 | reconstruction: 1 61 | latent: 10 62 | 63 | gt_labels: True 64 | -------------------------------------------------------------------------------- /config/ffhq_clip.yaml: -------------------------------------------------------------------------------- 1 | arch_betavae: False 2 | loss_reconstruction: perceptual 3 | 4 | factor_names: 5 | - age 6 | - gender 7 | - ethnicity 8 | - hair_color 9 | - beard 10 | - glasses 11 | 12 | factor_dim: 32 13 | residual_dim: 256 14 | 15 | residual_std: 1 16 | 17 | perceptual_loss: 18 | - 2 19 | - 7 20 | - 12 21 | - 21 22 | - 30 23 | 24 | train: 25 | batch_size: 16 26 | n_epochs: 50 27 | n_epochs_between_evals: 50 28 | n_epochs_between_visualizations: 1 29 | n_epochs_before_entropy: 10 30 | 31 | learning_rate: 32 | latent: 0.01 33 | classifier: 0.0001 34 | generator: 0.001 35 | min: 0.0001 36 | 37 | loss_weights: 38 | reconstruction: 1 39 | residual_decay: 0.00001 40 | 41 | entropy: 0.01 42 | classification: 0.01 43 | supervised: 10 44 | 45 | amortization: 46 | batch_size: 64 47 | n_epochs: 100 48 | n_epochs_between_evals: 50 49 | n_epochs_between_visualizations: 5 50 | 51 | learning_rate: 52 | max: 0.0005 53 | min: 0.00001 54 | 55 | synthesis: 56 | batch_size: 16 57 | n_epochs: 100 58 | n_epochs_between_evals: 50 59 | n_epochs_between_visualizations: 1 60 | 61 | adversarial: True 62 | 63 | learning_rate: 64 | generator: 0.0001 65 | discriminator: 0.0001 66 | 67 | loss_weights: 68 | reconstruction: 1 69 | latent: 1 70 | adversarial: 1 71 | 72 | gt_labels: False 73 | -------------------------------------------------------------------------------- /config/shapes3d.yaml: -------------------------------------------------------------------------------- 1 | arch_betavae: True 2 | loss_reconstruction: mse 3 | 4 | factor_names: 5 | - floor_color 6 | - wall_color 7 | - object_color 8 | 9 | train_size: 20000 10 | n_labels_per_factor: 1000 11 | 12 | factor_dim: 1 13 | residual_dim: 7 14 | 15 | residual_std: 1 16 | 17 | train: 18 | batch_size: 128 19 | n_epochs: 200 20 | n_epochs_between_evals: 50 21 | n_epochs_between_visualizations: 10 22 | n_epochs_before_entropy: 20 23 | 24 | learning_rate: 25 | latent: 0.01 26 | classifier: 0.0001 27 | generator: 0.001 28 | min: 0.0001 29 | 30 | loss_weights: 31 | reconstruction: 1 32 | residual_decay: 0.00001 33 | 34 | entropy: 0.001 35 | classification: 0.001 36 | supervised: 10 37 | 38 | amortization: 39 | batch_size: 128 40 | n_epochs: 50 41 | n_epochs_between_evals: 25 42 | n_epochs_between_visualizations: 10 43 | 44 | learning_rate: 45 | max: 0.001 46 | min: 0.00001 47 | 48 | synthesis: 49 | batch_size: 128 50 | n_epochs: 50 51 | n_epochs_between_evals: 25 52 | n_epochs_between_visualizations: 10 53 | 54 | adversarial: False 55 | 56 | learning_rate: 57 | generator: 0.0001 58 | 59 | loss_weights: 60 | reconstruction: 1 61 | latent: 10 62 | 63 | gt_labels: True 64 | -------------------------------------------------------------------------------- /config/smallnorb.yaml: -------------------------------------------------------------------------------- 1 | arch_betavae: True 2 | loss_reconstruction: mse 3 | 4 | factor_names: 5 | - elevation 6 | - azimuth 7 | - lighting 8 | 9 | train_size: 48600 10 | n_labels_per_factor: 1000 11 | 12 | factor_dim: 1 13 | residual_dim: 7 14 | 15 | residual_std: 1 16 | 17 | train: 18 | batch_size: 128 19 | n_epochs: 200 20 | n_epochs_between_evals: 50 21 | n_epochs_between_visualizations: 10 22 | n_epochs_before_entropy: 20 23 | 24 | learning_rate: 25 | latent: 0.01 26 | classifier: 0.0001 27 | generator: 0.001 28 | min: 0.0001 29 | 30 | loss_weights: 31 | reconstruction: 1 32 | residual_decay: 0.00001 33 | 34 | entropy: 0.001 35 | classification: 0.001 36 | supervised: 10 37 | 38 | amortization: 39 | batch_size: 128 40 | n_epochs: 50 41 | n_epochs_between_evals: 50 42 | n_epochs_between_visualizations: 10 43 | 44 | learning_rate: 45 | max: 0.001 46 | min: 0.00001 47 | 48 | synthesis: 49 | batch_size: 128 50 | n_epochs: 50 51 | n_epochs_between_evals: 50 52 | n_epochs_between_visualizations: 10 53 | 54 | adversarial: False 55 | 56 | learning_rate: 57 | generator: 0.0001 58 | 59 | loss_weights: 60 | reconstruction: 1 61 | latent: 10 62 | 63 | gt_labels: True 64 | -------------------------------------------------------------------------------- /config/stanfordcars_clip.yaml: -------------------------------------------------------------------------------- 1 | arch_betavae: False 2 | loss_reconstruction: perceptual 3 | 4 | factor_names: 5 | - type 6 | - color 7 | 8 | factor_dim: 256 9 | residual_dim: 64 10 | 11 | residual_std: 1 12 | 13 | perceptual_loss: 14 | - 2 15 | - 7 16 | - 12 17 | - 21 18 | - 30 19 | 20 | train: 21 | batch_size: 32 22 | n_epochs: 200 23 | n_epochs_between_evals: 50 24 | n_epochs_between_visualizations: 1 25 | n_epochs_before_entropy: 10 26 | 27 | learning_rate: 28 | latent: 0.01 29 | classifier: 0.0001 30 | generator: 0.001 31 | min: 0.0001 32 | 33 | loss_weights: 34 | reconstruction: 1 35 | residual_decay: 0.00001 36 | 37 | entropy: 0.001 38 | classification: 0.01 39 | supervised: 1 40 | 41 | amortization: 42 | batch_size: 64 43 | n_epochs: 50 44 | n_epochs_between_evals: 50 45 | n_epochs_between_visualizations: 5 46 | 47 | learning_rate: 48 | max: 0.0005 49 | min: 0.00001 50 | 51 | synthesis: 52 | batch_size: 32 53 | n_epochs: 100 54 | n_epochs_between_evals: 50 55 | n_epochs_between_visualizations: 1 56 | 57 | adversarial: True 58 | 59 | learning_rate: 60 | generator: 0.0001 61 | discriminator: 0.0001 62 | 63 | loss_weights: 64 | reconstruction: 1 65 | latent: 1 66 | adversarial: 1 67 | 68 | gt_labels: False 69 | -------------------------------------------------------------------------------- /data.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import os 3 | import glob 4 | from abc import ABC, abstractmethod 5 | from tqdm import tqdm 6 | 7 | import numpy as np 8 | import cv2 9 | import scipy.io 10 | import imageio 11 | from sklearn.utils.extmath import cartesian 12 | import h5py 13 | import PIL 14 | 15 | 16 | class DataSet(ABC): 17 | 18 | def __init__(self, base_dir=None, extras=None): 19 | super().__init__() 20 | self._base_dir = base_dir 21 | self._extras = extras 22 | 23 | @abstractmethod 24 | def read(self): 25 | pass 26 | 27 | def read_subset(self, size, seed): 28 | data = self.read() 29 | 30 | n_samples = data['imgs'].shape[0] 31 | rs = np.random.RandomState(seed) 32 | idx = rs.choice(n_samples, size, replace=False) 33 | 34 | data['imgs'] = data['imgs'][idx] 35 | data['factors'] = data['factors'][idx] 36 | 37 | return data 38 | 39 | 40 | class Cars3D(DataSet): 41 | 42 | def __init__(self, base_dir, extras): 43 | super().__init__(base_dir, extras) 44 | 45 | def read(self): 46 | imgs = np.empty(shape=(4, 24, 183, 64, 64, 3), dtype=np.uint8) 47 | 48 | for i, filename in enumerate(glob.glob(os.path.join(self._base_dir, '*.mat'))): 49 | data_mesh = self._load_mesh(filename) 50 | 51 | factor1 = np.array(list(range(4))) 52 | factor2 = np.array(list(range(24))) 53 | all_factors = np.transpose([ 54 | np.tile(factor1, len(factor2)), 55 | np.repeat(factor2, len(factor1)), 56 | np.tile(i, len(factor1) * len(factor2)) 57 | ]) 58 | 59 | imgs[all_factors[:, 0], all_factors[:, 1], all_factors[:, 2]] = data_mesh 60 | 61 | return { 62 | 'imgs': np.reshape(imgs, (-1, 64, 64, 3)), 63 | 'factors': cartesian((np.arange(4), np.arange(24), np.arange(183))), 64 | 'factor_sizes': [4, 24, 183], 65 | 'factor_names': ['elevation', 'azimuth', 'object'] 66 | } 67 | 68 | @staticmethod 69 | def _load_mesh(filename): 70 | with open(os.path.join(filename), "rb") as f: 71 | mesh = np.einsum("abcde->deabc", scipy.io.loadmat(f)["im"]) 72 | flattened_mesh = mesh.reshape((-1,) + mesh.shape[2:]) 73 | rescaled_mesh = np.zeros((flattened_mesh.shape[0], 64, 64, 3), np.uint8) 74 | for i in range(flattened_mesh.shape[0]): 75 | pic = PIL.Image.fromarray(flattened_mesh[i, :, :, :]) 76 | pic.thumbnail((64, 64), PIL.Image.ANTIALIAS) 77 | rescaled_mesh[i, :, :, :] = np.array(pic) 78 | return rescaled_mesh 79 | 80 | 81 | class SmallNorb(DataSet): 82 | 83 | def __init__(self, base_dir, extras): 84 | super().__init__(base_dir, extras) 85 | 86 | self.template = os.path.join(base_dir, "smallnorb-{}-{}.mat") 87 | self.chunk_names = [ 88 | "5x46789x9x18x6x2x96x96-training", 89 | "5x01235x9x18x6x2x96x96-testing", 90 | ] 91 | 92 | def read(self): 93 | list_of_images, list_of_features = self._load_chunks(self.chunk_names) 94 | imgs = np.concatenate(list_of_images, axis=0) 95 | features = np.concatenate(list_of_features, axis=0) 96 | features[:, 3] = features[:, 3] // 2 # azimuth values are 0, 2, 4, ..., 24 97 | 98 | sort_idx = np.lexsort([features[:, i] for i in range(4, -1, -1)]) 99 | 100 | return { 101 | 'imgs': imgs[sort_idx], 102 | 'factors': features[sort_idx], 103 | 'factor_sizes': [np.unique(features[:, f]).size for f in range(features.shape[1])], 104 | 'factor_names': ['category', 'instance', 'elevation', 'azimuth', 'lighting'] 105 | } 106 | 107 | def _load_chunks(self, chunk_names): 108 | list_of_images = [] 109 | list_of_features = [] 110 | for chunk_name in chunk_names: 111 | norb = self._read_binary_matrix(self.template.format(chunk_name, "dat")) 112 | list_of_images.append(self._resize_images(norb[:, 0])) 113 | norb_class = self._read_binary_matrix(self.template.format(chunk_name, "cat")) 114 | norb_info = self._read_binary_matrix(self.template.format(chunk_name, "info")) 115 | list_of_features.append(np.column_stack((norb_class, norb_info))) 116 | 117 | return list_of_images, list_of_features 118 | 119 | @staticmethod 120 | def _read_binary_matrix(filename): 121 | with open(filename, "rb") as f: 122 | s = f.read() 123 | magic = int(np.frombuffer(s, "int32", 1)) 124 | ndim = int(np.frombuffer(s, "int32", 1, 4)) 125 | eff_dim = max(3, ndim) 126 | raw_dims = np.frombuffer(s, "int32", eff_dim, 8) 127 | dims = [] 128 | for i in range(0, ndim): 129 | dims.append(raw_dims[i]) 130 | 131 | dtype_map = { 132 | 507333717: "int8", 133 | 507333716: "int32", 134 | 507333713: "float", 135 | 507333715: "double" 136 | } 137 | data = np.frombuffer(s, dtype_map[magic], offset=8 + eff_dim * 4) 138 | data = data.reshape(tuple(dims)) 139 | return data 140 | 141 | @staticmethod 142 | def _resize_images(integer_images): 143 | resized_images = np.zeros((integer_images.shape[0], 64, 64, 1), dtype=np.uint8) 144 | for i in range(integer_images.shape[0]): 145 | image = PIL.Image.fromarray(integer_images[i, :, :]) 146 | image = image.resize((64, 64), PIL.Image.ANTIALIAS) 147 | resized_images[i, :, :, 0] = image 148 | 149 | return resized_images 150 | 151 | 152 | class Shapes3D(DataSet): 153 | 154 | def __init__(self, base_dir, extras): 155 | super().__init__(base_dir, extras) 156 | 157 | self.__data_path = os.path.join(base_dir, '3dshapes.h5') 158 | 159 | def read(self): 160 | with h5py.File(self.__data_path, 'r') as data: 161 | imgs = data['images'][:] 162 | labels = data['labels'][:] 163 | 164 | factors = np.zeros(labels.shape, dtype=np.int64) 165 | for f in range(labels.shape[1]): 166 | factor_unique_values = np.unique(labels[:, f]) 167 | factors[:, f] = np.argmax(labels[:, [f]] == factor_unique_values, axis=1) 168 | 169 | return { 170 | 'imgs': imgs, 171 | 'factors': factors, 172 | 'factor_sizes': [np.unique(factors[:, f]).size for f in range(factors.shape[1])], 173 | 'factor_names': ['floor_color', 'wall_color', 'object_color', 'scale', 'shape', 'azimuth'] 174 | } 175 | 176 | 177 | class DSprites(DataSet): 178 | 179 | def __init__(self, base_dir, extras): 180 | super().__init__(base_dir, extras) 181 | 182 | self.__data_path = os.path.join(base_dir, 'dsprites_ndarray_co1sh3sc6or40x32y32_64x64.npz') 183 | 184 | def read(self): 185 | data = np.load(self.__data_path) 186 | imgs = data['imgs'][..., np.newaxis] * 255 187 | factors = data['latents_classes'][:, 1:] 188 | 189 | return { 190 | 'imgs': imgs, 191 | 'factors': factors, 192 | 'factor_sizes': [np.unique(factors[:, f]).size for f in range(factors.shape[1])], 193 | 'factor_names': ['shape', 'scale', 'orientation', 'x', 'y'] 194 | } 195 | 196 | 197 | class FFHQ(DataSet): 198 | 199 | def __init__(self, base_dir, extras): 200 | super().__init__(base_dir) 201 | 202 | parser = argparse.ArgumentParser() 203 | parser.add_argument('-is', '--img-size', type=int, default=256) 204 | 205 | args = parser.parse_args(extras) 206 | self.__dict__.update(vars(args)) 207 | 208 | def read(self): 209 | imgs = np.empty(shape=(70000, self.img_size, self.img_size, 3), dtype=np.uint8) 210 | img_ids = np.arange(70000) 211 | for i in tqdm(img_ids): 212 | img_path = os.path.join(self._base_dir, 'imgs', '{:05d}.png'.format(i)) 213 | imgs[i] = cv2.resize(imageio.imread(img_path), dsize=(self.img_size, self.img_size)) 214 | 215 | return { 216 | 'imgs': imgs 217 | } 218 | 219 | 220 | supported_datasets = { 221 | 'cars3d': Cars3D, 222 | 'smallnorb': SmallNorb, 223 | 'shapes3d': Shapes3D, 224 | 'dsprites': DSprites, 225 | 'ffhq': FFHQ 226 | } 227 | -------------------------------------------------------------------------------- /evaluation/classifier.py: -------------------------------------------------------------------------------- 1 | from sklearn.model_selection import train_test_split 2 | from sklearn.preprocessing import StandardScaler 3 | from sklearn.linear_model import LogisticRegression 4 | 5 | 6 | def logistic_regression(latents, factors): 7 | scaler = StandardScaler() 8 | latents = scaler.fit_transform(latents) 9 | 10 | latents_train, latents_test, factors_train, factors_test = train_test_split(latents, factors, test_size=0.2, random_state=1337) 11 | 12 | classifier = LogisticRegression(random_state=1337) 13 | classifier.fit(latents_train, factors_train) 14 | 15 | acc_train = classifier.score(latents_train, factors_train) 16 | acc_test = classifier.score(latents_test, factors_test) 17 | 18 | return acc_train, acc_test 19 | -------------------------------------------------------------------------------- /evaluation/dci.py: -------------------------------------------------------------------------------- 1 | from tqdm import tqdm 2 | 3 | import numpy as np 4 | import scipy 5 | 6 | from sklearn import ensemble 7 | from sklearn.model_selection import train_test_split 8 | 9 | 10 | def evaluate(latents, factors): 11 | latents_train, latents_test, factors_train, factors_test = train_test_split(latents, factors, test_size=0.2, random_state=1337) 12 | 13 | importance_matrix, acc_train, acc_test = compute_importance_gbt( 14 | latents_train, latents_test, 15 | factors_train, factors_test 16 | ) 17 | 18 | print(importance_matrix) 19 | 20 | scores = { 21 | 'informativeness_train': acc_train, 22 | 'informativeness_test': acc_test, 23 | 'disentanglement': disentanglement(importance_matrix), 24 | 'completeness': completeness(importance_matrix) 25 | } 26 | 27 | return scores 28 | 29 | 30 | def compute_importance_gbt(x_train, x_test, y_train, y_test): 31 | latent_dim = x_train.shape[1] 32 | n_factors = y_train.shape[1] 33 | 34 | importance_matrix = np.zeros(shape=[latent_dim, n_factors], dtype=np.float64) 35 | acc_train = [] 36 | acc_test = [] 37 | 38 | pbar = tqdm(range(n_factors)) 39 | for i in pbar: 40 | pbar.set_description_str('[dci] factor #{}/#{}'.format(i + 1, n_factors)) 41 | 42 | model = ensemble.GradientBoostingClassifier() 43 | model.fit(x_train.reshape(x_train.shape[0], -1), y_train[:, i]) 44 | 45 | importance_matrix[:, i] = np.sum(model.feature_importances_.reshape(latent_dim, -1), axis=-1) 46 | acc_train.append(np.mean(model.predict(x_train.reshape(x_train.shape[0], -1)) == y_train[:, i])) 47 | acc_test.append(np.mean(model.predict(x_test.reshape(x_test.shape[0], -1)) == y_test[:, i])) 48 | 49 | return importance_matrix, np.mean(acc_train), np.mean(acc_test) 50 | 51 | 52 | def disentanglement_per_code(importance_matrix): 53 | return 1. - scipy.stats.entropy(importance_matrix.T + 1e-11, base=importance_matrix.shape[1]) 54 | 55 | 56 | def disentanglement(importance_matrix): 57 | per_code = disentanglement_per_code(importance_matrix) 58 | 59 | if importance_matrix.sum() == 0.: 60 | importance_matrix = np.ones_like(importance_matrix) 61 | 62 | code_importance = importance_matrix.sum(axis=1) / importance_matrix.sum() 63 | return np.sum(per_code * code_importance) 64 | 65 | 66 | def completeness_per_factor(importance_matrix): 67 | return 1. - scipy.stats.entropy(importance_matrix + 1e-11, base=importance_matrix.shape[0]) 68 | 69 | 70 | def completeness(importance_matrix): 71 | per_factor = completeness_per_factor(importance_matrix) 72 | 73 | if importance_matrix.sum() == 0.: 74 | importance_matrix = np.ones_like(importance_matrix) 75 | 76 | factor_importance = importance_matrix.sum(axis=0) / importance_matrix.sum() 77 | return np.sum(per_factor * factor_importance) 78 | -------------------------------------------------------------------------------- /evaluation/mig.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import sklearn 3 | 4 | 5 | def evaluate(latents, factors): 6 | assert len(latents.shape) == 2 or latents.shape[2] == 1 7 | latents = latents.reshape(latents.shape[0], -1) 8 | 9 | latents = latents.T 10 | factors = factors.T 11 | 12 | latents_discretized = _histogram_discretize(latents) 13 | m = discrete_mutual_info(latents_discretized, factors) 14 | 15 | # m is [num_latents, num_factors] 16 | entropy = discrete_entropy(factors) 17 | sorted_m = np.sort(m, axis=0)[::-1] 18 | 19 | scores = { 20 | 'mig': np.mean(np.divide(sorted_m[0, :] - sorted_m[1, :], entropy[:])) 21 | } 22 | 23 | return scores 24 | 25 | 26 | def _histogram_discretize(target, num_bins=20): 27 | discretized = np.zeros_like(target) 28 | 29 | for i in range(target.shape[0]): 30 | discretized[i, :] = np.digitize(target[i, :], np.histogram(target[i, :], num_bins)[1][:-1]) 31 | 32 | return discretized 33 | 34 | 35 | def discrete_mutual_info(mus, ys): 36 | num_codes = mus.shape[0] 37 | num_factors = ys.shape[0] 38 | 39 | m = np.zeros([num_codes, num_factors]) 40 | for i in range(num_codes): 41 | for j in range(num_factors): 42 | m[i, j] = sklearn.metrics.mutual_info_score(ys[j, :], mus[i, :]) 43 | 44 | return m 45 | 46 | 47 | def discrete_entropy(ys): 48 | num_factors = ys.shape[0] 49 | h = np.zeros(num_factors) 50 | 51 | for j in range(num_factors): 52 | h[j] = sklearn.metrics.mutual_info_score(ys[j, :], ys[j, :]) 53 | 54 | return h 55 | -------------------------------------------------------------------------------- /evaluation/sap.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | from sklearn import svm 4 | from sklearn.model_selection import train_test_split 5 | 6 | 7 | def evaluate(latents, factors): 8 | assert len(latents.shape) == 2 or latents.shape[2] == 1 9 | latents = latents.reshape(latents.shape[0], -1) 10 | 11 | latents_train, latents_test, factors_train, factors_test = train_test_split(latents, factors, test_size=0.2, random_state=1337) 12 | 13 | score_matrix = compute_score_matrix( 14 | latents_train, latents_test, 15 | factors_train, factors_test 16 | ) 17 | 18 | scores = { 19 | 'sap': compute_avg_diff_top_two(score_matrix) 20 | } 21 | 22 | return scores 23 | 24 | 25 | def compute_score_matrix(x_train, x_test, y_train, y_test): 26 | latent_dim = x_train.shape[1] 27 | n_factors = y_train.shape[1] 28 | 29 | score_matrix = np.zeros(shape=[latent_dim, n_factors], dtype=np.float64) 30 | 31 | for i in range(latent_dim): 32 | for j in range(n_factors): 33 | mu_i = x_train[:, i] 34 | y_j = y_train[:, j] 35 | 36 | mu_i_test = x_test[:, i] 37 | y_j_test = y_test[:, j] 38 | 39 | # TODO: squeeze if needed 40 | 41 | classifier = svm.LinearSVC(C=0.01, class_weight="balanced") 42 | classifier.fit(mu_i[:, np.newaxis], y_j) 43 | pred = classifier.predict(mu_i_test[:, np.newaxis]) 44 | score_matrix[i, j] = np.mean(pred == y_j_test) 45 | 46 | return score_matrix 47 | 48 | 49 | def compute_avg_diff_top_two(matrix): 50 | sorted_matrix = np.sort(matrix, axis=0) 51 | return np.mean(sorted_matrix[-1, :] - sorted_matrix[-2, :]) 52 | -------------------------------------------------------------------------------- /img/animals/a/arctic_fox.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/a/arctic_fox.jpg -------------------------------------------------------------------------------- /img/animals/a/boerboel.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/a/boerboel.jpg -------------------------------------------------------------------------------- /img/animals/a/bombay_cat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/a/bombay_cat.jpg -------------------------------------------------------------------------------- /img/animals/a/cheetah.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/a/cheetah.jpg -------------------------------------------------------------------------------- /img/animals/a/chihuahua.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/a/chihuahua.jpg -------------------------------------------------------------------------------- /img/animals/a/husky.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/a/husky.jpg -------------------------------------------------------------------------------- /img/animals/a/input.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/a/input.jpg -------------------------------------------------------------------------------- /img/animals/a/jaguar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/a/jaguar.jpg -------------------------------------------------------------------------------- /img/animals/a/labradoodle.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/a/labradoodle.jpg -------------------------------------------------------------------------------- /img/animals/a/shiba_inu.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/a/shiba_inu.jpg -------------------------------------------------------------------------------- /img/animals/b/arctic_fox.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/b/arctic_fox.jpg -------------------------------------------------------------------------------- /img/animals/b/boerboel.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/b/boerboel.jpg -------------------------------------------------------------------------------- /img/animals/b/bombay_cat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/b/bombay_cat.jpg -------------------------------------------------------------------------------- /img/animals/b/cheetah.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/b/cheetah.jpg -------------------------------------------------------------------------------- /img/animals/b/chihuahua.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/b/chihuahua.jpg -------------------------------------------------------------------------------- /img/animals/b/husky.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/b/husky.jpg -------------------------------------------------------------------------------- /img/animals/b/input.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/b/input.jpg -------------------------------------------------------------------------------- /img/animals/b/jaguar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/b/jaguar.jpg -------------------------------------------------------------------------------- /img/animals/b/labradoodle.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/b/labradoodle.jpg -------------------------------------------------------------------------------- /img/animals/b/shiba_inu.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/b/shiba_inu.jpg -------------------------------------------------------------------------------- /img/animals/c/arctic_fox.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/c/arctic_fox.jpg -------------------------------------------------------------------------------- /img/animals/c/boerboel.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/c/boerboel.jpg -------------------------------------------------------------------------------- /img/animals/c/bombay_cat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/c/bombay_cat.jpg -------------------------------------------------------------------------------- /img/animals/c/cheetah.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/c/cheetah.jpg -------------------------------------------------------------------------------- /img/animals/c/chihuahua.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/c/chihuahua.jpg -------------------------------------------------------------------------------- /img/animals/c/husky.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/c/husky.jpg -------------------------------------------------------------------------------- /img/animals/c/input.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/c/input.jpg -------------------------------------------------------------------------------- /img/animals/c/jaguar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/c/jaguar.jpg -------------------------------------------------------------------------------- /img/animals/c/labradoodle.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/c/labradoodle.jpg -------------------------------------------------------------------------------- /img/animals/c/shiba_inu.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/c/shiba_inu.jpg -------------------------------------------------------------------------------- /img/animals/d/arctic_fox.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/d/arctic_fox.jpg -------------------------------------------------------------------------------- /img/animals/d/boerboel.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/d/boerboel.jpg -------------------------------------------------------------------------------- /img/animals/d/bombay_cat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/d/bombay_cat.jpg -------------------------------------------------------------------------------- /img/animals/d/cheetah.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/d/cheetah.jpg -------------------------------------------------------------------------------- /img/animals/d/chihuahua.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/d/chihuahua.jpg -------------------------------------------------------------------------------- /img/animals/d/husky.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/d/husky.jpg -------------------------------------------------------------------------------- /img/animals/d/input.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/d/input.jpg -------------------------------------------------------------------------------- /img/animals/d/jaguar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/d/jaguar.jpg -------------------------------------------------------------------------------- /img/animals/d/labradoodle.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/d/labradoodle.jpg -------------------------------------------------------------------------------- /img/animals/d/shiba_inu.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/d/shiba_inu.jpg -------------------------------------------------------------------------------- /img/animals/e/arctic_fox.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/e/arctic_fox.jpg -------------------------------------------------------------------------------- /img/animals/e/boerboel.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/e/boerboel.jpg -------------------------------------------------------------------------------- /img/animals/e/bombay_cat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/e/bombay_cat.jpg -------------------------------------------------------------------------------- /img/animals/e/cheetah.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/e/cheetah.jpg -------------------------------------------------------------------------------- /img/animals/e/chihuahua.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/e/chihuahua.jpg -------------------------------------------------------------------------------- /img/animals/e/husky.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/e/husky.jpg -------------------------------------------------------------------------------- /img/animals/e/input.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/e/input.jpg -------------------------------------------------------------------------------- /img/animals/e/jaguar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/e/jaguar.jpg -------------------------------------------------------------------------------- /img/animals/e/labradoodle.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/e/labradoodle.jpg -------------------------------------------------------------------------------- /img/animals/e/shiba_inu.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/e/shiba_inu.jpg -------------------------------------------------------------------------------- /img/animals/f/arctic_fox.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/f/arctic_fox.jpg -------------------------------------------------------------------------------- /img/animals/f/boerboel.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/f/boerboel.jpg -------------------------------------------------------------------------------- /img/animals/f/bombay_cat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/f/bombay_cat.jpg -------------------------------------------------------------------------------- /img/animals/f/cheetah.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/f/cheetah.jpg -------------------------------------------------------------------------------- /img/animals/f/chihuahua.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/f/chihuahua.jpg -------------------------------------------------------------------------------- /img/animals/f/husky.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/f/husky.jpg -------------------------------------------------------------------------------- /img/animals/f/input.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/f/input.jpg -------------------------------------------------------------------------------- /img/animals/f/jaguar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/f/jaguar.jpg -------------------------------------------------------------------------------- /img/animals/f/labradoodle.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/f/labradoodle.jpg -------------------------------------------------------------------------------- /img/animals/f/shiba_inu.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/f/shiba_inu.jpg -------------------------------------------------------------------------------- /img/animals/g/arctic_fox.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/g/arctic_fox.jpg -------------------------------------------------------------------------------- /img/animals/g/boerboel.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/g/boerboel.jpg -------------------------------------------------------------------------------- /img/animals/g/bombay_cat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/g/bombay_cat.jpg -------------------------------------------------------------------------------- /img/animals/g/cheetah.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/g/cheetah.jpg -------------------------------------------------------------------------------- /img/animals/g/chihuahua.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/g/chihuahua.jpg -------------------------------------------------------------------------------- /img/animals/g/husky.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/g/husky.jpg -------------------------------------------------------------------------------- /img/animals/g/input.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/g/input.jpg -------------------------------------------------------------------------------- /img/animals/g/jaguar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/g/jaguar.jpg -------------------------------------------------------------------------------- /img/animals/g/labradoodle.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/g/labradoodle.jpg -------------------------------------------------------------------------------- /img/animals/g/shiba_inu.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/g/shiba_inu.jpg -------------------------------------------------------------------------------- /img/animals/h/arctic_fox.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/h/arctic_fox.jpg -------------------------------------------------------------------------------- /img/animals/h/boerboel.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/h/boerboel.jpg -------------------------------------------------------------------------------- /img/animals/h/bombay_cat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/h/bombay_cat.jpg -------------------------------------------------------------------------------- /img/animals/h/cheetah.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/h/cheetah.jpg -------------------------------------------------------------------------------- /img/animals/h/chihuahua.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/h/chihuahua.jpg -------------------------------------------------------------------------------- /img/animals/h/husky.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/h/husky.jpg -------------------------------------------------------------------------------- /img/animals/h/input.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/h/input.jpg -------------------------------------------------------------------------------- /img/animals/h/jaguar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/h/jaguar.jpg -------------------------------------------------------------------------------- /img/animals/h/labradoodle.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/h/labradoodle.jpg -------------------------------------------------------------------------------- /img/animals/h/shiba_inu.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/h/shiba_inu.jpg -------------------------------------------------------------------------------- /img/animals/i/arctic_fox.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/i/arctic_fox.jpg -------------------------------------------------------------------------------- /img/animals/i/boerboel.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/i/boerboel.jpg -------------------------------------------------------------------------------- /img/animals/i/bombay_cat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/i/bombay_cat.jpg -------------------------------------------------------------------------------- /img/animals/i/cheetah.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/i/cheetah.jpg -------------------------------------------------------------------------------- /img/animals/i/chihuahua.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/i/chihuahua.jpg -------------------------------------------------------------------------------- /img/animals/i/husky.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/i/husky.jpg -------------------------------------------------------------------------------- /img/animals/i/input.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/i/input.jpg -------------------------------------------------------------------------------- /img/animals/i/jaguar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/i/jaguar.jpg -------------------------------------------------------------------------------- /img/animals/i/labradoodle.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/i/labradoodle.jpg -------------------------------------------------------------------------------- /img/animals/i/shiba_inu.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/i/shiba_inu.jpg -------------------------------------------------------------------------------- /img/animals/j/arctic_fox.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/j/arctic_fox.jpg -------------------------------------------------------------------------------- /img/animals/j/boerboel.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/j/boerboel.jpg -------------------------------------------------------------------------------- /img/animals/j/bombay_cat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/j/bombay_cat.jpg -------------------------------------------------------------------------------- /img/animals/j/cheetah.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/j/cheetah.jpg -------------------------------------------------------------------------------- /img/animals/j/chihuahua.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/j/chihuahua.jpg -------------------------------------------------------------------------------- /img/animals/j/husky.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/j/husky.jpg -------------------------------------------------------------------------------- /img/animals/j/input.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/j/input.jpg -------------------------------------------------------------------------------- /img/animals/j/jaguar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/j/jaguar.jpg -------------------------------------------------------------------------------- /img/animals/j/labradoodle.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/j/labradoodle.jpg -------------------------------------------------------------------------------- /img/animals/j/shiba_inu.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/j/shiba_inu.jpg -------------------------------------------------------------------------------- /img/animals/k/arctic_fox.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/k/arctic_fox.jpg -------------------------------------------------------------------------------- /img/animals/k/boerboel.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/k/boerboel.jpg -------------------------------------------------------------------------------- /img/animals/k/bombay_cat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/k/bombay_cat.jpg -------------------------------------------------------------------------------- /img/animals/k/cheetah.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/k/cheetah.jpg -------------------------------------------------------------------------------- /img/animals/k/chihuahua.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/k/chihuahua.jpg -------------------------------------------------------------------------------- /img/animals/k/husky.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/k/husky.jpg -------------------------------------------------------------------------------- /img/animals/k/input.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/k/input.jpg -------------------------------------------------------------------------------- /img/animals/k/jaguar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/k/jaguar.jpg -------------------------------------------------------------------------------- /img/animals/k/labradoodle.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/k/labradoodle.jpg -------------------------------------------------------------------------------- /img/animals/k/shiba_inu.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/animals/k/shiba_inu.jpg -------------------------------------------------------------------------------- /img/cars/a/black.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/a/black.jpg -------------------------------------------------------------------------------- /img/cars/a/blue.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/a/blue.jpg -------------------------------------------------------------------------------- /img/cars/a/family.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/a/family.jpg -------------------------------------------------------------------------------- /img/cars/a/input.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/a/input.jpg -------------------------------------------------------------------------------- /img/cars/a/jeep.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/a/jeep.jpg -------------------------------------------------------------------------------- /img/cars/a/red.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/a/red.jpg -------------------------------------------------------------------------------- /img/cars/a/sports.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/a/sports.jpg -------------------------------------------------------------------------------- /img/cars/a/white.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/a/white.jpg -------------------------------------------------------------------------------- /img/cars/a/yellow.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/a/yellow.jpg -------------------------------------------------------------------------------- /img/cars/aa/black.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/aa/black.jpg -------------------------------------------------------------------------------- /img/cars/aa/blue.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/aa/blue.jpg -------------------------------------------------------------------------------- /img/cars/aa/family.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/aa/family.jpg -------------------------------------------------------------------------------- /img/cars/aa/input.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/aa/input.jpg -------------------------------------------------------------------------------- /img/cars/aa/jeep.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/aa/jeep.jpg -------------------------------------------------------------------------------- /img/cars/aa/red.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/aa/red.jpg -------------------------------------------------------------------------------- /img/cars/aa/sports.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/aa/sports.jpg -------------------------------------------------------------------------------- /img/cars/aa/white.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/aa/white.jpg -------------------------------------------------------------------------------- /img/cars/aa/yellow.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/aa/yellow.jpg -------------------------------------------------------------------------------- /img/cars/b/black.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/b/black.jpg -------------------------------------------------------------------------------- /img/cars/b/blue.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/b/blue.jpg -------------------------------------------------------------------------------- /img/cars/b/family.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/b/family.jpg -------------------------------------------------------------------------------- /img/cars/b/input.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/b/input.jpg -------------------------------------------------------------------------------- /img/cars/b/jeep.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/b/jeep.jpg -------------------------------------------------------------------------------- /img/cars/b/red.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/b/red.jpg -------------------------------------------------------------------------------- /img/cars/b/sports.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/b/sports.jpg -------------------------------------------------------------------------------- /img/cars/b/white.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/b/white.jpg -------------------------------------------------------------------------------- /img/cars/b/yellow.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/b/yellow.jpg -------------------------------------------------------------------------------- /img/cars/c/black.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/c/black.jpg -------------------------------------------------------------------------------- /img/cars/c/blue.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/c/blue.jpg -------------------------------------------------------------------------------- /img/cars/c/family.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/c/family.jpg -------------------------------------------------------------------------------- /img/cars/c/input.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/c/input.jpg -------------------------------------------------------------------------------- /img/cars/c/jeep.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/c/jeep.jpg -------------------------------------------------------------------------------- /img/cars/c/red.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/c/red.jpg -------------------------------------------------------------------------------- /img/cars/c/sports.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/c/sports.jpg -------------------------------------------------------------------------------- /img/cars/c/white.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/c/white.jpg -------------------------------------------------------------------------------- /img/cars/c/yellow.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/c/yellow.jpg -------------------------------------------------------------------------------- /img/cars/d/black.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/d/black.jpg -------------------------------------------------------------------------------- /img/cars/d/blue.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/d/blue.jpg -------------------------------------------------------------------------------- /img/cars/d/family.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/d/family.jpg -------------------------------------------------------------------------------- /img/cars/d/input.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/d/input.jpg -------------------------------------------------------------------------------- /img/cars/d/jeep.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/d/jeep.jpg -------------------------------------------------------------------------------- /img/cars/d/red.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/d/red.jpg -------------------------------------------------------------------------------- /img/cars/d/sports.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/d/sports.jpg -------------------------------------------------------------------------------- /img/cars/d/white.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/d/white.jpg -------------------------------------------------------------------------------- /img/cars/d/yellow.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/d/yellow.jpg -------------------------------------------------------------------------------- /img/cars/e/black.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/e/black.jpg -------------------------------------------------------------------------------- /img/cars/e/blue.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/e/blue.jpg -------------------------------------------------------------------------------- /img/cars/e/family.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/e/family.jpg -------------------------------------------------------------------------------- /img/cars/e/input.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/e/input.jpg -------------------------------------------------------------------------------- /img/cars/e/jeep.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/e/jeep.jpg -------------------------------------------------------------------------------- /img/cars/e/red.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/e/red.jpg -------------------------------------------------------------------------------- /img/cars/e/sports.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/e/sports.jpg -------------------------------------------------------------------------------- /img/cars/e/white.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/e/white.jpg -------------------------------------------------------------------------------- /img/cars/e/yellow.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/e/yellow.jpg -------------------------------------------------------------------------------- /img/cars/ee/black.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/ee/black.jpg -------------------------------------------------------------------------------- /img/cars/ee/blue.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/ee/blue.jpg -------------------------------------------------------------------------------- /img/cars/ee/family.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/ee/family.jpg -------------------------------------------------------------------------------- /img/cars/ee/input.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/ee/input.jpg -------------------------------------------------------------------------------- /img/cars/ee/jeep.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/ee/jeep.jpg -------------------------------------------------------------------------------- /img/cars/ee/red.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/ee/red.jpg -------------------------------------------------------------------------------- /img/cars/ee/sports.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/ee/sports.jpg -------------------------------------------------------------------------------- /img/cars/ee/white.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/ee/white.jpg -------------------------------------------------------------------------------- /img/cars/ee/yellow.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/ee/yellow.jpg -------------------------------------------------------------------------------- /img/cars/ee2/black.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/ee2/black.jpg -------------------------------------------------------------------------------- /img/cars/ee2/blue.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/ee2/blue.jpg -------------------------------------------------------------------------------- /img/cars/ee2/family.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/ee2/family.jpg -------------------------------------------------------------------------------- /img/cars/ee2/input.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/ee2/input.jpg -------------------------------------------------------------------------------- /img/cars/ee2/jeep.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/ee2/jeep.jpg -------------------------------------------------------------------------------- /img/cars/ee2/red.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/ee2/red.jpg -------------------------------------------------------------------------------- /img/cars/ee2/sports.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/ee2/sports.jpg -------------------------------------------------------------------------------- /img/cars/ee2/white.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/ee2/white.jpg -------------------------------------------------------------------------------- /img/cars/ee2/yellow.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/ee2/yellow.jpg -------------------------------------------------------------------------------- /img/cars/f/black.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/f/black.jpg -------------------------------------------------------------------------------- /img/cars/f/blue.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/f/blue.jpg -------------------------------------------------------------------------------- /img/cars/f/family.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/f/family.jpg -------------------------------------------------------------------------------- /img/cars/f/input.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/f/input.jpg -------------------------------------------------------------------------------- /img/cars/f/jeep.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/f/jeep.jpg -------------------------------------------------------------------------------- /img/cars/f/red.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/f/red.jpg -------------------------------------------------------------------------------- /img/cars/f/sports.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/f/sports.jpg -------------------------------------------------------------------------------- /img/cars/f/white.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/f/white.jpg -------------------------------------------------------------------------------- /img/cars/f/yellow.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/f/yellow.jpg -------------------------------------------------------------------------------- /img/cars/g/black.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/g/black.jpg -------------------------------------------------------------------------------- /img/cars/g/blue.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/g/blue.jpg -------------------------------------------------------------------------------- /img/cars/g/family.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/g/family.jpg -------------------------------------------------------------------------------- /img/cars/g/input.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/g/input.jpg -------------------------------------------------------------------------------- /img/cars/g/jeep.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/g/jeep.jpg -------------------------------------------------------------------------------- /img/cars/g/red.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/g/red.jpg -------------------------------------------------------------------------------- /img/cars/g/sports.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/g/sports.jpg -------------------------------------------------------------------------------- /img/cars/g/white.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/g/white.jpg -------------------------------------------------------------------------------- /img/cars/g/yellow.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/g/yellow.jpg -------------------------------------------------------------------------------- /img/cars/gg/black.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/gg/black.jpg -------------------------------------------------------------------------------- /img/cars/gg/blue.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/gg/blue.jpg -------------------------------------------------------------------------------- /img/cars/gg/family.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/gg/family.jpg -------------------------------------------------------------------------------- /img/cars/gg/input.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/gg/input.jpg -------------------------------------------------------------------------------- /img/cars/gg/jeep.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/gg/jeep.jpg -------------------------------------------------------------------------------- /img/cars/gg/red.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/gg/red.jpg -------------------------------------------------------------------------------- /img/cars/gg/sports.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/gg/sports.jpg -------------------------------------------------------------------------------- /img/cars/gg/white.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/gg/white.jpg -------------------------------------------------------------------------------- /img/cars/gg/yellow.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/gg/yellow.jpg -------------------------------------------------------------------------------- /img/cars/h/black.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/h/black.jpg -------------------------------------------------------------------------------- /img/cars/h/blue.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/h/blue.jpg -------------------------------------------------------------------------------- /img/cars/h/family.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/h/family.jpg -------------------------------------------------------------------------------- /img/cars/h/input.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/h/input.jpg -------------------------------------------------------------------------------- /img/cars/h/jeep.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/h/jeep.jpg -------------------------------------------------------------------------------- /img/cars/h/red.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/h/red.jpg -------------------------------------------------------------------------------- /img/cars/h/sports.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/h/sports.jpg -------------------------------------------------------------------------------- /img/cars/h/white.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/h/white.jpg -------------------------------------------------------------------------------- /img/cars/h/yellow.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/h/yellow.jpg -------------------------------------------------------------------------------- /img/cars/i/black.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/i/black.jpg -------------------------------------------------------------------------------- /img/cars/i/blue.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/i/blue.jpg -------------------------------------------------------------------------------- /img/cars/i/family.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/i/family.jpg -------------------------------------------------------------------------------- /img/cars/i/input.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/i/input.jpg -------------------------------------------------------------------------------- /img/cars/i/jeep.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/i/jeep.jpg -------------------------------------------------------------------------------- /img/cars/i/red.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/i/red.jpg -------------------------------------------------------------------------------- /img/cars/i/sports.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/i/sports.jpg -------------------------------------------------------------------------------- /img/cars/i/white.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/i/white.jpg -------------------------------------------------------------------------------- /img/cars/i/yellow.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/i/yellow.jpg -------------------------------------------------------------------------------- /img/cars/k/black.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/k/black.jpg -------------------------------------------------------------------------------- /img/cars/k/blue.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/k/blue.jpg -------------------------------------------------------------------------------- /img/cars/k/family.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/k/family.jpg -------------------------------------------------------------------------------- /img/cars/k/input.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/k/input.jpg -------------------------------------------------------------------------------- /img/cars/k/jeep.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/k/jeep.jpg -------------------------------------------------------------------------------- /img/cars/k/red.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/k/red.jpg -------------------------------------------------------------------------------- /img/cars/k/sports.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/k/sports.jpg -------------------------------------------------------------------------------- /img/cars/k/white.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/k/white.jpg -------------------------------------------------------------------------------- /img/cars/k/yellow.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/k/yellow.jpg -------------------------------------------------------------------------------- /img/cars/l/black.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/l/black.jpg -------------------------------------------------------------------------------- /img/cars/l/blue.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/l/blue.jpg -------------------------------------------------------------------------------- /img/cars/l/family.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/l/family.jpg -------------------------------------------------------------------------------- /img/cars/l/input.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/l/input.jpg -------------------------------------------------------------------------------- /img/cars/l/jeep.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/l/jeep.jpg -------------------------------------------------------------------------------- /img/cars/l/red.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/l/red.jpg -------------------------------------------------------------------------------- /img/cars/l/sports.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/l/sports.jpg -------------------------------------------------------------------------------- /img/cars/l/white.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/l/white.jpg -------------------------------------------------------------------------------- /img/cars/l/yellow.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/l/yellow.jpg -------------------------------------------------------------------------------- /img/cars/p/black.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/p/black.jpg -------------------------------------------------------------------------------- /img/cars/p/blue.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/p/blue.jpg -------------------------------------------------------------------------------- /img/cars/p/family.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/p/family.jpg -------------------------------------------------------------------------------- /img/cars/p/input.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/p/input.jpg -------------------------------------------------------------------------------- /img/cars/p/jeep.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/p/jeep.jpg -------------------------------------------------------------------------------- /img/cars/p/red.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/p/red.jpg -------------------------------------------------------------------------------- /img/cars/p/sports.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/p/sports.jpg -------------------------------------------------------------------------------- /img/cars/p/white.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/p/white.jpg -------------------------------------------------------------------------------- /img/cars/p/yellow.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/cars/p/yellow.jpg -------------------------------------------------------------------------------- /img/faces/a/asian.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/a/asian.jpg -------------------------------------------------------------------------------- /img/faces/a/beard.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/a/beard.jpg -------------------------------------------------------------------------------- /img/faces/a/blond_hair.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/a/blond_hair.jpg -------------------------------------------------------------------------------- /img/faces/a/eyeglasses.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/a/eyeglasses.jpg -------------------------------------------------------------------------------- /img/faces/a/female.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/a/female.jpg -------------------------------------------------------------------------------- /img/faces/a/input.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/a/input.jpg -------------------------------------------------------------------------------- /img/faces/a/kid.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/a/kid.jpg -------------------------------------------------------------------------------- /img/faces/a/makeup.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/a/makeup.jpg -------------------------------------------------------------------------------- /img/faces/a/male.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/a/male.jpg -------------------------------------------------------------------------------- /img/faces/a/red_hair.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/a/red_hair.jpg -------------------------------------------------------------------------------- /img/faces/a/sunglasses.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/a/sunglasses.jpg -------------------------------------------------------------------------------- /img/faces/a/teenager.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/a/teenager.jpg -------------------------------------------------------------------------------- /img/faces/b/asian.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/b/asian.jpg -------------------------------------------------------------------------------- /img/faces/b/beard.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/b/beard.jpg -------------------------------------------------------------------------------- /img/faces/b/blond_hair.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/b/blond_hair.jpg -------------------------------------------------------------------------------- /img/faces/b/eyeglasses.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/b/eyeglasses.jpg -------------------------------------------------------------------------------- /img/faces/b/female.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/b/female.jpg -------------------------------------------------------------------------------- /img/faces/b/input.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/b/input.jpg -------------------------------------------------------------------------------- /img/faces/b/kid.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/b/kid.jpg -------------------------------------------------------------------------------- /img/faces/b/male.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/b/male.jpg -------------------------------------------------------------------------------- /img/faces/b/red_hair.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/b/red_hair.jpg -------------------------------------------------------------------------------- /img/faces/b/sunglasses.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/b/sunglasses.jpg -------------------------------------------------------------------------------- /img/faces/b/teenager.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/b/teenager.jpg -------------------------------------------------------------------------------- /img/faces/c/asian.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/c/asian.jpg -------------------------------------------------------------------------------- /img/faces/c/beard.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/c/beard.jpg -------------------------------------------------------------------------------- /img/faces/c/blond_hair.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/c/blond_hair.jpg -------------------------------------------------------------------------------- /img/faces/c/eyeglasses.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/c/eyeglasses.jpg -------------------------------------------------------------------------------- /img/faces/c/female.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/c/female.jpg -------------------------------------------------------------------------------- /img/faces/c/input.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/c/input.jpg -------------------------------------------------------------------------------- /img/faces/c/kid.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/c/kid.jpg -------------------------------------------------------------------------------- /img/faces/c/male.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/c/male.jpg -------------------------------------------------------------------------------- /img/faces/c/red_hair.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/c/red_hair.jpg -------------------------------------------------------------------------------- /img/faces/c/sunglasses.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/c/sunglasses.jpg -------------------------------------------------------------------------------- /img/faces/c/teenager.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/c/teenager.jpg -------------------------------------------------------------------------------- /img/faces/d/asian.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/d/asian.jpg -------------------------------------------------------------------------------- /img/faces/d/beard.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/d/beard.jpg -------------------------------------------------------------------------------- /img/faces/d/blond_hair.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/d/blond_hair.jpg -------------------------------------------------------------------------------- /img/faces/d/eyeglasses.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/d/eyeglasses.jpg -------------------------------------------------------------------------------- /img/faces/d/female.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/d/female.jpg -------------------------------------------------------------------------------- /img/faces/d/input.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/d/input.jpg -------------------------------------------------------------------------------- /img/faces/d/kid.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/d/kid.jpg -------------------------------------------------------------------------------- /img/faces/d/male.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/d/male.jpg -------------------------------------------------------------------------------- /img/faces/d/red_hair.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/d/red_hair.jpg -------------------------------------------------------------------------------- /img/faces/d/sunglasses.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/d/sunglasses.jpg -------------------------------------------------------------------------------- /img/faces/d/teenager.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/d/teenager.jpg -------------------------------------------------------------------------------- /img/faces/e/asian.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/e/asian.jpg -------------------------------------------------------------------------------- /img/faces/e/beard.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/e/beard.jpg -------------------------------------------------------------------------------- /img/faces/e/blond_hair.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/e/blond_hair.jpg -------------------------------------------------------------------------------- /img/faces/e/eyeglasses.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/e/eyeglasses.jpg -------------------------------------------------------------------------------- /img/faces/e/female.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/e/female.jpg -------------------------------------------------------------------------------- /img/faces/e/input.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/e/input.jpg -------------------------------------------------------------------------------- /img/faces/e/kid.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/e/kid.jpg -------------------------------------------------------------------------------- /img/faces/e/male.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/e/male.jpg -------------------------------------------------------------------------------- /img/faces/e/red_hair.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/e/red_hair.jpg -------------------------------------------------------------------------------- /img/faces/e/sunglasses.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/e/sunglasses.jpg -------------------------------------------------------------------------------- /img/faces/e/teenager.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/e/teenager.jpg -------------------------------------------------------------------------------- /img/faces/f/asian.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/f/asian.jpg -------------------------------------------------------------------------------- /img/faces/f/beard.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/f/beard.jpg -------------------------------------------------------------------------------- /img/faces/f/blond_hair.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/f/blond_hair.jpg -------------------------------------------------------------------------------- /img/faces/f/eyeglasses.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/f/eyeglasses.jpg -------------------------------------------------------------------------------- /img/faces/f/female.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/f/female.jpg -------------------------------------------------------------------------------- /img/faces/f/input.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/f/input.jpg -------------------------------------------------------------------------------- /img/faces/f/kid.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/f/kid.jpg -------------------------------------------------------------------------------- /img/faces/f/male.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/f/male.jpg -------------------------------------------------------------------------------- /img/faces/f/red_hair.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/f/red_hair.jpg -------------------------------------------------------------------------------- /img/faces/f/sunglasses.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/f/sunglasses.jpg -------------------------------------------------------------------------------- /img/faces/f/teenager.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/f/teenager.jpg -------------------------------------------------------------------------------- /img/faces/g/asian.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/g/asian.jpg -------------------------------------------------------------------------------- /img/faces/g/beard.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/g/beard.jpg -------------------------------------------------------------------------------- /img/faces/g/blond_hair.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/g/blond_hair.jpg -------------------------------------------------------------------------------- /img/faces/g/eyeglasses.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/g/eyeglasses.jpg -------------------------------------------------------------------------------- /img/faces/g/female.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/g/female.jpg -------------------------------------------------------------------------------- /img/faces/g/input.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/g/input.jpg -------------------------------------------------------------------------------- /img/faces/g/kid.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/g/kid.jpg -------------------------------------------------------------------------------- /img/faces/g/male.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/g/male.jpg -------------------------------------------------------------------------------- /img/faces/g/red_hair.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/g/red_hair.jpg -------------------------------------------------------------------------------- /img/faces/g/sunglasses.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/g/sunglasses.jpg -------------------------------------------------------------------------------- /img/faces/g/teenager.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/g/teenager.jpg -------------------------------------------------------------------------------- /img/faces/h/asian.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/h/asian.jpg -------------------------------------------------------------------------------- /img/faces/h/beard.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/h/beard.jpg -------------------------------------------------------------------------------- /img/faces/h/blond_hair.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/h/blond_hair.jpg -------------------------------------------------------------------------------- /img/faces/h/eyeglasses.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/h/eyeglasses.jpg -------------------------------------------------------------------------------- /img/faces/h/female.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/h/female.jpg -------------------------------------------------------------------------------- /img/faces/h/input.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/h/input.jpg -------------------------------------------------------------------------------- /img/faces/h/kid.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/h/kid.jpg -------------------------------------------------------------------------------- /img/faces/h/male.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/h/male.jpg -------------------------------------------------------------------------------- /img/faces/h/red_hair.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/h/red_hair.jpg -------------------------------------------------------------------------------- /img/faces/h/sunglasses.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/h/sunglasses.jpg -------------------------------------------------------------------------------- /img/faces/h/teenager.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/faces/h/teenager.jpg -------------------------------------------------------------------------------- /img/huji-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/huji-logo.png -------------------------------------------------------------------------------- /img/thumbnails/zerodim-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/thumbnails/zerodim-01.png -------------------------------------------------------------------------------- /img/thumbnails/zerodim-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/thumbnails/zerodim-02.png -------------------------------------------------------------------------------- /img/thumbnails/zerodim-03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/thumbnails/zerodim-03.png -------------------------------------------------------------------------------- /img/thumbnails/zerodim-04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/thumbnails/zerodim-04.png -------------------------------------------------------------------------------- /img/thumbnails/zerodim-05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/thumbnails/zerodim-05.png -------------------------------------------------------------------------------- /img/thumbnails/zerodim-06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/thumbnails/zerodim-06.png -------------------------------------------------------------------------------- /img/thumbnails/zerodim-07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/thumbnails/zerodim-07.png -------------------------------------------------------------------------------- /img/thumbnails/zerodim-08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/thumbnails/zerodim-08.png -------------------------------------------------------------------------------- /img/thumbnails/zerodim-09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avivga/zerodim/5c464362bd033a40d31efea0642751ac1912bdfd/img/thumbnails/zerodim-09.png -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import os 3 | import yaml 4 | import imageio 5 | 6 | import numpy as np 7 | import cv2 8 | 9 | import data 10 | from assets import AssetManager 11 | from network.training import Model 12 | 13 | 14 | def preprocess(args, extras=[]): 15 | assets = AssetManager(args.base_dir) 16 | 17 | img_dataset_def = data.supported_datasets[args.dataset_id] 18 | img_dataset = img_dataset_def(args.dataset_path, extras) 19 | 20 | np.savez(file=assets.get_preprocess_file_path(args.out_data_name), **img_dataset.read()) 21 | 22 | 23 | def train(args): 24 | assets = AssetManager(args.base_dir) 25 | model_dir = assets.recreate_model_dir(args.model_name) 26 | tensorboard_dir = assets.recreate_tensorboard_dir(args.data_name, args.model_name) 27 | eval_dir = assets.recreate_eval_dir(args.data_name, args.model_name) 28 | 29 | with open(os.path.join(os.path.dirname(__file__), 'config', '{}.yaml'.format(args.config)), 'r') as config_fp: 30 | config = yaml.safe_load(config_fp) 31 | 32 | data = np.load(assets.get_preprocess_file_path(args.data_name)) 33 | imgs = data['imgs'] 34 | 35 | labeled_factor_ids = [data['factor_names'].tolist().index(factor_name) for factor_name in config['factor_names']] 36 | residual_factor_ids = [f for f in range(len(data['factor_sizes'])) if f not in labeled_factor_ids] 37 | 38 | factors = data['factors'][:, labeled_factor_ids] 39 | residual_factors = data['factors'][:, residual_factor_ids] 40 | 41 | if config['gt_labels']: 42 | rs = np.random.RandomState(seed=args.seed) 43 | train_idx = rs.choice(imgs.shape[0], size=config['train_size'], replace=False) 44 | 45 | # labels are partial but complete = same seed for each factor 46 | rs = np.random.RandomState(seed=args.seed) 47 | label_idx = rs.choice(config['train_size'], size=config['n_labels_per_factor'], replace=False) 48 | 49 | label_masks = np.zeros_like(factors[train_idx]).astype(np.bool) 50 | for f in range(factors.shape[1]): 51 | label_masks[label_idx, f] = True 52 | else: 53 | train_idx = np.arange(imgs.shape[0]) 54 | label_masks = np.zeros_like(factors[train_idx]).astype(np.bool) 55 | for f in range(factors.shape[1]): 56 | label_idx = (factors[:, f] != -1) 57 | label_masks[label_idx, f] = True 58 | factors[~label_idx, f] = 0 # dummy unused valid value 59 | 60 | config.update({ 61 | 'img_shape': imgs[train_idx].shape[1:], 62 | 'n_imgs': imgs[train_idx].shape[0], 63 | 'n_factors': len(labeled_factor_ids), 64 | 'factor_sizes': data['factor_sizes'][labeled_factor_ids], 65 | 'residual_factor_sizes': data['factor_sizes'][residual_factor_ids], 66 | 'residual_factor_names': data['factor_names'][residual_factor_ids], 67 | 'seed': args.seed 68 | }) 69 | 70 | model = Model(config) 71 | model.train_latent_model( 72 | imgs[train_idx], factors[train_idx], label_masks, residual_factors[train_idx], 73 | model_dir, tensorboard_dir 74 | ) 75 | 76 | model.warmup_amortized_model( 77 | imgs[train_idx], factors[train_idx], label_masks, residual_factors[train_idx], 78 | model_dir, tensorboard_dir=os.path.join(tensorboard_dir, 'amortization') 79 | ) 80 | 81 | model.tune_amortized_model( 82 | imgs[train_idx], factors[train_idx], label_masks, residual_factors[train_idx], 83 | model_dir, tensorboard_dir=os.path.join(tensorboard_dir, 'synthesis') 84 | ) 85 | 86 | if config['gt_labels']: 87 | model.evaluate(imgs, factors, residual_factors, eval_dir) 88 | 89 | 90 | def manipulate(args): 91 | assets = AssetManager(args.base_dir) 92 | model_dir = assets.get_model_dir(args.model_name) 93 | model = Model.load(model_dir) 94 | 95 | img = imageio.imread(args.img_path) 96 | img = cv2.resize(img, dsize=(model.config['img_shape'][1], model.config['img_shape'][0])) 97 | manipulated_img = model.manipulate(img, args.factor_name) 98 | 99 | imageio.imwrite(args.output_img_path, manipulated_img) 100 | 101 | 102 | def main(): 103 | parser = argparse.ArgumentParser() 104 | parser.add_argument('-bd', '--base-dir', type=str, default='.') 105 | 106 | action_parsers = parser.add_subparsers(dest='action') 107 | action_parsers.required = True 108 | 109 | preprocess_parser = action_parsers.add_parser('preprocess') 110 | preprocess_parser.add_argument('-di', '--dataset-id', type=str, choices=data.supported_datasets, required=True) 111 | preprocess_parser.add_argument('-dp', '--dataset-path', type=str, required=True) 112 | preprocess_parser.add_argument('-odn', '--out-data-name', type=str, required=True) 113 | preprocess_parser.set_defaults(func=preprocess) 114 | 115 | train_parser = action_parsers.add_parser('train') 116 | train_parser.add_argument('-dn', '--data-name', type=str, required=True) 117 | train_parser.add_argument('-mn', '--model-name', type=str, required=True) 118 | train_parser.add_argument('-cf', '--config', type=str, required=True) 119 | train_parser.add_argument('-s', '--seed', type=int, default=0) 120 | train_parser.set_defaults(func=train) 121 | 122 | manipulate_parser = action_parsers.add_parser('manipulate') 123 | manipulate_parser.add_argument('-mn', '--model-name', type=str, required=True) 124 | manipulate_parser.add_argument('-fn', '--factor-name', type=str, required=True) 125 | manipulate_parser.add_argument('-i', '--img-path', type=str, required=True) 126 | manipulate_parser.add_argument('-o', '--output-img-path', type=str, required=True) 127 | manipulate_parser.set_defaults(func=manipulate) 128 | 129 | args, extras = parser.parse_known_args() 130 | if len(extras) == 0: 131 | args.func(args) 132 | else: 133 | args.func(args, extras) 134 | 135 | 136 | if __name__ == '__main__': 137 | main() 138 | -------------------------------------------------------------------------------- /network/modules.py: -------------------------------------------------------------------------------- 1 | import math 2 | import numpy as np 3 | 4 | import torch 5 | from torch import nn 6 | from torch.nn import functional as F 7 | from torchvision import models 8 | 9 | # stylegan2 modules 10 | from model import ConstantInput, ToRGB, ModulatedConv2d, FusedLeakyReLU 11 | 12 | 13 | class StyleGenerator(nn.Module): 14 | 15 | def __init__(self, latent_dim, img_size): 16 | super().__init__() 17 | 18 | channel_multiplier = 2 19 | blur_kernel = [1, 3, 3, 1] 20 | 21 | self.channels = { 22 | 4: 512, 23 | 8: 512, 24 | 16: 512, 25 | 32: 512, 26 | 64: 256 * channel_multiplier, 27 | 128: 128 * channel_multiplier, 28 | 256: 64 * channel_multiplier, 29 | 512: 32 * channel_multiplier, 30 | 1024: 16 * channel_multiplier, 31 | } 32 | 33 | self.input = ConstantInput(self.channels[4]) 34 | self.conv1 = StyledConv(self.channels[4], self.channels[4], 3, latent_dim, blur_kernel=blur_kernel) 35 | self.to_rgb1 = ToRGB(self.channels[4], latent_dim, upsample=False) 36 | 37 | self.log_size = int(math.log(img_size, 2)) 38 | self.num_layers = (self.log_size - 2) * 2 + 1 39 | 40 | self.convs = nn.ModuleList() 41 | self.upsamples = nn.ModuleList() 42 | self.to_rgbs = nn.ModuleList() 43 | self.noises = nn.Module() 44 | 45 | in_channel = self.channels[4] 46 | 47 | for i in range(3, self.log_size + 1): 48 | out_channel = self.channels[2 ** i] 49 | 50 | self.convs.append( 51 | StyledConv( 52 | in_channel, out_channel, 53 | kernel_size=3, style_dim=latent_dim, 54 | upsample=True, blur_kernel=blur_kernel 55 | ) 56 | ) 57 | 58 | self.convs.append( 59 | StyledConv( 60 | out_channel, out_channel, 61 | kernel_size=3, style_dim=latent_dim, 62 | upsample=False, blur_kernel=blur_kernel 63 | ) 64 | ) 65 | 66 | self.to_rgbs.append(ToRGB(out_channel, latent_dim)) 67 | 68 | in_channel = out_channel 69 | 70 | self.n_latent = self.log_size * 2 - 2 71 | 72 | def forward(self, latent_code): 73 | latent_code = latent_code.unsqueeze(dim=1).repeat(1, self.n_latent, 1) 74 | 75 | out = self.input(latent_code) 76 | out = self.conv1(out, latent_code[:, 0]) 77 | 78 | skip = self.to_rgb1(out, latent_code[:, 1]) 79 | 80 | i = 1 81 | for conv1, conv2, to_rgb in zip(self.convs[::2], self.convs[1::2], self.to_rgbs): 82 | out = conv1(out, latent_code[:, i]) 83 | out = conv2(out, latent_code[:, i + 1]) 84 | skip = to_rgb(out, latent_code[:, i + 2], skip) 85 | 86 | i += 2 87 | 88 | image = skip 89 | return image 90 | 91 | 92 | class BetaVAEGenerator(nn.Module): 93 | 94 | def __init__(self, latent_dim, n_channels): # img_size=64 95 | super().__init__() 96 | 97 | self.fc = nn.Sequential( 98 | nn.Linear(in_features=latent_dim, out_features=256), 99 | nn.ReLU(), 100 | 101 | nn.Linear(in_features=256, out_features=4*4*64), 102 | nn.ReLU() 103 | ) 104 | 105 | self.convs = nn.Sequential( 106 | nn.ConvTranspose2d(in_channels=64, out_channels=64, kernel_size=4, stride=2, padding=1), 107 | nn.ReLU(), 108 | 109 | nn.ConvTranspose2d(in_channels=64, out_channels=32, kernel_size=4, stride=2, padding=1), 110 | nn.ReLU(), 111 | 112 | nn.ConvTranspose2d(in_channels=32, out_channels=32, kernel_size=4, stride=2, padding=1), 113 | nn.ReLU(), 114 | 115 | nn.ConvTranspose2d(in_channels=32, out_channels=n_channels, kernel_size=4, stride=2, padding=1), 116 | nn.Sigmoid() 117 | ) 118 | 119 | def forward(self, latent_code): 120 | h = self.fc(latent_code) 121 | h = h.view((-1, 64, 4, 4)) 122 | 123 | return self.convs(h) 124 | 125 | 126 | class BetaVAEEncoder(nn.Module): 127 | 128 | def __init__(self, n_channels, latent_dim): # img_size=64 129 | super().__init__() 130 | 131 | self.convs = nn.Sequential( 132 | nn.Conv2d(in_channels=n_channels, out_channels=32, kernel_size=4, stride=2, padding=1), 133 | nn.ReLU(), 134 | 135 | nn.Conv2d(in_channels=32, out_channels=32, kernel_size=4, stride=2, padding=1), 136 | nn.ReLU(), 137 | 138 | nn.Conv2d(in_channels=32, out_channels=64, kernel_size=2, stride=2, padding=0), 139 | nn.ReLU(), 140 | 141 | nn.Conv2d(in_channels=64, out_channels=64, kernel_size=2, stride=2, padding=0), 142 | nn.ReLU(), 143 | ) 144 | 145 | self.fc = nn.Sequential( 146 | nn.Linear(in_features=64*4*4, out_features=256), 147 | nn.ReLU(), 148 | 149 | nn.Linear(in_features=256, out_features=latent_dim) 150 | ) 151 | 152 | def forward(self, img): 153 | h = self.convs(img) 154 | h = h.view((-1, 64*4*4)) 155 | 156 | return self.fc(h) 157 | 158 | 159 | class ConvEncoder(nn.Module): 160 | 161 | def __init__(self, img_shape, dim_in=32, max_conv_dim=128): 162 | super().__init__() 163 | 164 | blocks = [] 165 | blocks += [nn.Conv2d(in_channels=img_shape[-1], out_channels=dim_in, kernel_size=3, stride=1, padding=1)] 166 | 167 | n_blocks = int(np.log2(img_shape[0])) - 2 168 | for _ in range(n_blocks): 169 | dim_out = min(dim_in*2, max_conv_dim) 170 | 171 | blocks += [ 172 | nn.Conv2d(in_channels=dim_in, out_channels=dim_out, kernel_size=3, stride=1, padding=1), 173 | nn.LeakyReLU(0.2), 174 | nn.MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False), 175 | ] 176 | 177 | dim_in = dim_out 178 | 179 | blocks += [nn.Conv2d(in_channels=dim_out, out_channels=dim_out, kernel_size=4, stride=1, padding=0)] 180 | self.conv = nn.Sequential(*blocks) 181 | 182 | def forward(self, img): 183 | return self.conv(img) 184 | 185 | 186 | class ResidualEncoder(nn.Module): 187 | 188 | def __init__(self, img_size, latent_dim, dim_in=64, max_conv_dim=256): 189 | super().__init__() 190 | 191 | blocks = [] 192 | blocks += [nn.Conv2d(in_channels=3, out_channels=dim_in, kernel_size=3, stride=1, padding=1)] 193 | 194 | repeat_num = int(np.log2(img_size)) - 2 195 | for _ in range(repeat_num): 196 | dim_out = min(dim_in*2, max_conv_dim) 197 | blocks += [ResBlk(dim_in, dim_out, downsample=True)] 198 | dim_in = dim_out 199 | 200 | blocks += [nn.LeakyReLU(0.2)] 201 | blocks += [nn.Conv2d(dim_out, dim_out, 4, 1, 0)] 202 | blocks += [nn.LeakyReLU(0.2)] 203 | blocks += [nn.Conv2d(dim_out, latent_dim, 1, 1, 0)] 204 | 205 | self.main = nn.Sequential(*blocks) 206 | 207 | def forward(self, img): 208 | batch_size = img.shape[0] 209 | return self.main(img).view(batch_size, -1) 210 | 211 | 212 | class StyledConv(nn.Module): 213 | 214 | def __init__(self, in_channel, out_channel, kernel_size, style_dim, upsample=False, blur_kernel=[1, 3, 3, 1], demodulate=True): 215 | super().__init__() 216 | 217 | self.conv = ModulatedConv2d( 218 | in_channel, 219 | out_channel, 220 | kernel_size, 221 | style_dim, 222 | upsample=upsample, 223 | blur_kernel=blur_kernel, 224 | demodulate=demodulate, 225 | ) 226 | 227 | # self.noise = NoiseInjection() 228 | # self.bias = nn.Parameter(torch.zeros(1, out_channel, 1, 1)) 229 | # self.activate = ScaledLeakyReLU(0.2) 230 | self.activate = FusedLeakyReLU(out_channel) 231 | 232 | def forward(self, input, style): 233 | out = self.conv(input, style) 234 | # out = self.noise(out, noise=noise) 235 | # out = out + self.bias 236 | out = self.activate(out) 237 | 238 | return out 239 | 240 | 241 | class ResBlk(nn.Module): 242 | 243 | def __init__(self, dim_in, dim_out, actv=nn.LeakyReLU(0.2), normalize=False, downsample=False): 244 | super().__init__() 245 | 246 | self.actv = actv 247 | self.normalize = normalize 248 | self.downsample = downsample 249 | self.learned_sc = dim_in != dim_out 250 | self._build_weights(dim_in, dim_out) 251 | 252 | def _build_weights(self, dim_in, dim_out): 253 | self.conv1 = nn.Conv2d(dim_in, dim_in, 3, 1, 1) 254 | self.conv2 = nn.Conv2d(dim_in, dim_out, 3, 1, 1) 255 | if self.normalize: 256 | self.norm1 = nn.InstanceNorm2d(dim_in, affine=True) 257 | self.norm2 = nn.InstanceNorm2d(dim_in, affine=True) 258 | if self.learned_sc: 259 | self.conv1x1 = nn.Conv2d(dim_in, dim_out, 1, 1, 0, bias=False) 260 | 261 | def _shortcut(self, x): 262 | if self.learned_sc: 263 | x = self.conv1x1(x) 264 | if self.downsample: 265 | x = F.avg_pool2d(x, 2) 266 | return x 267 | 268 | def _residual(self, x): 269 | if self.normalize: 270 | x = self.norm1(x) 271 | x = self.actv(x) 272 | x = self.conv1(x) 273 | if self.downsample: 274 | x = F.avg_pool2d(x, 2) 275 | if self.normalize: 276 | x = self.norm2(x) 277 | x = self.actv(x) 278 | x = self.conv2(x) 279 | return x 280 | 281 | def forward(self, x): 282 | x = self._shortcut(x) + self._residual(x) 283 | return x / math.sqrt(2) # unit variance 284 | 285 | 286 | class VGGFeatures(nn.Module): 287 | 288 | def __init__(self, layer_ids): 289 | super().__init__() 290 | 291 | self.features = models.vgg16(pretrained=True).features 292 | self.layer_ids = layer_ids 293 | 294 | mean = torch.tensor([0.485, 0.456, 0.406]).view(1, 3, 1, 1) 295 | std = torch.tensor([0.229, 0.224, 0.225]).view(1, 3, 1, 1) 296 | self.register_buffer('mean', mean) 297 | self.register_buffer('std', std) 298 | 299 | def forward(self, x): 300 | x = (x - self.mean) / self.std # TODO: optional? 301 | 302 | output = [] 303 | for i in range(self.layer_ids[-1] + 1): 304 | x = self.features[i](x) 305 | 306 | if i in self.layer_ids: 307 | output.append(x) 308 | 309 | return output 310 | 311 | 312 | class VGGDistance(nn.Module): 313 | 314 | def __init__(self, layer_ids): 315 | super().__init__() 316 | 317 | self.vgg_features = torch.nn.DataParallel(VGGFeatures(layer_ids)) 318 | 319 | def forward(self, I1, I2): 320 | batch_size = I1.size(0) 321 | 322 | f1 = self.vgg_features(I1) 323 | f2 = self.vgg_features(I2) 324 | 325 | loss = torch.abs(I1 - I2).view(batch_size, -1).mean(dim=1) 326 | 327 | for i in range(len(f1)): 328 | layer_loss = torch.abs(f1[i] - f2[i]).view(batch_size, -1).mean(dim=1) 329 | loss = loss + layer_loss 330 | 331 | return loss.mean() 332 | -------------------------------------------------------------------------------- /network/training.py: -------------------------------------------------------------------------------- 1 | import os 2 | import itertools 3 | import pickle 4 | import json 5 | from tqdm import tqdm 6 | 7 | import numpy as np 8 | 9 | import torch 10 | from torch import nn 11 | from torch.nn import functional as F 12 | from torch.optim import Adam 13 | from torch.optim.lr_scheduler import CosineAnnealingLR 14 | from torch.distributions import Categorical 15 | from torch.utils.data import DataLoader 16 | from torch.utils.tensorboard import SummaryWriter 17 | 18 | from network.modules import BetaVAEGenerator, BetaVAEEncoder 19 | from network.modules import StyleGenerator, ConvEncoder, ResidualEncoder, VGGDistance 20 | from network.utils import ImageTensorDataset 21 | 22 | from evaluation import dci, sap, mig, classifier 23 | from model import Discriminator # from stylegan2 24 | 25 | 26 | class MultiFactorClassifier(nn.Module): 27 | 28 | def __init__(self, config): 29 | super().__init__() 30 | 31 | self.base_encoder = ConvEncoder(img_shape=config['img_shape'], max_conv_dim=128) 32 | self.heads = nn.ModuleList([ 33 | nn.Linear(in_features=128, out_features=config['factor_sizes'][f]) 34 | for f in range(config['n_factors']) 35 | ]) 36 | 37 | def forward(self, img): 38 | x = self.base_encoder(img).reshape(img.shape[0], -1) 39 | return [head(x) for head in self.heads] 40 | 41 | 42 | class FactorModel(nn.Module): 43 | 44 | def __init__(self, config): 45 | super().__init__() 46 | 47 | self.config = config 48 | 49 | self.factor_embeddings = nn.ModuleList([ 50 | nn.Embedding( 51 | num_embeddings=config['factor_sizes'][f], 52 | embedding_dim=config['factor_dim'], 53 | _weight=(2 * torch.rand(config['factor_sizes'][f], config['factor_dim']) - 1) * 0.05 54 | ) 55 | 56 | for f in range(config['n_factors']) 57 | ]) 58 | 59 | if config['arch_betavae']: 60 | self.factor_classifiers = nn.ModuleList([ 61 | BetaVAEEncoder(n_channels=config['img_shape'][-1], latent_dim=config['factor_sizes'][f]) 62 | for f in range(config['n_factors']) 63 | ]) 64 | 65 | else: 66 | self.factor_classifiers = MultiFactorClassifier(config) 67 | 68 | def forward(self, img, factors=None, label_masks=None): 69 | out = dict() 70 | 71 | factor_codes = [] 72 | assignment_entropy = [] 73 | 74 | if isinstance(self.factor_classifiers, MultiFactorClassifier): 75 | logits = self.factor_classifiers(img) 76 | else: 77 | logits = [factor_classifier(img) for factor_classifier in self.factor_classifiers] 78 | 79 | for f in range(self.config['n_factors']): 80 | assignment = Categorical(logits=logits[f]) 81 | 82 | with torch.no_grad(): 83 | factor_values = torch.arange(self.config['factor_sizes'][f], dtype=torch.int64).to(img.device) 84 | factor_embeddings = self.factor_embeddings[f](factor_values) 85 | 86 | if factors is not None: 87 | factor_code = ( 88 | self.factor_embeddings[f](factors[:, f]) * label_masks[:, [f]] 89 | + torch.matmul(assignment.probs, factor_embeddings) * (~label_masks[:, [f]]) 90 | ) 91 | 92 | else: 93 | factor_code = torch.matmul(assignment.probs, factor_embeddings) 94 | 95 | factor_codes.append(factor_code) 96 | assignment_entropy.append(assignment.entropy()) 97 | out['assignment_logits_{}'.format(f)] = assignment.logits 98 | 99 | out['factor_codes'] = torch.cat(factor_codes, dim=1) 100 | out['assignment_entropy'] = torch.stack(assignment_entropy, dim=1) 101 | 102 | return out 103 | 104 | 105 | class LatentModel(nn.Module): 106 | 107 | def __init__(self, config): 108 | super().__init__() 109 | 110 | self.config = config 111 | 112 | self.factor_model = FactorModel(config) 113 | 114 | self.residual_embeddings = nn.Embedding( 115 | num_embeddings=config['n_imgs'], 116 | embedding_dim=config['residual_dim'], 117 | _weight=(2 * torch.rand(config['n_imgs'], config['residual_dim']) - 1) * 0.05 118 | ) 119 | 120 | if config['arch_betavae']: 121 | self.generator = BetaVAEGenerator( 122 | latent_dim=config['n_factors'] * config['factor_dim'] + config['residual_dim'], 123 | n_channels=config['img_shape'][-1] 124 | ) 125 | 126 | else: 127 | self.generator = StyleGenerator( 128 | latent_dim=config['n_factors'] * config['factor_dim'] + config['residual_dim'], 129 | img_size=config['img_shape'][0] 130 | ) 131 | 132 | self.factor_model = torch.nn.DataParallel(self.factor_model) 133 | self.residual_embeddings = torch.nn.DataParallel(self.residual_embeddings) 134 | self.generator = torch.nn.DataParallel(self.generator) 135 | 136 | 137 | class AmortizedModel(nn.Module): 138 | 139 | def __init__(self, config): 140 | super().__init__() 141 | 142 | self.config = config 143 | 144 | self.factor_model = FactorModel(config) 145 | 146 | if config['arch_betavae']: 147 | self.residual_encoder = BetaVAEEncoder(n_channels=config['img_shape'][-1], latent_dim=config['residual_dim']) 148 | self.generator = BetaVAEGenerator( 149 | latent_dim=config['n_factors'] * config['factor_dim'] + config['residual_dim'], 150 | n_channels=config['img_shape'][-1] 151 | ) 152 | 153 | else: 154 | self.residual_encoder = ResidualEncoder(img_size=config['img_shape'][0], latent_dim=config['residual_dim']) 155 | self.generator = StyleGenerator( 156 | latent_dim=config['n_factors'] * config['factor_dim'] + config['residual_dim'], 157 | img_size=config['img_shape'][0] 158 | ) 159 | 160 | self.factor_model = torch.nn.DataParallel(self.factor_model) 161 | self.residual_encoder = torch.nn.DataParallel(self.residual_encoder) 162 | self.generator = torch.nn.DataParallel(self.generator) 163 | 164 | if self.config['synthesis']['adversarial']: 165 | self.discriminator = Discriminator(size=config['img_shape'][0]) 166 | self.discriminator = torch.nn.DataParallel(self.discriminator) 167 | 168 | 169 | class Model: 170 | 171 | def __init__(self, config): 172 | super().__init__() 173 | 174 | self.config = config 175 | 176 | self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') 177 | torch.manual_seed(seed=config['seed']) 178 | 179 | self.latent_model = None 180 | self.amortized_model = None 181 | 182 | if config['loss_reconstruction'] == 'bce': 183 | self.reconstruction_loss = nn.BCELoss() 184 | elif config['loss_reconstruction'] == 'l1': 185 | self.reconstruction_loss = nn.L1Loss() 186 | elif config['loss_reconstruction'] == 'mse': 187 | self.reconstruction_loss = nn.MSELoss() 188 | elif config['loss_reconstruction'] == 'perceptual': 189 | self.reconstruction_loss = VGGDistance(layer_ids=config['perceptual_loss']) 190 | else: 191 | raise Exception('unsupported reconstruction loss') 192 | 193 | self.classification_loss = nn.CrossEntropyLoss() 194 | self.visualization_rs = np.random.RandomState(seed=config['seed']) 195 | 196 | @staticmethod 197 | def load(model_dir): 198 | with open(os.path.join(model_dir, 'config.pkl'), 'rb') as config_fd: 199 | config = pickle.load(config_fd) 200 | 201 | model = Model(config) 202 | 203 | if os.path.exists(os.path.join(model_dir, 'latent.pth')): 204 | model.latent_model = LatentModel(config) 205 | model.latent_model.load_state_dict(torch.load(os.path.join(model_dir, 'latent.pth'))) 206 | 207 | if os.path.exists(os.path.join(model_dir, 'amortized.pth')): 208 | model.amortized_model = AmortizedModel(config) 209 | model.amortized_model.load_state_dict(torch.load(os.path.join(model_dir, 'amortized.pth'))) 210 | 211 | return model 212 | 213 | def save(self, model_dir): 214 | if not os.path.exists(model_dir): 215 | os.mkdir(model_dir) 216 | 217 | with open(os.path.join(model_dir, 'config.pkl'), 'wb') as config_fd: 218 | pickle.dump(self.config, config_fd) 219 | 220 | if self.latent_model: 221 | torch.save(self.latent_model.state_dict(), os.path.join(model_dir, 'latent.pth')) 222 | 223 | if self.amortized_model: 224 | torch.save(self.amortized_model.state_dict(), os.path.join(model_dir, 'amortized.pth')) 225 | 226 | def train_latent_model(self, imgs, factors, label_masks, residual_factors, model_dir, tensorboard_dir): 227 | self.latent_model = LatentModel(self.config) 228 | 229 | data = dict( 230 | img=torch.from_numpy(imgs).permute(0, 3, 1, 2), 231 | img_id=torch.from_numpy(np.arange(imgs.shape[0])), 232 | factors=torch.from_numpy(factors.astype(np.int64)), 233 | residual_factors=torch.from_numpy(residual_factors.astype(np.int64)), 234 | label_masks=torch.from_numpy(label_masks.astype(np.bool)) 235 | ) 236 | 237 | dataset = ImageTensorDataset(data) 238 | data_loader = DataLoader( 239 | dataset, batch_size=self.config['train']['batch_size'], 240 | shuffle=True, pin_memory=True, drop_last=False 241 | ) 242 | 243 | label_ids = np.sum(label_masks, axis=1) > 0 244 | dataset_labeled = ImageTensorDataset({name: tensor[label_ids] for name, tensor in data.items()}) 245 | data_loader_labeled = DataLoader( 246 | dataset_labeled, batch_size=self.config['train']['batch_size'], 247 | shuffle=True, pin_memory=True, drop_last=False 248 | ) 249 | 250 | optimizer = Adam([ 251 | { 252 | 'params': itertools.chain( 253 | self.latent_model.factor_model.module.factor_embeddings.parameters(), 254 | self.latent_model.residual_embeddings.parameters() 255 | ), 256 | 257 | 'lr': self.config['train']['learning_rate']['latent'] 258 | }, 259 | { 260 | 'params': self.latent_model.factor_model.module.factor_classifiers.parameters(), 261 | 'lr': self.config['train']['learning_rate']['classifier'] 262 | }, 263 | { 264 | 'params': self.latent_model.generator.parameters(), 265 | 'lr': self.config['train']['learning_rate']['generator'] 266 | } 267 | ], betas=(0.5, 0.999)) 268 | 269 | scheduler = CosineAnnealingLR( 270 | optimizer, 271 | T_max=self.config['train']['n_epochs'] * len(data_loader), 272 | eta_min=self.config['train']['learning_rate']['min'] 273 | ) 274 | 275 | self.latent_model.to(self.device) 276 | self.reconstruction_loss.to(self.device) 277 | 278 | summary = SummaryWriter(log_dir=tensorboard_dir) 279 | for epoch in range(self.config['train']['n_epochs'] + 1): 280 | self.latent_model.train() 281 | 282 | pbar = tqdm(iterable=data_loader) 283 | iterator_labeled = iter(data_loader_labeled) 284 | 285 | for batch in pbar: 286 | batch = {name: tensor.to(self.device) for name, tensor in batch.items()} 287 | 288 | losses_unsupervised = self.__iterate_latent_model(batch) 289 | loss_unsupervised = 0 290 | for term, val in losses_unsupervised.items(): 291 | if term == 'entropy' and epoch < self.config['train']['n_epochs_before_entropy']: 292 | continue 293 | 294 | loss_unsupervised += self.config['train']['loss_weights'][term] * val 295 | 296 | try: 297 | batch_labeled = next(iterator_labeled) 298 | except StopIteration: 299 | iterator_labeled = iter(data_loader_labeled) 300 | batch_labeled = next(iterator_labeled) 301 | 302 | batch_labeled = {name: tensor.to(self.device) for name, tensor in batch_labeled.items()} 303 | 304 | losses_supervised = self.__iterate_latent_model_with_labels(batch_labeled) 305 | loss_supervised = 0 306 | for term, val in losses_supervised.items(): 307 | loss_supervised += self.config['train']['loss_weights'][term] * val 308 | 309 | loss = loss_unsupervised + self.config['train']['loss_weights']['supervised'] * loss_supervised 310 | 311 | optimizer.zero_grad() 312 | loss.backward() 313 | optimizer.step() 314 | scheduler.step() 315 | 316 | pbar.set_description_str('[disentanglement] epoch #{}'.format(epoch)) 317 | pbar.set_postfix(loss=loss.item()) 318 | 319 | pbar.close() 320 | 321 | summary.add_scalar(tag='loss/total', scalar_value=loss.item(), global_step=epoch) 322 | summary.add_scalar(tag='loss/unsupervised', scalar_value=loss_unsupervised.item(), global_step=epoch) 323 | summary.add_scalar(tag='loss/supervised', scalar_value=loss_supervised.item(), global_step=epoch) 324 | 325 | for term, val in losses_unsupervised.items(): 326 | summary.add_scalar(tag='loss/unsupervised/{}'.format(term), scalar_value=val.item(), global_step=epoch) 327 | 328 | for term, val in losses_supervised.items(): 329 | summary.add_scalar(tag='loss/supervised/{}'.format(term), scalar_value=val.item(), global_step=epoch) 330 | 331 | if epoch % self.config['train']['n_epochs_between_evals'] == 0 and self.config['gt_labels']: 332 | latent_factors = self.__embed_factors(dataset) 333 | scores = dci.evaluate(latent_factors, factors) 334 | 335 | summary.add_scalar(tag='dci/informativeness', scalar_value=scores['informativeness_test'], global_step=epoch) 336 | summary.add_scalar(tag='dci/disentanglement', scalar_value=scores['disentanglement'], global_step=epoch) 337 | summary.add_scalar(tag='dci/completeness', scalar_value=scores['completeness'], global_step=epoch) 338 | 339 | for factor_idx, factor_name in enumerate(self.config['factor_names']): 340 | acc = self.__eval_factor_classification(imgs, factors, factor_idx) 341 | summary.add_scalar(tag='factors/{}'.format(factor_name), scalar_value=acc, global_step=epoch) 342 | 343 | latent_residuals = self.__embed_residuals(dataset) 344 | for factor_idx, factor_name in enumerate(self.config['factor_names']): 345 | acc_train, acc_test = classifier.logistic_regression(latent_residuals, factors[:, factor_idx]) 346 | summary.add_scalar(tag='residual/to-{}'.format(factor_name), scalar_value=acc_test, global_step=epoch) 347 | 348 | for factor_idx, factor_name in enumerate(self.config['residual_factor_names']): 349 | acc_train, acc_test = classifier.logistic_regression(latent_residuals, residual_factors[:, factor_idx]) 350 | summary.add_scalar(tag='residual/to-{}'.format(factor_name), scalar_value=acc_test, global_step=epoch) 351 | 352 | if epoch % self.config['train']['n_epochs_between_visualizations'] == 0: 353 | figure = self.__visualize_reconstruction(dataset) 354 | summary.add_image(tag='reconstruction', img_tensor=figure, global_step=epoch) 355 | 356 | for factor_idx, factor_name in enumerate(self.config['factor_names']): 357 | figure_fixed = self.__visualize_translation(dataset, factor_idx, randomized=False) 358 | figure_random = self.__visualize_translation(dataset, factor_idx, randomized=True) 359 | 360 | summary.add_image(tag='{}-fixed'.format(factor_name), img_tensor=figure_fixed, global_step=epoch) 361 | summary.add_image(tag='{}-random'.format(factor_name), img_tensor=figure_random, global_step=epoch) 362 | 363 | self.save(model_dir) 364 | 365 | summary.close() 366 | 367 | def warmup_amortized_model(self, imgs, factors, label_masks, residual_factors, model_dir, tensorboard_dir): 368 | self.amortized_model = AmortizedModel(self.config) 369 | self.amortized_model.factor_model.load_state_dict(self.latent_model.factor_model.state_dict()) 370 | self.amortized_model.generator.load_state_dict(self.latent_model.generator.state_dict()) 371 | 372 | data = dict( 373 | img=torch.from_numpy(imgs).permute(0, 3, 1, 2), 374 | img_id=torch.from_numpy(np.arange(imgs.shape[0])), 375 | factors=torch.from_numpy(factors.astype(np.int64)), 376 | residual_factors=torch.from_numpy(residual_factors.astype(np.int64)), 377 | label_masks=torch.from_numpy(label_masks.astype(np.bool)) 378 | ) 379 | 380 | dataset = ImageTensorDataset(data) 381 | data_loader = DataLoader( 382 | dataset, batch_size=self.config['amortization']['batch_size'], 383 | shuffle=True, pin_memory=True, drop_last=False 384 | ) 385 | 386 | optimizer = Adam( 387 | params=self.amortized_model.residual_encoder.parameters(), 388 | lr=self.config['amortization']['learning_rate']['max'] 389 | ) 390 | 391 | scheduler = CosineAnnealingLR( 392 | optimizer, 393 | T_max=self.config['amortization']['n_epochs'] * len(data_loader), 394 | eta_min=self.config['amortization']['learning_rate']['min'] 395 | ) 396 | 397 | self.latent_model.to(self.device) 398 | self.amortized_model.to(self.device) 399 | 400 | os.mkdir(tensorboard_dir) 401 | summary = SummaryWriter(log_dir=tensorboard_dir) 402 | 403 | for epoch in range(self.config['amortization']['n_epochs'] + 1): 404 | self.latent_model.train() 405 | self.amortized_model.train() 406 | 407 | pbar = tqdm(iterable=data_loader) 408 | for batch in pbar: 409 | batch = {name: tensor.to(self.device) for name, tensor in batch.items()} 410 | 411 | losses = self.__iterate_encoders(batch) 412 | loss_total = 0 413 | for term, loss in losses.items(): 414 | loss_total += loss 415 | 416 | optimizer.zero_grad() 417 | loss_total.backward() 418 | optimizer.step() 419 | scheduler.step() 420 | 421 | pbar.set_description_str('[amortization] epoch #{}'.format(epoch)) 422 | pbar.set_postfix(loss=loss_total.item()) 423 | 424 | pbar.close() 425 | 426 | summary.add_scalar(tag='loss/encoders', scalar_value=loss_total.item(), global_step=epoch) 427 | 428 | for term, loss in losses.items(): 429 | summary.add_scalar(tag='loss/encoders/{}'.format(term), scalar_value=loss.item(), global_step=epoch) 430 | 431 | if epoch % self.config['amortization']['n_epochs_between_evals'] == 0 and self.config['gt_labels']: 432 | latent_factors = self.__encode_factors(imgs) 433 | scores = dci.evaluate(latent_factors, factors) 434 | 435 | summary.add_scalar(tag='dci/informativeness', scalar_value=scores['informativeness_test'], global_step=epoch) 436 | summary.add_scalar(tag='dci/disentanglement', scalar_value=scores['disentanglement'], global_step=epoch) 437 | summary.add_scalar(tag='dci/completeness', scalar_value=scores['completeness'], global_step=epoch) 438 | 439 | latent_residuals = self.__encode_residuals(imgs) 440 | for factor_idx, factor_name in enumerate(self.config['factor_names']): 441 | acc_train, acc_test = classifier.logistic_regression(latent_residuals, factors[:, factor_idx]) 442 | summary.add_scalar(tag='residual/to-{}'.format(factor_name), scalar_value=acc_test, global_step=epoch) 443 | 444 | for factor_idx, factor_name in enumerate(self.config['residual_factor_names']): 445 | acc_train, acc_test = classifier.logistic_regression(latent_residuals, residual_factors[:, factor_idx]) 446 | summary.add_scalar(tag='residual/to-{}'.format(factor_name), scalar_value=acc_test, global_step=epoch) 447 | 448 | if epoch % self.config['amortization']['n_epochs_between_visualizations'] == 0: 449 | figure = self.__visualize_reconstruction(dataset, amortized=True) 450 | summary.add_image(tag='reconstruction', img_tensor=figure, global_step=epoch) 451 | 452 | for factor_idx, factor_name in enumerate(self.config['factor_names']): 453 | figure_fixed = self.__visualize_translation(dataset, factor_idx, randomized=False, amortized=True) 454 | figure_random = self.__visualize_translation(dataset, factor_idx, randomized=True, amortized=True) 455 | 456 | summary.add_image(tag='{}-fixed'.format(factor_name), img_tensor=figure_fixed, global_step=epoch) 457 | summary.add_image(tag='{}-random'.format(factor_name), img_tensor=figure_random, global_step=epoch) 458 | 459 | self.save(model_dir) 460 | 461 | summary.close() 462 | 463 | def tune_amortized_model(self, imgs, factors, label_masks, residual_factors, model_dir, tensorboard_dir): 464 | data = dict( 465 | img=torch.from_numpy(imgs).permute(0, 3, 1, 2), 466 | img_id=torch.from_numpy(np.arange(imgs.shape[0])), 467 | factors=torch.from_numpy(factors.astype(np.int64)), 468 | residual_factors=torch.from_numpy(residual_factors.astype(np.int64)), 469 | label_masks=torch.from_numpy(label_masks.astype(np.bool)) 470 | ) 471 | 472 | dataset = ImageTensorDataset(data) 473 | data_loader = DataLoader( 474 | dataset, batch_size=self.config['synthesis']['batch_size'], 475 | shuffle=True, pin_memory=True, drop_last=False 476 | ) 477 | 478 | generator_optimizer = Adam( 479 | params=itertools.chain( 480 | self.amortized_model.residual_encoder.parameters(), 481 | self.amortized_model.generator.parameters() 482 | ), 483 | 484 | lr=self.config['synthesis']['learning_rate']['generator'], 485 | betas=(0.5, 0.999) 486 | ) 487 | 488 | if self.config['synthesis']['adversarial']: 489 | discriminator_optimizer = Adam( 490 | params=self.amortized_model.discriminator.parameters(), 491 | lr=self.config['synthesis']['learning_rate']['discriminator'], 492 | betas=(0.5, 0.999) 493 | ) 494 | 495 | self.latent_model.to(self.device) 496 | self.amortized_model.to(self.device) 497 | self.reconstruction_loss.to(self.device) 498 | 499 | os.mkdir(tensorboard_dir) 500 | summary = SummaryWriter(log_dir=tensorboard_dir) 501 | 502 | for epoch in range(self.config['synthesis']['n_epochs'] + 1): 503 | self.latent_model.train() 504 | self.amortized_model.train() 505 | 506 | pbar = tqdm(iterable=data_loader) 507 | for batch in pbar: 508 | batch = {name: tensor.to(self.device) for name, tensor in batch.items()} 509 | 510 | if self.config['synthesis']['adversarial']: 511 | losses_discriminator = self.__iterate_discriminator(batch) 512 | loss_discriminator = ( 513 | losses_discriminator['fake'] 514 | + losses_discriminator['real'] 515 | + losses_discriminator['gradient_penalty'] 516 | ) 517 | 518 | generator_optimizer.zero_grad() 519 | discriminator_optimizer.zero_grad() 520 | loss_discriminator.backward() 521 | discriminator_optimizer.step() 522 | 523 | losses_generator = self.__iterate_amortized_model(batch) 524 | loss_generator = 0 525 | for term, loss in losses_generator.items(): 526 | loss_generator += self.config['synthesis']['loss_weights'][term] * loss 527 | 528 | generator_optimizer.zero_grad() 529 | if self.config['synthesis']['adversarial']: 530 | discriminator_optimizer.zero_grad() 531 | 532 | loss_generator.backward() 533 | generator_optimizer.step() 534 | 535 | pbar.set_description_str('[synthesis] epoch #{}'.format(epoch)) 536 | pbar.set_postfix(gen_loss=loss_generator.item()) 537 | 538 | pbar.close() 539 | 540 | summary.add_scalar(tag='loss/generator', scalar_value=loss_generator.item(), global_step=epoch) 541 | if self.config['synthesis']['adversarial']: 542 | summary.add_scalar(tag='loss/discriminator', scalar_value=loss_discriminator.item(), global_step=epoch) 543 | 544 | for term, loss in losses_generator.items(): 545 | summary.add_scalar(tag='loss/generator/{}'.format(term), scalar_value=loss.item(), global_step=epoch) 546 | 547 | if epoch % self.config['synthesis']['n_epochs_between_evals'] == 0 and self.config['gt_labels']: 548 | latent_residuals = self.__encode_residuals(imgs) 549 | for factor_idx, factor_name in enumerate(self.config['factor_names']): 550 | acc_train, acc_test = classifier.logistic_regression(latent_residuals, factors[:, factor_idx]) 551 | summary.add_scalar(tag='residual/to-{}'.format(factor_name), scalar_value=acc_test, global_step=epoch) 552 | 553 | for factor_idx, factor_name in enumerate(self.config['residual_factor_names']): 554 | acc_train, acc_test = classifier.logistic_regression(latent_residuals, residual_factors[:, factor_idx]) 555 | summary.add_scalar(tag='residual/to-{}'.format(factor_name), scalar_value=acc_test, global_step=epoch) 556 | 557 | if epoch % self.config['synthesis']['n_epochs_between_visualizations'] == 0: 558 | figure = self.__visualize_reconstruction(dataset, amortized=True) 559 | summary.add_image(tag='reconstruction', img_tensor=figure, global_step=epoch) 560 | 561 | for factor_idx, factor_name in enumerate(self.config['factor_names']): 562 | figure_fixed = self.__visualize_translation(dataset, factor_idx, randomized=False, amortized=True) 563 | figure_random = self.__visualize_translation(dataset, factor_idx, randomized=True, amortized=True) 564 | 565 | summary.add_image(tag='{}-fixed'.format(factor_name), img_tensor=figure_fixed, global_step=epoch) 566 | summary.add_image(tag='{}-random'.format(factor_name), img_tensor=figure_random, global_step=epoch) 567 | 568 | self.save(model_dir) 569 | 570 | summary.close() 571 | 572 | @torch.no_grad() 573 | def evaluate(self, imgs, factors, residual_factors, eval_dir): 574 | latent_factors = self.__encode_factors(imgs) 575 | 576 | scores = dci.evaluate(latent_factors, factors) 577 | with open(os.path.join(eval_dir, 'dci.json'), 'w') as fp: 578 | json.dump(scores, fp) 579 | 580 | scores = sap.evaluate(latent_factors, factors) 581 | with open(os.path.join(eval_dir, 'sap.json'), 'w') as fp: 582 | json.dump(scores, fp) 583 | 584 | scores = mig.evaluate(latent_factors, factors) 585 | with open(os.path.join(eval_dir, 'mig.json'), 'w') as fp: 586 | json.dump(scores, fp) 587 | 588 | scores = {} 589 | for f, factor_name in enumerate(self.config['factor_names']): 590 | scores[factor_name] = self.__eval_factor_classification(imgs, factors, f) 591 | 592 | with open(os.path.join(eval_dir, 'factors.json'), 'w') as fp: 593 | json.dump(scores, fp) 594 | 595 | latent_residuals = self.__encode_residuals(imgs) 596 | scores = {} 597 | for f, factor_name in enumerate(self.config['factor_names']): 598 | acc_train, acc_test = classifier.logistic_regression(latent_residuals, factors[:, f]) 599 | scores[factor_name] = acc_test 600 | 601 | for f, factor_name in enumerate(self.config['residual_factor_names']): 602 | acc_train, acc_test = classifier.logistic_regression(latent_residuals, residual_factors[:, f]) 603 | scores[factor_name] = acc_test 604 | 605 | with open(os.path.join(eval_dir, 'residual.json'), 'w') as fp: 606 | json.dump(scores, fp) 607 | 608 | @torch.no_grad() 609 | def manipulate(self, img, factor_name): 610 | self.amortized_model.to(self.device) 611 | self.amortized_model.eval() 612 | 613 | results = [img] 614 | 615 | img = torch.from_numpy(img.astype(np.float32) / 255.0).permute(2, 0, 1).to(self.device) 616 | residual_code = self.amortized_model.residual_encoder(img.unsqueeze(dim=0))[0] 617 | 618 | factor_idx = self.config['factor_names'].index(factor_name) 619 | factor_codes = self.amortized_model.factor_model(img.unsqueeze(dim=0))['factor_codes'][0] 620 | 621 | factor_codes = list(torch.split(factor_codes, split_size_or_sections=self.config['factor_dim'], dim=0)) 622 | factor_values = torch.arange(self.config['factor_sizes'][factor_idx], dtype=torch.int64).to(self.device) 623 | factor_embeddings = self.amortized_model.factor_model.module.factor_embeddings[factor_idx](factor_values) 624 | 625 | for v in range(factor_embeddings.shape[0]): 626 | factor_codes[factor_idx] = factor_embeddings[v] 627 | latent_code = torch.cat(factor_codes + [residual_code], dim=0) 628 | img_manipulated = self.amortized_model.generator(latent_code.unsqueeze(dim=0))[0] 629 | img_manipulated = (img_manipulated.clamp(min=0, max=1).permute(1, 2, 0).cpu().numpy() * 255).astype(np.uint8) 630 | results.append(img_manipulated) 631 | 632 | return np.concatenate(results, axis=1) 633 | 634 | def __iterate_latent_model(self, batch): 635 | factor_model_out = self.latent_model.factor_model(batch['img'], batch['factors'], batch['label_masks']) 636 | residual_code = self.latent_model.residual_embeddings(batch['img_id']) 637 | 638 | if self.config['residual_std'] != 0: 639 | noise = torch.zeros_like(residual_code) 640 | noise.normal_(mean=0, std=self.config['residual_std']) 641 | 642 | residual_code_regularized = residual_code + noise 643 | else: 644 | residual_code_regularized = residual_code 645 | 646 | latent_code_regularized = torch.cat((factor_model_out['factor_codes'], residual_code_regularized), dim=1) 647 | img_reconstructed = self.latent_model.generator(latent_code_regularized) 648 | loss_reconstruction = self.reconstruction_loss(img_reconstructed, batch['img']) 649 | 650 | loss_entropy = factor_model_out['assignment_entropy'].mean() 651 | loss_residual_decay = torch.mean(residual_code ** 2, dim=1).mean() 652 | 653 | return { 654 | 'reconstruction': loss_reconstruction, 655 | 'residual_decay': loss_residual_decay, 656 | 'entropy': loss_entropy 657 | } 658 | 659 | def __iterate_latent_model_with_labels(self, batch): 660 | factor_model_out = self.latent_model.factor_model(batch['img'], batch['factors'], batch['label_masks']) 661 | residual_code = self.latent_model.residual_embeddings(batch['img_id']) 662 | 663 | if self.config['residual_std'] != 0: 664 | noise = torch.zeros_like(residual_code) 665 | noise.normal_(mean=0, std=self.config['residual_std']) 666 | 667 | residual_code_regularized = residual_code + noise 668 | else: 669 | residual_code_regularized = residual_code 670 | 671 | latent_code_regularized = torch.cat((factor_model_out['factor_codes'], residual_code_regularized), dim=1) 672 | img_reconstructed = self.latent_model.generator(latent_code_regularized) 673 | loss_reconstruction = self.reconstruction_loss(img_reconstructed, batch['img']) 674 | 675 | loss_classification = 0 676 | for f in range(self.config['n_factors']): 677 | if batch['label_masks'][:, f].any(): 678 | loss_classification += self.classification_loss( 679 | factor_model_out['assignment_logits_{}'.format(f)][batch['label_masks'][:, f]], 680 | batch['factors'][batch['label_masks'][:, f], f] 681 | ) 682 | 683 | loss_residual_decay = torch.mean(residual_code ** 2, dim=1).mean() 684 | 685 | return { 686 | 'reconstruction': loss_reconstruction, 687 | 'residual_decay': loss_residual_decay, 688 | 'classification': loss_classification 689 | } 690 | 691 | def __iterate_encoders(self, batch): 692 | residual_code_target = self.latent_model.residual_embeddings(batch['img_id']) 693 | residual_code = self.amortized_model.residual_encoder(batch['img']) 694 | loss_residual = torch.mean((residual_code - residual_code_target) ** 2, dim=1).mean() 695 | 696 | return { 697 | 'residual': loss_residual 698 | } 699 | 700 | def __iterate_amortized_model(self, batch): 701 | with torch.no_grad(): 702 | factor_codes = self.amortized_model.factor_model(batch['img'])['factor_codes'] 703 | residual_code_target = self.latent_model.residual_embeddings(batch['img_id']) 704 | 705 | residual_code = self.amortized_model.residual_encoder(batch['img']) 706 | 707 | latent_code = torch.cat((factor_codes, residual_code), dim=1) 708 | img_reconstructed = self.amortized_model.generator(latent_code) 709 | loss_reconstruction = self.reconstruction_loss(img_reconstructed, batch['img']) 710 | 711 | loss_residual = torch.mean((residual_code - residual_code_target) ** 2, dim=1).mean() 712 | 713 | losses = { 714 | 'reconstruction': loss_reconstruction, 715 | 'latent': loss_residual 716 | } 717 | 718 | if self.config['synthesis']['adversarial']: 719 | discriminator_fake = self.amortized_model.discriminator(img_reconstructed) 720 | loss_adversarial = self.__adv_loss(discriminator_fake, 1) 721 | 722 | losses['adversarial'] = loss_adversarial 723 | 724 | return losses 725 | 726 | def __iterate_discriminator(self, batch): 727 | with torch.no_grad(): 728 | factor_codes = self.amortized_model.factor_model(batch['img'])['factor_codes'] 729 | residual_code = self.amortized_model.residual_encoder(batch['img']) 730 | latent_code = torch.cat((factor_codes, residual_code), dim=1) 731 | img_reconstructed = self.amortized_model.generator(latent_code) 732 | 733 | batch['img'].requires_grad_() # for gradient penalty 734 | discriminator_fake = self.amortized_model.discriminator(img_reconstructed) 735 | discriminator_real = self.amortized_model.discriminator(batch['img']) 736 | 737 | loss_fake = self.__adv_loss(discriminator_fake, 0) 738 | loss_real = self.__adv_loss(discriminator_real, 1) 739 | loss_gp = self.__gradient_penalty(discriminator_real, batch['img']) 740 | 741 | return { 742 | 'fake': loss_fake, 743 | 'real': loss_real, 744 | 'gradient_penalty': loss_gp 745 | } 746 | 747 | @staticmethod 748 | def __adv_loss(logits, target): 749 | targets = torch.full_like(logits, fill_value=target) 750 | loss = F.binary_cross_entropy_with_logits(logits, targets) 751 | return loss 752 | 753 | @staticmethod 754 | def __gradient_penalty(d_out, x_in): 755 | batch_size = x_in.size(0) 756 | 757 | grad_dout = torch.autograd.grad(outputs=d_out.sum(), inputs=x_in, create_graph=True, retain_graph=True, only_inputs=True)[0] 758 | grad_dout2 = grad_dout.pow(2) 759 | 760 | reg = 0.5 * grad_dout2.view(batch_size, -1).sum(1).mean(0) 761 | return reg 762 | 763 | @torch.no_grad() 764 | def __embed_factors(self, dataset): 765 | self.latent_model.eval() 766 | 767 | codes = [] 768 | data_loader = DataLoader(dataset, batch_size=64, shuffle=False, pin_memory=True, drop_last=False) 769 | for batch in data_loader: 770 | batch = {name: tensor.to(self.device) for name, tensor in batch.items()} 771 | 772 | batch_codes = self.latent_model.factor_model(batch['img'], batch['factors'], batch['label_masks'])['factor_codes'] 773 | codes.append(batch_codes.cpu()) 774 | 775 | codes = torch.cat(codes, dim=0) 776 | return torch.stack(torch.split(codes, split_size_or_sections=self.config['factor_dim'], dim=1), dim=1).numpy() 777 | 778 | @torch.no_grad() 779 | def __encode_factors(self, imgs): 780 | self.amortized_model.eval() 781 | 782 | codes = [] 783 | dataset = ImageTensorDataset({'img': torch.from_numpy(imgs).permute(0, 3, 1, 2)}) 784 | data_loader = DataLoader(dataset, batch_size=64, shuffle=False, pin_memory=True, drop_last=False) 785 | for batch in data_loader: 786 | batch_codes = self.amortized_model.factor_model(batch['img'].to(self.device))['factor_codes'] 787 | codes.append(batch_codes.cpu()) 788 | 789 | codes = torch.cat(codes, dim=0) 790 | return torch.stack(torch.split(codes, split_size_or_sections=self.config['factor_dim'], dim=1), dim=1).numpy() 791 | 792 | @torch.no_grad() 793 | def __embed_residuals(self, dataset): 794 | self.latent_model.eval() 795 | 796 | codes = [] 797 | data_loader = DataLoader(dataset, batch_size=64, shuffle=False, pin_memory=True, drop_last=False) 798 | for batch in data_loader: 799 | batch = {name: tensor.to(self.device) for name, tensor in batch.items()} 800 | 801 | batch_codes = self.latent_model.residual_embeddings(batch['img_id']) 802 | codes.append(batch_codes.cpu()) 803 | 804 | codes = torch.cat(codes, dim=0) 805 | return codes.numpy() 806 | 807 | @torch.no_grad() 808 | def __encode_residuals(self, imgs): 809 | self.amortized_model.eval() 810 | 811 | codes = [] 812 | dataset = ImageTensorDataset({'img': torch.from_numpy(imgs).permute(0, 3, 1, 2)}) 813 | data_loader = DataLoader(dataset, batch_size=64, shuffle=False, pin_memory=True, drop_last=False) 814 | for batch in data_loader: 815 | batch_codes = self.amortized_model.residual_encoder(batch['img'].to(self.device)) 816 | codes.append(batch_codes.cpu()) 817 | 818 | codes = torch.cat(codes, dim=0) 819 | return codes.numpy() 820 | 821 | @torch.no_grad() 822 | def __eval_factor_classification(self, imgs, factors, factor_idx): 823 | self.latent_model.eval() 824 | 825 | dataset = ImageTensorDataset({'img': torch.from_numpy(imgs).permute(0, 3, 1, 2)}) 826 | data_loader = DataLoader(dataset, batch_size=64, shuffle=False, pin_memory=True, drop_last=False) 827 | 828 | predictions = [] 829 | for batch in data_loader: 830 | if isinstance(self.latent_model.factor_model.module.factor_classifiers, MultiFactorClassifier): 831 | logits = self.latent_model.factor_model.module.factor_classifiers(batch['img'].to(self.device))[factor_idx] 832 | else: 833 | logits = self.latent_model.factor_model.module.factor_classifiers[factor_idx](batch['img'].to(self.device)) 834 | 835 | batch_predictions = logits.argmax(dim=1) 836 | predictions.append(batch_predictions.cpu().numpy()) 837 | 838 | predictions = np.concatenate(predictions, axis=0) 839 | accuracy = np.mean(factors[:, factor_idx] == predictions) 840 | 841 | return accuracy 842 | 843 | @torch.no_grad() 844 | def __visualize_translation(self, dataset, factor_idx, n_samples=10, randomized=False, amortized=False): 845 | random = self.visualization_rs if randomized else np.random.RandomState(seed=self.config['seed']) 846 | img_idx = torch.from_numpy(random.choice(len(dataset), size=n_samples, replace=False)) 847 | batch = dataset[img_idx] 848 | batch = {name: tensor.to(self.device) for name, tensor in batch.items()} 849 | 850 | if amortized: 851 | self.amortized_model.eval() 852 | 853 | batch['factor_codes'] = self.amortized_model.factor_model(batch['img'])['factor_codes'] 854 | batch['residual_code'] = self.amortized_model.residual_encoder(batch['img']) 855 | 856 | else: 857 | self.latent_model.eval() 858 | 859 | batch['factor_codes'] = self.latent_model.factor_model(batch['img'], batch['factors'], batch['label_masks'])['factor_codes'] 860 | batch['residual_code'] = self.latent_model.residual_embeddings(batch['img_id']) 861 | 862 | generator = self.amortized_model.generator if amortized else self.latent_model.generator 863 | 864 | figure = [] 865 | for i in range(n_samples): 866 | converted_imgs = [batch['img'][i]] 867 | 868 | factor_codes = list(torch.split(batch['factor_codes'][i], split_size_or_sections=self.config['factor_dim'], dim=0)) 869 | factor_values = torch.arange(self.config['factor_sizes'][factor_idx], dtype=torch.int64).to(self.device) 870 | factor_embeddings = self.latent_model.factor_model.module.factor_embeddings[factor_idx](factor_values) 871 | 872 | for j in range(factor_embeddings.shape[0]): 873 | factor_codes[factor_idx] = factor_embeddings[j] 874 | latent_code = torch.cat(factor_codes + [batch['residual_code'][i]], dim=0) 875 | converted_img = generator(latent_code.unsqueeze(dim=0)) 876 | converted_imgs.append(converted_img[0]) 877 | 878 | figure.append(torch.cat(converted_imgs, dim=2)) 879 | 880 | figure = torch.cat(figure, dim=1) 881 | return figure.clamp(min=0, max=1) 882 | 883 | @torch.no_grad() 884 | def __visualize_reconstruction(self, dataset, n_samples=10, amortized=False): 885 | random = np.random.RandomState(seed=self.config['seed']) 886 | img_idx = torch.from_numpy(random.choice(len(dataset), size=n_samples, replace=False)) 887 | batch = dataset[img_idx] 888 | batch = {name: tensor.to(self.device) for name, tensor in batch.items()} 889 | 890 | if amortized: 891 | self.amortized_model.eval() 892 | 893 | batch['factor_codes'] = self.amortized_model.factor_model(batch['img'])['factor_codes'] 894 | batch['residual_code'] = self.amortized_model.residual_encoder(batch['img']) 895 | 896 | else: 897 | self.latent_model.eval() 898 | 899 | batch['factor_codes'] = self.latent_model.factor_model(batch['img'], batch['factors'], batch['label_masks'])['factor_codes'] 900 | batch['residual_code'] = self.latent_model.residual_embeddings(batch['img_id']) 901 | 902 | generator = self.amortized_model.generator if amortized else self.latent_model.generator 903 | 904 | latent_code = torch.cat((batch['factor_codes'], batch['residual_code']), dim=1) 905 | img_reconstructed = generator(latent_code) 906 | 907 | figure = torch.cat([ 908 | torch.cat(list(batch['img']), dim=2), 909 | torch.cat(list(img_reconstructed), dim=2) 910 | ], dim=1) 911 | 912 | return figure.clamp(min=0, max=1) 913 | -------------------------------------------------------------------------------- /network/utils.py: -------------------------------------------------------------------------------- 1 | from torch.utils.data.dataset import Dataset 2 | 3 | 4 | class ImageTensorDataset(Dataset): 5 | 6 | def __init__(self, named_tensors): 7 | assert all(list(named_tensors.values())[0].size(0) == tensor.size(0) for tensor in named_tensors.values()) 8 | self.named_tensors = named_tensors 9 | 10 | def __getitem__(self, index): 11 | item = {name: tensor[index] for name, tensor in self.named_tensors.items()} 12 | 13 | if 'img' in item: 14 | item['img'] = item['img'].float() / 255.0 15 | 16 | return item 17 | 18 | def __len__(self): 19 | return list(self.named_tensors.values())[0].size(0) 20 | --------------------------------------------------------------------------------