AlienChen's picture
download
raw
3.2 kB
# Copyright (c) Meta Platforms, Inc.
# All rights reserved.
from pathlib import Path
from typing import List, Optional, Sequence, Tuple
import torch
from torch import nn, Tensor
from transformers.tokenization_utils import PreTrainedTokenizer
from flow_matching.path import ProbPath # adapter exposing .scheduler(t)
from flow_matching.solver import EditFlowsEulerSolver
from .flow import SourceDistribution
class WrappedEFModel:
"""
Thin wrapper so the solver has a stable interface:
forward(x_list, t_scalar or t_vec) -> lam_ins, logits_ins, lam_del, lam_sub, logits_sub
"""
def __init__(self, model: nn.Module) -> None:
self.model = model
@torch.no_grad()
def __call__(self, x_list: Sequence[Tensor], t: Tensor):
# Model already returns ragged lists (lam_ins, logits_ins, lam_del, lam_sub, logits_sub)
return self.model(x_t=list(x_list), time=t)
def _rows_to_ragged(x_dense: Tensor) -> List[Tensor]:
# Start from a (B, L) dense init -> ragged list of (L,)
B, L = x_dense.shape
return [x_dense[b].clone() for b in range(B)]
def _ragged_to_text(
seqs: Sequence[Tensor],
tokenizer: PreTrainedTokenizer,
) -> List[str]:
# Decode each sequence independently (no padding required)
out = []
for s in seqs:
ids = s.detach().tolist()
out.append(tokenizer.decode(ids, skip_special_tokens=False))
return out
def generate_samples(
model: nn.Module,
step: int,
vocab_size: int,
tokenizer: PreTrainedTokenizer,
rank: int,
device: torch.device,
path: ProbPath, # adapter or object exposing .scheduler(t)
source_distribution: SourceDistribution,
sample_batch_size: int,
sequence_length: int,
sampling_steps: int,
time_epsilon: float = 0.0, # not used in Option A; kept for API parity
sample_dir: Optional[Path] = None,
dtype_categorical: torch.dtype = torch.float64,
) -> List[Tensor]:
"""
EditFlows ragged generation with Euler thinning (≤1 jump per step).
Returns list[LongTensor] of final sequences.
"""
wrapped = WrappedEFModel(model=model)
# Initial sequences (dense) -> ragged
x_init_dense = source_distribution.sample(
tensor_size=(sample_batch_size, sequence_length), device=device
).long()
x_list = _rows_to_ragged(x_init_dense)
# New ragged solver
solver = EditFlowsEulerSolver(
model=wrapped,
scheduler=path.scheduler,
vocab_size=vocab_size,
dtype_categorical=dtype_categorical,
)
# Simulate from t=0 → t=1
x_final = solver.sample(
x_list=x_list,
n_steps=sampling_steps,
t0=0.0,
t1=1.0,
verbose=False,
)
# Decode to text (optional, for logging/inspection)
sentences = _ragged_to_text(x_final, tokenizer)
if sample_dir is not None:
file_name = sample_dir / f"iter_{step}" / f"sample_{rank}.txt"
file_name.parents[0].mkdir(exist_ok=True, parents=True)
with open(file_name, "w") as f:
for s in sentences:
f.write(s + "\n" + "=" * 20 + " New sample " + "=" * 20 + "\n")
return x_final

Xet Storage Details

Size:
3.2 kB
·
Xet hash:
03ee14d20397508c9203ed4b37eb05a485d33a39c0d2fbcf105ede7bafa2d0f5

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.