claude-opus-4-8
nano-gpt-data-curation — graded by the task's verifier against a measured baseline.
- backend
- modal
- variant
- claude claude-opus-4-8
- metric
- held-out multi-domain perplexity
- actions
- 48
- duration
- 47m
- recorded
- 2026-08-04
run iddclm-nano-curation__mqoYzmu
Everything claude-opus-4-8 did on this task, in order.
download JSON ↗I'll start by surveying the environment: time budget, data, and the training pipeline.
args
{
"command": "cat /workspace/.timer/remaining_secs; echo \"---\"; ls -la /workspace; echo \"---\"; ls -la /workspace/data; echo \"---\"; ls -la /workspace/submission 2>/dev/null || echo \"no submission dir\"",
"description": "Check timer, list workspace and data"
}Bash result
5390
---
total 14
drwxr-xr-x 1 root root 100 Aug 4 03:23 .
drwxr-xr-x 1 root root 160 Aug 4 03:23 ..
drwxr-xr-x 1 root root 60 Aug 4 03:23 .live
drwxr-xr-x 1 root root 100 Aug 4 03:22 .metrics
drwxr-xr-x 1 root root 140 Aug 4 03:22 .timer
drwxr-xr-x 1 root root 57 Aug 3 22:37 data
-rwxrwxr-x 1 root root 714 Aug 3 22:34 dev_eval.sh
-rw-rw-r-- 1 root root 5706 Aug 3 22:34 model.py
-rw-rw-r-- 1 root root 869 Aug 3 22:34 pack_selection.py
drwxr-xr-x 1 root root 10 Aug 3 22:37 submission
-rwxrwxr-x 1 root root 1509 Aug 3 22:34 timer.sh
-rw-rw-r-- 1 root root 2962 Aug 3 22:34 train_nano.py
---
total 792657
drwxr-xr-x 1 root root 57 Aug 3 22:37 .
drwxr-xr-x 1 root root 100 Aug 4 03:23 ..
-r--r--r-- 1 root root 2000128 Aug 3 22:34 multi_dev.npy
-r--r--r-- 1 root root 809679384 Aug 3 22:35 pool.jsonl
---
total 1
drwxr-xr-x 1 root root 10 Aug 3 22:37 .
drwxr-xr-x 1 root root 100 Aug 4 03:23 ..
[stdout]
5390
---
total 14
drwxr-xr-x 1 root root 100 Aug 4 03:23 .
drwxr-xr-x 1 root root 160 Aug 4 03:23 ..
drwxr-xr-x 1 root root 60 Aug 4 03:23 .live
drwxr-xr-x 1 root root 100 Aug 4 03:22 .metrics
drwxr-xr-x 1 root root 140 Aug 4 03:22 .timer
drwxr-xr-x 1 root root 57 Aug 3 22:37 data
-rwxrwxr-x 1 root root 714 Aug 3 22:34 dev_eval.sh
-rw-rw-r-- 1 root root 5706 Aug 3 22:34 model.py
-rw-rw-r-- 1 root root 869 Aug 3 22:34 pack_selection.py
drwxr-xr-x 1 root root 10 Aug 3 22:37 submission
-rwxrwxr-x 1 root root 1509 Aug 3 22:34 timer.sh
-rw-rw-r-- 1 root root 2962 Aug 3 22:34 train_nano.py
---
total 792657
drwxr-xr-x 1 root root 57 Aug 3 22:37 .
drwxr-xr-x 1 root root 100 Aug 4 03:23 ..
-r--r--r-- 1 root root 2000128 Aug 3 22:34 multi_dev.npy
-r--r--r-- 1 root root 809679384 Aug 3 22:35 pool.jsonl
---
total 1
drwxr-xr-x 1 root root 10 Aug 3 22:37 .
drwxr-xr-x 1 root root 100 Aug 4 03:23 ..
[metadata] {"noOutputExpected": false}~90 minutes total. Let me read the pipeline files quickly.
args
{
"command": "cd /workspace; echo \"=== train_nano.py ===\"; cat train_nano.py; echo \"=== pack_selection.py ===\"; cat pack_selection.py; echo \"=== dev_eval.sh ===\"; cat dev_eval.sh; echo \"=== timer.sh ===\"; cat timer.sh",
"description": "Read training and packing scripts"
}Bash result
=== train_nano.py ===
"""From-scratch nano-GPT (30M) LM training on a 1D token .npy; report held-out perplexity.
Frozen recipe — the ONLY thing that varies between runs is the training token set."""
import argparse, math, time, numpy as np, torch
from model import GPT, GPTConfig
ap = argparse.ArgumentParser()
ap.add_argument("--train_npy", required=True)
ap.add_argument("--heldout_npy", required=True)
ap.add_argument("--out_json", required=True)
ap.add_argument("--max_iters", type=int, default=3000)
ap.add_argument("--warmup", type=int, default=150)
ap.add_argument("--batch", type=int, default=32)
ap.add_argument("--block", type=int, default=256)
ap.add_argument("--lr", type=float, default=6e-4)
ap.add_argument("--seed", type=int, default=1337)
a = ap.parse_args()
torch.manual_seed(a.seed); np.random.seed(a.seed)
dev = "cuda"
tr = np.load(a.train_npy); ho = np.load(a.heldout_npy)
tr = torch.from_numpy(tr.astype(np.int64)); ho = torch.from_numpy(ho.astype(np.int64))
rng = np.random.default_rng(a.seed)
model = GPT(GPTConfig(block_size=a.block, vocab_size=50257, n_layer=6, n_head=6,
n_embd=384, dropout=0.0, bias=False)).to(dev)
opt = model.configure_optimizers(0.1, a.lr, (0.9, 0.95), "cuda")
def lr_at(it):
if it < a.warmup: return a.lr * (it + 1) / (a.warmup + 1)
r = (it - a.warmup) / max(1, a.max_iters - a.warmup)
return 0.1 * a.lr + 0.5 * (1 + math.cos(math.pi * r)) * (a.lr - 0.1 * a.lr)
def get_batch(src):
ix = rng.integers(0, len(src) - a.block - 1, size=a.batch)
x = torch.stack([src[i:i+a.block] for i in ix]).to(dev)
y = torch.stack([src[i+1:i+1+a.block] for i in ix]).to(dev)
return x, y
t0 = time.time()
model.train()
for it in range(a.max_iters):
for g in opt.param_groups: g["lr"] = lr_at(it)
x, y = get_batch(tr)
with torch.autocast("cuda", dtype=torch.bfloat16):
_, loss = model(x, y)
opt.zero_grad(set_to_none=True); loss.backward()
torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0); opt.step()
train_s = time.time() - t0
# held-out perplexity: mean next-token CE over non-overlapping windows (window-weighted)
import json
model.eval()
nwin = (len(ho) - 1) // a.block
starts = [j * a.block for j in range(nwin)]
sum_loss, nseen = 0.0, 0
with torch.no_grad():
for i in range(0, nwin, a.batch):
bs = starts[i:i+a.batch]
x = torch.stack([ho[s:s+a.block] for s in bs]).to(dev)
y = torch.stack([ho[s+1:s+1+a.block] for s in bs]).to(dev)
with torch.autocast("cuda", dtype=torch.bfloat16):
_, l = model(x, y)
sum_loss += l.item() * len(bs); nseen += len(bs)
mean_loss = sum_loss / max(1, nseen)
ppl = math.exp(mean_loss)
out = {"train_npy": a.train_npy, "heldout_ppl": ppl, "mean_loss": mean_loss,
"max_iters": a.max_iters, "seed": a.seed, "train_s": round(train_s, 1)}
json.dump(out, open(a.out_json, "w"))
print(f"HELDOUT_PPL {ppl:.3f} loss {mean_loss:.4f} train_s {train_s:.0f} {a.train_npy}")
=== pack_selection.py ===
"""Solver-side: pack a selection.json (ordered ids) into a 12M-token train array from pool.jsonl."""
import json, sys, numpy as np
from transformers import AutoTokenizer
POOL = "/workspace/data/pool.jsonl"
SEL = sys.argv[1] if len(sys.argv) > 1 else "/workspace/submission/selection.json"
OUT = sys.argv[2] if len(sys.argv) > 2 else "/tmp/dev_train.npy"
BUDGET = 12_000_000
tok = AutoTokenizer.from_pretrained("gpt2"); EOS = tok.eos_token_id
text = {}
for line in open(POOL):
r = json.loads(line); text[r["id"]] = r["text"]
sel = json.load(open(SEL))
parts, tot = [], 0
for i in sel:
ids = tok(text[i], add_special_tokens=False).input_ids
parts.extend(ids); parts.append(EOS); tot += len(ids) + 1
if tot >= BUDGET: break
arr = np.array(parts[:BUDGET], dtype=np.uint16)
np.save(OUT, arr)
print(f"packed {len(arr)} tokens from {len(sel)} ids -> {OUT}")
=== dev_eval.sh ===
#!/bin/bash
# Diagnostic: train the frozen 30M GPT on your selection and report DEV perplexity.
# Usage: bash dev_eval.sh [selection.json] (default /workspace/submission/selection.json)
# NOTE: the official target is a DIFFERENT (hidden) sample from the same HQ domain.
set -euo pipefail
export TOKENIZERS_PARALLELISM=false
SEL="${1:-/workspace/submission/selection.json}"
cd /workspace
python3 pack_selection.py "$SEL" /tmp/dev_train.npy
python3 train_nano.py --train_npy /tmp/dev_train.npy --heldout_npy /workspace/data/multi_dev.npy \
--out_json /tmp/dev.json --max_iters 3000 --seed 1337 2>&1 | grep HELDOUT_PPL
echo "(dev PPL on multi_dev; official uses a hidden disjoint sample of the same HQ domain)"
=== timer.sh ===
#!/usr/bin/env bash
# Budget timer daemon — writes /workspace/.timer/remaining_secs every 10s so the
# solver can poll time left instead of doing wall-clock arithmetic.
#
# Budget (seconds) comes from $TASK_BUDGET_SECS (set by the runner to the agent
# timeout). Idempotent via a PID file. On ScaleTrain the trial runner starts its
# own timer; this file is the fallback for the Modal/local harbor backends, which
# bootstrap /workspace/timer.sh on environment start. The fallback default below
# (7200 = 2 h) matches this task's [agent] timeout_sec and is only used if
# $TASK_BUDGET_SECS is unset.
set -u
TIMER_DIR="/workspace/.timer"
PID_FILE="$TIMER_DIR/timer.pid"
mkdir -p "$TIMER_DIR"
if [ -s "$PID_FILE" ] && kill -0 "$(cat "$PID_FILE" 2>/dev/null)" 2>/dev/null; then
exit 0 # already running
fi
echo $$ > "$PID_FILE"
trap 'rm -f "$PID_FILE"' EXIT INT TERM
START=$(date +%s)
BUDGET="${TASK_BUDGET_SECS:-7200}"
echo "$START" > "$TIMER_DIR/start_epoch"
echo "$BUDGET" > "$TIMER_DIR/budget_secs"
while true; do
NOW=$(date +%s)
ELAPSED=$((NOW - START))
REMAINING=$((BUDGET - ELAPSED))
[ "$REMAINING" -lt 0 ] && REMAINING=0
echo "$REMAINING" > "$TIMER_DIR/remaining_secs"
echo "$ELAPSED" > "$TIMER_DIR/elapsed_secs"
[ "$REMAINING" -le 1800 ] && [ ! -f "$TIMER_DIR/alert_30min" ] && touch "$TIMER_DIR/alert_30min"
[ "$REMAINING" -le 600 ] && [ ! -f "$TIMER_DIR/alert_10min" ] && touch "$TIMER_DIR/alert_10min"
[ "$REMAINING" -le 0 ] && break
sleep 10
done
[stdout]
=== train_nano.py ===
"""From-scratch nano-GPT (30M) LM training on a 1D token .npy; report held-out perplexity.
Frozen recipe — the ONLY thing that varies between runs is the training token set."""
import argparse, math, time, numpy as np, torch
from model import GPT, GPTConfig
ap = argparse.ArgumentParser()
ap.add_argument("--train_npy", required=True)
ap.add_argument("--heldout_npy", required=True)
ap.add_argument("--out_json", required=True)
ap.add_argument("--max_iters", type=int, default=3000)
ap.add_argument("--warmup", type=int, default=150)
ap.add_argument("--batch", type=int, default=32)
ap.add_argument("--block", type=int, default=256)
ap.add_argument("--lr", type=float, default=6e-4)
ap.add_argument("--seed", type=int, default=1337)
a = ap.parse_args()
torch.manual_seed(a.seed); np.random.seed(a.seed)
dev = "cuda"
tr = np.load(a.train_npy); ho = np.load(a.heldout_npy)
tr = torch.from_numpy(tr.astype(np.int64)); ho = torch.from_numpy(ho.astype(np.int64))
rng = np.random.default_rng(a.seed)
model = GPT(GPTConfig(block_size=a.block, vocab_size=50257, n_layer=6, n_head=6,
n_embd=384, dropout=0.0, bias=False)).to(dev)
opt = model.configure_optimizers(0.1, a.lr, (0.9, 0.95), "cuda")
def lr_at(it):
if it < a.warmup: return a.lr * (it + 1) / (a.warmup + 1)
r = (it - a.warmup) / max(1, a.max_iters - a.warmup)
return 0.1 * a.lr + 0.5 * (1 + math.cos(math.pi * r)) * (a.lr - 0.1 * a.lr)
def get_batch(src):
ix = rng.integers(0, len(src) - a.block - 1, size=a.batch)
x = torch.stack([src[i:i+a.block] for i in ix]).to(dev)
y = torch.stack([src[i+1:i+1+a.block] for i in ix]).to(dev)
return x, y
t0 = time.time()
model.train()
for it in range(a.max_iters):
for g in opt.param_groups: g["lr"] = lr_at(it)
x, y = get_batch(tr)
with torch.autocast("cuda", dtype=torch.bfloat16):
_, loss = model(x, y)
opt.zero_grad(set_to_none=True); loss.backward()
torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0); opt.step()
train_s = time.time() - t0
# held-out perplexity: mean next-token CE over non-overlapping windows (window-weighted)
import json
model.eval()
nwin = (len(ho) - 1) // a.block
starts = [j * a.block for j in range(nwin)]
sum_loss, nseen = 0.0, 0
with torch.no_grad():
for i in range(0, nwin, a.batch):
bs = starts[i:i+a.batch]
x = torch.stack([ho[s:s+a.block] for s in bs]).to(dev)
y = torch.stack([ho[s+1:s+1+a.block] for s in bs]).to(dev)
with torch.autocast("cuda", dtype=torch.bfloat16):
_, l = model(x, y)
sum_loss += l.item() * len(bs); nseen += len(bs)
mean_loss = sum_loss / max(1, nseen)
ppl = math.exp(mean_loss)
out = {"train_npy": a.train_npy, "heldout_ppl": ppl, "mean_loss": mean_loss,
"max_iters": a.max_iters, "seed": a.seed, "train_s": round(train_s, 1)}
json.dump(out, open(a.out_json, "w"))
print(f"HELDOUT_PPL {ppl:.3f} loss {mean_loss:.4f} train_s {train_s:.0f} {a.train_npy}")
=== pack_selection.py ===
"""Solver-side: pack a selection.json (ordered ids) into a 12M-token train array from pool.jsonl."""
import json, sys, numpy as np
from transformers import AutoTokenizer
POOL = "/workspace/data/pool.jsonl"
SEL = sys.argv[1] if len(sys.argv) > 1 else "/workspace/submission/selection.json"
OUT = sys.argv[2] if len(sys.argv) > 2 else "/tmp/dev_train.npy"
BUDGET = 12_000_000
tok = AutoTokenizer.from_pretrained("gpt2"); EOS = tok.eos_token_id
text = {}
for line in open(POOL):
r = json.loads(line); text[r["id"]] = r["text"]
sel = json.load(open(SEL))
parts, tot = [], 0
for i in sel:
ids = tok(text[i], add_special_tokens=False).input_ids
parts.extend(ids); parts.append(EOS); tot += len(ids) + 1
if tot >= BUDGET: break
arr = np.array(parts[:BUDGET], dtype=np.uint16)
np.save(OUT, arr)
print(f"packed {len(arr)} tokens from {len(sel)} ids -> {OUT}")
=== dev_eval.sh ===
#!/bin/bash
# Diagnostic: train the frozen 30M GPT on your selection and report DEV perplexity.
# Usage: bash dev_eval.sh [selection.json] (default /workspace/submission/selection.json)
# NOTE: the official target is a DIFFERENT (hidden) sample from the same HQ domain.
set -euo pipefail
export TOKENIZERS_PARALLELISM=false
SEL="${1:-/workspace/submission/selection.json}"
cd /workspace
python3 pack_selection.py "$SEL" /tmp/dev_train.npy
python3 train_nano.py --train_npy /tmp/dev_train.npy --heldout_npy /workspace/data/multi_dev.npy \
--out_json /tmp/dev.json --max_iters 3000 --seed 1337 2>&1 | grep HELDOUT_PPL
echo "(dev PPL on multi_dev; official uses a hidden disjoint sample of the same HQ domain)"
=== timer.sh ===
#!/usr/bin/env bash
# Budget timer daemon — writes /workspace/.timer/remaining_secs every 10s so the
# solver can poll time left instead of doing wall-clock arithmetic.
#
# Budget (seconds) comes from $TASK_BUDGET_SECS (set by the runner to the agent
# timeout). Idempotent via a PID file. On ScaleTrain the trial runner starts its
# own timer; this file is the fallback for the Modal/local harbor backends, which
# bootstrap /workspace/timer.sh on environment start. The fallback default below
# (7200 = 2 h) matches this task's [agent] timeout_sec and is only used if
# $TASK_BUDGET_SECS is unset.
set -u
TIMER_DIR="/workspace/.timer"
PID_FILE="$TIMER_DIR/timer.pid"
mkdir -p "$TIMER_DIR"
if [ -s "$PID_FILE" ] && kill -0 "$(cat "$PID_FILE" 2>/dev/null)" 2>/dev/null; then
exit 0 # already running
fi
echo $$ > "$PID_FILE"
trap 'rm -f "$PID_FILE"' EXIT INT TERM
START=$(date +%s)
BUDGET="${TASK_BUDGET_SECS:-7200}"
echo "$START" > "$TIMER_DIR/start_epoch"
echo "$BUDGET" > "$TIMER_DIR/budget_secs"
while true; do
NOW=$(date +%s)
ELAPSED=$((NOW - START))
REMAINING=$((BUDGET - ELAPSED))
[ "$REMAINING" -lt 0 ] && REMAINING=0
echo "$REMAINING" > "$TIMER_DIR/remaining_secs"
echo "$ELAPSED" > "$TIMER_DIR/elapsed_secs"
[ "$REMAINING" -le 1800 ] && [ ! -f "$TIMER_DIR/alert_30min" ] && touch "$TIMER_DIR/alert_30min"
[ "$REMAINING" -le 600 ] && [ ! -f "$TIMER_DIR/alert_10min" ] && touch "$TIMER_DIR/alert_10min"
[ "$REMAINING" -le 0 ] && break
sleep 10
done
[metadata] {"noOutputExpected": false}~90 min budget. This is a data-selection task: the pool is raw web, and I need to pick documents resembling the disclosed high-quality target. Crucially, multi_dev.npy is the target domain in token form — I can decode it and use it as a positive signal. Let me inspect the data.
args
{
"command": "cd /workspace; nvidia-smi --query-gpu=name,memory.total,memory.used --format=csv 2>/dev/null | head; echo \"---pool count---\"; wc -l data/pool.jsonl; echo \"---first doc sample---\"; head -c 2000 data/pool.jsonl; echo; echo \"---multi_dev shape---\"; python3 -c \"import numpy as np; a=np.load('data/multi_dev.npy'); print(a.shape, a.dtype, a.min(), a.max())\"",
"description": "GPU, pool count, sample doc, dev target shape"
}Bash result
name, memory.total [MiB], memory.used [MiB]
NVIDIA H100 80GB HBM3, 81559 MiB, 4 MiB
---pool count---
182016 data/pool.jsonl
---first doc sample---
{"id": 0, "text": "|Viewing Single Post From: Spoilers for the Week of February 11th|\n|Lil||Feb 1 2013, 09:58 AM|\nDon't care about Chloe/Taniel/Jen-Jen. Don't care about Sami, really, but hoping that we get some good \"SAMANTHA GENE!!\" Marlena Death-Stares out of it. And \"newfound\" feelings. Please. If only.\nSTEFANO!! STEFANO, STEFANO, STEFANO!!!! :cheer:\n|Spoilers for the Week of February 11th \u00b7 DAYS: News, Spoilers & Discussion|"}
{"id": 1, "text": "*sigh* Fundamentalist community, let me pass on some advice to you I learned from the atheistic community:\nIf you have set yourself on fire, do not run.\nOkay? Okay?? Please?\nLook, D, you had two months to say to Harvard in private emails, \"Im sorry, I shouldnt have been using that animation in my paid presentations. I wont use it again. I really do like 'Inner Life', though, and would love to use it in classroom presentations, from the BioVisions site, if that is acceptable.\"\nI sat here, for two months, waiting for that to happen, anything to happen, and it didnt. Two months, on your own terms, you could have written a similar post to yesterdays. I would have given you the benefit of the doubt-- maybe you didnt know the credits werent visible to the audience, and I wouldnt have said a word beyond this, as its Harvards problem, not mine. This would have been a funny joke to those of us involved in dealing with you people, but it would have been a PR non-issue for you.\nBut after you set yourself on fire, you didnt douse it out with a bucket of ice cold reality and accountability. You ran. And youre still running.\nWhy not just state \"I screwed up. Sorry everyone.\" and move on? Why the excuses? Why the denial? Why the passive language? Why the vague words and cryptic capitalizations? Why the writes and rewrites of your 'press release'? We know it wasnt written of your own volition, or it would have been done *before* Harvard had to take action. And, your behavior before this, regarding this issue, is
---multi_dev shape---
(1000000,) uint16 0 50256
[stdout]
name, memory.total [MiB], memory.used [MiB]
NVIDIA H100 80GB HBM3, 81559 MiB, 4 MiB
---pool count---
182016 data/pool.jsonl
---first doc sample---
{"id": 0, "text": "|Viewing Single Post From: Spoilers for the Week of February 11th|\n|Lil||Feb 1 2013, 09:58 AM|\nDon't care about Chloe/Taniel/Jen-Jen. Don't care about Sami, really, but hoping that we get some good \"SAMANTHA GENE!!\" Marlena Death-Stares out of it. And \"newfound\" feelings. Please. If only.\nSTEFANO!! STEFANO, STEFANO, STEFANO!!!! :cheer:\n|Spoilers for the Week of February 11th \u00b7 DAYS: News, Spoilers & Discussion|"}
{"id": 1, "text": "*sigh* Fundamentalist community, let me pass on some advice to you I learned from the atheistic community:\nIf you have set yourself on fire, do not run.\nOkay? Okay?? Please?\nLook, D, you had two months to say to Harvard in private emails, \"Im sorry, I shouldnt have been using that animation in my paid presentations. I wont use it again. I really do like 'Inner Life', though, and would love to use it in classroom presentations, from the BioVisions site, if that is acceptable.\"\nI sat here, for two months, waiting for that to happen, anything to happen, and it didnt. Two months, on your own terms, you could have written a similar post to yesterdays. I would have given you the benefit of the doubt-- maybe you didnt know the credits werent visible to the audience, and I wouldnt have said a word beyond this, as its Harvards problem, not mine. This would have been a funny joke to those of us involved in dealing with you people, but it would have been a PR non-issue for you.\nBut after you set yourself on fire, you didnt douse it out with a bucket of ice cold reality and accountability. You ran. And youre still running.\nWhy not just state \"I screwed up. Sorry everyone.\" and move on? Why the excuses? Why the denial? Why the passive language? Why the vague words and cryptic capitalizations? Why the writes and rewrites of your 'press release'? We know it wasnt written of your own volition, or it would have been done *before* Harvard had to take action. And, your behavior before this, regarding this issue, is
---multi_dev shape---
(1000000,) uint16 0 50256
[metadata] {"noOutputExpected": false}The pool is raw web (forum posts, rants). Let me decode the target to understand its register and set up scoring.
args
{
"command": "cd /workspace; python3 -c \"\nfrom transformers import AutoTokenizer\nimport numpy as np\ntok=AutoTokenizer.from_pretrained('gpt2')\na=np.load('data/multi_dev.npy')\n# decode in chunks, split by EOS (50256)\ntxt=tok.decode(a[:4000].tolist())\nprint(repr(txt[:3500]))\nprint('=== EOS count ===', int((a==50256).sum()))\n\"",
"description": "Decode dev target sample"
}Bash result
' Beardmore was sufficiently impressed with Shackleton to offer financial support , but other donations proved hard to come by . Nevertheless , in February 1907 , Shackleton presented to the Royal Geographic Society his plans for an Antarctic expedition , the details of which , under the name British Antarctic Expedition , were published in the Royal Society \'s newsletter , Geographic Journal . The aim was the conquest of both the geographical South Pole and the South Magnetic Pole . Shackleton then worked hard to persuade others of his wealthy friends and acquaintances to contribute , including Sir Philip Lee Brocklehurst , who subscribed £ 2 @,@ 000 ( 2011 equivalent £ 157 @,@ 000 ) to secure a place on the expedition ; author Campbell Mackellar ; and Guinness baron Lord Iveagh , whose contribution was secured less than two weeks before the departure of the expedition ship Nimrod . On 4 August 1907 , Shackleton was appointed a Member of the Royal Victorian Order , 4th Class ( MVO ; the present @-@ day grade of Lieutenant ) . \n<|endoftext|> On 1 January 1908 , Nimrod sailed for the Antarctic from Lyttelton Harbour , New Zealand . Shackleton \'s original plans had envisaged using the old Discovery base in McMurdo Sound to launch his attempts on the South Pole and South Magnetic Pole . However , before leaving England , he had been pressured to give an undertaking to Scott that he would not base himself in the McMurdo area , which Scott was claiming as his own field of work . Shackleton reluctantly agreed to look for winter quarters at either the Barrier Inlet ( which Discovery had briefly visited in 1902 ) or King Edward VII Land . \n<|endoftext|> To conserve coal , the ship was towed 1 @,@ 650 miles ( 2 @,@ 655 km ) by the steamer Koonya to the Antarctic ice , after Shackleton had persuaded the New Zealand government and the Union Steamship Company to share the cost . In accordance with Shackleton \'s promise to Scott , the ship headed for the eastern sector of the Great Ice Barrier , arriving there on 21 January 1908 . They found that the Barrier Inlet had expanded to form a large bay , in which were hundreds of whales , which led to the immediate christening of the area as the Bay of Whales . It was noted that ice conditions were unstable , precluding the establishment of a safe base there . An extended search for an anchorage at King Edward VII Land proved equally fruitless , so Shackleton was forced to break his undertaking to Scott and set sail for McMurdo Sound , a decision which , according to second officer Arthur Harbord , was " dictated by common sense " in view of the difficulties of ice pressure , coal shortage and the lack of any nearer known base . \n<|endoftext|> Nimrod arrived at McMurdo Sound on 29 January , but was stopped by ice 16 miles ( 26 km ) north of Discovery \'s old base at Hut Point . After considerable weather delays , Shackleton \'s base was eventually established at Cape Royds , about 24 miles ( 39 km ) north of Hut Point . The party was in high spirits , despite the difficult conditions ; Shackleton \'s ability to communicate with each man kept the party happy and focused . \n<|endoftext|> The " Great Southern Journey " , as Frank Wild called it , began on 29 October 1908 . On 9 January 1909 , Shackleton and three companions ( Wild , Eric Marshall and Jameson Adams ) reached a new Farthest South latitude of 88 ° 23 \' S , a point only 112 miles ( 180 km ) from the Pole . En route the South Pole party discovered th'
=== EOS count === 2704
[stdout]
' Beardmore was sufficiently impressed with Shackleton to offer financial support , but other donations proved hard to come by . Nevertheless , in February 1907 , Shackleton presented to the Royal Geographic Society his plans for an Antarctic expedition , the details of which , under the name British Antarctic Expedition , were published in the Royal Society \'s newsletter , Geographic Journal . The aim was the conquest of both the geographical South Pole and the South Magnetic Pole . Shackleton then worked hard to persuade others of his wealthy friends and acquaintances to contribute , including Sir Philip Lee Brocklehurst , who subscribed £ 2 @,@ 000 ( 2011 equivalent £ 157 @,@ 000 ) to secure a place on the expedition ; author Campbell Mackellar ; and Guinness baron Lord Iveagh , whose contribution was secured less than two weeks before the departure of the expedition ship Nimrod . On 4 August 1907 , Shackleton was appointed a Member of the Royal Victorian Order , 4th Class ( MVO ; the present @-@ day grade of Lieutenant ) . \n<|endoftext|> On 1 January 1908 , Nimrod sailed for the Antarctic from Lyttelton Harbour , New Zealand . Shackleton \'s original plans had envisaged using the old Discovery base in McMurdo Sound to launch his attempts on the South Pole and South Magnetic Pole . However , before leaving England , he had been pressured to give an undertaking to Scott that he would not base himself in the McMurdo area , which Scott was claiming as his own field of work . Shackleton reluctantly agreed to look for winter quarters at either the Barrier Inlet ( which Discovery had briefly visited in 1902 ) or King Edward VII Land . \n<|endoftext|> To conserve coal , the ship was towed 1 @,@ 650 miles ( 2 @,@ 655 km ) by the steamer Koonya to the Antarctic ice , after Shackleton had persuaded the New Zealand government and the Union Steamship Company to share the cost . In accordance with Shackleton \'s promise to Scott , the ship headed for the eastern sector of the Great Ice Barrier , arriving there on 21 January 1908 . They found that the Barrier Inlet had expanded to form a large bay , in which were hundreds of whales , which led to the immediate christening of the area as the Bay of Whales . It was noted that ice conditions were unstable , precluding the establishment of a safe base there . An extended search for an anchorage at King Edward VII Land proved equally fruitless , so Shackleton was forced to break his undertaking to Scott and set sail for McMurdo Sound , a decision which , according to second officer Arthur Harbord , was " dictated by common sense " in view of the difficulties of ice pressure , coal shortage and the lack of any nearer known base . \n<|endoftext|> Nimrod arrived at McMurdo Sound on 29 January , but was stopped by ice 16 miles ( 26 km ) north of Discovery \'s old base at Hut Point . After considerable weather delays , Shackleton \'s base was eventually established at Cape Royds , about 24 miles ( 39 km ) north of Hut Point . The party was in high spirits , despite the difficult conditions ; Shackleton \'s ability to communicate with each man kept the party happy and focused . \n<|endoftext|> The " Great Southern Journey " , as Frank Wild called it , began on 29 October 1908 . On 9 January 1909 , Shackleton and three companions ( Wild , Eric Marshall and Jameson Adams ) reached a new Farthest South latitude of 88 ° 23 \' S , a point only 112 miles ( 180 km ) from the Pole . En route the South Pole party discovered th'
=== EOS count === 2704
[metadata] {"noOutputExpected": false}Target is clearly the high-quality encyclopedic/news/prose register (WikiText-style Wikipedia here). My plan: build a quality classifier — positives = decoded multi_dev target segments, negatives = random pool docs — score every pool doc, gate on basic quality, rank by score. Let me explore pool length stats to set gates.
args
{
"command": "cd /workspace; python3 -c \"\nimport json, numpy as np\nlens=[]; alpha=[]; import re\nn=0\nwith open('data/pool.jsonl') as f:\n for line in f:\n r=json.loads(line); t=r['text']; n+=1\n lens.append(len(t))\n a=sum(c.isalpha() or c.isspace() for c in t[:1000]); alpha.append(a/max(1,len(t[:1000])))\nlens=np.array(lens); alpha=np.array(alpha)\nprint('docs',n)\nprint('char len pctiles',np.percentile(lens,[1,10,25,50,75,90,99]).astype(int))\nprint('mean char len', int(lens.mean()))\nprint('alpha+space ratio pctiles', np.round(np.percentile(alpha,[1,10,25,50,90]),3))\nprint('est total tokens (chars/4)', int(lens.sum()/4))\n\"",
"description": "Pool length and character stats"
}Bash result
docs 182016
char len pctiles [ 160 561 1050 2246 4500 8458 34874]
mean char len 4233
alpha+space ratio pctiles [0.758 0.905 0.939 0.959 0.978]
est total tokens (chars/4) 192634287
[stdout]
docs 182016
char len pctiles [ 160 561 1050 2246 4500 8458 34874]
mean char len 4233
alpha+space ratio pctiles [0.758 0.905 0.939 0.959 0.978]
est total tokens (chars/4) 192634287
[metadata] {"noOutputExpected": false}Total ~192M tokens, mean ~1000 tokens/doc. 12M budget ≈ ~12k docs. Now let me write the curation pipeline.
args
{
"file_path": "/workspace/submission/curate.py",
"content": "\"\"\"Curate a high-quality, on-target pretraining subset from a raw web pool.\n\nCriterion (stated): a document is selected in proportion to how much it *looks\nlike the disclosed target domain* -- broad high-quality English prose spanning\nencyclopedic (Wikipedia), general web prose, news, and technical Q&A -- as judged\nby a bag-of-words logistic-regression quality classifier, subject to hard quality\ngates that remove obviously degenerate web text.\n\nSignal source: the provided dev target `multi_dev.npy` is the target register in\nGPT-2-token form. We decode it and split on the EOS delimiter to obtain thousands\nof genuine positive examples of the target domain. Negatives are a random sample\nof the raw pool (mostly off-target web junk). A hashed word/bigram logistic\nclassifier trained on (positives vs random pool) gives, for every pool document,\nP(looks like target). We gate out degenerate docs (too short, non-English,\nsymbol/number spam, boilerplate-repetitive) and rank the survivors by classifier\nscore in descending order (best first). The training pipeline consumes this\npriority-ordered id list until the 12M-token budget is filled.\n\nReproducible: no hand-picked ids; the ordering is a pure function of the pool and\nthe decoded target under the stated criterion.\n\"\"\"\nimport json, re, math, numpy as np\nfrom collections import Counter\nfrom transformers import AutoTokenizer\nfrom sklearn.feature_extraction.text import HashingVectorizer\nfrom sklearn.linear_model import LogisticRegression\n\nPOOL = \"/workspace/data/pool.jsonl\"\nDEV = \"/workspace/data/multi_dev.npy\"\nOUT = \"/workspace/submission/selection.json\"\nSEED = 1337\nrng = np.random.default_rng(SEED)\n\n# ---------------------------------------------------------------- load pool\nids, texts = [], []\nwith open(POOL) as f:\n for line in f:\n r = json.loads(line)\n ids.append(r[\"id\"]); texts.append(r[\"text\"])\nids = np.array(ids)\nN = len(texts)\nprint(f\"loaded {N} pool docs\")\n\n# ---------------------------------------------------------------- target positives\ntok = AutoTokenizer.from_pretrained(\"gpt2\")\ndev = np.load(DEV).astype(np.int64)\nEOS = 50256\n# split target token stream on EOS into register segments, decode to text\nseg, cur = [], []\nfor t in dev:\n if t == EOS:\n if cur: seg.append(cur); cur = []\n else:\n cur.append(t)\nif cur: seg.append(cur)\npos_texts = [tok.decode(s) for s in seg if len(s) > 32]\nprint(f\"target positive segments: {len(pos_texts)}\")\n\n# ---------------------------------------------------------------- quality gates\n_word = re.compile(r\"[A-Za-z]{2,}\")\nSTOP = set(\"the of and to in a is that for it as was on are with be by this at from \"\n \"or an which not but have has had they you we he she его\".split())\ndef gate(t):\n \"\"\"Return True if doc passes hard quality gates (keep), False to drop.\"\"\"\n n = len(t)\n if n < 400: # too little content to be worth EOS overhead\n return False\n sample = t[:4000]\n letters = sum(c.isalpha() for c in sample)\n if letters / len(sample) < 0.55: # symbol / number / markup spam\n return False\n asc = sum(ord(c) < 128 for c in sample)\n if asc / len(sample) < 0.90: # mostly non-English / mojibake\n return False\n words = _word.findall(sample.lower())\n if len(words) < 40:\n return False\n # English stopword presence -> real prose, not keyword lists / boilerplate\n sw = sum(w in STOP for w in words) / len(words)\n if sw < 0.06:\n return False\n # repetition: unique-word ratio guards against spam / templated dumps\n if len(set(words)) / len(words) < 0.30:\n return False\n up = sum(c.isupper() for c in sample) / max(1, letters)\n if up > 0.30: # SHOUTING / navbar text\n return False\n return True\n\ngate_mask = np.array([gate(t) for t in texts])\nprint(f\"passed gates: {int(gate_mask.sum())} / {N}\")\n\n# ---------------------------------------------------------------- classifier\ndef norm(t):\n return t[:6000].lower()\n\n# negatives: random pool sample (mostly off-target); positives: target segments\nneg_idx = rng.choice(N, size=min(8000, N), replace=False)\ntrain_texts = pos_texts + [norm(texts[i]) for i in neg_idx]\ny = np.r_[np.ones(len(pos_texts)), np.zeros(len(neg_idx))]\n\nvec = HashingVectorizer(analyzer=\"word\", ngram_range=(1, 2),\n n_features=2**20, alternate_sign=False, norm=\"l2\",\n lowercase=True)\nXtr = vec.transform(train_texts)\nclf = LogisticRegression(C=1.0, max_iter=400, class_weight=\"balanced\")\nclf.fit(Xtr, y)\nprint(\"classifier train acc:\", round(clf.score(Xtr, y), 4))\n\n# score every pool doc\nXall = vec.transform([norm(t) for t in texts])\nscore = clf.decision_function(Xall)\n\n# ---------------------------------------------------------------- dedup + rank\n# rank gated docs by classifier score (best first)\ncand = np.where(gate_mask)[0]\ncand = cand[np.argsort(-score[cand])]\n\n# light exact-dedup on a normalized prefix signature to avoid wasting budget on\n# duplicated boilerplate; keeps the highest-scoring copy (we walk best-first).\nseen = set()\norder = []\nfor i in cand:\n sig = re.sub(r\"\\s+\", \" \", texts[i][:200].lower()).strip()\n if sig in seen:\n continue\n seen.add(sig)\n order.append(int(ids[i]))\n\n# provide well beyond the 12M-token budget (est ~1k tok/doc -> ~12k needed)\norder = order[:60000]\njson.dump(order, open(OUT, \"w\"))\nprint(f\"wrote {len(order)} ids -> {OUT}\")\nprint(\"score pctiles kept:\", np.round(np.percentile(score[cand], [50, 90, 99]), 3))\n"
}Write result
File created successfully at: /workspace/submission/curate.py (file state is current in your context — no need to Read it back)
[metadata] {"type": "create", "filePath": "/workspace/submission/curate.py", "content": "\"\"\"Curate a high-quality, on-target pretraining subset from a raw web pool.\n\nCriterion (stated): a document is selected in proportion to how much it *looks\nlike the disclosed target domain* -- broad high-quality English prose spanning\nencyclopedic (Wikipedia), general web prose, news, and technical Q&A -- as judged\nby a bag-of-words logistic-regression quality classifier, subject to hard quality\ngates that remove obviously degenerate web text.\n\nSignal source: the provided dev target `multi_dev.npy` is the target register in\nGPT-2-token form. We decode it and split on the EOS delimiter to obtain thousands\nof genuine positive examples of the target domain. Negatives are a random sample\nof the raw pool (mostly off-target web junk). A hashed word/bigram logistic\nclassifier trained on (positives vs random pool) gives, for every pool document,\nP(looks like target). We gate out degenerate docs (too short, non-English,\nsymbol/number spam, boilerplate-repetitive) and rank the survivors by classifier\nscore in descending order (best first). The training pipeline consumes this\npriority-ordered id list until the 12M-token budget is filled.\n\nReproducible: no hand-picked ids; the ordering is a pure function of the pool and\nthe decoded target under the stated criterion.\n\"\"\"\nimport json, re, math, numpy as np\nfrom collections import Counter\nfrom transformers import AutoTokenizer\nfrom sklearn.feature_extraction.text import HashingVectorizer\nfrom sklearn.linear_model import LogisticRegression\n\nPOOL = \"/workspace/data/pool.jsonl\"\nDEV = \"/workspace/data/multi_dev.npy\"\nOUT = \"/workspace/submission/selection.json\"\nSEED = 1337\nrng = np.random.default_rng(SEED)\n\n# ---------------------------------------------------------------- load pool\nids, texts = [], []\nwith open(POOL) as f:\n for line in f:\n r = json.loads(line)\n ids.append(r[\"id\"]); texts.append(r[\"text\"])\nids = np.array(ids)\nN = len(texts)\nprint(f\"loaded {N} pool docs\")\n\n# ---------------------------------------------------------------- target positives\ntok = AutoTokenizer.from_pretrained(\"gpt2\")\ndev = np.load(DEV).astype(np.int64)\nEOS = 50256\n# split target token stream on EOS into register segments, decode to text\nseg, cur = [], []\nfor t in dev:\n if t == EOS:\n if cur: seg.append(cur); cur = []\n else:\n cur.append(t)\nif cur: seg.append(cur)\npos_texts = [tok.decode(s) for s in seg if len(s) > 32]\nprint(f\"target positive segments: {len(pos_texts)}\")\n\n# ---------------------------------------------------------------- quality gates\n_word = re.compile(r\"[A-Za-z]{2,}\")\nSTOP = set(\"the of and to in a is that for it as was on are with be by this at from \"\n \"or an which not but have has had they you we he she его\".split())\ndef gate(t):\n \"\"\"Return True if doc passes hard quality gates (keep), False to drop.\"\"\"\n n = len(t)\n if n < 400: # too little content to be worth EOS overhead\n return False\n sample = t[:4000]\n letters = sum(c.isalpha() for c in sample)\n if letters / len(sample) < 0.55: # symbol / number / markup spam\n return False\n asc = sum(ord(c) < 128 for c in sample)\n if asc / len(sample) < 0.90: # mostly non-English / mojibake\n return False\n words = _word.findall(sample.lower())\n if len(words) < 40:\n return False\n # English stopword presence -> real prose, not keyword lists / boilerplate\n sw = sum(w in STOP for w in words) / len(words)\n if sw < 0.06:\n return False\n # repetition: unique-word ratio guards against spam / templated dumps\n if len(set(words)) / len(words) < 0.30:\n return False\n up = sum(c.isupper() for c in sample) / max(1, letters)\n if up > 0.30: # SHOUTING / navbar text\n return False\n return True\n\ngate_mask = np.array([gate(t) for t in texts])\nprint(f\"passed gates: {int(gate_mask.sum())} / {N}\")\n\n# ---------------------------------------------------------------- classifier\ndef norm(t):\n return t[:6000].lower()\n\n# negatives: random pool sample (mostly off-target); positives: target segments\nneg_idx = rng.choice(N, size=min(8000, N), replace=False)\ntrain_texts = pos_texts + [norm(texts[i]) for i in neg_idx]\ny = np.r_[np.ones(len(pos_texts)), np.zeros(len(neg_idx))]\n\nvec = HashingVectorizer(analyzer=\"word\", ngram_range=(1, 2),\n n_features=2**20, alternate_sign=False, norm=\"l2\",\n lowercase=True)\nXtr = vec.transform(train_texts)\nclf = LogisticRegression(C=1.0, max_iter=400, class_weight=\"balanced\")\nclf.fit(Xtr, y)\nprint(\"classifier train acc:\", round(clf.score(Xtr, y), 4))\n\n# score every pool doc\nXall = vec.transform([norm(t) for t in texts])\nscore = clf.decision_function(Xall)\n\n# ---------------------------------------------------------------- dedup + rank\n# rank gated docs by classifier score (best first)\ncand = np.where(gate_mask)[0]\ncand = cand[np.argsort(-score[cand])]\n\n# light exact-dedup on a normalized prefix signature to avoid wasting budget on\n# duplicated boilerplate; keeps the highest-scoring copy (we walk best-first).\nseen = set()\norder = []\nfor i in cand:\n sig = re.sub(r\"\\s+\", \" \", texts[i][:200].lower()).strip()\n if sig in seen:\n continue\n seen.add(sig)\n order.append(int(ids[i]))\n\n# provide well beyond the 12M-token budget (est ~1k tok/doc -> ~12k needed)\norder = order[:60000]\njson.dump(order, open(OUT, \"w\"))\nprint(f\"wrote {len(order)} ids -> {OUT}\")\nprint(\"score pctiles kept:\", np.round(np.percentile(score[cand], [50, 90, 99]), 3))\n", "structuredPatch": [], "originalFile": null, "userModified": false}encrypted chain-of-thought — recorded, not exposed
args
{
"command": "cd /workspace; time python3 submission/curate.py 2>&1 | grep -v Warning",
"description": "Run curation pipeline"
}Bash result
Traceback (most recent call last):
File "/workspace/submission/curate.py", line 25, in <module>
from sklearn.feature_extraction.text import HashingVectorizer
ModuleNotFoundError: No module named 'sklearn'
real 0m4.025s
user 0m4.930s
sys 0m0.930s
[stdout]
Traceback (most recent call last):
File "/workspace/submission/curate.py", line 25, in <module>
from sklearn.feature_extraction.text import HashingVectorizer
ModuleNotFoundError: No module named 'sklearn'
real 0m4.025s
user 0m4.930s
sys 0m0.930s
[metadata] {"noOutputExpected": false}encrypted chain-of-thought — recorded, not exposed
args
{
"command": "pip install scikit-learn -q 2>&1 | tail -2",
"description": "Install scikit-learn"
}Bash result
Command did not complete within its 120s timeout and was moved to the background (ID: b8asjxtuq). Output is being written to: /tmp/claude-0/-workspace/7699cb8a-1e37-4174-b570-b672872f1d62/tasks/b8asjxtuq.output. You will be notified when it completes. To check interim output, use Read on that file path.
[metadata] {"noOutputExpected": false, "backgroundTaskId": "b8asjxtuq", "timedOutAfterMs": 120000}No internet — pip may fail. Let me check.
args
{
"command": "sleep 20; cat /tmp/claude-0/-workspace/*/tasks/b8asjxtuq.output 2>/dev/null | tail -5; echo \"---check---\"; python3 -c \"import sklearn; print('ok', sklearn.__version__)\" 2>&1 | tail -1",
"description": "Check sklearn install status"
}Bash result
---check---
ModuleNotFoundError: No module named 'sklearn'
[stdout]
---check---
ModuleNotFoundError: No module named 'sklearn'
[metadata] {"noOutputExpected": false}No sklearn and no internet. I'll implement the classifier myself as a length-normalized Naive Bayes log-likelihood-ratio (target vs random-pool) in pure numpy — fast, no dependencies. Let me kill the pip job and rewrite.
args
{
"task_id": "b8asjxtuq"
}TaskStop result
{"message":"Successfully stopped task: b8asjxtuq (pip install scikit-learn -q 2>&1 | tail -2)","task_id":"b8asjxtuq","task_type":"local_bash","command":"pip install scikit-learn -q 2>&1 | tail -2"}
[metadata] {"message": "Successfully stopped task: b8asjxtuq (pip install scikit-learn -q 2>&1 | tail -2)", "task_id": "b8asjxtuq", "task_type": "local_bash", "command": "pip install scikit-learn -q 2>&1 | tail -2"}encrypted chain-of-thought — recorded, not exposed
args
{
"file_path": "/workspace/submission/curate.py",
"content": "\"\"\"Curate a high-quality, on-target pretraining subset from a raw web pool.\n\nCriterion (stated): a document is selected in proportion to how much it *looks\nlike the disclosed target domain* -- broad high-quality English prose spanning\nencyclopedic (Wikipedia), general web prose, news, and technical Q&A -- as judged\nby a length-normalized Naive-Bayes log-likelihood-ratio quality classifier,\nsubject to hard quality gates that remove obviously degenerate web text.\n\nSignal source: the provided dev target `multi_dev.npy` is the target register in\nGPT-2-token form. We decode it and split on the EOS delimiter to obtain thousands\nof genuine positive examples of the target domain. Negatives are a random sample\nof the raw pool (mostly off-target web junk). For every word we estimate\n s(w) = log P(w | target) - log P(w | random-pool)\nwith add-k smoothing, and score a document by the mean of s(w) over its words\n(length-normalized quality). Docs are gated to remove degenerate text (too short,\nnon-English, symbol/number spam, boilerplate-repetitive, SHOUTING) and the\nsurvivors are ranked by score, best first. The training pipeline consumes this\npriority-ordered id list until the 12M-token budget is filled.\n\nReproducible: no hand-picked ids; the ordering is a pure function of the pool and\nthe decoded target under the stated criterion. No third-party ML deps (numpy +\nthe GPT-2 tokenizer only).\n\"\"\"\nimport json, re, math, numpy as np\nfrom collections import Counter\nfrom transformers import AutoTokenizer\n\nPOOL = \"/workspace/data/pool.jsonl\"\nDEV = \"/workspace/data/multi_dev.npy\"\nOUT = \"/workspace/submission/selection.json\"\nSEED = 1337\nrng = np.random.default_rng(SEED)\n\n# ---------------------------------------------------------------- load pool\nids, texts = [], []\nwith open(POOL) as f:\n for line in f:\n r = json.loads(line)\n ids.append(r[\"id\"]); texts.append(r[\"text\"])\nids = np.array(ids)\nN = len(texts)\nprint(f\"loaded {N} pool docs\")\n\n# ---------------------------------------------------------------- target positives\ntok = AutoTokenizer.from_pretrained(\"gpt2\")\ndev = np.load(DEV).astype(np.int64)\nEOS = 50256\nseg, cur = [], []\nfor t in dev:\n if t == EOS:\n if cur: seg.append(cur); cur = []\n else:\n cur.append(t)\nif cur: seg.append(cur)\npos_texts = [tok.decode(s) for s in seg if len(s) > 32]\nprint(f\"target positive segments: {len(pos_texts)}\")\n\n# ---------------------------------------------------------------- tokenization\n_word = re.compile(r\"[a-z]{2,}\")\ndef words(t, cap=1200):\n return _word.findall(t.lower())[:cap]\n\n# ---------------------------------------------------------------- quality gates\nSTOP = set(\"the of and to in a is that for it as was on are with be by this at \"\n \"from or an which not but have has had they you we he she\".split())\ndef gate(t):\n n = len(t)\n if n < 400: # too little content to be worth EOS overhead\n return False\n s = t[:4000]\n letters = sum(c.isalpha() for c in s)\n if letters / len(s) < 0.55: # symbol / number / markup spam\n return False\n if sum(ord(c) < 128 for c in s) / len(s) < 0.90: # non-English / mojibake\n return False\n w = _word.findall(s.lower())\n if len(w) < 40:\n return False\n if sum(x in STOP for x in w) / len(w) < 0.06: # keyword lists / boilerplate\n return False\n if len(set(w)) / len(w) < 0.30: # repetitive spam\n return False\n if sum(c.isupper() for c in s) / max(1, letters) > 0.30: # SHOUTING / navbar\n return False\n return True\n\ngate_mask = np.array([gate(t) for t in texts])\nprint(f\"passed gates: {int(gate_mask.sum())} / {N}\")\n\n# ---------------------------------------------------------------- NB word scores\npos_ctr = Counter()\nfor t in pos_texts:\n pos_ctr.update(words(t))\nneg_idx = rng.choice(N, size=min(10000, N), replace=False)\nneg_ctr = Counter()\nfor i in neg_idx:\n neg_ctr.update(words(texts[i]))\n\n# vocabulary: words seen enough overall to be reliable\nvocab = {}\nfor w, c in pos_ctr.items():\n if c + neg_ctr.get(w, 0) >= 5:\n vocab[w] = len(vocab)\nfor w, c in neg_ctr.items():\n if w not in vocab and c >= 5:\n vocab[w] = len(vocab)\nV = len(vocab)\npos_tot = sum(pos_ctr.values()); neg_tot = sum(neg_ctr.values())\nk = 1.0\ns = np.zeros(V, dtype=np.float64)\nfor w, j in vocab.items():\n p = (pos_ctr.get(w, 0) + k) / (pos_tot + k * V)\n q = (neg_ctr.get(w, 0) + k) / (neg_tot + k * V)\n s[j] = math.log(p) - math.log(q)\nprint(f\"vocab {V}\")\n\n# ---------------------------------------------------------------- score pool\nscore = np.full(N, -1e9, dtype=np.float64)\nget = vocab.get\nfor i in range(N):\n if not gate_mask[i]:\n continue\n js = [get(w) for w in words(texts[i])]\n js = [j for j in js if j is not None]\n if len(js) >= 30:\n score[i] = s[np.asarray(js)].mean()\n\n# ---------------------------------------------------------------- dedup + rank\ncand = np.where(score > -1e8)[0]\ncand = cand[np.argsort(-score[cand])] # best first\nseen, order = set(), []\nfor i in cand:\n sig = re.sub(r\"\\s+\", \" \", texts[i][:200].lower()).strip()\n if sig in seen:\n continue\n seen.add(sig)\n order.append(int(ids[i]))\n\norder = order[:60000] # well beyond the 12M-token budget\njson.dump(order, open(OUT, \"w\"))\nprint(f\"wrote {len(order)} ids -> {OUT}\")\nprint(\"kept score pctiles:\", np.round(np.percentile(score[cand], [50, 90, 99]), 3))\n"
}Write result
The file /workspace/submission/curate.py has been updated successfully. (file state is current in your context — no need to Read it back)
[metadata] {"type": "update", "filePath": "/workspace/submission/curate.py", "content": "\"\"\"Curate a high-quality, on-target pretraining subset from a raw web pool.\n\nCriterion (stated): a document is selected in proportion to how much it *looks\nlike the disclosed target domain* -- broad high-quality English prose spanning\nencyclopedic (Wikipedia), general web prose, news, and technical Q&A -- as judged\nby a length-normalized Naive-Bayes log-likelihood-ratio quality classifier,\nsubject to hard quality gates that remove obviously degenerate web text.\n\nSignal source: the provided dev target `multi_dev.npy` is the target register in\nGPT-2-token form. We decode it and split on the EOS delimiter to obtain thousands\nof genuine positive examples of the target domain. Negatives are a random sample\nof the raw pool (mostly off-target web junk). For every word we estimate\n s(w) = log P(w | target) - log P(w | random-pool)\nwith add-k smoothing, and score a document by the mean of s(w) over its words\n(length-normalized quality). Docs are gated to remove degenerate text (too short,\nnon-English, symbol/number spam, boilerplate-repetitive, SHOUTING) and the\nsurvivors are ranked by score, best first. The training pipeline consumes this\npriority-ordered id list until the 12M-token budget is filled.\n\nReproducible: no hand-picked ids; the ordering is a pure function of the pool and\nthe decoded target under the stated criterion. No third-party ML deps (numpy +\nthe GPT-2 tokenizer only).\n\"\"\"\nimport json, re, math, numpy as np\nfrom collections import Counter\nfrom transformers import AutoTokenizer\n\nPOOL = \"/workspace/data/pool.jsonl\"\nDEV = \"/workspace/data/multi_dev.npy\"\nOUT = \"/workspace/submission/selection.json\"\nSEED = 1337\nrng = np.random.default_rng(SEED)\n\n# ---------------------------------------------------------------- load pool\nids, texts = [], []\nwith open(POOL) as f:\n for line in f:\n r = json.loads(line)\n ids.append(r[\"id\"]); texts.append(r[\"text\"])\nids = np.array(ids)\nN = len(texts)\nprint(f\"loaded {N} pool docs\")\n\n# ---------------------------------------------------------------- target positives\ntok = AutoTokenizer.from_pretrained(\"gpt2\")\ndev = np.load(DEV).astype(np.int64)\nEOS = 50256\nseg, cur = [], []\nfor t in dev:\n if t == EOS:\n if cur: seg.append(cur); cur = []\n else:\n cur.append(t)\nif cur: seg.append(cur)\npos_texts = [tok.decode(s) for s in seg if len(s) > 32]\nprint(f\"target positive segments: {len(pos_texts)}\")\n\n# ---------------------------------------------------------------- tokenization\n_word = re.compile(r\"[a-z]{2,}\")\ndef words(t, cap=1200):\n return _word.findall(t.lower())[:cap]\n\n# ---------------------------------------------------------------- quality gates\nSTOP = set(\"the of and to in a is that for it as was on are with be by this at \"\n \"from or an which not but have has had they you we he she\".split())\ndef gate(t):\n n = len(t)\n if n < 400: # too little content to be worth EOS overhead\n return False\n s = t[:4000]\n letters = sum(c.isalpha() for c in s)\n if letters / len(s) < 0.55: # symbol / number / markup spam\n return False\n if sum(ord(c) < 128 for c in s) / len(s) < 0.90: # non-English / mojibake\n return False\n w = _word.findall(s.lower())\n if len(w) < 40:\n return False\n if sum(x in STOP for x in w) / len(w) < 0.06: # keyword lists / boilerplate\n return False\n if len(set(w)) / len(w) < 0.30: # repetitive spam\n return False\n if sum(c.isupper() for c in s) / max(1, letters) > 0.30: # SHOUTING / navbar\n return False\n return True\n\ngate_mask = np.array([gate(t) for t in texts])\nprint(f\"passed gates: {int(gate_mask.sum())} / {N}\")\n\n# ---------------------------------------------------------------- NB word scores\npos_ctr = Counter()\nfor t in pos_texts:\n pos_ctr.update(words(t))\nneg_idx = rng.choice(N, size=min(10000, N), replace=False)\nneg_ctr = Counter()\nfor i in neg_idx:\n neg_ctr.update(words(texts[i]))\n\n# vocabulary: words seen enough overall to be reliable\nvocab = {}\nfor w, c in pos_ctr.items():\n if c + neg_ctr.get(w, 0) >= 5:\n vocab[w] = len(vocab)\nfor w, c in neg_ctr.items():\n if w not in vocab and c >= 5:\n vocab[w] = len(vocab)\nV = len(vocab)\npos_tot = sum(pos_ctr.values()); neg_tot = sum(neg_ctr.values())\nk = 1.0\ns = np.zeros(V, dtype=np.float64)\nfor w, j in vocab.items():\n p = (pos_ctr.get(w, 0) + k) / (pos_tot + k * V)\n q = (neg_ctr.get(w, 0) + k) / (neg_tot + k * V)\n s[j] = math.log(p) - math.log(q)\nprint(f\"vocab {V}\")\n\n# ---------------------------------------------------------------- score pool\nscore = np.full(N, -1e9, dtype=np.float64)\nget = vocab.get\nfor i in range(N):\n if not gate_mask[i]:\n continue\n js = [get(w) for w in words(texts[i])]\n js = [j for j in js if j is not None]\n if len(js) >= 30:\n score[i] = s[np.asarray(js)].mean()\n\n# ---------------------------------------------------------------- dedup + rank\ncand = np.where(score > -1e8)[0]\ncand = cand[np.argsort(-score[cand])] # best first\nseen, order = set(), []\nfor i in cand:\n sig = re.sub(r\"\\s+\", \" \", texts[i][:200].lower()).strip()\n if sig in seen:\n continue\n seen.add(sig)\n order.append(int(ids[i]))\n\norder = order[:60000] # well beyond the 12M-token budget\njson.dump(order, open(OUT, \"w\"))\nprint(f\"wrote {len(order)} ids -> {OUT}\")\nprint(\"kept score pctiles:\", np.round(np.percentile(score[cand], [50, 90, 99]), 3))\n", "structuredPatch": [{"oldStart": 3, "oldLines": 27, "newStart": 3, "newLines": 27, "lines": [" Criterion (stated): a document is selected in proportion to how much it *looks", " like the disclosed target domain* -- broad high-quality English prose spanning", " encyclopedic (Wikipedia), general web prose, news, and technical Q&A -- as judged", "-by a bag-of-words logistic-regression quality classifier, subject to hard quality", "-gates that remove obviously degenerate web text.", "+by a length-normalized Naive-Bayes log-likelihood-ratio quality classifier,", "+subject to hard quality gates that remove obviously degenerate web text.", " ", " Signal source: the provided dev target `multi_dev.npy` is the target register in", " GPT-2-token form. We decode it and split on the EOS delimiter to obtain thousands", " of genuine positive examples of the target domain. Negatives are a random sample", "-of the raw pool (mostly off-target web junk). A hashed word/bigram logistic", "-classifier trained on (positives vs random pool) gives, for every pool document,", "-P(looks like target). We gate out degenerate docs (too short, non-English,", "-symbol/number spam, boilerplate-repetitive) and rank the survivors by classifier", "-score in descending order (best first). The training pipeline consumes this", "+of the raw pool (mostly off-target web junk). For every word we estimate", "+ s(w) = log P(w | target) - log P(w | random-pool)", "+with add-k smoothing, and score a document by the mean of s(w) over its words", "+(length-normalized quality). Docs are gated to remove degenerate text (too short,", "+non-English, symbol/number spam, boilerplate-repetitive, SHOUTING) and the", "+survivors are ranked by score, best first. The training pipeline consumes this", " priority-ordered id list until the 12M-token budget is filled.", " ", " Reproducible: no hand-picked ids; the ordering is a pure function of the pool and", "-the decoded target under the stated criterion.", "+the decoded target under the stated criterion. No third-party ML deps (numpy +", "+the GPT-2 tokenizer only).", " \"\"\"", " import json, re, math, numpy as np", " from collections import Counter", " from transformers import AutoTokenizer", "-from sklearn.feature_extraction.text import HashingVectorizer", "-from sklearn.linear_model import LogisticRegression", " ", " POOL = \"/workspace/data/pool.jsonl\"", " DEV = \"/workspace/data/multi_dev.npy\""]}, {"oldStart": 45, "oldLines": 7, "newStart": 45, "newLines": 6, "lines": [" tok = AutoTokenizer.from_pretrained(\"gpt2\")", " dev = np.load(DEV).astype(np.int64)", " EOS = 50256", "-# split target token stream on EOS into register segments, decode to text", " seg, cur = [], []", " for t in dev:", " if t == EOS:"]}, {"oldStart": 56, "oldLines": 70, "newStart": 55, "newLines": 80, "lines": [" pos_texts = [tok.decode(s) for s in seg if len(s) > 32]", " print(f\"target positive segments: {len(pos_texts)}\")", " ", "+# ---------------------------------------------------------------- tokenization", "+_word = re.compile(r\"[a-z]{2,}\")", "+def words(t, cap=1200):", "+ return _word.findall(t.lower())[:cap]", "+", " # ---------------------------------------------------------------- quality gates", "-_word = re.compile(r\"[A-Za-z]{2,}\")", "-STOP = set(\"the of and to in a is that for it as was on are with be by this at from \"", "- \"or an which not but have has had they you we he she его\".split())", "+STOP = set(\"the of and to in a is that for it as was on are with be by this at \"", "+ \"from or an which not but have has had they you we he she\".split())", " def gate(t):", "- \"\"\"Return True if doc passes hard quality gates (keep), False to drop.\"\"\"", " n = len(t)", " if n < 400: # too little content to be worth EOS overhead", " return False", "- sample = t[:4000]", "- letters = sum(c.isalpha() for c in sample)", "- if letters / len(sample) < 0.55: # symbol / number / markup spam", "+ s = t[:4000]", "+ letters = sum(c.isalpha() for c in s)", "+ if letters / len(s) < 0.55: # symbol / number / markup spam", " return False", "- asc = sum(ord(c) < 128 for c in sample)", "- if asc / len(sample) < 0.90: # mostly non-English / mojibake", "+ if sum(ord(c) < 128 for c in s) / len(s) < 0.90: # non-English / mojibake", " return False", "- words = _word.findall(sample.lower())", "- if len(words) < 40:", "+ w = _word.findall(s.lower())", "+ if len(w) < 40:", " return False", "- # English stopword presence -> real prose, not keyword lists / boilerplate", "- sw = sum(w in STOP for w in words) / len(words)", "- if sw < 0.06:", "+ if sum(x in STOP for x in w) / len(w) < 0.06: # keyword lists / boilerplate", " return False", "- # repetition: unique-word ratio guards against spam / templated dumps", "- if len(set(words)) / len(words) < 0.30:", "+ if len(set(w)) / len(w) < 0.30: # repetitive spam", " return False", "- up = sum(c.isupper() for c in sample) / max(1, letters)", "- if up > 0.30: # SHOUTING / navbar text", "+ if sum(c.isupper() for c in s) / max(1, letters) > 0.30: # SHOUTING / navbar", " return False", " return True", " ", " gate_mask = np.array([gate(t) for t in texts])", " print(f\"passed gates: {int(gate_mask.sum())} / {N}\")", " ", "-# ---------------------------------------------------------------- classifier", "-def norm(t):", "- return t[:6000].lower()", "+# ---------------------------------------------------------------- NB word scores", "+pos_ctr = Counter()", "+for t in pos_texts:", "+ pos_ctr.update(words(t))", "+neg_idx = rng.choice(N, size=min(10000, N), replace=False)", "+neg_ctr = Counter()", "+for i in neg_idx:", "+ neg_ctr.update(words(texts[i]))", " ", "-# negatives: random pool sample (mostly off-target); positives: target segments", "-neg_idx = rng.choice(N, size=min(8000, N), replace=False)", "-train_texts = pos_texts + [norm(texts[i]) for i in neg_idx]", "-y = np.r_[np.ones(len(pos_texts)), np.zeros(len(neg_idx))]", "+# vocabulary: words seen enough overall to be reliable", "+vocab = {}", "+for w, c in pos_ctr.items():", "+ if c + neg_ctr.get(w, 0) >= 5:", "+ vocab[w] = len(vocab)", "+for w, c in neg_ctr.items():", "+ if w not in vocab and c >= 5:", "+ vocab[w] = len(vocab)", "+V = len(vocab)", "+pos_tot = sum(pos_ctr.values()); neg_tot = sum(neg_ctr.values())", "+k = 1.0", "+s = np.zeros(V, dtype=np.float64)", "+for w, j in vocab.items():", "+ p = (pos_ctr.get(w, 0) + k) / (pos_tot + k * V)", "+ q = (neg_ctr.get(w, 0) + k) / (neg_tot + k * V)", "+ s[j] = math.log(p) - math.log(q)", "+print(f\"vocab {V}\")", " ", "-vec = HashingVectorizer(analyzer=\"word\", ngram_range=(1, 2),", "- n_features=2**20, alternate_sign=False, norm=\"l2\",", "- lowercase=True)", "-Xtr = vec.transform(train_texts)", "-clf = LogisticRegression(C=1.0, max_iter=400, class_weight=\"balanced\")", "-clf.fit(Xtr, y)", "-print(\"classifier train acc:\", round(clf.score(Xtr, y), 4))", "+# ---------------------------------------------------------------- score pool", "+score = np.full(N, -1e9, dtype=np.float64)", "+get = vocab.get", "+for i in range(N):", "+ if not gate_mask[i]:", "+ continue", "+ js = [get(w) for w in words(texts[i])]", "+ js = [j for j in js if j is not None]", "+ if len(js) >= 30:", "+ score[i] = s[np.asarray(js)].mean()", " ", "-# score every pool doc", "-Xall = vec.transform([norm(t) for t in texts])", "-score = clf.decision_function(Xall)", "-", " # ---------------------------------------------------------------- dedup + rank", "-# rank gated docs by classifier score (best first)", "-cand = np.where(gate_mask)[0]", "-cand = cand[np.argsort(-score[cand])]", "-", "-# light exact-dedup on a normalized prefix signature to avoid wasting budget on", "-# duplicated boilerplate; keeps the highest-scoring copy (we walk best-first).", "-seen = set()", "-order = []", "+cand = np.where(score > -1e8)[0]", "+cand = cand[np.argsort(-score[cand])] # best first", "+seen, order = set(), []", " for i in cand:", " sig = re.sub(r\"\\s+\", \" \", texts[i][:200].lower()).strip()", " if sig in seen:"]}, {"oldStart": 127, "oldLines": 8, "newStart": 136, "newLines": 7, "lines": [" seen.add(sig)", " order.append(int(ids[i]))", " ", "-# provide well beyond the 12M-token budget (est ~1k tok/doc -> ~12k needed)", "-order = order[:60000]", "+order = order[:60000] # well beyond the 12M-token budget", " json.dump(order, open(OUT, \"w\"))", " print(f\"wrote {len(order)} ids -> {OUT}\")", "-print(\"score pctiles kept:\", np.round(np.percentile(score[cand], [50, 90, 99]), 3))", "+print(\"kept score pctiles:\", np.round(np.percentile(score[cand], [50, 90, 99]), 3))"]}], "originalFile": "\"\"\"Curate a high-quality, on-target pretraining subset from a raw web pool.\n\nCriterion (stated): a document is selected in proportion to how much it *looks\nlike the disclosed target domain* -- broad high-quality English prose spanning\nencyclopedic (Wikipedia), general web prose, news, and technical Q&A -- as judged\nby a bag-of-words logistic-regression quality classifier, subject to hard quality\ngates that remove obviously degenerate web text.\n\nSignal source: the provided dev target `multi_dev.npy` is the target register in\nGPT-2-token form. We decode it and split on the EOS delimiter to obtain thousands\nof genuine positive examples of the target domain. Negatives are a random sample\nof the raw pool (mostly off-target web junk). A hashed word/bigram logistic\nclassifier trained on (positives vs random pool) gives, for every pool document,\nP(looks like target). We gate out degenerate docs (too short, non-English,\nsymbol/number spam, boilerplate-repetitive) and rank the survivors by classifier\nscore in descending order (best first). The training pipeline consumes this\npriority-ordered id list until the 12M-token budget is filled.\n\nReproducible: no hand-picked ids; the ordering is a pure function of the pool and\nthe decoded target under the stated criterion.\n\"\"\"\nimport json, re, math, numpy as np\nfrom collections import Counter\nfrom transformers import AutoTokenizer\nfrom sklearn.feature_extraction.text import HashingVectorizer\nfrom sklearn.linear_model import LogisticRegression\n\nPOOL = \"/workspace/data/pool.jsonl\"\nDEV = \"/workspace/data/multi_dev.npy\"\nOUT = \"/workspace/submission/selection.json\"\nSEED = 1337\nrng = np.random.default_rng(SEED)\n\n# ---------------------------------------------------------------- load pool\nids, texts = [], []\nwith open(POOL) as f:\n for line in f:\n r = json.loads(line)\n ids.append(r[\"id\"]); texts.append(r[\"text\"])\nids = np.array(ids)\nN = len(texts)\nprint(f\"loaded {N} pool docs\")\n\n# ---------------------------------------------------------------- target positives\ntok = AutoTokenizer.from_pretrained(\"gpt2\")\ndev = np.load(DEV).astype(np.int64)\nEOS = 50256\n# split target token stream on EOS into register segments, decode to text\nseg, cur = [], []\nfor t in dev:\n if t == EOS:\n if cur: seg.append(cur); cur = []\n else:\n cur.append(t)\nif cur: seg.append(cur)\npos_texts = [tok.decode(s) for s in seg if len(s) > 32]\nprint(f\"target positive segments: {len(pos_texts)}\")\n\n# ---------------------------------------------------------------- quality gates\n_word = re.compile(r\"[A-Za-z]{2,}\")\nSTOP = set(\"the of and to in a is that for it as was on are with be by this at from \"\n \"or an which not but have has had they you we he she его\".split())\ndef gate(t):\n \"\"\"Return True if doc passes hard quality gates (keep), False to drop.\"\"\"\n n = len(t)\n if n < 400: # too little content to be worth EOS overhead\n return False\n sample = t[:4000]\n letters = sum(c.isalpha() for c in sample)\n if letters / len(sample) < 0.55: # symbol / number / markup spam\n return False\n asc = sum(ord(c) < 128 for c in sample)\n if asc / len(sample) < 0.90: # mostly non-English / mojibake\n return False\n words = _word.findall(sample.lower())\n if len(words) < 40:\n return False\n # English stopword presence -> real prose, not keyword lists / boilerplate\n sw = sum(w in STOP for w in words) / len(words)\n if sw < 0.06:\n return False\n # repetition: unique-word ratio guards against spam / templated dumps\n if len(set(words)) / len(words) < 0.30:\n return False\n up = sum(c.isupper() for c in sample) / max(1, letters)\n if up > 0.30: # SHOUTING / navbar text\n return False\n return True\n\ngate_mask = np.array([gate(t) for t in texts])\nprint(f\"passed gates: {int(gate_mask.sum())} / {N}\")\n\n# ---------------------------------------------------------------- classifier\ndef norm(t):\n return t[:6000].lower()\n\n# negatives: random pool sample (mostly off-target); positives: target segments\nneg_idx = rng.choice(N, size=min(8000, N), replace=False)\ntrain_texts = pos_texts + [norm(texts[i]) for i in neg_idx]\ny = np.r_[np.ones(len(pos_texts)), np.zeros(len(neg_idx))]\n\nvec = HashingVectorizer(analyzer=\"word\", ngram_range=(1, 2),\n n_features=2**20, alternate_sign=False, norm=\"l2\",\n lowercase=True)\nXtr = vec.transform(train_texts)\nclf = LogisticRegression(C=1.0, max_iter=400, class_weight=\"balanced\")\nclf.fit(Xtr, y)\nprint(\"classifier train acc:\", round(clf.score(Xtr, y), 4))\n\n# score every pool doc\nXall = vec.transform([norm(t) for t in texts])\nscore = clf.decision_function(Xall)\n\n# ---------------------------------------------------------------- dedup + rank\n# rank gated docs by classifier score (best first)\ncand = np.where(gate_mask)[0]\ncand = cand[np.argsort(-score[cand])]\n\n# light exact-dedup on a normalized prefix signature to avoid wasting budget on\n# duplicated boilerplate; keeps the highest-scoring copy (we walk best-first).\nseen = set()\norder = []\nfor i in cand:\n sig = re.sub(r\"\\s+\", \" \", texts[i][:200].lower()).strip()\n if sig in seen:\n continue\n seen.add(sig)\n order.append(int(ids[i]))\n\n# provide well beyond the 12M-token budget (est ~1k tok/doc -> ~12k needed)\norder = order[:60000]\njson.dump(order, open(OUT, \"w\"))\nprint(f\"wrote {len(order)} ids -> {OUT}\")\nprint(\"score pctiles kept:\", np.round(np.percentile(score[cand], [50, 90, 99]), 3))\n", "userModified": false}encrypted chain-of-thought — recorded, not exposed
args
{
"command": "cd /workspace; time python3 submission/curate.py 2>&1 | grep -v -i warning",
"description": "Run NB curation pipeline"
}Bash result
loaded 182016 pool docs
target positive segments: 2646
passed gates: 161914 / 182016
vocab 40831
wrote 60000 ids -> /workspace/submission/selection.json
kept score pctiles: [-0.239 0.015 0.203]
real 1m37.202s
user 1m32.430s
sys 0m1.420s
[stdout]
loaded 182016 pool docs
target positive segments: 2646
passed gates: 161914 / 182016
vocab 40831
wrote 60000 ids -> /workspace/submission/selection.json
kept score pctiles: [-0.239 0.015 0.203]
real 1m37.202s
user 1m32.430s
sys 0m1.420s
[metadata] {"noOutputExpected": false}Pipeline works (1m37s). Let me sanity-check what got ranked top vs. bottom before spending an eval run.
args
{
"command": "cd /workspace; python3 -c \"\nimport json\nsel=json.load(open('submission/selection.json'))\ntext={}\nfor line in open('data/pool.jsonl'):\n r=json.loads(line); text[r['id']]=r['text']\nprint('=== TOP 3 ===')\nfor i in sel[:3]:\n print('--- id',i,'---'); print(text[i][:600].replace(chr(10),' ')); print()\nprint('=== RANK ~500 ===')\nfor i in sel[500:501]:\n print(text[i][:500].replace(chr(10),' '))\nprint()\nprint('=== last selected (rank ~59999) ===')\nprint(text[sel[-1]][:400].replace(chr(10),' '))\n\"",
"description": "Inspect top and low ranked docs"
}Bash result
=== TOP 3 ===
--- id 163054 ---
.<|endoftext|>Per offrire informazioni e servizi nel miglior modo possibile,questo sito utilizza cookie tecnici e analitici. Per maggiori informazioni sui cookie e su come eventualmente disabilitarli vedi la Privacy Policy javax.servlet.jsp.JspException at org.apache.struts.taglib.template.InsertTag.doEndTag(InsertTag.java:149) at jsp.common._0002fjsp_0002fcommon_0002ferror_0002ejsperror_jsp_0._jspService(_0002fjsp_0002fcommon_0002ferror_0002ejsperror_jsp_0.java:226) at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:126) at javax.servlet.http.HttpServlet.service(HttpServlet.jav
--- id 146641 ---
<|endoftext|>Cast range - Dota 2 Wiki Gamepedia Help Sign In Register Cast range From Dota 2 Wiki Jump to: navigation, search Play By the forge of creation. This section is under construction. It may still lack crucial information or contain unvalidated statements. You can help by coordinating with the authors and offer your help. Cast range is the range at which a hero may use an ability on another unit. Cast range can be extended by certain abilities and talents. Contents 1 List of cast ranges 2 Cast range granting talents 3 Cast range granting abilities 4 See also List of cast ranges[edit]
--- id 108673 ---
Here are the list of players included in each of the eight playing team in IPL 2007-08. The tournament will begin on April 18, when Bangalore takes on Kolkata at the Chinnaswamy Stadium in Bangalore. The tournament will feature 59 matches in total, the teams playing each other on a home-and-away basis and top four teams will qualify for the semifinal round. 1st and 2nd Semi Final will be played on 30th and 31st of May 2008. Final of IPL will be played on 1st of June 2008 in Mumbai. Bangalore Royal Challengers Players From India: Rahul Dravid (Captain), Praveen Kumar, Anil Kumble, Wasim Jaffer,
=== RANK ~500 ===
UN denies halting Khmer Rouge investigation UNITED NATIONS — The United Nations on Tuesday strongly denied that it had ordered Cambodia war crimes judges to reject a new case involving the Khmer Rouge. With the country gearing up for a major Khmer Rouge era trial this month, Cambodian media reports said five UN staff have resigned in protest at a decision to close the new case without properly investigating the charges. The UN-backed war crimes court has threatened legal action in a bid to preve
=== last selected (rank ~59999) ===
encing Center.<|endoftext|>Prospect Design | Buildings Home Exhibitions Buildings Environments Contact Us South Freeport Residence This house replaced an old building that had suffered greatly over the years. It contains a number of highly efficient features in a relatively traditional package. Walls that are 12 inches thick with cellulose insulation produces a remarkably energy-efficient shell, f
[stdout]
=== TOP 3 ===
--- id 163054 ---
.<|endoftext|>Per offrire informazioni e servizi nel miglior modo possibile,questo sito utilizza cookie tecnici e analitici. Per maggiori informazioni sui cookie e su come eventualmente disabilitarli vedi la Privacy Policy javax.servlet.jsp.JspException at org.apache.struts.taglib.template.InsertTag.doEndTag(InsertTag.java:149) at jsp.common._0002fjsp_0002fcommon_0002ferror_0002ejsperror_jsp_0._jspService(_0002fjsp_0002fcommon_0002ferror_0002ejsperror_jsp_0.java:226) at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:126) at javax.servlet.http.HttpServlet.service(HttpServlet.jav
--- id 146641 ---
<|endoftext|>Cast range - Dota 2 Wiki Gamepedia Help Sign In Register Cast range From Dota 2 Wiki Jump to: navigation, search Play By the forge of creation. This section is under construction. It may still lack crucial information or contain unvalidated statements. You can help by coordinating with the authors and offer your help. Cast range is the range at which a hero may use an ability on another unit. Cast range can be extended by certain abilities and talents. Contents 1 List of cast ranges 2 Cast range granting talents 3 Cast range granting abilities 4 See also List of cast ranges[edit]
--- id 108673 ---
Here are the list of players included in each of the eight playing team in IPL 2007-08. The tournament will begin on April 18, when Bangalore takes on Kolkata at the Chinnaswamy Stadium in Bangalore. The tournament will feature 59 matches in total, the teams playing each other on a home-and-away basis and top four teams will qualify for the semifinal round. 1st and 2nd Semi Final will be played on 30th and 31st of May 2008. Final of IPL will be played on 1st of June 2008 in Mumbai. Bangalore Royal Challengers Players From India: Rahul Dravid (Captain), Praveen Kumar, Anil Kumble, Wasim Jaffer,
=== RANK ~500 ===
UN denies halting Khmer Rouge investigation UNITED NATIONS — The United Nations on Tuesday strongly denied that it had ordered Cambodia war crimes judges to reject a new case involving the Khmer Rouge. With the country gearing up for a major Khmer Rouge era trial this month, Cambodian media reports said five UN staff have resigned in protest at a decision to close the new case without properly investigating the charges. The UN-backed war crimes court has threatened legal action in a bid to preve
=== last selected (rank ~59999) ===
encing Center.<|endoftext|>Prospect Design | Buildings Home Exhibitions Buildings Environments Contact Us South Freeport Residence This house replaced an old building that had suffered greatly over the years. It contains a number of highly efficient features in a relatively traditional package. Walls that are 12 inches thick with cellulose insulation produces a remarkably energy-efficient shell, f
[metadata] {"noOutputExpected": false}Top-ranked docs are polluted — #1 is Italian + a Java stack trace. The mean-over-in-vocab score ignores foreign/code content: a mostly-foreign doc with 30+ encyclopedic English words scores high. Fix: require high in-vocab coverage (drops foreign/code). Let me patch the scoring.
args
{
"replace_all": false,
"file_path": "/workspace/submission/curate.py",
"old_string": "# ---------------------------------------------------------------- score pool\nscore = np.full(N, -1e9, dtype=np.float64)\nget = vocab.get\nfor i in range(N):\n if not gate_mask[i]:\n continue\n js = [get(w) for w in words(texts[i])]\n js = [j for j in js if j is not None]\n if len(js) >= 30:\n score[i] = s[np.asarray(js)].mean()",
"new_string": "# ---------------------------------------------------------------- score pool\n# Score = mean target-vs-pool log-ratio over in-vocab words, but only for docs\n# with high in-vocab COVERAGE. Coverage is the fraction of a doc's words that are\n# known English vocab; foreign-language and code/markup dumps have low coverage\n# and are dropped, which is what pollutes a pure mean-log-ratio ranking.\nscore = np.full(N, -1e9, dtype=np.float64)\nget = vocab.get\nfor i in range(N):\n if not gate_mask[i]:\n continue\n W = words(texts[i])\n js = [get(w) for w in W]\n js = [j for j in js if j is not None]\n if len(js) >= 40 and len(js) / len(W) >= 0.60:\n score[i] = s[np.asarray(js)].mean()"
}Edit result
The file /workspace/submission/curate.py has been updated successfully. (file state is current in your context — no need to Read it back)
[metadata] {"filePath": "/workspace/submission/curate.py", "oldString": "# ---------------------------------------------------------------- score pool\nscore = np.full(N, -1e9, dtype=np.float64)\nget = vocab.get\nfor i in range(N):\n if not gate_mask[i]:\n continue\n js = [get(w) for w in words(texts[i])]\n js = [j for j in js if j is not None]\n if len(js) >= 30:\n score[i] = s[np.asarray(js)].mean()", "newString": "# ---------------------------------------------------------------- score pool\n# Score = mean target-vs-pool log-ratio over in-vocab words, but only for docs\n# with high in-vocab COVERAGE. Coverage is the fraction of a doc's words that are\n# known English vocab; foreign-language and code/markup dumps have low coverage\n# and are dropped, which is what pollutes a pure mean-log-ratio ranking.\nscore = np.full(N, -1e9, dtype=np.float64)\nget = vocab.get\nfor i in range(N):\n if not gate_mask[i]:\n continue\n W = words(texts[i])\n js = [get(w) for w in W]\n js = [j for j in js if j is not None]\n if len(js) >= 40 and len(js) / len(W) >= 0.60:\n score[i] = s[np.asarray(js)].mean()", "originalFile": "\"\"\"Curate a high-quality, on-target pretraining subset from a raw web pool.\n\nCriterion (stated): a document is selected in proportion to how much it *looks\nlike the disclosed target domain* -- broad high-quality English prose spanning\nencyclopedic (Wikipedia), general web prose, news, and technical Q&A -- as judged\nby a length-normalized Naive-Bayes log-likelihood-ratio quality classifier,\nsubject to hard quality gates that remove obviously degenerate web text.\n\nSignal source: the provided dev target `multi_dev.npy` is the target register in\nGPT-2-token form. We decode it and split on the EOS delimiter to obtain thousands\nof genuine positive examples of the target domain. Negatives are a random sample\nof the raw pool (mostly off-target web junk). For every word we estimate\n s(w) = log P(w | target) - log P(w | random-pool)\nwith add-k smoothing, and score a document by the mean of s(w) over its words\n(length-normalized quality). Docs are gated to remove degenerate text (too short,\nnon-English, symbol/number spam, boilerplate-repetitive, SHOUTING) and the\nsurvivors are ranked by score, best first. The training pipeline consumes this\npriority-ordered id list until the 12M-token budget is filled.\n\nReproducible: no hand-picked ids; the ordering is a pure function of the pool and\nthe decoded target under the stated criterion. No third-party ML deps (numpy +\nthe GPT-2 tokenizer only).\n\"\"\"\nimport json, re, math, numpy as np\nfrom collections import Counter\nfrom transformers import AutoTokenizer\n\nPOOL = \"/workspace/data/pool.jsonl\"\nDEV = \"/workspace/data/multi_dev.npy\"\nOUT = \"/workspace/submission/selection.json\"\nSEED = 1337\nrng = np.random.default_rng(SEED)\n\n# ---------------------------------------------------------------- load pool\nids, texts = [], []\nwith open(POOL) as f:\n for line in f:\n r = json.loads(line)\n ids.append(r[\"id\"]); texts.append(r[\"text\"])\nids = np.array(ids)\nN = len(texts)\nprint(f\"loaded {N} pool docs\")\n\n# ---------------------------------------------------------------- target positives\ntok = AutoTokenizer.from_pretrained(\"gpt2\")\ndev = np.load(DEV).astype(np.int64)\nEOS = 50256\nseg, cur = [], []\nfor t in dev:\n if t == EOS:\n if cur: seg.append(cur); cur = []\n else:\n cur.append(t)\nif cur: seg.append(cur)\npos_texts = [tok.decode(s) for s in seg if len(s) > 32]\nprint(f\"target positive segments: {len(pos_texts)}\")\n\n# ---------------------------------------------------------------- tokenization\n_word = re.compile(r\"[a-z]{2,}\")\ndef words(t, cap=1200):\n return _word.findall(t.lower())[:cap]\n\n# ---------------------------------------------------------------- quality gates\nSTOP = set(\"the of and to in a is that for it as was on are with be by this at \"\n \"from or an which not but have has had they you we he she\".split())\ndef gate(t):\n n = len(t)\n if n < 400: # too little content to be worth EOS overhead\n return False\n s = t[:4000]\n letters = sum(c.isalpha() for c in s)\n if letters / len(s) < 0.55: # symbol / number / markup spam\n return False\n if sum(ord(c) < 128 for c in s) / len(s) < 0.90: # non-English / mojibake\n return False\n w = _word.findall(s.lower())\n if len(w) < 40:\n return False\n if sum(x in STOP for x in w) / len(w) < 0.06: # keyword lists / boilerplate\n return False\n if len(set(w)) / len(w) < 0.30: # repetitive spam\n return False\n if sum(c.isupper() for c in s) / max(1, letters) > 0.30: # SHOUTING / navbar\n return False\n return True\n\ngate_mask = np.array([gate(t) for t in texts])\nprint(f\"passed gates: {int(gate_mask.sum())} / {N}\")\n\n# ---------------------------------------------------------------- NB word scores\npos_ctr = Counter()\nfor t in pos_texts:\n pos_ctr.update(words(t))\nneg_idx = rng.choice(N, size=min(10000, N), replace=False)\nneg_ctr = Counter()\nfor i in neg_idx:\n neg_ctr.update(words(texts[i]))\n\n# vocabulary: words seen enough overall to be reliable\nvocab = {}\nfor w, c in pos_ctr.items():\n if c + neg_ctr.get(w, 0) >= 5:\n vocab[w] = len(vocab)\nfor w, c in neg_ctr.items():\n if w not in vocab and c >= 5:\n vocab[w] = len(vocab)\nV = len(vocab)\npos_tot = sum(pos_ctr.values()); neg_tot = sum(neg_ctr.values())\nk = 1.0\ns = np.zeros(V, dtype=np.float64)\nfor w, j in vocab.items():\n p = (pos_ctr.get(w, 0) + k) / (pos_tot + k * V)\n q = (neg_ctr.get(w, 0) + k) / (neg_tot + k * V)\n s[j] = math.log(p) - math.log(q)\nprint(f\"vocab {V}\")\n\n# ---------------------------------------------------------------- score pool\nscore = np.full(N, -1e9, dtype=np.float64)\nget = vocab.get\nfor i in range(N):\n if not gate_mask[i]:\n continue\n js = [get(w) for w in words(texts[i])]\n js = [j for j in js if j is not None]\n if len(js) >= 30:\n score[i] = s[np.asarray(js)].mean()\n\n# ---------------------------------------------------------------- dedup + rank\ncand = np.where(score > -1e8)[0]\ncand = cand[np.argsort(-score[cand])] # best first\nseen, order = set(), []\nfor i in cand:\n sig = re.sub(r\"\\s+\", \" \", texts[i][:200].lower()).strip()\n if sig in seen:\n continue\n seen.add(sig)\n order.append(int(ids[i]))\n\norder = order[:60000] # well beyond the 12M-token budget\njson.dump(order, open(OUT, \"w\"))\nprint(f\"wrote {len(order)} ids -> {OUT}\")\nprint(\"kept score pctiles:\", np.round(np.percentile(score[cand], [50, 90, 99]), 3))\n", "structuredPatch": [{"oldStart": 115, "oldLines": 14, "newStart": 115, "newLines": 19, "lines": [" print(f\"vocab {V}\")", " ", " # ---------------------------------------------------------------- score pool", "+# Score = mean target-vs-pool log-ratio over in-vocab words, but only for docs", "+# with high in-vocab COVERAGE. Coverage is the fraction of a doc's words that are", "+# known English vocab; foreign-language and code/markup dumps have low coverage", "+# and are dropped, which is what pollutes a pure mean-log-ratio ranking.", " score = np.full(N, -1e9, dtype=np.float64)", " get = vocab.get", " for i in range(N):", " if not gate_mask[i]:", " continue", "- js = [get(w) for w in words(texts[i])]", "+ W = words(texts[i])", "+ js = [get(w) for w in W]", " js = [j for j in js if j is not None]", "- if len(js) >= 30:", "+ if len(js) >= 40 and len(js) / len(W) >= 0.60:", " score[i] = s[np.asarray(js)].mean()", " ", " # ---------------------------------------------------------------- dedup + rank"]}], "userModified": false, "replaceAll": false}encrypted chain-of-thought — recorded, not exposed
args
{
"command": "cd /workspace; time python3 submission/curate.py 2>&1 | grep -v -i warning; echo \"=== TOP after fix ===\"; python3 -c \"\nimport json\nsel=json.load(open('submission/selection.json'))\ntext={}\nfor line in open('data/pool.jsonl'):\n r=json.loads(line); text[r['id']]=r['text']\nfor i in sel[:6]:\n print('--- id',i,'---'); print(text[i][:350].replace(chr(10),' ')); print()\n\"",
"description": "Re-run with coverage gate, inspect top"
}Bash result
loaded 182016 pool docs
target positive segments: 2646
passed gates: 161914 / 182016
vocab 40831
wrote 60000 ids -> /workspace/submission/selection.json
kept score pctiles: [-0.239 0.015 0.203]
real 1m36.791s
user 1m31.850s
sys 0m1.640s
=== TOP after fix ===
--- id 163054 ---
.<|endoftext|>Per offrire informazioni e servizi nel miglior modo possibile,questo sito utilizza cookie tecnici e analitici. Per maggiori informazioni sui cookie e su come eventualmente disabilitarli vedi la Privacy Policy javax.servlet.jsp.JspException at org.apache.struts.taglib.template.InsertTag.doEndTag(InsertTag.java:149) at jsp.common._0002f
--- id 146641 ---
<|endoftext|>Cast range - Dota 2 Wiki Gamepedia Help Sign In Register Cast range From Dota 2 Wiki Jump to: navigation, search Play By the forge of creation. This section is under construction. It may still lack crucial information or contain unvalidated statements. You can help by coordinating with the authors and offer your help. Cast range is the
--- id 168499 ---
<|endoftext|>SQLite: Check-in [b0cc6be4] / Check-in [b0cc6be4] Login Home Timeline Branches Tags Tickets Wiki More... Many hyperlinks are disabled. Use anonymous login to enable hyperlinks. Overview Comment: Allow ROWID values in indexed vector comparisons. Downloads: Tarball | ZIP archive | SQL archive Timelines: family | ancestors | descendants |
--- id 163002 ---
gPowered byeMuseum<|endoftext|>Instantiate Java Way2Java a blog for Java Responsive Menu Home Table Of Contents Search Instantiate Java Java General Instantiate Java S. Nageswara Rao, Corporate Trainer August 18, 2013 2 Comments In Java, object creation is known as instantiation because an instance of a class is object. Let us explain more through
--- id 73993 ---
|PREDECESSORS AND SHORT HISTORY: in the 16th century by Rao Gopalji fl.1550, 4th son of Raja Prithviraj Singhji I of Jaipur. Rulers were… - Rao GOPAL SINGH, Thakur Saheb of Chomu fl.1550, married and had issue. - Thakur NATHU SINGH, Thakur Saheb of Chomu, founder of - Thakur KARAN SINGH, Thakur Saheb of Chomu - Thakur MOHAN SINGH, Thakur Saheb of C
--- id 37522 ---
Prime Minister Imran Khan on Thursday congratulated India’s premier Narendra Modi on his victory in the country's national elections. "I congratulate Prime Minister Modi on the electoral victory of BJP and allies. Look forward to working with him for peace, progress and prosperity in South Asia," the prime minister said on Twitter. I congratulate P
[stdout]
loaded 182016 pool docs
target positive segments: 2646
passed gates: 161914 / 182016
vocab 40831
wrote 60000 ids -> /workspace/submission/selection.json
kept score pctiles: [-0.239 0.015 0.203]
real 1m36.791s
user 1m31.850s
sys 0m1.640s
=== TOP after fix ===
--- id 163054 ---
.<|endoftext|>Per offrire informazioni e servizi nel miglior modo possibile,questo sito utilizza cookie tecnici e analitici. Per maggiori informazioni sui cookie e su come eventualmente disabilitarli vedi la Privacy Policy javax.servlet.jsp.JspException at org.apache.struts.taglib.template.InsertTag.doEndTag(InsertTag.java:149) at jsp.common._0002f
--- id 146641 ---
<|endoftext|>Cast range - Dota 2 Wiki Gamepedia Help Sign In Register Cast range From Dota 2 Wiki Jump to: navigation, search Play By the forge of creation. This section is under construction. It may still lack crucial information or contain unvalidated statements. You can help by coordinating with the authors and offer your help. Cast range is the
--- id 168499 ---
<|endoftext|>SQLite: Check-in [b0cc6be4] / Check-in [b0cc6be4] Login Home Timeline Branches Tags Tickets Wiki More... Many hyperlinks are disabled. Use anonymous login to enable hyperlinks. Overview Comment: Allow ROWID values in indexed vector comparisons. Downloads: Tarball | ZIP archive | SQL archive Timelines: family | ancestors | descendants |
--- id 163002 ---
gPowered byeMuseum<|endoftext|>Instantiate Java Way2Java a blog for Java Responsive Menu Home Table Of Contents Search Instantiate Java Java General Instantiate Java S. Nageswara Rao, Corporate Trainer August 18, 2013 2 Comments In Java, object creation is known as instantiation because an instance of a class is object. Let us explain more through
--- id 73993 ---
|PREDECESSORS AND SHORT HISTORY: in the 16th century by Rao Gopalji fl.1550, 4th son of Raja Prithviraj Singhji I of Jaipur. Rulers were… - Rao GOPAL SINGH, Thakur Saheb of Chomu fl.1550, married and had issue. - Thakur NATHU SINGH, Thakur Saheb of Chomu, founder of - Thakur KARAN SINGH, Thakur Saheb of Chomu - Thakur MOHAN SINGH, Thakur Saheb of C
--- id 37522 ---
Prime Minister Imran Khan on Thursday congratulated India’s premier Narendra Modi on his victory in the country's national elections. "I congratulate Prime Minister Modi on the electoral victory of BJP and allies. Look forward to working with him for peace, progress and prosperity in South Asia," the prime minister said on Twitter. I congratulate P
[metadata] {"noOutputExpected": false}Doc 163054 is a mixed scraped page (Italian header + Java trace, then English body) — high coverage from the English body. The rest are reasonable (technical/news/encyclopedic) but boilerplate-heavy. Rather than over-tune blindly, let me measure. I'll run my selection's dev eval and a random baseline in parallel to calibrate.
args
{
"command": "cd /workspace; python3 -c \"\nimport json, numpy as np\nrng=np.random.default_rng(0)\nids=[json.loads(l)['id'] for l in open('data/pool.jsonl')]\nsel=list(rng.choice(ids, size=60000, replace=False))\njson.dump([int(x) for x in sel], open('/tmp/random_sel.json','w'))\nprint('random baseline selection written')\n\"",
"description": "Build random baseline selection"
}Bash result
random baseline selection written
[stdout]
random baseline selection written
[metadata] {"noOutputExpected": false}encrypted chain-of-thought — recorded, not exposed
args
{
"command": "cd /workspace; export TOKENIZERS_PARALLELISM=false; echo \"=== MY SELECTION ===\"; time bash dev_eval.sh /workspace/submission/selection.json 2>&1 | grep -Ei \"packed|HELDOUT|dev PPL\"",
"description": "Dev eval on my selection",
"run_in_background": true
}Bash result
Command running in background with ID: btsc4yc3z. Output is being written to: /tmp/claude-0/-workspace/7699cb8a-1e37-4174-b570-b672872f1d62/tasks/btsc4yc3z.output. You will be notified when it completes. To check interim output, use Read on that file path.
Session cwd remains /workspace; directory changes made by the backgrounded command do not apply to subsequent commands.
[metadata] {"noOutputExpected": false, "backgroundTaskId": "btsc4yc3z", "backgroundCwdHint": "Session cwd remains /workspace; directory changes made by the backgrounded command do not apply to subsequent commands."}While that runs, let me draft claim.md.
args
{
"file_path": "/workspace/claim.md",
"content": "# Claim\n\n## Hypothesis\nUnder a fixed 12M-token training budget (~6% of the pool), *which* documents we\ntrain on dominates final held-out perplexity. Selecting documents whose word\ndistribution matches the disclosed high-quality, multi-domain English target\n(Wikipedia / high-quality web prose / news / technical Q&A) — and discarding the\nraw-web junk that makes up most of the pool — will train a markedly better model\nthan a random draw from the pool, at the *same* token count.\n\n## Mechanism (predicts an observable other than final perplexity)\nThe pool is mostly off-target web text (forum chatter, SEO boilerplate, navigation\nmenus, non-English pages, code/stack-trace dumps). A length-normalized Naive-Bayes\nlog-likelihood-ratio scorer, trained with the decoded `multi_dev` target as the\npositive class and a random pool sample as the negative class, assigns each\ndocument a score `mean_w [ log P(w|target) − log P(w|pool) ]`.\n\nObservable predictions, independent of the final PPL number:\n1. **Score is bimodal / heavy-tailed**: only a minority of pool documents score\n above the random-pool mean (~0), so a quality-selected 12M-token set is drawn\n from a small high-scoring head, not the bulk.\n2. **The selected set is register-shifted**: relative to a random draw, selected\n docs have higher English in-vocab coverage, higher stopword rates (real prose),\n longer mean length, and fewer non-ASCII / symbol-spam docs.\n3. **Training-loss trajectory**: the model trained on the selected set reaches a\n lower held-out loss *and* its held-out loss keeps the gap over the random-set\n model throughout training (the gap is a data effect, not a transient of early\n optimization).\n\n## Falsification\nThe claim is false if, holding the frozen training recipe and 12M-token budget\nfixed, the classifier-selected selection does **not** achieve lower held-out\nperplexity on `multi_dev` than a random 60k-id selection from the same pool —\ni.e. quality filtering gives no advantage over do-nothing sampling. It is also\nfalsified if raising the selection threshold (taking a smaller, higher-scoring\nhead) does not move dev perplexity in the predicted direction (down, until the\nhead gets too small to fill the budget with diverse text).\n\n## Transfer\nThe criterion is target-agnostic: swap the positive class for any other\ndisclosed target distribution (e.g. biomedical, legal, code) and the same\nNB-log-ratio + quality-gate pipeline curates a budget-limited, on-target\npretraining set. It requires only a modest sample of target-domain text and no\nlabels on the pool, so it transfers to any raw-web curation problem where the\nevaluation domain is disclosed but the pool is unlabeled.\n"
}Write result
File created successfully at: /workspace/claim.md (file state is current in your context — no need to Read it back)
[metadata] {"type": "create", "filePath": "/workspace/claim.md", "content": "# Claim\n\n## Hypothesis\nUnder a fixed 12M-token training budget (~6% of the pool), *which* documents we\ntrain on dominates final held-out perplexity. Selecting documents whose word\ndistribution matches the disclosed high-quality, multi-domain English target\n(Wikipedia / high-quality web prose / news / technical Q&A) — and discarding the\nraw-web junk that makes up most of the pool — will train a markedly better model\nthan a random draw from the pool, at the *same* token count.\n\n## Mechanism (predicts an observable other than final perplexity)\nThe pool is mostly off-target web text (forum chatter, SEO boilerplate, navigation\nmenus, non-English pages, code/stack-trace dumps). A length-normalized Naive-Bayes\nlog-likelihood-ratio scorer, trained with the decoded `multi_dev` target as the\npositive class and a random pool sample as the negative class, assigns each\ndocument a score `mean_w [ log P(w|target) − log P(w|pool) ]`.\n\nObservable predictions, independent of the final PPL number:\n1. **Score is bimodal / heavy-tailed**: only a minority of pool documents score\n above the random-pool mean (~0), so a quality-selected 12M-token set is drawn\n from a small high-scoring head, not the bulk.\n2. **The selected set is register-shifted**: relative to a random draw, selected\n docs have higher English in-vocab coverage, higher stopword rates (real prose),\n longer mean length, and fewer non-ASCII / symbol-spam docs.\n3. **Training-loss trajectory**: the model trained on the selected set reaches a\n lower held-out loss *and* its held-out loss keeps the gap over the random-set\n model throughout training (the gap is a data effect, not a transient of early\n optimization).\n\n## Falsification\nThe claim is false if, holding the frozen training recipe and 12M-token budget\nfixed, the classifier-selected selection does **not** achieve lower held-out\nperplexity on `multi_dev` than a random 60k-id selection from the same pool —\ni.e. quality filtering gives no advantage over do-nothing sampling. It is also\nfalsified if raising the selection threshold (taking a smaller, higher-scoring\nhead) does not move dev perplexity in the predicted direction (down, until the\nhead gets too small to fill the budget with diverse text).\n\n## Transfer\nThe criterion is target-agnostic: swap the positive class for any other\ndisclosed target distribution (e.g. biomedical, legal, code) and the same\nNB-log-ratio + quality-gate pipeline curates a budget-limited, on-target\npretraining set. It requires only a modest sample of target-domain text and no\nlabels on the pool, so it transfers to any raw-web curation problem where the\nevaluation domain is disclosed but the pool is unlabeled.\n", "structuredPatch": [], "originalFile": null, "userModified": false}encrypted chain-of-thought — recorded, not exposed
args
{
"command": "sleep 45; cat /tmp/claude-0/-workspace/*/tasks/btsc4yc3z.output 2>/dev/null | grep -Ei \"packed|HELDOUT|dev PPL|real|Error\"",
"description": "Check my selection eval progress"
}Bash result
packed 12000000 tokens from 60000 ids -> /tmp/dev_train.npy
[stdout]
packed 12000000 tokens from 60000 ids -> /tmp/dev_train.npy
[metadata] {"noOutputExpected": false}Packed to 12M. Training now. Let me wait for the perplexity.
args
{
"command": "sleep 75; cat /tmp/claude-0/-workspace/*/tasks/btsc4yc3z.output 2>/dev/null | grep -Ei \"HELDOUT|dev PPL|real\"",
"description": "Check training result"
}Bash result
HELDOUT_PPL 360.267 loss 5.8868 train_s 54 /tmp/dev_train.npy
(dev PPL on multi_dev; official uses a hidden disjoint sample of the same HQ domain)
real 1m33.624s
[stdout]
HELDOUT_PPL 360.267 loss 5.8868 train_s 54 /tmp/dev_train.npy
(dev PPL on multi_dev; official uses a hidden disjoint sample of the same HQ domain)
real 1m33.624s
[metadata] {"noOutputExpected": false}My selection scores dev PPL 360.3. Now the random baseline for comparison.
args
{
"command": "cd /workspace; export TOKENIZERS_PARALLELISM=false; bash dev_eval.sh /tmp/random_sel.json 2>&1 | grep -Ei \"packed|HELDOUT\"",
"description": "Dev eval on random baseline"
}Bash result
packed 12000000 tokens from 60000 ids -> /tmp/dev_train.npy
HELDOUT_PPL 453.954 loss 6.1180 train_s 53 /tmp/dev_train.npy
[stdout]
packed 12000000 tokens from 60000 ids -> /tmp/dev_train.npy
HELDOUT_PPL 453.954 loss 6.1180 train_s 53 /tmp/dev_train.npy
[metadata] {"noOutputExpected": false}Beating random 360 vs 454 (−21%). The approach clearly works. Let me check time remaining before iterating.
args
{
"command": "cat /workspace/.timer/remaining_secs",
"description": "Check remaining time"
}Bash result
4489
[stdout]
4489
[metadata] {"noOutputExpected": false}~75 min left; evals are cheap enough to iterate. Let me analyze the composition of the docs actually used (top ~15k) to find the biggest quality lever.
args
{
"command": "cd /workspace; python3 -c \"\nimport json, re, numpy as np\nsel=json.load(open('submission/selection.json'))\ntext={}\nfor line in open('data/pool.jsonl'):\n r=json.loads(line); text[r['id']]=r['text']\ntop=sel[:15000]\neot=sum(text[i].count('<|endoftext|>')>=2 for i in top)\nlens=np.array([len(text[i]) for i in top])\n_w=re.compile(r'[a-z]{2,}')\nSTOP=set('the of and to in a is that for it as was on are with be by this at from or an which'.split())\nswr=[]; cov=[]\nfor i in top[:3000]:\n w=_w.findall(text[i][:4000].lower())\n if w: swr.append(sum(x in STOP for x in w)/len(w))\nprint('top15k used docs:')\nprint(' contain >=2 <|endoftext|>:', eot, f'({100*eot/15000:.0f}%)')\nprint(' char len pctiles', np.percentile(lens,[10,50,90]).astype(int))\nprint(' mean stopword ratio (sample):', round(np.mean(swr),3))\n# how many look like nav/boilerplate: many short menu words\n\"",
"description": "Analyze composition of used docs"
}Bash result
top15k used docs:
contain >=2 <|endoftext|>: 1 (0%)
char len pctiles [ 858 2631 9513]
mean stopword ratio (sample): 0.278
[stdout]
top15k used docs:
contain >=2 <|endoftext|>: 1 (0%)
char len pctiles [ 858 2631 9513]
mean stopword ratio (sample): 0.278
[metadata] {"noOutputExpected": false}The used docs are already clean (median 650 tokens, healthy stopword ratio, ~0% boilerplate-concatenation). Since packing fills from the top, only the ranking of the head matters. To improve I must reorder better docs to the front. The most principled lever: add bigrams to the scorer (separates fluent prose from keyword/nav salad). Let me build a v2 and A/B it.
args
{
"command": "cd /workspace; cp submission/curate.py /tmp/curate_v2.py; python3 - <<'EOF'\n# patch v2: add bigram NB features + length prior, output to /tmp/sel_v2.json\nimport re\nsrc=open('/tmp/curate_v2.py').read()\nsrc=src.replace('OUT = \"/workspace/submission/selection.json\"','OUT = \"/tmp/sel_v2.json\"')\nopen('/tmp/curate_v2.py','w').write(src)\nprint(\"patched output path\")\nEOF\necho done",
"description": "Copy script for v2 experiment"
}Bash result
patched output path
done
[stdout]
patched output path
done
[metadata] {"noOutputExpected": false}encrypted chain-of-thought — recorded, not exposed
args
{
"replace_all": false,
"file_path": "/tmp/curate_v2.py",
"old_string": "_word = re.compile(r\"[a-z]{2,}\")\ndef words(t, cap=1200):\n return _word.findall(t.lower())[:cap]",
"new_string": "_word = re.compile(r\"[a-z]{2,}\")\ndef words(t, cap=1200):\n return _word.findall(t.lower())[:cap]\n\ndef feats(t, cap=1200):\n \"\"\"unigrams + bigrams: bigrams capture prose fluency vs keyword/nav salad.\"\"\"\n u = _word.findall(t.lower())[:cap]\n f = list(u)\n f.extend(u[i] + \"_\" + u[i + 1] for i in range(len(u) - 1))\n return f"
}Edit result
The file /tmp/curate_v2.py has been updated successfully. (file state is current in your context — no need to Read it back)
[metadata] {"filePath": "/tmp/curate_v2.py", "oldString": "_word = re.compile(r\"[a-z]{2,}\")\ndef words(t, cap=1200):\n return _word.findall(t.lower())[:cap]", "newString": "_word = re.compile(r\"[a-z]{2,}\")\ndef words(t, cap=1200):\n return _word.findall(t.lower())[:cap]\n\ndef feats(t, cap=1200):\n \"\"\"unigrams + bigrams: bigrams capture prose fluency vs keyword/nav salad.\"\"\"\n u = _word.findall(t.lower())[:cap]\n f = list(u)\n f.extend(u[i] + \"_\" + u[i + 1] for i in range(len(u) - 1))\n return f", "originalFile": "\"\"\"Curate a high-quality, on-target pretraining subset from a raw web pool.\n\nCriterion (stated): a document is selected in proportion to how much it *looks\nlike the disclosed target domain* -- broad high-quality English prose spanning\nencyclopedic (Wikipedia), general web prose, news, and technical Q&A -- as judged\nby a length-normalized Naive-Bayes log-likelihood-ratio quality classifier,\nsubject to hard quality gates that remove obviously degenerate web text.\n\nSignal source: the provided dev target `multi_dev.npy` is the target register in\nGPT-2-token form. We decode it and split on the EOS delimiter to obtain thousands\nof genuine positive examples of the target domain. Negatives are a random sample\nof the raw pool (mostly off-target web junk). For every word we estimate\n s(w) = log P(w | target) - log P(w | random-pool)\nwith add-k smoothing, and score a document by the mean of s(w) over its words\n(length-normalized quality). Docs are gated to remove degenerate text (too short,\nnon-English, symbol/number spam, boilerplate-repetitive, SHOUTING) and the\nsurvivors are ranked by score, best first. The training pipeline consumes this\npriority-ordered id list until the 12M-token budget is filled.\n\nReproducible: no hand-picked ids; the ordering is a pure function of the pool and\nthe decoded target under the stated criterion. No third-party ML deps (numpy +\nthe GPT-2 tokenizer only).\n\"\"\"\nimport json, re, math, numpy as np\nfrom collections import Counter\nfrom transformers import AutoTokenizer\n\nPOOL = \"/workspace/data/pool.jsonl\"\nDEV = \"/workspace/data/multi_dev.npy\"\nOUT = \"/tmp/sel_v2.json\"\nSEED = 1337\nrng = np.random.default_rng(SEED)\n\n# ---------------------------------------------------------------- load pool\nids, texts = [], []\nwith open(POOL) as f:\n for line in f:\n r = json.loads(line)\n ids.append(r[\"id\"]); texts.append(r[\"text\"])\nids = np.array(ids)\nN = len(texts)\nprint(f\"loaded {N} pool docs\")\n\n# ---------------------------------------------------------------- target positives\ntok = AutoTokenizer.from_pretrained(\"gpt2\")\ndev = np.load(DEV).astype(np.int64)\nEOS = 50256\nseg, cur = [], []\nfor t in dev:\n if t == EOS:\n if cur: seg.append(cur); cur = []\n else:\n cur.append(t)\nif cur: seg.append(cur)\npos_texts = [tok.decode(s) for s in seg if len(s) > 32]\nprint(f\"target positive segments: {len(pos_texts)}\")\n\n# ---------------------------------------------------------------- tokenization\n_word = re.compile(r\"[a-z]{2,}\")\ndef words(t, cap=1200):\n return _word.findall(t.lower())[:cap]\n\n# ---------------------------------------------------------------- quality gates\nSTOP = set(\"the of and to in a is that for it as was on are with be by this at \"\n \"from or an which not but have has had they you we he she\".split())\ndef gate(t):\n n = len(t)\n if n < 400: # too little content to be worth EOS overhead\n return False\n s = t[:4000]\n letters = sum(c.isalpha() for c in s)\n if letters / len(s) < 0.55: # symbol / number / markup spam\n return False\n if sum(ord(c) < 128 for c in s) / len(s) < 0.90: # non-English / mojibake\n return False\n w = _word.findall(s.lower())\n if len(w) < 40:\n return False\n if sum(x in STOP for x in w) / len(w) < 0.06: # keyword lists / boilerplate\n return False\n if len(set(w)) / len(w) < 0.30: # repetitive spam\n return False\n if sum(c.isupper() for c in s) / max(1, letters) > 0.30: # SHOUTING / navbar\n return False\n return True\n\ngate_mask = np.array([gate(t) for t in texts])\nprint(f\"passed gates: {int(gate_mask.sum())} / {N}\")\n\n# ---------------------------------------------------------------- NB word scores\npos_ctr = Counter()\nfor t in pos_texts:\n pos_ctr.update(words(t))\nneg_idx = rng.choice(N, size=min(10000, N), replace=False)\nneg_ctr = Counter()\nfor i in neg_idx:\n neg_ctr.update(words(texts[i]))\n\n# vocabulary: words seen enough overall to be reliable\nvocab = {}\nfor w, c in pos_ctr.items():\n if c + neg_ctr.get(w, 0) >= 5:\n vocab[w] = len(vocab)\nfor w, c in neg_ctr.items():\n if w not in vocab and c >= 5:\n vocab[w] = len(vocab)\nV = len(vocab)\npos_tot = sum(pos_ctr.values()); neg_tot = sum(neg_ctr.values())\nk = 1.0\ns = np.zeros(V, dtype=np.float64)\nfor w, j in vocab.items():\n p = (pos_ctr.get(w, 0) + k) / (pos_tot + k * V)\n q = (neg_ctr.get(w, 0) + k) / (neg_tot + k * V)\n s[j] = math.log(p) - math.log(q)\nprint(f\"vocab {V}\")\n\n# ---------------------------------------------------------------- score pool\n# Score = mean target-vs-pool log-ratio over in-vocab words, but only for docs\n# with high in-vocab COVERAGE. Coverage is the fraction of a doc's words that are\n# known English vocab; foreign-language and code/markup dumps have low coverage\n# and are dropped, which is what pollutes a pure mean-log-ratio ranking.\nscore = np.full(N, -1e9, dtype=np.float64)\nget = vocab.get\nfor i in range(N):\n if not gate_mask[i]:\n continue\n W = words(texts[i])\n js = [get(w) for w in W]\n js = [j for j in js if j is not None]\n if len(js) >= 40 and len(js) / len(W) >= 0.60:\n score[i] = s[np.asarray(js)].mean()\n\n# ---------------------------------------------------------------- dedup + rank\ncand = np.where(score > -1e8)[0]\ncand = cand[np.argsort(-score[cand])] # best first\nseen, order = set(), []\nfor i in cand:\n sig = re.sub(r\"\\s+\", \" \", texts[i][:200].lower()).strip()\n if sig in seen:\n continue\n seen.add(sig)\n order.append(int(ids[i]))\n\norder = order[:60000] # well beyond the 12M-token budget\njson.dump(order, open(OUT, \"w\"))\nprint(f\"wrote {len(order)} ids -> {OUT}\")\nprint(\"kept score pctiles:\", np.round(np.percentile(score[cand], [50, 90, 99]), 3))\n", "structuredPatch": [{"oldStart": 60, "oldLines": 6, "newStart": 60, "newLines": 13, "lines": [" def words(t, cap=1200):", " return _word.findall(t.lower())[:cap]", " ", "+def feats(t, cap=1200):", "+ \"\"\"unigrams + bigrams: bigrams capture prose fluency vs keyword/nav salad.\"\"\"", "+ u = _word.findall(t.lower())[:cap]", "+ f = list(u)", "+ f.extend(u[i] + \"_\" + u[i + 1] for i in range(len(u) - 1))", "+ return f", "+", " # ---------------------------------------------------------------- quality gates", " STOP = set(\"the of and to in a is that for it as was on are with be by this at \"", " \"from or an which not but have has had they you we he she\".split())"]}], "userModified": false, "replaceAll": false}