Paper · 2023-02-06 · cs.LG
Beyond Statistical Similarity: Rethinking Metrics for Deep Generative Models in Engineering Design
A review and practical guide to metrics for deep generative models in engineering design. It groups metrics into similarity, novelty and diversity, constraints, performance and target achievement, and conditioning. On 2-D toys, similarity alone can rank models wrongly. Two case studies show the metrics. Author-reported; the repo holds the 2-D code only.
Generative model evaluationGenerative adversarial network (GAN)Variational autoencoderDiffusion modelsevaluation-metricsgenerative-modelsengineering-designmulti-objective-optimizationtopology-optimization
arXivPDFCodeMarkdown21 min read
AI-compiled by claude-haiku-5-5 on 2026-10-31, not yet reviewed by a human. Every claim cites its source; check it when a detail matters.
In plain words
Generative AI can propose new designs, such as a bicycle frame or a structural part. The usual way to score such a model is to ask whether its outputs look like the designs it was trained on. This paper argues that this is not enough for engineering. A design also has to obey rules, hit performance goals, be different from what already exists, and respond correctly to the requirements it was given.
The paper is a guide to scores for those other goals. It sorts them into five groups and explains when each one is useful. It also shows, on simple made-up 2-D examples, how a score for looking like the training data can point the wrong way. Then it runs the scores on two real problems: bicycle frames and structural topologies.
The authors released their code for the metrics and the 2-D examples. The data and models for the two real problems are not in that code. Use the paper to pick the right kind of score, and use the code to see exactly how each score is computed.
TL;DR
This is a review and practical guide, not a new generative model. It sorts evaluation metrics for deep generative models in engineering design into similarity, novelty and diversity, constraint satisfaction, performance and target achievement, and conditioning §1. It argues that similarity alone can lead to poor design choices §1§11.1 and shows this on 2-D examples and two case studies §4.5§9.4§10.4. The authors' repository implements most of the metrics and the 2-D experiments. The case-study data and the TopoDiff model are not in it load_data.py.
Problem
Deep generative models are usually scored by distribution matching, such as FID or perplexity in image and text generation. Those scores assume that a good model reproduces the training distribution §4. In design, the goals also include constraint satisfaction, functional performance, novelty and conditioning, and similarity scores do not measure these §1§11.1. The paper's example is two bicycle frames that look alike by most distance measures but whose deflections differ by more than two orders of magnitude fig. 1.
Image-based similarity scores rely on pretrained networks trained on natural images, so they are biased toward those datasets §4. Using them on structural designs needs a check §4.
Assumptions: the metrics are meant for any DGM used in design and do not depend on the architecture §1. Many of them need a distance on the design space or on the performance space. The paper leaves that choice to the practitioner §3.2 and gives distance options in app. 14.2.
Method
The paper has no single training procedure. Its contributions are the review and guide §1, a catalogue of metrics with their requirements and properties tab. 1, worked 2-D examples for each facet §4.5§5.3§6.4§7.3§8.4, two case studies §9§10, and a code release app. 14.5. The paper states most metric definitions in words. The only formulas it writes out are the two divergence families eq. 1eq. 2.
Divergence families, with P and Q distributions on a space M and P << Q §4:
D_\phi(\mathbb{P},\mathbb{Q}) = \int_M \phi\Big(\frac{d\mathbb{P}}{d\mathbb{Q}}\Big)\, d\mathbb{Q} eq. 1
with φ convex and φ(1) = 0; KL divergence is φ(t) = t log t §4.
D_\mathcal{F}(\mathbb{P},\mathbb{Q}) = \sup_{f\in\mathcal{F}} \Big\vert \int_M f\,d\mathbb{P} - \int_M f\,d\mathbb{Q} \Big\vert eq. 2
with F the RKHS unit ball for MMD §4. The paper says statistical divergences are hard to estimate in high dimensions and rarely domain-agnostic §4.
Where the paper gives no formula, the procedures below follow the authors' code and are marked (code). Each block says where the code is.
Metric catalogue
The metric catalogue is in tab. 1. Columns follow the paper. Where a row disagrees with the code or with the text, see Paper vs code.
| Category | Metric | Requirements / eval cost | Point / Set | Unary / Binary | Space | Hyperparameters | Bounds | Direction |
|---|---|---|---|---|---|---|---|---|
| Similarity | Statistical distance / divergence | Depends | Set | Binary | Either | Depends | [0, ∞) | Minimize |
| Similarity | Precision-recall curves | Emb**, CL | Set | Binary | Either | Yes | N/A | N/A |
| Similarity | Precision (F_β<<1) | Emb**, CL | Set | Binary | Either | Yes | [0, 1] | Maximize |
| Similarity | Nearest datapoint* | Dist | Point | Binary | Either | No | [0, ∞) | Minimize |
| Similarity | Recall (F_β>>1) | Emb**, CL | Set | Binary | Either | Yes | [0, 1] | Maximize |
| Similarity | Nearest generated sample* | Dist | Set | Binary | Either | Yes | [0, ∞) | Minimize |
| Similarity | Rediscovery* | Dist | Set | Binary | Either | Yes | [0, ∞) | Minimize |
| Similarity | ML efficacy | Aux | Set | Binary | Either | Yes | Varies | Varies |
| Novelty & diversity | Inter-sample distance* | Dist | Point | Unary | Either | No | [0, ∞) | Maximize |
| Novelty & diversity | Nearest datapoint* | Dist | Point | Binary | Either | No | [0, ∞) | Maximize |
| Novelty & diversity | Distance to centroid* | Emb | Point | Unary | Either | No | [0, ∞) | Maximize |
| Novelty & diversity | Entropy | Depends | Set | Unary | Either | Depends | [0, ∞) | Minimize (as printed) |
| Novelty & diversity | DPP diversity score | Dist | Set | Unary | Either | Yes | [0, ∞) | Minimize |
| Novelty & diversity | Smallest enclosing hypersphere | Emb | Set | Unary | Either | No | [0, ∞) | Maximize |
| Novelty & diversity | Convex hull | Emb | Set | Unary | Either | No | [0, ∞) | Maximize |
| Constraints | Constraint satisfaction | Const | Point | Unary | N/A | No | [0, 1] | Maximize |
| Constraints | Constraint satisfaction rate | Const | Point | Unary | N/A | No | [0, 1] | Maximize |
| Constraints | Signed distance to constraint boundary* | CFC | Point | Unary | Design | No | (-∞, ∞) | Maximize |
| Constraints | Predicted constraint satisfaction | Inv, Aux | Point | Binary | Design | Yes | [0, 1] | Maximize |
| Constraints | Nearest invalid datapoint* | Inv, Dist | Point | Binary | Design | No | [0, ∞) | Maximize |
| Performance & target | Hypervolume | Perf | Set | Unary | Perf. | No | [0, k] | Maximize |
| Performance & target | Target achievement | Perf | Point | Unary | Perf. | No | [0, 1] | Maximize |
| Performance & target | Target achievement rate | Perf | Point | Unary | Perf. | No | [0, 1] | Maximize |
| Performance & target | Signed distance to target* | Perf | Point | Unary | Perf. | No | (-∞, ∞) | Maximize |
| Performance & target | Design target achievement index (DTAI) | Perf | Point | Unary | Perf. | No | [0, 1] | Maximize |
| Performance & target | Generational distance* | Perf | Point | Binary | Perf. | No | [0, ∞) | Minimize |
| Performance & target | Instantaneous / cumulative optimality gap* | DP | Point | Unary | Perf. | Yes | [0, ∞) | Minimize |
| Conditioning | Conditioning adherence* | Cond | Point | Unary | Either | No | [0, ∞) | Minimize |
| Conditioning | Conditioning reconstruction | Aux | Point | Binary | Either | Yes | [0, ∞) | Minimize |
tab. 1 Notes from the paper: * assumes an L2 (Euclidean) distance kernel; ** clustering may replace a full embedding; problem parameters such as reference sets, objective weights and DTAI priorities are not hyperparameters tab. 1. Bounds are normalised here from the printed table.
Nearest-neighbour and coverage scores (code)
Realism, coverage, novelty and invalid-sample scores all reduce to distances
from one set of points to another §3.2app. 14.2. The code computes Euclidean
distances with scipy cdist evaluation.py. The code uses
Euclidean distance only and raises on anything else evaluation.py.
# Nearest datapoint per sample: realism [§4.2] or novelty [§5.1]
# [code: evaluation.py#L149-L173]
def nearest_datapoint(samples, dataset):
# Distances, shape (num_samples, num_data) [code: evaluation.py#L60]
distances = pairwise_l2(samples, dataset)
# Smallest distance per sample [code: evaluation.py#L166-L167]
per_sample = minimum(distances, axis=1)
# Reported score is the mean over samples [code: evaluation.py#L172]
return per_sample, mean(per_sample)# Nearest generated sample per datapoint: coverage [§4.3]
# [code: evaluation.py#L175-L199]
def nearest_generated_sample(samples, dataset):
# Distances from each dataset point to each generated sample
distances = pairwise_l2(dataset, samples) # (num_data, num_samples)
# Smallest distance per dataset point [code: evaluation.py#L192-L193]
per_datapoint = minimum(distances, axis=1)
# The code returns the mean of these values [code: evaluation.py#L198]
return None, mean(per_datapoint)# Inter-sample distance: distance to nearest other sample [§5.1]
# [code: evaluation.py#L87-L108]
def inter_sample_distance(samples):
# Pairwise distances between generated samples
distances = pairwise_l2(samples, samples)
# Remove self-distance by setting the diagonal to the maximum
# [code: evaluation.py#L100]
fill_diagonal(distances, max(distances))
# Nearest other sample per sample [code: evaluation.py#L102]
per_sample = minimum(distances, axis=1)
return per_sample, mean(per_sample)# Distance to centroid: spread of the generated set [§5.1]
# [code: evaluation.py#L110-L126]
def distance_to_centroid(samples):
# Centroid is the mean of the generated set [code: evaluation.py#L122]
centroid = mean(samples, axis=0)
# Euclidean norm of each sample's offset [code: evaluation.py#L123-L124]
distance = norm(samples - centroid, axis=1)
return distance, mean(distance)# Nearest invalid datapoint: approximate constraint distance [§6.3]
# [code: evaluation.py#L245-L257]
def nearest_invalid(samples, invalid_points):
# Smallest distance from each sample to any known invalid point
distances = pairwise_l2(samples, invalid_points)
per_sample = minimum(distances, axis=1)
return per_sample, mean(per_sample)Distribution matching: precision, recall, F-beta and AUC (code)
The paper uses the precision-recall curve of Sajjadi et al. §4.1. It pools the generated and reference points, clusters them, and sweeps a weight to trace a curve. The summaries are the maximum F-beta and the area under the curve §4.1§4.2§4.3. The code follows this pattern.
# Precision-recall curve, averaged over repeated clusterings [§4.1]
# [code: eval_prd.py#L93-L141]
def prd_curve(generated, reference, num_clusters=20, num_runs=5):
precisions = []
recalls = []
for run in range(num_runs):
# K-means on pooled points, n_init=10, no seed [code: eval_prd.py#L80]
# Histogram of each set over the clusters [code: eval_prd.py#L64-L92]
gen_bins, ref_bins = cluster_bins(generated, reference, num_clusters)
# Equiangular grid of 1001 angles in (0, pi/2); slope = tan(angle)
# [code: eval_prd.py#L39-L41]
slopes = tan(linspace(1e-10, pi / 2 - 1e-10, num=1001))
# precision = sum_k min(slope * ref_k, gen_k)
# [code: eval_prd.py#L51]
precision = sum_over_clusters(minimum(slopes * ref_bins, gen_bins))
# recall = precision / slope [code: eval_prd.py#L52]
recall = precision / slopes
precisions.append(precision)
recalls.append(recall)
# Average the curves over runs [code: eval_prd.py#L139-L141]
return mean(precisions, axis=0), mean(recalls, axis=0)# Maximum F-beta over the curve (F0.1, F1, F10 in the paper) [§4.2][§4.3]
# [code: evaluation.py#L313-L336]
def max_f_beta(precision, recall, beta):
# F_beta = (1 + beta^2) p r / (beta^2 p + r + eps)
# [code: eval_prd.py#L170-L171]
f = (1 + beta ** 2) * precision * recall
f = f / (beta ** 2 * precision + recall + 1e-10)
# Score: maximum over the curve [code: evaluation.py#L336]
return maximum(f)# Area under the precision-recall curve [§4.1] [code: evaluation.py#L365-L369]
def prd_auc(precision, recall):
total = 0
for i in range(len(precision) - 1):
# Trapezoid, angle order, no sorting [code: evaluation.py#L366-L367]
width = recall[i + 1] - recall[i]
total += (precision[i] + precision[i + 1]) / 2 * width
return totalMaximum mean discrepancy (code)
MMD is the only kernel IPM in the code §4.1eq. 2. Its settings are not in the paper. The code uses random subsamples and the biased estimator.
# Maximum mean discrepancy, Gaussian kernel [§4.1][eq. 2]
# [code: evaluation.py#L259-L311]
def mmd(samples, dataset, sigma=1, batch_size=1000, num_iter=100):
# gamma = 1 / (2 sigma^2) [code: evaluation.py#L284]
gamma = 1 / (2 * sigma ** 2)
estimates = []
for it in range(num_iter):
# Random subsample, at most batch_size [code: evaluation.py#L275-L283]
x = subsample(samples, batch_size)
y = subsample(dataset, batch_size)
# Kernel matrices K(x,x), K(y,y), K(x,y) with exp(-gamma * sq. distance)
# [code: evaluation.py#L286-L298]
k_xx = exp(-gamma * squared_distances(x, x))
k_yy = exp(-gamma * squared_distances(y, y))
k_xy = exp(-gamma * squared_distances(x, y))
# Biased estimator (default) [code: evaluation.py#L300-L301]
estimates.append(mean(k_xx) + mean(k_yy) - 2 * mean(k_xy))
return mean(estimates)Diversity: DPP score (code)
The paper describes the DPP score as a volume of a kernel matrix built on pairwise distances §5.2. The code builds the kernel as follows.
# DPP diversity, lower is more diverse [§5.2] [code: evaluation.py#L128-L146]
def dpp_diversity(samples):
# Squared distances D, shape (N, N) [code: evaluation.py#L138-L139]
squared = pairwise_squared_l2(samples)
# Kernel exp(-0.5 * D^2): D is squared already, so this is the 4th power
# of the distance [code: evaluation.py#L140]
kernel = exp(-0.5 * squared ** 2)
# Eigenvalues of the kernel [code: evaluation.py#L141-L144]
try:
eigenvalues = eigvalsh(kernel)
except:
eigenvalues = ones(N)
# Mean -log eigenvalue, floored at 1e-7 [code: evaluation.py#L145]
return -mean(log(maximum(eigenvalues, 1e-7)))Target achievement and performance (code)
# Design target achievement index (DTAI), normalised to [0, 1] [§7.2]
# [code: evaluation.py#L201-L225]
def dtai(objectives, targets, p, a, eps=1e-7):
# Floor objectives at eps [code: evaluation.py#L203]
objectives = maximum(objectives, eps)
# Ratio to target (maximise case) [code: evaluation.py#L207-L208]
ratio = objectives / targets
# Below target: linear penalty p * (x - 1) [code: evaluation.py#L213]
penalty = p * ratio - p
# Above target: decaying reward (p / a) (1 - exp(a (1 - x)))
# [code: evaluation.py#L214-L216]
reward = (p / a) * (1 - exp(a * (1 - ratio)))
# Pick the branch per objective [code: evaluation.py#L217-L218]
per_objective = where(ratio > 1, reward, penalty)
# Sum over objectives [code: evaluation.py#L219]
total = sum(per_objective, axis=1)
# Rescale with smin = -sum(p), smax = sum(p / a)
# [code: evaluation.py#L220-L223]
s_min = -sum(p)
s_max = sum(p / a)
return (total - s_min) / (s_max - s_min)# Weighted target achievement rate [§7.2] [code: evaluation.py#L227-L243]
def weighted_target_rate(objectives, targets, p):
# 1 where objective beats target [code: evaluation.py#L235]
met = (objectives > targets).astype(float)
# Weighted share of targets met [code: evaluation.py#L241]
return dot(met, p) / sum(p)# Signed distance to target, linear form [§7.2] [code: evaluation.py#L62-L85]
def signed_distance_to_target(objectives, targets, p):
# Difference to target [code: evaluation.py#L65]
diff = objectives - targets
# Scale by p [code: evaluation.py#L77]
scaled = diff * p
# Margin when every target is met: the smallest scaled gain
# [code: evaluation.py#L81-L82]
margin = min(scaled, axis=1)
all_met = all(diff > 0, axis=1)
# Otherwise: norm of the scaled shortfalls [code: evaluation.py#L78-L80]
shortfall = norm(minimum(scaled, 0), axis=1)
return all_met * margin - shortfall# Hypervolume of the generated objective vectors [§7.1]
# [code: evaluation.py#L14-L24]
def hypervolume(objectives, ref=None):
# Default reference: the 0.99 quantile of the generated objectives
# [code: evaluation.py#L19-L21]
if ref is None:
ref = quantile(objectives, 0.99, axis=0)
# Dominated volume, via pymoo's HV indicator [code: evaluation.py#L22-L23]
return hv_indicator(ref_point=ref)(objectives)Constraints and conditioning (code)
# Predicted constraint satisfaction via k-NN [§6.3]
# [code: evaluation.py#L404-L413]
def predicted_constraint_satisfaction(samples, valid, invalid, clf):
# Valid = 1, invalid = 0 [code: evaluation.py#L408-L409]
x_all = concatenate(valid, invalid)
y_all = concatenate(ones(len(valid)), zeros(len(invalid)))
# Fit the classifier (notebook: k-NN, k=5) [code: evaluation.py#L410]
clf.fit(x_all, y_all)
# Probability of being valid, per sample; the score is its mean
# [code: evaluation.py#L411-L412]
return clf.predict_proba(samples)[:, 1]# Conditioning adherence: recompute the condition on samples [§8.1]
# [code: utils.py#L427-L430]
def conditioning_adherence(samples, cond_func, condition):
# Recompute the condition from the generated designs
recomputed = cond_func(samples)
# Mean squared error to the requested condition (paper: MSE)
return mean((recomputed - condition) ** 2)MO-PaDGAN training objective (code)
The paper uses MO-PaDGAN in its experiments §9.2app. 14.3. It is not specified in the paper beyond "performance-weighted DPP kernel" §9.2. The training code is below.
# Quality per sample: random-weight scalarisation
# [code: Padgan_variants.py#L246-L258]
def evaluate_mo(objectives):
# Uniform random weight per objective, normalised per sample
# [code: Padgan_variants.py#L252-L255]
weights = uniform(shape=objectives.shape)
weights = weights / sum(weights, axis=1, keepdims=True)
# Weighted sum per sample [code: Padgan_variants.py#L256-L257]
return sum(objectives * weights, axis=1)# Diversity term in the generator loss [code: Padgan_variants.py#L89-L125]
def diversity_loss(samples, quality, lambda0):
# Squared pairwise distances and kernel [code: Padgan_variants.py#L92-L93]
squared = pairwise_squared_l2(samples)
kernel = exp(-0.5 * squared ** 2)
# Quality-weighted kernel S * Q^lambda0, with Q = y y^T
# [code: Padgan_variants.py#L113-L117]
q_outer = outer(quality, quality)
weighted = kernel * q_outer ** lambda0
# Clamp entries at most 1e-5 (minimum) [code: Padgan_variants.py#L118]
clamped = minimum(weighted, 1e-5)
# Mean log-eigenvalue, floored at 1e-5 [code: Padgan_variants.py#L119-L123]
try:
eigenvalues = eigvalsh(clamped)
except:
eigenvalues = ones(N)
return -mean(log(maximum(eigenvalues, 1e-5)))# Generator loss: adversarial loss plus weighted diversity term
# [code: Padgan_variants.py#L170-L176]
def generator_loss(adversarial_loss, samples, lambda0, lambda1):
# Quality from a regressor that predicts the objectives, inverse-scaled
# [code: Padgan_variants.py#L265-L271][code: Padgan_variants.py#L173-L175]
quality = evaluate_mo(predict_objectives(samples))
# Diversity term [code: Padgan_variants.py#L176]
dpp = diversity_loss(samples, quality, lambda0)
# lambda1 = 0 disables it [code: Padgan_variants.py#L173-L180]
return adversarial_loss + lambda1 * dppHyperparameters
Appendix sections are cited by their LaTeX section number, because the paper's appendix is not lettered. Section 14 is the appendix app. 14.x. Paper values come from the appendix. Code values come from the notebook that runs the 2-D experiments 3. Paper Results.ipynb.
2-D synthetic experiments
| Name | Value | Where | Notes |
|---|---|---|---|
| Data | Six modes; 10,000 samples; 0 negatives | app. 14.3 3. Paper Results.ipynb | Paper states six modes; sample count is code-only |
| Generated samples per model | 1000 | 3. Paper Results.ipynb | Not stated in paper |
| Instances per model | 1 | 3. Paper Results.ipynb | Not stated in paper; one run per model |
| Scaling before metrics | StandardScaler on data | 3. Paper Results.ipynb | Not stated in paper; distances use scaled space |
| GAN / cGAN networks | 2 hidden layers, 100 units, LeakyReLU α=0.2 | app. 14.3 Padgan_variants.py | Paper says "100 parameters"; code uses 100 units per layer |
| Latent dimension | 4 | app. 14.3 3. Paper Results.ipynb | |
| Latent noise | Normal, stddev 0.5 | Padgan_variants.py | Not stated in paper |
| Optimiser | Adam, lr 1e-3, β1 = 0.5 | app. 14.3 Padgan_variants.py | Paper gives lr only |
| GAN training steps | 5000 | app. 14.3 3. Paper Results.ipynb | Paper: "5000 randomized batches" |
| GAN batch size | Paper: 32; code: 128 | app. 14.3 3. Paper Results.ipynb | See Paper vs code |
| VAE encoder and decoder | 3 hidden layers, 100 units, ReLU | app. 14.3 VAEs.py | |
| VAE latent dimension | 4 | app. 14.3 3. Paper Results.ipynb | |
| VAE training | 1000 steps, batch 128, lr 1e-3, KL weight 0.05 | 3. Paper Results.ipynb | Paper: "1000 epochs of batches of 100" |
| MO-PaDGAN λ0 (quality exponent) | 5 | app. 14.3 3. Paper Results.ipynb | Matches |
| MO-PaDGAN λ1 (diversity weight) | 2 | app. 14.3 3. Paper Results.ipynb | Matches |
| MO-PaDGAN batch, steps | 128, 5000 | 3. Paper Results.ipynb | Paper's batch size is 32 |
| Quality regressor | Dropout 0.1, 2 layers, 100 units, LeakyReLU, lr 1e-4, batch 32, 100 epochs, patience 30 | 3. Paper Results.ipynb | Paper does not state these |
| k for k-NN | 5 | app. 14.3 3. Paper Results.ipynb | Matches |
| PRD clusters | 20 | app. 14.3 evaluation.py | Matches |
| PRD angle grid | 1000 | app. 14.3 eval_prd.py | Code uses 1001 |
| PRD clustering runs | 10 | app. 14.3 evaluation.py | Code uses 5 |
| DPP subset size | 10 | app. 14.3 evaluation.py | Parameter exists but is unused |
| DPP exponent | 0.1 | app. 14.3 | Not in code |
| Hypervolume reference | 99th quantile of dataset performance | app. 14.3 | Code uses generated set |
| Target (2-D) | (0.5, 0.5), equal weights | app. 14.3 3. Paper Results.ipynb | Matches |
| DTAI α, β (2-D) | α = β = [1, 1] | app. 14.3 3. Paper Results.ipynb | Matches |
| Pareto reference (KNO1) | Line x + y = 0.4705, 1000 points | app. 14.3 3. Paper Results.ipynb | Matches |
| Conditioning value | 0.3 | 3. Paper Results.ipynb | Not stated in paper |
| Conditional reference | Nearest 10% of data by condition | app. 14.3 utils.py | Matches |
Bicycle frame case study (paper only)
The bicycle experiment code is not in the repository. Its data loader points to CSV files that are not in the repository load_data.py.
| Name | Value | Where | Notes |
|---|---|---|---|
| Target | 0.75 quantile of each objective in FRAMED | app. 14.4 Padgan_variants.py | Code's auto path uses the same rule |
| DTAI α | [1, 1, 1, 1, 2, 1, 1, 4, 4, 3] | app. 14.4 | Mapping to code arguments not stated |
| DTAI β | [4, 4, 4, 4, 4, 4, 4, 4, 4, 2] | app. 14.4 | Mapping to code arguments not stated |
| γ0, γ1 | 5, 0.5 | app. 14.4 | Code not in repository |
| Training | 50000 batches of 8; lr 1e-4 | app. 14.4 | |
| Networks | 2 (GAN) and 3 (PaDGAN) hidden layers, 128 units | app. 14.4 | |
| Latent | 4 | app. 14.4 | |
| Metric settings | F1: 20 clusters, 1000 angles, 10 runs; DPP subset 10, exponent 0.1 | app. 14.4 | |
| Quality and constraint surrogates | Best nets from Bayesian optimisation in the FRAMED work | app. 14.4 | Not in repository |
| Dataset | About 4000 valid and 300 invalid designs, 37 variables, 10 performance values | §9.1 | Not in repository |
Topology case study (paper only)
| Name | Value | Where | Notes |
|---|---|---|---|
| Conditions | First 300 conditions of TopoDiff level-1 test data | §10.4 | |
| Diffusion steps | 100 | §10.4 | |
| Samples per condition | 10 | §10.4 | Paper uses 1 in prior work |
| Inference time | Taken from the cited source | §10.4 | Not recomputed |
Results
Author-reported throughout. The paper gives single numbers with no variance or repeat runs §4.5§5.3§6.4§7.3§8.4. Its hardware is not stated.
2-D experiments
Setup: six-mode 2-D data; one VAE and one GAN §4.5. The paper cautions that these results may not carry over to other datasets or architectures §4.5.
tab. 2 Distribution-matching scores; point metrics averaged over samples; bold is better.
| Metrics | VAE | GAN |
|---|---|---|
| Nearest datapoint | 0.043 | 0.018 |
| Nearest generated sample | 0.090 | 0.100 |
| Rediscovery | 0.093 | 0.099 |
| Precision-recall curve F1 | 0.475 | 0.386 |
| Precision-recall curve F10 | 0.907 | 0.934 |
| Precision-recall curve F0.1 | 0.804 | 0.753 |
| Precision-recall curve AUC | 0.468 | 0.379 |
| Maximum mean discrepancy | 0.045 | 0.013 |
| Machine learning efficacy | 0.675 | 0.765 |
tab. 3 Diversity and novelty scores, same models; bold is better.
| Metrics | VAE | GAN |
|---|---|---|
| Nearest datapoint | 0.043 | 0.018 |
| Inter-sample distance | 0.030 | 0.019 |
| Convex hull | 5.651 | 7.173 |
| DPP diversity | 14.398 | 14.688 |
| Distance to centroid | 1.120 | 1.391 |
tab. 4 Constraint adherence, same models; bold is better.
| Metrics | VAE | GAN |
|---|---|---|
| Constraint satisfaction | 0.713 | 0.833 |
| Constraint satisfaction rate | 0.857 | 0.917 |
| Predicted constraint satisfaction | 0.698 | 0.823 |
| Nearest invalid datapoint | 0.17 | 0.173 |
tab. 5 Performance and target achievement, GAN vs MO-PaDGAN on KNO1; bold is better as printed. See Paper vs code for the generational distance row.
| Metrics | GAN | MO-PaDGAN |
|---|---|---|
| Hypervolume | 0.460 | 0.571 |
| Generational distance | 0.215 | 0.315 |
| Weighted target achievement rate | 0.162 | 0.430 |
| Signed distance to target | -0.275 | -0.154 |
| Design target achievement index | 0.324 | 0.433 |
tab. 6 Conditioning, cVAE vs cGAN; conditional and marginal reference sets; bold is better.
| Metrics | cVAE | cGAN |
|---|---|---|
| Conditioning reconstruction | 0.007 | 0.026 |
| Conditioning adherence | 0.008 | 0.026 |
| Conditional F10 | 0.909 | 0.826 |
| Conditional F0.1 | 0.879 | 0.960 |
| Conditional MMD | 0.035 | 0.021 |
| Marginal F10 | 0.949 | 0.933 |
| Marginal F0.1 | 0.447 | 0.554 |
| Marginal MMD | 0.068 | 0.097 |
Bicycle frame design (narrative only)
Three GANs: vanilla GAN, MO-PaDGAN and DTAI-GAN §9.2. The paper reports results as figure panels, not as a table fig. 11. In the text, DTAI-GAN scores highest on all performance and target-achievement metrics, and the vanilla GAN scores lowest §9.4. The vanilla GAN has the best distribution matching. DTAI-GAN sits further from the dataset than MO-PaDGAN, with a slight edge on nearest datapoint §9.4. DTAI-GAN's average target success rate is only slightly above MO-PaDGAN's, but its signed distance to target is much higher §9.4.
Topology optimisation (TopoDiff)
tab. 7 Two TopoDiff variants, first 300 conditions of level-1 test data; bold is better as printed.
| Metric | TopoDiff, FEA fields | TopoDiff, kernel fields |
|---|---|---|
| Median compliance error (distance to target boundary) | 1.99% | 9.61% |
| Mean volume fraction error (conditioning adherence) | 1.49% | 1.69% |
| Mean load validity (binary constraint satisfaction 1) | 0.00% | 0.13% |
| Mean floating material (binary constraint satisfaction 2) | 6.60% | 8.97% |
| Mean floating material quantity (distance to constraint boundary 2) | 0.022% | 0.031% |
| Mean distance to SIMP (mean novelty) | 11.6% | 17.3% |
| Topology diversity (diversity) | 7.144 | 5.87 |
| Mean inference time (sec.) | 5.87 | 2.35 |
Paper vs code
The code is in raw/code/2302.02913 at dd4b81f, MIT licence, owned by author
Lyle Regenwetter LICENSE. It covers the 2-D experiments and the
metrics. It does not contain the bicycle or topology experiments load_data.py.
- Generational distance direction. The text says MO-PaDGAN is closer to the
reference front, which means lower generational distance §7.3, and
Table 1 says minimise tab. 1. Table 5 bolds 0.315 for MO-PaDGAN, which is
the higher number tab. 5. The printed table contradicts itself. The code
defines GD with pymoo's
GDevaluation.py. Check values before use. - Hypervolume reference point. Paper: 99th quantile of dataset performance app. 14.3. Code: 0.99 quantile of the generated set, recomputed for each model evaluation.py. The 2-D notebook calls the default 3. Paper Results.ipynb. This differs from the paper.
- PRD clustering runs. Paper: 10 app. 14.3. Code:
F_wrapperandAUC_wrapperdefault to 5 and pass it on evaluation.py[code: evaluation.py#L339]. Thecompute_prd_from_embeddingdefault of 10 is overridden eval_prd.py. The notebook uses the defaults [code: 3. Paper Results.ipynb#L346-L349]. - PRD angle grid. Paper: 1000 app. 14.3. Code: 1001 angles [code: evaluation.py#L313]eval_prd.py. A grid of 1000 is not what the code uses. The difference is small.
- GAN batch size. Paper: 5000 batches of 32 app. 14.3. Notebook: batch size 128 3. Paper Results.ipynb.
- VAE training length. Paper: 1000 epochs of batches of 100 app. 14.3. Code: 1000 random minibatch steps of 128, not epochs [code: 3. Paper Results.ipynb#L335]VAEs.py.
- DPP settings. Paper: subset size 10 and exponent 0.1 app. 14.3. Code:
DPP_diversity_wrapperacceptssubset_size=10but never uses it, and has no exponent evaluation.py. - Metrics not implemented. Entropy, smallest enclosing hypersphere,
optimality gap and all-targets target achievement are in tab. 1 but not in
evaluation.py. TheTarget achievement rateis implemented as the weighted form evaluation.py. - Bicycle DTAI arguments. The notebook calls
DTAI_wrapper(direction, target, a_, p_)3. Paper Results.ipynb. The function signature is(direction, ref, p_, a_)evaluation.py. The arguments are swapped. With both set to ones in the 2-D experiment, the effect is nil. For the bicycle experiment the paper's α and β values could be applied in the wrong slots. The paper does not say how its α and β map to code arguments app. 14.4. - Bicycle and topology code. The paper says it releases "the code for the datasets, models, and metrics used throughout the paper" [abstract]. The repository has the 2-D code and metrics only. The FRAMED CSV files are read from the working directory load_data.py but are not committed. TopoDiff is an external model §10.3.
- Matches. k = 5 for k-NN app. 14.3. Target (0.5, 0.5) and KNO1 Pareto line app. 14.3. MO-PaDGAN λ0 = 5 and λ1 = 2 app. 14.3. Latent dimension 4. Adam learning rate 1e-3 for the 2-D models. ML efficacy uses R² app. 14.3.
Pitfalls
- Bugs in the training path.
train_padgancallsevaluation.DTAI_wrapper(ref, p_, a_)with three arguments, but the function needs four (direction, ref, p_, a_) Padgan_variants.py[code: evaluation.py#L201]. This path runs when DTAI is enabled. The 2-D notebooks do not enable it 3. Paper Results.ipynb. I read the code but did not execute it. - Clamp in the diversity kernel. The code uses
minimum(L, EPS)with a comment saying "for stability" Padgan_variants.py. Every kernel entry above 1e-5 becomes 1e-5, and the gradient through those entries is zero. The effect on training is not measured in the paper. Check before relying on MO-PaDGAN's diversity term. - Kernel on squared distance. Both the metric and the training loss compute
exp(-0.5 * D^2)whereDis already squared distance, so the kernel depends on the fourth power of distance evaluation.py[code: Padgan_variants.py#L92-L93]. The paper gives no kernel formula §5.2. - Unguarded convex hull.
ConvexHull(x)has no guard for degenerate input evaluation.py. Fewer than d + 1 points, or collinear points, will typically make scipy's Qhull raise an error. I did not run this case. The paper warns that the hull assumes convexity and is sensitive to outliers §5.2. allbranch of nearest generated sample. Withflag="all", the code assigns toy_evaland then uses an undefinedxevaluation.py. The notebooks use"x"3. Paper Results.ipynb.- Hypervolume depends on the model's own samples. The default reference point is recomputed from each model's output evaluation.py. Hypervolumes of different models use different reference points. Use a fixed reference when comparing models.
- Direction of Entropy. Table 1 says minimise tab. 1. Entropy is a diversity score §5.2, so maximising is the natural reading. Confirm against the source before use. The code has no entropy.
- Nearest datapoint has two directions. The same metric is minimised for realism and maximised for novelty tab. 1§5.1. Pick the direction for the question you ask.
- AUC sign. The code integrates in angle order evaluation.py. As angle increases, recall falls eval_prd.py, so the trapezoid sum may come out negative. The paper reports positive AUCs tab. 2. I read this but did not run the code, so check the sign before using AUC values.
- Randomness is unseeded. K-means has no
random_stateeval_prd.py. MMD subsamples withnp.randomand no seed evaluation.py. Repeat runs will differ. The paper states no seed. - Scaled distances. The 2-D notebook scales the data before the metrics run, so distances are in standardised units 3. Paper Results.ipynb[code: utils.py#L406-L413]. The paper does not say this app. 14.2.
- Single instances. The 2-D notebook runs one instance per model 3. Paper Results.ipynb. Differences such as GAN vs VAE are not tested for significance.
- KNO1 inputs are scaled. The objectives divide the inputs by 4 and then
apply
a = 3 (a + 0.5)load_data.py. The paper does not state this. - Conditional reference. The conditional subset is the nearest 10% of the data by condition value, found with a quantile mask utils.py evaluation.py. With repeated condition values, the inclusive bounds can keep more than 10% of rows.
- Table 5 is not reliable as printed. See Paper vs code.
Lineage
- Builds on: MO-PaDGAN, Chen and Ahmed, Applied Soft Computing, cited as [chen2021mopadgan]. The 2-D training settings are the same except λ0 and λ1 app. 14.3. DTAI from Regenwetter and Ahmed, arXiv:2205.03005 §7.2.
- Compared against: GAN and VAE in 2-D §4.5§5.3§6.4; cGAN and cVAE for conditioning §8.4; GAN, MO-PaDGAN and DTAI-GAN on bicycle frames §9.2; two TopoDiff variants on topologies §10.3. TopoDiff is from Mazé and Ahmed [maze2022topodiff]. The kernel-field variant follows giannone2023diffusing §10.3.
- Superseded by: not stated.
Source and license
Adapted from “Beyond Statistical Similarity: Rethinking Metrics for Deep Generative Models in Engineering Design” by Lyle Regenwetter, Akash Srivastava, Dan Gutfreund, Faez Ahmed (arXiv:2302.02913), used under CC BY 4.0. Changes: condensed and restructured for implementation, with tables, equations and algorithms taken from the paper and its code, each cited to its source. Not affiliated with or endorsed by the authors. Code citations refer to https://github.com/Lyleregenwetter/DGM-Evaluation-Metrics at commit dd4b81fddb2e (MIT). Any quoted code is shown under that license.