KEEP Single Image
Restore the face without inventing a different person
- image
- keep_model
- IMAGE
Every upscaler you already own has a face problem. ESRGAN-family models add no content, so a soft 60-pixel face stays a soft 60-pixel face with nicer edges. The generative rung above it - SUPIR, SeedVR2, a Qwen-Edit pass - will happily rebuild that face into someone who isn't the person in the photo. Not a settings issue; it's what those models do. KEEP sits in the gap: a dedicated face restorer trained on real faces, so what comes back is recognisably the same human.
How it works
Three stages, and knowing them tells you how it will fail.
It detects: the detector you picked in Load KEEP Models finds five landmarks per face. It aligns and warps each face into a 512x512 canonical crop. Then the KEEP network runs on those crops and the result is pasted back through the inverse warp, with the parsing model blending edges rather than dropping a rectangle in.
The interesting part is the trick in the middle. KEEP is a video model whose whole job is propagating features across a clip so a face doesn't drift between frames, and a still gives it nothing to propagate from - so the node hands it the same frame twice:
net_output = self.keep_net(torch.cat([cropped_faces_tensor, cropped_faces_tensor], dim=1), need_upscale=False)
Two identical frames in, first half kept. Which means a still gets the model in a mode it wasn't trained for, and in practice that reads as stable, faithful, slightly smooth - identity retention per-frame detailers can't match, less crisp micro-texture than a diffusion detail pass.
The inputs you'll actually touch
image and keep_model are obvious - the second one comes from Load KEEP Models, and it carries the detector and upscalers, so this node's settings depend on that node's.
final_upscale_factor (0.5–4.0, default 1.0) is the output size, full stop - the tooltip is honest about that. A 4x background upscaler at factor 2.0 gives you 2.0 output. Set it to 1.0 and your output matches your input dimensions with the face swapped for the restored crop. Most people underestimate how often 1.0 is the right answer.
has_aligned_face - flip this when the input is already a 512x512 aligned crop from a detailer or a face-crop node. It skips detection, resizes the whole image to 512, and treats all of it as the face. Set it on a normal photo and you get the photo squashed to 512 and restored as if it were a portrait, which looks as wrong as it sounds.
only_center_face defaults true: one face, the one nearest frame centre. Turn it off on group shots and every detected face gets restored - slower, and it'll sometimes tidy up a background face you didn't want touched.
draw_bounding_box is a debug switch; useful once, when you're not sure the detector is finding what you think.
Output is a single IMAGE - Save Image, an image-comparison node, whatever.
Install
Manager → search ComfyUI-KEEP → install. Or:
cd ComfyUI/custom_nodes
git clone https://github.com/wildminder/ComfyUI-KEEP
cd ComfyUI-KEEP
grep -v -E '^(torch|torchvision)$' requirements.txt > /tmp/keep-req.txt
pip install -r /tmp/keep-req.txt
The README says plain pip install -r requirements.txt, but that file lists bare torch/torchvision, and letting pip resolve those in a cu-something ComfyUI environment is how you break a working install - hence the filtered list. The first run pulls the KEEP checkpoint plus the detection/parsing stack by itself; manual fallback is the upstream v1.0.0 release.
Traps worth knowing
It only processes the first frame of a batch. image[0] and that's it. Feed it a Load Images batch of twelve, get one image back, wonder where the other eleven went. Batches and clips belong in KEEP Image Sequence.
No face, no error. If the detector finds nothing you get the resized background back, no restoration, no complaint - which reads as "KEEP did nothing" when the detector simply missed. draw_bounding_box is the fastest way to tell those apart.
Oversized faces gain little. Flip the usual detailer rule: if the face already occupies 800 pixels of a sharp render, KEEP has nothing to restore and will just re-encode it slightly smoother. It's a repair tool for faces that are small, soft or compressed - check before/after at 100% before committing a batch.
Several processing nodes, one loader. Point them all at a single keep_model_pack; the weights are cached, so a second load node buys you nothing.
Where it earns its place: after generation, before the big upscale, on the one thing in the frame you can't afford to have rewritten. FaceDetailer and SeedVR2 will both beat it on crispness and lose on "that's not what my grandmother looked like".
Inputs (6)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | — | |
| keep_model | KEEP_MODEL_PACK | — | |
| final_upscale_factor | FLOAT | 1.00.5–4 | The final upscaling factor for the output image. The image will be resized to this scale after processing. |
| has_aligned_face | BOOLEAN | false | Check if the input image is an already aligned 512x512 face. |
| only_center_face | BOOLEAN | true | If the image has multiple faces, only process the one closest to the center. |
| draw_bounding_box | BOOLEAN | false | Draw a bounding box around the detected face on the output image. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| IMAGE | IMAGE | — |