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