Clean tokenizer swap migration

This commit is contained in:
Codex
2026-06-18 10:10:57 +00:00
commit 5d1e9c4bc3
37 changed files with 9574 additions and 0 deletions
+98
View File
@@ -0,0 +1,98 @@
# Dataset Building
This folder owns all dataset construction for the migration: SFT data, CPT data, and the public heldout validation/evaluation set.
It does not build model weights and does not run training.
## Inputs
The builders expect raw or intermediate source data outside the git repo, such as FineWeb/FineWeb-Edu shards, BAAI/CCI3-HQ Chinese data, StarCoder/code data, OpenWebMath-derived data, science reasoning caches, and instruction QA mixes.
Tokenizer paths are configurable with CLI flags. Generated data should be written under:
```text
dataset_building/generated/
```
That directory is ignored by git.
## Kept Dataset
Only the latest public heldout 2K set is versioned here:
```text
heldout_public_mcq_2k_20260607/heldout_public_mcq_2k.jsonl
heldout_public_mcq_2k_20260607/heldout_public_mcq_2k_stats.json
```
Older in-domain heldout and earlier ratio-imbalanced 2K heldout datasets are intentionally not included.
## SFT Builders
Main scripts:
```text
build_training_and_test_mix_v3.py
build_dsv4_chat_tokenized_messages_jsonl.py
build_dsv4_chat_tokenized_custom.py
```
Expected final generated layout:
```text
dataset_building/generated/dsv4_chat_tokenized_v4_noupsample_nobbh_921k/
train_dsv4_chat_tokenized.jsonl.gz
validation_dsv4_chat_tokenized.jsonl.gz
```
Build metadata from the final SFT recipe is kept in:
```text
metadata/sft_v4_mix_build_stats.json
metadata/sft_v4_tokenization_build_stats.json
```
## CPT Builders
Main scripts:
```text
build_cpt_docmix_1b.py
build_cpt_packed_stratified.py
build_cpt_packed_5b_stratified.py
build_cci3_chinese_docmix_fix.py
build_math_docmix_fix.py
build_science_docmix_fix.py
```
The final CPT recipes use stratified packing with sequence length 8192 and seed 42.
Source proportions:
| Source bucket | Ratio |
|---|---:|
| English web | 25% |
| English education | 20% |
| Chinese clean | 25% |
| Code | 15% |
| Math | 10% |
| Science | 3% |
| QA as text | 2% |
Final manifests are kept in:
```text
metadata/cpt_packed_1b_seed42_stratified_manifest.json
metadata/cpt_packed_5b_seed42_stratified_manifest.json
metadata/cpt_docmix_5b_manifest.json
metadata/cpt_docmix_5b_stats.json
```
## Output Contract
Downstream training expects either:
- tokenized SFT `.jsonl.gz` files for `train_dsv4_tokenized_full_sft.py`
- packed CPT arrays/manifests for `train_cpt_packed_full.py`
Do not commit generated `.jsonl.gz`, `.npy`, `.parquet`, or other large intermediate files.
+173
View File
@@ -0,0 +1,173 @@
#!/usr/bin/env python3
import argparse
import gzip
import json
import os
import re
import time
from collections import Counter
from pathlib import Path
from huggingface_hub import HfApi, hf_hub_download
from transformers import AutoTokenizer
def clean_text(text):
if text is None:
return ""
text = str(text).replace("\x00", " ")
text = re.sub(r"[ \t\r\f\v]+", " ", text)
text = re.sub(r"\n{4,}", "\n\n\n", text)
return text.strip()
def iter_jsonl(path):
with open(path, "r", encoding="utf-8", errors="replace") as f:
for line in f:
line = line.strip()
if not line:
continue
try:
yield json.loads(line)
except json.JSONDecodeError:
continue
def download_with_retry(filename, args):
last = None
for attempt in range(1, args.retries + 1):
try:
return hf_hub_download(
repo_id=args.repo,
repo_type="dataset",
filename=filename,
endpoint=args.endpoint,
token=os.environ.get("HF_TOKEN"),
local_dir=args.raw_dir,
)
except Exception as exc:
last = exc
print(json.dumps({"event": "download_retry", "file": filename, "attempt": attempt, "error": repr(exc)[:800]}, ensure_ascii=False), flush=True)
time.sleep(min(120, 5 * attempt))
raise RuntimeError(f"download failed for {filename}: {last!r}")
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--repo", default="BAAI/CCI3-HQ")
ap.add_argument("--endpoint", default=os.environ.get("HF_ENDPOINT", "https://hf-mirror.com"))
ap.add_argument("--tokenizer", default="model_building/generated_models/Qwen3-0.6B-DSV4-tokenizer-remap-v2")
ap.add_argument("--raw-dir", default="data/raw_jsonl/cci3_hq_probe")
ap.add_argument("--out-dir", default="data/cpt_docmix_5b_sources_8192_20260614")
ap.add_argument("--target-tokens", type=int, default=1_250_000_000)
ap.add_argument("--min-tokens", type=int, default=128)
ap.add_argument("--max-doc-tokens", type=int, default=32768)
ap.add_argument("--log-every", type=int, default=5000)
ap.add_argument("--retries", type=int, default=16)
ap.add_argument("--start-index", type=int, default=0)
ap.add_argument("--keep-raw", action="store_true")
args = ap.parse_args()
base = Path.cwd()
raw_dir = base / args.raw_dir
out_dir = base / args.out_dir
doc_dir = out_dir / "documents"
doc_dir.mkdir(parents=True, exist_ok=True)
raw_dir.mkdir(parents=True, exist_ok=True)
token = os.environ.get("HF_TOKEN")
if not token:
raise SystemExit("HF_TOKEN is required for gated CCI3-HQ")
api = HfApi(endpoint=args.endpoint, token=token)
files = [f for f in api.list_repo_files(args.repo, repo_type="dataset") if f.startswith("data/part_") and f.endswith(".jsonl")]
files = sorted(files)
if args.start_index:
files = [f for f in files if int(Path(f).stem.split("_")[-1]) >= args.start_index]
tok = AutoTokenizer.from_pretrained(base / args.tokenizer, trust_remote_code=True)
tmp_out = doc_dir / "chinese_clean.jsonl.gz.tmp"
final_out = doc_dir / "chinese_clean.jsonl.gz"
if tmp_out.exists():
tmp_out.unlink()
stats = {
"target_tokens": args.target_tokens,
"tokens": 0,
"docs": 0,
"rows_seen": 0,
"files_done": [],
"tokens_by_file": Counter(),
"rejected": Counter(),
"started_at": time.time(),
"repo": args.repo,
"endpoint": args.endpoint,
}
with gzip.open(tmp_out, "wt", encoding="utf-8") as w:
for filename in files:
if stats["tokens"] >= args.target_tokens:
break
local_path = Path(download_with_retry(filename, args))
file_tokens = 0
file_docs = 0
for row in iter_jsonl(local_path):
stats["rows_seen"] += 1
if stats["tokens"] >= args.target_tokens:
break
text = clean_text(row.get("text") or row.get("content"))
if not text:
stats["rejected"]["empty"] += 1
continue
ntok = len(tok.encode(text, add_special_tokens=False))
if ntok < args.min_tokens:
stats["rejected"]["too_short"] += 1
continue
if ntok > args.max_doc_tokens:
stats["rejected"]["too_long"] += 1
continue
idx = stats["docs"]
rec = {
"id": f"chinese_clean_cci3_hq_{idx:09d}",
"category": "chinese_clean",
"source": f"{args.repo}:{filename}",
"text": text,
"token_count": ntok,
"metadata": {"cci3_id": row.get("id"), "cci3_score": row.get("score")},
}
w.write(json.dumps(rec, ensure_ascii=False) + "\n")
stats["docs"] += 1
stats["tokens"] += ntok
file_docs += 1
file_tokens += ntok
if stats["docs"] % args.log_every == 0:
print(json.dumps({"event": "progress", "docs": stats["docs"], "tokens": stats["tokens"], "target": args.target_tokens, "file": filename, "elapsed_sec": time.time() - stats["started_at"]}, ensure_ascii=False), flush=True)
stats["files_done"].append({"file": filename, "docs": file_docs, "tokens": file_tokens, "path": str(local_path)})
stats["tokens_by_file"][filename] += file_tokens
print(json.dumps({"event": "file_done", "file": filename, "docs": file_docs, "tokens": file_tokens, "total_tokens": stats["tokens"]}, ensure_ascii=False), flush=True)
if not args.keep_raw:
try:
local_path.unlink()
except Exception:
pass
if stats["tokens"] < args.target_tokens:
raise SystemExit(f"only collected {stats['tokens']} / {args.target_tokens} tokens")
backup = final_out.with_suffix(".jsonl.gz.failed_empty_20260614")
if final_out.exists() and final_out.stat().st_size < 1024:
final_out.replace(backup)
elif final_out.exists():
final_out.replace(final_out.with_suffix(".jsonl.gz.backup_20260614"))
tmp_out.replace(final_out)
stats["elapsed_sec"] = time.time() - stats["started_at"]
stats["tokens_by_file"] = dict(stats["tokens_by_file"])
stats["rejected"] = dict(stats["rejected"])
(out_dir / "chinese_clean_5b_fix_stats.json").write_text(json.dumps(stats, ensure_ascii=False, indent=2), encoding="utf-8")
(out_dir / ".chinese_clean_5b_ready").write_text(json.dumps({"tokens": stats["tokens"], "docs": stats["docs"], "elapsed_sec": stats["elapsed_sec"]}, ensure_ascii=False), encoding="utf-8")
print(json.dumps({"event": "done", "tokens": stats["tokens"], "docs": stats["docs"], "elapsed_sec": stats["elapsed_sec"], "output": str(final_out)}, ensure_ascii=False), flush=True)
if __name__ == "__main__":
main()
+489
View File
@@ -0,0 +1,489 @@
#!/usr/bin/env python3
import argparse
import gzip
import json
import os
import re
import time
from collections import Counter, defaultdict
from pathlib import Path
from datasets import load_dataset
from transformers import AutoTokenizer
BUDGETS = {
"english_web": 250_000_000,
"english_edu": 200_000_000,
"chinese_clean": 250_000_000,
"code": 150_000_000,
"math": 100_000_000,
"science": 30_000_000,
"qa_as_text": 20_000_000,
}
STREAM_SOURCES = {
"english_web": [
{"kind": "hf", "name": "HuggingFaceFW/fineweb", "config": "CC-MAIN-2025-26", "split": "train", "max_rows": 0},
{"kind": "hf", "name": "HuggingFaceFW/fineweb", "config": "CC-MAIN-2025-21", "split": "train", "max_rows": 0},
],
"english_edu": [
{"kind": "hf", "name": "HuggingFaceFW/fineweb-edu", "config": None, "split": "train", "max_rows": 0},
],
"chinese_clean": [
{"kind": "hf", "name": "BAAI/CCI3-HQ", "config": None, "split": "train", "max_rows": 0},
{"kind": "hf", "name": "Skywork/SkyPile-150B", "config": None, "split": "train", "max_rows": 0},
],
"code": [
{"kind": "hf", "name": "bigcode/starcoderdata", "config": None, "split": "train", "max_rows": 0},
{"kind": "hf", "name": "codeparrot/github-code", "config": None, "split": "train", "max_rows": 0},
],
"math": [
{"kind": "hf", "name": "open-web-math/open-web-math", "config": None, "split": "train", "max_rows": 0},
{"kind": "hf", "name": "GAIR/MathPile", "config": None, "split": "train", "max_rows": 0},
],
}
LOCAL_GLOBS = {
"science": [
"data/offline_text_only_reasoning_sources_20260611/science_reasoning__*.jsonl",
"data/offline_text_only_reasoning_sources_20260611/logic__*.jsonl",
],
"qa_as_text": [
"data/training_mix_v4_train1m_test2p8k_noupsample_nobbh_20260611/train_1m.jsonl",
"data/open_recovery_sft_mix_alt_sources_1m_parquet_20260607/normalized.jsonl",
],
}
LOCAL_PARQUET_GLOBS = {
"english_web": [
"data/raw_parquets/fineweb_2025/*.parquet",
],
"english_edu": [
"data/raw_parquets/fineweb_edu/*.parquet",
],
"code": [
"data/raw_parquets/starcoder/python/*.parquet",
"data/raw_parquets/starcoder/javascript/*.parquet",
"data/raw_parquets/starcoder/typescript/*.parquet",
"data/raw_parquets/starcoder/java/*.parquet",
"data/raw_parquets/starcoder/cpp/*.parquet",
"data/raw_parquets/starcoder/go/*.parquet",
"data/raw_parquets/starcoder/rust/*.parquet",
"data/raw_parquets/starcoder/shell/*.parquet",
],
}
def clean_text(text):
if text is None:
return ""
text = str(text).replace("\x00", " ")
text = re.sub(r"[ \t\r\f\v]+", " ", text)
text = re.sub(r"\n{4,}", "\n\n\n", text)
return text.strip()
def first_user_assistant(messages):
user = None
assistant = None
for msg in messages or []:
role = msg.get("role")
content = clean_text(msg.get("content"))
if not content:
continue
if role == "user" and user is None:
user = content
elif role == "assistant" and user is not None:
assistant = content
break
if user and assistant:
return user, assistant
return None, None
def qa_text(user, assistant):
if not user or not assistant:
return ""
user_label = "" if user.lstrip().lower().startswith(("question:", "problem:", "context:", "support:", "fact1:")) else "Question:\n"
assistant_label = "" if assistant.lstrip().lower().startswith(("answer:", "solution:", "final answer:", "explanation:")) else "Answer:\n"
return f"{user_label}{user}\n\n{assistant_label}{assistant}"
def extract_text(row, category, source_name):
if category == "science":
user, assistant = first_user_assistant(row.get("messages"))
if user and assistant:
return qa_text(user, assistant)
if category == "qa_as_text" or row.get("messages"):
user, assistant = first_user_assistant(row.get("messages"))
if user and assistant:
return qa_text(user, assistant)
if category == "code":
content = clean_text(row.get("content") or row.get("text") or row.get("code"))
if not content:
return ""
path = clean_text(row.get("path") or row.get("max_stars_repo_path") or row.get("repo_name") or "")
lang = clean_text(row.get("lang") or row.get("language") or "")
if path or lang:
attrs = []
if path:
attrs.append(f'path="{path[:300]}"')
if lang:
attrs.append(f'language="{lang[:80]}"')
return f"<file {' '.join(attrs)}>\n{content}\n</file>"
return content
for key in ("text", "content", "markdown", "raw_content"):
text = clean_text(row.get(key))
if text:
return text
return ""
def token_count(tok, text):
return len(tok.encode(text, add_special_tokens=False))
def open_gz_writer(path):
path.parent.mkdir(parents=True, exist_ok=True)
return gzip.open(path, "at", encoding="utf-8")
def write_doc(writer, doc_id, category, source, text, ntok, metadata=None):
writer.write(
json.dumps(
{
"id": doc_id,
"category": category,
"source": source,
"text": text,
"token_count": ntok,
"metadata": metadata or {},
},
ensure_ascii=False,
)
+ "\n"
)
def should_keep(row, category, text, ntok, args):
if ntok < args.min_tokens:
return False, "too_short"
if ntok > args.max_doc_tokens:
return False, "too_long"
if category == "english_web":
lang = row.get("language")
score = row.get("language_score")
if lang and str(lang).lower() != "en":
return False, "non_en"
if score is not None:
try:
if float(score) < args.min_fineweb_language_score:
return False, "low_language_score"
except Exception:
pass
return True, ""
def iter_local_jsonl(paths):
for path in paths:
with open(path, "r", encoding="utf-8") as f:
for line in f:
if line.strip():
yield path, json.loads(line)
def flush_pack(writer, category, source, parts, ntok, stats, args):
if not parts:
return [], 0
if ntok < args.min_tokens:
stats["rejected"][category]["pack_too_short"] += 1
return [], 0
idx = stats["docs_by_category"][category]
text = "\n\n---\n\n".join(parts)
write_doc(
writer,
f"{category}_packed_{idx:09d}",
category,
source,
text,
ntok,
{"local_path": source, "packed_items": len(parts)},
)
stats["docs_by_category"][category] += 1
stats["tokens_by_category"][category] += ntok
stats["tokens_by_source"][source] += ntok
if stats["docs_by_category"][category] % args.log_every == 0:
print_progress(stats, category)
return [], 0
def collect_local(base, tok, category, out_dir, args, stats):
paths = []
for pattern in LOCAL_GLOBS.get(category, []):
paths.extend(str(p) for p in sorted((base).glob(pattern)))
if not paths:
stats["sources"].append({"category": category, "kind": "local", "error": "no local files"})
return
out_path = out_dir / "documents" / f"{category}.jsonl.gz"
with open_gz_writer(out_path) as writer:
pack_parts = []
pack_tokens = 0
pack_source = ""
for path, row in iter_local_jsonl(paths):
if stats["tokens_by_category"][category] >= BUDGETS[category] * args.scale:
break
text = extract_text(row, category, path)
if not text:
stats["rejected"][category]["empty"] += 1
continue
ntok = token_count(tok, text)
if category == "science" and ntok < args.min_tokens:
if ntok > args.max_doc_tokens:
stats["rejected"][category]["too_long"] += 1
continue
if pack_source and pack_source != path:
pack_parts, pack_tokens = flush_pack(writer, category, pack_source, pack_parts, pack_tokens, stats, args)
pack_source = path
if pack_tokens + ntok > args.science_pack_tokens and pack_parts:
pack_parts, pack_tokens = flush_pack(writer, category, pack_source, pack_parts, pack_tokens, stats, args)
pack_parts.append(text)
pack_tokens += ntok
continue
keep, reason = should_keep(row, category, text, ntok, args)
if not keep:
stats["rejected"][category][reason] += 1
continue
if category == "science" and pack_parts:
pack_parts, pack_tokens = flush_pack(writer, category, pack_source, pack_parts, pack_tokens, stats, args)
idx = stats["docs_by_category"][category]
write_doc(writer, f"{category}_local_{idx:09d}", category, path, text, ntok, {"local_path": path})
stats["docs_by_category"][category] += 1
stats["tokens_by_category"][category] += ntok
stats["tokens_by_source"][path] += ntok
if stats["docs_by_category"][category] % args.log_every == 0:
print_progress(stats, category)
if category == "science" and pack_parts and stats["tokens_by_category"][category] < BUDGETS[category] * args.scale:
flush_pack(writer, category, pack_source, pack_parts, pack_tokens, stats, args)
def collect_local_parquet(base, tok, category, out_dir, args, stats):
try:
import pyarrow.parquet as pq
except Exception as exc:
stats["sources"].append({"category": category, "kind": "local_parquet", "error": repr(exc)})
return
paths = []
for pattern in LOCAL_PARQUET_GLOBS.get(category, []):
paths.extend(sorted(base.glob(pattern)))
if not paths:
stats["sources"].append({"category": category, "kind": "local_parquet", "error": "no parquet files"})
return
out_path = out_dir / "documents" / f"{category}.jsonl.gz"
with open_gz_writer(out_path) as writer:
for path in paths:
if stats["tokens_by_category"][category] >= BUDGETS[category] * args.scale:
break
source_label = str(path.relative_to(base))
source_rec = {"category": category, "kind": "local_parquet", "source": source_label, "rows_seen": 0, "docs_written": 0, "tokens": 0, "error": ""}
try:
pf = pq.ParquetFile(path)
for batch in pf.iter_batches(batch_size=args.parquet_batch_size):
rows = batch.to_pylist()
for row in rows:
source_rec["rows_seen"] += 1
if stats["tokens_by_category"][category] >= BUDGETS[category] * args.scale:
break
text = extract_text(row, category, source_label)
if not text:
stats["rejected"][category]["empty"] += 1
continue
ntok = token_count(tok, text)
keep, reason = should_keep(row, category, text, ntok, args)
if not keep:
stats["rejected"][category][reason] += 1
continue
idx = stats["docs_by_category"][category]
write_doc(
writer,
f"{category}_{safe_source(source_label)}_{idx:09d}",
category,
source_label,
text,
ntok,
{k: row.get(k) for k in ("url", "dump", "date", "language", "language_score", "path", "lang", "license") if k in row},
)
stats["docs_by_category"][category] += 1
stats["tokens_by_category"][category] += ntok
stats["tokens_by_source"][source_label] += ntok
source_rec["docs_written"] += 1
source_rec["tokens"] += ntok
if stats["docs_by_category"][category] % args.log_every == 0:
print_progress(stats, category)
if stats["tokens_by_category"][category] >= BUDGETS[category] * args.scale:
break
except Exception as exc:
source_rec["error"] = repr(exc)
print(json.dumps({"event": "local_parquet_error", **source_rec}, ensure_ascii=False), flush=True)
stats["sources"].append(source_rec)
def collect_stream(tok, category, out_dir, args, stats):
out_path = out_dir / "documents" / f"{category}.jsonl.gz"
with open_gz_writer(out_path) as writer:
for spec in STREAM_SOURCES.get(category, []):
if stats["tokens_by_category"][category] >= BUDGETS[category] * args.scale:
break
source_label = spec["name"] if not spec.get("config") else f"{spec['name']}:{spec['config']}"
source_rec = {"category": category, "kind": "hf_stream", "source": source_label, "rows_seen": 0, "docs_written": 0, "tokens": 0, "error": ""}
try:
ds = load_dataset(
spec["name"],
spec.get("config"),
split=spec.get("split", "train"),
streaming=True,
trust_remote_code=True,
)
for row in ds:
source_rec["rows_seen"] += 1
if spec.get("max_rows") and source_rec["rows_seen"] > spec["max_rows"]:
break
if stats["tokens_by_category"][category] >= BUDGETS[category] * args.scale:
break
text = extract_text(row, category, source_label)
if not text:
stats["rejected"][category]["empty"] += 1
continue
ntok = token_count(tok, text)
keep, reason = should_keep(row, category, text, ntok, args)
if not keep:
stats["rejected"][category][reason] += 1
continue
idx = stats["docs_by_category"][category]
write_doc(
writer,
f"{category}_{safe_source(source_label)}_{idx:09d}",
category,
source_label,
text,
ntok,
{k: row.get(k) for k in ("url", "dump", "date", "language", "language_score", "path", "lang", "license") if k in row},
)
stats["docs_by_category"][category] += 1
stats["tokens_by_category"][category] += ntok
stats["tokens_by_source"][source_label] += ntok
source_rec["docs_written"] += 1
source_rec["tokens"] += ntok
if stats["docs_by_category"][category] % args.log_every == 0:
print_progress(stats, category)
except Exception as exc:
source_rec["error"] = repr(exc)
print(json.dumps({"event": "source_error", **source_rec}, ensure_ascii=False), flush=True)
stats["sources"].append(source_rec)
def safe_source(text):
return re.sub(r"[^A-Za-z0-9._-]+", "_", text)[:120]
def print_progress(stats, category):
print(
json.dumps(
{
"event": "progress",
"category": category,
"docs": stats["docs_by_category"][category],
"tokens": stats["tokens_by_category"][category],
"target": int(BUDGETS[category] * stats["scale"]),
"elapsed_sec": time.time() - stats["start_time"],
},
ensure_ascii=False,
),
flush=True,
)
def dump_stats(out_dir, stats):
serializable = {
"scale": stats["scale"],
"budgets": {k: int(v * stats["scale"]) for k, v in BUDGETS.items()},
"tokens_by_category": dict(stats["tokens_by_category"]),
"docs_by_category": dict(stats["docs_by_category"]),
"tokens_by_source": dict(stats["tokens_by_source"].most_common()),
"rejected": {k: dict(v) for k, v in stats["rejected"].items()},
"sources": stats["sources"],
"elapsed_sec": time.time() - stats["start_time"],
}
(out_dir / "stats.json").write_text(json.dumps(serializable, ensure_ascii=False, indent=2), encoding="utf-8")
def main():
parser = argparse.ArgumentParser()
parser.add_argument("--base-dir", default="/ssd/yi/Tokenizer_Swap")
parser.add_argument("--tokenizer", default="model_building/generated_models/Qwen3-0.6B-DSV4-tokenizer-remap-v2")
parser.add_argument("--out-dir", default="data/cpt_docmix_1b_8192_20260613")
parser.add_argument("--scale", type=float, default=1.0, help="1.0 = 1B token budget; 0.001 = 1M token smoke")
parser.add_argument("--categories", default="english_web,english_edu,chinese_clean,code,math,science,qa_as_text")
parser.add_argument("--min-tokens", type=int, default=128)
parser.add_argument("--max-doc-tokens", type=int, default=32768)
parser.add_argument("--min-fineweb-language-score", type=float, default=0.65)
parser.add_argument("--log-every", type=int, default=1000)
parser.add_argument("--parquet-batch-size", type=int, default=1000)
parser.add_argument("--science-pack-tokens", type=int, default=2048)
args = parser.parse_args()
base = Path(args.base_dir)
out_dir = base / args.out_dir
out_dir.mkdir(parents=True, exist_ok=True)
(out_dir / "manifest.json").write_text(
json.dumps(
{
"tokenizer": str(base / args.tokenizer),
"budgets": {k: int(v * args.scale) for k, v in BUDGETS.items()},
"seq_len_for_later_packing": 8192,
"stream_sources": STREAM_SOURCES,
"local_globs": LOCAL_GLOBS,
"local_parquet_globs": LOCAL_PARQUET_GLOBS,
"min_tokens": args.min_tokens,
"max_doc_tokens": args.max_doc_tokens,
},
ensure_ascii=False,
indent=2,
),
encoding="utf-8",
)
tok = AutoTokenizer.from_pretrained(base / args.tokenizer, trust_remote_code=True)
stats = {
"scale": args.scale,
"start_time": time.time(),
"tokens_by_category": Counter(),
"docs_by_category": Counter(),
"tokens_by_source": Counter(),
"rejected": defaultdict(Counter),
"sources": [],
}
for category in [x.strip() for x in args.categories.split(",") if x.strip()]:
if category in LOCAL_PARQUET_GLOBS:
collect_local_parquet(base, tok, category, out_dir, args, stats)
if category in STREAM_SOURCES:
collect_stream(tok, category, out_dir, args, stats)
if category in LOCAL_GLOBS:
collect_local(base, tok, category, out_dir, args, stats)
dump_stats(out_dir, stats)
dump_stats(out_dir, stats)
print(out_dir / "stats.json")
if __name__ == "__main__":
main()
+95
View File
@@ -0,0 +1,95 @@
#!/usr/bin/env python3
import argparse, gzip, json, random, time
from pathlib import Path
import numpy as np
from transformers import AutoTokenizer
BUDGETS_1B = {
"english_web": 250_000_000,
"english_edu": 200_000_000,
"chinese_clean": 250_000_000,
"code": 150_000_000,
"math": 100_000_000,
"science": 30_000_000,
"qa_as_text": 20_000_000,
}
def open_text(path):
return gzip.open(path, "rt", encoding="utf-8") if path.suffix == ".gz" else path.open("r", encoding="utf-8")
def flush(out_dir, split, shard_idx, arrays):
if not arrays: return None
arr = np.stack(arrays, axis=0)
path = out_dir / f"{split}_{shard_idx:05d}.npy"
np.save(path, arr)
return {"path": path.name, "blocks": int(arr.shape[0]), "tokens": int(arr.size)}
def main():
ap=argparse.ArgumentParser()
ap.add_argument("--base-dir", default="/ssd/yi/Tokenizer_Swap")
ap.add_argument("--tokenizer", default="model_building/generated_models/Qwen3-0.6B-DSV4-tokenizer-remap-v2")
ap.add_argument("--docmix-dir", default="data/cpt_docmix_5b_sources_8192_20260614")
ap.add_argument("--out-dir", default="data/cpt_packed_5b_seq8192_seed42_stratified_20260614")
ap.add_argument("--scale", type=float, default=5.0)
ap.add_argument("--seq-len", type=int, default=8192)
ap.add_argument("--seed", type=int, default=42)
ap.add_argument("--eval-blocks", type=int, default=2048)
ap.add_argument("--eval-rate", type=float, default=0.01)
ap.add_argument("--shard-blocks", type=int, default=2048)
ap.add_argument("--log-every-docs", type=int, default=20000)
args=ap.parse_args()
base=Path(args.base_dir); docmix=base/args.docmix_dir; out_dir=base/args.out_dir; out_dir.mkdir(parents=True, exist_ok=True)
sources={cat: docmix/"documents"/f"{cat}.jsonl.gz" for cat in BUDGETS_1B}
missing=[str(p) for p in sources.values() if not p.exists()]
if missing: raise FileNotFoundError(missing)
budgets={k:int(v*args.scale) for k,v in BUDGETS_1B.items()}
tok=AutoTokenizer.from_pretrained(base/args.tokenizer, trust_remote_code=True); eos=tok.eos_token_id
rng=random.Random(args.seed)
total_budget=sum(budgets.values())
eval_quota={k:round(args.eval_blocks*v/total_budget) for k,v in budgets.items()}
diff=args.eval_blocks-sum(eval_quota.values())
if diff: eval_quota["english_web"] += diff
stats={"docs_seen":0,"train_blocks":0,"eval_blocks":0,"train_tokens":0,"eval_tokens":0,"source_docs":{},"source_tokens":{},"train_blocks_by_category":{},"eval_blocks_by_category":{},"leftover_tokens_by_category":{},"start_time":time.time()}
shards={"train":[],"eval":[]}; shard_idx={"train":0,"eval":0}; train_arrays=[]; eval_arrays=[]
def add_block(block, category):
if stats["eval_blocks_by_category"].get(category,0) < eval_quota.get(category,0) and rng.random() < args.eval_rate:
eval_arrays.append(block); stats["eval_blocks"] += 1; stats["eval_tokens"] += args.seq_len
stats["eval_blocks_by_category"][category]=stats["eval_blocks_by_category"].get(category,0)+1
if len(eval_arrays) >= args.shard_blocks:
rec=flush(out_dir,"eval",shard_idx["eval"],eval_arrays); shards["eval"].append(rec); shard_idx["eval"] += 1; eval_arrays.clear()
else:
train_arrays.append(block); stats["train_blocks"] += 1; stats["train_tokens"] += args.seq_len
stats["train_blocks_by_category"][category]=stats["train_blocks_by_category"].get(category,0)+1
if len(train_arrays) >= args.shard_blocks:
rec=flush(out_dir,"train",shard_idx["train"],train_arrays); shards["train"].append(rec); shard_idx["train"] += 1; train_arrays.clear()
for category,path in sources.items():
target=budgets[category]; cat_tokens=0; cat_docs=0; buffer=[]
with open_text(path) as f:
for line in f:
if cat_tokens >= target: break
if not line.strip(): continue
row=json.loads(line); text=row.get("text") or ""
if not text: continue
ids=tok.encode(text, add_special_tokens=False)
if not ids: continue
ids.append(eos)
if cat_tokens + len(ids) > target and cat_tokens > 0:
break
buffer.extend(ids); cat_tokens += len(ids); cat_docs += 1; stats["docs_seen"] += 1
stats["source_docs"][category]=cat_docs; stats["source_tokens"][category]=cat_tokens
while len(buffer) >= args.seq_len:
block=np.asarray(buffer[:args.seq_len], dtype=np.uint32); del buffer[:args.seq_len]; add_block(block, category)
if stats["docs_seen"] % args.log_every_docs == 0:
rec={k:stats[k] for k in ["docs_seen","train_blocks","eval_blocks","train_tokens","eval_tokens"]}; rec.update({"category":category,"category_tokens":cat_tokens,"elapsed_sec":time.time()-stats["start_time"]})
print(json.dumps(rec, ensure_ascii=False), flush=True)
while len(buffer) >= args.seq_len:
block=np.asarray(buffer[:args.seq_len], dtype=np.uint32); del buffer[:args.seq_len]; add_block(block, category)
stats["leftover_tokens_by_category"][category]=len(buffer)
rec=flush(out_dir,"train",shard_idx["train"],train_arrays)
if rec: shards["train"].append(rec)
rec=flush(out_dir,"eval",shard_idx["eval"],eval_arrays)
if rec: shards["eval"].append(rec)
manifest={**stats,"tokenizer":str(base/args.tokenizer),"seq_len":args.seq_len,"seed":args.seed,"scale":args.scale,"budgets":budgets,"sources":{k:str(v) for k,v in sources.items()},"eval_quota_blocks":eval_quota,"train_shards":shards["train"],"eval_shards":shards["eval"],"elapsed_sec":time.time()-stats["start_time"]}
(out_dir/"manifest.json").write_text(json.dumps(manifest, ensure_ascii=False, indent=2), encoding="utf-8")
print(out_dir/"manifest.json")
if __name__=="__main__": main()
+115
View File
@@ -0,0 +1,115 @@
#!/usr/bin/env python3
import argparse, gzip, json, random, time
from pathlib import Path
import numpy as np
from transformers import AutoTokenizer
SOURCES = {
"english_web": "data/cpt_docmix_parquet_sources_8192_20260613/documents/english_web.jsonl.gz",
"english_edu": "data/cpt_docmix_parquet_sources_8192_20260613/documents/english_edu.jsonl.gz",
"chinese_clean": "data/cpt_docmix_cci3_science_fixed_8192_20260614/documents/chinese_clean.jsonl.gz",
"code": "data/cpt_docmix_parquet_sources_8192_20260613/documents/code.jsonl.gz",
"math": "data/cpt_docmix_available_sources_8192_20260613/documents/math.jsonl.gz",
"science": "data/cpt_docmix_cci3_science_fixed_8192_20260614/documents/science.jsonl.gz",
"qa_as_text": "data/cpt_docmix_available_sources_8192_20260613/documents/qa_as_text.jsonl.gz",
}
BUDGETS = {
"english_web": 250_000_000,
"english_edu": 200_000_000,
"chinese_clean": 250_000_000,
"code": 150_000_000,
"math": 100_000_000,
"science": 30_000_000,
"qa_as_text": 20_000_000,
}
def open_text(path):
return gzip.open(path, "rt", encoding="utf-8") if path.suffix == ".gz" else path.open("r", encoding="utf-8")
def flush(out_dir, split, shard_idx, arrays):
if not arrays: return None
arr = np.stack(arrays, axis=0)
path = out_dir / f"{split}_{shard_idx:05d}.npy"
np.save(path, arr)
return {"path": path.name, "blocks": int(arr.shape[0]), "tokens": int(arr.size)}
def maybe_write_block(block, category, args, rng, eval_quota_blocks, counts, train_arrays, eval_arrays, shards, shard_idx):
# Stratified eval: each category contributes proportional eval blocks, seed fixed.
if counts["eval_blocks_by_category"].get(category, 0) < eval_quota_blocks.get(category, 0) and rng.random() < args.eval_rate:
eval_arrays.append(block)
counts["eval_blocks"] += 1
counts["eval_tokens"] += args.seq_len
counts["eval_blocks_by_category"][category] = counts["eval_blocks_by_category"].get(category, 0) + 1
if len(eval_arrays) >= args.shard_blocks:
rec = flush(args.out_dir_path, "eval", shard_idx["eval"], eval_arrays)
shards["eval"].append(rec); shard_idx["eval"] += 1; eval_arrays.clear()
else:
train_arrays.append(block)
counts["train_blocks"] += 1
counts["train_tokens"] += args.seq_len
counts["train_blocks_by_category"][category] = counts["train_blocks_by_category"].get(category, 0) + 1
if len(train_arrays) >= args.shard_blocks:
rec = flush(args.out_dir_path, "train", shard_idx["train"], train_arrays)
shards["train"].append(rec); shard_idx["train"] += 1; train_arrays.clear()
def main():
ap=argparse.ArgumentParser()
ap.add_argument("--base-dir", default="/ssd/yi/Tokenizer_Swap")
ap.add_argument("--tokenizer", default="model_building/generated_models/Qwen3-0.6B-DSV4-tokenizer-remap-v2")
ap.add_argument("--out-dir", default="data/cpt_packed_1b_seq8192_seed42_stratified_20260614")
ap.add_argument("--seq-len", type=int, default=8192)
ap.add_argument("--seed", type=int, default=42)
ap.add_argument("--eval-blocks", type=int, default=1024)
ap.add_argument("--eval-rate", type=float, default=0.02)
ap.add_argument("--shard-blocks", type=int, default=2048)
ap.add_argument("--log-every-docs", type=int, default=10000)
args=ap.parse_args()
base=Path(args.base_dir); out_dir=base/args.out_dir; out_dir.mkdir(parents=True, exist_ok=True)
args.out_dir_path=out_dir
tok=AutoTokenizer.from_pretrained(base/args.tokenizer, trust_remote_code=True)
eos=tok.eos_token_id
total_budget=sum(BUDGETS.values())
eval_quota={k: round(args.eval_blocks*v/total_budget) for k,v in BUDGETS.items()}
diff=args.eval_blocks-sum(eval_quota.values())
if diff:
eval_quota["english_web"] += diff
rng=random.Random(args.seed)
counts={"docs_seen":0,"train_blocks":0,"eval_blocks":0,"train_tokens":0,"eval_tokens":0,"source_docs":{},"source_tokens":{},"train_blocks_by_category":{},"eval_blocks_by_category":{},"start_time":time.time()}
shards={"train":[],"eval":[]}; shard_idx={"train":0,"eval":0}
train_arrays=[]; eval_arrays=[]
for category,path_s in SOURCES.items():
path=base/path_s
target=BUDGETS[category]
cat_tokens=0; cat_docs=0; buffer=[]
with open_text(path) as f:
for line in f:
if cat_tokens >= target: break
if not line.strip(): continue
row=json.loads(line); text=row.get("text") or ""
if not text: continue
ids=tok.encode(text, add_special_tokens=False)
if not ids: continue
ids.append(eos)
if cat_tokens + len(ids) > target and cat_tokens > 0:
# Keep category budgets tight; do not substantially overshoot.
break
buffer.extend(ids); cat_tokens += len(ids); cat_docs += 1; counts["docs_seen"] += 1
counts["source_docs"][category]=cat_docs; counts["source_tokens"][category]=cat_tokens
while len(buffer) >= args.seq_len:
block=np.asarray(buffer[:args.seq_len], dtype=np.uint32); del buffer[:args.seq_len]
maybe_write_block(block, category, args, rng, eval_quota, counts, train_arrays, eval_arrays, shards, shard_idx)
if counts["docs_seen"] % args.log_every_docs == 0:
rec={k:counts[k] for k in ["docs_seen","train_blocks","eval_blocks","train_tokens","eval_tokens"]}; rec["category"]=category; rec["category_tokens"]=cat_tokens; rec["elapsed_sec"]=time.time()-counts["start_time"]
print(json.dumps(rec, ensure_ascii=False), flush=True)
while len(buffer) >= args.seq_len:
block=np.asarray(buffer[:args.seq_len], dtype=np.uint32); del buffer[:args.seq_len]
maybe_write_block(block, category, args, rng, eval_quota, counts, train_arrays, eval_arrays, shards, shard_idx)
counts.setdefault("leftover_tokens_by_category", {})[category]=len(buffer)
rec=flush(out_dir,"train",shard_idx["train"],train_arrays)
if rec: shards["train"].append(rec)
rec=flush(out_dir,"eval",shard_idx["eval"],eval_arrays)
if rec: shards["eval"].append(rec)
manifest={**counts,"tokenizer":str(base/args.tokenizer),"seq_len":args.seq_len,"seed":args.seed,"budgets":BUDGETS,"sources":SOURCES,"eval_quota_blocks":eval_quota,"train_shards":shards["train"],"eval_shards":shards["eval"],"elapsed_sec":time.time()-counts["start_time"]}
(out_dir/"manifest.json").write_text(json.dumps(manifest, ensure_ascii=False, indent=2), encoding="utf-8")
print(out_dir/"manifest.json")
if __name__=="__main__": main()
@@ -0,0 +1,166 @@
#!/usr/bin/env python3
import argparse
import gzip
import json
import sys
from pathlib import Path
from transformers import AutoTokenizer
def import_encoding(encoding_dir: Path):
sys.path.insert(0, str(encoding_dir))
import encoding_dsv4 # type: ignore
return encoding_dsv4
def read_json(path):
return json.loads(Path(path).read_text(encoding="utf-8"))
def open_writer(path: Path):
path.parent.mkdir(parents=True, exist_ok=True)
if path.suffix == ".gz":
return gzip.open(path, "wt", encoding="utf-8")
return path.open("w", encoding="utf-8")
def quantiles(xs):
if not xs:
return {}
xs = sorted(xs)
return {
"p50": xs[int((len(xs) - 1) * 0.50)],
"p90": xs[int((len(xs) - 1) * 0.90)],
"p95": xs[int((len(xs) - 1) * 0.95)],
"p99": xs[int((len(xs) - 1) * 0.99)],
"max": xs[-1],
}
def build_split(name, src_path, out_path, tok, enc, cutoff_len):
rows = read_json(src_path)
stats = {
"split": name,
"source": str(src_path),
"output": str(out_path),
"n": len(rows),
"cutoff_len": cutoff_len,
"truncated": 0,
"prompt_tokens": [],
"response_tokens": [],
"total_tokens": [],
"eos_in_labels": 0,
"prefix_mismatch": 0,
}
with open_writer(out_path) as f:
for idx, row in enumerate(rows):
instruction = (row.get("instruction") or "").strip()
output = row.get("output") or ""
messages_prompt = [{"role": "user", "content": instruction}]
messages_full = [
{"role": "user", "content": instruction},
{"role": "assistant", "content": output},
]
prompt_text = enc.encode_messages(messages_prompt, thinking_mode="chat")
full_text = enc.encode_messages(messages_full, thinking_mode="chat")
if not full_text.startswith(prompt_text):
stats["prefix_mismatch"] += 1
prompt_ids = tok(prompt_text, add_special_tokens=False).input_ids
full_ids = tok(full_text, add_special_tokens=False).input_ids
response_ids = full_ids[len(prompt_ids) :]
labels = [-100] * len(prompt_ids) + response_ids
truncated = False
if len(full_ids) > cutoff_len:
truncated = True
full_ids = full_ids[:cutoff_len]
labels = labels[:cutoff_len]
stats["truncated"] += 1
eos_in_labels = tok.eos_token_id in [x for x in labels if x != -100]
stats["eos_in_labels"] += int(eos_in_labels)
stats["prompt_tokens"].append(len(prompt_ids))
stats["response_tokens"].append(len(response_ids))
stats["total_tokens"].append(len(prompt_ids) + len(response_ids))
out = {
"id": row.get("id", f"{name}_{idx:07d}"),
"split": name,
"source_task": row.get("task_type") or row.get("task") or row.get("category"),
"source": row.get("source"),
"thinking_mode": "chat",
"messages": messages_full,
"prompt_text": prompt_text,
"full_text": full_text,
"prompt_tokens": len(prompt_ids),
"response_tokens": len(response_ids),
"total_tokens": len(prompt_ids) + len(response_ids),
"truncated": truncated,
"eos_in_labels": eos_in_labels,
"input_ids": full_ids,
"labels": labels,
}
f.write(json.dumps(out, ensure_ascii=False) + "\n")
for key in ["prompt_tokens", "response_tokens", "total_tokens"]:
stats[key] = quantiles(stats[key])
stats["truncated_rate"] = stats["truncated"] / max(1, stats["n"])
stats["eos_label_rate"] = stats["eos_in_labels"] / max(1, stats["n"])
return stats
def main():
p = argparse.ArgumentParser()
p.add_argument("--base-dir", default="/ssd/yi/Tokenizer_Swap")
p.add_argument("--tokenizer", default="model_building/generated_models/Qwen3-0.6B-DSV4-tokenizer-remap-v2")
p.add_argument("--encoding-dir", default="external/deepseek_v4_encoding")
p.add_argument("--data-dir", required=True)
p.add_argument("--out-dir", required=True)
p.add_argument("--train-file", required=True)
p.add_argument("--validation-file", default="fixed_validation.json")
p.add_argument("--case-file", default="fixed_case.json")
p.add_argument("--cutoff-len", type=int, default=2048)
p.add_argument("--gzip", action="store_true")
args = p.parse_args()
base = Path(args.base_dir)
data_dir = base / args.data_dir
out_dir = base / args.out_dir
enc = import_encoding(base / args.encoding_dir)
tok = AutoTokenizer.from_pretrained(base / args.tokenizer, trust_remote_code=True)
suffix = ".jsonl.gz" if args.gzip else ".jsonl"
split_files = {
"train": args.train_file,
"validation": args.validation_file,
"case": args.case_file,
}
all_stats = {
"tokenizer": str(base / args.tokenizer),
"encoding_dir": str(base / args.encoding_dir),
"data_dir": str(data_dir),
"cutoff_len": args.cutoff_len,
"eos_token": tok.eos_token,
"eos_token_id": tok.eos_token_id,
"splits": {},
}
for split, filename in split_files.items():
stats = build_split(
split,
data_dir / filename,
out_dir / f"{split}_dsv4_chat_tokenized{suffix}",
tok,
enc,
args.cutoff_len,
)
all_stats["splits"][split] = stats
print(json.dumps(stats, ensure_ascii=False), flush=True)
(out_dir / "build_stats.json").write_text(json.dumps(all_stats, ensure_ascii=False, indent=2), encoding="utf-8")
print(out_dir / "build_stats.json")
if __name__ == "__main__":
main()
@@ -0,0 +1,208 @@
#!/usr/bin/env python3
import argparse
import gzip
import json
import sys
from collections import Counter
from pathlib import Path
from transformers import AutoTokenizer
def import_encoding(encoding_dir: Path):
sys.path.insert(0, str(encoding_dir))
import encoding_dsv4 # type: ignore
return encoding_dsv4
def open_reader(path: Path):
if path.suffix == ".gz":
return gzip.open(path, "rt", encoding="utf-8")
return path.open("r", encoding="utf-8")
def open_writer(path: Path):
path.parent.mkdir(parents=True, exist_ok=True)
if path.suffix == ".gz":
return gzip.open(path, "wt", encoding="utf-8")
return path.open("w", encoding="utf-8")
def quantiles(xs):
if not xs:
return {}
xs = sorted(xs)
return {
"p50": xs[int((len(xs) - 1) * 0.50)],
"p90": xs[int((len(xs) - 1) * 0.90)],
"p95": xs[int((len(xs) - 1) * 0.95)],
"p99": xs[int((len(xs) - 1) * 0.99)],
"max": xs[-1],
}
def first_user_assistant(messages):
user = None
assistant = None
for msg in messages or []:
role = msg.get("role")
content = (msg.get("content") or "").strip()
if not content:
continue
if role == "user" and user is None:
user = content
elif role == "assistant" and user is not None:
assistant = content
break
if not user or not assistant:
return None
return [
{"role": "user", "content": user},
{"role": "assistant", "content": assistant},
]
def tokenize_split(name, src_path, out_path, tok, enc, cutoff_len, max_rows):
stats = {
"split": name,
"source": str(src_path),
"output": str(out_path),
"cutoff_len": cutoff_len,
"rows_seen": 0,
"rows_written": 0,
"skipped_no_messages": 0,
"truncated": 0,
"eos_in_labels": 0,
"prefix_mismatch": 0,
"capability_counts": Counter(),
"source_counts": Counter(),
"prompt_tokens": [],
"response_tokens": [],
"total_tokens": [],
}
with open_reader(src_path) as src, open_writer(out_path) as dst:
for idx, line in enumerate(src):
if max_rows and stats["rows_written"] >= max_rows:
break
line = line.strip()
if not line:
continue
stats["rows_seen"] += 1
row = json.loads(line)
messages_full = first_user_assistant(row.get("messages"))
if not messages_full:
stats["skipped_no_messages"] += 1
continue
messages_prompt = [messages_full[0]]
prompt_text = enc.encode_messages(messages_prompt, thinking_mode="chat")
full_text = enc.encode_messages(messages_full, thinking_mode="chat")
if not full_text.startswith(prompt_text):
stats["prefix_mismatch"] += 1
prompt_ids = tok(prompt_text, add_special_tokens=False).input_ids
full_ids = tok(full_text, add_special_tokens=False).input_ids
response_ids = full_ids[len(prompt_ids) :]
labels = [-100] * len(prompt_ids) + response_ids
truncated = False
if len(full_ids) > cutoff_len:
truncated = True
full_ids = full_ids[:cutoff_len]
labels = labels[:cutoff_len]
stats["truncated"] += 1
eos_in_labels = tok.eos_token_id in [x for x in labels if x != -100]
stats["eos_in_labels"] += int(eos_in_labels)
stats["prompt_tokens"].append(len(prompt_ids))
stats["response_tokens"].append(len(response_ids))
stats["total_tokens"].append(len(prompt_ids) + len(response_ids))
stats["capability_counts"][row.get("capability") or "unknown"] += 1
stats["source_counts"][row.get("source_id") or row.get("source") or "unknown"] += 1
out = {
"id": row.get("id", f"{name}_{idx:08d}"),
"split": name,
"capability": row.get("capability"),
"source": row.get("source_id") or row.get("source"),
"thinking_mode": "chat",
"messages": messages_full,
"prompt_text": prompt_text,
"full_text": full_text,
"prompt_tokens": len(prompt_ids),
"response_tokens": len(response_ids),
"total_tokens": len(prompt_ids) + len(response_ids),
"truncated": truncated,
"eos_in_labels": eos_in_labels,
"input_ids": full_ids,
"labels": labels,
}
dst.write(json.dumps(out, ensure_ascii=False) + "\n")
stats["rows_written"] += 1
if stats["rows_written"] % 50000 == 0:
print(json.dumps({"split": name, "rows_written": stats["rows_written"]}, ensure_ascii=False), flush=True)
for key in ["prompt_tokens", "response_tokens", "total_tokens"]:
stats[key] = quantiles(stats[key])
stats["truncated_rate"] = stats["truncated"] / max(1, stats["rows_written"])
stats["eos_label_rate"] = stats["eos_in_labels"] / max(1, stats["rows_written"])
stats["capability_counts"] = dict(stats["capability_counts"].most_common())
stats["source_counts_top50"] = dict(stats["source_counts"].most_common(50))
stats.pop("source_counts")
return stats
def main():
parser = argparse.ArgumentParser()
parser.add_argument("--base-dir", default="/ssd/yi/Tokenizer_Swap")
parser.add_argument("--tokenizer", default="model_building/generated_models/Qwen3-0.6B-DSV4-tokenizer-remap-v2")
parser.add_argument("--encoding-dir", default="external/deepseek_v4_encoding")
parser.add_argument("--train-jsonl", required=True)
parser.add_argument("--eval-jsonl", required=True)
parser.add_argument("--out-dir", required=True)
parser.add_argument("--cutoff-len", type=int, default=2048)
parser.add_argument("--max-train-rows", type=int, default=0)
parser.add_argument("--max-eval-rows", type=int, default=0)
parser.add_argument("--gzip", action="store_true")
args = parser.parse_args()
base = Path(args.base_dir)
out_dir = base / args.out_dir
enc = import_encoding(base / args.encoding_dir)
tok = AutoTokenizer.from_pretrained(base / args.tokenizer, trust_remote_code=True)
suffix = ".jsonl.gz" if args.gzip else ".jsonl"
all_stats = {
"tokenizer": str(base / args.tokenizer),
"encoding_dir": str(base / args.encoding_dir),
"cutoff_len": args.cutoff_len,
"eos_token": tok.eos_token,
"eos_token_id": tok.eos_token_id,
"splits": {},
}
all_stats["splits"]["train"] = tokenize_split(
"train",
Path(args.train_jsonl),
out_dir / f"train_dsv4_chat_tokenized{suffix}",
tok,
enc,
args.cutoff_len,
args.max_train_rows,
)
all_stats["splits"]["validation"] = tokenize_split(
"validation",
Path(args.eval_jsonl),
out_dir / f"validation_dsv4_chat_tokenized{suffix}",
tok,
enc,
args.cutoff_len,
args.max_eval_rows,
)
(out_dir / "build_stats.json").write_text(json.dumps(all_stats, ensure_ascii=False, indent=2), encoding="utf-8")
print(out_dir / "build_stats.json", flush=True)
if __name__ == "__main__":
main()
+377
View File
@@ -0,0 +1,377 @@
#!/usr/bin/env python3
import argparse
import json
import os
import random
from pathlib import Path
from datasets import get_dataset_config_names, load_dataset
MMLU_DATASET = "cais/mmlu"
GPQA_DATASET = "Idavidrein/gpqa"
CEVAL_DATASET = "ceval/ceval-exam"
CMMLU_DATASET = "haonan-li/cmmlu"
MMLU_CONFIGS = [
"abstract_algebra",
"anatomy",
"astronomy",
"business_ethics",
"clinical_knowledge",
"college_biology",
"college_chemistry",
"college_computer_science",
"college_mathematics",
"college_physics",
"computer_security",
"conceptual_physics",
"econometrics",
"electrical_engineering",
"elementary_mathematics",
"formal_logic",
"global_facts",
"high_school_biology",
"high_school_chemistry",
"high_school_computer_science",
"high_school_government_and_politics",
"high_school_macroeconomics",
"high_school_mathematics",
"high_school_physics",
"high_school_statistics",
"international_law",
"jurisprudence",
"machine_learning",
"management",
"marketing",
"medical_genetics",
"moral_disputes",
"nutrition",
"philosophy",
"professional_law",
"professional_medicine",
"professional_psychology",
"public_relations",
"security_studies",
"sociology",
"us_foreign_policy",
"world_religions",
]
CEVAL_CONFIGS = [
"computer_network",
"operating_system",
"computer_architecture",
"college_programming",
"college_physics",
"college_chemistry",
"advanced_mathematics",
"probability_and_statistics",
"discrete_mathematics",
"electrical_engineer",
"metrology_engineer",
"high_school_mathematics",
"high_school_physics",
"high_school_chemistry",
"high_school_biology",
"legal_professional",
"business_administration",
"marxism",
"mao_zedong_thought",
"education_science",
"teacher_qualification",
"modern_chinese_history",
"chinese_language_and_literature",
"logic",
]
CMMLU_CONFIGS = [
"agronomy",
"anatomy",
"ancient_chinese",
"arts",
"astronomy",
"business_ethics",
"chinese_civil_service_exam",
"chinese_driving_rule",
"chinese_food_culture",
"chinese_foreign_policy",
"chinese_history",
"college_actuarial_science",
"college_education",
"college_engineering_hydrology",
"college_law",
"college_mathematics",
"college_medical_statistics",
"college_medicine",
"computer_science",
"conceptual_physics",
"econometrics",
"education",
"electrical_engineering",
"elementary_chinese",
"elementary_commonsense",
"elementary_information_and_technology",
"elementary_mathematics",
"ethnology",
"food_science",
"genetics",
"global_facts",
"high_school_biology",
"high_school_chemistry",
"high_school_geography",
"high_school_mathematics",
"high_school_physics",
"human_sexuality",
"international_law",
"journalism",
"jurisprudence",
"legal_and_moral_basis",
"logical",
"machine_learning",
"management",
"marketing",
"marxist_theory",
"modern_chinese",
"nutrition",
"philosophy",
"professional_accounting",
"professional_law",
"professional_medicine",
"professional_psychology",
"public_relations",
"security_study",
"sociology",
"sports_science",
"traditional_chinese_medicine",
"virology",
"world_history",
"world_religions",
]
def norm(text):
return " ".join(str(text or "").replace("\x00", " ").split()).strip()
def stable_sample(rng, rows, n):
if len(rows) <= n:
return list(rows)
return rng.sample(rows, n)
def add_item(items, prefix, idx, source, subset, question, choices, answer_idx, metadata=None):
question = norm(question)
choices = [norm(x) for x in choices]
if not question or len(choices) < 2:
return
if answer_idx < 0 or answer_idx >= len(choices):
return
answer_text = choices[answer_idx]
if not answer_text:
return
mcq_prompt = (
"Answer the following multiple-choice question. Choose the single best option.\n\n"
f"Question:\n{question}\n\nAnswer:"
)
ppl_text = f"Question: {question}\nCorrect answer: {answer_text}"
items.append(
{
"id": f"{prefix}_{idx:05d}",
"category": prefix,
"source": source,
"subset": subset,
"ppl_text": ppl_text,
"mcq_prompt": mcq_prompt,
"choices": choices,
"answer_idx": int(answer_idx),
"answer_text": answer_text,
"metadata": metadata or {},
}
)
def build_mmlu(rng, quota):
configs = list(MMLU_CONFIGS)
rng.shuffle(configs)
rows = []
per_config = max(20, quota // 24)
for cfg in configs:
print(f"[info] load mmlu {cfg}", flush=True)
try:
ds = load_dataset(MMLU_DATASET, cfg, split="test")
except Exception as exc:
print(f"[warn] skip MMLU {cfg}: {type(exc).__name__}: {str(exc)[:160]}")
continue
sampled = stable_sample(rng, list(ds), min(per_config, len(ds)))
for r in sampled:
rows.append((cfg, r))
if len(rows) >= quota * 2:
break
rng.shuffle(rows)
items = []
for i, (cfg, r) in enumerate(rows[:quota]):
add_item(
items,
"mmlu",
i,
MMLU_DATASET,
cfg,
r.get("question"),
r.get("choices", []),
r.get("answer"),
{"subject": r.get("subject", cfg)},
)
return items
def build_gpqa(rng, quota, config="gpqa_main"):
ds = load_dataset(GPQA_DATASET, config, split="train", token=True)
rows = stable_sample(rng, list(ds), min(quota, len(ds)))
items = []
for i, r in enumerate(rows):
choices = [
r.get("Correct Answer"),
r.get("Incorrect Answer 1"),
r.get("Incorrect Answer 2"),
r.get("Incorrect Answer 3"),
]
order = list(range(4))
rng.shuffle(order)
shuffled = [choices[j] for j in order]
answer_idx = order.index(0)
add_item(
items,
"gpqa",
i,
GPQA_DATASET,
config,
r.get("Question"),
shuffled,
answer_idx,
{
"high_level_domain": r.get("High-level domain"),
"subdomain": r.get("Subdomain"),
"record_id": r.get("Record ID"),
},
)
return items
def letter_answer_idx(ans):
if ans is None:
return -1
s = str(ans).strip()
if s in {"0", "1", "2", "3"}:
return int(s)
if s:
ch = s[0].upper()
if ch in "ABCD":
return ord(ch) - ord("A")
return -1
def build_abcd_dataset(rng, dataset_name, prefix, quota):
if prefix == "ceval":
configs = list(CEVAL_CONFIGS)
elif prefix == "cmmlu":
configs = list(CMMLU_CONFIGS)
else:
configs = get_dataset_config_names(dataset_name)
rng.shuffle(configs)
rows = []
per_config = max(24, quota // 18)
for cfg in configs:
print(f"[info] load {prefix} {cfg}", flush=True)
split = "test"
try:
ds = load_dataset(dataset_name, cfg, split=split)
except Exception:
try:
split = "val"
ds = load_dataset(dataset_name, cfg, split=split)
except Exception as exc:
print(f"[warn] skip {prefix} {cfg}: {type(exc).__name__}: {str(exc)[:160]}")
continue
sampled = stable_sample(rng, list(ds), min(per_config, len(ds)))
for r in sampled:
rows.append((cfg, split, r))
if len(rows) >= quota * 2:
break
rng.shuffle(rows)
items = []
for i, (cfg, split, r) in enumerate(rows[:quota]):
choices = [r.get("A"), r.get("B"), r.get("C"), r.get("D")]
add_item(
items,
prefix,
i,
dataset_name,
cfg,
r.get("question"),
choices,
letter_answer_idx(r.get("answer")),
{"split": split},
)
return items
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--out-dir", required=True)
ap.add_argument("--seed", type=int, default=20260607)
ap.add_argument("--mmlu", type=int, default=700)
ap.add_argument("--gpqa", type=int, default=400)
ap.add_argument("--ceval", type=int, default=450)
ap.add_argument("--cmmlu", type=int, default=450)
args = ap.parse_args()
rng = random.Random(args.seed)
out_dir = Path(args.out_dir)
out_dir.mkdir(parents=True, exist_ok=True)
print("[info] HF_ENDPOINT", os.environ.get("HF_ENDPOINT", ""))
builders = [
("mmlu", lambda: build_mmlu(rng, args.mmlu)),
("gpqa", lambda: build_gpqa(rng, args.gpqa)),
("ceval", lambda: build_abcd_dataset(rng, CEVAL_DATASET, "ceval", args.ceval)),
("cmmlu", lambda: build_abcd_dataset(rng, CMMLU_DATASET, "cmmlu", args.cmmlu)),
]
all_items = []
errors = {}
for name, fn in builders:
if getattr(args, name) <= 0:
print(f"[info] skip {name}: quota=0")
continue
try:
items = fn()
print(f"[info] built {name}: {len(items)}")
all_items.extend(items)
except Exception as exc:
errors[name] = f"{type(exc).__name__}: {str(exc)[:500]}"
print(f"[error] {name}: {errors[name]}")
rng.shuffle(all_items)
bench_path = out_dir / "heldout_public_mcq_2k.jsonl"
with bench_path.open("w", encoding="utf-8") as f:
for item in all_items:
f.write(json.dumps(item, ensure_ascii=False) + "\n")
counts = {}
for item in all_items:
counts[item["category"]] = counts.get(item["category"], 0) + 1
stats = {
"seed": args.seed,
"requested": {"mmlu": args.mmlu, "gpqa": args.gpqa, "ceval": args.ceval, "cmmlu": args.cmmlu},
"total_items": len(all_items),
"counts": counts,
"errors": errors,
"output": str(bench_path),
}
with (out_dir / "heldout_public_mcq_2k_stats.json").open("w", encoding="utf-8") as f:
json.dump(stats, f, ensure_ascii=False, indent=2)
print(json.dumps(stats, ensure_ascii=False, indent=2))
if __name__ == "__main__":
main()
+264
View File
@@ -0,0 +1,264 @@
#!/usr/bin/env python3
import argparse
import gzip
import json
import os
import re
import time
from collections import Counter
from pathlib import Path
from huggingface_hub import HfApi, hf_hub_download
from transformers import AutoTokenizer
MATHPILE_PRIORITY = [
"train/textbooks/textbooks_markdown.jsonl.gz",
"train/textbooks/synthetic_textbooks_markdown.jsonl.gz",
"train/wikipedia/wikipedia_en_mathematics_nopic_2023-08_v0.2.jsonl.gz",
"train/proofwiki/ProofWiki_definitions.jsonl.gz",
"train/proofwiki/ProofWiki_theorem_proofs.jsonl.gz",
"train/stackexchange/math.stackexchange.com.jsonl.gz",
"train/stackexchange/mathoverflow.net.jsonl.gz",
"train/stackexchange/physics.stackexchange.com.jsonl.gz",
"train/arXiv/math_arXiv_v0.2_chunk_1.jsonl.gz",
"train/arXiv/math_arXiv_v0.2_chunk_2.jsonl.gz",
"train/arXiv/math_arXiv_v0.2_chunk_3.jsonl.gz",
"train/arXiv/math_arXiv_v0.2_chunk_4.jsonl.gz",
"train/commoncrawl/C4_math_docs_chunk_0.jsonl.gz",
"train/commoncrawl/CC_math_docs_chunk_0.jsonl.gz",
]
def clean_text(text):
if text is None:
return ""
text = str(text).replace("\x00", " ")
text = re.sub(r"[ \t\r\f\v]+", " ", text)
text = re.sub(r"\n{4,}", "\n\n\n", text)
return text.strip()
def extract_text(row):
for key in ("text", "content", "markdown", "raw_content", "document"):
if isinstance(row, dict):
text = clean_text(row.get(key))
if text:
return text
return ""
def safe_source(text):
return re.sub(r"[^A-Za-z0-9._-]+", "_", text)[:120]
def download_with_retry(repo, filename, args):
last = None
for attempt in range(1, args.retries + 1):
try:
return hf_hub_download(
repo_id=repo,
repo_type="dataset",
filename=filename,
endpoint=args.endpoint,
token=os.environ.get("HF_TOKEN"),
local_dir=args.raw_dir,
)
except Exception as exc:
last = exc
print(json.dumps({"event": "download_retry", "repo": repo, "file": filename, "attempt": attempt, "error": repr(exc)[:800]}, ensure_ascii=False), flush=True)
time.sleep(min(120, 5 * attempt))
raise RuntimeError(f"download failed for {repo}:{filename}: {last!r}")
def copy_existing(existing, writer, target):
tokens = 0
docs = 0
if not existing.exists() or existing.stat().st_size < 1024:
return tokens, docs
with gzip.open(existing, "rt", encoding="utf-8", errors="replace") as f:
for line in f:
if not line.strip() or tokens >= target:
continue
try:
rec = json.loads(line)
except json.JSONDecodeError:
continue
ntok = int(rec.get("token_count") or 0)
if ntok <= 0:
continue
writer.write(json.dumps(rec, ensure_ascii=False) + "\n")
tokens += ntok
docs += 1
return tokens, docs
def iter_jsonl_gz(path):
opener = gzip.open if str(path).endswith(".gz") else open
with opener(path, "rt", encoding="utf-8", errors="replace") as f:
for line in f:
if not line.strip():
continue
try:
yield json.loads(line)
except json.JSONDecodeError:
continue
def add_jsonl_source(path, source_label, tok, writer, stats, args):
for row in iter_jsonl_gz(path):
if stats["tokens"] >= args.target_tokens:
break
text = extract_text(row)
if not text:
stats["rejected"]["empty"] += 1
continue
ntok = len(tok.encode(text, add_special_tokens=False))
if ntok < args.min_tokens:
stats["rejected"]["too_short"] += 1
continue
if ntok > args.max_doc_tokens:
stats["rejected"]["too_long"] += 1
continue
idx = stats["docs"]
writer.write(json.dumps({
"id": f"math_fix_{idx:09d}",
"category": "math",
"source": source_label,
"text": text,
"token_count": ntok,
"metadata": {k: row.get(k) for k in ("id", "url", "source", "title") if isinstance(row, dict) and k in row},
}, ensure_ascii=False) + "\n")
stats["docs"] += 1
stats["tokens"] += ntok
stats["tokens_by_source"][source_label] += ntok
if stats["docs"] % args.log_every == 0:
print(json.dumps({"event": "progress", "docs": stats["docs"], "tokens": stats["tokens"], "target": args.target_tokens, "source": source_label, "elapsed_sec": time.time() - stats["started_at"]}, ensure_ascii=False), flush=True)
def add_parquet_source(path, source_label, tok, writer, stats, args):
import pyarrow.parquet as pq
pf = pq.ParquetFile(path)
for batch in pf.iter_batches(batch_size=args.parquet_batch_size):
if stats["tokens"] >= args.target_tokens:
break
for row in batch.to_pylist():
if stats["tokens"] >= args.target_tokens:
break
text = extract_text(row)
if not text:
stats["rejected"]["empty"] += 1
continue
ntok = len(tok.encode(text, add_special_tokens=False))
if ntok < args.min_tokens:
stats["rejected"]["too_short"] += 1
continue
if ntok > args.max_doc_tokens:
stats["rejected"]["too_long"] += 1
continue
idx = stats["docs"]
writer.write(json.dumps({
"id": f"math_fix_{idx:09d}",
"category": "math",
"source": source_label,
"text": text,
"token_count": ntok,
"metadata": {k: row.get(k) for k in ("url", "date", "language", "language_score") if k in row},
}, ensure_ascii=False) + "\n")
stats["docs"] += 1
stats["tokens"] += ntok
stats["tokens_by_source"][source_label] += ntok
if stats["docs"] % args.log_every == 0:
print(json.dumps({"event": "progress", "docs": stats["docs"], "tokens": stats["tokens"], "target": args.target_tokens, "source": source_label, "elapsed_sec": time.time() - stats["started_at"]}, ensure_ascii=False), flush=True)
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--endpoint", default=os.environ.get("HF_ENDPOINT", "https://hf-mirror.com"))
ap.add_argument("--tokenizer", default="model_building/generated_models/Qwen3-0.6B-DSV4-tokenizer-remap-v2")
ap.add_argument("--raw-dir", default="data/raw_math_fix_20260614")
ap.add_argument("--out-dir", default="data/cpt_docmix_5b_sources_8192_20260614")
ap.add_argument("--target-tokens", type=int, default=500_000_000)
ap.add_argument("--min-tokens", type=int, default=128)
ap.add_argument("--max-doc-tokens", type=int, default=32768)
ap.add_argument("--log-every", type=int, default=5000)
ap.add_argument("--retries", type=int, default=16)
ap.add_argument("--parquet-batch-size", type=int, default=1000)
ap.add_argument("--keep-raw", action="store_true")
ap.add_argument("--skip-mathpile", action="store_true")
ap.add_argument("--skip-openwebmath-prefix-count", type=int, default=0)
args = ap.parse_args()
base = Path.cwd()
out_dir = base / args.out_dir
doc_dir = out_dir / "documents"
doc_dir.mkdir(parents=True, exist_ok=True)
raw_dir = base / args.raw_dir
raw_dir.mkdir(parents=True, exist_ok=True)
args.raw_dir = str(raw_dir)
tok = AutoTokenizer.from_pretrained(base / args.tokenizer, trust_remote_code=True)
final_out = doc_dir / "math.jsonl.gz"
tmp_out = doc_dir / "math.jsonl.gz.tmp"
if tmp_out.exists():
tmp_out.unlink()
stats = {"target_tokens": args.target_tokens, "tokens": 0, "docs": 0, "tokens_by_source": Counter(), "rejected": Counter(), "sources": [], "started_at": time.time()}
api = HfApi(endpoint=args.endpoint, token=os.environ.get("HF_TOKEN"))
with gzip.open(tmp_out, "wt", encoding="utf-8") as writer:
existing_tokens, existing_docs = copy_existing(final_out, writer, args.target_tokens)
stats["tokens"] += existing_tokens
stats["docs"] += existing_docs
stats["tokens_by_source"]["existing_math_docmix"] += existing_tokens
print(json.dumps({"event": "copied_existing", "docs": existing_docs, "tokens": existing_tokens}, ensure_ascii=False), flush=True)
for filename in ([] if args.skip_mathpile else MATHPILE_PRIORITY):
if stats["tokens"] >= args.target_tokens:
break
try:
local = Path(download_with_retry("GAIR/MathPile", filename, args))
before = stats["tokens"]
add_jsonl_source(local, f"GAIR/MathPile:{filename}", tok, writer, stats, args)
stats["sources"].append({"repo": "GAIR/MathPile", "file": filename, "tokens": stats["tokens"] - before})
print(json.dumps({"event": "source_done", "source": f"GAIR/MathPile:{filename}", "tokens_added": stats["tokens"] - before, "total_tokens": stats["tokens"]}, ensure_ascii=False), flush=True)
if not args.keep_raw:
try: local.unlink()
except Exception: pass
except Exception as exc:
stats["sources"].append({"repo": "GAIR/MathPile", "file": filename, "error": repr(exc)[:1000]})
print(json.dumps({"event": "source_error", "source": f"GAIR/MathPile:{filename}", "error": repr(exc)[:1000]}, ensure_ascii=False), flush=True)
if stats["tokens"] < args.target_tokens:
files = [f for f in api.list_repo_files("open-web-math/open-web-math", repo_type="dataset") if f.startswith("data/") and f.endswith(".parquet")]
for filename in sorted(files)[args.skip_openwebmath_prefix_count:]:
if stats["tokens"] >= args.target_tokens:
break
try:
local = Path(download_with_retry("open-web-math/open-web-math", filename, args))
before = stats["tokens"]
add_parquet_source(local, f"open-web-math/open-web-math:{filename}", tok, writer, stats, args)
stats["sources"].append({"repo": "open-web-math/open-web-math", "file": filename, "tokens": stats["tokens"] - before})
print(json.dumps({"event": "source_done", "source": f"open-web-math/open-web-math:{filename}", "tokens_added": stats["tokens"] - before, "total_tokens": stats["tokens"]}, ensure_ascii=False), flush=True)
if not args.keep_raw:
try: local.unlink()
except Exception: pass
except Exception as exc:
stats["sources"].append({"repo": "open-web-math/open-web-math", "file": filename, "error": repr(exc)[:1000]})
print(json.dumps({"event": "source_error", "source": f"open-web-math/open-web-math:{filename}", "error": repr(exc)[:1000]}, ensure_ascii=False), flush=True)
if stats["tokens"] < args.target_tokens:
raise SystemExit(f"only collected {stats['tokens']} / {args.target_tokens} tokens")
if final_out.exists():
final_out.replace(final_out.with_suffix(".jsonl.gz.underfilled_20260614"))
tmp_out.replace(final_out)
stats["elapsed_sec"] = time.time() - stats["started_at"]
stats["tokens_by_source"] = dict(stats["tokens_by_source"])
stats["rejected"] = dict(stats["rejected"])
(out_dir / "math_5b_fix_stats.json").write_text(json.dumps(stats, ensure_ascii=False, indent=2), encoding="utf-8")
(out_dir / ".math_5b_ready").write_text(json.dumps({"tokens": stats["tokens"], "docs": stats["docs"], "elapsed_sec": stats["elapsed_sec"]}, ensure_ascii=False), encoding="utf-8")
print(json.dumps({"event": "done", "tokens": stats["tokens"], "docs": stats["docs"], "elapsed_sec": stats["elapsed_sec"], "output": str(final_out)}, ensure_ascii=False), flush=True)
if __name__ == "__main__":
main()
+208
View File
@@ -0,0 +1,208 @@
#!/usr/bin/env python3
import argparse
import gzip
import json
import re
import time
from collections import Counter
from pathlib import Path
from transformers import AutoTokenizer
SCIENCE_KEYWORDS = re.compile(
r"\b(physics|chemistry|biology|biological|medical|medicine|clinical|anatomy|physiology|genetics|ecology|astronomy|geology|neuroscience|experiment|hypothesis|laboratory|scientific|research|disease|protein|cell|molecule|atom|energy|force|gravity|electric|magnetic|quantum|planet|star|organism|evolution|climate|weather|ecosystem|bacteria|virus|vaccine|enzyme|hormone|blood|brain|heart|lung|kidney|cancer|therapy|diagnosis)\b",
re.I,
)
def clean_text(text):
if text is None:
return ""
text = str(text).replace("\x00", " ")
text = re.sub(r"[ \t\r\f\v]+", " ", text)
text = re.sub(r"\n{4,}", "\n\n\n", text)
return text.strip()
def first_user_assistant(messages):
user = None
assistant = None
for msg in messages or []:
role = msg.get("role")
content = clean_text(msg.get("content"))
if not content:
continue
if role == "user" and user is None:
user = content
elif role == "assistant" and user is not None:
assistant = content
break
return user, assistant
def qa_text(user, assistant):
if not user or not assistant:
return ""
return f"Question:\n{user}\n\nAnswer:\n{assistant}"
def extract_row_text(row):
if isinstance(row, dict) and row.get("messages"):
u, a = first_user_assistant(row.get("messages"))
if u and a:
return qa_text(u, a)
for key in ("text", "content", "markdown", "raw_content"):
if isinstance(row, dict):
text = clean_text(row.get(key))
if text:
return text
return ""
def write_record(writer, stats, source, text, ntok, metadata=None):
idx = stats["docs"]
writer.write(json.dumps({
"id": f"science_fix_{idx:09d}",
"category": "science",
"source": source,
"text": text,
"token_count": ntok,
"metadata": metadata or {},
}, ensure_ascii=False) + "\n")
stats["docs"] += 1
stats["tokens"] += ntok
stats["tokens_by_source"][source] += ntok
def copy_existing(existing, writer, target):
tokens = docs = 0
if not existing.exists() or existing.stat().st_size < 1024:
return tokens, docs
with gzip.open(existing, "rt", encoding="utf-8", errors="replace") as f:
for line in f:
if not line.strip() or tokens >= target:
continue
try:
rec = json.loads(line)
except json.JSONDecodeError:
continue
ntok = int(rec.get("token_count") or 0)
if ntok <= 0:
continue
writer.write(json.dumps(rec, ensure_ascii=False) + "\n")
tokens += ntok
docs += 1
return tokens, docs
def add_jsonl(path, source, tok, writer, stats, args, capability_filter=None):
with open(path, "r", encoding="utf-8", errors="replace") as f:
for line in f:
if stats["tokens"] >= args.target_tokens:
break
if not line.strip():
continue
try:
row = json.loads(line)
except json.JSONDecodeError:
continue
if capability_filter and row.get("capability") not in capability_filter:
continue
text = extract_row_text(row)
if not text:
stats["rejected"]["empty"] += 1
continue
ntok = len(tok.encode(text, add_special_tokens=False))
if ntok < args.min_tokens:
stats["rejected"]["too_short"] += 1
continue
if ntok > args.max_doc_tokens:
stats["rejected"]["too_long"] += 1
continue
write_record(writer, stats, source, text, ntok, {k: row.get(k) for k in ("id", "capability", "source_id", "split") if k in row})
if stats["docs"] % args.log_every == 0:
print(json.dumps({"event": "progress", "docs": stats["docs"], "tokens": stats["tokens"], "target": args.target_tokens, "source": source, "elapsed_sec": time.time() - stats["started_at"]}, ensure_ascii=False), flush=True)
def add_fineweb_edu_parquets(paths, tok, writer, stats, args):
import pyarrow.parquet as pq
for path in paths:
if stats["tokens"] >= args.target_tokens:
break
source = f"fineweb_edu_science_supplement:{path.name}"
before = stats["tokens"]
pf = pq.ParquetFile(path)
for batch in pf.iter_batches(batch_size=args.parquet_batch_size):
if stats["tokens"] >= args.target_tokens:
break
for row in batch.to_pylist():
if stats["tokens"] >= args.target_tokens:
break
text = extract_row_text(row)
if not text or not SCIENCE_KEYWORDS.search(text[:12000]):
stats["rejected"]["not_science_like"] += 1
continue
ntok = len(tok.encode(text, add_special_tokens=False))
if ntok < args.min_tokens:
stats["rejected"]["too_short"] += 1
continue
if ntok > args.max_doc_tokens:
stats["rejected"]["too_long"] += 1
continue
write_record(writer, stats, source, text, ntok, {k: row.get(k) for k in ("url", "dump", "language", "language_score") if k in row})
if stats["docs"] % args.log_every == 0:
print(json.dumps({"event": "progress", "docs": stats["docs"], "tokens": stats["tokens"], "target": args.target_tokens, "source": source, "elapsed_sec": time.time() - stats["started_at"]}, ensure_ascii=False), flush=True)
print(json.dumps({"event": "source_done", "source": source, "tokens_added": stats["tokens"] - before, "total_tokens": stats["tokens"]}, ensure_ascii=False), flush=True)
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--tokenizer", default="model_building/generated_models/Qwen3-0.6B-DSV4-tokenizer-remap-v2")
ap.add_argument("--out-dir", default="data/cpt_docmix_5b_sources_8192_20260614")
ap.add_argument("--target-tokens", type=int, default=150_000_000)
ap.add_argument("--min-tokens", type=int, default=128)
ap.add_argument("--max-doc-tokens", type=int, default=32768)
ap.add_argument("--log-every", type=int, default=5000)
ap.add_argument("--parquet-batch-size", type=int, default=1000)
args = ap.parse_args()
base = Path.cwd()
out_dir = base / args.out_dir
doc_dir = out_dir / "documents"
final_out = doc_dir / "science.jsonl.gz"
tmp_out = doc_dir / "science.jsonl.gz.tmp"
if tmp_out.exists():
tmp_out.unlink()
tok = AutoTokenizer.from_pretrained(base / args.tokenizer, trust_remote_code=True)
stats = {"target_tokens": args.target_tokens, "tokens": 0, "docs": 0, "tokens_by_source": Counter(), "rejected": Counter(), "started_at": time.time(), "sources": []}
with gzip.open(tmp_out, "wt", encoding="utf-8") as writer:
t, d = copy_existing(final_out, writer, args.target_tokens)
stats["tokens"] += t; stats["docs"] += d; stats["tokens_by_source"]["existing_science_docmix"] += t
print(json.dumps({"event": "copied_existing", "docs": d, "tokens": t}, ensure_ascii=False), flush=True)
mix = base / "data/training_mix_v4_train1m_test2p8k_noupsample_nobbh_20260611/train_1m.jsonl"
if mix.exists() and stats["tokens"] < args.target_tokens:
before = stats["tokens"]
add_jsonl(mix, "training_mix_v4_science_logic", tok, writer, stats, args, {"science_reasoning", "logic"})
stats["sources"].append({"source": str(mix), "tokens": stats["tokens"] - before})
paths = sorted((base / "data/raw_parquets/fineweb_edu").glob("*.parquet"))
if paths and stats["tokens"] < args.target_tokens:
add_fineweb_edu_parquets(paths, tok, writer, stats, args)
if stats["tokens"] < args.target_tokens:
raise SystemExit(f"only collected {stats['tokens']} / {args.target_tokens} tokens")
if final_out.exists():
final_out.replace(final_out.with_suffix(".jsonl.gz.underfilled_20260614"))
tmp_out.replace(final_out)
stats["elapsed_sec"] = time.time() - stats["started_at"]
stats["tokens_by_source"] = dict(stats["tokens_by_source"])
stats["rejected"] = dict(stats["rejected"])
(out_dir / "science_5b_fix_stats.json").write_text(json.dumps(stats, ensure_ascii=False, indent=2), encoding="utf-8")
(out_dir / ".science_5b_ready").write_text(json.dumps({"tokens": stats["tokens"], "docs": stats["docs"], "elapsed_sec": stats["elapsed_sec"]}, ensure_ascii=False), encoding="utf-8")
print(json.dumps({"event": "done", "tokens": stats["tokens"], "docs": stats["docs"], "elapsed_sec": stats["elapsed_sec"], "output": str(final_out)}, ensure_ascii=False), flush=True)
if __name__ == "__main__":
main()
@@ -0,0 +1,745 @@
#!/usr/bin/env python3
import argparse
import copy
import csv
import hashlib
import json
import os
import random
import re
from collections import Counter, defaultdict
from pathlib import Path
from tokenizers import Tokenizer
from transformers import AutoTokenizer
GROUPS = [
"chinese_exam",
"chinese_dialogue",
"code",
"math",
"logic",
"science_reasoning",
"english_dialogue",
]
TRAIN_RATIOS = {
"chinese_exam": 0,
"chinese_dialogue": 35,
"code": 30,
"math": 20,
"logic": 5,
"science_reasoning": 5,
"english_dialogue": 5,
}
LOCAL_TRAIN_SOURCES = [
("data/open_recovery_sft_mix_alt_sources_1m_parquet_20260607/normalized.jsonl", "normalized"),
("data/open_recovery_sft_mix_100k_4_3_2_1_20260604/normalized.jsonl", "normalized"),
("data/modelscope_alt_sources_20260607/CodeAlpaca-20k.jsonl", "jsonl:code:AI-ModelScope/CodeAlpaca-20k"),
("data/modelscope_alt_sources_20260607/alpaca-gpt4-data-zh_train.csv", "csv:chinese_dialogue:AI-ModelScope/alpaca-gpt4-data-zh"),
]
HF_TRAIN_SOURCES = {
"chinese_exam": [],
"chinese_dialogue": [
{"name": "BelleGroup/train_0.5M_CN", "splits": ["train"]},
{"name": "m-a-p/COIG-CQIA", "configs": ["coig_pc", "zhihu", "wikihow"], "splits": ["train"]},
],
"code": [
{"name": "ise-uiuc/Magicoder-OSS-Instruct-75K", "splits": ["train"]},
{"name": "bigcode/self-oss-instruct-sc2-exec-filter-50k", "splits": ["train"]},
{"name": "nvidia/OpenCodeInstruct", "splits": ["train"]},
{"name": "HuggingFaceTB/smoltalk", "configs": ["self-oss-instruct", "apigen-80k"], "splits": ["train"]},
],
"math": [
{"name": "TIGER-Lab/MathInstruct", "splits": ["train"]},
{"name": "nvidia/OpenMathInstruct-2", "splits": ["train"]},
{"name": "HuggingFaceTB/smoltalk", "configs": ["numina-cot-100k", "metamathqa-50k"], "splits": ["train"]},
],
"logic": [
{"name": "metaeval/reclor", "splits": ["train", "validation"]},
{"name": "tasksource/bigbench", "configs": [
"causal_judgment",
"date_understanding",
"disambiguation_qa",
"logical_args",
"logical_deduction",
"logical_fallacy_detection",
"social_iqa",
"strategyqa",
"temporal_sequences",
], "splits": ["train"]},
{"name": "tau/commonsense_qa", "splits": ["train", "validation"]},
],
"science_reasoning": [
{"name": "allenai/ai2_arc", "configs": ["ARC-Challenge"], "splits": ["train", "validation"]},
{"name": "allenai/ai2_arc", "configs": ["ARC-Easy"], "splits": ["train", "validation"]},
{"name": "allenai/qasc", "splits": ["train", "validation"]},
{"name": "allenai/openbookqa", "configs": ["main", "additional"], "splits": ["train", "validation"]},
{"name": "sciq", "splits": ["train", "validation"]},
{"name": "qiaojin/PubMedQA", "configs": ["pqa_labeled"], "splits": ["train"]},
],
"english_dialogue": [
{"name": "HuggingFaceTB/smoltalk", "configs": ["all"], "splits": ["train"]},
{"name": "allenai/tulu-3-sft-mixture", "splits": ["train"]},
{"name": "HuggingFaceH4/ultrachat_200k", "splits": ["train_sft", "train"]},
],
}
HF_TEST_SOURCES = {
"chinese_exam": [
{"name": "ceval/ceval-exam", "configs": "all", "splits": ["val", "dev"]},
],
"chinese_dialogue": [
{"name": "BelleGroup/train_0.5M_CN", "splits": ["train"]},
{"name": "m-a-p/COIG-CQIA", "configs": ["zhihu", "wikihow", "coig_pc"], "splits": ["train"]},
],
"code": [
{"name": "openai/openai_humaneval", "splits": ["test"]},
{"name": "google-research-datasets/mbpp", "splits": ["test", "validation", "train"]},
],
"math": [
{"name": "gsm8k", "configs": ["main"], "splits": ["test"]},
{"name": "hendrycks/competition_math", "splits": ["test"]},
],
"logic": [
{"name": "metaeval/reclor", "splits": ["test", "validation"]},
{"name": "lighteval/bbh", "configs": ["logical_deduction_three_objects", "logical_deduction_five_objects", "logical_deduction_seven_objects"], "splits": ["test", "train"]},
{"name": "cais/mmlu", "configs": ["formal_logic", "logical_fallacies"], "splits": ["test", "validation", "dev"]},
],
"science_reasoning": [
{"name": "Idavidrein/gpqa", "splits": ["train"]},
{"name": "allenai/ai2_arc", "configs": ["ARC-Challenge"], "splits": ["test", "validation"]},
{"name": "sciq", "splits": ["test", "validation"]},
],
"english_dialogue": [
{"name": "HuggingFaceH4/ultrachat_200k", "splits": ["test_sft", "test", "train_sft"]},
{"name": "HuggingFaceTB/smoltalk", "configs": ["all"], "splits": ["test", "train"]},
],
}
def clean_text(x):
if x is None:
return ""
if not isinstance(x, str):
x = str(x)
x = x.replace("\r\n", "\n").replace("\r", "\n")
return re.sub(r"\n{4,}", "\n\n\n", x).strip()
def normalize_text_for_hash(text):
text = clean_text(text).lower()
return re.sub(r"\s+", " ", text)
def pair_hash(user, assistant):
payload = normalize_text_for_hash(user) + "\n\n---\n\n" + normalize_text_for_hash(assistant)
return hashlib.sha256(payload.encode("utf-8")).hexdigest()
def prompt_hash(user):
return hashlib.sha256(normalize_text_for_hash(user).encode("utf-8")).hexdigest()
def load_tokenizer(path):
try:
return AutoTokenizer.from_pretrained(path, trust_remote_code=True)
except Exception:
return Tokenizer.from_file(str(Path(path) / "tokenizer.json"))
def token_len(tok, text):
if isinstance(tok, Tokenizer):
return len(tok.encode(text, add_special_tokens=False).ids)
return len(tok(text, add_special_tokens=False)["input_ids"])
def message_content(m):
if isinstance(m, dict):
return clean_text(m.get("content") or m.get("value") or m.get("text") or "")
return clean_text(m)
def role_of(m, default):
if isinstance(m, dict):
role = (m.get("role") or m.get("from") or m.get("speaker") or default).lower()
if role in {"human", "user"}:
return "user"
if role in {"gpt", "assistant", "model"}:
return "assistant"
if role == "system":
return "system"
return default
def normalize_messages(row):
if not isinstance(row, dict):
return None
# Code generation schemas: HumanEval / MBPP-like.
if clean_text(row.get("prompt")) and clean_text(row.get("canonical_solution")):
prompt = clean_text(row.get("prompt"))
tests = clean_text(row.get("test"))
user = "Complete the following Python function.\n\n" + prompt
if tests:
user += "\n\nThe solution should pass these tests:\n" + tests
return [{"role": "user", "content": user}, {"role": "assistant", "content": clean_text(row.get("canonical_solution"))}]
if clean_text(row.get("text")) and clean_text(row.get("code")):
user = clean_text(row.get("text"))
tests = row.get("test_list")
if isinstance(tests, list) and tests:
user += "\n\nTests:\n" + "\n".join(str(x) for x in tests)
return [{"role": "user", "content": user}, {"role": "assistant", "content": clean_text(row.get("code"))}]
# BBH-like schemas.
if clean_text(row.get("input")) and isinstance(row.get("choices"), list) and row.get("target_idx") is not None:
choices_list = [clean_text(x) for x in row.get("choices") if clean_text(x)]
try:
ans_idx = int(row.get("target_idx"))
except Exception:
ans_idx = None
prefix = clean_text(row.get("task_prefix"))
prompt = (prefix + "\n\n" if prefix else "") + clean_text(row.get("input"))
if choices_list:
prompt += "\n" + "\n".join(f"{chr(ord('A') + i)}. {x}" for i, x in enumerate(choices_list))
if ans_idx is not None and 0 <= ans_idx < len(choices_list):
assistant = f"{chr(ord('A') + ans_idx)}. {choices_list[ans_idx]}"
else:
assistant = clean_text(row.get("target_idx"))
if assistant:
return [{"role": "user", "content": prompt}, {"role": "assistant", "content": assistant}]
if clean_text(row.get("input")) and clean_text(row.get("target")):
return [{"role": "user", "content": clean_text(row.get("input"))}, {"role": "assistant", "content": clean_text(row.get("target"))}]
# BIG-bench/tasksource schemas.
if clean_text(row.get("inputs")) and isinstance(row.get("targets"), list):
prompt = clean_text(row.get("inputs"))
targets = [clean_text(x) for x in row.get("targets") if clean_text(x)]
choices = [clean_text(x) for x in row.get("multiple_choice_targets") or [] if clean_text(x)]
scores = row.get("multiple_choice_scores") or []
if choices:
prompt += "\n" + "\n".join(f"{chr(ord('A') + i)}. {x}" for i, x in enumerate(choices))
answer = targets[0] if targets else ""
if choices and scores:
try:
best_idx = max(range(len(scores)), key=lambda i: scores[i])
except Exception:
best_idx = None
if best_idx is not None and 0 <= best_idx < len(choices):
answer = f"{chr(ord('A') + best_idx)}. {choices[best_idx]}"
if answer:
return [{"role": "user", "content": prompt}, {"role": "assistant", "content": answer}]
# ReClor/LogiQA-like schemas.
if clean_text(row.get("context")) and clean_text(row.get("question")) and isinstance(row.get("answers"), list):
answers = [clean_text(x) for x in row.get("answers") if clean_text(x)]
label = row.get("label")
try:
label_idx = int(label)
except Exception:
label_idx = None
prompt = clean_text(row.get("context")) + "\n\nQuestion: " + clean_text(row.get("question"))
prompt += "\n" + "\n".join(f"{chr(ord('A') + i)}. {x}" for i, x in enumerate(answers))
if label_idx is not None and 0 <= label_idx < len(answers):
assistant = f"{chr(ord('A') + label_idx)}. {answers[label_idx]}"
else:
assistant = clean_text(label)
if assistant:
return [{"role": "user", "content": prompt}, {"role": "assistant", "content": assistant}]
# GPQA-like schemas.
gpqa_question = clean_text(row.get("Question") or row.get("question"))
gpqa_correct = clean_text(row.get("Correct Answer") or row.get("correct_answer"))
if gpqa_question and gpqa_correct and any(clean_text(row.get(f"Incorrect Answer {i}")) for i in [1, 2, 3]):
choices = [gpqa_correct] + [clean_text(row.get(f"Incorrect Answer {i}")) for i in [1, 2, 3] if clean_text(row.get(f"Incorrect Answer {i}"))]
prompt = gpqa_question + "\nChoices:\n" + "\n".join(f"- {x}" for x in choices)
return [{"role": "user", "content": prompt}, {"role": "assistant", "content": gpqa_correct}]
# PubMedQA-like schemas.
if clean_text(row.get("question")) and isinstance(row.get("context"), dict) and clean_text(row.get("long_answer")):
contexts = row.get("context", {}).get("contexts") or []
context_text = "\n".join(clean_text(x) for x in contexts if clean_text(x))
prompt = clean_text(row.get("question"))
if context_text:
prompt = context_text + "\n\nQuestion: " + prompt
answer = clean_text(row.get("final_decision"))
long_answer = clean_text(row.get("long_answer"))
assistant = answer + "\n\n" + long_answer if answer else long_answer
return [{"role": "user", "content": prompt}, {"role": "assistant", "content": assistant}]
# MedMCQA-like schemas.
if clean_text(row.get("question")) and all(clean_text(row.get(k)) for k in ["opa", "opb", "opc", "opd"]) and row.get("cop") is not None:
labels = ["A", "B", "C", "D"]
values = [clean_text(row.get(k)) for k in ["opa", "opb", "opc", "opd"]]
try:
ans_idx = int(row.get("cop"))
except Exception:
ans_idx = None
prompt = clean_text(row.get("question")) + "\n" + "\n".join(f"{label}. {value}" for label, value in zip(labels, values))
if ans_idx is not None and 0 <= ans_idx < len(values):
assistant = f"{labels[ans_idx]}. {values[ans_idx]}"
else:
assistant = clean_text(row.get("cop"))
exp = clean_text(row.get("exp"))
if exp:
assistant += "\n\n" + exp
return [{"role": "user", "content": prompt}, {"role": "assistant", "content": assistant}]
# Common MCQ schemas: CEval/CMMLU, ARC, SciQ.
question = clean_text(row.get("question") or row.get("question_stem") or row.get("formatted_question"))
if question:
choices = []
answer_text = ""
explanation = clean_text(row.get("explanation") or row.get("support") or "")
for label in ["A", "B", "C", "D", "E"]:
if clean_text(row.get(label)):
choices.append((label, clean_text(row.get(label))))
if choices and clean_text(row.get("answer")):
ans = clean_text(row.get("answer")).strip()
answer_value = dict(choices).get(ans, ans)
prompt = question + "\n" + "\n".join(f"{label}. {text}" for label, text in choices)
answer_text = f"{ans}. {answer_value}"
if explanation:
answer_text += "\n\n" + explanation
return [{"role": "user", "content": prompt}, {"role": "assistant", "content": answer_text}]
# MMLU/ScienceQA-style: choices is a list and answer is an integer index.
if isinstance(row.get("choices"), list) and row.get("answer") is not None:
choices_list = [clean_text(x) for x in row.get("choices") if clean_text(x)]
try:
ans_idx = int(row.get("answer"))
except Exception:
ans_idx = None
prompt_parts = [question]
hint = clean_text(row.get("hint"))
lecture = clean_text(row.get("lecture"))
solution = clean_text(row.get("solution"))
if hint:
prompt_parts.append("Hint: " + hint)
prompt_parts.append("\n".join(f"{chr(ord('A') + i)}. {x}" for i, x in enumerate(choices_list)))
prompt = "\n\n".join(x for x in prompt_parts if x)
if ans_idx is not None and 0 <= ans_idx < len(choices_list):
assistant = f"{chr(ord('A') + ans_idx)}. {choices_list[ans_idx]}"
else:
assistant = clean_text(row.get("answer"))
extra = "\n\n".join(x for x in [lecture, solution] if x)
if assistant and extra:
assistant += "\n\n" + extra
if assistant:
return [{"role": "user", "content": prompt}, {"role": "assistant", "content": assistant}]
arc_choices = row.get("choices")
if isinstance(arc_choices, dict) and arc_choices.get("text") and row.get("answerKey"):
labels = arc_choices.get("label") or [chr(ord("A") + i) for i in range(len(arc_choices["text"]))]
choices = list(zip(labels, arc_choices["text"]))
ans = clean_text(row.get("answerKey"))
answer_value = dict(choices).get(ans, ans)
prompt = question + "\n" + "\n".join(f"{label}. {text}" for label, text in choices)
facts = [clean_text(row.get(k)) for k in ["combinedfact", "fact1", "fact2"] if clean_text(row.get(k))]
assistant = f"{ans}. {answer_value}"
if facts:
assistant += "\n\n" + "\n".join(facts)
return [{"role": "user", "content": prompt}, {"role": "assistant", "content": assistant}]
if row.get("correct_answer"):
distractors = [clean_text(row.get(k)) for k in ["distractor1", "distractor2", "distractor3"] if clean_text(row.get(k))]
prompt = question
if distractors:
all_choices = distractors + [clean_text(row.get("correct_answer"))]
prompt += "\nChoices:\n" + "\n".join(f"- {x}" for x in all_choices)
answer_text = clean_text(row.get("correct_answer"))
if explanation:
answer_text += "\n\n" + explanation
return [{"role": "user", "content": prompt}, {"role": "assistant", "content": answer_text}]
for key in ("messages", "conversations", "conversation"):
val = row.get(key)
if isinstance(val, list) and len(val) >= 2:
out = []
for i, m in enumerate(val):
content = message_content(m)
role = role_of(m, "user" if i % 2 == 0 else "assistant")
if content:
out.append({"role": role, "content": content})
if any(m["role"] == "user" for m in out) and any(m["role"] == "assistant" for m in out):
return out
prompt = clean_text(row.get("instruction") or row.get("prompt") or row.get("question") or row.get("problem") or row.get("query") or row.get("input"))
if clean_text(row.get("instruction")) and clean_text(row.get("input")):
prompt = clean_text(row.get("instruction")) + "\n\n" + clean_text(row.get("input"))
answer = clean_text(row.get("response") or row.get("output") or row.get("answer") or row.get("solution") or row.get("completion") or row.get("target") or row.get("label"))
if not answer and isinstance(row.get("choices"), list) and row.get("answer") is not None:
try:
answer = str(row["choices"][int(row["answer"])])
except Exception:
answer = clean_text(row.get("answer"))
if prompt and answer:
return [{"role": "user", "content": prompt}, {"role": "assistant", "content": answer}]
return None
def first_user_assistant(messages):
system_parts = []
user = None
assistant = None
for m in messages:
if m.get("role") == "system" and m.get("content"):
system_parts.append(m["content"])
elif m.get("role") == "user" and user is None:
user = m.get("content", "")
elif m.get("role") == "assistant" and user is not None:
assistant = m.get("content", "")
break
if not user or not assistant:
return None, None
if system_parts:
user = "System context:\n" + "\n\n".join(system_parts) + "\n\nUser request:\n" + user
return clean_text(user), clean_text(assistant)
def infer_local_group(row):
task = row.get("task_type")
sid = str(row.get("source_id") or row.get("source") or "")
if task == "chinese":
return "chinese_exam" if ":exam" in sid or "ceval" in sid.lower() or "cmmlu" in sid.lower() else "chinese_dialogue"
if task == "code":
return "code"
if task == "math":
return "math"
if task == "dialogue":
return "english_dialogue"
return None
def valid_item(group, user, assistant, tok, args, preset_lengths=None):
if preset_lengths and args.trust_metadata_lengths:
ptok, atok = preset_lengths
else:
ptok = token_len(tok, user)
atok = token_len(tok, assistant)
if ptok < args.min_prompt_tokens or atok < args.min_answer_tokens:
return False, "too_short", ptok, atok
if ptok > args.max_prompt_tokens or atok > args.max_answer_tokens:
return False, "too_long", ptok, atok
if group == "code" and "```" in assistant and assistant.count("```") % 2 != 0:
return False, "bad_code_fence", ptok, atok
return True, "ok", ptok, atok
def make_item(group, source_id, user, assistant, ptok, atok, split, metadata):
return {
"capability": group,
"source": source_id.split(":")[0],
"source_id": source_id,
"split": split,
"messages": [{"role": "user", "content": user}, {"role": "assistant", "content": assistant}],
"hashes": {"pair_sha256": pair_hash(user, assistant), "prompt_sha256": prompt_hash(user)},
"metadata": {"prompt_tokens": ptok, "answer_tokens": atok, **metadata},
}
def add_row(buckets, seen_pair, excluded_pairs, excluded_prompts, group, source_id, split, messages, tok, args, stats, metadata=None, preset_lengths=None):
user, assistant = first_user_assistant(messages)
if not user or not assistant:
stats["no_first_pair"] += 1
return False
ph = prompt_hash(user)
h = pair_hash(user, assistant)
if h in excluded_pairs or ph in excluded_prompts:
stats["heldout_excluded"] += 1
return False
if h in seen_pair:
stats["duplicate"] += 1
return False
ok, reason, ptok, atok = valid_item(group, user, assistant, tok, args, preset_lengths)
if not ok:
stats[reason] += 1
return False
seen_pair.add(h)
buckets[group].append(make_item(group, source_id, user, assistant, ptok, atok, split, metadata or {}))
stats["accepted"] += 1
return True
def read_jsonl(path):
with Path(path).open("r", encoding="utf-8") as f:
for line in f:
if line.strip():
yield json.loads(line)
def load_local_train(buckets, seen_pair, excluded_pairs, excluded_prompts, tok, args):
stats = {}
for path, mode in LOCAL_TRAIN_SOURCES:
path = Path(path)
if not path.exists():
continue
s = Counter()
if mode == "normalized":
for row in read_jsonl(path):
group = infer_local_group(row)
if not group:
s["unknown_group"] += 1
continue
meta = row.get("metadata") or {}
preset = None
if meta.get("prompt_tokens") is not None and meta.get("answer_tokens") is not None:
preset = (int(meta["prompt_tokens"]), int(meta["answer_tokens"]))
add_row(buckets, seen_pair, excluded_pairs, excluded_prompts, group, row.get("source_id") or row.get("source") or str(path), row.get("split", "local"), row.get("messages") or [], tok, args, s, {"loader": "local_normalized", "path": str(path)}, preset)
elif mode.startswith("jsonl:"):
_, group, source_id = mode.split(":", 2)
for row in read_jsonl(path):
msg = normalize_messages(row)
if not msg:
s["no_messages"] += 1
continue
add_row(buckets, seen_pair, excluded_pairs, excluded_prompts, group, source_id, "local", msg, tok, args, s, {"loader": "local_jsonl", "path": str(path)})
elif mode.startswith("csv:"):
_, group, source_id = mode.split(":", 2)
with path.open("r", encoding="utf-8", newline="") as f:
for row in csv.DictReader(f):
msg = normalize_messages(row)
if not msg:
s["no_messages"] += 1
continue
add_row(buckets, seen_pair, excluded_pairs, excluded_prompts, group, source_id, "local", msg, tok, args, s, {"loader": "local_csv", "path": str(path)})
stats[str(path)] = dict(s)
return stats
def iter_configs(src):
configs = src.get("configs")
if not configs:
yield None
elif configs == "all":
from datasets import get_dataset_config_names
try:
for cfg in get_dataset_config_names(src["name"]):
yield cfg
except Exception:
yield None
else:
for cfg in configs:
yield cfg
def load_dataset_iter(src, config, split):
from datasets import load_dataset
if config:
return load_dataset(src["name"], config, split=split, streaming=True)
return load_dataset(src["name"], split=split, streaming=True)
def fill_from_hf(buckets, seen_pair, excluded_pairs, excluded_prompts, tok, quotas, args, split_sources, phase):
stats = {}
rng = random.Random(args.seed + (101 if phase == "test" else 202))
for group in GROUPS:
rng.shuffle(split_sources[group])
for src in split_sources[group]:
if len(buckets[group]) >= quotas[group]:
break
source_base = src["name"]
source_stats = Counter()
print(
f"[{phase}] group={group} source={source_base} "
f"have={len(buckets[group])} target={quotas[group]}",
flush=True,
)
for config in iter_configs(src):
if len(buckets[group]) >= quotas[group]:
break
for split in src.get("splits", ["train"]):
if len(buckets[group]) >= quotas[group]:
break
source_id = f"{source_base}:{config}" if config else source_base
print(f"[{phase}] start group={group} source={source_id} split={split}", flush=True)
try:
ds = load_dataset_iter(src, config, split)
except Exception as exc:
print(f"[{phase}] load_error group={group} source={source_id} split={split} error={exc!r}", flush=True)
source_stats[f"load_error:{split}:{config}"] += 1
source_stats[f"error:{repr(exc)[:160]}"] += 1
continue
skipped = 0
accepted_before = source_stats["accepted"]
try:
for row in ds:
source_stats["seen"] += 1
if skipped < int(src.get("sample_offset", 0)):
skipped += 1
continue
msg = normalize_messages(row)
if not msg:
source_stats["no_messages"] += 1
continue
add_row(buckets, seen_pair, excluded_pairs, excluded_prompts, group, source_id, split, msg, tok, args, source_stats, {"loader": f"hf_{phase}", "row_keys": sorted(row.keys())})
if len(buckets[group]) >= quotas[group]:
break
if source_stats["seen"] >= args.max_seen_per_source:
source_stats["max_seen_stop"] += 1
break
except Exception as exc:
print(f"[{phase}] iter_error group={group} source={source_id} split={split} error={exc!r}", flush=True)
source_stats[f"iter_error:{split}:{config}"] += 1
source_stats[f"error:{repr(exc)[:160]}"] += 1
print(
f"[{phase}] done group={group} source={source_id} split={split} "
f"accepted_delta={source_stats['accepted'] - accepted_before} "
f"accepted_total={source_stats['accepted']} seen={source_stats['seen']} "
f"group_have={len(buckets[group])}",
flush=True,
)
if source_stats["accepted"] == accepted_before and args.stop_empty_source_early:
break
stats[f"{phase}:{group}:{source_base}"] = dict(source_stats)
return stats
def quotas_from_ratios(total, ratios):
denom = sum(ratios.values())
quotas = {g: total * ratios[g] // denom for g in GROUPS}
quotas["chinese_dialogue"] += total - sum(quotas.values())
return quotas
def write_jsonl(path, rows):
path.parent.mkdir(parents=True, exist_ok=True)
with path.open("w", encoding="utf-8") as f:
for row in rows:
f.write(json.dumps(row, ensure_ascii=False) + "\n")
def write_stats(path, stats):
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(json.dumps(stats, ensure_ascii=False, indent=2), encoding="utf-8")
def upsample_bucket(rows, target, rng):
if len(rows) >= target:
return rows[:target], 0
if not rows:
return [], 0
out = list(rows)
added = 0
while len(out) < target:
item = copy.deepcopy(rng.choice(rows))
item.setdefault("metadata", {})["upsampled"] = True
item["metadata"]["upsample_index"] = added
out.append(item)
added += 1
rng.shuffle(out)
return out, added
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--out", required=True)
ap.add_argument("--tokenizer", default="/ssd/yi/Tokenizer_Swap/model_building/generated_models/Qwen3-0.6B-DSV4-tokenizer-remap-v2")
ap.add_argument("--train-total", type=int, default=1000000)
ap.add_argument("--test-per-group", type=int, default=400)
ap.add_argument("--seed", type=int, default=20260611)
ap.add_argument("--hf-endpoint", default="https://hf-mirror.com")
ap.add_argument("--use-hf", action="store_true")
ap.add_argument("--allow-shortfall", action="store_true")
ap.add_argument("--upsample-train-shortfall", action="store_true")
ap.add_argument("--min-prompt-tokens", type=int, default=4)
ap.add_argument("--min-answer-tokens", type=int, default=8)
ap.add_argument("--max-prompt-tokens", type=int, default=1024)
ap.add_argument("--max-answer-tokens", type=int, default=1024)
ap.add_argument("--trust-metadata-lengths", action="store_true")
ap.add_argument("--max-seen-per-source", type=int, default=300000)
ap.add_argument("--stop-empty-source-early", action="store_true")
args = ap.parse_args()
os.environ.setdefault("HF_ENDPOINT", args.hf_endpoint)
out = Path(args.out)
tok = load_tokenizer(args.tokenizer)
rng = random.Random(args.seed)
test_quotas = {g: args.test_per_group for g in GROUPS}
test_buckets = defaultdict(list)
test_seen = set()
empty_excluded = set()
stats = {"args": vars(args), "train_ratios": TRAIN_RATIOS, "test_quotas": test_quotas, "loaders": {}}
if args.use_hf:
stats["loaders"]["test_hf"] = fill_from_hf(test_buckets, test_seen, set(), set(), tok, test_quotas, args, HF_TEST_SOURCES, "test")
test_rows = []
test_shortfall = {}
for g in GROUPS:
rng.shuffle(test_buckets[g])
take = min(test_quotas[g], len(test_buckets[g]))
test_rows.extend(test_buckets[g][:take])
if take < test_quotas[g]:
test_shortfall[g] = test_quotas[g] - take
test_pair_hashes = {r["hashes"]["pair_sha256"] for r in test_rows}
test_prompt_hashes = {r["hashes"]["prompt_sha256"] for r in test_rows}
train_quotas = quotas_from_ratios(args.train_total, TRAIN_RATIOS)
train_buckets = defaultdict(list)
train_seen = set()
stats["loaders"]["train_local"] = load_local_train(train_buckets, train_seen, test_pair_hashes, test_prompt_hashes, tok, args)
if args.use_hf:
stats["loaders"]["train_hf"] = fill_from_hf(train_buckets, train_seen, test_pair_hashes, test_prompt_hashes, tok, train_quotas, args, HF_TRAIN_SOURCES, "train")
train_rows = []
train_shortfall = {}
train_upsampled = {}
for g in GROUPS:
rng.shuffle(train_buckets[g])
if args.upsample_train_shortfall:
selected, added = upsample_bucket(train_buckets[g], train_quotas[g], rng)
take = len(selected)
train_rows.extend(selected)
if added:
train_upsampled[g] = added
else:
take = min(train_quotas[g], len(train_buckets[g]))
train_rows.extend(train_buckets[g][:take])
if take < train_quotas[g]:
train_shortfall[g] = train_quotas[g] - take
if (test_shortfall or train_shortfall) and not args.allow_shortfall:
stats["result"] = {
"failed": True,
"test_shortfall": test_shortfall,
"train_shortfall": train_shortfall,
"train_upsampled": train_upsampled,
"test_available": {g: len(test_buckets[g]) for g in GROUPS},
"train_available": {g: len(train_buckets[g]) for g in GROUPS},
"train_quotas": train_quotas,
}
write_stats(out / "build_stats.json", stats)
raise SystemExit(json.dumps(stats["result"], ensure_ascii=False, indent=2))
rng.shuffle(test_rows)
rng.shuffle(train_rows)
write_jsonl(out / "heldout_2p8k.jsonl", test_rows)
write_jsonl(out / "train_1m.jsonl", train_rows)
write_jsonl(out / "heldout_exclusion_hashes.jsonl", [{"pair_sha256": r["hashes"]["pair_sha256"], "prompt_sha256": r["hashes"]["prompt_sha256"], "capability": r["capability"], "source_id": r["source_id"]} for r in test_rows])
stats["result"] = {
"failed": False,
"test_total": len(test_rows),
"train_total": len(train_rows),
"test_counts": dict(Counter(r["capability"] for r in test_rows)),
"train_counts": dict(Counter(r["capability"] for r in train_rows)),
"test_shortfall": test_shortfall,
"train_shortfall": train_shortfall,
"train_upsampled": train_upsampled,
"train_quotas": train_quotas,
"train_source_top": dict(Counter(r["source_id"] for r in train_rows).most_common(80)),
"test_source_top": dict(Counter(r["source_id"] for r in test_rows).most_common(80)),
}
write_stats(out / "build_stats.json", stats)
print(json.dumps(stats["result"], ensure_ascii=False, indent=2))
print(out)
if __name__ == "__main__":
main()
File diff suppressed because one or more lines are too long
@@ -0,0 +1,17 @@
{
"seed": 20260607,
"requested": {
"mmlu": 1000,
"gpqa": 400,
"ceval": 600,
"cmmlu": 0
},
"total_items": 2000,
"counts": {
"gpqa": 400,
"ceval": 600,
"mmlu": 1000
},
"errors": {},
"output": "data/heldout_public_mcq_2k_20260607/heldout_public_mcq_2k.jsonl"
}
@@ -0,0 +1,118 @@
{
"tokenizer": "/ssd/yi/tokenizer_swap_cepe/models/Qwen3-0.6B-DSV4-tokenizer-remap-v2",
"budgets": {
"english_web": 1250000000,
"english_edu": 1000000000,
"chinese_clean": 1250000000,
"code": 750000000,
"math": 500000000,
"science": 150000000,
"qa_as_text": 100000000
},
"seq_len_for_later_packing": 8192,
"stream_sources": {
"english_web": [
{
"kind": "hf",
"name": "HuggingFaceFW/fineweb",
"config": "CC-MAIN-2025-26",
"split": "train",
"max_rows": 0
},
{
"kind": "hf",
"name": "HuggingFaceFW/fineweb",
"config": "CC-MAIN-2025-21",
"split": "train",
"max_rows": 0
}
],
"english_edu": [
{
"kind": "hf",
"name": "HuggingFaceFW/fineweb-edu",
"config": null,
"split": "train",
"max_rows": 0
}
],
"chinese_clean": [
{
"kind": "hf",
"name": "BAAI/CCI3-HQ",
"config": null,
"split": "train",
"max_rows": 0
},
{
"kind": "hf",
"name": "Skywork/SkyPile-150B",
"config": null,
"split": "train",
"max_rows": 0
}
],
"code": [
{
"kind": "hf",
"name": "bigcode/starcoderdata",
"config": null,
"split": "train",
"max_rows": 0
},
{
"kind": "hf",
"name": "codeparrot/github-code",
"config": null,
"split": "train",
"max_rows": 0
}
],
"math": [
{
"kind": "hf",
"name": "open-web-math/open-web-math",
"config": null,
"split": "train",
"max_rows": 0
},
{
"kind": "hf",
"name": "GAIR/MathPile",
"config": null,
"split": "train",
"max_rows": 0
}
]
},
"local_globs": {
"science": [
"data/offline_text_only_reasoning_sources_20260611/science_reasoning__*.jsonl",
"data/offline_text_only_reasoning_sources_20260611/logic__*.jsonl"
],
"qa_as_text": [
"data/training_mix_v4_train1m_test2p8k_noupsample_nobbh_20260611/train_1m.jsonl",
"data/open_recovery_sft_mix_alt_sources_1m_parquet_20260607/normalized.jsonl"
]
},
"local_parquet_globs": {
"english_web": [
"data/raw_parquets/fineweb_2025/*.parquet"
],
"english_edu": [
"data/raw_parquets/fineweb_edu/*.parquet"
],
"code": [
"data/raw_parquets/starcoder/python/*.parquet",
"data/raw_parquets/starcoder/javascript/*.parquet",
"data/raw_parquets/starcoder/typescript/*.parquet",
"data/raw_parquets/starcoder/java/*.parquet",
"data/raw_parquets/starcoder/cpp/*.parquet",
"data/raw_parquets/starcoder/go/*.parquet",
"data/raw_parquets/starcoder/rust/*.parquet",
"data/raw_parquets/starcoder/shell/*.parquet"
]
},
"min_tokens": 128,
"max_doc_tokens": 32768
}
@@ -0,0 +1,215 @@
{
"scale": 5.0,
"budgets": {
"english_web": 1250000000,
"english_edu": 1000000000,
"chinese_clean": 1250000000,
"code": 750000000,
"math": 500000000,
"science": 150000000,
"qa_as_text": 100000000
},
"tokens_by_category": {
"english_web": 1250000445,
"english_edu": 1000000462,
"code": 750001624,
"math": 96992014,
"science": 30016910,
"qa_as_text": 100000055
},
"docs_by_category": {
"english_web": 1571857,
"english_edu": 973081,
"code": 589463,
"math": 51576,
"science": 48872,
"qa_as_text": 244246
},
"tokens_by_source": {
"data/raw_parquets/fineweb_2025/CC-MAIN-2025-26_000_00000.parquet": 684777289,
"data/raw_parquets/fineweb_edu/CC-MAIN-2024-10_000_00000.parquet": 627654914,
"data/raw_parquets/fineweb_2025/CC-MAIN-2025-26_001_00000.parquet": 565223156,
"data/raw_parquets/fineweb_edu/CC-MAIN-2024-10_000_00001.parquet": 372345548,
"data/raw_parquets/starcoder/python/train-00000-of-00059.parquet": 238778818,
"data/raw_parquets/starcoder/python/train-00002-of-00059.parquet": 233459009,
"data/raw_parquets/starcoder/python/train-00001-of-00059.parquet": 233210510,
"/ssd/yi/tokenizer_swap_cepe/data/training_mix_v4_train1m_test2p8k_noupsample_nobbh_20260611/train_1m.jsonl": 100000055,
"open-web-math/open-web-math": 96992014,
"data/raw_parquets/starcoder/python/train-00003-of-00059.parquet": 44553287,
"/ssd/yi/tokenizer_swap_cepe/data/offline_text_only_reasoning_sources_20260611/science_reasoning__openlifescienceai_medmcqa__train.jsonl": 10027949,
"/ssd/yi/tokenizer_swap_cepe/data/offline_text_only_reasoning_sources_20260611/logic__tasksource_proofwriter__train.jsonl": 6138410,
"/ssd/yi/tokenizer_swap_cepe/data/offline_text_only_reasoning_sources_20260611/science_reasoning__derek-thomas_ScienceQA__train.jsonl": 3119670,
"/ssd/yi/tokenizer_swap_cepe/data/offline_text_only_reasoning_sources_20260611/logic__tasksource_proofwriter__test.jsonl": 1837710,
"/ssd/yi/tokenizer_swap_cepe/data/offline_text_only_reasoning_sources_20260611/science_reasoning__GBaker_MedQA-USMLE-4-options__train.jsonl": 1572096,
"/ssd/yi/tokenizer_swap_cepe/data/offline_text_only_reasoning_sources_20260611/science_reasoning__sciq__train.jsonl": 1182676,
"/ssd/yi/tokenizer_swap_cepe/data/offline_text_only_reasoning_sources_20260611/science_reasoning__derek-thomas_ScienceQA__test.jsonl": 1033827,
"/ssd/yi/tokenizer_swap_cepe/data/offline_text_only_reasoning_sources_20260611/science_reasoning__derek-thomas_ScienceQA__validation.jsonl": 1032383,
"/ssd/yi/tokenizer_swap_cepe/data/offline_text_only_reasoning_sources_20260611/logic__tasksource_proofwriter__validation.jsonl": 895384,
"/ssd/yi/tokenizer_swap_cepe/data/offline_text_only_reasoning_sources_20260611/science_reasoning__allenai_qasc__train.jsonl": 688074,
"/ssd/yi/tokenizer_swap_cepe/data/offline_text_only_reasoning_sources_20260611/science_reasoning__openlifescienceai_medmcqa__test.jsonl": 307416,
"/ssd/yi/tokenizer_swap_cepe/data/offline_text_only_reasoning_sources_20260611/logic__tasksource_folio__train.jsonl": 261306,
"/ssd/yi/tokenizer_swap_cepe/data/offline_text_only_reasoning_sources_20260611/science_reasoning__openlifescienceai_medmcqa__validation.jsonl": 242852,
"/ssd/yi/tokenizer_swap_cepe/data/offline_text_only_reasoning_sources_20260611/science_reasoning__allenai_openbookqa__main__train.jsonl": 221520,
"/ssd/yi/tokenizer_swap_cepe/data/offline_text_only_reasoning_sources_20260611/science_reasoning__GBaker_MedQA-USMLE-4-options__test.jsonl": 203198,
"/ssd/yi/tokenizer_swap_cepe/data/offline_text_only_reasoning_sources_20260611/logic__tasksource_bigbench__temporal_sequences__train.jsonl": 141867,
"/ssd/yi/tokenizer_swap_cepe/data/offline_text_only_reasoning_sources_20260611/science_reasoning__allenai_ai2_arc__ARC-Easy__test.jsonl": 139093,
"/ssd/yi/tokenizer_swap_cepe/data/offline_text_only_reasoning_sources_20260611/science_reasoning__allenai_ai2_arc__ARC-Easy__train.jsonl": 130752,
"/ssd/yi/tokenizer_swap_cepe/data/offline_text_only_reasoning_sources_20260611/logic__tasksource_bigbench__logical_deduction__train.jsonl": 118299,
"/ssd/yi/tokenizer_swap_cepe/data/offline_text_only_reasoning_sources_20260611/science_reasoning__sciq__test.jsonl": 102393,
"/ssd/yi/tokenizer_swap_cepe/data/offline_text_only_reasoning_sources_20260611/science_reasoning__sciq__validation.jsonl": 99297,
"/ssd/yi/tokenizer_swap_cepe/data/offline_text_only_reasoning_sources_20260611/science_reasoning__allenai_ai2_arc__ARC-Challenge__test.jsonl": 79458,
"/ssd/yi/tokenizer_swap_cepe/data/offline_text_only_reasoning_sources_20260611/science_reasoning__allenai_qasc__validation.jsonl": 79086,
"/ssd/yi/tokenizer_swap_cepe/data/offline_text_only_reasoning_sources_20260611/science_reasoning__allenai_ai2_arc__ARC-Challenge__train.jsonl": 74207,
"/ssd/yi/tokenizer_swap_cepe/data/offline_text_only_reasoning_sources_20260611/logic__tasksource_folio__validation.jsonl": 53607,
"/ssd/yi/tokenizer_swap_cepe/data/offline_text_only_reasoning_sources_20260611/logic__tasksource_bigbench__temporal_sequences__validation.jsonl": 35418,
"/ssd/yi/tokenizer_swap_cepe/data/offline_text_only_reasoning_sources_20260611/science_reasoning__allenai_ai2_arc__ARC-Easy__validation.jsonl": 33149,
"/ssd/yi/tokenizer_swap_cepe/data/offline_text_only_reasoning_sources_20260611/logic__tasksource_bigbench__logical_deduction__validation.jsonl": 31008,
"/ssd/yi/tokenizer_swap_cepe/data/offline_text_only_reasoning_sources_20260611/science_reasoning__allenai_openbookqa__main__validation.jsonl": 23331,
"/ssd/yi/tokenizer_swap_cepe/data/offline_text_only_reasoning_sources_20260611/science_reasoning__allenai_openbookqa__main__test.jsonl": 22745,
"/ssd/yi/tokenizer_swap_cepe/data/offline_text_only_reasoning_sources_20260611/science_reasoning__qiaojin_PubMedQA__pqa_labeled__train.jsonl": 22169,
"/ssd/yi/tokenizer_swap_cepe/data/offline_text_only_reasoning_sources_20260611/science_reasoning__allenai_ai2_arc__ARC-Challenge__validation.jsonl": 19963,
"/ssd/yi/tokenizer_swap_cepe/data/offline_text_only_reasoning_sources_20260611/logic__tasksource_bigbench__disambiguation_qa__train.jsonl": 15771,
"/ssd/yi/tokenizer_swap_cepe/data/offline_text_only_reasoning_sources_20260611/logic__tasksource_bigbench__date_understanding__train.jsonl": 14547,
"/ssd/yi/tokenizer_swap_cepe/data/offline_text_only_reasoning_sources_20260611/logic__tasksource_bigbench__disambiguation_qa__validation.jsonl": 3843,
"/ssd/yi/tokenizer_swap_cepe/data/offline_text_only_reasoning_sources_20260611/logic__tasksource_bigbench__date_understanding__validation.jsonl": 3629,
"/ssd/yi/tokenizer_swap_cepe/data/offline_text_only_reasoning_sources_20260611/logic__tasksource_bigbench__logical_args__validation.jsonl": 3136,
"/ssd/yi/tokenizer_swap_cepe/data/offline_text_only_reasoning_sources_20260611/logic__tasksource_bigbench__logical_args__train.jsonl": 2729,
"/ssd/yi/tokenizer_swap_cepe/data/offline_text_only_reasoning_sources_20260611/logic__tasksource_bigbench__analytic_entailment__train.jsonl": 2277,
"/ssd/yi/tokenizer_swap_cepe/data/offline_text_only_reasoning_sources_20260611/logic__tasksource_bigbench__analytic_entailment__validation.jsonl": 665
},
"rejected": {
"english_web": {
"too_short": 168039,
"too_long": 179
},
"english_edu": {
"too_short": 18375,
"too_long": 221
},
"code": {
"too_short": 106203,
"too_long": 816
},
"math": {
"too_short": 3669,
"too_long": 152
},
"science": {
"pack_too_short": 5591
},
"qa_as_text": {
"too_short": 108331
}
},
"sources": [
{
"category": "english_web",
"kind": "local_parquet",
"source": "data/raw_parquets/fineweb_2025/CC-MAIN-2025-26_000_00000.parquet",
"rows_seen": 961000,
"docs_written": 864351,
"tokens": 684777289,
"error": ""
},
{
"category": "english_web",
"kind": "local_parquet",
"source": "data/raw_parquets/fineweb_2025/CC-MAIN-2025-26_001_00000.parquet",
"rows_seen": 779076,
"docs_written": 707506,
"tokens": 565223156,
"error": ""
},
{
"category": "english_edu",
"kind": "local_parquet",
"source": "data/raw_parquets/fineweb_edu/CC-MAIN-2024-10_000_00000.parquet",
"rows_seen": 621759,
"docs_written": 610163,
"tokens": 627654914,
"error": ""
},
{
"category": "english_edu",
"kind": "local_parquet",
"source": "data/raw_parquets/fineweb_edu/CC-MAIN-2024-10_000_00001.parquet",
"rows_seen": 369919,
"docs_written": 362918,
"tokens": 372345548,
"error": ""
},
{
"category": "chinese_clean",
"kind": "hf_stream",
"source": "BAAI/CCI3-HQ",
"rows_seen": 0,
"docs_written": 0,
"tokens": 0,
"error": "DatasetNotFoundError(\"Dataset 'BAAI/CCI3-HQ' is a gated dataset on the Hub. You must be authenticated to access it.\")"
},
{
"category": "chinese_clean",
"kind": "hf_stream",
"source": "Skywork/SkyPile-150B",
"rows_seen": 0,
"docs_written": 0,
"tokens": 0,
"error": "RuntimeError('Cannot send a request, as the client has been closed.')"
},
{
"category": "code",
"kind": "local_parquet",
"source": "data/raw_parquets/starcoder/python/train-00000-of-00059.parquet",
"rows_seen": 218079,
"docs_written": 184958,
"tokens": 238778818,
"error": ""
},
{
"category": "code",
"kind": "local_parquet",
"source": "data/raw_parquets/starcoder/python/train-00001-of-00059.parquet",
"rows_seen": 218079,
"docs_written": 184495,
"tokens": 233210510,
"error": ""
},
{
"category": "code",
"kind": "local_parquet",
"source": "data/raw_parquets/starcoder/python/train-00002-of-00059.parquet",
"rows_seen": 218079,
"docs_written": 184331,
"tokens": 233459009,
"error": ""
},
{
"category": "code",
"kind": "local_parquet",
"source": "data/raw_parquets/starcoder/python/train-00003-of-00059.parquet",
"rows_seen": 42246,
"docs_written": 35679,
"tokens": 44553287,
"error": ""
},
{
"category": "math",
"kind": "hf_stream",
"source": "open-web-math/open-web-math",
"rows_seen": 55397,
"docs_written": 51576,
"tokens": 96992014,
"error": "ProxyError('503 Service Unavailable')"
},
{
"category": "math",
"kind": "hf_stream",
"source": "GAIR/MathPile",
"rows_seen": 0,
"docs_written": 0,
"tokens": 0,
"error": "DatasetNotFoundError(\"Dataset 'GAIR/MathPile' is a gated dataset on the Hub. You must be authenticated to access it.\")"
}
],
"elapsed_sec": 10098.068085193634
}
@@ -0,0 +1,393 @@
{
"docs_seen": 960549,
"train_blocks": 121041,
"eval_blocks": 1024,
"train_tokens": 991567872,
"eval_tokens": 8388608,
"source_docs": {
"english_web": 318271,
"english_edu": 194585,
"chinese_clean": 181655,
"code": 116242,
"math": 53125,
"science": 47973,
"qa_as_text": 48698
},
"source_tokens": {
"english_web": 249999374,
"english_edu": 199998420,
"chinese_clean": 249999618,
"code": 149999958,
"math": 99987860,
"science": 29999428,
"qa_as_text": 19999497
},
"train_blocks_by_category": {
"english_web": 30261,
"english_edu": 24208,
"chinese_clean": 30261,
"code": 18156,
"math": 12103,
"science": 3631,
"qa_as_text": 2421
},
"eval_blocks_by_category": {
"english_web": 256,
"english_edu": 205,
"chinese_clean": 256,
"code": 154,
"math": 102,
"science": 31,
"qa_as_text": 20
},
"start_time": 1781429820.1093097,
"leftover_tokens_by_category": {
"english_web": 4110,
"english_edu": 7124,
"chinese_clean": 4354,
"code": 4438,
"math": 4500,
"science": 324,
"qa_as_text": 2825
},
"tokenizer": "/ssd/yi/tokenizer_swap_cepe/models/Qwen3-0.6B-DSV4-tokenizer-remap-v2",
"seq_len": 8192,
"seed": 42,
"budgets": {
"english_web": 250000000,
"english_edu": 200000000,
"chinese_clean": 250000000,
"code": 150000000,
"math": 100000000,
"science": 30000000,
"qa_as_text": 20000000
},
"sources": {
"english_web": "data/cpt_docmix_parquet_sources_8192_20260613/documents/english_web.jsonl.gz",
"english_edu": "data/cpt_docmix_parquet_sources_8192_20260613/documents/english_edu.jsonl.gz",
"chinese_clean": "data/cpt_docmix_cci3_science_fixed_8192_20260614/documents/chinese_clean.jsonl.gz",
"code": "data/cpt_docmix_parquet_sources_8192_20260613/documents/code.jsonl.gz",
"math": "data/cpt_docmix_available_sources_8192_20260613/documents/math.jsonl.gz",
"science": "data/cpt_docmix_cci3_science_fixed_8192_20260614/documents/science.jsonl.gz",
"qa_as_text": "data/cpt_docmix_available_sources_8192_20260613/documents/qa_as_text.jsonl.gz"
},
"eval_quota_blocks": {
"english_web": 256,
"english_edu": 205,
"chinese_clean": 256,
"code": 154,
"math": 102,
"science": 31,
"qa_as_text": 20
},
"train_shards": [
{
"path": "train_00000.npy",
"blocks": 2048,
"tokens": 16777216
},
{
"path": "train_00001.npy",
"blocks": 2048,
"tokens": 16777216
},
{
"path": "train_00002.npy",
"blocks": 2048,
"tokens": 16777216
},
{
"path": "train_00003.npy",
"blocks": 2048,
"tokens": 16777216
},
{
"path": "train_00004.npy",
"blocks": 2048,
"tokens": 16777216
},
{
"path": "train_00005.npy",
"blocks": 2048,
"tokens": 16777216
},
{
"path": "train_00006.npy",
"blocks": 2048,
"tokens": 16777216
},
{
"path": "train_00007.npy",
"blocks": 2048,
"tokens": 16777216
},
{
"path": "train_00008.npy",
"blocks": 2048,
"tokens": 16777216
},
{
"path": "train_00009.npy",
"blocks": 2048,
"tokens": 16777216
},
{
"path": "train_00010.npy",
"blocks": 2048,
"tokens": 16777216
},
{
"path": "train_00011.npy",
"blocks": 2048,
"tokens": 16777216
},
{
"path": "train_00012.npy",
"blocks": 2048,
"tokens": 16777216
},
{
"path": "train_00013.npy",
"blocks": 2048,
"tokens": 16777216
},
{
"path": "train_00014.npy",
"blocks": 2048,
"tokens": 16777216
},
{
"path": "train_00015.npy",
"blocks": 2048,
"tokens": 16777216
},
{
"path": "train_00016.npy",
"blocks": 2048,
"tokens": 16777216
},
{
"path": "train_00017.npy",
"blocks": 2048,
"tokens": 16777216
},
{
"path": "train_00018.npy",
"blocks": 2048,
"tokens": 16777216
},
{
"path": "train_00019.npy",
"blocks": 2048,
"tokens": 16777216
},
{
"path": "train_00020.npy",
"blocks": 2048,
"tokens": 16777216
},
{
"path": "train_00021.npy",
"blocks": 2048,
"tokens": 16777216
},
{
"path": "train_00022.npy",
"blocks": 2048,
"tokens": 16777216
},
{
"path": "train_00023.npy",
"blocks": 2048,
"tokens": 16777216
},
{
"path": "train_00024.npy",
"blocks": 2048,
"tokens": 16777216
},
{
"path": "train_00025.npy",
"blocks": 2048,
"tokens": 16777216
},
{
"path": "train_00026.npy",
"blocks": 2048,
"tokens": 16777216
},
{
"path": "train_00027.npy",
"blocks": 2048,
"tokens": 16777216
},
{
"path": "train_00028.npy",
"blocks": 2048,
"tokens": 16777216
},
{
"path": "train_00029.npy",
"blocks": 2048,
"tokens": 16777216
},
{
"path": "train_00030.npy",
"blocks": 2048,
"tokens": 16777216
},
{
"path": "train_00031.npy",
"blocks": 2048,
"tokens": 16777216
},
{
"path": "train_00032.npy",
"blocks": 2048,
"tokens": 16777216
},
{
"path": "train_00033.npy",
"blocks": 2048,
"tokens": 16777216
},
{
"path": "train_00034.npy",
"blocks": 2048,
"tokens": 16777216
},
{
"path": "train_00035.npy",
"blocks": 2048,
"tokens": 16777216
},
{
"path": "train_00036.npy",
"blocks": 2048,
"tokens": 16777216
},
{
"path": "train_00037.npy",
"blocks": 2048,
"tokens": 16777216
},
{
"path": "train_00038.npy",
"blocks": 2048,
"tokens": 16777216
},
{
"path": "train_00039.npy",
"blocks": 2048,
"tokens": 16777216
},
{
"path": "train_00040.npy",
"blocks": 2048,
"tokens": 16777216
},
{
"path": "train_00041.npy",
"blocks": 2048,
"tokens": 16777216
},
{
"path": "train_00042.npy",
"blocks": 2048,
"tokens": 16777216
},
{
"path": "train_00043.npy",
"blocks": 2048,
"tokens": 16777216
},
{
"path": "train_00044.npy",
"blocks": 2048,
"tokens": 16777216
},
{
"path": "train_00045.npy",
"blocks": 2048,
"tokens": 16777216
},
{
"path": "train_00046.npy",
"blocks": 2048,
"tokens": 16777216
},
{
"path": "train_00047.npy",
"blocks": 2048,
"tokens": 16777216
},
{
"path": "train_00048.npy",
"blocks": 2048,
"tokens": 16777216
},
{
"path": "train_00049.npy",
"blocks": 2048,
"tokens": 16777216
},
{
"path": "train_00050.npy",
"blocks": 2048,
"tokens": 16777216
},
{
"path": "train_00051.npy",
"blocks": 2048,
"tokens": 16777216
},
{
"path": "train_00052.npy",
"blocks": 2048,
"tokens": 16777216
},
{
"path": "train_00053.npy",
"blocks": 2048,
"tokens": 16777216
},
{
"path": "train_00054.npy",
"blocks": 2048,
"tokens": 16777216
},
{
"path": "train_00055.npy",
"blocks": 2048,
"tokens": 16777216
},
{
"path": "train_00056.npy",
"blocks": 2048,
"tokens": 16777216
},
{
"path": "train_00057.npy",
"blocks": 2048,
"tokens": 16777216
},
{
"path": "train_00058.npy",
"blocks": 2048,
"tokens": 16777216
},
{
"path": "train_00059.npy",
"blocks": 209,
"tokens": 1712128
}
],
"eval_shards": [
{
"path": "eval_00000.npy",
"blocks": 1024,
"tokens": 8388608
}
],
"elapsed_sec": 2387.9453027248383
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,309 @@
{
"args": {
"out": "data/training_mix_v4_train1m_test2p8k_noupsample_nobbh_20260611",
"tokenizer": "/ssd/yi/tokenizer_swap_cepe/models/Qwen3-0.6B-DSV4-tokenizer-remap-v2",
"train_total": 1000000,
"test_per_group": 400,
"seed": 20260611,
"hf_endpoint": "https://hf-mirror.com",
"use_hf": true,
"allow_shortfall": true,
"upsample_train_shortfall": false,
"min_prompt_tokens": 4,
"min_answer_tokens": 8,
"max_prompt_tokens": 1024,
"max_answer_tokens": 1024,
"trust_metadata_lengths": true,
"max_seen_per_source": 500000,
"stop_empty_source_early": false
},
"train_ratios": {
"chinese_exam": 0,
"chinese_dialogue": 35,
"code": 30,
"math": 20,
"logic": 5,
"science_reasoning": 5,
"english_dialogue": 5
},
"test_quotas": {
"chinese_exam": 400,
"chinese_dialogue": 400,
"code": 400,
"math": 400,
"logic": 400,
"science_reasoning": 400,
"english_dialogue": 400
},
"loaders": {
"test_hf": {
"test:chinese_exam:ceval/ceval-exam": {
"seen": 728,
"accepted": 400,
"too_short": 328
},
"test:chinese_dialogue:m-a-p/COIG-CQIA": {
"seen": 414,
"accepted": 400,
"too_long": 14
},
"test:code:openai/openai_humaneval": {
"seen": 164,
"accepted": 154,
"too_short": 8,
"too_long": 2
},
"test:code:google-research-datasets/mbpp": {
"seen": 246,
"accepted": 246
},
"test:math:gsm8k": {
"seen": 400,
"accepted": 400
},
"test:logic:cais/mmlu": {
"seen": 331,
"accepted": 164,
"too_short": 167
},
"test:logic:lighteval/bbh": {
"load_error:test:logical_deduction_three_objects": 1,
"error:ValueError(\"Bad split: test. Available splits: ['train']\")": 1,
"seen": 296,
"accepted": 236,
"too_short": 60
},
"test:science_reasoning:Idavidrein/gpqa": {
"seen": 448,
"too_short": 195,
"accepted": 252,
"too_long": 1
},
"test:science_reasoning:allenai/ai2_arc": {
"seen": 287,
"accepted": 148,
"too_short": 139
},
"test:english_dialogue:HuggingFaceH4/ultrachat_200k": {
"seen": 420,
"too_long": 20,
"accepted": 400
}
},
"train_local": {
"data/open_recovery_sft_mix_alt_sources_1m_parquet_20260607/normalized.jsonl": {
"accepted": 1051916,
"heldout_excluded": 411,
"duplicate": 30
},
"data/open_recovery_sft_mix_100k_4_3_2_1_20260604/normalized.jsonl": {
"duplicate": 88687,
"accepted": 9020,
"heldout_excluded": 401
},
"data/modelscope_alt_sources_20260607/CodeAlpaca-20k.jsonl": {
"duplicate": 18820,
"too_short": 1193,
"no_messages": 6,
"too_long": 3
},
"data/modelscope_alt_sources_20260607/alpaca-gpt4-data-zh_train.csv": {
"duplicate": 46476,
"too_short": 2342
}
},
"train_hf": {
"train:chinese_dialogue:m-a-p/COIG-CQIA": {
"seen": 10116,
"duplicate": 7211,
"too_short": 1138,
"too_long": 1354,
"no_messages": 1,
"accepted": 1,
"heldout_excluded": 411
},
"train:chinese_dialogue:BelleGroup/train_0.5M_CN": {
"seen": 330837,
"too_short": 34263,
"duplicate": 2188,
"accepted": 294334,
"too_long": 32,
"no_messages": 20
},
"train:code:ise-uiuc/Magicoder-OSS-Instruct-75K": {
"seen": 75197,
"duplicate": 69998,
"bad_code_fence": 34,
"too_long": 48,
"accepted": 5117
},
"train:code:bigcode/self-oss-instruct-sc2-exec-filter-50k": {
"seen": 50661,
"duplicate": 31578,
"accepted": 19076,
"too_long": 6,
"bad_code_fence": 1
},
"train:code:HuggingFaceTB/smoltalk": {
"seen": 131271,
"duplicate": 78743,
"too_long": 1498,
"bad_code_fence": 1,
"accepted": 51029
},
"train:code:nvidia/OpenCodeInstruct": {
"seen": 43455,
"duplicate": 6678,
"too_long": 39,
"accepted": 36738
},
"train:logic:tasksource/bigbench": {
"seen": 8291,
"too_short": 5767,
"accepted": 2338,
"heldout_excluded": 186
},
"train:logic:tau/commonsense_qa": {
"seen": 10962,
"too_short": 10961,
"accepted": 1
},
"train:logic:metaeval/reclor": {
"seen": 5138,
"accepted": 5117,
"too_short": 21
},
"train:science_reasoning:allenai/ai2_arc": {
"seen": 1418,
"too_short": 739,
"accepted": 679
},
"train:science_reasoning:allenai/qasc": {
"iter_error:train:None": 1,
"error:ProxyError('503 Service Unavailable')": 2,
"iter_error:validation:None": 1
},
"train:science_reasoning:allenai/openbookqa": {
"iter_error:train:main": 1,
"error:ProxyError('503 Service Unavailable')": 4,
"iter_error:validation:main": 1,
"iter_error:train:additional": 1,
"iter_error:validation:additional": 1
},
"train:science_reasoning:sciq": {
"seen": 12679,
"accepted": 11370,
"too_short": 1309
},
"train:science_reasoning:qiaojin/PubMedQA": {
"seen": 1000,
"accepted": 1000
}
}
},
"result": {
"failed": false,
"test_total": 2800,
"train_total": 921360,
"test_counts": {
"science_reasoning": 400,
"logic": 400,
"code": 400,
"chinese_exam": 400,
"math": 400,
"chinese_dialogue": 400,
"english_dialogue": 400
},
"train_counts": {
"chinese_dialogue": 350000,
"code": 300000,
"english_dialogue": 50000,
"math": 200000,
"science_reasoning": 13904,
"logic": 7456
},
"test_shortfall": {},
"train_shortfall": {
"logic": 42544,
"science_reasoning": 36096
},
"train_upsampled": {},
"train_quotas": {
"chinese_exam": 0,
"chinese_dialogue": 350000,
"code": 300000,
"math": 200000,
"logic": 50000,
"science_reasoning": 50000,
"english_dialogue": 50000
},
"train_source_top": {
"BelleGroup/train_0.5M_CN": 296334,
"nvidia/OpenMathInstruct-2": 89260,
"TIGER-Lab/MathInstruct": 85173,
"ise-uiuc/Magicoder-OSS-Instruct-75K": 75115,
"bigcode/self-oss-instruct-sc2-exec-filter-50k": 66632,
"HuggingFaceTB/smoltalk:apigen-80k": 51029,
"AI-ModelScope/alpaca-gpt4-data-zh:file": 46476,
"nvidia/OpenCodeInstruct": 43404,
"AI-ModelScope/smoltalk:self-oss-instruct-file": 25000,
"AI-ModelScope/smoltalk:apigen-80k-file": 20000,
"AI-ModelScope/CodeAlpaca-20k:file": 18820,
"AI-ModelScope/smoltalk:numina-cot-100k-file": 17080,
"HuggingFaceTB/smoltalk:all": 15260,
"HuggingFaceH4/ultrachat_200k": 15238,
"allenai/tulu-3-sft-mixture": 15198,
"sciq": 11370,
"AI-ModelScope/smoltalk:metamathqa-50k-file": 8487,
"metaeval/reclor": 5117,
"m-a-p/COIG-CQIA:zhihu": 4978,
"AI-ModelScope/smoltalk:openhermes-100k": 4304,
"m-a-p/COIG-CQIA:coig_pc": 1877,
"qiaojin/PubMedQA:pqa_labeled": 1000,
"allenai/ai2_arc:ARC-Easy": 855,
"tasksource/bigbench:logical_deduction": 812,
"tasksource/bigbench:temporal_sequences": 800,
"allenai/ai2_arc:ARC-Challenge": 679,
"tasksource/bigbench:social_iqa": 343,
"m-a-p/COIG-CQIA:wikihow": 335,
"tasksource/bigbench:date_understanding": 296,
"tasksource/bigbench:disambiguation_qa": 71,
"tasksource/bigbench:logical_args": 16,
"tau/commonsense_qa": 1
},
"test_source_top": {
"gsm8k:main": 400,
"m-a-p/COIG-CQIA:zhihu": 400,
"HuggingFaceH4/ultrachat_200k": 400,
"Idavidrein/gpqa": 252,
"google-research-datasets/mbpp": 246,
"lighteval/bbh:logical_deduction_three_objects": 236,
"openai/openai_humaneval": 154,
"allenai/ai2_arc:ARC-Challenge": 148,
"cais/mmlu:formal_logic": 98,
"cais/mmlu:logical_fallacies": 66,
"ceval/ceval-exam:civil_servant": 38,
"ceval/ceval-exam:college_economics": 36,
"ceval/ceval-exam:accountant": 31,
"ceval/ceval-exam:college_programming": 23,
"ceval/ceval-exam:fire_engineer": 22,
"ceval/ceval-exam:advanced_mathematics": 22,
"ceval/ceval-exam:high_school_chinese": 21,
"ceval/ceval-exam:high_school_biology": 19,
"ceval/ceval-exam:college_chemistry": 18,
"ceval/ceval-exam:college_physics": 18,
"ceval/ceval-exam:high_school_chemistry": 17,
"ceval/ceval-exam:environmental_impact_assessment_engineer": 16,
"ceval/ceval-exam:business_administration": 15,
"ceval/ceval-exam:discrete_mathematics": 14,
"ceval/ceval-exam:education_science": 13,
"ceval/ceval-exam:clinical_medicine": 13,
"ceval/ceval-exam:electrical_engineer": 12,
"ceval/ceval-exam:computer_network": 11,
"ceval/ceval-exam:art_studies": 11,
"ceval/ceval-exam:computer_architecture": 11,
"ceval/ceval-exam:chinese_language_and_literature": 10,
"ceval/ceval-exam:basic_medicine": 9
}
}
}
@@ -0,0 +1,164 @@
{
"tokenizer": "/ssd/yi/tokenizer_swap_cepe/models/dsv4_chat_full_sft_remap_v2_alt1m_5epoch_bsz8_accum16_20260610",
"encoding_dir": "/ssd/yi/tokenizer_swap_cepe/external/deepseek_v4_encoding",
"cutoff_len": 2048,
"eos_token": "<end▁of▁sentence>",
"eos_token_id": 1,
"splits": {
"train": {
"split": "train",
"source": "/ssd/yi/tokenizer_swap_cepe/data/training_mix_v4_train1m_test2p8k_noupsample_nobbh_20260611/train_1m.jsonl",
"output": "/ssd/yi/tokenizer_swap_cepe/data/dsv4_chat_tokenized_v4_noupsample_nobbh_921k_20260611/train_dsv4_chat_tokenized.jsonl.gz",
"cutoff_len": 2048,
"rows_seen": 921360,
"rows_written": 921360,
"skipped_no_messages": 0,
"truncated": 0,
"eos_in_labels": 921360,
"prefix_mismatch": 0,
"capability_counts": {
"chinese_dialogue": 350000,
"code": 300000,
"math": 200000,
"english_dialogue": 50000,
"science_reasoning": 13904,
"logic": 7456
},
"prompt_tokens": {
"p50": 65,
"p90": 461,
"p95": 698,
"p99": 951,
"max": 1028
},
"response_tokens": {
"p50": 101,
"p90": 340,
"p95": 457,
"p99": 748,
"max": 1025
},
"total_tokens": {
"p50": 223,
"p90": 699,
"p95": 889,
"p99": 1165,
"max": 1957
},
"truncated_rate": 0.0,
"eos_label_rate": 1.0,
"source_counts_top50": {
"BelleGroup/train_0.5M_CN": 296334,
"nvidia/OpenMathInstruct-2": 89260,
"TIGER-Lab/MathInstruct": 85173,
"ise-uiuc/Magicoder-OSS-Instruct-75K": 75115,
"bigcode/self-oss-instruct-sc2-exec-filter-50k": 66632,
"HuggingFaceTB/smoltalk:apigen-80k": 51029,
"AI-ModelScope/alpaca-gpt4-data-zh:file": 46476,
"nvidia/OpenCodeInstruct": 43404,
"AI-ModelScope/smoltalk:self-oss-instruct-file": 25000,
"AI-ModelScope/smoltalk:apigen-80k-file": 20000,
"AI-ModelScope/CodeAlpaca-20k:file": 18820,
"AI-ModelScope/smoltalk:numina-cot-100k-file": 17080,
"HuggingFaceTB/smoltalk:all": 15260,
"HuggingFaceH4/ultrachat_200k": 15238,
"allenai/tulu-3-sft-mixture": 15198,
"sciq": 11370,
"AI-ModelScope/smoltalk:metamathqa-50k-file": 8487,
"metaeval/reclor": 5117,
"m-a-p/COIG-CQIA:zhihu": 4978,
"AI-ModelScope/smoltalk:openhermes-100k": 4304,
"m-a-p/COIG-CQIA:coig_pc": 1877,
"qiaojin/PubMedQA:pqa_labeled": 1000,
"allenai/ai2_arc:ARC-Easy": 855,
"tasksource/bigbench:logical_deduction": 812,
"tasksource/bigbench:temporal_sequences": 800,
"allenai/ai2_arc:ARC-Challenge": 679,
"tasksource/bigbench:social_iqa": 343,
"m-a-p/COIG-CQIA:wikihow": 335,
"tasksource/bigbench:date_understanding": 296,
"tasksource/bigbench:disambiguation_qa": 71,
"tasksource/bigbench:logical_args": 16,
"tau/commonsense_qa": 1
}
},
"validation": {
"split": "validation",
"source": "/ssd/yi/tokenizer_swap_cepe/data/training_mix_v4_train1m_test2p8k_noupsample_nobbh_20260611/heldout_2p8k.jsonl",
"output": "/ssd/yi/tokenizer_swap_cepe/data/dsv4_chat_tokenized_v4_noupsample_nobbh_921k_20260611/validation_dsv4_chat_tokenized.jsonl.gz",
"cutoff_len": 2048,
"rows_seen": 2800,
"rows_written": 2800,
"skipped_no_messages": 0,
"truncated": 0,
"eos_in_labels": 2800,
"prefix_mismatch": 0,
"capability_counts": {
"science_reasoning": 400,
"logic": 400,
"code": 400,
"chinese_exam": 400,
"math": 400,
"chinese_dialogue": 400,
"english_dialogue": 400
},
"prompt_tokens": {
"p50": 85,
"p90": 238,
"p95": 346,
"p99": 687,
"max": 1020
},
"response_tokens": {
"p50": 53,
"p90": 416,
"p95": 547,
"p99": 837,
"max": 1019
},
"total_tokens": {
"p50": 177,
"p90": 543,
"p95": 688,
"p99": 981,
"max": 1162
},
"truncated_rate": 0.0,
"eos_label_rate": 1.0,
"source_counts_top50": {
"gsm8k:main": 400,
"m-a-p/COIG-CQIA:zhihu": 400,
"HuggingFaceH4/ultrachat_200k": 400,
"Idavidrein/gpqa": 252,
"google-research-datasets/mbpp": 246,
"lighteval/bbh:logical_deduction_three_objects": 236,
"openai/openai_humaneval": 154,
"allenai/ai2_arc:ARC-Challenge": 148,
"cais/mmlu:formal_logic": 98,
"cais/mmlu:logical_fallacies": 66,
"ceval/ceval-exam:civil_servant": 38,
"ceval/ceval-exam:college_economics": 36,
"ceval/ceval-exam:accountant": 31,
"ceval/ceval-exam:college_programming": 23,
"ceval/ceval-exam:fire_engineer": 22,
"ceval/ceval-exam:advanced_mathematics": 22,
"ceval/ceval-exam:high_school_chinese": 21,
"ceval/ceval-exam:high_school_biology": 19,
"ceval/ceval-exam:college_chemistry": 18,
"ceval/ceval-exam:college_physics": 18,
"ceval/ceval-exam:high_school_chemistry": 17,
"ceval/ceval-exam:environmental_impact_assessment_engineer": 16,
"ceval/ceval-exam:business_administration": 15,
"ceval/ceval-exam:discrete_mathematics": 14,
"ceval/ceval-exam:education_science": 13,
"ceval/ceval-exam:clinical_medicine": 13,
"ceval/ceval-exam:electrical_engineer": 12,
"ceval/ceval-exam:computer_network": 11,
"ceval/ceval-exam:art_studies": 11,
"ceval/ceval-exam:computer_architecture": 11,
"ceval/ceval-exam:chinese_language_and_literature": 10,
"ceval/ceval-exam:basic_medicine": 9
}
}
}
}