# How the Faceswap Preview System Handles Mask Toggling During Training

> Learn how the Faceswap preview system toggles masks during training using a thread-safe buffer. View raw faces, masked faces, and predicted masks in real-time without interrupting the training loop.

- Repository: [deepfakes/faceswap](https://github.com/deepfakes/faceswap)
- Tags: internals
- Published: 2026-03-06

---

**The Faceswap preview system uses a thread-safe buffer to stream training batches to a separate UI thread, allowing users to toggle between raw faces, masked faces, and predicted masks in real-time without interrupting the training loop.**

During model training in the deepfakes/faceswap repository, the preview system provides continuous visual feedback by displaying sample batches from the current training iteration. Understanding how mask toggling works within this system requires examining the interaction between the training loop's data pipeline, the preview buffer architecture, and the UI control panels that manage mask selection.

## The Preview Architecture: Buffering and Threading

The preview system decouples the training loop from the rendering process to prevent UI operations from slowing down model training. At the core of this architecture is the `PreviewBuffer` class defined in [`lib/training/preview_cv.py`](https://github.com/deepfakes/faceswap/blob/main/lib/training/preview_cv.py) (lines 29-55).

The training loop continuously pushes the most recent batch of aligned faces into this thread-safe buffer:

```python

# Training loop pushes samples without blocking

self.preview_buffer.push(sample)  # lib/training/preview_cv.py

```

A separate preview thread reads from this buffer and handles all rendering. The system supports two rendering backends: **Tkinter** ([`lib/training/preview_tk.py`](https://github.com/deepfakes/faceswap/blob/main/lib/training/preview_tk.py), lines 119-136) when available, and **OpenCV** ([`lib/training/preview_cv.py`](https://github.com/deepfakes/faceswap/blob/main/lib/training/preview_cv.py), lines 122-140) as a fallback. This threading model ensures that expensive mask calculations and GUI updates never stall the gradient computation.

## Configuring Mask Types in the Control Panel

The mask selection UI is built by [`tools/preview/control_panels.py`](https://github.com/deepfakes/faceswap/blob/main/tools/preview/control_panels.py), specifically within the `_create_mask_choices` method (lines 14-42). This function dynamically populates the **Mask Type** dropdown based on two data sources:

- **Alignment file masks**: Extracted from `alignments.mask_summary` (e.g., "components", "extended")
- **Predicted masks**: Added only when the training configuration reports `has_predicted_mask=True`
- **None**: Always available to display raw, unmasked faces

The system maintains sensible defaults. If the saved default mask type from a previous session is no longer available (for example, if the alignment file changed), the code automatically falls back to the first valid mask in the list.

## Applying Masks to Preview Images

When a user selects a mask from the dropdown, the preview system applies it to the buffered image before display. This logic resides in [`tools/sort/sort_methods.py`](https://github.com/deepfakes/faceswap/blob/main/tools/sort/sort_methods.py) within the `_mask_face` method (lines 436-475).

The function performs three critical operations:

1. **Retrieves the mask tensor** using `det_face.mask.get("components")` or the selected type
2. **Resizes the mask** to 256×256 to match the aligned face dimensions
3. **Blends the images** using `np.minimum(aln_face.face, nmask)`

This visualization pipeline is completely isolated from the training loss calculation. While the preview shows masked versions of faces, the underlying training code in [`lib/training/cache.py`](https://github.com/deepfakes/faceswap/blob/main/lib/training/cache.py) and [`lib/training/generator.py`](https://github.com/deepfakes/faceswap/blob/main/lib/training/generator.py) continues to process raw mask tensors according to the model's configuration.

## Real-Time Display Updates

After mask application, the updated image flows back through the buffer system. The preview thread retrieves the modified image and refreshes the canvas immediately:

```python

# Preview thread retrieves and displays

img = self.preview_buffer.get()  # lib/training/preview_cv.py

# Apply selected mask based on UI state

masked_img = SortMethods._mask_face(img, alignments)  # tools/sort/sort_methods.py

# Update the canvas (Tkinter example)

canvas.itemconfig(self._image_id, image=ImageTk.PhotoImage(masked_img))

```

If the user changes the mask type again, the pipeline re-executes starting from the buffered raw image, providing instant visual feedback. For CLI-based preview launches, [`tools/preview/preview.py`](https://github.com/deepfakes/faceswap/blob/main/tools/preview/preview.py) (line 541) validates the selected `mask_type` against available options before the UI initializes.

## Summary

- The training loop pushes samples to a `PreviewBuffer` ([`lib/training/preview_cv.py`](https://github.com/deepfakes/faceswap/blob/main/lib/training/preview_cv.py)) while a separate thread handles rendering via Tkinter or OpenCV.
- Mask choices are populated from alignment files and training config via `_create_mask_choices` in [`tools/preview/control_panels.py`](https://github.com/deepfakes/faceswap/blob/main/tools/preview/control_panels.py), always including "none" and conditionally including "predicted".
- Mask application occurs in `tools/sort/sort_methods.py::_mask_face`, which resizes masks to 256×256 and blends them using `np.minimum`.
- Mask toggling affects only visualization; the training loss continues using raw mask tensors from [`lib/training/cache.py`](https://github.com/deepfakes/faceswap/blob/main/lib/training/cache.py) and [`lib/training/generator.py`](https://github.com/deepfakes/faceswap/blob/main/lib/training/generator.py).

## Frequently Asked Questions

### Does mask toggling affect the model's training loss?

No, mask toggling in the preview system is purely for visualization. The underlying training loop continues using raw mask tensors defined in the training configuration and handled by [`lib/training/cache.py`](https://github.com/deepfakes/faceswap/blob/main/lib/training/cache.py) and [`lib/training/generator.py`](https://github.com/deepfakes/faceswap/blob/main/lib/training/generator.py). The `_mask_face` function only modifies the image displayed in the preview window.

### What mask types are available in the preview system?

The dropdown includes masks defined in the alignment file (such as "components" or "extended"), a "predicted" option if the model was trained with mask prediction enabled, and "none" to show raw faces. The `_create_mask_choices` function in [`tools/preview/control_panels.py`](https://github.com/deepfakes/faceswap/blob/main/tools/preview/control_panels.py) dynamically builds this list based on `alignments.mask_summary` and the `has_predicted_mask` configuration flag.

### How does the preview system maintain performance while training?

The system decouples training from rendering using a thread-safe `PreviewBuffer` that stores the most recent batch. The training loop pushes samples via `push()` without blocking, while the preview thread retrieves them via `get()` and handles the expensive mask application and GUI rendering separately in [`lib/training/preview_tk.py`](https://github.com/deepfakes/faceswap/blob/main/lib/training/preview_tk.py) or [`lib/training/preview_cv.py`](https://github.com/deepfakes/faceswap/blob/main/lib/training/preview_cv.py).

### Where is the mask actually applied to the face image?

The masking logic resides in [`tools/sort/sort_methods.py`](https://github.com/deepfakes/faceswap/blob/main/tools/sort/sort_methods.py) within the `_mask_face` method (lines 436-475). This function retrieves the requested mask from the alignment data, resizes it to 256×256, and applies it using `np.minimum(aln_face.face, nmask)` to produce the final preview image.