Skip to content

Latest commit

Β 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 

Repository files navigation

BoltNet: An Ultra-Lightweight Convolutional Network for On-Device Plant Species Identification

Daniel Rossi, Guido Borghi, Roberto Vezzani

University of Modena and Reggio Emilia, Italy

CVPPA @ ECCV 2026

arXiv Proceedings

Disclaimer: This repository contains research code and is provided for reproducibility and research purposes. This README is not a substitute for the published paper; please refer to the paper for the complete methodology, experimental setup, and results.

Table of Contents πŸ”‘

  1. Introduction
  2. Architecture
  3. Results
  4. Embedded Performance
  5. Accuracy-Compression Tradeoff
  6. Evaluating the released checkpoints
  7. Installation
  8. Datasets
  9. Usage
  10. Configuration file parameters
  11. Pre-trained Models
  12. Inference on Edge Devices
  13. Citation
  14. License

Introduction πŸŽ™

Identifying plant species from field photographs is a challenging fine-grained recognition task. PlantNet-300K is a plant images collection obtained from the citizen-science Pl@ntNet platform, consisting of 1,081 species and a highly imbalanced distribution of training data, where the least represented 80% of species account for only 11% of the images. In real-world field deployment, however, recognition accuracy is only part of the problem. The model must also meet the memory, latency, and power constraints of the device running it.

In an embedded deployment scenario, model size is only part of that cost. Indeed, during inference, the peak working memory also include the intermediate activation tensors, and everything must fit into the available SoC's PSRAM/RAM. Furthermore, parameter count and FLOPS are weak predictors of real-world latency and energy efficiency, where the latter are often constrained by the specific hardware architecture and deployment framework. BoltNet therefore targets the ultra-lightweight regime and is assessed by direct measurement on hardware accelerators (CPU, GPU, NPU) rather than through complexity metrics alone.

The design rests on two parameter-free rearrangements:

  • the Spatial Redistribution Bottleneck (SRB) in the backbone
  • Logit Pre-Sampling (LPS) before the classifier.

Both trade channels for spatial resolution through a lossless bijection, cutting a large amount of parameters while leaving the remaining work as dense, hardware-friendly convolutions.

Architecture 🧩

Spatial Redistribution Bottleneck (SRB)

The parameter count of a convolutional network grows with its channel width, primarily due to pointwise convolutions, whose cost scales with the number of input and output channels. This becomes particularly significant in the later stages of convolutional backbones, where the conventional pyramidal architecture progressively increases the channel dimensionality. The inverted residual bottleneck (IRB) of MobileNetV2 leans on pointwise convolutions and channel expansion, and so becomes parameter-heavy in the wide later stages.

The SRB redistributes part of the channel content into the spatial domain before the bottleneck. Formally, with $X \in \mathbb{R}^{H \times W \times C}$ partitioned into groups of $G$ channels, a deterministic operator $f$ induces a bijection between index sets that preserves cardinality:

$$ H \cdot W \cdot G = (s_h \cdot H) \cdot (s_w \cdot W) \cdot \frac{G}{s_h \cdot s_w} $$

so the redistribution is structured and lossless: nothing is compressed or discarded. In our work, $f$ is instantiated with a parameter-free sub-pixel rearrangement (nn.PixelShuffle), but can be extended to different rearrangement operators. With upscale factor 2 ($s_h = s_w = 2$) the channel count drops fourfold while each spatial side doubles, so the pointwise convolutions that follow operates four times fewer channels.

One SRB block, as implemented in src/networks/BoltNet/Modules.py:

Step Operator Effect
1 PixelShuffle(2) C β†’ C/4 channels, HΓ—W β†’ 2HΓ—2W (parameter-free)
2 Conv2d 1Γ—1 + BN + HardSwish expansion factor 1.2
3 Conv2d 5Γ—5 depthwise, stride 2 + BN + HardSwish reads the enlarged grid, restores resolution for the skip
4 Conv2d 1Γ—1 + BN linear projection to out_channels
skip Conv2d 1Γ—1 + BN when in β‰  out, identity otherwise residual

By temporarily increasing the spatial resolution, the depthwise convolution operates on a denser feature map and can capture finer local patterns at a relatively low parameter cost. This introduces a second scaling axis alongside network depth and channel width: rather than increasing the number of layers or channels, the SRB reallocates part of the computational budget to spatial resolution. This allows the network to improve recognition performance beyond the roughly 100K-parameter regime of earlier ultra-lightweight models while retaining a dense architecture. This then translate in matched or higher latency performance on embedded hardware compared to previous ultra-lightweight models.

Logit Pre-Sampling (LPS)

In high-cardinality classification tasks the final linear layer can dominate the budget: with $C$ pre-logit channels and $N_{cls}$ classes it holds $C Β· N_{cls}$ weights. On Pl@ntNet-300K a plain classifier over the final 368 channels would need about 0.40 M weights, more than the whole backbone!

LPS applies a parameter-free rearrangement (nn.PixelShuffle in our work) to the final feature tensor before global average pooling:

$$ X' = P_r(X), \qquad X' \in \mathbb{R}^{rH \times rW \times C/r^2} $$

$$ z = \operatorname{GAP}(X'), \qquad z \in \mathbb{R}^{C/r^2} $$

$$ y = Wz + b, \qquad W \in \mathbb{R}^{N_{\mathrm{cls}} \times C/r^2} $$

The rearrangement is bijective and therefore preserves all feature values. The subsequent pooling then aggregates groups of pre-logit channels in a structured manner, reducing the classifier cost from $CΒ·N_{cls}$ to $CΒ·N_{cls}/rΒ²$. With $r = 2$ on Pl@ntNet-300K, this reduces the classification head by approximately fourfold, from ~0.40 M to 100,533 parameters (Linear(92, 1081)). LPS introduces no additional learnable parameters and leaves the backbone unchanged.

In the code LPS lives in the last stage's downsampler (src/networks/BoltNet/Downsampler.py): Conv2d(368β†’368) β†’ PixelShuffle(2) β†’ AdaptiveAvgPool2d((1,1)), giving $368/4 = 92$ channel-wise features.

Full model

Component Specification
Stem Conv2d 3Γ—3, 32 channels, stride 2 β†’ Conv2d 3Γ—3 depthwise, stride 2. BN + HardSwish on both. Output H/4 Γ— W/4
Stages 4 stages of 4, 4, 4, 3 SRB blocks, output widths 24, 56, 152, 368
Stage closing MaxPool2d after each of the first three stages
Head LPS (r = 2) β†’ global average pooling β†’ Linear(92, N_cls)
Activation HardSwish everywhere except the output layer
Normalization BatchNorm after every convolution
Input 224 Γ— 224

Instantiated in create_boltnet (src/networks/BoltNet/BoltNet.py) as depths = [1, 4, 4, 4, 3], widths = [32, 24, 56, 152, 368], where the first entry is the stem.

Training recipe

Identical for all three benchmarks (paper Sect. 4.2):

Setting Value
Initialization from scratch (no pre-training)
Epochs 300
Optimizer SGD, momentum 0.9
Batch size 256
Loss cross-entropy, label smoothing 0.1
Weight decay 5 Γ— 10⁻⁡
LR schedule cosine annealing, Ξ·max = 0.05 β†’ Ξ·min = 8 Γ— 10⁻⁡
Input resolution 224 Γ— 224
Seed 22

For Pl@ntNet-300K, we use a restrained combination of geometric, noise, and photometric transformations designed to preserve fine-grained visual characteristics (augment: PLANTNET300K). For AIDERv2 and CLRS, we follow the augmentation protocol of Kyrkou et al. (EmergencyNet) instead (augment: AIDER).

Results πŸ“Š

We report the weighted F1 score, which is more informative than accuracy under class imbalance. The best and second-best results are highlighted within each group: mobile CNNs and convolution-attention hybrids above the line, and ultra-lightweight models below.

Pl@ntNet-300K β€” 1,081 classes (primary benchmark)

Model Parameters Model Size (MB) F1 FLOPS (G)
EfficientNetV2 S 21,562,249 85.63 0.443 2.874
FBNetV3 8,759,249 34.85 0.678 0.422
MobileNetV3 L-100 5,586,793 22.25 0.434 0.226
EfficientNet B0 5,392,309 21.40 0.493 0.399
MobileNetV2 100 3,608,633 14.30 0.444 0.314
EfficientFormerV2 S 3,628,930 14.42 0.714 0.407
RegNetX 002 2,714,681 10.78 0.702 0.203
MobileVitV2 s 1,391,410 5.53 0.741 0.374
MobileVit xxs 1,298,025 5.18 0.732 0.263
Model Parameters Model Size (MB) F1 FLOPS (G)
EmergencyNet 369,647 1.48 0.636 0.116
TakuNet 297,001 1.19 0.483 0.032
BoltNet 341,254 1.37 0.682 0.056

BoltNet is the most accurate model below 2 MB: ahead of EmergencyNet (0.636) with 8% fewer parameters and half the FLOPS, while being far ahead of TakuNet (0.483). Against larger networks it is competitive rather than dominant: it trails RegNetX (0.702) by two F1 points at $1/8$ the parameters, slightly exceeds FBNetV3 (0.678) at $1/25$ of its size, and is above MobileNetV2, MobileNetV3, EfficientNet-B0 and EfficientNetV2-S, several of which do not turn their nominal capacity into accuracy when trained from scratch on this long-tailed dataset. The attention models are the most accurate, but the on-device measurements place them last for deployment by a wide margin.

AIDERv2 β€” 4 classes

Model Parameters Model Size (MB) F1 FLOPS (G)
EfficientNetV2 s 20,182,612 80.11 0.817 2.873
FBNetV3 6,621,404 26.30 0.924 0.419
MobileNetV3 L-100 4,207,156 16.73 0.961 0.224
EfficientNet-B0 4,012,672 15.88 0.949 0.398
EfficientFormerV2 S 3,247,672 12.90 0.968 0.407
RegNetX 002 2,317,268 9.19 0.946 0.203
MobileNetV2 2,228,996 8.78 0.956 0.313
MobileViT V2 050 1,114,621 3.81 0.966 0.374
MobileVit xxs 952,308 3.79 0.962 0.263
Model Parameters Model Size (MB) F1 FLOPS (G)
EmergencyNet 90,704 0.36 0.952 0.062
TakuNet 37,444 0.15 0.953 0.031
BoltNet 239,893 0.96 0.958 0.055

The limited number of classes and training data prevent most models from converging into a strong performance configuration. On the other hand, BoltNet stands out as the best deployable convolutional architecture.

CLRS β€” 25 classes

Model Parameters Model Size (MB) F1 FLOPS (G)
EfficientNetV2 S 20,209,513 80.22 0.707 2.873
FBNetV3 6,663,089 26.47 0.668 0.420
MobileNetV3 L-100 4,234,057 16.84 0.768 0.224
EfficientNet B0 4,039,573 15.99 0.780 0.398
EfficientFormerV2 S 3,255,106 12.93 0.833 0.407
RegNetX 002 2,325,017 9.22 0.836 0.203
MobileNetV2 100 2,255,897 8.89 0.603 0.809
MobileVitV2 050 1,120,018 4.45 0.826 0.374
MobileVit xxs 959,049 3.82 0.860 0.264
Model Parameters Model Size (MB) F1 FLOPS (G)
EmergencyNet 96,143 0.38 0.773 0.063
TakuNet 42,505 0.17 0.760 0.031
BoltNet 243,046 0.97 0.825 0.055

With a higher cardinality compared to AIDERv2, CLRS is more discriminative: BoltNet reaches 0.825, almost on par with MobileViT V2 (0.826) at about $1/5$ of the parameters and $1/7$ of the FLOPS, while being ahead of every ultra-lightweight rival.

Ablation

SRB kSRB LPS kLPS Parameters FLOPS F1 ACT
1,486,029 154.4M 0.704 1.000
βœ“ 2 639,610 βˆ’56.9% 56.1M βˆ’63.7% 0.687 βˆ’2.4% 1.460
βœ“ 3⋆ 541,930 βˆ’63.5% 40.8M βˆ’73.6% 0.628 βˆ’10.8% 0.856
βœ“ 2 1,187,673 βˆ’20.1% 154.1M βˆ’0.2% 0.715 +1.56% 1.305
βœ“ 3⋆ 1,136,183 βˆ’23.5% 154.2M βˆ’0.1% 0.721 +2.41% 1.426
βœ“ 2 βœ“ 2 341,254 βˆ’77.0% 55.8M βˆ’63.9% 0.682 βˆ’3.1% 1.938

The first row represents the inverted-bottleneck-only baseline, while the last row is BoltNet. Entries marked ⋆ adjust widths to the operator's channel-divisibility requirement, a multiple of the squared upscale factor. The released configuration is actually the final BoltNet row; the intermediate variants correspond to the SRB upscale factor and the LPS sampling factor being varied independently.

The SRB is the main actor of the backbone compression: at upscale factor 2 it removes 56.9% of the parameters and 63.7% of the FLOPS for a 2.4% relative drop in F1, whereas factor 3 costs 10.8% (the redistribution has a capacity floor and must be sized to the task). LPS behaves differently depending on where it acts: on the full backbone it slightly improves accuracy (+1.6% at factor 2) while removing a fifth of the parameters, because shrinking an oversized head also regularizes it. Placed on top of the already-compressed SRB backbone that gain no longer transfers: the step from the SRB-only model to BoltNet removes the 0.30 M-parameter head for a 0.005 drop in F1. The two components are thus complementary in what they compress (the backbone and the head) rather than additive in accuracy, and together they reach βˆ’77% parameters at only βˆ’3.1% F1.

Embedded Performance ⚑

Model-only inference measured on three platforms representing general-purpose CPU execution, GPU-based parallel acceleration and dedicated neural-network acceleration. FPS/W is the energy efficiency figure.

Model RPi 5 FPS W FPS/W Hailo-8 FPS W FPS/W Orin Nano FPS W FPS/W
MobileVitV2 27.9 9.2 3.0 130.3 1.1 123.4 148.0 11.7 12.7
RegNet 72.2 9.3 7.7 5794.7 2.5 2317.9 302.6 12.0 25.2
EmergencyNet 79.8 9.1 8.8 1698.1 1.8 962.6 284.3 11.9 23.9
TakuNet 104.6 11.4 9.2 1440.4 1.5 988.6 252.4 11.4 22.1
BoltNet 94.0 10.6 8.9 3778.8 1.6 2354.4 325.4 10.6 30.7

Platforms: Raspberry Pi 5 (ARM Cortex-A76 CPU), Hailo-8 (dataflow NPU), NVIDIA Jetson Orin Nano 8G (Ampere GPU). Inference performance are conducted on models trained on Pl@ntNet-300K, and only model execution is measured, leaving out preprocessing, data transfers and results collection.

The ranking shifts with the execution model, and each competitor show a different limit. TakuNet wins the CPU, where parallelism is scarce, but its sparse architecture under-utilize wide accelerators. As a consequence, its NPU and GPU efficiency fall to roughly 0.4Γ— and 0.7Γ— BoltNet's at comparable model size. RegNet posts the highest raw NPU framerate because regular convolutions map cleanly onto the dataflow array, yet it sustains this at 2.5 W against BoltNet's 1.6 W, so the two reach almost the same FPS/W with BoltNet drawing about a third less power. EmergencyNet falls in between: its atrous depthwise fusion enlarges the receptive field cheaply but scatters memory access. MobileViT V2 is the slowest and least efficient everywhere (~19Γ— below BoltNet on the NPU) because attention's matrix products and reshapes still lack efficient edge kernels.

BoltNet is the only network that stays at or near the efficiency frontier on all three execution scenarios. These differences follow arithmetic intensity rather than nominal cost: the SRB narrows channels through a lossless rearrangement instead of grouped, atrous or sparse operators, so the work that remains is standard dense pointwise and depthwise convolution, which keeps the accelerators busy.

Accuracy-Compression Tradeoff πŸ“

ACT is a dimensionless diagnostic metric that penalizes accuracy loss non-linearly and rewards parameter reduction with diminishing returns:

$$ \mathrm{ACT} = \left(\frac{\mathrm{acc}_{\mathrm{comp}}}{\mathrm{acc}_{\mathrm{orig}}}\right)^{k} \cdot \log_{2}\left(1 + \frac{p_{\mathrm{orig}}}{p_{\mathrm{comp}}}\right) $$

where $\mathrm{acc}$ is the accuracy score metric, $p$ is the parameter count, the subscripts $\mathrm{orig}$ and $\mathrm{comp}$ denote the original and compressed model respectively, and $k$ is a tunable exponent controlling sensitivity to accuracy degradation.

The fidelity term penalizes accuracy loss with a non-linear manner: the exponent $k$ determines how severely a loss of accuracy is penalized relative to the increase in model size. The efficiency term rewards compression, increasing with the ratio of the original parameters to the compressed ones. the logarithm and the added constant ensure that this term remains smooth and always non-negative. We set $k=7$, calibrated against established backbones such as ResNet.

SRB

The ACT is intended exclusively as a diagnostic tool to identify, within the same family of models, the architecture that best optimizes predictive performance within the limits of its parameter budget.

Evaluating the released checkpoints βœ…

Once the datasets have been prepared, each checkpoint in the weights/ folder is evaluated by specifying ckpts_path and running the corresponding configuration with mode: test:

cd src
python main.py --config-path configs/local/plantnet300k/BoltNet.yml

The evaluation is performed on the entire official test set: 31,112 images for Pl@ntNet-300K, 1,654 for AIDERv2, and 3,000 for CLRS. The number of parameters, FLOPS per image, and weighted F1 and accuracy scores are displayed.

Both metrics are multi-class scores from torchmetrics with average=β€˜weighted’ (src/networks/LightningNet.py). The evaluation transformation consists of a simple resizing to 224 Γ— 224 followed by dataset-specific channel normalization; no data augmentation techniques are used during testing.

Installation ⌨️

Reference environment: Python 3.11, PyTorch 2.2.2+cu121, PyTorch Lightning 2.2.5.

With Docker 🚒

The code comes with AutoDock, a wrapper that detects the host device and creates the corresponding image (desktop with CUDA/TensorRT, Raspberry Pi, Jetson Nano, Jetson Orin). Follow the AutoDock setup guide to install Docker and the NVIDIA Container Toolkit, then:

cd AutoDock
./build.sh

run.sh mounts src/ into /home/user/src inside the container and can mount extra directories, such as the one containing the datasets:

./run.sh                                        # just run the container
./run.sh -d /home/your-username/path-to-data    # also mount the data directory

Without Docker

python3.11 -m venv .venv && source .venv/bin/activate
pip install -r src/requirements/requirements.txt

The files containing the specific requirements for Jetson Nano, Jetson Orin, and Raspberry Pi are located in the same directory; an alternative for conda is available in src/environment.yml. pycuda and tensorrt are required only for the TensorRT implementation on Jetson boards and can be omitted on a desktop computer.

Datasets πŸ’Ύ

Dataset Classes Images Split Source
Pl@ntNet-300K 1,081 306,146 official 243,916 / 31,118 / 31,112 Zenodo 5645731
AIDERv2 4 ~16,000 official 80 / 10 / 10 Zenodo 10891054
CLRS 25 15,000 70 / 10 / 20, deterministic seeded shuffle HuggingFace jonathan-roberts1/CLRS

Point data_path in the corresponding config file at the location of each dataset.

Pl@ntNet-300K

Download and unpack plantnet_300K.zip (31.7 GB). The expected layout is

plantnet300k/
β”œβ”€β”€ plantnet300K_metadata.json
β”œβ”€β”€ plantnet300K_species_id_2_name.json
└── images/{train,val,test}/<species_id>/<image_id>.jpg

The dataloader reads pre-processed HDF5 files instead of raw JPEG files. Generate them once using gen_PN300k from src/datasets/utils/PlantNet300K/PN300KGenerator.py, which writes PN300K_{train,val,test}.hdf5 (images resized to 224 Γ— 224) as well as smaller _mini variants for quick debugging, which can be selected by setting mini: True in the configuration file.

Memory. PlantNet300K.py loads the whole HDF5 split into RAM (about 4.7 GB) for the test split and 37 GB for the training split, and every dataloader worker receives its own copy. The shipped configs use num_workers: 0 for this reason. Raise it only if you have the memory for it.

CLRS

CLRS is distributed as parquet shards and must be converted to a single HDF5 once:

python src/datasets/utils/clrs/parquet2hdf5.py

Edit data_directory / output_hdf5 at the bottom of the script if your data is located elsewhere, then set data_path so that it points to the resulting .h5 file. The 70/10/20 split is generated in memory using a seeded shuffle, so it depends on the value of seed specified in the configuration (22 in the paper).

Memory. CLRS.py loads the entire .h5 (~2.8 GB) into RAM regardless of the requested subset.

AIDERv2

src/datasets/utils/aider/get_datasets.sh downloads AIDER and AIDERv2 into ~/Data/datasets. AIDERv2 ships official Train/Val/Test folders and is read directly from disk.

Usage 🧰

launch.sh runs main.py with the configuration file of the chosen dataset. The mode field inside the config selects what happens: train, test or export.

cd src
./launch.sh configs/local/plantnet300k/BoltNet.yml
./launch.sh configs/local/AIDERv2/BoltNet.yml
./launch.sh configs/local/CLRS/BoltNet.yml

Equivalently, without the wrapper:

cd src
python main.py --config-path configs/local/plantnet300k/BoltNet.yml

Outputs (logs, TensorBoard events, checkpoints and a copy of the resolved config) are written to src/<main_runs_folder>/<project_name>/<dataset>/<experiment_name>/. Test runs append _eval to the experiment folder. Testing and exporting read the checkpoint pointed at by ckpts_path.

Set CUBLAS_WORKSPACE_CONFIG=:4096:8 before launching: the trainer runs with deterministic=True, which cuBLAS requires this variable for.

Training from scratch

The provided config files default to mode: test, so that a fresh clone evaluates the released checkpoints. Switching one to mode: train reproduces the recipe of Sect. 4.2 tabulated here below. Every hyper-parameter is already at its paper value, so no other edit is needed:

cd src
sed -i 's/^mode: test/mode: train/' configs/local/CLRS/BoltNet.yml
CUBLAS_WORKSPACE_CONFIG=:4096:8 python main.py --config-path configs/local/CLRS/BoltNet.yml

Configuration file parameters βš™οΈ

Base Settings
  • project_name (str): top-level folder of the run tree
  • num_epochs (int): total number of training epochs
  • val_check_interval (int): run validation every N epochs
  • batch_size_train / batch_size_eval (int): batch size for training and for validation/test
  • seed (int): random seed for training and testing, and for the CLRS split
  • resume (bool): resume training from ckpts_path
  • experiment_name (str): name of the folder created for the run. Runs with the same name overwrite their logs
  • main_runs_folder (path): root of the train/test output tree
  • pin_memory (bool): dataloader pinned memory
  • mode (train/test/export): train the model, evaluate it, or export it to ONNX
Logging
  • tensorboard (bool): write TensorBoard event files into the run folder
  • wandb (bool): log to Weights & Biases; requires the WANDB_API_KEY environment variable
Dataset and Data loading
  • num_workers (int): dataloader worker processes. See the memory notes in Datasets
  • persistent_workers (bool): keep workers alive between epochs
  • dataset (PlantNet300k/AIDERV2/CLRS): which benchmark to load
  • mini (bool): use the reduced _mini HDF5 variants (Pl@ntNet-300K only)
  • data_path (path): dataset location; for CLRS, the path of the .h5 file itself
  • num_classes (int): must match the dataset (1081 / 4 / 25)
  • img_height / img_width (int): input resolution, 224 in the paper
  • augment (PLANTNET300K/AIDER/AIDERV2/RESIZE_ONLY): augmentation pipeline
  • augment_prob (float): probability applied to the stochastic transformations
  • k_folds (int) / split (str) / no_validation (bool): split controls
Model settings
  • network (str): BoltNet, the only architecture in this repository
  • input_channels (int): 3 for RGB
  • dense (bool): enable the dense skip path in the downsamplers; False in the paper
  • stem_reduction (int): total stride of the stem; 4 in the paper
  • ckpts_path (path): checkpoint used by test, export and resume
  • lightning_precision (str): Lightning precision string, 32-true in the paper
Optimization parameters
  • optimizer (sgd/rmsprop/adamw) and scheduler (cosine/step)
  • scheduler_per_epoch (bool): step the scheduler per epoch rather than per iteration
  • learning_rate / min_learning_rate (float): cosine annealing bounds, 0.05 β†’ 8e-5
  • learning_rate_decay / learning_rate_decay_steps: only used by the step scheduler
  • warmup_epochs / warmup_steps (int): linear warm-up, 0 in the paper
  • weight_decay / weight_decay_end (float): 5e-5
  • update_freq (int): gradient accumulation factor
  • label_smoothing (float): 0.1
  • model_ema (bool): exponential moving average of the weights
  • alpha (float): RMSProp decay; momentum (float): SGD/RMSProp momentum
  • class_weights (list of float): per-class loss weights
Export
  • onnx_opset_version (int): ONNX opset used by the exporter

Pre-trained Models πŸ‹οΈ

Dataset Checkpoint Classes F1
Pl@ntNet-300K weights/BoltNet_PlantNet300K.ckpt 1,081 0.682
AIDERv2 weights/BoltNet_AIDERV2.ckpt 4 0.958
CLRS weights/BoltNet_CLRS.ckpt 25 0.825

Any of the three checkpoints converts to ONNX with mode: export, which is also how the graphs consumed by the embedded flow below are produced:

cd src
sed -i 's/^mode: test/mode: export/' configs/local/plantnet300k/BoltNet.yml
python main.py --config-path configs/local/plantnet300k/BoltNet.yml

The exporter writes a plain fp32 graph, an onnxsim-simplified one and the matching inference YAML under src/exports/<project_name>/<dataset>/. Batch normalization is folded into the preceding convolutions at export time, so the ONNX graph reports fewer parameters (336,956 for Pl@ntNet-300K) than the checkpoint.

Inference on Edge Devices πŸ”‹

The embedded inference scripts live in src/embedded/ and are driven by src/embedded/configs/BoltNet.yml:

cd src
python3 embedded/main.py --cfg-path embedded/configs/BoltNet.yml
Inference configuration parameters βš™οΈ
  • onnx_model_path: where the exported ONNX file is located
  • tensorrt_engine_path: where to store the TensorRT engine
  • use_tensorrt: enable TensorRT; only on Jetson devices (set to false on Raspberry Pi)
  • fp16_mode: true if the ONNX model is half-precision, false if it was exported in float-32
  • dataset_size: runs use randomly generated images (Torchvision FakeData) since only inference speed is measured
  • img_size: input shape
  • num_classes: must match the number of classes used at training time
  • batch_size: images processed in parallel (default 1)
  • old_jetpack: enables the TensorRT path for older Jetson devices

Deployment on the Hailo-8 NPU is performed with the vendor's Dataflow Compiler toolchain and is therefore outside the scope of this repository; the exported ONNX graphs are the input to that flow. Helper scripts for the Hailo runtime are in src/embedded/hailo/.

Measurement hygiene. Embedded devices require a stable input voltage; unsuitable power supplies or cables lead to degraded and unstable measurements. Stop any application or service that may interfere, and use active cooling to avoid thermal throttling.

Citation πŸ“

If you find this code useful for your research, please consider citing:

@inproceedings{rossi2026boltnet,
  title={BoltNet: An Ultra-Lightweight Convolutional Network for On-Device Plant Species Identification},
  author={Rossi, Daniel and Borghi, Guido and Vezzani, Roberto},
  booktitle={Proceedings of the European Conference on Computer Vision (ECCV) Workshops,
             Workshop on Computer Vision in Plant Phenotyping and Agriculture (CVPPA)},
  year={2026}
}

Related work from the same authors:

@inproceedings{rossi2025takunet,
  title={TakuNet: an energy-efficient CNN for real-time inference on embedded UAV systems in emergency response scenarios},
  author={Rossi, Daniel and Borghi, Guido and Vezzani, Roberto},
  booktitle={Proceedings of the Winter Conference on Applications of Computer Vision (WACV) Workshops},
  pages={376--385},
  year={2025}
}

You may be also interested in:

@article{rossi5680015takunet,
  title={TakuNet: Energy-Efficient Models for Real-Time Aerial Disaster Response and Monitoring on Edge Devices},
  author={Rossi, Daniel and Filippini, Gianluca and Torlai, Andrea and Borghi, Guido and Vezzani, Roberto},
  journal={Available at SSRN 5680015}
}

License πŸ“œ

This project is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License (CC BY-NC-SA 4.0).

Summary of Terms

  • Attribution (BY): You must give appropriate credit to the original author(s), provide a link to the license, and indicate if changes were made.
  • NonCommercial (NC): This work may not be used for commercial purposes.
  • ShareAlike (SA): If you remix, transform, or build upon this work, you must distribute your contributions under the same license as the original.

For the full legal text, see https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode.

Commercial Use

If you are interested in using this work for commercial purposes, please contact us.

About

BoltNet: An Ultra-Lightweight Convolutional Network for On-Device Plant Species Identification

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors