Generative Modeling
By the end: For autoregressive, VAE, GAN and diffusion models you state the training objective in one line, name the constraint each one fits, read a quality-versus-coverage table from a sampling sweep, and list the provenance and licensing checks that precede sharing generated data.
At a glance
Four generative families trade likelihood, speed and stability differently; judge samples on quality and coverage separately and check memorisation before release.
Four objectives
Next element, reconstruction + prior, fool a critic, undo noise.
One knob
Temperature, truncation and guidance trade coverage for typicality.
Rare patterns first
Cleaner settings delete the rare mode while every sample still looks real.
Precision and recall
Score realism and coverage separately; a single score folds them together.
Before release
Search for memorised rows, confirm licence, label provenance.
Recall
If no cards are due, answer from memory: what does temperature change in a next-token sampler, and why is "fluent" not evidence that a statement is supported? Then name one number you would need before trusting a generated answer.
Concept
A Generative model learns the distribution of the data, , so you can draw new samples. Four families answer "how do we train it so samples look like data?" differently, each with a price. One knob exists in all of them, the Quality-diversity trade-off: cleaner, more typical samples cost coverage, and rare patterns vanish first.
Predict first
Temperature drops from 1.0 to 0.3. What happens to the share of samples from a pattern that makes up about 5% of the real data?
Text description of the figure
A scatter of generated points over five dashed real-data regions (toy two-dimensional Gaussian clusters, one of them rare at 6% of the data) and a fixed set of real reference points. Sliders set sampling temperature, truncation (keep the densest share of probability), the number of samples and the seed. Readouts give quality (generated points inside a real region) and coverage (reference points with a generated neighbour), a per-cluster table and a curve of both against temperature. As temperature falls, quality rises, coverage falls and the rare cluster empties; as it rises, points land outside every region.
- AR: sequence so far
- predict: to p(next element)
- VAE: data x
- encode: to Latent code z
- p(next element)trained on exact likelihood
- sample: to Sampled element
- Latent code zpulled toward a simple prior
- decode: to Reconstruction of x
- z drawn from the priorgeneration: no input x
- decode: to New sample
- Sampled element
- append, repeat: back to AR: sequence so far
- Reconstruction of xscored against the input x
- New sample
Generation reuses the trained part: AR samples one element at a time; a VAE decodes a z drawn from the prior in one pass, which works only because training kept codes near that prior.
- GAN: generatorturns random noise into a sample
- generate: to Fake sample
- Diffusion: data x
- add noise: to Noisy x_t
- Fake sample
- judged: to Discriminator: real?
- Noisy x_tnoise level t drawn at random
- predict noise: to Noise predictor
- Discriminator: real?
- fool D: back to GAN: generator
- Noise predictorregression on the known noise
- Real data
- judged: back to Discriminator: real?
The dashed arrow is the gradient that teaches G to fool D. Generation: a GAN runs the generator once; diffusion starts from pure noise and applies the noise predictor many times.
| Criterion | Autoregressive | VAE | GAN | Diffusion |
|---|---|---|---|---|
| Trained to | Predict each next element from the ones before | Reconstruct x through a latent code kept near a prior | Fool a discriminator that tells real from fake | Predict the noise added to data; generate by denoising |
| Exact likelihood | Yes | Lower bound only | No | Bound, not used directly |
| Sampling | Sequential, one element at a time | One pass through the decoder | One pass | Many denoising steps |
| Training | Stable maximum likelihood | Stable | Delicate two-player game | Stable regression on noise |
| Typical weakness | Slow long outputs; errors compound | Softer, blurrier samples | Mode collapse: covers part of the data | Slow sampling; latent diffusion cuts cost |
Kingma 2014 (VAE), Goodfellow 2014 (GAN), Ho 2020 (DDPM), Rombach 2022 (latent diffusion).
- Precision (realism)
- Recall (coverage)
Cooling keeps precision and loses coverage; heating keeps coverage and loses precision. T 1.0 matches the data process (T 2.0: 0.94 and 0.98; T 3.0: 0.88 and 0.96).
- Held-out real rows
- Fresh generator
- Memorising generator
Rows closer to a training row than 99% of held-out real rows (left of the line): held-out 4, fresh 5, memorising 36 of 400. The spike is the 32 planted copies.
| Generator | Quality | Coverage | Near-copies |
|---|---|---|---|
| Fresh | 0.96 | 0.91 | 5 |
| Memorising | 0.96 | 0.90 | 36 |
The same two generators on the fidelity metrics: a copy of a real row is as realistic as a row can be, so quality and coverage cannot see memorisation.
Synthetic 2-D rows from the Day 46 toy mixture: 400 training, 400 held-out and 400 generated rows (seeded). The memorising generator replaces 8% of its rows with training rows plus jitter of at most 0.005. Threshold = 1st percentile of held-out distances.
Generated rows are compared with real rows held out from training; a generated row closer to a training row than almost any held-out row is a near-copy.
- Autoregressive: predict the next element; exact likelihood, sequential sampling (Day 42).
- VAE: encode to a latent code and decode; smooth latent space, softer samples.
- GAN: generator against discriminator; one-pass sampling, may cover only part of the data.
- Diffusion: learn to undo small noising steps; high quality, slow sampling.
- Measure precision (samples inside real data) and recall (real variety reached) separately, then check memorisation, licence and provenance before release (not legal advice).
Assumptions
The training data represent the distribution you want; a generator reproduces only patterns the data and model capacity cover.
Quality and coverage are measured with enough samples and a defined "close" (here a two-dimensional nearest-neighbour ball; image work uses learned feature spaces).
A generated sample is a draw from a learned distribution, not an observation of the world; it supports testing and augmentation, not claims about real customers.
Application and workplace decision
- A vendor needs a synthetic copy of bookings (lead time and fare index, synthetic) for load testing now and, later, to train a group-booking detector. Group bookings are about 5% of rows.
- The code's generator is a three-pattern mixture with a temperature control, plus a "collapsed" generator that emits only the largest pattern; each is scored against 1,000 real rows with nearest-neighbour precision and recall.
- T = 1.0 matches the data process (the reference ceiling). Predict which settings keep the rare pattern.
Python
import numpy as np
from scipy.spatial.distance import cdist
rng = np.random.default_rng(46)
centers = np.array([[0.0, 0.0], [6.0, 0.0], [3.0, 5.0]]) # three booking patterns (synthetic)
weights = np.array([0.50, 0.45, 0.05]) # the third pattern is rare
def sample(n, temp=1.0, only_mode=None):
w = weights ** (1 / temp)
w = w / w.sum()
comp = np.full(n, only_mode) if only_mode is not None else rng.choice(3, n, p=w)
return centers[comp] + rng.normal(0, np.sqrt(temp), (n, 2)), comp
def knn_radius(x, k=3):
return np.sort(cdist(x, x), axis=1)[:, k] # distance to k-th neighbour (column 0 is self)
def precision_recall(real, gen):
r_real, r_gen = knn_radius(real), knn_radius(gen)
precision = (cdist(gen, real) <= r_real).any(axis=1).mean() # gen inside real manifold
recall = (cdist(real, gen) <= r_gen).any(axis=1).mean() # real covered by gen manifold
return precision, recall
real, _ = sample(1000, temp=1.0)
print("setting precision recall rare-mode share")
for name, temp, mode in [("T=0.3", 0.3, None), ("T=1.0", 1.0, None), ("T=2.0", 2.0, None), ("T=3.0", 3.0, None), ("collapsed", 1.0, 0)]:
gen, comp = sample(1000, temp, mode)
p, r = precision_recall(real, gen)
print(f"{name:<13} {p:9.2f} {r:6.2f} {np.mean(comp == 2):10.3f}")
Mini-assessment
Technical depth
The four objectives, term by termOne line of maths per family, every symbol explained, the derivation behind each line, and the GAN game as a loop.
- the joint probability of the whole sequence, the thing being learned
- the chain rule, p(x1, x2, ...) = p(x1) p(x2 | x1) ...: exact for any ordering, an identity, not an approximation
- element t (token, product id, pixel)
- everything generated before it
- one conditional per position; the model's only job
Derivation in one line: the chain rule makes maximum likelihood split into one next-element prediction per position. Logs turn the product into a sum, so exact log-likelihood is computable; the optional lab compares model and true process (-1.168 versus -1.163 per move).
- the quantity we would like to maximise but cannot compute directly
- Jensen's inequality: the right side (the ELBO) never exceeds the left
- encoder distribution over latent codes
- average over the codes the encoder proposes for this x
- reconstruction term: how well the decoder rebuilds x from z
- keeps codes close to the prior p(z), usually a standard normal
- the gap, exactly KL(q(z|x) ‖ p(z|x)) ≥ 0: the bound is tight when the encoder matches the true posterior
Derivation: write log p(x) = log ∫ p(x|z) p(z) dz, multiply and divide by q(z|x) inside the integral, and apply Jensen's inequality to the concave log. What is lost is the KL gap in the last row (Kingma 2014).
- two players with opposite objectives: D is trained up, G is trained against it
- discriminator; probability that its input is real
- D's reward for recognising real data as real
- generator output from noise z
- falls as fakes fool D, which is exactly what G minimises
- the best discriminator for a fixed G; substituting it back shows G minimises the Jensen-Shannon divergence to the data, zero only when they match
Goodfellow et al. 2014 (the divergence result holds up to a constant). No likelihood is computed, so there is no shared yardstick with the other families.
- the Gaussian noise the training loop itself added, so the label is known exactly
- data after t noising steps, built in closed form in one jump; this is why the noise label is known exactly
- a noise level drawn at random each training step, so one network covers all levels
- network that predicts the added noise
- a plain squared error: training is stable supervised regression
Ho et al. 2020 derive this loss as a simplified weighting of the ELBO. Generation runs the learned denoising step many times, starting from pure noise.
- Draw noise za fresh batch every stepgenerate ↓
- Fakes G(z) + real rowsone mixed batchD scores each row ↓
- D(x) for every rowprobability that the row is realupdate D (max) ↓
- Sharper Dreal scored up, fakes downupdate G (min) ↓
- Better Gfakes move toward what D calls realrepeat ↓
- ↺ back to 1 · Draw noise z
The game in the equation above, run as a loop. If G finds one pattern D accepts, nothing in the loop pushes it to cover the others: that is mode collapse, the low-recall failure.
Temperature, measuredWhat the knob does to a distribution, worked by hand on three weights, shown at four settings and swept end to end.
- probability of outcome i at T = 1 (a token, a mixture component, a grid cell)
- temperature: below 1 sharpens, above 1 flattens
- every ratio between two outcomes is raised to 1/T, so the smallest outcomes shrink fastest when T < 1
The same as dividing logits by T before the softmax. A 1-in-10 ratio between two outcomes becomes 1-in-100 at T = 0.5.
| Step | T = 0.5 (each weight squared) | T = 2.0 (square root of each) |
|---|---|---|
| Raise each weight to 1/T | 0.36, 0.09, 0.01 | 0.775, 0.548, 0.316 |
| Sum the raised weights | 0.46 | 1.639 |
| Divide each by the sum | 0.783, 0.196, 0.022 | 0.473, 0.334, 0.193 |
| Rare pattern (bulk orders) | 10% falls to 2.2% | 10% rises to 19.3% |
Hypothetical e-commerce mixture (weekday, weekend, bulk), verified in Python. The 6:1 ratio between largest and rare becomes 36:1 at T = 0.5 and 2.4:1 at T = 2.0: ratios move, which is why the smallest weight moves most.
Quality 99% · coverage 79% · rare mode 1% of in-region points (real 6%), 1/9 rare reference points covered.
Quality 93% · coverage 89% · rare mode 5% of in-region points (real 6%), 6/9 rare reference points covered.
Quality 85% · coverage 92% · rare mode 5% of in-region points (real 6%), 7/9 rare reference points covered.
Quality 67% · coverage 94% · rare mode 10% of in-region points (real 6%), 7/9 rare reference points covered.
- generated, inside a real region
- generated, outside every region
- rare mode (6% of real data)
Toy 2-D mixture (five modes) and a generator that is 1.3x too wide, both from the Day 46 widget code; 350 seeded samples per panel against 240 reference points. Not a trained network.
Cooling pulls samples into the dense cores and the rare mode (outlined) empties first, while every remaining point still looks real.
- quality (generated points inside a real region)
- coverage (reference points with a generated neighbour)
- rare-mode share ÷ real share (1 = right amount)
Toy 2-D mixture from the Day 46 widget; 350 seeded samples per temperature against 240 reference points. Shapes carry over to real generators; the numbers do not.
Cooling raises quality and loses coverage; the rare mode reaches half its real share only from T ≈ 0.55. The best balance of quality and coverage here is T ≈ 0.50 (quality 0.97, coverage 0.91), below 1 because this generator is too wide.
For an imperfect generator the balance point need not be T = 1. Tune on quality, coverage and pattern shares together, at a fixed sample size, and record the setting with the generator version.
| Knob | Family | Turn it toward typical and you get |
|---|---|---|
| Temperature | Autoregressive, mixtures | Sharper weights; rare patterns lose mass fastest |
| Truncation | GAN latents, top-p | Cuts the tail outright: a pattern below the cut gets exactly zero mass |
| Guidance scale | Diffusion | Fidelity up, diversity down (Ho and Salimans 2022) |
Nucleus (top-p) sampling is from Holtzman et al. 2020. Temperature shrinks a rare pattern; truncation deletes it.
Optional-lab output (seeded bigram model over six airport codes): the share of distinct trips among 300 generated. At T = 0.4 and 1.0 every trip uses only observed moves.
Measuring quality and coverageHow nearest-neighbour precision and recall work, how to read them together, and what every metric misses.
Radii
For every real point, the distance to its 3rd nearest real neighbour; same for generated points.
Precision
Share of generated points inside at least one real point's ball.
Recall
Share of real points inside at least one generated point's ball.
Task test
Train on generated data, score on real data: the use the data is for.
Varied but sloppy
Covers the data, many off-pattern rows (T = 3.0).
The goal
Real-looking samples across all patterns (T = 1.0 here).
Broken
Neither realistic nor covering.
Typical but narrow
Mode collapse or low temperature: rare patterns missing.
The idea of separating the two is from Kynkaanniemi et al. 2019; the toy metric imitates it.
| Check | Measures | Blind to |
|---|---|---|
| FID (images) | Distance between real and generated feature statistics | Whether a loss is quality or coverage; copies of training images |
| Precision | Share of samples inside the real data's neighbourhood | Missing modes; a memorised row scores perfectly |
| Recall | Share of real data reached by some sample | Off-pattern rows, as long as each sits near something real |
| Pattern shares | Each known segment's share against its real share | Segments nobody labelled |
| Distance to closest record | Near-copies of training rows | Whether the data are useful |
| Train on synthetic, test on real | Usefulness for the intended model | Privacy; patterns that task does not use |
FID from Heusel et al. 2017; precision and recall from Kynkaanniemi et al. 2019. Report several checks; none is sufficient alone.
How each family failsThe typical failure of each family, the symptom that exposes it, and three common misreadings.
GAN: mode collapse
Precision fine, recall low, whole patterns missing. Check per-pattern shares.
Autoregressive: compounding
Each element conditions on earlier ones, so an early slip shapes the rest. Check quality by position.
VAE: averaging
Samples blend nearby data; sharp edges and rare extremes soften.
Diffusion: cost and copies
Many network calls per sample; training images have been extracted from such models (Carlini 2023).
Any family: feedback loops
Training on unlabelled generated data thins the tails (Shumailov 2024).
"T = 1 is the correct setting"
Only for a perfect model. An imperfect one balances quality and coverage elsewhere (see the temperature sweep).
"Low FID means good synthetic data"
One number mixes quality and coverage, and it rewards copies of the reference set.
"Labelled synthetic means anonymous"
Generators can reproduce training rows; only a nearest-record check looks for them.
Choosing a familyA decision path from the binding constraint to a shortlist, with the evaluation every branch shares.
- Purpose and data type known
- Small table, few columns?
- no: to Sequences or a likelihood needed?
yes - Simple baseline firstmixture model; compare before anything deep
- Sequences or a likelihood needed?
- no: to One-pass sampling required?
yes - Autoregressivetext, codes, event sequences
- One-pass sampling required?
- no: to Diffusion, often latent
yes - GAN or VAEwatch recall: modes go missing
- Diffusion, often latentquality first; many steps
Every branch ends in the same evaluation, quality and coverage separately plus a task test on real held-out rows, and the same release checks.
Memorisation, licence and provenanceThe nearest-record check step by step, and the other checks before any generated row is shared.
- Generated set
- Near-copy of a training row?
- no: to Licence permits this use?
yes - Remove, re-checkor retrain with safeguards
- Licence permits this use?
- yes: to Label provenance
no or unknown - Stop and ask the data owner
- Label provenancesynthetic, source, generator version
- Release
Diffusion models have emitted individual training images (Carlini 2023); generated data is not automatically private. NIST AI 600-1 lists information integrity and intellectual property among generative-AI risks. Not legal advice.
Scale the columns
Scale numeric columns and treat categorical ones separately, or one wide column decides every distance.
Generated to training
For each generated row, the distance to its nearest training row.
Held-out to training
The same distance for real rows held out from training: what a fresh draw looks like.
Flag near-copies
Generated rows closer than almost every held-out row (the demo uses its 1st percentile) are near-copies.
Read it honestly
A clean result is evidence against verbatim copying, not a privacy guarantee; rare combinations need their own re-identification test.
The memorisation demo in the Concept block runs exactly this check against planted copies.
A tabular baseline and its defaultsadvancedThe scikit-learn defaults that matter when a mixture model is the first synthetic-data generator.
| Setting | Default | Why it matters for synthetic data |
|---|---|---|
| GaussianMixture n_components | 1 | One Gaussian cannot hold a separate rare pattern; choose the count on held-out likelihood or BIC |
| covariance_type | full | Keeps correlation between columns within each component; diag drops it |
| n_init | 1 | A single start can merge a small cluster into a large one; try several starts |
| NearestNeighbors metric | minkowski, p = 2 | Euclidean: scale columns first, or one wide column decides every nearest-record distance |
GaussianMixture.sample has no temperature argument; sampling with narrower spread means editing the fitted covariances, a choice to document.
Latent diffusionadvancedWhy modern image generators run diffusion in an autoencoder's latent space.
- AutoencoderCompresses images into a smaller latent grid and decodes back.
- Diffusion in latent spaceNoising and denoising run on the compact latents, far cheaper.
- ConditioningText or other inputs steer denoising; guidance trades diversity for fidelity.
- DecodeThe final latent is decoded to pixels.
Rombach et al. 2022.
Memory anchor
Objective explains behaviour; realism is not coverage; and generated data has a source.
Useful for
Choosing a model family for synthetic data, image or audio generation across domains: synthetic transactions for fraud-detector testing (banking), patient-like records for research access (healthcare), defect images for augmentation (manufacturing).
Reviewing a generative proposal for the right evaluation (quality and coverage separately, plus a task test) and the right release checks.
Explaining to stakeholders why "looks realistic" does not mean "covers our customers" and why generated data is not automatically private.
Not suitable for
Judging whether a particular generator is good enough for your data; that needs your data, your metric and a downstream task test.
Training or tuning a generative model; this day is orientation and the toy code scores samples, it does not train a network.
Legal conclusions about copyright or licensing; the lesson names the checks, and a lawyer decides what they imply.
Traps
Ranking generators by one realism score
A single number such as FID mixes sample quality and coverage, so a generator that emits a narrow set of excellent samples can win while missing the rare patterns the project needs.
How to avoid it
Report precision and recall (or quality and coverage) separately at the same sample size, compare pattern shares with the real data, and finish with a downstream task test on real held-out data.
Treating generated data as private and licence-free
Generators can reproduce training records, and synthetic copies of licensed or personal data inherit the terms and the risk of their source. A "synthetic" patient table or transaction log can still expose the original record, and in regulated sectors (health, banking) that is a reportable incident, not a modelling bug.
How to avoid it
Search outputs for near-duplicates of training rows, keep a provenance record of sources and licences, get governance sign-off before release, and never feed unlabelled generated data back into training.
Senior reasoning
A senior does not ask which family is best. They ask which constraint binds (coverage of rare patterns, sampling speed, a usable latent space, a likelihood, training stability, data volume), shortlist two families, and test them on the target task with quality and coverage reported separately. They treat sampling settings as a decision about the product, not a cosmetic choice, and they ask where the training data came from before anyone asks how good the samples look.
Interview question
"A team proposes a diffusion model to generate synthetic customer data for a vendor. What questions do you ask before approving it?"
Recall cards scheduled after completion
- State the training objective of an autoregressive model, a VAE, a GAN and a diffusion model in one line each.
- What does lowering temperature (or raising guidance) do to precision, recall and rare patterns?
Prerequisites and related concepts
References
- Auto-Encoding Variational Bayesoptional
Defines the variational autoencoder, its lower-bound objective and the reparameterisation trick behind the VAE line in the mechanism. (Section 2 (Method))
- Generative Adversarial Netsoptional
States the generator-discriminator game that defines the GAN objective. (Section 3 (Adversarial nets))
- Denoising Diffusion Probabilistic Modelscore
Gives the forward noising process and the learned reverse denoising process used in the diffusion line. (Sections 2-3)
- High-Resolution Image Synthesis with Latent Diffusion Modelsoptional
Moves the diffusion process into an autoencoder's latent space to cut compute; supports the latent diffusion sentence. (Section 3 (Method))
- Improved Precision and Recall Metric for Assessing Generative Modelscore
Separates sample quality (precision) from coverage of the real distribution (recall), which a single FID-style value conflates; the toy metric imitates this idea.
- Classifier-Free Diffusion Guidanceoptional
Shows that guidance trades diversity for fidelity, in the spirit of low-temperature sampling.
- Extracting Training Data from Diffusion Modelsoptional
Documents that diffusion models memorised and emitted individual training images, which is why generated data is not automatically private.
- GANs Trained by a Two Time-Scale Update Rule Converge to a Local Nash Equilibriumoptional
Introduces FID, the single feature-statistics distance that the metric table contrasts with separate precision and recall.
- The Curious Case of Neural Text Degenerationoptional
Proposes nucleus (top-p) sampling, the truncation knob that removes low-probability outcomes outright.
- AI models collapse when trained on recursively generated dataoptional
Shows that training on recursively generated data removes the tails of the original distribution, the feedback-loop failure in the failure cards.
- Artificial Intelligence Risk Management Framework: Generative Artificial Intelligence Profileoptional
Lists information integrity and intellectual property among generative-AI risks and describes provenance-related actions; supports the release-check list. (Section 2 (risks), Information Integrity and Intellectual Property)
Optional sections
Deep dive
Objectives in symbols.
- VAE: , the evidence lower bound (ELBO). The first term rewards reconstruction; the second keeps the encoder's codes close to the prior so that sampling is meaningful.
- GAN: . There is no likelihood term, which is why held-out likelihood cannot score a GAN.
- Diffusion (DDPM-style): train to predict the noise added to at a random step , minimising .
- Classifier-free guidance mixes a conditional and an unconditional noise estimate, ; larger gives samples that follow the condition more closely and vary less.
| Family | Training signal | Sampling | Likelihood | Typical price | |---|---|---|---|---| | Autoregressive | Next-element likelihood | Sequential, one element per step | Exact | Slow for long outputs; error compounds | | VAE | Lower bound: reconstruction and prior match | One decoder pass | Bound only | Smooth latent space, softer samples | | GAN | Adversarial game | One generator pass | None | Unstable training; may miss modes | | Diffusion | Denoising of noised data | Many denoising steps | Bound, indirect | Slow sampling; latent variants cut cost |
Feedback loops. Training a generator on its own earlier output removes the tails of the distribution (Shumailov et al., 2024, shown for several model types). Keep a real-data anchor and a provenance label on every record (insight 0545).
What the toy metric hides. The nearest-neighbour balls assume that "inside the real data's neighbourhood" means realistic. In high dimensions distances behave differently, which is why practitioners use features from a trained network; the principle of reporting two numbers survives, the exact values do not transfer.
Hands-on lab: Exact likelihood and sampling temperature for an autoregressive model
Fit a first-order autoregressive model (a bigram table over airport codes) to synthetic trips, compute its exact held-out log-likelihood, and sample at three temperatures. Before running, write down which temperature should give the most distinct trips and which the highest share of trips that use only moves observed in training. Then run it and note two things: how close the fitted model's likelihood is to the true process (an exact likelihood is available here, which a GAN cannot offer), and what the share of "observed moves only" does at the highest temperature. Finally, explain in two sentences why this is a coverage-versus-validity trade-off.
import numpy as np
rng = np.random.default_rng(7)
codes = ["IST", "ADB", "AYT", "ESB", "LHR", "FRA"]
K = len(codes)
true_p = rng.dirichlet(np.full(K, 0.4), size=K) # synthetic "true" next-airport process
def make_trips(n, length=6):
trips = np.zeros((n, length), dtype=int)
for i in range(n):
s = rng.integers(K)
for t in range(length):
trips[i, t] = s
s = rng.choice(K, p=true_p[s])
return trips
train, test = make_trips(600), make_trips(200)
counts = np.full((K, K), 0.5) # additive smoothing so unseen moves keep a little probability
for trip in train:
for a, b in zip(trip[:-1], trip[1:]):
counts[a, b] += 1
model = counts / counts.sum(axis=1, keepdims=True)
def avg_loglik(trips, p):
return np.mean([np.log(p[a, b]) for tr in trips for a, b in zip(tr[:-1], tr[1:])])
print(f"avg log-lik per move: model {avg_loglik(test, model):.3f}, true process {avg_loglik(test, true_p):.3f}")
seen = counts > 0.5 # transitions observed in the training trips
def generate(temp, n=300, length=6):
p = model ** (1 / temp)
p = p / p.sum(axis=1, keepdims=True)
out = []
for _ in range(n):
s, trip = rng.integers(K), []
for _ in range(length):
trip.append(s)
s = rng.choice(K, p=p[s])
out.append(tuple(trip))
return out
for temp in (0.4, 1.0, 2.0):
trips = generate(temp)
distinct = len(set(trips)) / len(trips)
valid = np.mean([all(seen[a, b] for a, b in zip(t[:-1], t[1:])) for t in trips])
print(f"T={temp}: distinct trips {distinct:.2f}, share using only observed moves {valid:.2f}")
Interview practice
An insurer wants to release a "synthetic version" of its claims table to external researchers. How do you decide whether it is safe and useful?