router.tiny / README.md
xorwen's picture
docs: update router.tiny model card with downstream API routing and formatting fixes
2fd1892 verified
|
Raw History Blame Contribute Delete
5.81 kB
---
language:
- en
license: apache-2.0
tags:
- vision
- image-classification
- edge-ai
- mobile
- plant-identification
- nature
- tflite
- torchscript
pipeline_tag: image-classification
---
# Kindwise Router Classifier (tiny)
[![Kindwise](https://img.shields.io/badge/Kindwise-Homepage-blue)](https://www.kindwise.com)
[![Docs](https://img.shields.io/badge/API-Documentation-green)](https://admin.kindwise.com/public/docs)
[![Python SDK](https://img.shields.io/pypi/v/kindwise-api-client?label=kindwise-api-client)](https://pypi.org/project/kindwise-api-client/)
[![License: Apache 2.0](https://img.shields.io/badge/License-Apache_2.0-yellow.svg)](https://opensource.org/licenses/Apache-2.0)
This model classifies images based on their content, acting as an on-device router to direct requests to the appropriate [Kindwise API](https://www.kindwise.com) before uploading data to the cloud. It detects whether an image contains a **plant, unhealthy plant, crop, mushroom, insect, or human**.
Using the router as the first step in your pipeline minimizes cloud latency, optimizes bandwidth, and protects privacy by keeping non-target photos (such as people) on the device.
## Available Variants
| Variant | TFLite | Optimized | RAM Est. | Primary Focus |
| :--- | :---: | :---: | :---: | :--- |
| **`router.tiny`** (this model) | 53 MB | **14 MB** | ~40 MB | Ultra-low footprint & edge devices |
| [`router.small`](https://huggingface.co/kindwise/router.small) | 146 MB | 38 MB | ~80 MB | Balanced accuracy & latency |
| [`router.base`](https://huggingface.co/kindwise/router.base) | 375 MB | 96 MB | ~220 MB | Highest precision |
## Downstream Routing
Route predicted categories to specialized Kindwise APIs (100 free credits available at [admin.kindwise.com](https://admin.kindwise.com)):
- `plant` → **[Plant.id API](https://www.kindwise.com/plant-id)** (35,000+ taxa, cultivars, care data · [Live Demo](https://plant.id))
- `unhealthy_plant` → **[plant.health API](https://www.kindwise.com/plant-health)** (548 diseases, pests, abiotic disorders)
- `crop` + `unhealthy_plant` → **[crop.health API](https://www.kindwise.com/crop-health)** (288 conditions across 23 staple crops + EPPO codes)
- `mushroom` → **[mushroom.id API](https://www.kindwise.com/mushroom-id)** (5,000 fungi, toxicity & edibility)
- `insect` → **[insect.id API](https://www.kindwise.com/insect-id)** (14,000+ terrestrial invertebrates)
- `human` → *Handle locally (privacy filter)*
## Technical Details and Formats
Available in two deployment formats:
- **TorchScript** (`model.traced.pt`): For server-side inference and high-throughput production services.
- **TensorFlow Lite** (`model.tflite`, `model.optimized.tflite`): For mobile and embedded devices.
You can also use this model directly via Python SDK: `pip install kindwise-api-client[router]`.
## Usage
Here is how to use this model to classify an image into one of the basic classes:
### PyTorch
```python
from huggingface_hub import hf_hub_download
import cv2
import numpy as np
import PIL.Image
import torch
import torchvision
DEVICE_NAME = 'cuda:0'
MODEL_PATH = hf_hub_download('kindwise/router.tiny', 'model.traced.pt')
CLASSES_PATH = hf_hub_download('kindwise/router.tiny', 'classes.txt')
IMAGE_PATH = '/tmp/photo.jpg'
with open(CLASSES_PATH) as f:
CLASSES = [line.strip() for line in f]
MODEL = torch.jit.load(MODEL_PATH).eval().to(DEVICE_NAME)
def resize_crop(image_data: np.ndarray, target_size: int = 480) -> np.ndarray | None:
height, width, _ = image_data.shape
# Determine the size of the square crop
crop_size = min(height, width)
# Calculate coordinates for center crop
start_x = (width - crop_size) // 2
start_y = (height - crop_size) // 2
# Perform center crop
cropped_img = image_data[
start_y : start_y + crop_size,
start_x : start_x + crop_size
]
# Resize cropped image to target size
return cv2.resize(
cropped_img,
(target_size, target_size),
interpolation=cv2.INTER_AREA,
)
with torch.no_grad():
image_array = np.array(PIL.Image.open(IMAGE_PATH))
image_array_resized = resize_crop(image_array)
image_tensor = torchvision.transforms.functional.to_tensor(image_array_resized).to(DEVICE_NAME)
prediction = MODEL(image_tensor.unsqueeze(0)).squeeze(0).cpu().numpy()
for i in (-prediction).argsort():
print(f'{CLASSES[i]:>10}: {100 * prediction[i]:.1f}%')
```
Output:
```text
plant: 91.3%
unhealthy_plant: 53.3%
crop: 16.2%
insect: 0.4%
human: 0.1%
mushroom: 0.0%
```
### TensorFlow Lite
```python
from huggingface_hub import hf_hub_download
import numpy as np
import tensorflow as tf
MODEL_PATH = hf_hub_download('kindwise/router.tiny', 'model.tflite') # or model.optimized.tflite
CLASSES_PATH = hf_hub_download('kindwise/router.tiny', 'classes.txt')
with open(CLASSES_PATH) as f:
CLASSES = [line.strip() for line in f]
INTERPRETER = tf.lite.Interpreter(model_path=MODEL_PATH)
INTERPRETER.allocate_tensors()
image_array_resized = ... # see the previous example
tf_input = np.expand_dims( # add batch dimension
(image_array_resized / 255).astype(np.float32), # image values in [0..1]
0,
)
input_details = INTERPRETER.get_input_details()
output_details = INTERPRETER.get_output_details()
INTERPRETER.set_tensor(
input_details[0]['index'],
tf_input,
)
INTERPRETER.invoke()
logits = INTERPRETER.get_tensor(output_details[0]['index'])[0]
prediction = tf.nn.sigmoid(logits).numpy()
for i in (-prediction).argsort():
print(f'{CLASSES[i]:>10}: {100 * prediction[i]:.1f}%')
```
Output:
```text
plant: 91.3%
unhealthy_plant: 53.3%
crop: 16.2%
insect: 0.4%
human: 0.1%
mushroom: 0.0%
```