StarpowerTechnology's picture
Upload 31 files
262eb2c verified
Raw History Blame Contribute Delete
3.32 kB
from __future__ import annotations
import argparse
import json
import math
from pathlib import Path
from transformers import AutoTokenizer
from .data import discover_files, iter_documents
def parser() -> argparse.ArgumentParser:
value = argparse.ArgumentParser(description="Scan training data and count its tokens")
value.add_argument("--data", required=True, help="File or directory containing training data")
value.add_argument("--tokenizer", default="assets/tokenizer", help="Local tokenizer path or Hub ID")
value.add_argument("--text-field", default="text", help="Text column in structured files")
value.add_argument("--max-documents", type=int, default=0, help="Stop after N documents; 0 scans all")
value.add_argument("--min-parameters", type=int, default=1_000_000)
value.add_argument("--max-parameters", type=int, default=50_000_000)
value.add_argument("--tokens-per-parameter", type=float, default=20.0)
value.add_argument("--output", default="artifacts/data_report.json")
return value
def scan(args: argparse.Namespace) -> dict:
files = discover_files(args.data)
tokenizer = AutoTokenizer.from_pretrained(args.tokenizer, use_fast=True)
documents = characters = bytes_total = tokens = 0
minimum = math.inf
maximum = 0
for text in iter_documents(files, args.text_field):
count = len(tokenizer.encode(text, add_special_tokens=False))
documents += 1
characters += len(text)
bytes_total += len(text.encode("utf-8"))
tokens += count
minimum = min(minimum, count)
maximum = max(maximum, count)
if args.max_documents and documents >= args.max_documents:
break
if documents == 0:
raise ValueError("The scan found no non-empty documents")
raw_target = round(tokens / args.tokens_per_parameter)
suggested = min(args.max_parameters, max(args.min_parameters, raw_target))
report = {
"data_path": str(Path(args.data).expanduser().resolve()),
"files": len(files),
"documents_scanned": documents,
"characters": characters,
"utf8_bytes": bytes_total,
"tokens": tokens,
"tokens_per_document": tokens / documents,
"minimum_document_tokens": int(minimum),
"maximum_document_tokens": maximum,
"tokenizer": args.tokenizer,
"tokenizer_vocab_size": len(tokenizer),
"target_rule": {
"tokens_per_parameter": args.tokens_per_parameter,
"unclamped_parameters": raw_target,
"minimum_parameters": args.min_parameters,
"maximum_parameters": args.max_parameters,
"suggested_parameters": suggested,
"status": "inside_range" if raw_target == suggested else "clamped_to_requested_range"
},
"warning": "The token-to-parameter value is a planning input, not a proven LiquidWVY scaling law. Change --tokens-per-parameter for your compute and reuse goals."
}
destination = Path(args.output)
destination.parent.mkdir(parents=True, exist_ok=True)
destination.write_text(json.dumps(report, indent=2) + "\n", encoding="utf-8")
return report
def main() -> None:
args = parser().parse_args()
print(json.dumps(scan(args), indent=2))
if __name__ == "__main__":
main()