Nodes/ComfyUI-Apt_Preset/model_patch_controlnet
ComfyUI Node

model_patch_controlnet

Z-Image ControlNet with no ControlNet wires

By cardenluo·Created 2 years ago·Updated 5 days ago· 359
model_patch_controlnet
  • context
  • image
  • latent_image
  • latent_mask
  • context
  • model
◄controlnetZ-Image-Turbo-Fun-Controlnet-Union-2.1.safetensors►
◄strength0.80►
◄diffDiffusiontrue►

If you learned ControlNet on SD 1.5 or SDXL, you learned a ritual: ControlNetLoader, preprocessor, Apply ControlNet, conditioning to the sampler. Z-Image doesn't work that way. Its Fun ControlNet isn't a second network writing into your conditioning - it's a patch on the model itself, and model_patch_controlnet is Apt_Preset's one-node version of the two nodes core ComfyUI uses (ModelPatchLoader → Z-Image Fun ControlNet).

Reach for it if you already run that pack's stack - loader, controller stacks, sampler, all on one RUN_CONTEXT wire - and want a canny, depth, pose, HED or MLSD pass, or inpaint, on Z-Image Turbo. Off that bus, use core's pair.

How it works

The patch loads from ComfyUI/models/model_patches, ComfyUI's own folder. ComfyUI sniffs the state dict, recognises Alibaba PAI's Z-Image Fun ControlNet by its keys, builds a small control module and hooks it into the diffusion transformer: the control output is added into the block stream as the model denoises (img += control_out * strength). You're modifying the model, not feeding it a hint.

Two consequences. You can't stack it with classic Apply ControlNet nodes, and the strength dial is here, not on a sampler. Your control map is also rescaled to the latent at run time, so a 1024px canny map drives a 1216x832 generation without you matching sizes.

The inputs that matter

context - the RUN_CONTEXT from your loader. Everything else is optional: leave a field empty and the node does less.

  • controlnet - a dropdown of everything in models/model_patches, defaulting to Z-Image-Turbo-Fun-Controlnet-Union-2.1.safetensors (2.1 is the one to use: bugfix on 2.0, ~35% faster). Set None and the model passes through untouched.
  • image - the control map, preprocessed however you like; the union takes canny, depth, pose, HED and MLSD, plus inpaint.
  • strength - 0 to 2, default 0.8, which sits in the 0.65–0.8 pocket the 2026 unions publish. Past 1.0 Z-Image starts tracing your wireframe and skin goes crisp and plastic.
  • latent_image + latent_mask - the inpaint path: the picture to repair, and the region. Both go to the patch's inpaint mode (2.0+ unions), which composites the masked image into the conditioning and regenerates inside it. Give it a mask, or nothing meaningful happens and you'll decide the feature is broken when it's just unconfigured.
  • diffDiffusion - boolean, default True. Wraps the model in core's DifferentialDiffusion, which binarises the noise mask each step against a schedule-ramped threshold, so a blurred mask edge becomes a gradient instead of a seam. No noise mask means no effect, so leaving it on is harmless; turn it off for crisp boundaries.

Outputs are context (carrying the patched model) and model. Send the context on to your next controller stack or the sampler; off the bus, wire model into a KSampler or through a LoRA node.

Install

ComfyUI Manager, search "ComfyUI-Apt_Preset", or clone it:

cd ComfyUI/custom_nodes
git clone https://github.com/cardenluo/ComfyUI-Apt_Preset

The README says to double-click install.bat, which doesn't exist - the repo ships install-ComfyUI-Portable.bat and install-ComfyUI-aki.bat for the Windows portable and 阿基整合包 builds. Everywhere else:

cd ComfyUI/custom_nodes/ComfyUI-Apt_Preset
pip install -r requirements.txt

Then restart. That list is heavy (pandas, scipy, matplotlib, onnxruntime, transparent-background, opencv, scenedetect…), and those are the packages that drag numpy around - give the pack its own venv if you can.

Finally the ControlNet: grab Z-Image-Turbo-Fun-Controlnet-Union-2.1.safetensors from alibaba-pai/Z-Image-Turbo-Fun-Controlnet-Union-2.1 on HuggingFace (Apache 2.0):

ComfyUI/models/model_patches/

Create the folder if needed, and update ComfyUI first - model patch support only landed in late 2025 (PR #11062). Ignore the pack's other install chores (the Quark-hosted Apt_File segmenter pack, ollama models); they belong to different nodes.

Where people get burned

The whole pack fails to import. The recurring Apt_Preset complaint in the wild is a red IMPORT FAILED line in the first second of the startup log, still unresolved in a 2025 r/comfyui thread for a user who had reinstalled via Manager and git. The pack imports everything up front (matplotlib, spandrel, torchvision, the whole NodeChx tree), so one missing line kills all of it. Read the traceback under the error, install what it names, restart.

Wrong file, wrong folder. Not models/controlnet: models/model_patches. The dropdown is a plain folder listing with no architecture filter - Qwen-Image 2.1 Fun patches and Anima LLLite files sit in the same list, so pick the Z-Image union. If the file is missing entirely, the widget still shows the default name and the run fails validation.

No step cutoff. The real limitation. The Fun union was trained by a different Alibaba team on top of Turbo and partially breaks its distillation; the community fix is to apply the ControlNet for the first few steps and drop it for the last few. Core's Z-Image Fun ControlNet exposes start_percent/end_percent for that. This node doesn't - the patch runs the full schedule, and you feel it at high strength.

ControlNet plus LoRA also reportedly drops quality when both are active; if a render goes mushy, pull the LoRA first.

One last thing it isn't: a sampler. Turbo still wants 8–9 steps at CFG 1 with ModelSamplingAuraFlow shift around 7, not the default 3. That's the difference between "the ControlNet ruined my image" and "my sampling was wrong".

CategoryApt_Preset/chx_tool

Inputs (7)

NameTypeDefaultDescription
contextRUN_CONTEXT—
imageoptIMAGE—
controlnetoptCOMBOZ-Image-Turbo-Fun-Controlnet-Union-2.1.safetensors1 options: None
strengthoptFLOAT0.800–2—
latent_imageoptIMAGE—
latent_maskoptMASK—
diffDiffusionoptBOOLEANtrue—

Outputs (2)

NameTypeDescription
contextRUN_CONTEXT—
modelMODEL—