faceage-onnx
FaceAge ClientScan halved to fp16 for use as an ffrwd model pin. The network and weights are TrungTran's, Apache-2.0: a DINOv3 ViT-L/16 backbone with a CORAL ordinal-regression age head and a gender head, trained on face crops. This repo holds one converted file and the source's own configuration, nothing more.
Built with DINOv3. The backbone is Meta's, under the DINOv3 License, which travels with any derivative: a copy is in this repo, and anything that redistributes the model carries it too.
| file | bytes | sha256 |
|---|---|---|
| faceage-dino-fp16.onnx | 611872451 | b2e804783e197066cd8cf65a7cbc39a0579ea87c34660abd8ca942df8672cf70 |
The source it was converted from, as downloaded:
| file | bytes | sha256 |
|---|---|---|
| faceage_dino_fp32.onnx | 1219158136 | b0fefb4473978dae8128803d4577de2586f974198991f2c6252a5609dffb3233 |
source/ holds the source repo's config.json,
preprocessor_config.json, modeling_faceage_dino.py and
configuration_faceage_dino.py, which are where the preprocessing and
the decoding below come from.
Model I/O
The input face is Bx3x224x224 fp32, the batch dimension dynamic:
one face crop per row, RGB in NCHW, resized to 224x224 with bicubic
resampling and no aspect padding, scaled to 0..1, then normalized
with ImageNet's mean (0.485, 0.456, 0.406) and standard deviation
(0.229, 0.224, 0.225).
Crop the face with 10 percent proportional padding on each side: for
a box x0, y0, x1, y1, widen it by 0.1 * (x1 - x0) left and right
and by 0.1 * (y1 - y0) above and below, clamped to the image. That
is how the model was trained, and the source card reports that
without the padding its error grows from 3.56 to 3.76 years.
Two outputs, both fp32:
age_logits,Bx100: the CORAL thresholds. The age in years is the sum of their sigmoids,age = sum(sigmoid(age_logits[k]) for k in 0..99), a continuous value in 0..100.gender_logits,Bx2: softmax, then argmax; 0 is female, 1 is male.
The source card reports MAE 3.56 years on LAGENDA (84k faces), with 1.55 on ages 0 to 12 and 2.85 on 13 to 17.
The fp16 conversion
The file is the source graph with every MatMul weight in fp16 and the input and outputs left fp32, so a caller feeds and reads fp32 tensors exactly as it would the source. The weights in fp16 are 99.5 percent of the 304M parameters, which is why the file is half the size.
A plain onnxconverter_common.float16.convert_float_to_float16 with
keep_io_types=True produces a graph that returns NaN for every
input. DINOv3 carries a "massive activation" on its residual stream,
one channel at about 1.57e5 from the first block onward, and fp16
tops out at 65,504. Keeping the residual ops in fp32 through
op_block_list is not enough on its own, because the converter wraps
every blocked node with its own down-cast and up-cast, so the value
still passes through fp16 between two adjacent fp32 nodes and
overflows there.
So the conversion is two steps, both in scripts/:
to_fp16.py LayerNormalization Softmax Add Mulconverts with those four ops added to the converter's default block list.fuse_casts.pyremoves everyCast(to fp16)feeding aCast(to fp32), rewiring the consumer to the original fp32 tensor, and drops the down-casts left without a reader. On this graph that removes 118 up-casts and 47 orphaned down-casts. The residual stream, all 50 LayerNormalizations and all 24 Softmaxes are then fp32 end to end, and the 192 MatMuls stay fp16.
scripts/validate_fp16.py compares the result against the source on
200 WIDER FACE validation face crops of at least 32 px, padded and
resized as above:
| mean absolute age difference | 0.012 years |
| max absolute age difference | 0.074 years |
| NaN or inf in either output | none |
| gender agreement | 200 of 200 |
Converted with onnx 1.22.0, onnxconverter-common 1.16.0 and
onnxruntime 1.29.0 under Python 3.11; opset 18, IR 10, a single
self-contained file with no external data.
License
The weights are Apache-2.0 as the source declares. The backbone is DINOv3, and the DINOv3 License applies to it and to this derivative: use, modification and redistribution are permitted, commercial use included, on condition that the license accompanies any redistribution and that "Built with DINOv3" is displayed where the model is used. The source's training data is its own and is not distributed here.
Model tree for imbcmdth/faceage-onnx
Base model
TrungTran/faceage_ClientScan