ys / generate.py
AmauryLC's picture
Publication initiale de Ys et de sa fiche
eefb08d verified
Raw History Blame Contribute Delete
2.68 kB
import argparse
import json
from pathlib import Path
import torch
import tiktoken
from safetensors.torch import load_file
from modeling_ys import GPTModel
TOKENIZER_VOCAB_SIZE = 50257
END_OF_TEXT_ID = 50256
def main():
parser = argparse.ArgumentParser(description="Génère du texte avec Ys.")
parser.add_argument("--prompt", default="Il était une fois")
parser.add_argument("--max-new-tokens", type=int, default=120)
parser.add_argument("--temperature", type=float, default=0.8,
help="0 pour choisir le token le plus probable")
parser.add_argument("--top-k", type=int, default=40,
help="0 pour désactiver le filtrage top-k")
parser.add_argument("--device", choices=("auto", "cpu", "cuda"), default="auto")
args = parser.parse_args()
repo_dir = Path(__file__).resolve().parent
config = json.loads((repo_dir / "config.json").read_text(encoding="utf-8"))
device = args.device
if device == "auto":
device = "cuda" if torch.cuda.is_available() else "cpu"
if device == "cuda" and not torch.cuda.is_available():
raise SystemExit("CUDA n'est pas disponible. Relance avec --device cpu.")
if args.temperature < 0:
raise SystemExit("--temperature doit être positif ou égal à 0.")
model = GPTModel(config)
state_dict = load_file(str(repo_dir / "model.safetensors"), device="cpu")
model.load_state_dict(state_dict, strict=True)
model.to(device).eval()
tokenizer = tiktoken.get_encoding("gpt2")
token_ids = torch.tensor([tokenizer.encode(args.prompt)], dtype=torch.long, device=device)
if token_ids.shape[1] == 0:
token_ids = torch.tensor([[END_OF_TEXT_ID]], dtype=torch.long, device=device)
for _ in range(args.max_new_tokens):
context = token_ids[:, -config["context_length"]:]
with torch.inference_mode():
logits = model(context)[:, -1, :TOKENIZER_VOCAB_SIZE]
if args.temperature == 0:
next_id = torch.argmax(logits, dim=-1, keepdim=True)
else:
logits = logits / args.temperature
if 0 < args.top_k < logits.shape[-1]:
threshold = torch.topk(logits, args.top_k, dim=-1).values[:, -1, None]
logits = logits.masked_fill(logits < threshold, float("-inf"))
probabilities = torch.softmax(logits, dim=-1)
next_id = torch.multinomial(probabilities, num_samples=1)
if next_id.item() == END_OF_TEXT_ID:
break
token_ids = torch.cat((token_ids, next_id), dim=1)
print(tokenizer.decode(token_ids[0].tolist()))
if __name__ == "__main__":
main()