wikillm

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.

CategoryMetricRequirements / eval costPoint / SetUnary / BinarySpaceHyperparametersBoundsDirection
SimilarityStatistical distance / divergenceDependsSetBinaryEitherDepends[0, ∞)Minimize
SimilarityPrecision-recall curvesEmb**, CLSetBinaryEitherYesN/AN/A
SimilarityPrecision (F_β<<1)Emb**, CLSetBinaryEitherYes[0, 1]Maximize
SimilarityNearest datapoint*DistPointBinaryEitherNo[0, ∞)Minimize
SimilarityRecall (F_β>>1)Emb**, CLSetBinaryEitherYes[0, 1]Maximize
SimilarityNearest generated sample*DistSetBinaryEitherYes[0, ∞)Minimize
SimilarityRediscovery*DistSetBinaryEitherYes[0, ∞)Minimize
SimilarityML efficacyAuxSetBinaryEitherYesVariesVaries
Novelty & diversityInter-sample distance*DistPointUnaryEitherNo[0, ∞)Maximize
Novelty & diversityNearest datapoint*DistPointBinaryEitherNo[0, ∞)Maximize
Novelty & diversityDistance to centroid*EmbPointUnaryEitherNo[0, ∞)Maximize
Novelty & diversityEntropyDependsSetUnaryEitherDepends[0, ∞)Minimize (as printed)
Novelty & diversityDPP diversity scoreDistSetUnaryEitherYes[0, ∞)Minimize
Novelty & diversitySmallest enclosing hypersphereEmbSetUnaryEitherNo[0, ∞)Maximize
Novelty & diversityConvex hullEmbSetUnaryEitherNo[0, ∞)Maximize
ConstraintsConstraint satisfactionConstPointUnaryN/ANo[0, 1]Maximize
ConstraintsConstraint satisfaction rateConstPointUnaryN/ANo[0, 1]Maximize
ConstraintsSigned distance to constraint boundary*CFCPointUnaryDesignNo(-∞, ∞)Maximize
ConstraintsPredicted constraint satisfactionInv, AuxPointBinaryDesignYes[0, 1]Maximize
ConstraintsNearest invalid datapoint*Inv, DistPointBinaryDesignNo[0, ∞)Maximize
Performance & targetHypervolumePerfSetUnaryPerf.No[0, k]Maximize
Performance & targetTarget achievementPerfPointUnaryPerf.No[0, 1]Maximize
Performance & targetTarget achievement ratePerfPointUnaryPerf.No[0, 1]Maximize
Performance & targetSigned distance to target*PerfPointUnaryPerf.No(-∞, ∞)Maximize
Performance & targetDesign target achievement index (DTAI)PerfPointUnaryPerf.No[0, 1]Maximize
Performance & targetGenerational distance*PerfPointBinaryPerf.No[0, ∞)Minimize
Performance & targetInstantaneous / cumulative optimality gap*DPPointUnaryPerf.Yes[0, ∞)Minimize
ConditioningConditioning adherence*CondPointUnaryEitherNo[0, ∞)Minimize
ConditioningConditioning reconstructionAuxPointBinaryEitherYes[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.

Pseudocode
# 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)
Pseudocode
# 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)
Pseudocode
# 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)
Pseudocode
# 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)
Pseudocode
# 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.

Pseudocode
# 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)
Pseudocode
# 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)
Pseudocode
# 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 total

Maximum 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.

Pseudocode
# 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.

Pseudocode
# 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)

Pseudocode
# 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)
Pseudocode
# 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)
Pseudocode
# 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
Pseudocode
# 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)

Pseudocode
# 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]
Pseudocode
# 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.

Pseudocode
# 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)
Pseudocode
# 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)))
Pseudocode
# 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 * dpp

Hyperparameters

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

NameValueWhereNotes
DataSix modes; 10,000 samples; 0 negativesapp. 14.3 3. Paper Results.ipynbPaper states six modes; sample count is code-only
Generated samples per model10003. Paper Results.ipynbNot stated in paper
Instances per model13. Paper Results.ipynbNot stated in paper; one run per model
Scaling before metricsStandardScaler on data3. Paper Results.ipynbNot stated in paper; distances use scaled space
GAN / cGAN networks2 hidden layers, 100 units, LeakyReLU α=0.2app. 14.3 Padgan_variants.pyPaper says "100 parameters"; code uses 100 units per layer
Latent dimension4app. 14.3 3. Paper Results.ipynb
Latent noiseNormal, stddev 0.5Padgan_variants.pyNot stated in paper
OptimiserAdam, lr 1e-3, β1 = 0.5app. 14.3 Padgan_variants.pyPaper gives lr only
GAN training steps5000app. 14.3 3. Paper Results.ipynbPaper: "5000 randomized batches"
GAN batch sizePaper: 32; code: 128app. 14.3 3. Paper Results.ipynbSee Paper vs code
VAE encoder and decoder3 hidden layers, 100 units, ReLUapp. 14.3 VAEs.py
VAE latent dimension4app. 14.3 3. Paper Results.ipynb
VAE training1000 steps, batch 128, lr 1e-3, KL weight 0.053. Paper Results.ipynbPaper: "1000 epochs of batches of 100"
MO-PaDGAN λ0 (quality exponent)5app. 14.3 3. Paper Results.ipynbMatches
MO-PaDGAN λ1 (diversity weight)2app. 14.3 3. Paper Results.ipynbMatches
MO-PaDGAN batch, steps128, 50003. Paper Results.ipynbPaper's batch size is 32
Quality regressorDropout 0.1, 2 layers, 100 units, LeakyReLU, lr 1e-4, batch 32, 100 epochs, patience 303. Paper Results.ipynbPaper does not state these
k for k-NN5app. 14.3 3. Paper Results.ipynbMatches
PRD clusters20app. 14.3 evaluation.pyMatches
PRD angle grid1000app. 14.3 eval_prd.pyCode uses 1001
PRD clustering runs10app. 14.3 evaluation.pyCode uses 5
DPP subset size10app. 14.3 evaluation.pyParameter exists but is unused
DPP exponent0.1app. 14.3Not in code
Hypervolume reference99th quantile of dataset performanceapp. 14.3Code uses generated set
Target (2-D)(0.5, 0.5), equal weightsapp. 14.3 3. Paper Results.ipynbMatches
DTAI α, β (2-D)α = β = [1, 1]app. 14.3 3. Paper Results.ipynbMatches
Pareto reference (KNO1)Line x + y = 0.4705, 1000 pointsapp. 14.3 3. Paper Results.ipynbMatches
Conditioning value0.33. Paper Results.ipynbNot stated in paper
Conditional referenceNearest 10% of data by conditionapp. 14.3 utils.pyMatches

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.

NameValueWhereNotes
Target0.75 quantile of each objective in FRAMEDapp. 14.4 Padgan_variants.pyCode's auto path uses the same rule
DTAI α[1, 1, 1, 1, 2, 1, 1, 4, 4, 3]app. 14.4Mapping to code arguments not stated
DTAI β[4, 4, 4, 4, 4, 4, 4, 4, 4, 2]app. 14.4Mapping to code arguments not stated
γ0, γ15, 0.5app. 14.4Code not in repository
Training50000 batches of 8; lr 1e-4app. 14.4
Networks2 (GAN) and 3 (PaDGAN) hidden layers, 128 unitsapp. 14.4
Latent4app. 14.4
Metric settingsF1: 20 clusters, 1000 angles, 10 runs; DPP subset 10, exponent 0.1app. 14.4
Quality and constraint surrogatesBest nets from Bayesian optimisation in the FRAMED workapp. 14.4Not in repository
DatasetAbout 4000 valid and 300 invalid designs, 37 variables, 10 performance values§9.1Not in repository

Topology case study (paper only)

NameValueWhereNotes
ConditionsFirst 300 conditions of TopoDiff level-1 test data§10.4
Diffusion steps100§10.4
Samples per condition10§10.4Paper uses 1 in prior work
Inference timeTaken from the cited source§10.4Not 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.

MetricsVAEGAN
Nearest datapoint0.0430.018
Nearest generated sample0.0900.100
Rediscovery0.0930.099
Precision-recall curve F10.4750.386
Precision-recall curve F100.9070.934
Precision-recall curve F0.10.8040.753
Precision-recall curve AUC0.4680.379
Maximum mean discrepancy0.0450.013
Machine learning efficacy0.6750.765

tab. 3 Diversity and novelty scores, same models; bold is better.

MetricsVAEGAN
Nearest datapoint0.0430.018
Inter-sample distance0.0300.019
Convex hull5.6517.173
DPP diversity14.39814.688
Distance to centroid1.1201.391

tab. 4 Constraint adherence, same models; bold is better.

MetricsVAEGAN
Constraint satisfaction0.7130.833
Constraint satisfaction rate0.8570.917
Predicted constraint satisfaction0.6980.823
Nearest invalid datapoint0.170.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.

MetricsGANMO-PaDGAN
Hypervolume0.4600.571
Generational distance0.2150.315
Weighted target achievement rate0.1620.430
Signed distance to target-0.275-0.154
Design target achievement index0.3240.433

tab. 6 Conditioning, cVAE vs cGAN; conditional and marginal reference sets; bold is better.

MetricscVAEcGAN
Conditioning reconstruction0.0070.026
Conditioning adherence0.0080.026
Conditional F100.9090.826
Conditional F0.10.8790.960
Conditional MMD0.0350.021
Marginal F100.9490.933
Marginal F0.10.4470.554
Marginal MMD0.0680.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.

MetricTopoDiff, FEA fieldsTopoDiff, 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.1445.87
Mean inference time (sec.)5.872.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 GD evaluation.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_wrapper and AUC_wrapper default to 5 and pass it on evaluation.py[code: evaluation.py#L339]. The compute_prd_from_embedding default 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_wrapper accepts subset_size=10 but 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. The Target achievement rate is 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_padgan calls evaluation.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) where D is 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.
  • all branch of nearest generated sample. With flag="all", the code assigns to y_eval and then uses an undefined x evaluation.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_state eval_prd.py. MMD subsamples with np.random and 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.