MiniFAS Face Anti-spoofing System

repository·main·Indexed 42 days ago

https://github.com/facenox/face-antispoof-onnx

A lightweight face anti-spoofing system using MiniFASNet V2 SE to distinguish real faces from spoofing attempts like photos or screens. Optimized for mobile and low-spec devices, it supports PyTorch and ONNX (including INT8 quantization) for high-efficiency inference. Features include a specialized architecture with Squeeze-and-Excitation blocks and Fourier Transform supervision during training to detect moiré patterns and texture differences.

Tokens
11.3K
Snippets
36
Records
51
Agent score
55%

What's inside MiniFAS

  1. Benefits of INT8 Quantization in MiniFAS

    main

    Quantizing the model to INT8 provides significant deployment advantages with negligible impact on performance:

    • Accuracy: No measurable drop in accuracy compared to the FP32 model.
    • Size Reduction: The file size is reduced to approximately 600 KB, which is 67% smaller than the original.
    • Performance Parity: Maintains the same ROC-AUC and Average Precision (AP) scores as the FP32 version.
  2. Resizing strategies: LANCZOS4 vs AREA

    main

    The pipeline uses different interpolation methods depending on whether the face crop is being upscaled or downscaled to reach the target 128x128 resolution:

    • Upscaling (Small crop $\rightarrow$ 128x128): Uses cv2.INTER_LANCZOS4. This high-quality interpolation uses a windowed sinc function to ensure sharp edges and preserve texture without blocky artifacts.
    • Downscaling (Large crop $\rightarrow$ 128x128): Uses cv2.INTER_AREA. This method averages pixels that map to each output pixel, providing proper downsampling that prevents aliasing and preserves texture better than bilinear or bicubic interpolation.
    interp = cv2.INTER_LANCZOS4 if crop_size < target_size else cv2.INTER_AREA
  3. Handle pose, occlusion, and motion blur limitations

    main

    The model's accuracy is affected by the following environmental and physical factors:

    • Pose: Accuracy is highest with frontal views (within +/-30 degrees of yaw/pitch). Profile views significantly reduce performance.
    • Occlusions: Masks, hands covering the face, or thick glasses with heavy reflections interfere with texture extraction.
    • Attack Types: The model is effective against printed photos and screens but is not trained on 3D silicone masks or prosthetics.
    • Motion Blur: Fast movement smears textures. To mitigate this in video streams, implement temporal filtering by requiring a sequence of consecutive 'Real' predictions.
  4. How the Fourier Transform (FT) branch works during training

    main

    The Fourier Transform branch is an auxiliary component used only during training to improve the backbone's ability to detect frequency-based spoofing artifacts (like screen pixel grids or print halftoning).

    Mechanism:

    • It takes features from Stage 2.
    • It uses three convolutional layers (128→64→1) to predict a single-channel Fourier spectrum.
    • The prediction is supervised against the actual FFT of the input image.
    • Gradients from this branch flow back into the main backbone.

    Note: This branch is removed during inference, so it does not add overhead to the deployed model.

  5. How Squeeze-and-Excitation (SE) blocks function in MiniFASNet

    main

    SE blocks are used at the boundaries of each stage to allow the network to dynamically emphasize specific feature channels that are most relevant to the input (e.g., channels detecting moiré patterns vs. those detecting paper texture).

    The SE process:

    1. Squeeze: Global average pooling is applied to obtain one value per channel.
    2. Excitation: Two small Fully Connected (FC) layers process these values to produce a weight for each channel.
    3. Scale: The original feature maps are multiplied by these calculated weights.
  6. How MiniFASNet V2 SE works

    main

    MiniFASNet V2 SE is a specialized neural network designed for face anti-spoofing (distinguishing real faces from fakes like printed photos, screens, or masks) rather than general image classification.

    It achieves this by detecting subtle presentation attack artifacts such as:

    • Moiré patterns from phone screens.
    • Color shifts from printed photos.
    • Texture differences between paper/plastic and skin.
    • Reflections and glare from displays.

    To maintain a small footprint while remaining effective, the architecture uses:

    1. Depthwise separable convolutions to minimize parameter count.
    2. Squeeze-and-Excitation (SE) blocks to prioritize relevant feature channels.
    3. Fourier Transform (FT) supervision (during training) to force the network to learn frequency-domain patterns characteristic of spoofs.
  7. Understand the MiniFASNet V2 SE architecture stages

    main

    The model is structured into several stages that progressively reduce spatial resolution while increasing channel depth:

    • Early Layers: Two convolutional layers (Conv1: 3×3, stride 2; Conv2 DW: depthwise 3×3) reduce resolution to 64×64×32.
    • Stage 1 (32×32×64): One depth-wise block followed by 4 residual blocks (1×1 → 3×3 DW → 1×1 pattern). Includes an SE module at the end.
    • Stage 2 (16×16×128): 6 residual blocks. This stage contains the most texture information and is the point where the Fourier Transform branch taps in during training.
    • Stage 3 (8×8×128): 2 residual blocks. The receptive field at this stage covers most of the input image.
    • Reduction: Collapses spatial dimensions using a SepConv 1×1 (to 512 channels) and a DW Conv 5×5 (to 1×1×512).
    • Classifier Head: Flattens to a 512-d vector, passes through an FC layer (512→128) with BatchNorm and aggressive Dropout (0.75), and finally an FC layer (128→2) to produce Real/Spoof logits.
  8. Prepare Dataset for Training

    main

    To train the model, you need face images (.jpg or .png), bounding box files (image_BB.txt with x y w h), and label files (metas/labels/train_label.json and metas/labels/test_label.json).

    Use scripts/prepare_data.py to crop and resize faces into organized training and testing folders:

    python scripts/prepare_data.py \
      --orig_dir <path> \
      --crop_dir <path> \
      --size <number> \
      --bbox_expansion_factor <float> \
      --spoof_types <number> [<number> ...]
    python scripts/prepare_data.py \
      --orig_dir <path> \
      --crop_dir <path> \
      --size <number> \
      --bbox_expansion_factor <float> \
      --spoof_types <number> [<number> ...]
  9. The Data Preparation Pipeline for `scripts/prepare_data.py`

    main

    The data preparation process transforms raw images into a standardized format suitable for the MiniFAS model. The pipeline follows these steps for each image:

    1. Read Bounding Box: Extract the face bounding box from image_BB.txt.
    2. Expand Bounding Box: Expand the box by a factor of 1.5x (50% larger on each side) to include contextual features like skin texture, hair, ears, and face-background boundaries.
    3. Square Cropping: To avoid geometric distortion, the pipeline identifies the longer side of the expanded bounding box and creates a square crop centered on the face.
    4. Padding: If the square crop extends beyond the original image boundaries, it uses cv2.BORDER_REFLECT_101 to provide a natural-looking extension of the image pixels.
    5. Resizing: The crop is resized to a final resolution of 128x128 pixels using interpolation methods optimized for the direction of scaling.
    6. Save: The processed images and labels are saved to a structured directory.
  10. Train the MiniFAS Model

    main

    Run the training script using the prepared cropped dataset. Checkpoints and TensorBoard logs are saved to <output_dir>/MINIFAS/.

    Standard Training:

    python scripts/train.py \
      --crop_dir <path> \
      --input_size <number> \
      --batch_size <number> \
      --output_dir <path>

    Resume Training:

    python scripts/train.py \
      --crop_dir <path> \
      --resume <checkpoint_path>
    python scripts/train.py \
      --crop_dir <path> \
      --input_size <number> \
      --batch_size <number> \
      --output_dir <path>
  11. Install MiniFAS Face Antispoofing

    main

    To use MiniFAS, you must use Python 3.8.0 or higher. Note that Python 3.7.x is incompatible and will cause installation errors during dependency setup.

    1. Create and activate a virtual environment

    Using Conda:

    conda create -n face-antispoof python
    conda activate face-antispoof

    Using venv:

    python -m venv venv
    # Linux/macOS
    source venv/bin/activate
    # Windows
    venv\Scripts\activate

    2. Install dependencies

    pip install -r requirements.txt
    IMPORTANT

    To run inference on a GPU, install onnxruntime-gpu instead of onnxruntime.

    pip install -r requirements.txt
  12. Optimize input preprocessing for face anti-spoofing

    main

    To ensure the model can detect spoofing artifacts (like screen pixels or print dots), inputs must follow specific preprocessing requirements:

    • Padding: Use a 1.5x padding factor around the face bounding box. Tight crops lose the 3D structural context necessary to distinguish a face from a flat screen or paper.
    • Resolution: The model resizes inputs to 128x128. However, the source face should be at least 64x64 pixels. Upscaling very small, blurry faces destroys the texture artifacts the model relies on.
    • Lighting: Use even lighting. Avoid low-light environments or harsh backlighting (e.g., bright windows behind the subject), as these create noise in the Fourier Transform patterns used for analysis.
    import cv2
    import numpy as np
    
    def crop_face_with_padding(image, bbox, padding_factor=1.5):
        """
        Crop face with proper padding for anti-spoofing model.
        
        Args:
            image: Input image (numpy array)
            bbox: Bounding box as (x, y, w, h)
            padding_factor: Padding multiplier (default: 1.5)
        
        Returns:
            Cropped face image
        """
        x, y, w, h = bbox
        
        # Calculate center and expanded dimensions
        center_x = x + w / 2
        center_y = y + h / 2
        max_dim = max(w, h)
        new_size = int(max_dim * padding_factor)
        
        # Calculate new bounding box
        x1 = int(center_x - new_size / 2)
        y1 = int(center_y - new_size / 2)
        x2 = x1 + new_size
        y2 = y1 + new_size
        
        # Clamp to image boundaries
        h_img, w_img = image.shape[:2]
        x1 = max(0, x1)
        y1 = max(0, y1)
        x2 = min(w_img, x2)
        y2 = min(h_img, y2)
        
        # Crop and resize to 128x128
        face_crop = image[y1:y2, x1:x2]
        face_resized = cv2.resize(face_crop, (128, 128), interpolation=cv2.INTER_LANCZOS4)
        
        return face_resized