smartcore-v1 / code /kod /faz1_01_tokenize_shard.py
kdirgul's picture
faz1_01: --n_shards/--shard_index paralelize (ds.shard, ~8x)
9db6cba verified
Raw
History Blame Contribute Delete
6.68 kB
"""
Faz 1 / Adım 1 — Pre-tokenize + parquet shard (kaynak bazlı).
Akış: HF streaming -> sc_tokenizer (SP) ile encode + EOS -> 2048'lik dizilere paketle
(doc sınırları arası carry-over) -> ~256MB parquet shard'lar + manifest.json.
Mixture EĞİTİMDE uygulanır; shard'lar source/lang etiketli tutulur.
Kaynaklar (--source):
en_fineweb_edu : HuggingFaceFW/fineweb-edu (sample-10BT) lang=en
tr_fineweb2_hq : epfml/FineWeb2-HQ (tur_Latn) lang=tr
tr_tc100b : lumees/turkish-corpus-100b (data_dir=pretrain, ~103B, Apache) lang=tr [v1.5b ANA TR]
Kullanım:
python kod/faz1_01_tokenize_shard.py --source en_fineweb_edu --target_tokens 5_000_000 --seqs_per_shard 1500
"""
import os, sys, json, time, argparse
os.environ["HF_HUB_DISABLE_SYMLINKS_WARNING"] = "1"
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
import pyarrow as pa
import pyarrow.parquet as pq
from datasets import load_dataset
from sc_tokenizer import SCTokenizer
from decontam import Decontaminator
SOURCES = {
"en_fineweb_edu": ("HuggingFaceFW/fineweb-edu", "sample-10BT", "en"),
"tr_fineweb2_hq": ("epfml/FineWeb2-HQ", "tur_Latn", "tr"),
# v1.5b ANA TR: TC-100B (~103B, Apache, FineWeb-2-TR+Cosmos-sentetik+TR-Wiki+haber+math). 4. eleman = data_dir.
"tr_tc100b": ("lumees/turkish-corpus-100b", None, "tr", "pretrain"),
# NOT: StarCoder2/the-stack gate'li, datasets 4.x script kaynaklarını desteklemiyor.
# codeparrot-clean (ham Python, content kolonu) gate'siz ikamesi.
"code_codeparrot": ("codeparrot/codeparrot-clean", None, "code"),
"math_openwebmath": ("open-web-math/open-web-math", None, "math"),
}
# içerik kolonu önceliği (codeparrot=content, owm/fineweb=text)
TEXT_KEYS = ("text", "content", "code")
def text_of(rec):
for k in TEXT_KEYS:
v = rec.get(k)
if isinstance(v, str) and v:
return v
for v in rec.values():
if isinstance(v, str) and len(v) > 0:
return v
return ""
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--source", required=True, choices=list(SOURCES))
ap.add_argument("--target_tokens", type=lambda x: int(float(x)), default=5_000_000) # 5e7/7.5e9 kabul
ap.add_argument("--seq_len", type=int, default=2048)
ap.add_argument("--seqs_per_shard", type=int, default=32768) # ~256MB @2048 int32
ap.add_argument("--out_dir", default="kod/data/shards")
ap.add_argument("--decontam", default="kod/data/decontam_13gram.pkl.gz",
help="13-gram index; yoksa filtre atlanır")
ap.add_argument("--n_shards", type=int, default=1, help="paralel worker sayısı (ds.shard ile parça böl)")
ap.add_argument("--shard_index", type=int, default=0, help="bu worker'ın parça indeksi (0..n_shards-1)")
args = ap.parse_args()
src = SOURCES[args.source]
repo, cfg, lang = src[0], src[1], src[2]
data_dir = src[3] if len(src) > 3 else None # dizin-yapılı dataset (TC-100B: pretrain/)
outdir = os.path.join(args.out_dir, args.source)
if args.n_shards > 1: # paralel: her worker kendi alt-dizinine yazar (çakışma yok)
outdir = os.path.join(outdir, f"w{args.shard_index:02d}")
os.makedirs(outdir, exist_ok=True)
per_target = args.target_tokens // max(1, args.n_shards) # worker başına hedef
tok = SCTokenizer()
dec = None
if args.decontam and os.path.exists(args.decontam):
dec = Decontaminator.load(args.decontam)
print(f"[decontam] {len(dec.grams):,} adet 13-gram yüklendi → kontamine doc'lar atlanacak")
else:
print("[decontam] index yok → filtre KAPALI (uyarı: eval sızıntısı kontrol edilmiyor)")
print(f"[{args.source} w{args.shard_index}/{args.n_shards}] repo={repo} dir={data_dir} lang={lang} "
f"| seq_len={args.seq_len} | hedef ~{per_target/1e6:.1f}M token | vocab={tok.vocab_size}")
ds = load_dataset(repo, name=cfg, data_dir=data_dir, split="train", streaming=True)
if args.n_shards > 1:
ds = ds.shard(num_shards=args.n_shards, index=args.shard_index) # bu worker'a düşen parçalar
buf, seqs, shard_idx = [], [], 0
tot_tokens = tot_seqs = ndocs = n_skip = 0
manifest = {"source": args.source, "repo": repo, "config": cfg, "data_dir": data_dir, "lang": lang,
"seq_len": args.seq_len, "shards": []}
t0 = time.perf_counter()
def flush():
nonlocal seqs, shard_idx, tot_seqs
if not seqs:
return
fn = f"shard_{shard_idx:05d}.parquet"
table = pa.table({
# uint16: token id < 48000 < 65535 → diski/upload'ı yarıya indirir (int32 yerine)
"input_ids": pa.array(seqs, type=pa.list_(pa.uint16())),
"source": pa.array([args.source] * len(seqs)),
"lang": pa.array([lang] * len(seqs)),
})
pq.write_table(table, os.path.join(outdir, fn), compression="zstd")
manifest["shards"].append({"file": fn, "n_seqs": len(seqs)})
tot_seqs += len(seqs)
shard_idx += 1
seqs = []
for rec in ds:
ndocs += 1
txt = text_of(rec)
if dec is not None and dec.is_contaminated(txt):
n_skip += 1
continue # eval ile örtüşen doc'u at (dekontaminasyon)
buf.extend(tok.encode(txt, add_eos=True))
while len(buf) >= args.seq_len:
seqs.append(buf[:args.seq_len]); buf = buf[args.seq_len:]
tot_tokens += args.seq_len
if len(seqs) >= args.seqs_per_shard:
flush()
if tot_tokens >= per_target:
break
if ndocs % 5000 == 0:
dt = time.perf_counter() - t0
print(f" {tot_tokens/1e6:6.2f}M tok | {ndocs} doc | {shard_idx} shard | "
f"{tot_tokens/1e6/max(1e-9,dt):.2f} M tok/s", flush=True)
flush() # kalan
manifest["n_seqs"] = tot_seqs
manifest["n_tokens"] = tot_seqs * args.seq_len
manifest["n_docs"] = ndocs
manifest["n_decontam_skipped"] = n_skip
manifest["decontam"] = bool(dec)
with open(os.path.join(outdir, "manifest.json"), "w", encoding="utf-8") as f:
json.dump(manifest, f, ensure_ascii=False, indent=2)
dt = time.perf_counter() - t0
skip_pct = 100 * n_skip / max(1, ndocs)
print(f"[{args.source}] BİTTİ: {tot_seqs} dizi × {args.seq_len} = {tot_seqs*args.seq_len/1e6:.2f}M token "
f"| {shard_idx} shard | {ndocs} doc | {dt:.0f}s ({tot_tokens/1e6/max(1e-9,dt):.2f} M tok/s)")
print(f" dekontaminasyon: {n_skip} doc atlandı ({skip_pct:.2f}%) | -> {outdir}/")
if __name__ == "__main__":
main()