├── 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 | 
44 | 
45 | 
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 |
--------------------------------------------------------------------------------