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.
pip install libreyoloThe 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:
pip install "libreyolo[gaze]"Without it, LibreYOLO prints manual download instructions instead of failing silently.
Predict
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)libreyolo predict model=LibreL2CSr50.pt source=https://raw.githubusercontent.com/LibreYOLO/libreyolo/release/libreyolo/assets/parkour.jpg save=Truefrom 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
| Task | ONNX | TorchScript | ExecuTorch | TensorRT | OpenVINO | Paddle | MNN | RKNN | ncnn | TFLite | CoreML | Core AI |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| gaze | gaze to ONNX: supported. | gaze to TorchScript: supported. | gaze to ExecuTorch: supported. | gaze to TensorRT: supported. | gaze to OpenVINO: supported. | gaze to Paddle: not supported | gaze to MNN: not supported | gaze to RKNN: not supported | gaze to ncnn: not supported | gaze to TFLite: not supported | gaze to CoreML: not supported | gaze to Core AI: not supported |
from libreyolo import LibreYOLO model = LibreYOLO("LibreL2CSr50.pt")model.export(format="onnx")model.export(format="tensorrt", half=True)libreyolo export model=LibreL2CSr50.pt format=onnximport 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
- Upstream source
- github.com/Ahmednull/L2CS-Net
- 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.