This benchmark evaluates four published floor-plan generators against HypergraphFormer:
| Model | Dataset | Inputs |
|---|---|---|
| HouseGAN++ | WMR24 | room set + adjacency graph |
| House-Diffusion | WMR24 | room set + adjacency graph |
| DiffPlanner | RPLAN | input boundary + room count + room categories (b+nc mode) |
| iPLAN (CVPR 2022) | RPLAN | input boundary + room count + room categories (OurII mode; Stage 1 skipped) |
It ships automated setup scripts, data conversion utilities, and a shared evaluation pipeline. Available metrics are: GED, room accuracy (combined / count-only / type-only), delta (geometric similarity), area proportion error, plus boundary-aware coverage / outside-spill / inter-room overlap ratios for the boundary-conditioned models.
- Quick Start: HouseGAN++
- Quick Start: House-Diffusion
- Quick Start: DiffPlanner
- Quick Start: iPLAN
- Evaluation Metrics
- Shell Scripts
- Core Scripts
- Utility Scripts
- Dataset Format
- Project Structure
cd benchmark
./setup_houseganpp.shThis will:
- Clone the HouseGAN++ repository (if needed)
- Create a Python virtual environment
- Install all dependencies
- Convert the WMR24 dataset to HouseGAN++ format (JSON → pickle)
cd benchmark
./eval_houseganpp.shOr run directly:
cd benchmark
source ../.venv/bin/activate
python src/evaluate_houseganpp.py \
--data_path /path/to/test_data.pkl \
--checkpoint ../houseganpp/checkpoints/pretrained.pth \
--out eval_results_houseganpp \
--num_variations 5 \
--save_graphsResults are saved to eval_results_houseganpp/results.npz and
results.txt. Comparison images go into eval_results_houseganpp/fig/.
cd benchmark
./setup_housediffusion.shThis will:
- Verify the
house_diffusionrepository exists - Create/reuse the shared virtual environment
- Install House-Diffusion dependencies and package
- Reuse HouseGAN++ JSON data (or convert fresh) and build NPZ files
cd benchmark
./eval_housediffusion.shResults are saved to eval_results_housediffusion/results.npz.
DiffPlanner is evaluated on the RPLAN test split (12k samples) in
its b+nc cascade mode: the model receives the input boundary, the
desired room count, and the desired room categories, then runs three
sub-models in sequence (NodeDiff -> AdjacencyDiff -> PartitioningDiff)
followed by post-processing.
# from the repo root
./prepare_rplan_hypergraph.shThis downloads the RPLAN floorplan PNGs and the official DiffPlanner
JSON dataset and lays them out at
dataset/rplan/dataset_diffplanner/data_{train,val,test}.json.
cd benchmark
./setup_diffplanner.shThis will:
- Clone the
DiffPlannerrepository alongside the project (skipped if already present) - Download
trained_model.zip(~665 MB) from the official release and place the three required checkpoints at the exact paths the evaluator's--node_checkpoint/--adjacency_checkpoint/--partition_checkpointdefaults expect - Symlink the prepared
data_test.json(anddata_train.jsonif present) into<DiffPlanner>/dataset/dataset_json/so DiffPlanner's internal helpers (RPlanDataset,post_processing.py) load the same source-of-truth data
There is no pip-install step: DiffPlanner ships no setup.py /
requirements.txt, and the evaluator imports its sub-packages by
adding them to sys.path at runtime.
Run the full cascade once and cache the post-processed records (a few hours on one GPU):
cd <repo root>
python benchmark/src/evaluate_diffplanner.py \
--data_path dataset/rplan/dataset_diffplanner/data_test.json \
--diffplanner_root ../DiffPlanner \
--use_ddim \
--save_generations cache/dp_bnc_test_full.pkl \
--out benchmark/eval_results_diffplanner_bncThen re-score from the cache as many times as you like (no GPU required):
python benchmark/src/evaluate_diffplanner.py \
--load_generations cache/dp_bnc_test_full.pkl \
--data_path dataset/rplan/dataset_diffplanner/data_test.json \
--out benchmark/eval_results_diffplanner_bncResults are saved to
benchmark/eval_results_diffplanner_bnc/results.npz and
results.txt. To render side-by-side GT vs predicted floor plans
(plus bubble diagrams) with metrics overlaid, use the visualizer:
python -m benchmark.utils.visualize_diffplanner \
--predicted cache/dp_bnc_test_full.pkl \
--gt-json dataset/rplan/dataset_diffplanner/data_test.json \
--metrics-npz benchmark/eval_results_diffplanner_bnc/results.npz \
--out-dir benchmark/eval_results_diffplanner_bnc/vis \
--limit 50iPLAN is evaluated on the RPLAN test split (12,110 samples) in its
OurII mode: the user supplies the boundary AND the per-floorplan
ground-truth room types/count, and iPLAN's three-stage cascade fills
in the rest:
- Stage 1 (BCVAE for room types) -- skipped (
rTypes := gt_rTypes) - Stage 2 (room locations, ResNet18 + ASPP) -- runs
- Stage 3 (room partitions, step-wise GAN) -- runs (with iterative refinement)
iPLAN ships its own pinned Python 3.8 / torch==1.10.1+cu113 stack
that is incompatible with the shared .venv used by HouseGAN++ /
House-Diffusion / DiffPlanner, so it lives in a dedicated iplan conda
env. The setup script bootstraps it on first run.
If you have not already, download the RPLAN floorplan PNGs:
# from the repo root
./prepare_rplan_hypergraph.shThis places the PNGs at
dataset/rplan/dataset_original/floorplan_dataset/*.png. iPLAN's
.mat files are derived from these in step 2.
cd benchmark
./setup_iplan.shThis will (idempotently):
- Clone the iPLAN repository
(
https://github.com/hsalehipour/iPLAN-Interactive-and-Procedural-Layout-Planning.git) alongside the project - Apply 3 small inference-time patches to upstream iPLAN so its modules can be imported and run from outside the iPLAN repo (these fix pre-existing import-shadowing and cwd-relative path bugs in the upstream code; not algorithm changes)
- Create the
iplanconda env if missing andpip installa version-pinned dependency list (Python 3.8 + the cu113 torch wheel from PyTorch's own index) - Download the iPLAN trained-model bundle from the official Google
Drive folder using
gdownand lay each.pth/.pklat the exact path the evaluator's_load_iplan_models()expects - Build
dataset/rplan/dataset_iplan/by runningbenchmark/utils/convert_png_to_iplan_mat.pyon RPLAN's test split (~12,110.matfiles; ~4 minutes on 64 cores)
Useful flags: --force-checkpoints, --force-dataset,
--force-patches, --force-env, --skip-dataset.
Run the full cascade once and cache the post-processed records:
conda activate iplan
cd <repo root>
python -m benchmark.src.evaluate_iplan \
--iplan_data_dir dataset/rplan/dataset_iplan \
--iplan_root ../iPlan \
--save_generations cache/iplan_ourII_test.pkl \
--out benchmark/eval_results_iplan_ourIIRe-score from the cache as many times as you like (no GPU required):
python -m benchmark.src.evaluate_iplan \
--load_generations cache/iplan_ourII_test.pkl \
--out benchmark/eval_results_iplan_ourIIBoth inputs and ground truth are read from the same iPLAN .mat file
(Boundary, gt_rTypes, gt_rBoxes for GT; rTypes is seeded from
gt_rTypes and Stage 2/3 fill in rCenters / rBoxes). This
sidesteps any cross-format coordinate-frame or category-vocabulary
mapping and keeps the evaluation strictly inside iPLAN's native 128px
13-class space. There is no eval_iplan.sh wrapper today; the two
commands above are the recommended invocations.
All evaluation scripts delegate statistics computation, printing, and
file output to utils/report_results.py. Per-script metric coverage:
| Metric | HouseGAN++ | House-Diffusion | DiffPlanner | iPLAN |
|---|---|---|---|---|
| GED | yes | yes | -- | -- |
| Room Accuracy (combined / count / type) | yes | yes | yes | yes |
| Delta (Room Similarity) | yes | yes | yes | yes |
| Area Proportion Error | yes | yes | yes | yes |
| Spatial Overlap Ratio (no boundary) | yes | yes | -- | -- |
| Boundary geometry triplet (gap / outside / overlap) | -- | -- | yes | yes |
Definitions:
-
GED -- Graph Edit Distance between predicted and ground-truth door-based access graphs. Computed with a 10 s timeout per pair; timed-out cases are recorded as NaN.
-
Room Accuracy -- Three sub-scores from
utils.metrics.room_type_accuracy: combinedaccuracy(matches count and types),room_count_accuracy(count-only), androom_type_accuracy(type multiset only). For DiffPlanner, "predicted rooms" means the rooms that survive post-processing (rooms whoser_boundary_alignedwas dropped byregularize_fpor covered by a sibling inget_room_boundaryare counted as lost). The lost-room rate is also reported asHidden roomsinresults.txt. For iPLAN, predicted rooms are read from the rasterized 128px Stage-3 layout (one bbox per connected component, including the Living room which iPLAN recovers as the leftover interior). -
Delta (Room Similarity) -- Geometric shape similarity between matched predicted and ground-truth room pairs, based on area and perimeter ratios.
-
Area Proportion Error -- Mean absolute difference between room-area proportions of paired predicted and ground-truth rooms of the same type.
-
Spatial Overlap Ratio (HouseGAN++ / House-Diffusion) --
1 - area(union(pred)) / sum(area(pred_i)). Captures inter-room overlap only; not normalized by an input boundary because the WMR24-conditioned models are not given one. -
Boundary geometry triplet (DiffPlanner / iPLAN) -- Three complementary ratios, all normalized by the input boundary area F so values are directly comparable across samples and methods. Let
U = union of predicted room polygonsandS = sum of their individual areas:Metric Formula Ideal Failure mode it catches gap_ratioarea(F − U) / area(F)0 predicted rooms leave the boundary uncovered outside_ratioarea(U − F) / area(F)0 predicted rooms spill outside the boundary overlap_ratio(S − area(U)) / area(F)0 rooms double-count area by overlapping each other See
compute_boundary_geometry_metrics()inevaluate_diffplanner.pyandevaluate_iplan.pyfor the exact Shapely implementation.
All metrics are saved to results.npz and a human-readable
results.txt summary.
# Bin metrics by room count (auto-detects all available metrics in the NPZ)
python utils/analyze_metrics_by_room_count.py \
--results_npz eval_results_houseganpp/results.npz
# With display title + JSON export
python utils/analyze_metrics_by_room_count.py \
--results_npz eval_results_housediffusion/results.npz \
--title "House-Diffusion" \
--output_json binned_stats.jsonComplete automated setup for HouseGAN++ evaluation on the WMR24 dataset.
- Clones HouseGAN++ from
https://github.com/hsalehipour/houseganpp - Creates a virtual environment with all Python dependencies
- Converts WMR24 hypergraph JSON → HouseGAN++ JSON → pickle format
Complete automated setup for House-Diffusion evaluation on the WMR24 dataset.
- Verifies the
house_diffusionrepo exists alongside the project - Creates/reuses the shared virtual environment
- Installs House-Diffusion as a package
- Converts WMR24 data to HouseGAN++ JSON (reuses existing if available)
- Converts JSON data to NPZ format expected by House-Diffusion
Complete automated setup for DiffPlanner evaluation on the RPLAN test
split. Idempotent; pass --force-checkpoints to re-download the
trained_model.zip.
- Clones
DiffPlannerfromhttps://github.com/shidong-wang/DiffPlanneralongside the project (skipped if already present) - Downloads
trained_model.zipand lays out the three required checkpoints at the exact paths the evaluator's CLI defaults expect:<DP>/node_diff/scripts/trained_model/bnc_model300000.pt<DP>/adjacency_diff/scripts/trained_model/bncsl_model300000.pt<DP>/partitioning_diff/scripts/trained_model/bncsla_model300000.pt
- Symlinks the prepared
data_test.json(anddata_train.jsonif present) into<DP>/dataset/dataset_json/
The script assumes the dataset JSONs themselves were already produced
by ./prepare_rplan_hypergraph.sh from the repo root.
Complete automated setup for iPLAN evaluation on the RPLAN test split
in OurII mode. Five idempotent steps; pass --force-checkpoints,
--force-dataset, --force-patches, --force-env, or
--skip-dataset to override individual stages.
- Clones the iPLAN repo (
hsalehipour/iPLAN-Interactive-and-Procedural-Layout-Planning) alongside the project (skipped if already present) - Applies 3 small inference-time patches to upstream iPLAN
(
room_partition/models/__init__.py,loss_layer.py,net.py) that fix pre-existing import-shadowing and cwd-relative path bugs. Marker file<iPlan>/.hf_inference_patches_appliedmakes re-runs a no-op. - Creates the
iplanconda env with Python 3.8 andpip installs a version-pinned dependency list (including the cu113 torch wheel from PyTorch's own index). Existing envs are left alone unless--force-envis passed. - Downloads the iPLAN trained-model bundle from the official Google
Drive folder using
gdownand lays out 8 weight files (<iPlan>/room_location/{pretrained_model,weights}/*.pthand<iPlan>/room_partition/weights/{G_net_210.pth,renderer.pkl}). - Builds
dataset/rplan/dataset_iplan/fromdataset_original/floorplan_dataset/*.pngviabenchmark/utils/convert_png_to_iplan_mat.py(~12,110.matfiles).
The script assumes ./prepare_rplan_hypergraph.sh has already
populated the original RPLAN PNGs in dataset_original/.
Evaluate a trained HouseGAN++ model. Supports generation caching via
--save_generations / --load_generations for reproducible re-evaluation.
Evaluate a trained House-Diffusion model. Same caching support as above.
DiffPlanner and iPLAN have no eval_*.sh wrappers today; see the
Quick Start: DiffPlanner and
Quick Start: iPLAN sections for the recommended
invocations.
Shared PyTorch dataset and collation functions for loading WMR24 data in HouseGAN++ format.
BenchmarkDataset— Loads pickle files, builds room masks from polygons, one-hot encodes room types (RPLAN format), creates adjacency edge lists. Supports room-count filtering viatarget_set.collate_fn— Batches samples with variable numbers of rooms, concatenating masks, nodes, and edges with proper index adjustment.
Evaluate HouseGAN++ with four metrics (GED, room accuracy, delta, area proportion error).
- Incremental generation — generates floorplans room-by-room using HouseGAN++'s iterative refinement
- Builds door-based access graphs from generated masks (IoU-based door detection) and from ground-truth structure (graph triples)
- Multiple variations per sample for consistency measurement
--save_graphsproduces side-by-side GT vs predicted comparison images- Generation caching via
--save_generations/--load_generations
Evaluate House-Diffusion with the same four metrics.
- Generates floorplans using diffusion sampling
- Extracts room polygons from generated outputs
- Builds predicted access graphs from polygon adjacency
- Generation caching for reproducible re-evaluation
Evaluate DiffPlanner's b+nc cascade end-to-end on the RPLAN test
split. Computes delta, area proportion error, the boundary geometry
triplet (gap / outside / overlap ratios), and the three
room-accuracy sub-scores (combined / count / type).
- Loads all three sub-model checkpoints (NodeDiff, AdjacencyDiff, PartitioningDiff) and runs the cascade in-memory in batches
- Wraps DiffPlanner's
output/post_processing.py; falls back to raw cascade boxes when alignment aborts (recorded asraw_fallback_count) - Tracks rooms dropped by post-processing (
Empty box i!!!/empty intersection) and reports the lost-room rate asHidden rooms - Generation caching via
--save_generations/--load_generations(post-processed records are pickled, so re-scoring metrics is GPU-free) - Supports
--use_ddimfor ~10x faster sampling than ancestral DDPM
Evaluate iPLAN's OurII cascade on the RPLAN test split (Stage 1
skipped; Stage 2 + Stage 3 run with ground-truth room types as input).
Computes delta, area proportion error, the boundary geometry triplet,
and the three room-accuracy sub-scores. Must run inside the iplan
conda env -- iPLAN's pinned torch / cv2 stack is not in the shared
.venv.
- Loads Stage 2 (Living + Location ResNet18+ASPP) and Stage 3 (G_net GAN + renderer) checkpoints from the iPLAN repo, then runs both stages per sample
- Stage 2 is iteratively re-rolled (default 50 attempts) when
get_rcentersfails to place all rooms; falls back to the most-complete partial placement so Stage 3 still has centers to partition over - Reads BOTH inputs (
Boundary,gt_rTypes) and ground truth (gt_rTypes,gt_rBoxes) from the same iPLAN.matfile -- no cross-format coordinate or category mapping is needed - Predicted rooms come from connected-component analysis of the rasterized 128px Stage-3 layout, so the Living room (which iPLAN recovers as the leftover interior, not a predicted bbox) is included
- Generation caching via
--save_generations/--load_generations(cached records are pickled.mat-style dicts, so re-scoring is GPU-free and doesn't even need the iPLAN repo) - Python-3.8-friendly: imports
utils.metricsandutils.report_resultsby absolute file path so the evaluator runs inside iPLAN's pinned env without dragging in the rest of the HypergraphFormer Python-3.10 stack
Convert WMR24 hypergraph JSON format to HouseGAN++-compatible JSON files. Extracts room polygons, door positions, and adjacency triples from the BSP-tree representation using the RGL geometry library.
Convert HouseGAN++ JSON files to pickle format used by BenchmarkDataset.
Normalizes polygons to a target grid (64x64), maps room types to RPLAN IDs,
and builds adjacency triples.
Convert HouseGAN++ JSON files to NPZ format expected by House-Diffusion's
RPlanhgDataset. Remaps room types and structures the data as houses,
graphs, door_masks, self_masks, gen_masks, and ids arrays.
Convert hypergraph data to DiffPlanner JSON format. Maps the hypergraph
room taxonomy (living, bed, kitchen, bath, foyer, extra)
onto DiffPlanner's 6-class category id space (0..5) and emits per-sample
records with rooms[*].{id, category, r_boundary, size, location, box, order}, adjacencies, and access_adjacencies.
Convert original RPLAN PNGs to iPLAN's native .mat format for a given
split. Wraps iPLAN's own FloorPlan parser (no algorithm changes) and
parallelises across CPU workers. The output .mat carries name,
Boundary, gt_rTypes, gt_rBoxes, rTypes, rBoxes, rCenters
fields and is the canonical input for evaluate_iplan.py. Runs inside
the iplan conda env (needs iPLAN's pinned scipy and cv2); the
default --out-dir points directly at
dataset/rplan/dataset_iplan/ so re-running setup_iplan.sh is
sufficient to refresh the dataset. Honors iPLAN's shipped split lists
(<iplan-root>/data/{train,val,test}.txt) so we evaluate on the same
test split iPLAN was trained against. Default test split has 12,110
entries; ~4 minutes on 64 cores.
Model-agnostic DiffPlanner visualizer. Reads any DiffPlanner-shaped
input (a data_test.json-style list, a single-record JSON, a benchmark
cache .pkl, or a directory of per-sample <name>.json files) and
writes a side-by-side panel per sample (GT floor plan, predicted floor
plan, GT bubble diagram, predicted bubble diagram), an aggregate
summary.png, and a multi-page visualizations.pdf. Pass
--metrics-npz to overlay per-sample numbers from a results.npz.
Color palette and rendering primitives mirror
DiffPlanner/output/visualization.py exactly. Run as
python -m benchmark.utils.visualize_diffplanner --help for the full
flag list.
Note: Reporting and per-room-count analysis have been moved to the shared
utils/ package:
utils/report_results.py-- unified NPZ + TXT reporting used by both benchmark eval scripts andscripts/score_results.py.utils/analyze_metrics_by_room_count.py-- bins NPZ metrics by room count (read fromroom_countsin the NPZ) and produces per-bin statistics.
Each entry in dataset/wmr24/wmr24.json:
{
"database": "zurich",
"id": "ch-z-0020",
"area": 32.73,
"bedrooms": 1,
"bathrooms": 1,
"bounds": { "corners": [...], ... },
"facade": [...],
"circulation": [...],
"split": { "name": "root", "children": [...], ... }
}Produced by convert_hypergraph_to_housegan_json.py:
{
"id": "ch-z-0020",
"room_type": [1, 6, 2, 4, 17, 17, 17],
"boxes": [...],
"edges": [[0, 1, 1], [0, 1, 2], [1, -1, 3], ...]
}Produced by convert_json_to_pickle.py:
{
'id': 'ch-z-0020',
'polygons': [[(x1, y1), (x2, y2), ...], ...],
'room_types': [1, 6, 2, 4, 17, 17, 17],
'triples': [[0, 1, 1], [0, -1, 2], ...]
}Produced by convert_json_to_npz.py:
| Key | Shape | Description |
|---|---|---|
houses |
(N, 100, 94) |
Packed room geometry (corners + one-hot types) |
graphs |
(N,) object |
Adjacency triples per sample |
door_masks |
(N, 100, 100) |
Door adjacency matrices |
self_masks |
(N, 100, 100) |
Self-connection masks |
gen_masks |
(N, 100, 100) |
Generation masks |
ids |
(N,) object |
Sample ID strings |
Produced by convert_png_to_iplan_mat.py (one file per RPLAN sample,
under dataset/rplan/dataset_iplan/<id>.mat). Each file has a top-level
data struct with the fields:
| Field | Shape | Description |
|---|---|---|
name |
scalar string | Source PNG filename |
Boundary |
(N_v, 4) int |
Boundary polygon vertices (y, x, dir, isNew); first two points indicate the front door |
gt_rTypes |
(1, R_gt) int |
Ground-truth room categories (iPLAN 13-class vocab) |
gt_rBoxes |
(R_gt, 4) int |
Ground-truth axis-aligned room boxes (y0, x0, y1, x1) in 128-grid pixels |
rTypes |
(1, R_pred) int |
Inference-filled predicted room types (Stage 1 output, or seeded from gt_rTypes in OurII mode) |
rCenters |
(R_pred, 2) int |
Stage 2 predicted room centers |
rBoxes |
(R_pred, 4) int |
Stage 3 predicted axis-aligned room boxes |
Coordinate conventions in .mat files come straight from iPLAN's
upstream parser, so (y, x) ordering is preserved; evaluate_iplan.py
swaps to (x, y) for Shapely internally.
| WMR24 mergeid | RPLAN ID | Room Type | HouseGAN++ Color |
|---|---|---|---|
| living | 1 | Living Room | #ED6D87 |
| bed | 3 | Bedroom | #5B448C |
| kitchen | 2 | Kitchen | #F0E34F |
| bath | 4 | Bathroom | #5D9AD4 |
| foyer | 6 | Entrance | #FFA17A |
| extra | 10 | Storage | #B0B0B0 |
| — | 17 | Interior Door | #888888 |
benchmark/
├── README.md # This file
├── setup_houseganpp.sh # HouseGAN++ automated setup
├── setup_housediffusion.sh # House-Diffusion automated setup
├── setup_diffplanner.sh # DiffPlanner automated setup
├── setup_iplan.sh # iPLAN automated setup (clone+patch+env+weights+data)
├── eval_houseganpp.sh # HouseGAN++ evaluation launcher
├── eval_housediffusion.sh # House-Diffusion evaluation launcher
│
├── src/ # Core Python scripts
│ ├── dataset_loader.py # Shared PyTorch dataset module
│ ├── evaluate_houseganpp.py # HouseGAN++ evaluation (WMR24)
│ ├── evaluate_housediffusion.py # House-Diffusion evaluation (WMR24)
│ ├── evaluate_diffplanner.py # DiffPlanner b+nc cascade evaluation (RPLAN)
│ └── evaluate_iplan.py # iPLAN OurII cascade evaluation (RPLAN, runs in iplan conda env)
│
├── utils/ # Utility and conversion scripts
│ ├── convert_hypergraph_to_housegan_json.py # WMR24 JSON → HouseGAN++ JSON
│ ├── convert_hypergraph_to_diffplanner.py # WMR24 JSON → DiffPlanner JSON
│ ├── convert_json_to_pickle.py # HouseGAN++ JSON → pickle
│ ├── convert_json_to_npz.py # HouseGAN++ JSON → NPZ
│ ├── convert_png_to_iplan_mat.py # RPLAN PNG → iPLAN .mat (parallel)
│ ├── visualize_rplan_json.py # RPLAN JSON visualization
│ └── visualize_diffplanner.py # DiffPlanner panel renderer (GT/pred)
│
└── eval_results_*/ # Output directories (per experiment)
├── results.npz # All metric arrays + summary dicts
├── results.txt # Human-readable summary
├── fig/ # Comparison images (if --save_graphs)
└── generations*.pkl # Cached generations (if --save_generations)