L2CS-Net

L2CS-Net is a two-stage gaze estimator: a face detector locates faces, and a ResNet trunk with two angle-bin classification heads predicts pitch and yaw per face. LibreYOLO wraps it for inference only.

Tasks
gaze
Sizes
r18, r34, r50, r101, r152 at 448 px
Install
pip install libreyolo
Support tier
Inference only, since v. Predict, validate and export only. Training features do not apply.
Upstream
L2CS-Net by Ahmed A. Abdelrahman et al., Gaze360 dataset terms: research and non-commercial use only, no redistribution. Paper, source
Licenses
Code MIT, weights Gaze360 dataset terms: research and non-commercial use only, no redistribution. Commercial use

Install

L2CS-Net needs no extra to construct, predict on, or export a model you already have a checkpoint for.

bash
pip install libreyolo

The one checkpoint LibreYOLO can fetch automatically, a Gaze360-trained ResNet-50, downloads over gdown rather than a plain HTTP mirror, because it lives on the author's Google Drive rather than the LibreYOLO org. That path needs the gaze extra:

bash
pip install "libreyolo[gaze]"

Without it, LibreYOLO prints manual download instructions instead of failing silently.

Predict

Python
from libreyolo import LibreYOLO, SAMPLE_IMAGE # No face_detector given: falls back to OpenCV's bundled face# detector (Haar on OpenCV 4, YuNet on OpenCV 5), so this runs with# no extra download beyond the L2CS checkpoint itself.model = LibreYOLO("LibreL2CSr50.pt")result = model(SAMPLE_IMAGE) print(result.gaze.pitch, result.gaze.yaw)
CLI
libreyolo predict model=LibreL2CSr50.pt source=https://raw.githubusercontent.com/LibreYOLO/libreyolo/release/libreyolo/assets/parkour.jpg save=True
Face source
from libreyolo import LibreYOLO, SAMPLE_IMAGE model = LibreYOLO("LibreL2CSr50.pt") # Hand L2CS boxes from a detector you already ran.result = model(SAMPLE_IMAGE, face_boxes=[[34, 12, 90, 80]]) # Or name a specific bundled face detector.result = model(SAMPLE_IMAGE, face_detector="yunet")

L2CS-Net is a two-stage estimator: a face detector runs first, and the gaze head reads pitch and yaw from each face crop it returns. Left alone, prediction falls back to OpenCV's bundled detector, so a bare call works with no additional download once the L2CS checkpoint itself is in hand. face_boxes accepts boxes from a detector you already ran; face_detector accepts "auto", "haar", "yunet", a LibreYOLO detection model, or a plain callable. result.gaze carries pitch and yaw in radians, aligned row by row with result.boxes, the detected face boxes. See prediction for sources, streaming and result handling.

Variants

Five backbone depths share one input resolution and take the same arguments. Gaze360, the dataset behind the only published checkpoint, trained a ResNet-50; the other four depths are supported architecturally but have no published weights to load.

Export

TaskONNXTorchScriptExecuTorchTensorRTOpenVINOPaddleMNNRKNNncnnTFLiteCoreMLCore AI
gazegaze to ONNX: supported. gaze to TorchScript: supported. gaze to ExecuTorch: supported. gaze to TensorRT: supported. gaze to OpenVINO: supported. gaze to Paddle: not supportedgaze to MNN: not supportedgaze to RKNN: not supportedgaze to ncnn: not supportedgaze to TFLite: not supportedgaze to CoreML: not supportedgaze to Core AI: not supported

Python
from libreyolo import LibreYOLO model = LibreYOLO("LibreL2CSr50.pt")model.export(format="onnx")model.export(format="tensorrt", half=True)
CLI
libreyolo export model=LibreL2CSr50.pt format=onnx
Use the exported file
import numpy as npimport onnxruntime as ort # The exported graph is the ResNet trunk and the two angle-bin heads# alone: it takes a preprocessed 448x448 face crop and returns raw# (yaw_logits, pitch_logits), not decoded angles. The softmax,# bin-expectation and degree conversion stay in Python; see# libreyolo.models.l2cs.utils.bin_logits_to_angles.session = ort.InferenceSession("LibreL2CSr50.onnx")name = session.get_inputs()[0].nameyaw_logits, pitch_logits = session.run(    None, {name: np.zeros((1, 3, 448, 448), dtype=np.float32)})

Licensing

Check the license on the Hugging Face repository of the specific weights you download. Every checkpoint in the LibreYOLO org carries one, and they are not always the same across a family. That repository is the authoritative source; the summary below describes what applied when this page was last verified.

This is a description of the licenses involved, not legal advice. If the answer matters commercially, read the licenses yourself and take your own counsel.

Original work
L2CS-Net, Ahmed A. Abdelrahman et al.
Upstream license
Gaze360 dataset terms: research and non-commercial use only, no redistribution
LibreYOLO code
MIT
Weights
Gaze360 dataset terms: research and non-commercial use only, no redistribution, distributed by their authors. LibreYOLO does not host or mirror them.
Interpretation
The L2CS-Net source is MIT and may be used, modified and redistributed, including commercially. The one checkpoint LibreYOLO can fetch automatically, a ResNet-50 trained on Gaze360, is not covered by that grant: the Gaze360 dataset license restricts use of models trained on it to research and non-commercial purposes and forbids redistribution. LibreYOLO does not mirror or host that checkpoint. It downloads it, on request, directly from the author's own distribution and prints the Gaze360 terms once before the transfer starts. A model trained on data you hold the rights to, using this MIT architecture, carries none of those restrictions.

LibreYOLO does not host or mirror any L2CS checkpoint: nothing for this family exists in the LibreYOLO Hugging Face org, unlike most other families on this site. The one checkpoint the library can fetch automatically comes straight from the author's own Google Drive distribution, gated behind the Gaze360 license notice printed before the transfer starts, and is not the "republished at huggingface.co/LibreYOLO" copy the summary above implies.

Verified against LibreYOLO v1.5.0. Support tables, checkpoints and benchmark numbers on this page are generated from the released library and the published weights, not written by hand.