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/:

  1. to_fp16.py LayerNormalization Softmax Add Mul converts with those four ops added to the converter's default block list.
  2. fuse_casts.py removes every Cast(to fp16) feeding a Cast(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.

Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support

Model tree for imbcmdth/faceage-onnx

Quantized
(1)
this model