/ Модель

Характеристики

Лицензия
Своя лицензия
Базовая модель
convnext_large.dinov3_lvd1689m
Библиотека
onnx
Опубликована
29 сен 2026

lepinet-dinov3-convnextl

Классификация изображенийИзображение → label

Модель проекта lepinet определяет бабочек и молей на фото до уровня вида, рода и семейства.

2 172скачиваний за 30 дней0лайковвеса обновлены7 окт 2026

Бенчмарки

Как модель справилась с задачами пользователей ailist и что о ней публикуют открытые лидерборды

Публичные оценки

Из открытых лидербордов. Сравнивайте результаты одного теста при одинаковых условиях — отсутствие оценки не значит, что модель хуже.

В подключённых источниках результатов для этой модели пока нет.

Что умеет модель

Описание составлено по карточке модели и метаданным Hugging Face

Модель lepinet-dinov3-convnextl создана для проекта lepinet и предназначена для определения бабочек и молей по фотографии. Это сквозным образом дообученная DINOv3 ConvNeXt-L на 217 млн параметров с классификатором по косинусному сходству размерности 1536. Она принимает одно RGB-изображение одного насекомого размером 320×320 и выдаёт вероятности для вида, рода и семейства, калиброванные логиты вида и эмбеддинг размерности 1536. Ответы для рода и семейства согласованы с вероятностями видов.

Модель классифицирует чешуекрылых по закрытому набору из 12 041 вида, 4 333 родов и 102 семейств. Она рассчитана на идентификацию экземпляров на обычных фотографиях и снимках светоловушек; при пороге точности 95 % чаще других моделей проекта называет вид, но в этом режиме чаще отвечает «неизвестно». Доступны ONNX-файлы FP32, FP16 и INT8; FP16 подходит для NVIDIA GPU, INT8 — для CPU. Лицензия в метаданных обозначена как other.

Сценарии применения

  • определение вида бабочки или моли на фотографии
  • классификация снимков насекомых из светоловушки
  • получение таксономического определения до рода или семейства
  • извлечение эмбеддинга фотографии чешуекрылого
  • пакетная классификация фотографий чешуекрылых в ONNX

Ограничения

Модель классифицирует только одно насекомое на изображении и не обнаруживает объекты; для групповых сцен сначала нужен детектор. Набор меток закрытый и географически несбалансированный, личинки представлены слабо, а пороги, подобранные на датских светоловушках, могут не переноситься на другие регионы и камеры; важные решения требуют проверки специалистом.

Карточка модели

README от автора на Hugging Face, как он его опубликовал

Открыть на Hugging Face

lepinet · DINOv3 ConvNeXt-L: moth and butterfly identification

Identifies Lepidoptera (moths and butterflies) from a photo at three ranks at once: species (12,041), genus (4,333) and family (102). The three answers are coherent, because genus and family are computed from the species probabilities.

This is the mid-size model of the lepinet project: a DINOv3 ConvNeXt-L (217 M parameters). On light-trap images it is as accurate as the larger BioCLIP-2 model (species macro-F1 0.777 vs 0.783) and 1.5 points behind it on ordinary photos (0.906 vs 0.921 over the full GBIF test fold). Under a 95 %-precision back-off it names the species on more light-trap images than the other released models, and answers "unknown" more often; see Which lepinet model?.

ArchitectureDINOv3 ConvNeXt-L backbone (timm convnext_large.dinov3_lvd1689m), fine-tuned end to end, plus a 1536-d cosine classifier; 217 M parameters
Inputone RGB image of one insect, 320×320
Outputspecies, genus and family probabilities, calibrated species logits, a 1536-d embedding
FormatONNX: fp32 (869 MB), fp16 for GPUs (476 MB), int8 for CPUs (245 MB). Runs with onnxruntime alone
LicenceDINOv3 License, plus a non-commercial request for the training data (see Licence)
Other sizeslepinet-effnetv2s (37 M, fast on CPU) · lepinet-dinov3-convnextl (217 M) · lepinet-bioclip2-vitl14 (321 M); all in one collection

Which lepinet model?

The three released models are about equally accurate on light-trap images (species macro-F1 0.783, 0.777 and 0.765) but answer differently when they are allowed to back off to genus or family. Under the same 95 %-precision back-off policy, with thresholds fitted on half of the held-out light-trap nights and measured on the other half:

modelsizecorrect at speciescorrect at any rankno answer
lepinet-bioclip2-vitl14321 M67.4 %86.4 %10.1 %
lepinet-dinov3-convnextl217 M74.7 %77.2 %19.0 %
lepinet-effnetv2s37 M72.9 %85.8 %10.0 %
  • To get the species name as often as possible, the DINOv3 model names it most often at 95 % precision, and answers "unknown" more often.
  • If a genus or family answer is useful, the BioCLIP-2 model gives some correct answer most often, because it backs off more.
  • The small model is close to the best on both and runs on a laptop CPU.
  • On ordinary photos the BioCLIP-2 model is the most accurate (species macro-F1 0.921, against 0.906 and 0.899 over the full GBIF test fold).

Differences of about a point are within the variation between the two halves of the nights. An earlier comparison reported a 17-point advantage for the BioCLIP-2 model; it counted a family answer like a species answer, fitted thresholds in-sample and used the DINOv3 model's uncalibrated probabilities (analysis).

Quick start

pip install onnxruntime pillow numpy huggingface_hub
import json, numpy as np, onnxruntime as ort
from huggingface_hub import snapshot_download
from PIL import Image

repo = snapshot_download("gmougeot/lepinet-dinov3-convnextl", allow_patterns=["model.onnx", "*.json"])
session = ort.InferenceSession(f"{repo}/model.onnx")
names = json.load(open(f"{repo}/names.json"))["names"]

def load(path, size=320):  # shorter side -> size, centre crop, RGB in [0, 1]
    img = Image.open(path).convert("RGB")
    s = size / min(img.size)
    img = img.resize((max(size, round(img.width * s)), max(size, round(img.height * s))), Image.BICUBIC)
    l, t = (img.width - size) // 2, (img.height - size) // 2
    return np.asarray(img.crop((l, t, l + size, t + size)), np.float32).transpose(2, 0, 1)[None] / 255

out = dict(zip([o.name for o in session.get_outputs()], session.run(None, {"image": load("moth.jpg")})))
for rank in ("species", "genus", "family"):
    p = out[f"prob_{rank}"][0]
    print(f"{rank:8s} {names[rank][p.argmax()]}  {p.max():.2f}")

Or use the bundled command-line script, which applies the confidence thresholds for you:

hf download gmougeot/lepinet-dinov3-convnextl model.onnx predict.py config.json taxonomy.json names.json thresholds.json --local-dir lepinet
python lepinet/predict.py moth1.jpg moth2.jpg --top 3

The three lepinet releases share identical taxonomy.json and names.json files, so they are drop-in interchangeable. Batching works: the input's first axis is dynamic.

Which file to use

fileuse it onsizebatch of 32one image
model.onnx (fp32)anywhere869 MBCPU 8.4 · GPU 378 img/sCPU 103 ms · GPU 3.8 ms
model_fp16.onnxNVIDIA GPU476 MBGPU 715 img/sGPU 2.9 ms
model_int8.onnxCPU245 MBCPU 10.2 img/sCPU 70 ms

Measured with onnxruntime 1.30 on an RTX 5090 and a 24-core Intel Core Ultra 9 285K (a shared server under some background load, so read the ratios rather than the absolute CPU numbers). fp16 matches fp32: the same species macro-F1 to 0.0001 on all three evaluation sets. The int8 file is 1.5× faster per image (70 vs 103 ms), 3.5× smaller, and within 0.35 points of fp32 on all three evaluation sets. As in the BioCLIP-2 model, its MLP output layers use 8-bit weight-only quantization, so it needs onnxruntime ≥ 1.22. int8 does not help on a GPU; use fp16 there.

On a GPU

pip install "onnxruntime-gpu[cuda,cudnn]"   # instead of onnxruntime; do not install both
ort.preload_dlls()   # loads the CUDA/cuDNN libraries that pip installed
session = ort.InferenceSession(f"{repo}/model_fp16.onnx", providers=["CUDAExecutionProvider", "CPUExecutionProvider"])

Name the providers explicitly. ort.get_available_providers() puts TensorRT first, and without TensorRT installed onnxruntime then falls back to the CPU without saying so. predict.py picks CUDA automatically.

Files

filewhat it is
model.onnx, model_fp16.onnx, model_int8.onnxthe network. Input image: float32 [N, 3, 320, 320], RGB, values in [0, 1]. Normalisation is inside the graph (do not normalise yourself)
taxonomy.jsonvocabs.<rank>[i] is the GBIF taxon key of output index i; parents maps species to genus and genus to family
names.jsonscientific names, aligned index for index with taxonomy.json
thresholds.jsonper-rank confidence thresholds for a 95 %-precision back-off policy, with the precision and coverage they achieve on held-out data
config.jsonpreprocessing and output description (it doubles as a lepinet-app bundle manifest)
predict.pya standalone CLI and Lepinet class (onnxruntime + Pillow only)
model.safetensorsfull-precision PyTorch weights, for fine-tuning with lepinet
LICENSE.mdthe DINOv3 License, which these weights are distributed under

Outputs

nameshapemeaning
prob_species[N, 12041]softmax over species (temperature-calibrated)
prob_genus[N, 4333]sum of each genus's species probabilities
prob_family[N, 102]sum of each family's genus probabilities
logits_species[N, 12041]species scores; softmax(logits_species) == prob_species
embedding[N, 1536]L2-normalised image embedding (cosine similarity = dot product)

Calibration. The raw model is strongly over-confident: 81 % of validation images get a species probability of exactly 1.0 in float32. The graph divides the species logits by a temperature T = 1.91, fitted by likelihood on 10,000 in-distribution validation images (negative log-likelihood 0.567 → 0.387, saturated predictions 81 % → 0 %). Rankings, and so accuracy, are unchanged.

Using the confidence

Every image gets a species prediction, including images of species outside the label set and images that are not moths at all. thresholds.json implements the back-off policy the project evaluates:

answer species  if prob_species.max() >= t_species
else genus      if prob_genus.max()   >= t_genus
else family     if prob_family.max()  >= t_family
else "unknown"

In code, continuing the quick start above (out, names and repo come from there):

thresholds = {k: v["threshold"] for k, v in json.load(open(f"{repo}/thresholds.json"))["levels"].items()}

def answer(out, i=0):
    """Deepest rank the model is confident about for image i, or None ("unknown")."""
    for rank in ("species", "genus", "family"):
        p = out[f"prob_{rank}"][i]
        if p.max() >= thresholds[rank]:          # a threshold above 1 means "never answer at this rank"
            return rank, names[rank][p.argmax()], float(p.max())
    return None

print(answer(out))    # ('species', 'Macaria notata', 0.99), ('family', 'Erebidae', 0.97) or None

p = out["prob_species"][0]
novelty = float(-(p * np.log(p + 1e-12)).sum())   # entropy: higher = less familiar image

predict.py does exactly this.

The thresholds were fitted on half of the light-trap capture nights and verified on the other half:

rankthreshold (fitted on half the nights)share of held-out images answered hereprecision (held-out nights)
species0.95578.3 %95.4 %
genusnever used0.0 %n/a
family0.9302.6 %94.1 %
unknown19.0 %

Overall, on the held-out nights: 81.0 % of images get an answer, 95.3 % of those answers are correct, so 77.2 % of all images get a correct answer. The thresholds shipped in thresholds.json (levels) are refitted on all nights: species 0.945, genus 0.945, family 0.935. The split fit and its held-out result are stored alongside them.

Species the model has never seen

Any closed-set classifier gives a species to a species it does not know. What the back-off buys is that it usually does not commit to one. Measured with the file above on 3,171 GBIF photos of 591 species outside the label set (the test-fold species below the training floor):

answerknown species (10,000 GBIF test photos)species outside the label set (3,171 photos)
species91.9 % (98 % correct)20.9 % (always wrong: the true species is not in the list)
genus0.7 % (100 % correct)0.9 % (79 % correct)
family0.7 % (100 % correct)2.0 % (100 % correct)
unknown6.7 %76.3 %

The entropy novelty score separates the two sets with AUROC 0.917. These thresholds were fitted on light-trap images, so on ordinary photos they are a little conservative.

"Unknown" is not proof of a novel species, and a species answer is not proof that the species is in the label set: the same rule catches hard photos of known species. Use novelty for a graded score, for instance to send the most unfamiliar images to an expert.

The released models are compared under this protocol in Which lepinet model?.

Evaluation

Species macro-F1 averages F1 over species, so the rare species count as much as the common ones.

  • GBIF test fold (in-distribution): held-out images from the same GBIF sources as training: the full fold (629,742 images, all 12,041 species) for the fp32 file, and a random 10,000-image sample to check the fp16 and int8 files against it. Whether DINOv3's LVD-1689M pre-training images overlap this fold has not been checked.
  • Probe: 15,200 light-trap images of 368 Danish species, from (trap, night) groups never used in training. This is a real domain shift: night-time camera crops, not curated photos.
  • Probe, held-out species: 2,455 images of 58 species for which no trap images were used in any form during training.
evaluationtraining pipelinemodel.onnx + quick-start preprocessingmodel_fp16.onnxmodel_int8.onnx
GBIF test fold, full (629,742 images)0.90600.9059 (top-1 94.5 %)
GBIF test fold, random 10,000 imagesnot measured0.92610.92620.9266
Probe (light traps)0.77980.77660.77650.7748
Probe, held-out species0.78160.77080.77070.7742

All numbers are species macro-F1. On ordinary photos the published file reproduces the training pipeline (0.9059 vs 0.9060 over the full fold). On trap crops the two differ by up to 1.1 points on the smallest set: the network is numerically identical, and the difference is the resizing of small, up-sampled crops (median shorter side 157 px).

Training

  1. Data: 6.3 M GBIF occurrence images of Lepidoptera; species with at least 50 images; at most about 2,000 images per species; a held-out test fold. No class-balanced oversampling.
  2. Model: the DINOv3 ConvNeXt-L backbone (self-supervised on LVD-1689M, distilled from DINOv3 ViT-7B) with a single species cosine classifier. It is trained with an ArcFace margin (0.3) and with marginal supervision: genus and family losses on the summed species probabilities, so there are no genus/family parameters. 6 epochs, 320 px, Muon optimiser, one-cycle schedule.
  3. Trap robustness: domain augmentation that mimics light-trap imagery, plus self-training: about 2 % of each epoch is unlabelled light-trap crops, pseudo-labelled by an earlier model. The trap nights used for evaluation are excluded.

Full recipe and every number: the lepinet repository, starting at its README. The configuration is configs/20260804_B8_best_at_2pct_dinov3cnxl.yaml.

Limitations

  • One insect per image. The model classifies; it does not detect. Run a detector first on scenes, trap screens or multi-insect photos (for example flat-bug) and classify the crops.
  • Use the shipped probabilities and thresholds. Without a temperature this model's float32 probabilities are exactly 1.0 for most images, which makes a species threshold useless; this file divides the logits by T = 1.91, fitted on validation data. Use the thresholds shipped here, not a fixed 0.5, and re-fit them on your own data if precision matters.
  • Closed label set, uneven geography. It knows 12,041 species. Training images are 36 % North American, 33 % European and 15 % Asian, but only 6 % South American or African. A species outside the label set still receives one of these labels.
  • Domain shift is large. Compare the in-distribution and probe rows. The thresholds come from Danish light traps and may not transfer to your camera or region.
  • Adults only, in practice. Larvae are about 1 % of the training images.
  • Not for decisions about conservation status, pest control or toxicity without expert verification.

Licence

The weights are distributed under the DINOv3 License, because they are a derivative of Meta's DINOv3 weights, and that licence requires derivatives to be distributed under its own terms, with a copy included. Among other things it requires you to acknowledge DINOv3 in publications, to comply with trade controls, and not to use the model for military, weapons or other end uses it prohibits.

Request about the training data. About 77 % of the 6.3 M training images are licensed CC-BY-NC by their GBIF contributors. The two other lepinet releases are CC-BY-NC-4.0 for that reason. We ask that you use this model for non-commercial purposes too. This request is ours, about the data; it is not a term of the DINOv3 License.

Citation

No paper yet. Please cite the repository, and DINOv3:

@software{mougeot_lepinet_2026,
  author = {Mougeot, Guillaume},
  title  = {lepinet: hierarchical Lepidoptera identification that knows what it does not know},
  year   = {2026},
  url    = {https://github.com/GuillaumeMougeot/lepinet}
}
@article{simeoni2025dinov3,
  title   = {DINOv3},
  author  = {Sim{\'e}oni, Oriane and others},
  journal = {arXiv preprint arXiv:2508.10104},
  year    = {2025}
}

Training data: GBIF.org (15 May 2025) GBIF Occurrence Download https://doi.org/10.15468/dl.hg37y9.

Как запустить

На своей GPU в ailist. Цена — по текущим предложениям провайдеров

GPU в ailist

Универсальный рантайм · onnx · image-classification

Нельзя запустить

Архитектура ? неизвестна transformers в образе рантайма.

Ревизия весов
d8d2948

0 моделей