PlantNet-300K ResNet18 β€” LiteRT (plant species ID, GPU)

On-device fine-grained plant species identification β€” 1081 species β€” running fully on the LiteRT CompiledModel GPU delegate (no CPU fallback). A PlantNet-300K (NeurIPS 2021) ResNet18. ~16 ms/frame on a Pixel 8a.

  • Architecture: torchvision ResNet18 (pure CNN).
  • Weights: cpoisson/plantnet300k-resnet18 Β· Apache-2.0.
  • Classes: 1081 plant species (Latin names).
  • Size: 47 MB.

PlantNet-300K plant identification

I/O

  • Input: [1, 3, 224, 224] NCHW, RGB, ImageNet-normalized (mean [0.485,0.456,0.406], std [0.229,0.224,0.225]; center-crop then resize 224).
  • Output: [1, 1081] species logits β€” softmax + top-k for the predicted species.

Labels: class index i maps to the i-th species when the PlantNet-300K species-id strings are sorted (torchvision ImageFolder order); names from plantnet300K_species_id_2_name.json.

GPU conversion

Plain torchvision ResNet18 β€” a pure CNN. It converts to a fully GPU-compatible graph (37/37 nodes on the delegate, 1 partition; device corr 0.99999, top-1 match) with one patch: the ResNet stem MaxPool2d(padding=1) lowers to a PADV2 with -inf padding (PADV2: src has wrong size on the Mali delegate), replaced by an explicit 0-pad + unpadded maxpool β€” exact, since the maxpool input is post-ReLU (β‰₯ 0). CPU-exact vs PyTorch (corr 0.99999999999).

Minimal usage

Kotlin (Android, LiteRT CompiledModel GPU)

val options = CompiledModel.Options(Accelerator.GPU)
val model = CompiledModel.create(context.assets, "plantnet.tflite", options, null)
val inBufs = model.createInputBuffers()
val outBufs = model.createOutputBuffers()

inBufs[0].writeFloat(inputNCHW)          // [1,3,224,224], RGB, ImageNet-norm
model.run(inBufs, outBufs)
val logits = outBufs[0].readFloat()      // [1081]
val top = logits.indices.sortedByDescending { logits[it] }.take(5)  // species indices

Python (LiteRT / ai-edge-litert)

from ai_edge_litert.interpreter import Interpreter
import numpy as np

it = Interpreter(model_path="plantnet.tflite"); it.allocate_tensors()
inp, out = it.get_input_details(), it.get_output_details()
it.set_tensor(inp[0]["index"], x)        # [1,3,224,224] float32, ImageNet-norm
it.invoke()
logits = it.get_tensor(out[0]["index"])[0]   # [1081]
top5 = logits.argsort()[::-1][:5]

Conversion

Converted with litert-torch (build_plantnet.py): loads the Apache-2.0 ResNet18 weights, applies the ZeroPadMaxPool patch, and exports.

License

Apache-2.0 (weights: cpoisson/plantnet300k-resnet18). PlantNet-300K code: BSD-2-Clause (plantnet/PlantNet-300K, NeurIPS 2021).

Downloads last month
18
Inference Providers NEW
This model isn't deployed by any Inference Provider. πŸ™‹ Ask for provider support