Model Releases

pagedMark: invisible SynthID-class watermark removal for AI images (ChatGPT, gpt-image, DALL·E, Sora, Gemini, Nano Banana), running on Metal

pagedMark removes AI provenance from content you generated yourself. Two different things, and it is worth separating them. The first is metadata: C2PA Content Credentials, EXIF, XMP, IPTC, the genera

DGX agentreddit
model-releasesr-ollama

pagedMark removes AI provenance from content you generated yourself. Two different things, and it is worth separating them. The first is metadata: C2PA Content Credentials, EXIF, XMP, IPTC, the generator parameters. That part is easy and verifiable, and a screenshot does it too. The second is the invisible pixel watermark that a screenshot does not touch, the SynthID class of marks, which has to be disrupted by regenerating the image itself. Coverage on the image side is ChatGPT, gpt-image, DALL·E, Sora, Gemini and Nano Banana for the invisible marks, plus a registry of visible vendor labels (Doubao, Jimeng, Qwen, Kling, Yuanbao, Baidu, LibLibAI, Samsung Galaxy AI). On the video side it handles the visible marks from Sora, Veo, Seedance, Dola, Hailuo and Kling, and the metadata that travels with them. The reason this is worth a post rather than a link is that it is built for Apple Silicon instead of ported to it. I spent several days getting the pipeline to run correctly on an M5 with 16 GB, meaning predictable and measured rather than merely launching. Most of what I assumed turned out to be wrong, so the measurements are below. The four-step distillation LoRA invents texture, and more steps make it worse A low strength edit runs the tail of a long schedule: strength 0.15 executes the last four steps of twenty seven. A LoRA distilled for four timesteps spanning the entire noise range is off its distribution there. Wherever nothing conditions the model, and flat dark fabric gives a Canny ControlNet no edges at all, it fills the gap from its prior. On a night photograph that arrives as coloured camouflage across black clothing. Global stage, 1448x1080, strength 0.15, seed 0 Invented texture PSNR Wall Lightning, 4 steps 1.73x source 28.54 dB 41 s Lightning, 8 steps 1.80x 28.19 dB 29 s Lightning, 16 steps 1.84x 27.85 dB 62 s Undistilled base, 16 steps 1.19x 29.25 dB 71 s Undistilled base, 24 steps 1.20x 29.17 dB 132 s Asking the distilled model for more steps made the artifact worse, which is what identified the distillation rather than the step count as the cause. Dropping the LoRA costs roughly three times the wall time and buys back both fidelity and correctness. Three wrong theories I paid for first, in case they save someone else the time. Not the fp16 VAE: a bare encode and decode round trip of the same crop is clean in fp16 and in fp32, tiled or whole, at 34.6 dB. Not Metal's fp16 in general: bf16 measured marginally worse. Not Canny picking up sensor noise: the Canny map of that region is completely empty, which was the actual clue. Metal pages instead of failing, so memory has to be measured torch.mps.recommended_max_memory() reports 11.84 GiB on a 16 GB machine. Exceed it and nothing raises an error. The process starts swapping, and a run that should take 23 seconds takes an hour instead. With VAE tiling disabled, a 1.57 MP frame peaks at 18.74 GiB and takes 59 seconds. With tiling it peaks at 10.92 GiB and takes 23 seconds. So tiling carries real weight on a small machine, but its boundaries leave a faint texture, which is why it is now decided per frame from the device budget rather than switched on globally. Diffusion untiled at 2.5 MP went into swap and did not finish within twelve minutes. Tiled at 1024 px, a 5.07 MP frame holds 10.93 GiB, finishes in 88 seconds, and keeps its native geometry. Sequential CPU offload works on MPS, and it is what makes 8 GB usable The stack is 7.7 GiB of weights. An 8 GB Mac reports a working set of roughly 5.3 GiB, so it does not fit however the activations are handled. Streaming the weights one module at a time: Same frame, same seed Peak device memory Wall Weights resident 7.70 GiB 7.1 s enable_sequential_cpu_offload(device="mps") 0.28 GiB 24.1 s Twenty seven times less peak memory for 3.4 times the wall time. The plan is chosen from the measured budget and then printed, because a run three times slower than the fast path looks broken unless it says why. Two Metal gaps worth knowing if you are porting anything torch.float8_e4m3fn does not exist on MPS at all. The error is RuntimeError: Undefined type Float8_e4m3fn. Any pipeline that streams float8 weights, which several VRAM managed stacks do, cannot be loaded there under any configuration. SAM's processor emits its box and point prompts as float64, which Metal also has no type for, so moving the batch to the device raises rather than degrading. A single cast fixes it, but nothing tells you that is the problem. The expensive one: fp16 sampling on MPS returns zeros silently I added a memory optimisation that encodes the two fixed prompts once and drops the text encoders, saving a measured 1.52 GiB of the 8.79 GiB the loaded stack holds. Two of four face crops then came back as all zero black rectangles. Deterministically, at the same seed, with nothing raised anywhere. The embeddings were innocent. CPU fp16, MPS fp16 and fp32 encodings of that prompt agree to 0.0009 on tensors with a standard deviation of 3.06, and the same crop generated in isolation is correct either way. Freeing unrelated memory changed the allocation pattern the crops met after the global pass, and that alone was enough. I withdrew the optimisation and added a guard that drops any empty crop instead of compositing it. If you run fp16 diffusion on Metal, check your output for degeneracy. It will not tell you. What it does not claim Regeneration is not payload deletion. The image changes: faces, text and fine detail move, and the numbers above are the measured size of that change rather than a reassurance. No public local decoder exists for SynthID class marks, so identify reports unknown and never clean. Verification is the provider's verifier or nothing. The 0.15 operating point comes from the upstream project's record against openai.com/verify on CUDA. I have not re-run that check on Metal, and Metal is not bit identical to CUDA, so I am claiming the same operating point and not the same verdict. It is for content you generated or own. The visible mark registry accepts AI generation labels only. Stock agency previews, marketplace and classifieds watermarks are deliberately out of scope, and that boundary is in the repository rather than only in this comment. Because "how much did that cost my picture" is the whole question pagedmark measure before.png after.png PSNR over the frame, PSNR per detected face, and how much mid band structure appeared where the source was flat and dark. The third metric is the one that caught the camouflage, and it took two attempts. Per pixel chroma statistics rank the artifact below the source, because the source's own sensor grain carries more per pixel variance than the invented blotches do. A plain band ratio fails too, since any linear filter reports doubled grain and doubled blotches identically. Normalising mid band energy by fine detail energy, against the same ratio in the source, measures the shape of the spectrum instead of its size. uv tool install "pagedmark[diffusion]" pagedmark invisible photo.png -o clean.png pagedmark invisible photo.png --preview # 46.6 s instead of 112.6 s Code: https://github.com/doofzoff/pagedMark PyPI: https://pypi.org/project/pagedmark/ Happy to answer anything about the Metal specifics. That is the part I would have wanted written down before I started. submitted by /u/d0ofz [link] [comments]

Source: r/ollama | 2026-08-17

Loading related sources…