diffusion_baseline / upstreams /candi /trainer_base.py
jyliuAI's picture
Add files using upload-large-folder tool
9a46c96 verified
Raw History Blame Contribute Delete
30.1 kB
import itertools
import pdb
from dataclasses import dataclass
import hydra.utils
import lightning as L
import numpy as np
import torch
import torch.nn.functional as F
import transformers
import dataloader
import metrics
import models
import utils
import time
@dataclass
class Loss:
loss: torch.FloatTensor
nlls: torch.FloatTensor
prior_loss: torch.FloatTensor
num_tokens: torch.FloatTensor
class LogLinear(torch.nn.Module):
def __init__(self):
super().__init__()
self.eps = 1e-3 # To be consistent with SEDD: https://github.com/louaaron/Score-Entropy-Discrete-Diffusion/blob/0605786da5ccb5747545e26d66fdf477187598b6/noise_lib.py#L56
def forward(self, t):
t = (1 - self.eps) * t
alpha_t = 1 - t
dalpha_t = -(1 - self.eps)
return dalpha_t, alpha_t
def sample_categorical(categorical_probs):
gumbel_norm = 1e-10 - (torch.rand_like(categorical_probs) + 1e-10).log()
return (categorical_probs / gumbel_norm).argmax(dim=-1)
def _unsqueeze(x, reference):
return x.view(*x.shape, *((1,) * (len(reference.shape) - len(x.shape))))
class TrainerBase(L.LightningModule):
def __init__(
self, config, tokenizer: transformers.PreTrainedTokenizer, vocab_size=None
):
super().__init__()
self.save_hyperparameters()
self.config = config
if hasattr(self.config.algo, "ignore_bos"):
self.ignore_bos = config.algo.ignore_bos
else:
self.ignore_bos = False
if hasattr(self.config.algo, "loss_type"):
self.loss_type = config.algo.loss_type
self.tokenizer = tokenizer
if vocab_size is None:
if hasattr(self.config.data, 'vocab_file'):
self.vocab_size = len(self.tokenizer.added_tokens_decoder)
self.token_offset = True
else:
self.token_offset = False
self.vocab_size = len(self.tokenizer)
else:
self.vocab_size = vocab_size
self.sampler = self.config.sampling.predictor
self.antithetic_sampling = self.config.training.antithetic_sampling
self.parameterization = self.config.algo.parameterization
if self.config.algo.backbone == "dit":
self.backbone = models.dit.DIT(self.config, vocab_size=self.vocab_size)
elif self.config.algo.backbone == "cont_dit":
backbone = models.dit_cont.ContDIT(self.config.model, vocab_size=self.vocab_size, mixed_coeff=self.config.algo.mixed_coeff)
self.backbone = backbone
elif self.config.algo.backbone == "dimamba":
self.backbone = models.dimamba.DiMamba(
self.config,
vocab_size=self.vocab_size,
pad_token_id=self.tokenizer.pad_token_id,
)
elif self.config.algo.backbone == "hf_dit":
self.backbone = transformers.AutoModelForMaskedLM.from_pretrained(
config.eval.checkpoint_path, trust_remote_code=True
)
self.T = self.config.algo.T
self.num_tokens = self.config.model.length
self.softplus = torch.nn.Softplus()
self.p_nucleus = self.config.sampling.p_nucleus
# Noise Schedule
self.noise = LogLinear()
self.metrics = metrics.Metrics(
gen_ppl_eval_model_name_or_path=self.config.eval.gen_ppl_eval_model_name_or_path,
eval_ppl_batch_size=self.config.eval.perplexity_batch_size,
)
if self.config.training.ema > 0:
self.ema = models.ema.ExponentialMovingAverage(
self._get_parameters(), decay=self.config.training.ema
)
else:
self.ema = None
self.lr = self.config.optim.lr
self.sampling_eps = self.config.training.sampling_eps
self.time_conditioning = self.config.algo.time_conditioning
self.neg_infinity = -1000000.0
self.fast_forward_epochs = None
self.fast_forward_batches = None
def _validate_configuration(self):
assert self.config.algo.backbone in {"dit", "hf_dit"}
if self.config.algo.parameterization == "ar":
assert not self.config.algo.time_conditioning
assert self.config.prior.type == "none"
if self.parameterization in {"score", "mean"}:
assert self.time_conditioning
if self.T > 0:
assert self.parameterization != "score"
def to(self, *args, **kwargs):
self = super().to(*args, **kwargs)
self.metrics.to(*args, **kwargs)
return self
def q_xt(self, x, alpha_t):
raise NotImplementedError
def _get_parameters(self):
return itertools.chain(self.backbone.parameters(), self.noise.parameters())
def _eval_mode(self):
if self.ema:
self.ema.store(self._get_parameters())
self.ema.copy_to(self._get_parameters())
self.backbone.eval()
self.noise.eval()
def _train_mode(self):
if self.ema:
self.ema.restore(self._get_parameters())
self.backbone.train()
self.noise.train()
def on_load_checkpoint(self, checkpoint):
if self.ema:
self.ema.load_state_dict(checkpoint["ema"])
# Copied from:
# https://github.com/Dao-AILab/flash-attention/blob/main/training/src/datamodules/language_modeling_hf.py#L41
self.fast_forward_epochs = checkpoint["loops"]["fit_loop"]["epoch_progress"][
"current"
]["completed"]
self.fast_forward_batches = checkpoint["loops"]["fit_loop"][
"epoch_loop.batch_progress"
]["current"]["completed"]
if 'state_dict' in checkpoint:
state_dict = checkpoint['state_dict']
cleaned_state_dict = {}
for key, value in state_dict.items():
if "teacher" not in key:
cleaned_key = key
# Remove _orig and other modifiers
cleaned_key = cleaned_key.replace('_orig_mod.', '')
cleaned_state_dict[cleaned_key] = value
checkpoint['state_dict'] = cleaned_state_dict
def on_save_checkpoint(self, checkpoint):
if self.ema:
checkpoint["ema"] = self.ema.state_dict()
# Copied from:
# https://github.com/Dao-AILab/flash-attention/blob/main/training/src/tasks/seq.py
# ['epoch_loop.batch_progress']['total']['completed']
# is 1 iteration behind, so we're using the optimizer's progress.
checkpoint["loops"]["fit_loop"]["epoch_loop.batch_progress"]["total"][
"completed"
] = (
checkpoint["loops"]["fit_loop"][
"epoch_loop.automatic_optimization.optim_progress"
]["optimizer"]["step"]["total"]["completed"]
* self.trainer.accumulate_grad_batches
)
checkpoint["loops"]["fit_loop"]["epoch_loop.batch_progress"]["current"][
"completed"
] = (
checkpoint["loops"]["fit_loop"][
"epoch_loop.automatic_optimization.optim_progress"
]["optimizer"]["step"]["current"]["completed"]
* self.trainer.accumulate_grad_batches
)
# _batches_that_stepped tracks the number of global steps,
# not the number of local steps, so we don't multiply with
# self.trainer.accumulate_grad_batches here.
checkpoint["loops"]["fit_loop"]["epoch_loop.state_dict"][
"_batches_that_stepped"
] = checkpoint["loops"]["fit_loop"][
"epoch_loop.automatic_optimization.optim_progress"
][
"optimizer"
][
"step"
][
"total"
][
"completed"
]
if "sampler" not in checkpoint.keys():
checkpoint["sampler"] = {}
if hasattr(self.trainer.train_dataloader.sampler, "state_dict"):
sampler_state_dict = self.trainer.train_dataloader.sampler.state_dict()
checkpoint["sampler"]["random_state"] = sampler_state_dict.get(
"random_state", None
)
else:
checkpoint["sampler"]["random_state"] = None
def on_train_start(self):
if self.ema:
self.ema.move_shadow_params_to_device(self.device)
# Adapted from:
# https://github.com/Dao-AILab/flash-attention/blob/main/training/src/datamodules/language_modeling_hf.py
distributed = (
self.trainer._accelerator_connector.use_distributed_sampler
and self.trainer._accelerator_connector.is_distributed
)
if distributed:
sampler_cls = dataloader.FaultTolerantDistributedSampler
else:
sampler_cls = dataloader.RandomFaultTolerantSampler
updated_dls = []
for dl in self.trainer.fit_loop._combined_loader.flattened:
if hasattr(dl.sampler, "shuffle"):
dl_sampler = sampler_cls(dl.dataset, shuffle=dl.sampler.shuffle)
else:
dl_sampler = sampler_cls(dl.dataset)
if (
distributed
and self.fast_forward_epochs is not None
and self.fast_forward_batches is not None
):
dl_sampler.load_state_dict(
{
"epoch": self.fast_forward_epochs,
"counter": (
self.fast_forward_batches * self.config.loader.batch_size
),
}
)
updated_dls.append(
torch.utils.data.DataLoader(
dl.dataset,
batch_size=self.config.loader.batch_size,
num_workers=self.config.loader.num_workers,
pin_memory=self.config.loader.pin_memory,
sampler=dl_sampler,
shuffle=False,
persistent_workers=True,
)
)
self.trainer.fit_loop._combined_loader.flattened = updated_dls
def optimizer_step(self, *args, **kwargs):
super().optimizer_step(*args, **kwargs)
if self.ema:
self.ema.update(self._get_parameters())
def _process_sigma(self, sigma):
raise NotImplementedError
def _process_model_output(self, model_output, xt, sigma):
raise NotImplementedError
def forward(self, xt, sigma):
sigma = self._process_sigma(sigma)
with torch.cuda.amp.autocast(dtype=torch.float32):
model_output = self.backbone(xt, sigma)
return self._process_model_output(model_output=model_output, xt=xt, sigma=sigma)
def on_train_epoch_start(self):
self.metrics.reset()
assert self.metrics.train_nlls.nll.mean_value == 0
assert self.metrics.train_nlls.nll.weight == 0
def training_step(self, batch, batch_idx):
current_accumulation_step = batch_idx % self.trainer.accumulate_grad_batches
losses = self._loss(
batch["input_ids"],
batch["attention_mask"],
current_accumulation_step,
train_mode=True,
)
self.metrics.update_train(losses.nlls, losses.prior_loss, losses.num_tokens)
self.log(
name="trainer/loss",
value=losses.loss.item(),
on_step=True,
on_epoch=False,
sync_dist=True,
)
return losses.loss
def on_train_epoch_end(self):
for k, v in self.metrics.valid_nlls.items():
self.log(
name=k, value=v.compute(), on_step=False, on_epoch=True, sync_dist=True
)
def on_validation_epoch_start(self):
self.metrics.reset()
self._eval_mode()
assert self.metrics.valid_nlls.nll.mean_value == 0
assert self.metrics.valid_nlls.nll.weight == 0
def validation_step(self, batch, batch_idx):
del batch_idx
losses = self._loss(batch["input_ids"], batch["attention_mask"])
self.metrics.update_valid(losses.nlls, losses.prior_loss, losses.num_tokens)
return losses.loss
def on_validation_epoch_end(self):
for k, v in self.metrics.valid_nlls.items():
self.log(
name=k, value=v.compute(), on_step=False, on_epoch=True, sync_dist=True
)
if (
self.config.eval.compute_perplexity_on_sanity
or not self.trainer.sanity_checking
) and self.config.eval.generate_samples:
samples, text_samples = None, None
for _ in range(self.config.sampling.num_sample_batches):
samples = self.generate_samples(
num_samples=self.config.loader.eval_batch_size
)
self.metrics.record_entropy(samples)
# Decode the samples to be re-tokenized by eval model
text_samples = self.tokenizer.batch_decode(samples)
if self.config.eval.compute_generative_perplexity:
self.metrics.record_generative_perplexity(
text_samples, self.num_tokens, self.device
)
if text_samples is not None:
if self.trainer.global_rank == 0 and hasattr(
self.trainer.logger, "log_table"
):
# Log the last generated samples
text_samples = text_samples[: self.config.sampling.num_sample_log]
self.trainer.logger.log_table(
key=f"samples@global_step{self.global_step}",
columns=["Generated Samples"],
data=[[s] for s in text_samples],
)
if self.config.eval.compute_generative_perplexity:
self.log(
"val/gen_ppl",
self.metrics.gen_ppl.compute(),
on_epoch=True,
on_step=False,
sync_dist=True,
)
self.log(
"val/sample_entropy",
self.metrics.sample_entropy.compute(),
on_epoch=True,
on_step=False,
sync_dist=True,
)
self._train_mode()
def configure_optimizers(self):
optimizer = torch.optim.AdamW(
self._get_parameters(),
lr=self.config.optim.lr,
betas=(self.config.optim.beta1, self.config.optim.beta2),
eps=self.config.optim.eps,
weight_decay=self.config.optim.weight_decay,
)
scheduler = hydra.utils.instantiate(
self.config.lr_scheduler, optimizer=optimizer
)
scheduler_dict = {
"scheduler": scheduler,
"interval": "step",
"monitor": "val/loss",
"name": "trainer/lr",
}
return [optimizer], [scheduler_dict]
def generate_samples(self, num_samples, num_steps, eps):
raise NotImplementedError
def restore_model_and_sample(self, num_steps, eps=1e-5):
"""Generate samples from the model."""
# Lightning auto-casting is not working in this method for some reason
self._eval_mode()
start = time.time()
samples = self.generate_samples(
num_samples=self.config.loader.eval_batch_size, num_steps=num_steps, eps=eps
)
end = time.time()
self._train_mode()
return samples
def _process_model_input(self, x0, valid_tokens):
raise NotImplementedError
def nll(
self,
input_tokens,
output_tokens,
current_accumulation_step=None,
train_mode=False,
):
raise NotImplementedError
def _loss(self, x0, valid_tokens, current_accumulation_step=None, train_mode=False):
(input_tokens, output_tokens, valid_tokens) = self._process_model_input(
x0, valid_tokens
)
loss = self.nll(
input_tokens, output_tokens, current_accumulation_step, train_mode
)
assert loss.ndim == 2
if self.ignore_bos:
loss[:, 1:] = loss[:, 1:]
valid_tokens[:, 1:] = valid_tokens[:, 1:]
nlls = (loss * valid_tokens).sum()
num_tokens = valid_tokens.sum()
token_nll = nlls / num_tokens
return Loss(loss=token_nll, nlls=nlls, prior_loss=0.0, num_tokens=num_tokens)
class Diffusion(TrainerBase):
def _validate_configuration(self):
super()._validate_configuration()
assert self.config.sampling.noise_removal in {"none", "ancestral", "greedy"}
assert self.loss_type in {"elbo", "low_var"}
if self.config.sampling.noise_removal == "greedy":
assert self.sampler != "analytic"
assert self.parameterization in {"mean", "subs"}
def _process_model_input(self, x0, valid_tokens):
return x0, None, valid_tokens
def _process_sigma(self, sigma):
assert sigma.ndim == 2
sigma = sigma.mean(-1).squeeze()
if sigma.ndim == 0:
sigma = sigma.unsqueeze(0)
if not self.time_conditioning:
sigma = torch.zeros_like(sigma)
assert sigma.ndim == 1, sigma.shape
return sigma
def _sample_t(self, n, accum_step):
if accum_step is not None:
# During training
batch_dim = n
n = self.config.loader.global_batch_size
_eps_t = torch.rand(n, device=self.device)
if self.antithetic_sampling:
offset = torch.arange(n, device=self.device) / n
_eps_t = (_eps_t / n + offset) % 1
t = (1 - self.sampling_eps) * _eps_t + self.sampling_eps
if accum_step is not None:
t = t.chunk(self.trainer.num_nodes)[self.trainer.node_rank]
t = t.chunk(self.trainer.num_devices)[self.trainer.local_rank]
t = t.chunk(self.trainer.accumulate_grad_batches)[accum_step]
# corner case for the last datapoint
t = t[:batch_dim]
return t
def _sigma_from_alphat(self, alpha_t):
return -torch.log(alpha_t)
def _reconstruction_loss(self, x0):
t0 = torch.zeros(1, x0.shape[0], dtype=self.dtype, device=self.device)
sigma_t0 = self._sigma_from_alphat(self.noise(t0)[1])
model_output_t0 = self.forward(x0, sigma_t0)
return -torch.gather(
input=model_output_t0, dim=-1, index=x0[:, :, None]
).squeeze(-1)
def nll_per_token(self, model_output, xt, x0, alpha_t, dalpha_t, low_var):
raise NotImplementedError
def nll(self, x0, output_tokens, current_accumulation_step=None, train_mode=False):
del output_tokens
t = self._sample_t(x0.shape[0], current_accumulation_step)
assert t.shape[0] == x0.shape[0]
if self.T > 0:
t = (t * self.T).to(torch.int)
t = t / self.T
# t \in {1/T, 2/T, ..., 1}
t += 1 / self.T
dalpha_t, alpha_t = self.noise(t)
alpha_t = alpha_t.unsqueeze(-1)
assert alpha_t.ndim == 2
sigma = self._sigma_from_alphat(alpha_t)
xt = self.q_xt(x0, alpha_t)
log_x_theta = self.forward(xt, sigma=sigma)
utils.print_nans(log_x_theta, "model_output")
return self.nll_per_token(
log_x_theta=log_x_theta,
xt=xt,
x0=x0,
alpha_t=alpha_t,
dalpha_t=dalpha_t,
low_var=train_mode and self.loss_type == "low_var",
)
def _get_score(self, **kwargs):
del kwargs
raise NotImplementedError
def _denoiser_update(self, x, t):
raise NotImplementedError
def _analytic_update(self, x, t, dt):
raise NotImplementedError
def _ancestral_update(self, x, t, dt, p_x0, noise_removal_step):
raise NotImplementedError
@torch.no_grad()
def generate_samples(self, num_samples, num_steps=None, eps=1e-5, prompt_mask=None, prompt_tokens=None):
"""Generate samples from the model."""
# Lightning auto-casting is not working in this method for some reason
if num_steps is None:
num_steps = self.config.sampling.steps
x = self.prior_sample(num_samples, self.num_tokens)
if prompt_tokens is not None and prompt_mask is not None:
# assumes that they will be the same shape
x = (prompt_mask * prompt_tokens + (1 - prompt_mask) * x).long()
timesteps = torch.linspace(1, eps, num_steps + 1, device=self.device)
dt = (1 - eps) / num_steps
p_x0_cache = None
for i in range(num_steps):
t = timesteps[i] * torch.ones(x.shape[0], 1, device=self.device)
if self.sampler == "ancestral":
# for mdlm, because of SUBS, the prompt mask wont be used
# but is needed to make duo / usdms condition on promtps / infill
_, x = self._ancestral_update(x=x, t=t, dt=dt, p_x0=None, prompt_mask=prompt_mask)
elif self.sampler == "ancestral_cache":
p_x0_cache, x_next = self._ancestral_update(
x=x, t=t, dt=dt, p_x0=p_x0_cache
)
if not torch.allclose(x_next, x) or self.time_conditioning:
# Disable caching
p_x0_cache = None
x = x_next
else:
x = self._analytic_update(x=x, t=t, dt=dt)
t0 = timesteps[-1] * torch.ones(x.shape[0], 1, device=self.device)
if self.config.sampling.noise_removal == "ancestral":
if self.sampler == "analytic":
x = self._denoiser_update(x=x, t=t0)
else:
_, x = self._ancestral_update(
x=x, t=t0, dt=None, p_x0=p_x0_cache, noise_removal_step=True, prompt_mask=prompt_mask
)
elif self.config.sampling.noise_removal == "greedy":
sigma = self._sigma_from_alphat(self.noise(t0)[1])
x = self.forward(xt=x, sigma=sigma).argmax(dim=-1)
if self.token_offset:
x += self.tokenizer.eos_token_id
return x
@torch.no_grad
def _semi_ar_sampler(self, n_samples, stride_length, num_strides, dt=0.001):
# TODO(subham): Test this method after refactoring.
ones = torch.ones(n_samples, dtype=self.dtype, device=self.device)
num_steps = int(1 / dt)
sampling_steps = 0
intermediate_tokens = []
target = None
for _ in range(num_strides + 1):
p_x0_cache = None
x = self.prior_sample(n_samples, self.num_tokens)
if target is not None:
x[:, :-stride_length] = target
for i in range(num_steps + 1):
p_x0_cache, x_next = self._ancestral_update(
x=x, t=(1 - i * dt) * ones, dt=dt, p_x0=p_x0_cache
)
if not torch.allclose(x_next, x) or self.time_conditioning:
p_x0_cache = None
sampling_steps += 1
x = x_next
x = self.forward(x, 0 * ones).argmax(dim=-1)
intermediate_tokens.append(x[:, :stride_length].cpu().numpy())
target = x[:, stride_length:]
intermediate_tokens.append(target.cpu().numpy())
intermediate_text_samples = []
sequence_lengths = (
(
np.concatenate(intermediate_tokens, axis=1)[:, 1:]
== self.tokenizer.eos_token_id
).cumsum(-1)
== 0
).sum(-1)
for i in range(2, len(intermediate_tokens) + 1):
intermediate_text_samples.append(
self.tokenizer.batch_decode(
np.concatenate(intermediate_tokens[:i], axis=1)
)
)
return (sampling_steps, intermediate_text_samples, sequence_lengths)
def restore_model_and_semi_ar_sample(self, stride_length, num_strides, dt=0.001):
"""Generate samples from the model."""
# Lightning auto-casting is not working in this method for some reason
# TODO(subham): Test this method after refactoring.
self._eval_mode()
(sampling_steps, samples, sequence_lengths) = self._semi_ar_sampler(
n_samples=self.config.loader.eval_batch_size,
stride_length=stride_length,
num_strides=num_strides,
dt=dt,
)
self._train_mode()
return sampling_steps, samples, sequence_lengths
class AbsorbingState(Diffusion):
def __init__(self, config, tokenizer):
self.temp = config.algo.get("temp", 1.0)
# NOTE: Ideally, we should do
# vocab_size = len(tokenizer), so that we account
# for the special tokens added in dataloader.py.
# But we use tokenizer.vocab_size so as to to be
# consistent with the prior checkpoints.
vocab_size = tokenizer.vocab_size
if hasattr(config.data, 'vocab_file'):
vocab_size = len(tokenizer.added_tokens_decoder)
self.token_offset = True
else:
self.token_offset = False
if not hasattr(tokenizer, "mask_token") or tokenizer.mask_token is None:
self.mask_index = vocab_size
vocab_size += 1
else:
self.mask_index = tokenizer.mask_token_id
self.subs_masking = config.algo.subs_masking
super().__init__(config, tokenizer, vocab_size=vocab_size)
self.save_hyperparameters()
def _validate_configuration(self):
super()._validate_configuration()
if self.parameterization in {"score", "mean"}:
assert self.time_conditioning
assert not (self.parameterization == "mean" and self.T == 0)
if self.T > 0:
assert self.parameterization in {"mean", "subs"}
if self.subs_masking:
assert self.parameterization == "mean"
def q_xt(self, x, alpha_t):
"""Computes the noisy sample xt.
Args:
x: int torch.Tensor with shape (batch_size,
diffusion_model_input_length), input.
alpha_t: float torch.Tensor with shape (batch_size, 1).
"""
move_indices = torch.rand(*x.shape, device=x.device) < 1 - alpha_t
xt = torch.where(move_indices, self.mask_index, x)
if self.ignore_bos:
xt[:, 0] = x[:, 0]
return xt
def prior_sample(self, *batch_dims):
# pdb.set_trace()
return self.mask_index * torch.ones(
*batch_dims, dtype=torch.int64, device=self.device
)
def _ancestral_update(self, x, t, dt, p_x0=None, noise_removal_step=False, **kwargs):
_, alpha_t = self.noise(t)
if noise_removal_step:
alpha_s = torch.ones_like(alpha_t)
else:
_, alpha_s = self.noise(t - dt)
assert alpha_t.ndim == 2
p_x0 = (self.forward(x, self._sigma_from_alphat(alpha_t)).double())
p_x0 = p_x0.exp()
q_xs = p_x0 * (alpha_s - alpha_t)[:, :, None]
q_xs[:, :, self.mask_index] = 1 - alpha_s
_x = sample_categorical(q_xs)
copy_flag = (x != self.mask_index).to(x.dtype)
return p_x0, copy_flag * x + (1 - copy_flag) * _x
def _staggered_score(self, score, dsigma):
score = score.clone()
extra_const = (1 - dsigma.exp()) * score.sum(dim=-1)
score *= dsigma.exp()[:, None]
score[..., self.mask_index] += extra_const
return score
def _analytic_update(self, x, t, dt):
sigma_t = self._sigma_from_alphat(self.noise(t)[1])
sigma_s = self._sigma_from_alphat(self.noise(t - dt)[1])
dsigma = sigma_t - sigma_s
score = self._get_score(x, sigma_t)
if self.config.sampling.use_float64:
score = score.to(torch.float64)
stag_score = self._staggered_score(score, dsigma)
probs = stag_score * self._transp_transition(x, dsigma)
return sample_categorical(probs)
def _denoiser_update(self, x, t):
sigma = self._sigma_from_alphat(self.noise(t)[1])
score = self._get_score(x, sigma)
if self.config.sampling.use_float64:
score = score.to(torch.float64)
stag_score = self._staggered_score(score, sigma)
probs = stag_score * self._transp_transition(x, sigma)
probs[..., self.mask_index] = 0
samples = sample_categorical(probs)
return samples
def _transp_transition(self, i, sigma):
sigma = _unsqueeze(sigma, reference=i[..., None])
edge = torch.exp(-sigma) * F.one_hot(i, num_classes=self.vocab_size)
edge += torch.where(i == self.mask_index, 1 - torch.exp(-sigma).squeeze(-1), 0)[
..., None
]
return edge
class UniformState(Diffusion):
def _validate_configuration(self):
super()._validate_configuration()
assert self.time_conditioning
assert self.parameterization == "mean"
if self.config.algo.name != "distillation":
assert self.T == 0
def q_xt(self, x, alpha_t):
"""Computes the noisy sample xt.
Args:
x: int torch.Tensor with shape (batch_size,
diffusion_model_input_length), input.
move_chance: float torch.Tensor with shape
(batch_size, 1).
"""
move_indices = torch.rand(*x.shape, device=x.device) < 1 - alpha_t
uniform_tensor = torch.randint(0, self.vocab_size, x.shape, device=x.device)
xt = torch.where(move_indices, uniform_tensor, x)
if self.ignore_bos:
xt[:, 0] = x[:, 0]
return xt
def prior_sample(self, *batch_dims):
return torch.randint(
0, self.vocab_size, batch_dims, dtype=torch.int64, device=self.device
)