EmergentTwilight/MMCoT / docs /thinkmorph.md
EmergentTwilight's picture
|
download
raw
51.7 kB
# ThinkMorph workflows
## Canonical BAGEL-family framework
`OURS-Bagel/` owns new training work for the shared BAGEL architecture,
including both `models/Bagel-7B-MoT` and `models/ThinkMorph-7B`. SFT v1 is
implemented with strict YAML, a typed configurable interleaved protocol,
protocol-fingerprinted Parquet conversion, native full-parameter FSDP,
global-count-normalized CE/flow-MSE, EMA, atomic resume, and per-update
TensorBoard/JSONL. LoRA `opd` implements the text/flow contract below; `rl` is
reserved.
The first canonical configs are
`OURS-Bagel/config/sft/thinkmorph_paper_bagel7b.yaml` and the one-update
`thinkmorph7b_sft_smoke.yaml`. New jobs use
`cluster_jobs.submit --source-profile=bagel`; outputs live below
`experiments/output/<base-model>/<dataset>/<version>/...`; see `docs/artifacts.md`.
BAGEL SFT supports two explicit controls. `updates` preserves ThinkMorph's
32K token-packed, optimizer-step recipe. `epochs` uses fixed source-sample
packs and derives the update target from dataset size and logical batch. The
first rank-128 LoRA candidate uses the full original trainable component scope,
constant LR `2e-5`, four samples per rank on four GPUs, logical batch 16, and
ten sample-counted epochs. Its full parity audit is
`docs/research/20260914-225604_bagel_thinkmorph_lora_sft_parity_audit.md`.
The main candidate uses `data/ThinkMorph/Bagel-SFT-IDVal5`, which projects the
audited source-coordinate split onto the native BAGEL Parquet without changing
images or rendered text. It contains 23,741 train rows and 1,249 validation
rows (5%). Epoch mode shuffles every train row deterministically, pads only the
three-slot final logical batch, and resumes by update number. Validation uses
the EMA model, disables all condition dropout, excludes the 15 distributed
tail-padding rows from losses/counts, and runs at step 0 and every epoch.
The BAGEL Qwen stack routes packed-training and query-inference calls by their
explicit keyword contracts rather than `Module.training`; EMA can therefore
remain in deterministic eval mode while using the loss-producing packed path.
Rank-128 LoRA uses replicated DDP, not FSDP: every rank constructs a zero-data
meta skeleton, rank zero reads the base once, and DDP broadcasts it; every GPU stores one BF16 frozen backbone and FP32 LoRA
parameters. EMA is an FP32 adapter shadow temporarily swapped in for
validation, so no second backbone is constructed. Full-parameter paper
reproduction remains FSDP.
Checkpoint assign restores persistent tensors; the omitted non-persistent
rotary buffer is rebuilt before moving rank zero to GPU, while other ranks use
`to_empty` and receive the synchronized state.
Condition dropout retains its original behavior. DDP uses
`find_unused_parameters=true` with a dynamic graph; the attempted static-graph
optimization was removed after it triggered a reducer assertion during
gradient accumulation. LoRA DDP uses activation checkpointing: disabling it
reached roughly 137.5/139.8 GiB even at smaller execution packs and exhausted
memory again when Adam state was initialized. The stable execution is four
samples/rank with accumulation one.
If a rank drops every ViT carrier, BAGEL skips the ViT branch for that batch;
dynamic DDP then treats its ViT LoRA parameters as legitimately unused.
One-hour Delta SIQ attempts write atomic recovery checkpoints every 100
updates and at every validation boundary; wall-clock checkpointing is disabled.
The current step-17599 continuation runs on DeltaAI GH200×2 with microbatch
2 × accumulation 4, preserving logical batch 16 and the fixed logical-batch
sample cursor. It restores adapter, EMA, AdamW, scheduler and both rank RNG
states. Subsequent TIMEOUT retries prefer the continuation's own newest
complete checkpoint. Attempts use the two-hour `ghx4-interactive` queue.
Its config is
`OURS-Bagel/config/sft/thinkmorph_lora_r128_constant_val5_16epoch_2gpu_resume17600.yaml`;
it resumes the four-GPU continuation's latest complete checkpoint `0017599`
and continues toward 23,744 total updates, retaining the parent TensorBoard history.
After the A6000 trial OOMed before publishing a checkpoint, the original frozen
GH200×2 run was re-enqueued in the same output directory. Its newest committed
checkpoint is `0019599`; it resumes at update 19,600 with GPU-resident EMA.
The 16-epoch continuation config
`OURS-Bagel/config/sft/thinkmorph_lora_r128_constant_val5_16epoch_4gpu_continue.yaml`
extends the completed 10-epoch checkpoint `0014839` to 23,744 total updates.
It uses four GH200s, two samples per rank and two accumulation microsteps.
Epoch extension requires a completed constant-LR parent at its final update;
seed and all mathematical settings stay identical. Explicit hardware migrations
may adjust processes, samples per pack and accumulation while preserving logical
batch 16; added ranks use their seeded RNG when no parent-rank RNG exists.
It restores student/EMA/optimizer/scheduler/RNG state, inherits TensorBoard
history, and writes new checkpoints in its own parent-linked run directory.
Lab continuation uses `/mnt/ultracube/tac010/MMCoT`, shared by simiao and
luogeng, and the private shared environment
`/mnt/ultracube/tac010/apps/miniforge3/envs/ThinkMorph`. The A6000×8 config
`thinkmorph_lora_r128_constant_val5_16epoch_luogeng_a6000x8.yaml` resumes
checkpoint `0019599`, with train microbatch one and accumulation two (logical
batch 16). Validation uses one sample per rank while retaining all 1,249 rows
and padding masks. `distributed.ema_cpu_offload=true` keeps the FP32 EMA shadow
and validation student backup on CPU; updates retain the same EMA equation and
checkpoint keys. NCCL loading stages one adapter tensor at a time on CUDA.
This frees about 2.7 GiB per rank; GPU-resident EMA at microbatch one reached
47 GiB and OOMed on the first A6000 batch. CPU EMA passed the first updates
but later also OOMed, so this configuration is not validated for the full run.
Hardware continuation may change
validation pack size and EMA placement.
Transfer only the BAGEL source closure, base weights, IDVal5 cache, selected
checkpoint and parent metadata/TensorBoard through the `EmergentTwilight/MMCoT`
bucket. `thinkmorph_sft.relocate_bagel_cache` rebases copied JSON path metadata
and retains its original files. Prepare a parent-linked source snapshot on the
lab filesystem and execute its frozen script through luogeng's `gpuq` with
eight exclusive GPUs; Slurm directives are inert when that script runs in Bash.
Independent OPD replicas stage the originating run's immutable source closure
under `experiments/cache/` through a task-scoped HF bucket prefix, leaving the
lab's live source tree unchanged. Prepare a BAGEL snapshot from that staged
source project and record `env SPATIAL_MMCOT_PROJECT_ROOT=/mnt/ultracube/tac010/MMCoT`
in the launch argv, so models/data still resolve from the canonical lab project
while `SPATIAL_MMCOT_SOURCE_ROOT` remains the new frozen source. Use the explicit
`/mnt/ultracube/tac010/apps/miniforge3/envs/ThinkMorph` prefix: a separate empty
`/mnt/ultracube/tac010/envs/ThinkMorph` can shadow a name-only mamba invocation.
Luogeng's approved `http://webproxy.ucsd.edu:3128` HTTP(S) proxy is required for
Hub/judge access; pin it per task, without changing scheduler/global settings.
Transfer judge credentials only over SSH into the ignored, mode-0600 key file;
keep them out of buckets, snapshots, argv and logs.
A same-start replica copies the original step-zero checkpoint (including
student/EMA/reference and all four rank RNG states), not the active run's newest
checkpoint. `lab_replica.json` records source provenance, GPU allowlist and the
future `gpuq` argv. `prepared_not_queued` means no GPU task has been submitted;
only an explicit later launch should execute that argv. Four-GPU replicas keep
logical batch 16 and use `--gpu-count 4 --gpus 0,1,2,3`; the queue owns device
visibility. The cluster run is independent and remains untouched.
For a two-GPU launch of an **unstarted** replica, use
`config/opd/thinkmorph_igopd_nec_all_2gpu.yaml`; only `trainer.processes` changes
from four to two. The dynamic queues still collect 16 fresh trajectories per
optimizer update and backpropagate one trajectory at a time, so no separate
accumulation or batch-size change is needed. Prepare a new parent-linked
snapshot and invoke `thinkmorph_sft.prepare_opd_initial_world_change` before
queueing. It rejects every config difference except process count, rejects
trained/Adam-updated checkpoints, preserves student/EMA/reference/optimizer/
scheduler tensors, and copies parent RNG ranks 0/1 into the two-rank checkpoint.
Only the checkpoint world/config identity is rewritten, with provenance in
`initial_world_change.json`. This initializer does not relax ordinary runtime
resume checks or support world-size changes after training has started.
Use `gpuq --gpu-count 2 --gpus 0,1`; retain the unstarted four-GPU preparation.
If this two-GPU launch is stopped during initial validation before **any**
optimizer update, the untouched four-GPU preparation can be activated again.
Before reusing validation bundles, hold writer locks, require both latest
checkpoints to be step zero, compare every checkpoint field/tensor except
world/config identity, verify matching core-source hashes and config fields
except process count, and validate each sample/seed identity. Copy bundles and
judge diagnostics only into an absent target validation directory; preserve
the source and the original four-rank RNG files. Record this cache import in
`validation_reuse_from_2gpu.json`. This is reuse under an identical initial
policy, not permission to rewind a trained run or relax runtime resume guards.
`projects/ThinkMorph-edited` supplies pinned architecture, packer and FSDP
execution code. It accepts an external dataset registry and both EMA-only
Bagel-7B and model-only ThinkMorph-7B initialization. Experiment configuration,
protocols, preparation, launch and artifact publication belong only to
`OURS-Bagel`.
## Canonical BAGEL on-policy distillation
`bagel_mmcot.opd` implements `docs/modeling.md` §4. The strict schema and entry
point are `config/opd/thinkmorph_joint.yaml` and
`python -m bagel_mmcot opd train --config ... --output-dir ...`.
Default initialization is `models/ThinkMorph-7B/model.safetensors`; original
BAGEL uses `model.path=models/Bagel-7B-MoT`, `model.weights=ema`. An optional
canonical SFT adapter may initialize the student; its rank/alpha and target
scope must match. LoRA is FP32 over a BF16 backbone and the VAE stays frozen.
- Text targets use exact sampled IDs, including model-owned EOS. Full-vocabulary
JSD, forward KL and reverse KL are selectable; positive log-ratio clipping
shapes the detached EMA target. Vocabulary projection is checkpointed by
target-token chunk rather than dropping support mass.
- Flow targets use detached `(x_t,t)` recorded before selected steps of the
student's actual reverse Euler solve. Selection is uniform without replacement
and seeded independently of the solver. Targets use signed, unclipped teacher
velocity extrapolation and coordinate-mean MSE. v1 validates raw data-to-noise
velocity, Euler and CFG scales one explicitly; guided inference fields and
alternative solvers are not implemented.
- All four views preserve query carriers, block layout and RoPE positions.
Scoring reconstructs the complete packed prefix; hidden text payload keys and
both VAE/ViT generated-image payloads are zeroed and masked at every layer.
Structural marker pieces remain visible. Frozen VAE posterior samples use a
content-derived seed/cache, shared by rollout and all scoring views. Learned
vision/projection features are recomputed with the active parameter view.
- Necessity uses student 11; sufficiency uses student 01 and excludes events
without earlier generated blocks. Components reduce event means within a
trajectory, then means over globally accepted trajectories with that component.
- Reference is the run-start student adapter, persisted independently of EMA.
It evaluates accepted event unions once, always full-visible and unprivileged,
with the same sampled prefix/flow state. Direction means are equally weighted
over the fixed enabled directions. Reference weight zero disables this term.
- Routing modes are `all`, `correct_only`, `privileged_wrong`. Only paired
teacher views receive answer privilege; student and reference never do.
Verifiers use normalized exact answers or rule-prefetched DeepSeek semantic
equivalence. Presentation-only outer answer/math/boxed wrappers and comma
spacing normalize locally; leading decimal points remain significant. This does not infer an answer from full reasoning,
inspect images, or simulate navigation paths. API errors remain errors, never
silently converted to incorrect labels.
- Replay modes are `off`, `uniform`, `failure_first`. Its fixed global budget
uses current failed indices first when requested, then samples outside all
current raw indices. Replay rereads complete native GT, with unweighted text
CE and flow MSE globally normalized by their own target counts. Condition
dropout is disabled. Its logit-normal forward noising is separate from OPD's
saved reverse states.
OPD uses two dynamic queues per frozen logical batch:
1. GPU workers atomically claim prompts and commit each trajectory/verdict.
2. After every logical slot completes, determine routing, component/trajectory
denominators and fixed-budget GT replay in **logical-slot order**. Native
replay packs are counted before backward; their deterministic reconstruction
is checked against those counts.
3. One shared backward queue contains whole trajectory-scoring tasks and whole
GT-replay tasks. Any optimizer rank can read another worker's committed
trajectory and claim the next task. Event/query losses are backpropagated
serially within a trajectory to bound activation memory.
4. Only after every backward task completes, SUM globally normalized gradients
across bounded buckets, clip once, apply AdamW once, then update EMA once.
`trainer.processes` is the number of GPUs/optimizer ranks. Logical batch remains
16 in the canonical config; it need not divide the rank/worker count, and a rank
may receive zero tasks. `rollout.workers_per_gpu` and
`evaluation.workers_per_gpu` include the main rank and default to one. Values
above one spawn persistent inference-only replicas on that rank's assigned GPU;
their student adapters refresh through shared CPU buffers before each phase.
They do not join NCCL or own optimizer/EMA/reference state. Backward uses one
replica per GPU to bound memory, with dynamic ownership across GPUs. Extra
inference replicas retain their backbone allocations during backward: worker
counts must fit the combined peak, not just standalone inference memory.
Python, NumPy and Torch randomness is scoped to sample/update/phase rather than
worker identity, including the native GT packer's logit-normal time draws.
Queue completion order cannot alter failure-first selection or normalization.
Floating-point accumulation order can still differ; numerical agreement, not
cross-hardware bitwise identity, is the reproducibility contract.
Queue claims are attempt-local FileStore state. Workers wait on file-store
completion/failure markers before entering collectives, so a healthy long query
does not consume a collective timeout. `scheduling/` exposes the latest attempt's
task owners/timings in logical order; `_runtime/<attempt>/audit/` retains each
attempt's original scheduling evidence. Reference remains frozen. Losses,
coverage, clipping and fixed validation go to TensorBoard and per-update JSON.
Each sample first atomically saves text IDs, images and solver states with
`verdict: null`, then atomically finalizes the same bundle after valid judging.
Retries reuse that pending trajectory and rerun only the judge; committed
verdicts remain immutable. A pending/unverified trajectory cannot enter backward.
Complete checkpoints include optimizer/scheduler, student, EMA, reference
identity/weights and rank RNG; an initial checkpoint precedes rollout.
`checkpoint_every=1` is required: every reusable query batch must have a
committed behavior policy. Recomputing several uncheckpointed updates under a
different task order could change floating-point weights and invalidate later
saved trajectories, even when their update numbers/seeds match.
Identical argv resumes the newest complete in-run checkpoint, rebuilds fresh
queues and reuses committed queries with matching behavior update/sample/seed.
An interrupted backward discards partial gradients and reruns the whole
uncommitted update; it never skips tasks because a previous attempt claimed
them. Scheduled validation interrupted after its checkpoint is completed before
the next training batch (including validation at the final update).
New experiments use submission-time BAGEL snapshots and SIQ for interactive
partitions. `config/opd/thinkmorph_joint_a40_smoke.yaml` reduces rank, images,
solver/query budget and logical batch for a runtime check. The wrapper
`thinkmorph_sft.opd_resume_smoke` invokes identical argv twice and verifies
reference immutability, optimizer progression and nonzero native components.
GPU execution evidence is recorded in its `smoke_report.json`; successful CPU
tests alone do not establish GPU or learning quality.
`thinkmorph_dynamic_a40_smoke.yaml` runs two optimizer ranks with a smaller
logical batch for queue verification. The same wrapper's
`--interrupt-collection` option deliberately terminates only its own process
group after a committed query, then checks identical-argv query reuse, distinct
backward tasks and checkpoint progression. The deterministic CPU suite also
checks skewed queues, peer failure, persistent worker refresh, and logical-16
distributed-versus-serial gradient agreement.
The A40 smoke `20260929-162430_joint_text_flow_nec_suf_reference_replay_a40`
completed two updates/four fresh rollouts across two identical launches. It
restored EMA counter 1 and immutable reference counter 0, then verified the
reference tensors remained exactly equal at update 2. Text nec/suf and flow
nec were nonzero; pre-clipping norms were 0.02385 and 0.47283, with no clipping
and 29.27 GiB peak allocation. Each sampled trajectory had one generated image,
so T→V sufficiency was correctly absent; its multi-image masks/gradient/query
semantics have CPU regression coverage, not real multi-image GPU evidence yet.
All four answers matched the exact verifier, so this smoke exercised replay's
batch-external fallback; incorrect/invalid routing and failure-first selection
are covered separately by deterministic tests. These are runtime checks, not
evidence of accuracy or image-quality gains.
### Necessity-only routing comparison and memory smoke
`config/opd/thinkmorph_igopd_nec_all.yaml` and
`thinkmorph_igopd_nec_privileged_wrong.yaml` differ only in name and routing.
Both disable sufficiency without renormalizing the remaining weights: T→V and
V→T necessity each have weight 0.25; guidance alpha is respectively 0.25/0.5.
They use LoRA-r16, LR 2e-6, logical batch 16, uniform replay budget 4 with weight
0.01, frozen-reference weight 0.1 and EMA decay 0.995. `all` admits every
structurally valid complete trajectory, including wrong answers;
`privileged_wrong` adds the verified GT answer only to wrong trajectories'
paired teacher views. Invalid/truncated trajectories enter neither OPD branch.
Student, reference, and validation rollout never receive answer privilege.
The text cap is 4,096 **new tokens per text block**, not per trajectory;
`max_images=5` counts generated images. The separate 16,384-position context
guard remains in place, so these are independent stopping bounds, not a promise
to generate five images plus six full-length text blocks. Images retain native
512–1,024 geometry, and raw Euler sampling retains 49 intervals/four queries.
Every 16 updates, the current **student** autonomously rolls out the same fixed
128 held-out queries and the verifier checks final answers. This is rollout
accuracy/validity, not teacher-forced token accuracy or validation loss.
Current validation inherits the training rollout temperature/sampling/limits;
there is no separate greedy-validation switch. Step-zero and final validation
also run; identical-argv retries reuse committed validation samples.
For the A100×4 30-minute memory check,
`thinkmorph_igopd_nec_a100_smoke.yaml` changes only the run name, horizon to one
update, validation count to four and `trainer.memory_profile=true` from the
privileged configuration. It retains logical16, r16, full image resolution,
solver budget and long rollout caps. The entrypoint
`python -m thinkmorph_sft.opd_memory_smoke --config ... --output-dir ...`
reports all ranks' allocation/reservation peaks, phase errors, actual generated
length/image counts and which necessity components executed. Profiling records
live state sizes and CUDA peaks under `memory/rank-<rank>-<attempt>/`; it is
disabled in production and preserves lifetime peak metrics when enabled.
Natural short-rollout success does not establish worst-case 4,096-token/five-image
safety. A timeout or an unexercised branch is not reported as a passed memory test.
### Robust judging and startup recovery
The DeepSeek fallback puts the equivalence rule in a system message and serializes
question/reference/candidate as JSON data. It requests `json_object` output with
one boolean `correct` field and explicitly disables thinking. The output budget
starts at 256 tokens and doubles to at most 1,024 across the existing bounded
retry count. Empty/malformed/truncated responses are retried with backoff;
HTTP 408/429/5xx and connection failures are retryable, while permanent client
errors (such as authentication) fail promptly. Only `finish_reason=stop` can
yield a verdict. Exact, full-string legacy labels such as `A.`, `(A)` or
`Answer: B` are accepted, but prose containing letters, duplicate JSON keys,
string/number booleans and ambiguous answers are rejected.
Every API attempt records the judge protocol, sample, request data, response
content (bounded/redacted), finish reason, usage and error class in the sample's
adjacent `<slot>.judge/` directory. Authorization headers are never recorded;
the active API key and key-like strings are redacted. Exhausted retries still
abort the uncommitted update, preserving the pending rollout for the next launch.
The archived failure's original API response was not saved, so its exact text
cannot be reconstructed; formatting and pending-rollout regressions exercise the
known failure paths without claiming to reproduce that lost response.
For a verifier failure before the **first optimizer update**, prepare a distinct
source snapshot with `--parent-run`, then run
`python -m thinkmorph_sft.prepare_opd_verifier_retry --parent-run ... --run-dir ... --config ...`
before SIQ enqueue. This requires an unchanged full config/world/reference
identity, a step-zero checkpoint whose student/EMA/reference are equal, no Adam
update state, complete rank RNG files and an inactive parent writer. It copies
that state byte-for-byte and validates each cached query's split/slot/sample/
seed/behavior identity. Generated trajectories are reused as pending; old judge
decisions and validation aggregates are deliberately not carried over to the
repaired judge protocol. `verifier_retry.json` records the lineage and selected
samples. The parent remains untouched. Later SIQ TIMEOUT retries use the child's
ordinary newest complete checkpoint and committed query cache. This narrow
startup repair does not authorize changing a trained run's judge mid-experiment.
Each GPU stores one frozen BF16 backbone, student FP32 LoRA and its gradients/
Adam states. EMA and reference have independent FP32 LoRA shadows on CPU; a
no-grad teacher/reference call temporarily loads that shadow and restores the
student afterward. No second full teacher backbone or teacher autograd graph
is retained. For the native ThinkMorph-7B checkpoint and `scope=mot,r=16`,
header-derived estimates are: backbone 27.21 GiB, VAE 0.16 GiB, student LoRA
0.30 GiB, gradients 0.30 GiB, Adam moments 0.60 GiB (about 28.6 GiB fixed GPU
storage), plus one temporary 0.30 GiB adapter view. Each CPU shadow is 0.30 GiB.
Activations, KV caches, vocabulary chunks, attention masks, NCCL and allocator
workspace are additional. These are estimates, not measured peaks; A100×4
replicates this footprint on each card instead of pooling four cards' memory.
## Legacy native ThinkMorph-7B OPD prototype
`ThinkMorph-OPD/` contains the earlier native `models/ThinkMorph-7B` backbone,
protocol tracer, and V→T-only LoRA OPD trainer. It imports BAGEL/MoT architecture code from
`projects/ThinkMorph-edited` but never substitutes `models/Bagel-7B-MoT`
weights. The first real trace, exact token IDs, heterogeneous VAE/ViT/diffusion
carriers, controller state machine, and LoRA boundary are recorded in
`docs/research/20260910-222300_thinkmorph7b_native_token_and_state_machine.md`.
It is retained for evidence and migration tests; new OPD changes wait for its
audited move into `OURS-Bagel`.
The first native objective selects every complete generated-image→next-text
block and implements Necessity only. EMA C11 includes both the generated
clean-VAE and ViT carriers; EMA C10 creates shape-matched carriers without
encoding RGB and marks every VAE/ViT payload KV invisible to target attention.
It preserves `<|vision_start|>`, `<|vision_end|>`, logical carrier length and the
two image RoPE steps. Both views receive the same answer privilege only for an
incorrect rollout. They score the unchanged sampled text block, including its
ChatML end target. A positive C11−C10 log-ratio shapes the C11 teacher target,
which is distilled to the full-visible student with symmetric JSD.
Scoring reconstructs historical carriers under stop-gradient, then retains the
student graph through the current generated image and target block. The base
adapter covers understanding and `_moe_gen` attention/MLP linears; SigLIP,
VAE, connectors and output heads stay frozen. Its support is the deduplicated union
of C11/C10 top-128 tokens, with retained-mass checks and the same per-coordinate
0.05 clipping semantics as the public Visual-OPSD implementation.
The DeepSeek verifier is rule-prefetched and fail-closed. Current-update wrong
or invalid sample indices fill the fixed replay budget first; any deficit is
uniformly filled outside the raw rollout batch. Replay re-reads the independent
GT sample and reconstructs the original ThinkMorph training plan: observation
VAE+ViT, instruction, GT text-1, noised GT-image rectified-flow target, the same
image as clean VAE+ViT context, and GT text-2. It applies length-reweighted text
CE plus visual-position-mean flow MSE, and never pairs a wrong sampled image
with GT continuation. T→V remains absent from OPD but is preserved by replay.
`configs/v2t_opd_base.yaml` uses logical batch 16 on four GH200 ranks, 128 updates
(2,048 fresh rollouts), rank/alpha 16, rollout temperature 0.75, LR 5e-6,
EMA 0.995, JSD β/temperature 0.5/1.0, contrast alpha 0.5, and replay 4/16 with
outer coefficient 0.01 and text/flow weights 1/1. These values and their evidence status are audited in
`docs/research/20260910-225127_thinkmorph_native_v2t_opd_hyperparameters.md`.
After this 2,048-rollout pilot passes its stop criteria,
`configs/v2t_opd_main.yaml` is the recommended main experiment: 1,000 updates
and 16,000 unique task-proportional rollouts, retaining all objective/replay
settings while using the official-quality 50-step flow sampler, 50-update
warmup, validation every 50 updates and recovery checkpoints every 16 updates.
The trainer writes every rollout atomically, synchronizes globally normalized
LoRA gradients with one flattened collective per dtype instead of hundreds of
per-tensor collectives, checkpoints optimizer/scheduler/EMA state, and
resumes in the same prepared run directory.
The revised GH200×4 smoke completed 4 updates/16 rollouts in 5m06s, including
attention-masked C10, both-expert LoRA/EMA, full text+flow replay, flattened
gradient SUM, start/end validation, per-update checkpoints, TensorBoard and
student/EMA adapters. Peak allocated memory was 79.19 GiB and all gradient
norms were finite without clipping. Its replay coefficient 0.1 was numerically
too large relative to raw OPD, so canonical pilot/main configs use 0.01. No
pilot or main experiment was submitted.
## Paper-aligned BAGEL baseline
The execution fork is `projects/ThinkMorph-edited`, pinned from upstream commit
`c1a48ad`; `OURS-Bagel` owns the baseline and future BAGEL objectives. This is
separate from the UniAR conversion below. The starting model
is the pinned `models/Bagel-7B-MoT` EMA checkpoint, and its isolated DeltaAI
environment is `ThinkMorph` (Torch 2.7.1+cu128, Transformers 4.49.0,
FlashAttention 2.8.3.post1).
`data.convert_thinkmorph` converts all four released datasets to the official
three-column BAGEL contract under `data/ThinkMorph/Bagel-SFT`. It preserves the
official system prompt and tag strings byte-for-byte, re-encodes both images as
PNG, writes 100 rows/file and 10 rows/row-group, and publishes a hash manifest,
`parquet_info.json`, and `READY` atomically.
`OURS-Bagel/config/sft/thinkmorph_paper_bagel7b.yaml` is the canonical
four-GH200 baseline:
8,000 optimizer updates, LR `1e-5`, cosine with 2,000-step warmup, CE/MSE weights
1, condition dropout `0.1/0.3/0.3`, 32K carriers per rank microstep, four
microsteps per update, BF16 four-way `FULL_SHARD`, activation checkpointing,
full-parameter AdamW, EMA `0.9999`, and clip norm 1. The accumulation window uses
one global CE denominator and one global MSE denominator. The smoke entrypoint
keeps the 8,000-step scheduler but stops after 20 committed updates.
The primary-source audit and the known defects in the public launch script are
recorded in
`docs/research/20260905-140823_thinkmorph_official_sft_reproduction_contract.md`.
### DeltaAI environment
```bash
MAMBA=/work/nvme/bgjw/tcheng2/apps/miniforge3-deltaai/bin/mamba
$MAMBA create -n ThinkMorph python=3.12 pip setuptools wheel ninja -y
$MAMBA run -n ThinkMorph python -m pip install 'torch==2.7.1+cu128' \
--index-url https://download.pytorch.org/whl/cu128
$MAMBA run -n ThinkMorph python -m pip install --no-deps \
'torchvision==0.22.1' --index-url https://download.pytorch.org/whl/cu128
$MAMBA run -n ThinkMorph python -m pip install \
-r projects/ThinkMorph-edited/requirements-gh200.txt
```
Install FlashAttention 2.8.3.post1 from an SM90/Torch-2.7-compatible wheel or
build it on a GH200 using the CUDA 12.9 procedure in `docs/uniar.md`. The
current isolated environment passes `pip check` and imports Torch 2.7.1+cu128,
Transformers 4.49.0, and FlashAttention 2.8.3.post1.
The matching x86 environment on Delta is
`/work/nvme/bgjw/tcheng2/apps/miniforge-delta/envs/ThinkMorph`; it has the same
Torch, torchvision, Transformers, and FlashAttention versions. Do not reuse the
DeltaAI AArch64 prefix on Delta.
### VLMEvalKit UniAR evaluation
`projects/VLMEvalKit_Thinkmorph_llm` is the canonical evaluation fork and has
a separate `ThinkMorph-Eval` environment
under both Miniforge installations. It uses Torch 2.7.1+cu128, Transformers
4.57.0, PEFT 0.20.0, FlashAttention 2.8.3.post1, and the fork's evaluation
requirements. `pip check` and the full VLMEvalKit configuration import must
pass on both architectures.
The registered model keys are `uniar-sft`, the rank-64 two-/four-epoch
development adapters, the two-epoch BitCE weight-1/weight-3 ablations, and the
two-epoch absolute-IG adapter `uniar-thinkmorph-v1-ig-abs-r64-val5-2epoch`.
The adapter injects only the canonical training protocol
as the system prompt. It preserves the VLMEvalKit image/text user message
exactly, with no appended instruction, uses the canonical full-prefix
interleaved controller, and returns the readable assistant sequence. Set
`SPLIT_THINK=1` so MCQ scoring receives only the post-thought final segment.
VSP is the exception: inference retains the full assistant response even when
`SPLIT_THINK=1`, because its upstream scorer extracts the boxed path from the
reasoning trace.
Prompt-controlled VSP studies use the registered
`VSP_maze_task_main_original_60_balanced` dataset (ten deterministic examples
per maze size 3--8). Model keys ending in `vsp-thinkmorph-short` or
`vsp-short` replace only the framework-owned VSP user content with the exact
training prompt and its final test image; they retain the UniAR system protocol,
chat template, generation path, and upstream strict scorer.
VSP scoring defaults to the fork-compatible `thinkmorph_strict` mode. Set
`VSP_VALIDATION_MODE=official` to reproduce the official FrozenLake transition
semantics: off-grid actions leave the state unchanged and reaching the goal
terminates successfully. Mode-qualified result filenames prevent cache reuse
across scoring definitions.
Native `models/ThinkMorph-7B` uses `thinkmorph-7b-vsp-short-a40` for the same
short-prompt VSP protocol; its A40-safe model-side batch is four.
BLINK-Jigsaw is cached at `data/VLMEvalKit/BLINK_Jigsaw.tsv`; its MD5 is
`174fc5d2ed0d67f9e0b33cb8a8be6727` and it contains 150 rows.
Canonical LLM-assisted evaluation uses the fork's original verifier with
DeepSeek V4 Flash as its fallback choice extractor:
```bash
LMUData=data/VLMEvalKit SPLIT_THINK=1 torchrun --standalone \
--nproc-per-node=4 projects/VLMEvalKit_Thinkmorph_llm/run.py \
--data BLINK_Jigsaw \
--model uniar-thinkmorph-v1-vanilla-r64-val5-2epoch \
--judge deepseek-v4-flash --reuse --work-dir <prepared-run>
```
The completed canonical DeepSeek-V4-Flash-judged results supersede all scores
from the retired local exact matcher:
| Epoch | Bit CE weight | IG | BLINK-J | VStar overall (direct/relative) | MMVP | SAT overall (action/ego/goal/object/perspective) |
|---:|---:|---|---:|---:|---:|---:|
| 0 | 10 | none | 58.67 | 60.73 (59.13/63.16) | 72.33 | 44.67 (54.05/43.48/58.82/26.09/33.33) |
| 2 | 1 | none | 57.33 | 59.69 (58.26/61.84) | 75.00 | 48.67 (56.76/69.57/52.94/30.43/33.33) |
| 2 | 3 | none | 58.00 | 59.69 (56.52/64.47) | 73.67 | 52.67 (56.76/60.87/76.47/43.48/24.24) |
| 2 | 10 | none | 52.67 | 60.73 (56.52/67.11) | 73.33 | 46.67 (51.35/56.52/70.59/30.43/21.21) |
| 4 | 10 | none | 51.33 | 62.30 (60.87/64.47) | 70.67 | 45.33 (51.35/56.52/70.59/26.09/18.18) |
| 2 | 10 | absolute IG | 46.00 | 59.69 (57.39/63.16) | 74.33 | 46.00 (48.65/69.57/58.82/26.09/27.27) |
All values are percentages. BLINK-J has 150 rows, VStar 191, MMVP 300,
and SAT circular scoring reports 150 paired groups.
When an evaluation is queued before its adapter is committed, bind the SIQ
task to the training SIQ Task ID with `afterok` and set
`WAIT_FOR_ADAPTER_DIR` to the expected adapter directory. The evaluator waits
for its atomic `COMPLETE` marker before loading weights; resumable `--reuse`
keeps a retried bundle in the same result directory.
The same frozen evaluator runs other VLMEvalKit MCQ datasets by setting
`DATASET_NAME`; it leaves each framework-generated user prompt unchanged.
Versioned task evaluations live under
`experiments/output/uniar-sft/<dataset>/v1/runs/eval/`. On Delta, A100 evaluation uses
one model rank per GPU; A40 evaluation may set `VLMEVAL_WORKERS_PER_GPU=2`
and launch eight ranks on four GPUs. Shared-GPU ranks use Gloo only for
barriers, while inference and result shards remain rank-local.
Canonical UniAR task evaluation sets `UNIAR_ROLLOUT_DIR` and atomically saves
one `rollouts/<dataset>/<sample-id>/` directory per generated answer. Its
`rollout.pt` contains prompt, assistant and full token IDs plus observation and
generated visual codes; `metadata.json` contains the unchanged framework
message, decoded event stream, grids, stop/cycle metadata and workbook-facing
artifact identity. RGB image decoding is deferred. A `COMPLETE` marker is the
artifact commit boundary, and the workbook `extra_records` cell links back to
the committed directory.
The runner fixes `VLMEVAL_EVAL_ID=RUN` for the lifetime of a prepared eval run;
otherwise upstream's date/live-Git identity can change across SIQ retries and
strand partial rank pickles in an older directory. It also sets
`VLMEVAL_DUMP_EVERY=1`, so every completed sample updates its rank pickle.
These are persistence controls only and do not modify generation,
`dataset.evaluate`, or the upstream verifier.
Canonical multi-rank inference uses `VLMEVAL_SCHEDULING=dynamic`: ranks claim
the next pending row from one distributed Store counter, commit after every
sample, and merge all prior rank shards before queue initialization. Static
scheduling remains selectable for controlled continuations.
When changing evaluator world size or hardware, seed a new parent-linked run
with `thinkmorph_sft.seed_vlmeval_resume`: it copies committed rollout and
completed benchmark artifacts, merges old rank shards into dataset `PREV.pkl`
files, and rewrites workbook rollout links to the new self-contained run.
When the canonical output path must remain stable, create the changed execution
snapshot under `<eval-run>/_continuations/<timestamp>/` and keep its
`OUTPUT_DIR` pointed at the parent eval run. The nested snapshot and parent
record preserve execution provenance while results and rollouts stay canonical.
The v2 BitCE-weight-3 long control exposes exact epoch-boundary evaluation keys
for epoch 1 (`step-001524`), epoch 2 (`step-003048`), and epoch 3
(`step-004572`); all load the nested checkpoint `adapter/` while validating the
checkpoint-level `COMPLETE` marker.
The lower-LR (`1e-5`) eight-epoch control exposes epoch 3 (`step-004572`) and
`step-009144` through dedicated evaluation model keys.
The Grid16 lower-LR control exposes epoch 6 (`step-009144`) as
`uniar-thinkmorph-v2-r64-grid16-bitce-lambda3-lr1e-5-epoch6`.
The GH200-resumed Grid16 lower-LR control exposes epoch 7 (`step-010668`) as
`uniar-thinkmorph-v2-r64-grid16-lr1e-5-resume1100-epoch7`.
The matching 12-epoch continuation resumes its completed `step-012192` state on
four Delta H200s with the unchanged per-rank microbatch 4/global batch 16; four
additional epochs end at step 18,288.
The LLM fork preserves upstream VLMEvalKit verifier and option-prefetch logic;
do not port the stricter local exact-match verifier into it. Its external judge
is `deepseek-v4-flash` through the official OpenAI-compatible endpoint, using
`DEEPSEEK_API_KEY`; judging defaults to non-thinking mode. `API_KEY` is an
ignored local convenience file and must never enter Git or source snapshots.
Native `models/ThinkMorph-7B` task evaluation uses model key
`thinkmorph-7b-local`. Its batch-8 adapter keeps static rank sharding, writes
intermediate generated images under the eval run's `generated_images/`, and
uses the same stable result namespace and DeepSeek verifier.
The BAGEL rank-128 ten-epoch control uses model key
`bagel-thinkmorph-r128-val5-10epoch`. It reconstructs the audited 556-target
LoRA schema on `models/Bagel-7B-MoT/ema.safetensors`, loads the final EMA
adapter, and prefixes the unchanged benchmark question with the exact training
system prompt after its input-image carrier instead of adding the native
pre-image prompt. Use model-side batch one with the
dynamic queue when sharing each GH200/H200 between two evaluator workers.
The matched unfine-tuned baseline uses `bagel-7b-mot-original`: it loads the
released BAGEL EMA weights with the same protocol, decoding and benchmark
scoring, but does not inject an adapter.
For the canonical VSP comparison use their `-vsp-short` model-key variants
with `VSP_VALIDATION_MODE=official`. These use the exact ThinkMorph short
custom prompt and only the final test image. The suffix affects VSP prompts
only; the other five benchmarks retain their standard dataset prompts.
Prompt variants use separate run/model namespaces to avoid prediction reuse.
## UniAR conversion
### Training corpus
The public ThinkMorph SFT corpus under `data/ThinkMorph/` contains 24,990
train-only rows: Chart Refocus 6,000, Jigsaw Assembly 6,000, Spatial Navigation
6,000, and Visual Search 6,990. Each row has one problem image, two textual
reasoning segments, one intermediate reasoning image, and one answer. Public
training rows are not repurposed as a held-out test split.
`thinkmorph_sft.prepare_cache` converts every row to the canonical
`spatial_mmcot_trajectory_v1` and `zebra_uniar_cache_v1` contracts. The exact
event order is system prompt, user question and observation, then assistant
thought, generated state, thought, and final answer. Rendering is owned by the
same v2 ChatML path as Zebra-CoT, including exactly one newline between
assistant events and the student-owned `<|vision_start|>` boundary. Generated
images are encoded into UniAR BSQ targets; raw ThinkMorph records remain
immutable.
The full-data cache is `data/ThinkMorph/ThinkMorph`. All its manifest rows have
split `train`; it is unchanged by development splitting. Full-data training
disables internal validation. Configuration/epoch selection instead uses the
fixed `data/ThinkMorph/ThinkMorph-IDVal5` development view described below.
Final task evaluation uses external benchmarks, not training membership.
### Fixed 16×16 generated-state cache
`thinkmorph_sft.prepare_grid16_cache` builds the parallel all-train cache
`data/ThinkMorph/ThinkMorph-Grid16` and then projects the existing IDVal5
assignments onto `data/ThinkMorph/ThinkMorph-Grid16-IDVal5`. It never modifies
the original cache or recomputes validation membership.
For every assistant-generated target, the source RGB image is resized with
preserved aspect ratio until its longest edge is 512 pixels, centered on a
512×512 RGB `(128,128,128)` canvas, and then encoded by the canonical UniAR BSQ
encoder. The resulting patch grid is always 32×32 and its composite BSQ grid is
always 16×16. User-query images are not passed through the historical 960px cap
or the extra qwen-vl-utils resize stage; they go directly through the checkpoint
image processor, matching the intended understanding path and its declared
`min_pixels=4096`, `max_pixels=16777216`, patch size 16, and merge size 2.
`OURS/config/sft/v2/thinkmorph_vanilla_r64_val5_grid16_bitlambda3_lr1e-5_8epoch.yaml`
is byte-for-byte equivalent in model, loss, optimizer, schedule, batching,
validation, and duration to the prior lower-LR eight-epoch control, except for
its run identity and Grid16 development-cache path.
### UniAR v1 vanilla configuration
`OURS/config/sft/v1/thinkmorph_vanilla_base.yaml` is the train-only UniAR
counterpart of the v1 Tetris vanilla base, not the separate BAGEL baseline.
It uses all 24,990 cached rows without a validation/test split or prefix subset,
one epoch, half-sample trajectory/update-uniform BitFlip in `[0, 0.1]`,
IG/EMA disabled, and the same text/bit weights, rsLoRA, optimizer, scheduler,
and clip norm 5. Its current rank is 64 (Tetris's original base uses 32).
Four-GPU DDP with microbatch 4 and accumulation 1 gives nominal
logical batch 16. TensorBoard and JSONL log every update; update/wall checkpoints
remain enabled.
`evaluation.enabled=false`, `evaluation.at_start=false`,
`evaluation.samples=0`, and `data.validation_splits=[]` disable startup,
periodic, resumed-step, and final internal validation. No test job is implied.
The Zebra-specific probe IDs/provenance are cleared; this config targets
`sft train`, not the Zebra-small `sft inspect/probe` diagnostics.
### UniAR v2 constant schedule
`OURS/config/sft/v2/` carries the long-horizon configuration family. Its base
files retain the v1 model, data, objective, optimizer, batching, evaluation,
checkpoint, and logging settings, while switching to constant LR after a
fixed update-count warmup. ThinkMorph uses 50 warmup updates; the value is
independent of the configured epoch count.
`thinkmorph_vanilla_r64_val5_bitlambda3_16epoch.yaml` is the first v2
development run: rank 64, fixed IDVal5 split, 16 epochs, Bit CE weight 3,
vanilla SFT with IG/EMA disabled, logical batch 16, and clip norm 5. It saves
an exact checkpoint at every epoch boundary in addition to the ordinary
100-update and 30-minute recovery points, then runs the complete 1,249-row
validation exactly once per epoch. Update-periodic validation is disabled for
this config. The 4/8/12/16-epoch states therefore belong to one constant-LR
trajectory and can be evaluated without changing the scheduler horizon.
### Fixed same-distribution development validation
`data/ThinkMorph/README.md` declares the two views. The development view has
23,741 training and 1,249 validation rows (approximately 5% held out):
Chart Refocus 5700/300, Jigsaw Assembly 5700/300, Spatial Navigation 5700/300,
and Visual Search 6641/349. Whole-group and subtype rounding takes precedence
over forcing exactly 1,250 rows. This is our development split, not an
author-held-out validation/test set.
The split builder owns grouping and selection:
- Preserve source cache IDs and all token/code tensors; only metadata changes.
The new view uses the established absolute-shard-path zero-copy contract.
- Join original-image filename families, exact decoded RGB input **and target**
images, and cross-task image matches into connected groups. Reconstructed
jigsaw targets protect against different shuffles of the same source image.
- Natural-image resize/re-encoding checks use a conservative 128-bit dHash and
thumbnail-difference rule. Sparse charts/mazes are excluded from that fuzzy
rule to avoid grouping distinct diagrams merely because templates match.
- Stratify whole groups by task and available subtype: puzzle grid, maze size,
and chart/search source type. A seeded whole-group subset targets 5% of rows
per stratum; cross-stratum connected groups stay intact.
- Neither answer labels, model losses, nor evaluation outcomes select the
membership. There are 28 multirow groups and 16 recorded near-duplicate
linking edges. Source identity, decoded-pixel identity, and group leakage
audits all pass. This does not prove absence of all arbitrary crops or
semantically equivalent rerenders without retained source identity.
`SPLIT.json` records policy, source hashes and the manifest checksum;
`image_groups.jsonl` records image/source/group/subtype provenance. The fixed
manifest SHA256 is
`6fc8ab060cd29efebe303c4a9c0660271d6e8f5c69c49375a466aa2f04c92c1a`.
Task-specific v3 SFT uses zero-copy views of this fixed split. The Navigation
view is `data/ThinkMorph/ThinkMorph-Navigation-IDVal5`: it retains exactly the
original 5,700 train / 300 validation `Spatial_Navigation` rows and points to
the unchanged tensor shards. Its vanilla configuration is
`OURS/config/sft/v3/thinkmorph_navigation_vanilla_r64_val5_lr1e-5_8epoch.yaml`;
only the run identity, cache view, and full-validation sample count differ from
the v3 all-task control. Its controlled absolute-IG counterpart changes only
the run name, enables validation IG, and applies the established all-event best
setting: T→V weight/temperature `0.05/32` and V→T `10/0.25`.
The Navigation BitCE scale control changes only the vanilla run name and visual
BitCE weight from `10` to `3`; it retains eight epochs and the same fixed split.
The Grid16 Navigation vanilla control instead keeps BitCE weight `10` and all
training settings, but uses the zero-copy
`data/ThinkMorph/ThinkMorph-Grid16-Navigation-IDVal5` view. All 5,700/300 rows
preserve the fixed split and use a 16×16 generated BSQ target.
The completed epoch-6 (`step-002196`) and epoch-8 (`step-002928`) checkpoints
are registered for VSP evaluation as
`uniar-thinkmorph-v3-navigation-r64-lr1e-5-epoch6` and
`uniar-thinkmorph-v3-navigation-r64-lr1e-5-epoch8`.
The matching absolute-IG epoch-6/epoch-8 VSP-short keys are
`uniar-thinkmorph-v3-navigation-ig-abs-best-r64-lr1e-5-epoch6-vsp-short`
and `uniar-thinkmorph-v3-navigation-ig-abs-best-r64-lr1e-5-epoch8-vsp-short`.
The Grid16 navigation epoch-8 VSP-short key is
`uniar-thinkmorph-v3-navigation-grid16-r64-lr1e-5-epoch8-vsp-short`.
Reproduction (only to a new output path; existing views fail closed):
```bash
PYTHONPATH=OURS/src:experiments/src mamba run -n UniAR \
python -m thinkmorph_sft.split_validation \
--source-root data/ThinkMorph \
--source-cache data/ThinkMorph/ThinkMorph \
--output data/ThinkMorph/ThinkMorph-IDVal5 --seed 17 --workers 2
```
### Rank-64 duration selection and full-data final training
The explicitly controlled development configs are:
- `OURS/config/sft/v1/thinkmorph_vanilla_r64_val5_2epoch.yaml`
- `OURS/config/sft/v1/thinkmorph_vanilla_r64_val5_4epoch.yaml`
- `OURS/config/sft/v1/thinkmorph_vanilla_r64_val5_8epoch.yaml`
These are result-producing v1 runs and use `run.category: runs`; their
artifacts resolve below `experiments/output/uniar-sft/thinkmorph/v1/runs/sft/`.
The 2-epoch visual-loss scale ablation uses
`thinkmorph_vanilla_r64_val5_bitlambda{1,3}_2epoch.yaml`. Each changes only
`run.name` and `objective.bit.weight` from the rank-64 2-epoch baseline
(whose bit weight is 10); text weight remains 1. These are independent runs
from UniAR-SFT with their own identical 2-epoch cosine schedules and the full
1,249-row development validation.
`thinkmorph_ig_abs_r64_val5_2epoch.yaml` is the controlled absolute-IG
counterpart of the rank-64 2-epoch vanilla configuration. It enables all-event
absolute IG with T→V weight/temperature `0.05/32` and V→T `10/0.25`, and
records IG during the same complete 1,249-row validation. Every other model,
data, BitFlip, optimizer, schedule, DDP, and logging field matches vanilla.
They differ only in run name and epoch count. All use rank 64, rsLoRA alpha 32,
the existing LoRA/head learning rates 5e-5/1e-5, uniform half-sample BitFlip,
IG/EMA off, global batch 16, clip norm 5, and every-step TensorBoard/JSONL.
Each starts from UniAR-SFT independently and uses its own duration's cosine
schedule; this is not equivalent to taking epoch-2/4 snapshots of an 8-epoch
schedule. No learning-rate change is implied by creating this split.
Internal validation is enabled at startup, every 250 updates, and training
completion, with all 1,249 fixed rows. It is clean teacher-forced text/visual
validation, **not autonomous rollout accuracy**. Treat component losses and
stability as supporting evidence; task-appropriate answer/visual-operation
rollouts and a protected final test remain separate workflows. Do not repeatedly
use a final benchmark test for epoch/rank/LR selection.
`thinkmorph_vanilla_r64_base.yaml` is the matching full-data template: original
cache, rank 64, no held-out split and internal validation off. Set
`trainer.epochs` to the selected duration for the final run. It preserves the
same model/objective/optimizer settings as the development family. Start the
final run from the base model; changing data membership is not an exact resume
of a development run. Keep the held-out results from development runs, but do
not call those rows held out after final full-data training includes them.
### Preparation
The cache builder is multi-GPU, strict about all task counts, and resumable from
committed rank manifests. A torn terminal JSONL line is discarded; an existing
atomic `READY` marker makes a retry exit successfully.
```bash
torchrun --standalone --nproc-per-node=4 -m thinkmorph_sft.prepare_cache \
--source-root data/ThinkMorph \
--model-path models/UniAR-SFT \
--output-root data/ThinkMorph/ThinkMorph \
--attn flash_attention_2 \
--auto-resume
```

Xet Storage Details

Size:
51.7 kB
·
Xet hash:
3bb1afe067a12da54fb8d5377e29173b47db7d9e74d2ac70bd44b00d15a0085c

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.