forma3d-tiny-2 / stage_v2.py
Lucasgitguy-co's picture
Release evaluated Forma3D Tiny 2 continuation
1648582 verified
Raw History Blame Contribute Delete
7.95 kB
"""Evaluate versus pinned forma3d-tiny, stage honest v2 metadata, never upload."""
import argparse
import hashlib
import importlib.util
import json
import shutil
from pathlib import Path
import torch
from audit_data import audit
ROOT = Path(__file__).resolve().parent
REV = 'e80b8d895cc2e405894473abe4ce40b3472eaca7'
BASE = 'Lucasgitguy-co/forma3d-tiny'
def sha(p):
return hashlib.sha256(Path(p).read_bytes()).hexdigest()
def main():
p = argparse.ArgumentParser()
for name in ('run','data','base','release'):
p.add_argument('--'+name, required=True)
p.add_argument('--device', default='mps', choices=['mps','cpu'])
args = p.parse_args()
destination = Path(args.release)
if destination.exists():
raise ValueError('Release directory exists; choose a fresh --release path')
audit(args.data, ROOT / 'upstream/ATTRIBUTIONS.json')
# Ensure the asserted parent is the pinned public checkpoint, not another run.
if sha(args.base) != '83c065d2a50cf086928542cf8d40dc4416b379e38b9aa61d842dc9106d4b3306':
raise ValueError('Expected the pinned published forma3d-tiny model.pt')
spec = importlib.util.spec_from_file_location('pinned_release', ROOT / 'upstream/scripts/release.py')
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
checkpoint, meta, report = module.evaluate_release(args)
# Upstream gate checks completed training, validation loss, held-out loss/IoU,
# source separation, initialization hash and nonempty qualitative predictions.
source = ROOT / 'upstream'
destination.mkdir(parents=True)
for folder in ('src','licenses'):
shutil.copytree(source / folder, destination / folder,
ignore=shutil.ignore_patterns('__pycache__','*.egg-info'))
for name in ('LICENSE','NOTICE','THIRD_PARTY.md','DATASETS.md','requirements-tested-macos.txt'):
shutil.copyfile(source / name, destination / name)
project = (source / 'pyproject.toml').read_text()
project = project.replace('name = "forma3d-tiny"','name = "forma3d-tiny-2"')
project = project.replace('version = "0.2.0"','version = "0.3.0"')
(destination / 'pyproject.toml').write_text(project)
(destination / 'scripts').mkdir()
for name in ('prepare_hf.py','release.py'):
shutil.copyfile(source / 'scripts' / name, destination / 'scripts' / name)
# This file set can reproduce the training recipe from pinned upstream.
for name in ('posttrain.sh','prepare_v2.py','audit_data.py','stage_v2.py','publish_v2.py','COMMANDS.md'):
shutil.copyfile(ROOT / name, destination / name)
public_meta = {k:v for k,v in meta.items() if k != 'dataset'}
public_meta.update({'base_model':BASE, 'base_revision':REV,
'training_method':'weights-only continuation; fresh AdamW',
'known_v1_assets_excluded':True})
torch.save({'format':1,'config':checkpoint['config'],'model':checkpoint['model'],
'step':checkpoint['step'],'metadata':public_meta}, destination / 'model.pt')
(destination / 'config.json').write_text(json.dumps(checkpoint['config'],indent=2))
(destination / 'training.json').write_text(json.dumps(public_meta,indent=2))
report.update({'base_model':BASE,'base_revision':REV,
'published_model_sha256':sha(destination / 'model.pt')})
(destination / 'evaluation.json').write_text(json.dumps(report,indent=2))
for src, dst in [('sources.json','ATTRIBUTIONS.json'),('v2-audit.json','data-audit.json'),
('preparation.json','preparation.json')]:
# preparation.json includes user-local paths; publish only portable fields.
if src == 'preparation.json':
prepared = json.loads((Path(args.data) / src).read_text())
prepared['settings'] = {k:v for k,v in prepared['settings'].items() if k not in ('out','cache')}
(destination / dst).write_text(json.dumps(prepared,indent=2))
else:
shutil.copyfile(Path(args.data) / src,destination / dst)
shutil.copyfile(Path(args.run) / 'metrics.jsonl',destination / 'metrics.jsonl')
if (ROOT / 'runs/environment.txt').exists():
lines = (ROOT / 'runs/environment.txt').read_text().splitlines()
portable = [line for line in lines if ' @ file:' not in line and not line.startswith('-e ')]
portable.append('# Local forma3d-tiny 0.2.0 source: '+BASE+' @ '+REV)
(destination / 'environment.txt').write_text('\n'.join(portable)+'\n')
datasets = sorted({r['repo'] for r in json.loads((destination / 'ATTRIBUTIONS.json').read_text())})
dataset_yaml = '\n'.join('- '+d for d in datasets)
bt, ft = report['baseline_test'],report['posttrained_test']
card = f'''---
license: apache-2.0
pipeline_tag: image-to-3d
base_model: {BASE}
base_model_relation: finetune
model_name: Forma3D Tiny 2
datasets:
{dataset_yaml}
tags:
- pytorch
- gaussian-splatting
- mesh-proxy-supervision
- research-prototype
---
# Forma3D Tiny 2
A {meta['parameters']:,}-parameter image-to-Gaussian research model continued from
{BASE} at revision `{REV}`. The optimizer starts fresh. It uses a
{checkpoint['config']['grid']} cubed grid and width {checkpoint['config']['width']}.
Selected checkpoint step {checkpoint['step']} from {meta['steps_requested']} completed steps.
## Training
See training.json and metrics.jsonl for actual optimizer settings and validation
history. Inputs are orthographic renders of centered mesh-derived Gaussian proxy
clouds on black. Targets are isotropic surface samples compressed to one Gaussian
per occupied grid cell. No pretrained 3D teacher was run. No natural-photo training
or differentiable rendering is claimed. Asset IDs, known source groups, and exact
mesh hashes from all 96 known v1 assets were excluded. Near duplicates can remain.
The separate 15 percent object-group test split does not enter checkpoint selection;
20 percent of development groups supply validation. Counts are realized counts in
preparation.json and data-audit.json, not assumed independent asset counts.
## Evaluation
Both checkpoints were evaluated on the same new held-out proxy data.
| Metric | Starting Forma3D Tiny | Selected Forma3D Tiny 2 |
|---|---:|---:|
| Mean test loss | {bt['loss']:.6f} | {ft['loss']:.6f} |
| Mean view occupancy IoU at threshold 0.5 | {bt['occupancy_iou']:.6f} | {ft['occupancy_iou']:.6f} |
Test groups: {report['test_objects']}; views: {report['test_samples']}.
See evaluation.json for hashes and release gates. Metrics are view-averaged over
proxy renders. They do not establish photo realism, novel-view image quality,
mesh quality, texture fidelity, gameplay, or general-purpose 3D reconstruction.
## Use
Install this source with Python 3.11 and `uv pip install ".[data]"` in a virtual
environment, then run:
```bash
image3d generate --checkpoint model.pt --image your-centered-cutout.png \\
--out results/object.ply --device mps
image3d preview --ply results/object.ply --out results/preview.png
```
Output is Gaussian PLY. Inputs should match centered objects on black. See
COMMANDS.md for the complete continuation recipe. This model retains the same
architecture; no text-prompt conditioning or new mesh decoder was added.
## License
Publisher source and weights are offered under Apache 2.0. Retain NOTICE,
THIRD_PARTY.md and ATTRIBUTIONS.json. CC BY Scenario assets and CC0 Objaverse
assets have their own attribution and license records in DATASETS.md.
'''
(destination / 'README.md').write_text(card)
sums = [sha(f)+' '+str(f.relative_to(destination)) for f in sorted(destination.rglob('*')) if f.is_file()]
(destination / 'SHA256SUMS').write_text('\n'.join(sums)+'\n')
print('Staged evaluated release at',destination)
print('Inspect PNG files under',Path(args.run)/'inspection','before optional publication.')
if __name__ == '__main__':
main()