imagehide / ops

Operations β€” scripts / datasets / deploy

UMass Unity HPC
Highlight any text β†’ πŸ’¬ comment. Publishes to GitHub Issues; optional πŸ€– Ask Claude to fix tag for action items.

Sources: docs/scripts.md, docs/datasets.md, docs/site_deploy.md. All compute runs go through SLURM; the login node is for edits + light inspection only.

Β§1Environment

settingvalue
ClusterUMass Unity HPC
Usernamehangyang_umass_edu
Home/home/hangyang_umass_edu
Work/work/pi_nwycoff_umass_edu/hang
Project root/work/pi_nwycoff_umass_edu/hang/imagehide
Conda envhang at /work/pi_nwycoff_umass_edu/.conda/envs/hang/
Disk budget50 GB total under project root

Activate env

module load conda/latest
eval "$(conda shell.bash hook)"
conda activate hang
# Don't use `source activate` β€” Unity's conda/latest is miniforge3 and only `conda activate` works.

Β§2SLURM policy

This is an HPC cluster. Do not run training or large-scale eval on the login node. All compute β†’ SLURM. Login node = edits + light inspection.
fieldvalue
partitiongpu-preempt only
GPU--gres=gpu:2080_ti:1 (underscore, not space)
preempt safetyrequired: training scripts must checkpoint & auto-resume

Useful commands

# check 2080Ti availability
sinfo -p gpu-preempt -o "%t %D %G" | grep 2080_ti

# running jobs
squeue -u $USER -o "%.18i %.9P %.20j %.8t %.10M %R"

# interactive debug session
srun --partition=gpu-preempt --gres=gpu:2080_ti:1 \
     --mem=16G --time=1:00:00 --pty bash

# inspect a finished job
sacct -j <JOBID> --format=JobID,State,ExitCode,Elapsed

# disk usage
du -sh /work/pi_nwycoff_umass_edu/hang/imagehide/*
df -h /work/pi_nwycoff_umass_edu/hang

Β§3Scripts filter by kind or search

scriptkindpurposewalltime
smoke_test.{py,sbatch}smokeRun TrustMark Q/C/P on a test image; report PSNR and bit recovery. First run downloads model weights from Adobe CDN (~100 MB).~2 min Β· 30 min
download_data.sbatchdataCOCO 2017 train + DIV2K. Restart-safe (wget --continue).~4 h
download_clic.sbatchdataCLIC 2020 pro + mobile, train + valid. ~6.4 GB.~6 h
download_dped.sbatchdataDPED full-resolution originals from 4 phones + Canon DSLR. ~58 GB tar β†’ ~51 GB extracted (~22 K images).~24 h
download_flickr2k.sbatchdata Β· optionalFlickr2K (2,650 imgs, ~22 GB). Not currently submitted.~12 h
exp0_inn_p896.sbatchtrainINN v3 legacy baseline (16 / RDB, 4.05 M params). Pins --num_blocks 16 --subnet_type rdb.~5 h
exp0_inn_p896_light.sbatchtrainINN v3 mobile target (8 / light, 0.167 M params). Canonical light run.~1.7 h
exp0_inn_idea084_d001*.sbatchtrainidea084 / design001 family β€” subband-weighted permutation adapter, multi-aux losses. Variants _v2 / _full / _best.~3–8 h
exp0_inn_idea097_d001_full.sbatchtrainidea097 / design001 β€” currently deployed carrier on imagehide-demo. 1024 b ECC codeword, no-AMP.~5 h
exp0_inn_idea{109,112}_d*.sbatchtrainIn-flight research lines (idea109, idea112). 6 jobs running concurrently across 3 design variants each.~5–10 h
exp0_inn_eval_multires_v2.sbatchevalMulti-resolution eval at 9 sizes (256Β² β†’ 4032Γ—3008) Γ— 13 compression attacks on 100 DIV2K val. Auto-detects architecture from saved args. --amp recommended.~30 min
eval_phash_512.sbatchevalRobust hash (pHash) drift sweep at 512Β².~10 min
eval_phash_drift.sbatchevalpHash drift across the canonical benign-transform suite (JPEG / resize).~15 min
eval_phash_{latest,wechat,chain_x}_idea084_d001.sbatchevalTargeted attack chains for the idea084/d001 checkpoint family. chain_wechat dropped on 2026-04-28 from live suite (past resize-tolerance bound).~10 min
eval_pdq_drift_ext.sbatchevalExtended PDQ drift validation β€” adversarial multi-pass JPEG chains. Verifies the BCH t=4 budget assumption.~15 min
eval_phash_v2_best{_multires,}.sbatchevalMulti-res eval against the v2 best checkpoint on the chain_x platform pipeline.~20 min
export_onnx_fp16.sbatchexportONNX export at fp16. Required step for Exp 4 (camera-deployment benchmark).~15 min
fp16_attempt{1,1b,2,3,3b}.sbatchexportfp16 conversion experiments β€” try onnxsim dedupe, polygraphy, weights-only conversion, selective fp16. fp16 round-trip remains numerically tricky.~10 min each
fp16_{check_ort,validate_bitacc}.sbatchexportfp16 verification β€” ONNXRuntime parity + bit_acc validation against fp32 reference. Pending: fp16 max-diff vs fp32 within 0.0001 on bit_acc.~5 min each

Run the smoke test (first-time setup check)

cd /work/pi_nwycoff_umass_edu/hang/imagehide
sbatch scripts/smoke_test.sbatch
squeue -u $USER                              # check progress
tail -f logs/smoke-<JOBID>.out                # follow output

Logs land at logs/<name>-<JOBID>.{out,err}.

Β§4Datasets

All under /work/pi_nwycoff_umass_edu/hang/imagehide/data/. ~143K images, ~26 GB on disk after extraction cleanup (~84 GB including kept DPED archive).

datasetimageslong sidediskrolestatus
COCO 2017~118 000≀ 640 px~18 GBtraining (≀ 512Β²)on disk
DIV2K800 + 100~2 040 px~3 GBtraining (HR) + valon disk
CLIC 20201 7351.5K–5K px~12 GBtraining (HR)on disk
DPED originals22 2602K–4K px~51 GBtraining (HR)on disk

Per-dataset notes

COCO 2017
DIV2K
CLIC 2020
DPED originals

Β§5Manifests

data/train.txt and data/val.txt list absolute image paths, one per line, sorted. build_resolution_manifests.py filters per-resolution-class for the multi-res sampler.

filetrainvalsources
train.txt / val.txt142 565617COCO + DIV2K + CLIC + DPED
{train,val}_256.txt141 741617all sources
{train,val}_384.txt122 070617HR + most COCO
{train,val}_512.txt32 696615HR only (COCO ≀ 640 px falls out)
{train,val}_768.txt24 204612HR-only: DPED + DIV2K + CLIC

Sidecar {train,val}_dims.tsv (path \t w \t h) is also written for arbitrary downstream filtering.

Multi-res dataloader

src/multi_res_dataset.py: MultiResDataset + MultiResBatchSampler + make_loader. Reads train_dims.tsv and materializes per-(H, W) eligibility lists. RES_POOL defines 18 (H, W) tuples; the sampler picks one per batch and derives batch size from a pixel budget (default 1.0 M). src/exp0_inn_train.py consumes via make_loader(args.manifest_dims, ...).

Native resolution per source (for VRAM planning)
sourcelong sidenotes
COCO 2017≀ 640 pxCheap; dominates count (83%)
DIV2K~2 040 pxCurated, modest count
CLIC pro2K–5K pxLargest images β€” heaviest VRAM hit
CLIC mobile1.5K–4K pxMid-weight
DPED2K–4K pxLargest count among HR sources

Β§6Site deploy

The public dashboard at yanghangai.github.io/imagehide is served by GitHub Pages from the gh-pages branch β€” not main. A commit to main won't update the live site.

wheresource path (main)served path (gh-pages)URL
Dashboard (landing)index.htmlindex.html/
Spec pagedocs/html/spec.htmldocs/html/spec.html/docs/html/spec.html
Design / Plan / Ops pagesdocs/html/{design,plan,ops}.htmlsame/docs/html/<page>
Feedback overlayassets/feedback.{css,js}same/assets/...
Paper site (archived)site/index.html, site/img/*paper/index.html, paper/img/*/paper/

Deploy steps

# 1. Commit + push source edits on main
git add index.html docs/html/ assets/ site/ docs/site_deploy.md
git commit -m "Site: <summary>"
git push origin main

# 2. Mirror to gh-pages via a worktree
git fetch origin gh-pages
git worktree add /tmp/imagehide-ghpages gh-pages
cd /tmp/imagehide-ghpages

# 2a. Dashboard + spec/design/plan/ops
cp /work/pi_nwycoff_umass_edu/hang/imagehide/index.html index.html
mkdir -p docs/html
cp /work/pi_nwycoff_umass_edu/hang/imagehide/docs/html/*.html docs/html/

# 2b. Feedback overlay assets
mkdir -p assets
cp /work/pi_nwycoff_umass_edu/hang/imagehide/assets/feedback.{css,js} assets/

# 2c. Paper site at /paper/ (only when site/ source changes)
mkdir -p paper/img
cp /work/pi_nwycoff_umass_edu/hang/imagehide/site/index.html paper/index.html
cp /work/pi_nwycoff_umass_edu/hang/imagehide/site/img/*.png paper/img/

# 2d. Rewrite repo-internal .md / src/ links β†’ github.com/blob/main URLs
GH=https://github.com/yanghangAI/imagehide/blob/main
sed -i \
  -e "s|href=\"docs/inn_arch_notes.md\"|href=\"${GH}/docs/inn_arch_notes.md\"|g" \
  -e "s|href=\"docs/PLAN.md\"|href=\"${GH}/docs/PLAN.md\"|g" \
  -e "s|href=\"docs/scripts.md\"|href=\"${GH}/docs/scripts.md\"|g" \
  -e "s|href=\"index.md\"|href=\"${GH}/index.md\"|g" \
  -e "s|href=\"HANDOFF.md\"|href=\"${GH}/HANDOFF.md\"|g" \
  index.html
sed -i \
  -e "s|href=\"../../src/|href=\"${GH}/src/|g" \
  -e "s|href=\"../inn_arch_notes.md\"|href=\"${GH}/docs/inn_arch_notes.md\"|g" \
  docs/html/spec.html

# 3. Commit + push
git add -A
git commit -m "<summary>"
git push origin gh-pages
cd -
git worktree remove /tmp/imagehide-ghpages

Verify

# landing
curl -s https://yanghangai.github.io/imagehide/ | grep -oE 'A-tolerant|MWIP' | sort -u

# spec / design / plan / ops
for p in docs/html/{spec,design,plan,ops}.html; do
  printf "%-32s β†’ HTTP %s\n" "/$p" "$(curl -s -o /dev/null -w '%{http_code}' https://yanghangai.github.io/imagehide/$p)"
done
Pitfalls.

Refresh archived paper-site eval samples

Regenerate site/img/{cover,container,residual_x10}.png from a newer run
RUN=/work/pi_nwycoff_umass_edu/hang/autohide/runs/idea084/design002
cp "$RUN/eval_samples/cover_1024x1024.png"      site/img/cover.png
cp "$RUN/eval_samples/container_1024x1024.png"  site/img/container.png

python3 - <<'PY'
from PIL import Image
import numpy as np
cov = np.asarray(Image.open('site/img/cover.png').convert('RGB'), dtype=np.int16)
con = np.asarray(Image.open('site/img/container.png').convert('RGB'), dtype=np.int16)
amp = 20                                  # match site/index.html alt-text
res = np.clip(np.abs(con - cov) * amp, 0, 255).astype(np.uint8)
Image.fromarray(res).save('site/img/residual_x10.png', optimize=True)
PY

The residual filename is residual_x10.png for legacy reasons; amplification factor lives in the CSS comment, the <img alt>, and the regeneration snippet. Keep all three in sync. Then re-run step 2c above.