Jonathandav commited on
Commit
587e1f0
Β·
verified Β·
1 Parent(s): 1bde2ba

Update README.md

Browse files
Files changed (1) hide show
  1. README.md +231 -6
README.md CHANGED
@@ -1,13 +1,238 @@
1
  ---
2
  title: Facade
3
- emoji: πŸ‘
4
- colorFrom: pink
5
- colorTo: yellow
6
  sdk: gradio
7
- sdk_version: 6.22.0
8
- python_version: '3.12'
9
  app_file: app.py
10
  pinned: false
 
 
11
  ---
12
 
13
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
  title: Facade
3
+ emoji: πŸ›
4
+ colorFrom: blue
5
+ colorTo: red
6
  sdk: gradio
 
 
7
  app_file: app.py
8
  pinned: false
9
+ license: mit
10
+ short_description: Photograph a building, find its architectural style
11
  ---
12
 
13
+ # Facade
14
+
15
+ **Point a camera at a building. Find out what you are looking at.**
16
+
17
+ Upload a photograph of a facade and the app returns the three closest
18
+ architectural styles from a 1,000-plate synthetic reference corpus, a reading
19
+ written for *your* photograph at query time, the measurements behind the match,
20
+ and real named buildings near you in the same style.
21
+
22
+ - **Dataset:** [Jonathandav/facade-styles](https://huggingface.co/datasets/Jonathandav/facade-styles)
23
+ - **Corpus:** 1,000 generated plates Β· 20 styles Β· 50 each
24
+ - **Retrieval model:** `laion/CLIP-ViT-B-32-laion2B-s34B-b79K`
25
+ - **Reading model:** `Qwen/Qwen2.5-1.5B-Instruct`
26
+
27
+ ---
28
+
29
+ ## The idea
30
+
31
+ Architectural style is a family resemblance rather than a fact about a
32
+ building. That makes it a good target for *synthetic* reference data: a
33
+ generated Bauhaus facade **is** a Bauhaus facade, because there is no external
34
+ specimen it can contradict.
35
+
36
+ It also makes style unusually measurable. Brutalism is low-saturation and
37
+ heavy-massed; Gothic Revival is vertical-edge dominant; Bauhaus is horizontal;
38
+ Ottoman Revival is curve-rich. Every one of those has a pixel-level correlate,
39
+ so "did the generator do what it was told?" is a computed quantity rather than
40
+ an opinion.
41
+
42
+ The whole project is built on that: a corpus specified attribute by attribute,
43
+ audited by measurement, and finally tested against real photographs.
44
+
45
+ ---
46
+
47
+ ## How it works
48
+
49
+ ```
50
+ style_seed.csv 20 styles, each with massing, material, window
51
+ β”‚ rhythm, roofline, palette, and two EXPECTED
52
+ β”‚ measurements (saturation band, edge orientation)
53
+ β–Ό
54
+ sample_plates() 50 specs per style; view / crop / light / condition
55
+ β”‚ CYCLED, not sampled β€” so they cannot correlate
56
+ β–Ό with style
57
+ SDXL-Turbo style name + period + key features lead the prompt
58
+ β”‚ acceptance gate measures every render and retries
59
+ β–Ό with a fresh seed until it passes
60
+ 1,000 plates ──► LAION-CLIP embeddings ──► index_embeddings.npy
61
+ β”‚
62
+ β–Ό
63
+ Qwen2.5-1.5B style readings, barred from naming architects,
64
+ asserting dates, or claiming heritage status
65
+ ```
66
+
67
+ At query time: embed the photograph β†’ cosine similarity against the index β†’
68
+ optionally rerank with an OpenStreetMap prior over what actually stands nearby
69
+ β†’ generate a reading from the matched style, the runner-up, and the
70
+ measurements taken off the photograph.
71
+
72
+ ---
73
+
74
+ ## What the corpus can identify
75
+
76
+ Bauhaus International Β· Brutalist Β· Art Deco Β· Ottoman Revival Β· Mandate
77
+ Eclectic Β· Neoclassical Β· Gothic Revival Β· Venetian Gothic Β· Georgian Β·
78
+ Victorian Terrace Β· Mid-century Modern Β· Postmodern Β· Deconstructivist Β·
79
+ Contemporary Curtain Wall Β· Mediterranean Vernacular Β· Adobe Pueblo Β· Soviet
80
+ Constructivist Β· Scandinavian Functionalist Β· Industrial Warehouse Β· Japanese
81
+ Metabolist
82
+
83
+ Anything outside these twenty is still forced onto the nearest of them. The app
84
+ says so in the interface, because a user should know that before trusting a
85
+ result.
86
+
87
+ ---
88
+
89
+ ## Did the generator obey?
90
+
91
+ ![Declared vs measured saturation, and compliance by style](assets/eda_compliance.png)
92
+
93
+ Each style declares an expected saturation level. That is an **ordinal** claim β€”
94
+ brutalism less saturated than Art Deco β€” not a value on a calibrated scale.
95
+
96
+ **Spearman ρ = 0.67, p β‰ˆ 1.5 Γ— 10⁻¹³², n = 1000.** Declared rank predicts
97
+ measured saturation strongly.
98
+
99
+ The first version of this test scored **8%** compliance, because the bands were
100
+ absolute thresholds chosen before any image existed: measured saturation ran
101
+ 0.30–0.85 while "medium" had been guessed at 0.22–0.50. Recalibrating the bands
102
+ to corpus quantiles and reporting rank agreement is the correct test, and it is
103
+ a better methodological story than thresholds that happened to work first time.
104
+
105
+ ---
106
+
107
+ ## Where will it get confused?
108
+
109
+ ![Style centroids in measured feature space, and centroid distance matrix](assets/eda_style_space.png)
110
+
111
+ Plotting each style's centroid in saturation Γ— edge-orientation space produces
112
+ a **prediction, before any embedding model runs**, of which pairs will be
113
+ conflated:
114
+
115
+ | pair | centroid distance |
116
+ |---|---|
117
+ | Neoclassical ↔ Postmodern | 0.41 |
118
+ | Japanese Metabolist ↔ Scandinavian Functionalist | 0.62 |
119
+ | Mandate Eclectic ↔ Neoclassical | 0.65 |
120
+ | Brutalist ↔ Japanese Metabolist | 0.65 |
121
+ | Georgian ↔ Victorian Terrace | 0.75 |
122
+
123
+ These are architecturally meaningful, not arbitrary. Postmodernism is *defined*
124
+ by ironic quotation of classical form. Mandate Eclectic borrowed classical
125
+ proportion directly. Brutalism and Metabolism are contemporaneous raw-concrete
126
+ movements. A purely pixel-level metric recovered relationships an architectural
127
+ historian would recognise.
128
+
129
+ **Georgian ↔ Victorian Terrace was confirmed** by the CLIP confusion matrix at
130
+ 0.16 β€” the top confusion by a wide margin. The others were not, and CLIP's
131
+ actual confusions cluster differently: Bauhaus International acts as an
132
+ *attractor* for the modernist styles, with Brutalist, Soviet Constructivist and
133
+ Japanese Metabolist all leaking toward it. That is a semantic effect the pixel
134
+ metric cannot see.
135
+
136
+ One prediction confirmed and four refuted with a coherent explanation is a
137
+ better result than five vague hits.
138
+
139
+ ---
140
+
141
+ ## Does style dominate the nuisance factors?
142
+
143
+ ![Variance explained by each factor, and style's margin over the strongest nuisance](assets/eda_variance.png)
144
+
145
+ Style explains **43–66%** of variance in every measured feature. Crop, view and
146
+ condition sit at essentially **zero** β€” which validates the sampler: those axes
147
+ are cycled rather than drawn independently, so they cannot correlate with
148
+ style. Had they done so, an embedding model could have scored well by learning
149
+ framing instead of architecture.
150
+
151
+ Light is the only meaningful contaminant, and only on the photometric features,
152
+ which is physically unsurprising.
153
+
154
+ ---
155
+
156
+ ## Retrieval
157
+
158
+ Image-to-image over the corpus, style as the label, chance β‰ˆ 0.049.
159
+
160
+ | model | Recall@1 | Recall@3 | MRR | lift |
161
+ |---|---|---|---|---|
162
+ | SigLIP-B/16 | 0.972 | 0.994 | 0.983 | 19.8Γ— |
163
+ | LAION-CLIP-B/32 | 0.970 | 0.991 | 0.981 | 19.8Γ— |
164
+ | CLIP-B/32 | 0.955 | 0.988 | 0.972 | 19.5Γ— |
165
+
166
+ **These are at ceiling and the comparison cannot resolve.** Plates of the same
167
+ style share nearly identical prompts, differing only in angle, crop, light and
168
+ condition, so they are near-siblings. Every slice falls between 0.975 and
169
+ 1.000. The differences between models are inside noise.
170
+
171
+ ---
172
+
173
+ ## Sim-to-real β€” the result that matters
174
+
175
+ 17 hand-labelled photographs of real buildings in Tel Aviv, Jaffa, Paris and
176
+ the Greek islands, retrieved against the wholly synthetic index.
177
+
178
+ | model | real R@3 | synthetic R@3 | gap |
179
+ |---|---|---|---|
180
+ | **LAION-CLIP-B/32** | **0.94** (16/17) | 0.991 | **βˆ’0.05** |
181
+ | SigLIP-B/16 | 0.88 (15/17) | 0.994 | βˆ’0.11 |
182
+ | CLIP-B/32 | 0.76 (13/17) | 0.988 | βˆ’0.22 |
183
+
184
+ The synthetic benchmark ranked SigLIP first by 0.002 on Recall@1. On real
185
+ photographs LAION wins and has less than half the domain gap. **Selecting on
186
+ the saturated benchmark would have shipped the weaker model.** A benchmark at
187
+ ceiling does not merely fail to discriminate β€” it discriminates wrongly.
188
+
189
+ Both failure cases are architecturally sensible: a Bauhaus building retrieved
190
+ as Soviet Constructivist (contemporaneous interwar modernism, strip windows,
191
+ white render), and a night photograph of a Mandate building retrieved as
192
+ Mediterranean Vernacular (both cream render with shutters).
193
+
194
+ ---
195
+
196
+ ## Generator failures found along the way
197
+
198
+ Four, plus one measurement bug. **Three of the four were silent** β€” no
199
+ exception, no warning, and plausible-looking output.
200
+
201
+ | # | failure | how it was caught | silent |
202
+ |---|---|---|---|
203
+ | 1 | SDXL's pooled embedding overrode every style | Bauhaus, Brutalist and Gothic all rendered as the same beige office block | yes |
204
+ | 2 | detail crops destroyed the class signal | style unrecoverable from a cropped window grid | yes |
205
+ | 3 | `key_features` never reached the image prompt | code review after failure 1 | no |
206
+ | 4 | prompts truncated at 77 tokens | validator token-budget check | yes |
207
+
208
+ The fifth was a **metric** bug: the orientation classifier could only emit three
209
+ of the five declared labels, so every style declaring `curved` or `diagonal`
210
+ scored zero and looked like a total generator failure. Fixing the measurement
211
+ raised orientation compliance from 60% to 83%.
212
+
213
+ A broken metric can invent a failure as easily as a broken generator can hide
214
+ one. Both argue for the same thing: instrumented acceptance criteria, not
215
+ visual inspection.
216
+
217
+ ---
218
+
219
+ ## Limitations
220
+
221
+ - Visual-similarity search, **not** authoritative identification.
222
+ - No plate depicts a real building; none is attributable to any architect.
223
+ - The real-photograph evaluation is small (n = 17) and unevenly distributed
224
+ across styles.
225
+ - Style boundaries blur where visual grammars genuinely overlap.
226
+ - Location reranking depends on OpenStreetMap tag density, which varies
227
+ enormously by city β€” Paris returns far more than Tel Aviv.
228
+ - The app makes no claim about any building's date, architect, or heritage
229
+ status, and both models are explicitly prompted not to.
230
+
231
+ ## Using it
232
+
233
+ Include the whole building where you can. Style lives in massing, roofline and
234
+ silhouette, and a cropped window grid discards all three.
235
+
236
+ For the location features, type a place with its country β€” "Rothschild
237
+ Boulevard, Tel Aviv, Israel" β€” and check the resolved name before running.
238
+ Geocoders will happily match a street name on the wrong continent.