Files

8.8 KiB
Raw Permalink Blame History

INSTALL_NOTES — ComfyUI-LensTurbo

The deployment story for this pack — every pitfall discovered while bringing it online, with root cause and fix. If you're hitting an error, scan the pitfall library below first.

Confirmed working configuration

  • Ubuntu 22.04, dual RTX 3090 (24 GB each, sm_86)
  • CUDA 12.6, Python 3.13, torch 2.11.0+cu126
  • ComfyUI venv managed by uv
  • HF_HOME on a large disk (/mnt/largedisk/hf_cache or similar)
  • TMPDIR on the same large disk (avoid the small root partition)
  • System RAM 48 GB+ (required, see Why 48 GB RAM)

Deployment recipe

# 0. Pre-flight env
export HF_HOME=$HOME/hf_cache               # or wherever your big disk is
export TMPDIR=$HOME/tmp
mkdir -p "$HF_HOME" "$TMPDIR"

cd $COMFY_ROOT
source .venv/bin/activate

# 1. Drop the pack in
cd custom_nodes/
git clone https://github.com/aadebuger/ComfyUI-LensTurbo
cd ComfyUI-LensTurbo

# 2. Vendor upstream
bash scripts/fetch_upstream.sh
ls lens_source/lens/ | head    # should show __init__.py, pipeline.py, ...

# 3. Install deps with override + kernels uninstall
bash scripts/install_deps.sh

# 4. HF login + license agreement
bash scripts/hf_login_check.sh
# If any FAILs:
#   - Visit https://huggingface.co/microsoft/Lens-Turbo  and click Agree
#   - Visit https://huggingface.co/black-forest-labs/FLUX.2-dev  and click Agree
#   - hf auth login  (paste token)

# 5. Pre-download (~58 GB, foreground, resumable)
bash scripts/download_models.sh
# Use tmux/screen if you want to detach. Ctrl-C + re-run resumes.

# 6. Restart ComfyUI with the right env
pkill -9 -f main.py; sleep 5
cd $COMFY_ROOT && source .venv/bin/activate
export HF_HOME=$HOME/hf_cache
export TMPDIR=$HOME/tmp
unset HF_HUB_ENABLE_HF_TRANSFER   # deprecated in huggingface_hub 1.x
export PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True
nohup stdbuf -oL -eL python main.py --listen 0.0.0.0 --port 8188 \
    > $TMPDIR/comfy.log 2>&1 &
sleep 30

# 7. Banner check
grep -iE "ComfyUI-LensTurbo|lens-turbo|IMPORT FAILED" $TMPDIR/comfy.log | head -20

# 8. Node-registered check
curl -s http://127.0.0.1:8188/object_info | python3 -c "
import json, sys
d = json.load(sys.stdin)
for n in ['LensTurboLoader', 'LensTurboSampler']:
    print(f'  {n}: {\"OK\" if n in d else \"MISSING\"}')"

# 9. Smoke test via CLI
python cli/lens_turbo_cli.py "a cat" \
    --ip 127.0.0.1 --gpu 0 \
    --steps 4 --cfg 1.0 --seed 0 \
    --ws-recv-timeout 1800 --timeout 3600 \
    --out ./out

Pitfall library (L1–L10)

The full story of what went wrong while bringing this online. Cross-reference against the v3 README pitfall framework (modes A-F).

# Symptom Root cause Fix Framework
L1 huggingface-cli prints a deprecation warning, some commands fail huggingface-cli deprecated in huggingface_hub ≥1.x Migrate to hf (hf auth login, hf download, hf cache scan) env hygiene
L2 HF_HUB_ENABLE_HF_TRANSFER FutureWarning on every script Variable deprecated, replaced by Xet backend unset HF_HUB_ENABLE_HF_TRANSFER. Optional opt-in: export HF_XET_HIGH_PERFORMANCE=1 env hygiene
L3 from_pretrained returns 401 on microsoft/Lens-Turbo Gated repo, needs license Agree + token hf auth login + click Agree on the HF web page gated repos
L4 httpx.LocalProtocolError: Illegal header value b'kernels/0.14.0; ...' during from_pretrained kernels==0.14.0 builds the user_agent with a trailing ; ; httpx ≥0.28 rejects headers with trailing whitespace uv pip uninstall kernels. RTX 3090 (sm_86) can't run MXFP4 native (needs sm_90+ / H100) so transformers gracefully dequantizes to bf16. The kernels package is unused on Ampere. Mode F (uninstall unused optimization)
L5 OOM at ~22.9 GB on first sample using enable_model_cpu_offload() Dequantized GPT-OSS-20B is ~40 GB bf16, doesn't fit on a 24 GB card even when "offloaded" because model_cpu_offload puts the WHOLE sub-model on GPU during its forward Use offload_mode="cpu_text_encoder" (the default) Hybrid placement
L6 NotImplementedError: Cannot copy out of meta tensor; no data! when using enable_sequential_cpu_offload() accelerate ≥1.x wraps pre_forward with torch.compile (_compiled_fn). Combined with Lens's custom TextEncoder forward and meta-device weight loading, residual meta tensors leak into send_to_device(args, ...). TORCHDYNAMO_DISABLE=1 does not fix this — _fn is on every code path. Abandon sequential mode entirely. Use cpu_text_encoder instead. Hybrid placement (forced)
L7 AttributeError: property '_execution_device' has no setter diffusers exposes _execution_device as @property with no setter, inferred from sub-model devices Patch the class descriptor, not the instance: type(pipe)._execution_device = property(lambda self: target_device) Monkey-patch A
L8 ValueError: Cannot generate a cpu tensor from a generator of type cuda in prepare_latents _execution_device returned cpu because text_encoder is on CPU, so latents got allocated on CPU and clashed with the cuda Generator Same fix as L7 (auto-applied by cpu_text_encoder mode) Monkey-patch A
L9 RuntimeError: Expected all tensors to be on the same device, but found at least two devices, cuda:0 and cpu in transformer's txt_norm[i](encoder_hidden_states[i]) LensPipeline doesn't .to(execution_device) the text encoder outputs; they stay on CPU (encoder's device) and clash with the GPU transformer Wrap text_encoder.encode_layers: send inputs → CPU, outputs → target device. Auto-applied by cpu_text_encoder mode. Monkey-patch B
L10 CLI workflow validation fails: Required input is missing: offload_mode Server pack upgraded to new schema, but client-side lens_turbo_cli.py builds the old workflow Update both sides: extract the same tarball on the Mac client and on the server. deployment discipline

Framework summary

These pitfalls map to broader patterns useful for other custom nodes:

  • Mode F (L4): when a Python package's "fast path" doesn't apply to your hardware AND the fallback path is acceptable, just uninstall the package. Don't try to patch around its bugs.
  • Hybrid CPU/GPU placement (L5–L9): for any pipeline composed of "huge text encoder + small generative network + VAE", keep the text encoder on CPU and the generative parts on GPU. This requires three monkey-patches (override _execution_device, wrap encoder I/O for device crossings) that are reusable across Flux+T5XXL, Lumina, and similar architectures.
  • Deployment discipline (L10): when you change a node's input schema, both the server-side pack and any client-side CLI need to be re-deployed. Use a single tarball + identical extraction commands on both sides.

Verifying the cpu_text_encoder patches fire

If cpu_text_encoder mode looks like it's not working (still OOMs, still device mismatches), add the diagnostic:

print(f"[diag] _execution_device = {pipe._execution_device}")
print(f"[diag] text_encoder      = {next(pipe.text_encoder.parameters()).device}")
print(f"[diag] transformer       = {next(pipe.transformer.parameters()).device}")
print(f"[diag] vae               = {next(pipe.vae.parameters()).device}")
print(f"[diag] encode_layers id  = {id(pipe.text_encoder.encode_layers)}")

Expected output (target_device = cuda:0):

[diag] _execution_device = cuda:0
[diag] text_encoder      = cpu
[diag] transformer       = cuda:0
[diag] vae               = cuda:0
[diag] encode_layers id  = 140392847102464   # different from original function id

If _execution_device is cpu or encode_layers id matches the unwrapped function, the patches didn't apply — check that you're really using offload_mode="cpu_text_encoder".

Recovery: a bad .py broke ComfyUI startup

# Clear pycache
find $COMFY_ROOT/custom_nodes/ComfyUI-LensTurbo -name __pycache__ -type d -exec rm -rf {} + 2>/dev/null
find $COMFY_ROOT/custom_nodes/ComfyUI-LensTurbo -name "*.pyc" -delete

# Temporarily disable the pack (MOVE OUT of custom_nodes/, not rename to .bak!)
mkdir -p $HOME/node_backups
mv $COMFY_ROOT/custom_nodes/ComfyUI-LensTurbo \
   $HOME/node_backups/ComfyUI-LensTurbo.$(date +%Y%m%d_%H%M)

# Restart and confirm baseline still works
pkill -9 -f main.py; sleep 5
# ... launch ...

⚠️ Don't rename to .bak inside custom_nodes/ — ComfyUI scans every subdirectory and .bak shadows can silently override NODE_CLASS_MAPPINGS. Move the backup OUT of the directory entirely.

When to bump --ws-recv-timeout

First-time loads pull ~58 GB from HF. On a 100 Mbps connection that's ≥80 minutes with zero WebSocket traffic. The default --ws-recv-timeout=600 will time out; use 1200+ or 3600 for first run. After the cache warms, subsequent runs are <5 s of loader work.