Skip to content

Commit 59a151b

Browse files
Release v1.0.0: torch.export, new features, pyproject.toml, uv in Docker
Breaking changes: - Minimum Python 3.10, PyTorch 2.0 - All models migrated from TorchScript (.pt) to torch.export (.pt2) - path_image and tensor params deprecated in favor of image_source New features: - Selective predictor execution (include/exclude_predictors) - Pre-cropped face input (skip_detector) - Grayscale/RGBA auto-conversion to RGB - Robust input routing (tensor, numpy, PIL, bytes, path) - __call__ methods on FaceAnalyzer, BaseProcessor, BaseDownloader, BaseModel Packaging & tooling: - Migrated from setup.py to pyproject.toml (PEP 621) - Docker dev/test images migrated from conda to uv - Dev dependencies consolidated into pyproject.toml - Production Docker images use uv as pip drop-in - CI updated for Python 3.10-3.13, CUDA 12.4 - Google Colab notebook updated for v1.0.0 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent dad7d0e commit 59a151b

53 files changed

Lines changed: 2714 additions & 2258 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/auto-release.yml

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ on:
44
push:
55
branches: [ "main" ]
66
paths:
7-
- "version"
7+
- "pyproject.toml"
88

99
jobs:
1010
create-release:
@@ -23,7 +23,12 @@ jobs:
2323
- name: Read version
2424
id: version
2525
run: |
26-
VERSION=$(cat ./version | tr -d '[:space:]')
26+
VERSION=$(python3 -c "
27+
import re
28+
with open('pyproject.toml') as f:
29+
match = re.search(r'^version\s*=\s*\"(.+?)\"', f.read(), re.MULTILINE)
30+
print(match.group(1))
31+
")
2732
echo "VERSION=$VERSION" >> $GITHUB_OUTPUT
2833
echo "TAG=v$VERSION" >> $GITHUB_OUTPUT
2934
echo "VERSION=$VERSION" >> $GITHUB_ENV
@@ -74,7 +79,7 @@ jobs:
7479
- name: Set up Python
7580
uses: actions/setup-python@v5
7681
with:
77-
python-version: "3.10"
82+
python-version: "3.12"
7883

7984
- name: Install build dependencies
8085
run: |
@@ -100,7 +105,13 @@ jobs:
100105
- uses: actions/checkout@v4
101106

102107
- name: Set VERSION variable
103-
run: echo "VERSION=$(cat ./version | tr -d '[:space:]')" >> $GITHUB_ENV
108+
run: |
109+
echo "VERSION=$(python3 -c "
110+
import re
111+
with open('pyproject.toml') as f:
112+
match = re.search(r'^version\s*=\s*\"(.+?)\"', f.read(), re.MULTILINE)
113+
print(match.group(1))
114+
")" >> $GITHUB_ENV
104115
105116
- name: Login to Docker Hub
106117
env:

.github/workflows/lint.yml

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,20 +12,18 @@ jobs:
1212
strategy:
1313
fail-fast: false
1414
matrix:
15-
python-version: ["3.9"]
15+
python-version: ["3.12"]
1616

1717
steps:
1818
- uses: actions/checkout@v4
1919
- name: Set up Python ${{ matrix.python-version }}
2020
uses: actions/setup-python@v5
2121
with:
2222
python-version: ${{ matrix.python-version }}
23-
- name: Install dependencies
24-
run: |
25-
python -m pip install --upgrade pip
2623
- name: Install development dependencies
2724
run: |
28-
python -m pip install -r requirements.dev.txt
25+
python -m pip install --upgrade pip
26+
python -m pip install .[dev]
2927
- name: Lint with flake8
3028
run: |
3129
flake8 --config=.flake8

.github/workflows/python-package.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ jobs:
1313
strategy:
1414
fail-fast: false
1515
matrix:
16-
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
16+
python-version: ["3.10", "3.11", "3.12", "3.13"]
1717

1818
steps:
1919
- uses: actions/checkout@v4

.github/workflows/release.yml

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ on:
44
workflow_dispatch:
55
inputs:
66
tag:
7-
description: "Release tag (e.g., v0.6.1). Defaults to version file."
7+
description: "Release tag (e.g., v1.0.0). Defaults to pyproject.toml version."
88
required: false
99

1010
jobs:
@@ -22,7 +22,12 @@ jobs:
2222
if [ -n "${{ github.event.inputs.tag }}" ]; then
2323
TAG="${{ github.event.inputs.tag }}"
2424
else
25-
FILE_VERSION=$(cat ./version | tr -d '[:space:]')
25+
FILE_VERSION=$(python3 -c "
26+
import re
27+
with open('pyproject.toml') as f:
28+
match = re.search(r'^version\s*=\s*\"(.+?)\"', f.read(), re.MULTILINE)
29+
print(match.group(1))
30+
")
2631
TAG="v$FILE_VERSION"
2732
fi
2833
VERSION="${TAG#v}"
@@ -39,7 +44,7 @@ jobs:
3944
- name: Set up Python
4045
uses: actions/setup-python@v5
4146
with:
42-
python-version: "3.10"
47+
python-version: "3.12"
4348

4449
- name: Install build dependencies
4550
run: |

CHANGELOG.md

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,45 @@
11
# Change Log
22

3+
## 1.0.0
4+
5+
Released on April 18, 2026.
6+
7+
### Breaking Changes
8+
* Minimum Python version raised from 3.8 to 3.10
9+
* Minimum PyTorch version raised from 1.9 to 2.0
10+
* All models migrated from TorchScript (.pt) to torch.export (.pt2) format
11+
* `path_image` and `tensor` parameters in `FaceAnalyzer.run()` are deprecated in favor of `image_source`
12+
13+
### Added
14+
* Selective predictor execution via `include_predictors` and `exclude_predictors` parameters in `FaceAnalyzer.run()`
15+
* Pre-cropped face input support via `skip_detector=True` parameter in `FaceAnalyzer.run()`
16+
* Grayscale image handling: automatic conversion of single-channel and RGBA inputs to RGB across all input paths
17+
* `__call__` methods on `FaceAnalyzer`, `BaseProcessor`, `BaseDownloader`, and `BaseModel` (delegates to `run()`)
18+
* Optional logger configuration: `FaceAnalyzer` falls back to `logging.getLogger("facetorch")` when no logger is configured
19+
* Robust input routing in `FaceAnalyzer.run()` — tensor, numpy array, PIL Image, bytes, and file path inputs work with any reader type
20+
* All .pt2 models uploaded to Hugging Face Hub with model cards
21+
* `uv.lock` for reproducible PyPI-based dependency resolution
22+
* `[tool.uv]` configuration in `pyproject.toml`
23+
24+
### Changed
25+
* Migrated from `setup.py` + `version` file to `pyproject.toml` (PEP 621)
26+
* All model files migrated from TorchScript (.pt) to torch.export (.pt2) portable format with dynamic batch support
27+
* AU predictor model rewritten with timm Swin Transformer backbone for torch.export compatibility
28+
* Docker dev/test images migrated from conda/conda-lock to [uv](https://github.com/astral-sh/uv) for faster builds
29+
* Docker production images now use uv as a pip drop-in
30+
* Development dependencies consolidated from `requirements.dev.txt` into `pyproject.toml`
31+
* Docker base images updated to Python 3.12 and CUDA 12.4
32+
* CI test matrix updated to Python 3.10, 3.11, 3.12, 3.13
33+
* GPU environment updated from CUDA 11.2 to CUDA 12.1+
34+
* Development status classifier updated from Alpha to Production/Stable
35+
* Google Colab notebook updated to v1.0.0 (uses `image_source`, removes pinned torch versions)
36+
37+
### Fixed
38+
* "File name too long" error when passing tensor/array to `FaceAnalyzer.run()` with `ImageReader`
39+
* AU predictor YAML indentation error in merged config files
40+
* Numpy array reader now handles (H, W) and (H, W, 1) grayscale arrays
41+
42+
343
## 0.6.2
444

545
Released on April 17, 2026.
@@ -33,7 +73,7 @@ Released on April 14, 2026.
3373
### Added
3474
* Unit tests for all post-processor tuple input handling
3575
* Version tag validation in release workflow
36-
* Auto-release workflow that creates GitHub Releases when version file changes on main
76+
* Auto-release workflow that creates GitHub Releases when version changes on main
3777

3878

3979
## 0.6.0

MANIFEST.in

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
include LICENSE
2-
include version
2+
include pyproject.toml
33
include environment.yml
44
recursive-include conf *
55
recursive-include docs *
66
include data/input*/*.jpg
77
include data*/*.png
8-
include tests*/*.py
8+
include tests*/*.py

README.md

Lines changed: 54 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,25 @@
1717
[Docker Hub](https://hub.docker.com/repository/docker/tomasgajarsky/facetorch) [(GPU)](https://hub.docker.com/repository/docker/tomasgajarsky/facetorch-gpu)
1818

1919

20-
**Facetorch** is a Python library designed for facial detection and analysis, leveraging the power of deep neural networks. Its primary aim is to curate open-source face analysis models from the community, optimize them for high performance using TorchScript, and integrate them into a versatile face analysis toolkit. The library offers the following key features:
20+
**Facetorch** is a Python library designed for facial detection and analysis, leveraging the power of deep neural networks. Its primary aim is to curate open-source face analysis models from the community, package them as portable [torch.export](https://pytorch.org/docs/stable/export.html) models, and integrate them into a versatile face analysis toolkit. The library offers the following key features:
2121

2222
1. **Customizable Configuration:** Easily configure your setup using [Hydra](https://hydra.cc/docs/intro/) and its powerful [OmegaConf](https://omegaconf.readthedocs.io/) capabilities.
2323

24-
2. **Reproducible Environments:** Ensure reproducibility with tools like [conda-lock](https://github.com/conda-incubator/conda-lock) for dependency management and [Docker](https://docs.docker.com/get-docker/) for containerization.
24+
2. **Reproducible Environments:** Ensure reproducibility with [uv](https://github.com/astral-sh/uv) for fast Python package management, [conda-lock](https://github.com/conda-incubator/conda-lock) for conda-forge dependency management, and [Docker](https://docs.docker.com/get-docker/) for containerization.
2525

26-
3. **Accelerated Performance:** Enjoy enhanced performance on both CPU and GPU with [TorchScript](https://pytorch.org/docs/stable/jit.html) optimization.
26+
3. **Portable Models:** Models are serialized with `torch.export` (`.pt2` format) — no model source code needed at inference time, with dynamic batch support and `torch.compile` compatibility.
2727

28-
4. **Simple Extensibility:** Extend the library by uploading your model file to Hugging Face Hub (previously Google Drive) and adding a corresponding configuration YAML file to the repository.
28+
4. **Simple Extensibility:** Extend the library by uploading your model file to Hugging Face Hub and adding a corresponding configuration YAML file to the repository.
29+
30+
5. **Flexible Input:** Accepts file paths, URLs, tensors, numpy arrays, PIL Images, and bytes. Grayscale and RGBA inputs are automatically converted to RGB.
2931

3032
Facetorch provides an efficient, scalable, and user-friendly solution for facial analysis tasks, catering to developers and researchers looking for flexibility and performance.
3133

34+
### Requirements
35+
36+
* Python >= 3.10
37+
* PyTorch >= 2.0
38+
3239
Please use this library responsibly and with caution. Adhere to the [European Commission's Ethics Guidelines for Trustworthy AI](https://ec.europa.eu/futurium/en/ai-alliance-consultation.1.html) to ensure ethical and fair usage. Keep in mind that the models may have limitations and potential biases, so it is crucial to evaluate their outputs critically and consider their impact.
3340

3441

@@ -58,6 +65,28 @@ Check *data/output* for resulting images with bounding boxes and facial 3D landm
5865

5966
(Apple Mac M1) Use Rosetta 2 emulator in Docker Desktop to run the CPU version.
6067

68+
### Python API
69+
70+
```python
71+
from facetorch import FaceAnalyzer
72+
from omegaconf import OmegaConf
73+
74+
cfg = OmegaConf.load("conf/config.yaml")
75+
analyzer = FaceAnalyzer(cfg.analyzer)
76+
77+
# Analyze from file path, URL, tensor, numpy array, PIL Image, or bytes
78+
response = analyzer.run(image_source="path/to/image.jpg")
79+
80+
# Run only specific predictors
81+
response = analyzer.run(image_source="image.jpg", include_predictors=["fer", "embed"])
82+
83+
# Skip detector for pre-cropped face inputs
84+
response = analyzer.run(image_source=face_tensor, skip_detector=True)
85+
86+
# FaceAnalyzer is also callable
87+
response = analyzer("image.jpg")
88+
```
89+
6190
### Configure
6291

6392
The project is configured by files located in *conf* with the main file: *conf/config.yaml*. One can easily add or remove modules from the configuration.
@@ -157,7 +186,7 @@ analyzer
157186
1. CVI-SZU
158187
* code: [ME-GraphAU](https://github.com/CVI-SZU/ME-GraphAU)
159188
* paper: [Luo et al. - Learning Multi-dimensional Edge Feature-based AU Relation Graph for Facial Action Unit Recognition](https://arxiv.org/abs/2205.01782)
160-
* ! Does not work with CUDA > 12.0
189+
* Note: As of v1.0.0, the AU model uses torch.export format and works with all CUDA versions
161190

162191
#### Facial Valence Arousal (va)
163192

@@ -232,13 +261,22 @@ Run the Docker container:
232261

233262
### Add predictor
234263
#### Prerequisites
235-
1. File of the TorchScript model
236-
2. Repository on Hugging Face Hub for hosting the model (or legacy ID of the Google Drive model file)
264+
1. Exported `.pt2` model file (see below)
265+
2. Repository on Hugging Face Hub for hosting the model
237266
3. facetorch [fork](https://docs.github.com/en/get-started/quickstart/fork-a-repo)
238267

239-
Facetorch works with models that were exported from PyTorch to TorchScript. You can apply [torch.jit.trace](https://pytorch.org/docs/stable/generated/torch.jit.trace.html) function to compile a PyTorch model as a TorchScript module. Please verify that the output of the traced model equals the output of the original model.
268+
Facetorch uses models exported with [torch.export](https://pytorch.org/docs/stable/export.html) (`.pt2` format). Export your model with dynamic batch support:
269+
270+
```python
271+
import torch
240272

241-
Models are now hosted on [Hugging Face Hub](https://huggingface.co/tomas-gajarsky) which is the default download source. You can host your model on your own Hugging Face account or use the legacy Google Drive hosting option by specifying the appropriate downloader in your configuration.
273+
model.eval()
274+
batch = torch.export.Dim("batch", min=1, max=64)
275+
ep = torch.export.export(model, (dummy_input,), dynamic_shapes={"x": {0: batch}})
276+
torch.export.save(ep, "model.pt2")
277+
```
278+
279+
Verify that the exported model produces the same outputs as the original. Models are hosted on [Hugging Face Hub](https://huggingface.co/tomas-gajarsky).
242280

243281
#### Configuration
244282
##### Create yaml file
@@ -272,6 +310,13 @@ the requirements of the new model.
272310

273311

274312
### Update environment
313+
314+
#### uv (used by Docker dev/test images)
315+
* Add packages with corresponding versions to ```pyproject.toml``` dependencies
316+
* Lock the environment: ```uv lock```
317+
* Sync the environment: ```uv sync --extra dev```
318+
319+
#### conda (for conda-forge users)
275320
CPU:
276321
* Add packages with corresponding versions to ```environment.yml``` file
277322
* Lock the environment: ```conda lock -p linux-64 -f environment.yml --lockfile conda-lock.yml```

conf/analyzer/detector/retinaface.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ _target_: facetorch.analyzer.detector.FaceDetector
44
downloader:
55
_target_: facetorch.downloader.DownloaderHuggingFace
66
file_id: 1eMuOdGkiNCOUTiEbKKoPCHGCuDgiKeNC
7-
path_local: /opt/facetorch/models/torchscript/detector/1/model.pt # str
7+
path_local: /opt/facetorch/models/exported/detector/1/model.pt2 # str
88
repo_id: tomas-gajarsky/facetorch-detector-retinaface # HuggingFace repo ID
9-
filename: model.pt # Filename in the HuggingFace repo
9+
filename: model.pt2 # Filename in the HuggingFace repo
1010

1111
device:
1212
_target_: torch.device

conf/analyzer/detector/retinaface_hf.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ _target_: facetorch.analyzer.detector.FaceDetector
44
downloader:
55
_target_: facetorch.downloader.DownloaderHuggingFace
66
file_id: 1eMuOdGkiNCOUTiEbKKoPCHGCuDgiKeNC
7-
path_local: /opt/facetorch/models/torchscript/detector/1/model.pt # str
7+
path_local: /opt/facetorch/models/exported/detector/1/model.pt2 # str
88
repo_id: tomas-gajarsky/facetorch-detector-retinaface # HuggingFace repo ID
9-
filename: model.pt # Filename in the HuggingFace repo
9+
filename: model.pt2 # Filename in the HuggingFace repo
1010

1111
device:
1212
_target_: torch.device

conf/analyzer/predictor/align/synergy_mobilenet_v2.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ _target_: facetorch.analyzer.predictor.FacePredictor
33
downloader:
44
_target_: facetorch.downloader.DownloaderHuggingFace
55
file_id: 16gNFQdEH2nWvW3zTbdIAniKIbPAp6qBA
6-
path_local: /opt/facetorch/models/torchscript/predictor/align/1/model.pt # str
6+
path_local: /opt/facetorch/models/exported/predictor/align/1/model.pt2 # str
77
repo_id: tomas-gajarsky/facetorch-align-synergynet # HuggingFace repo ID
8-
filename: model.pt # Filename in the HuggingFace repo
8+
filename: model.pt2 # Filename in the HuggingFace repo
99

1010
device:
1111
_target_: torch.device

0 commit comments

Comments
 (0)