|
Download README.md from imbcmdth/faceage-onnx: direct link, hf CLI and curl.
- Browser
- Download file 7.47 kB
-
https://huggingface.co/imbcmdth/faceage-onnx/resolve/main/README.md
- Command line
-
hf download hf://imbcmdth/faceage-onnx/README.md
-
curl -L -o README.md https://huggingface.co/imbcmdth/faceage-onnx/resolve/main/README.md
7.47 kB
| license: apache-2.0 | |
| base_model: TrungTran/faceage_ClientScan | |
| tags: | |
| - age-estimation | |
| - face-analysis | |
| - onnx | |
| - fp16 | |
| - dinov3 | |
| # faceage-onnx | |
| [FaceAge ClientScan](https://huggingface.co/TrungTran/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 two converted files of that network and the source's | |
| own configuration, nothing more. | |
| Built with DINOv3. The backbone is Meta's, under the | |
| [DINOv3 License](DINOv3_LICENSE.md), 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 | | |
| | faceage-dino-vitl16-fused-fp16.onnx | 611187743 | 30c5531f17a1faa1f27891cb8af3e12f1fb14ea5f456192d0f1afcc8c9105ba0 | | |
| `faceage-dino-fp16.onnx` is the source converted to fp16 (see "The | |
| fp16 conversion"). `faceage-dino-vitl16-fused-fp16.onnx` is the same | |
| network and weights rebuilt with fused operators, 2.6 to 3.9 times as | |
| fast on ONNX Runtime's CUDA provider (see "The fused rebuild"). Both | |
| take the same input and return the same outputs. | |
| 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. | |
| ## The fused rebuild | |
| `faceage-dino-vitl16-fused-fp16.onnx` is written by | |
| `scripts/rebuild_fused.py`, which reads the weights out of the source | |
| fp32 file and writes a new graph for them by hand. The network is the | |
| source's; only the way the graph is written changes: | |
| - The residual stream is carried scaled by 1/8, and each LayerNorm's | |
| epsilon by 1/64, so every LayerNorm's output is what it was. The | |
| massive activation on channel 757 then peaks at about 1.95e4 instead | |
| of 1.56e5, inside fp16's 65,504, and the residual stream can no longer | |
| overflow. The layer scales, times 1/8, are folded into the output | |
| projections' weights and biases. | |
| - Attention is one `com.microsoft` MultiHeadAttention per block, in | |
| fp16. The rotary position embedding is `com.microsoft` | |
| RotaryEmbedding, with its cos and sin tables computed once in float64 | |
| from the source's angle table and stored as fp16 constants; the CLS | |
| token and the four register tokens get rows of cos 1 and sin 0, so one | |
| operator covers all 201 tokens. Each residual add and the LayerNorm | |
| after it are one `com.microsoft` SkipLayerNormalization in fp32, and | |
| the MLP's bias and GELU are one `com.microsoft` BiasGelu. | |
| - v's bias is folded into o's bias. A row of attention weights sums to | |
| one, so a constant added to every value passes through attention | |
| unchanged. | |
| - The last block computes the query and the MLP for the CLS token only, | |
| since only the CLS token is read after it. | |
| - The MatMuls are fp16; the residual stream, the LayerNorms, the input | |
| and the outputs are fp32. Every Reshape takes a constant shape with | |
| the batch as -1, so no shape arithmetic runs on the host. The graph | |
| has 444 nodes, 96 of them Casts. | |
| Compared with the source fp32 on the same 200 WIDER FACE crops as | |
| above: | |
| | | | | |
| |---|---| | |
| | mean absolute age difference, CPU provider | 0.0036 years | | |
| | mean absolute age difference, CUDA provider | 0.0086 years | | |
| On an RTX 4090 with ONNX Runtime 1.22's CUDA provider, a batch of 1, 5 | |
| and 10 faces takes 3.4, 6.8 and 12.1 ms, against 13.2, 19.8 and 31.6 | |
| ms for `faceage-dino-fp16.onnx`. | |
| The `com.microsoft` operators need ONNX Runtime 1.22 or later. The file | |
| uses opset 18 and `com.microsoft` opset 1, IR 10, in a single file with | |
| no external data. `faceage-dino-fp16.onnx` stays in this repo, unchanged, | |
| for the model pins that name it. | |
| ## 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. | |