# How to Prepare and Use the WFLW Dataset for PFLD Training: Complete Setup Guide

> Prepare and use the WFLW dataset for PFLD training by downloading images and annotations, extracting them, and running the setup script. Get your PFLD model trained quickly.

- Repository: [Guoqiang QI/pfld](https://github.com/guoqiangqi/pfld)
- Tags: how-to-guide
- Published: 2026-03-02

---

**To prepare and use the WFLW dataset for PFLD training, download the WFLW images and annotation files, extract them into the repository's `data/` directory structure, and execute `python data/SetPreparation.py` to generate processed `train_data/` and `test_data/` folders containing normalized images and [`list.txt`](https://github.com/guoqiangqi/pfld/blob/main/list.txt) label files.**

The `guoqiangqi/pfld` repository provides a stand‑alone preprocessing pipeline that converts raw WFLW resources into the exact format consumed by the TensorFlow training script. This guide walks through the mandatory directory layout, the internal mechanics of the preparation script, and how to verify the output before launching [`train_model.py`](https://github.com/guoqiangqi/pfld/blob/main/train_model.py).

## Downloading WFLW Images and Annotations

Before running any code, you must obtain the original dataset files. The WFLW (Wider Facial Landmarks in-the-wild) dataset provides 10,000 faces with 98 manually annotated landmarks.

### Downloading WFLW Images

The image archive contains 7,500 training and 2,500 test face images.

- **Google Drive**: `https://drive.google.com/file/d/1hzBd48JIdWTJSsATBEB_eFVvPL1bx6UC/view?usp=sharing`
- **Baidu Drive**: `https://pan.baidu.com/s/1paoOpusuyafHY154lqXYrA`

Download `WFLW_images.zip` and preserve it for extraction in the next step.

### Downloading Annotation Files

The annotation tarball provides the 98-point landmark coordinates, face bounding boxes, and attribute flags (pose, expression, illumination, etc.).

- **Direct link**: `https://wywu.github.io/projects/LAB/support/WFLW_annotations.tar.gz`

This archive contains [`list_98pt_rect_attr_train.txt`](https://github.com/guoqiangqi/pfld/blob/main/list_98pt_rect_attr_train.txt) and [`list_98pt_rect_attr_test.txt`](https://github.com/guoqiangqi/pfld/blob/main/list_98pt_rect_attr_test.txt), which [`SetPreparation.py`](https://github.com/guoqiangqi/pfld/blob/main/SetPreparation.py) parses line-by-line.

## Setting Up the Directory Structure

The preparation script expects a rigid folder hierarchy under the repository root. Misplacing the archives will cause `FileNotFoundError` during execution.

Create the following layout:

```bash
pfld/
├── data/
│   ├── WFLW_images/                    # Extracted image folder

│   │   └── ... (10,000 .jpg files)
│   └── WFLW_annotations/
│       └── list_98pt_rect_attr_train_test/
│           ├── list_98pt_rect_attr_test.txt
│           └── list_98pt_rect_attr_train.txt
├── data/SetPreparation.py
└── ...

```

Execute these commands from the repository root to unpack the downloads:

```bash

# Create expected directories

mkdir -p data/WFLW_images
mkdir -p data/WFLW_annotations/list_98pt_rect_attr_train_test

# Extract archives

unzip WFLW_images.zip -d data/WFLW_images
tar -xzf WFLW_annotations.tar.gz -C data/WFLW_annotations/list_98pt_rect_attr_train_test

```

The script references these paths directly at lines 199–204 of [`data/SetPreparation.py`](https://github.com/guoqiangqi/pfld/blob/main/data/SetPreparation.py):

```python
imageDirs = './data/WFLW_images'
Mirror_file = './data/Mirror98.txt'
train_file = './data/WFLW_annotations/list_98pt_rect_attr_train_test/list_98pt_rect_attr_train.txt'
test_file = './data/WFLW_annotations/list_98pt_rect_attr_train_test/list_98pt_rect_attr_test.txt'

```

## Running the WFLW Preparation Script

With the data in place, run the preprocessing script to generate training-ready tensors:

```bash
python data/SetPreparation.py

```

This executes the full pipeline defined in [`SetPreparation.py`](https://github.com/guoqiangqi/pfld/blob/main/SetPreparation.py), performing three core operations:

### 1. Parsing Annotations with `ImageDate`

The `ImageDate` class (lines 28–44) splits each line of the annotation text file into:

- **Landmarks**: 98 points (x, y) normalized by image width/height.
- **Bounding box**: Face rectangle (x, y, w, h).
- **Attributes**: 6 binary flags (pose, expression, illumination, make-up, occlusion, blur).
- **Euler angles**: Pre-computed pitch, yaw, roll (or placeholders).

### 2. Image Processing and Augmentation

The `load_data` function (lines 59–98) handles:

- **Cropping**: Extracts a square region 1.2× the tight bounding box.
- **Resizing**: Scales the crop to `image_size` (default 112×112 pixels).
- **Data augmentation** (training set only):
  - Random rotation between -20° and +20° (repeated 10× per image).
  - Horizontal mirroring using the indices defined in [`data/Mirror98.txt`](https://github.com/guoqiangqi/pfld/blob/main/data/Mirror98.txt).

### 3. Generating Output Files

The `save_data` function (lines 146–170) writes:

- **Processed images**: Saved as PNG files in `train_data/imgs/` and `test_data/imgs/`.
- **Label lines**: Each line contains:
  1. Relative image path.
  2. 196 normalized landmark coordinates (98×2).
  3. 6 attribute integers.
  4. 3 Euler angles (pitch, yaw, roll) calculated by `calculate_pitch_yaw_roll` in [`euler_angles_utils.py`](https://github.com/guoqiangqi/pfld/blob/main/euler_angles_utils.py).

The `get_dataset_list` function aggregates these lines and writes [`train_data/list.txt`](https://github.com/guoqiangqi/pfld/blob/main/train_data/list.txt) and [`test_data/list.txt`](https://github.com/guoqiangqi/pfld/blob/main/test_data/list.txt), which are the direct inputs to the training script.

## Verifying the WFLW Dataset Preparation

After execution, confirm the output structure:

```bash
tree train_data test_data -L 2 | head -n 20

```

Expected output:

```

train_data/
├── imgs/
│   ├── 0_0.png
│   ├── 0_1.png
│   └── ...
└── list.txt
test_data/
├── imgs/
│   ├── 0_0.png
│   └── ...
└── list.txt

```

Inspect a sample label line to ensure correct formatting:

```bash
head -n 1 train_data/list.txt

```

The line should contain 207 space-separated fields: 1 path + 196 landmarks + 6 attributes + 3 angles.

## Integrating with PFLD Training

The [`train_model.py`](https://github.com/guoqiangqi/pfld/blob/main/train_model.py) script expects the [`list.txt`](https://github.com/guoqiangqi/pfld/blob/main/list.txt) files generated above. In the repository code, the data loader reads each line and splits it into tensors:

```python

# Simplified excerpt from the training data pipeline

def parse_line(line):
    parts = line.strip().split()
    img_path = parts[0]
    landmarks = np.array(parts[1:1+196], dtype=np.float32).reshape(98, 2)
    attributes = np.array(parts[1+196:1+196+6], dtype=np.int32)
    euler_angles = np.array(parts[-3:], dtype=np.float32)  # pitch, yaw, roll

    return img_path, landmarks, attributes, euler_angles

```

Pass the generated paths to the training script:

```bash
python train_model.py --train_list train_data/list.txt --test_list test_data/list.txt

```

## Summary

- **Download** the WFLW images and annotation files from the official mirrors (Google Drive, Baidu Drive, or the project website).
- **Extract** archives into `data/WFLW_images` and `data/WFLW_annotations/list_98pt_rect_attr_train_test` to match the hardcoded paths in [`SetPreparation.py`](https://github.com/guoqiangqi/pfld/blob/main/SetPreparation.py).
- **Execute** `python data/SetPreparation.py` to parse annotations, crop faces to 112×112, apply augmentation (rotation, mirroring), compute Euler angles via [`euler_angles_utils.py`](https://github.com/guoqiangqi/pfld/blob/main/euler_angles_utils.py), and write [`train_data/list.txt`](https://github.com/guoqiangqi/pfld/blob/main/train_data/list.txt) and [`test_data/list.txt`](https://github.com/guoqiangqi/pfld/blob/main/test_data/list.txt).
- **Verify** that [`list.txt`](https://github.com/guoqiangqi/pfld/blob/main/list.txt) contains 207 fields per line (path, 196 landmarks, 6 attributes, 3 angles) before launching [`train_model.py`](https://github.com/guoqiangqi/pfld/blob/main/train_model.py).

## Frequently Asked Questions

### What is the exact directory structure required for WFLW dataset preparation?

The [`SetPreparation.py`](https://github.com/guoqiangqi/pfld/blob/main/SetPreparation.py) script expects images at `./data/WFLW_images` and annotation text files at [`./data/WFLW_annotations/list_98pt_rect_attr_train_test/list_98pt_rect_attr_train.txt`](https://github.com/guoqiangqi/pfld/blob/main/./data/WFLW_annotations/list_98pt_rect_attr_train_test/list_98pt_rect_attr_train.txt) (and test). Create these folders under the repository root and extract the downloaded ZIP and TAR archives into them before running the script.

### How does the SetPreparation.py script handle data augmentation?

During processing of the training split, the script generates 10 augmented variants per source image. It applies random rotations between -20 and +20 degrees and optionally mirrors the image horizontally using the landmark indices defined in [`data/Mirror98.txt`](https://github.com/guoqiangqi/pfld/blob/main/data/Mirror98.txt). The test split is processed without augmentation to ensure consistent evaluation.

### What format does the generated list.txt file follow?

Each line in [`list.txt`](https://github.com/guoqiangqi/pfld/blob/main/list.txt) contains 207 space-separated values: the relative path to the processed PNG image, 196 floating-point numbers representing the 98 normalized (x,y) landmark coordinates, 6 integer attribute flags (pose, expression, illumination, make-up, occlusion, blur), and 3 floating-point Euler angles (pitch, yaw, roll) pre-computed by [`euler_angles_utils.py`](https://github.com/guoqiangqi/pfld/blob/main/euler_angles_utils.py).

### Can I skip the preprocessing and use raw WFLW images directly for training?

No. The PFLD training pipeline in [`train_model.py`](https://github.com/guoqiangqi/pfld/blob/main/train_model.py) expects normalized 112×112 crops, pre-computed Euler angles, and specific attribute flags that are only generated by [`SetPreparation.py`](https://github.com/guoqiangqi/pfld/blob/main/SetPreparation.py). Running the preprocessing step once creates reusable [`list.txt`](https://github.com/guoqiangqi/pfld/blob/main/list.txt) files that eliminate the computational overhead of on-the-fly angle calculation during training epochs.