""" Sample from a trained NanoDiffusionGPT checkpoint. Unlike GPT sampling, this does not append one token at a time. It creates a fixed number of [MASK] tokens after the prompt and denoises them in parallel. """ import os import pickle from contextlib import nullcontext import torch from model import NanoDiffusionGPT, NanoDiffusionGPTConfig # ----------------------------------------------------------------------------- out_dir = "out-diffusion" start = "\n" num_samples = 5 max_new_tokens = 300 steps = 128 temperature = 0.8 top_k = 20 seed = 1337 device = "cuda" dtype = "bfloat16" if torch.cuda.is_available() and torch.cuda.is_bf16_supported() else "float16" compile = False if os.path.exists("configurator.py"): exec(open("configurator.py").read()) # ----------------------------------------------------------------------------- torch.manual_seed(seed) if torch.cuda.is_available(): torch.cuda.manual_seed(seed) torch.backends.cuda.matmul.allow_tf32 = True torch.backends.cudnn.allow_tf32 = True device_type = "cuda" if "cuda" in device else "cpu" ptdtype = {"float32": torch.float32, "bfloat16": torch.bfloat16, "float16": torch.float16}[dtype] ctx = nullcontext() if device_type == "cpu" else torch.amp.autocast(device_type=device_type, dtype=ptdtype) ckpt_path = os.path.join(out_dir, "ckpt.pt") checkpoint = torch.load(ckpt_path, map_location=device) model = NanoDiffusionGPT(NanoDiffusionGPTConfig(**checkpoint["model_args"])) state_dict = checkpoint["model"] unwanted_prefix = "_orig_mod." for k, v in list(state_dict.items()): if k.startswith(unwanted_prefix): state_dict[k[len(unwanted_prefix) :]] = state_dict.pop(k) model.load_state_dict(state_dict) model.eval() model.to(device) if compile: model = torch.compile(model) raw_model = model._orig_mod if hasattr(model, "_orig_mod") else model dataset = checkpoint["config"]["dataset"] meta_path = os.path.join("data", dataset, "meta.pkl") if not os.path.exists(meta_path): meta_path = os.path.join(out_dir, "meta.pkl") if not os.path.exists(meta_path): meta_path = "meta.pkl" print(f"Loading meta from {meta_path}...") with open(meta_path, "rb") as f: meta = pickle.load(f) stoi, itos = meta["stoi"], meta["itos"] def encode(s): return [stoi[c] for c in s if c in stoi] def decode(ids): return "".join(itos[i] for i in ids if i in itos) if start.startswith("FILE:"): with open(start[5:], "r", encoding="utf-8") as f: start = f.read() start_ids = encode(start) if not start_ids: raise ValueError("prompt has no characters that exist in the dataset vocabulary") if len(start_ids) + max_new_tokens > raw_model.config.block_size: raise ValueError( f"prompt length ({len(start_ids)}) + max_new_tokens ({max_new_tokens}) " f"exceeds block_size ({raw_model.config.block_size})" ) x = torch.tensor(start_ids, dtype=torch.long, device=device)[None, ...] with torch.no_grad(): with ctx: for k in range(num_samples): y = model.generate( x, max_new_tokens=max_new_tokens, steps=steps, temperature=temperature, top_k=top_k, ) print(decode(y[0].tolist())) print("---------------")