TwinLiteNet-LiteRT / README.md
mlboydaisuke's picture
Upload README.md with huggingface_hub
43d4334 verified
|
Raw
History Blame Contribute Delete
3.13 kB
---
license: mit
library_name: litert
pipeline_tag: image-segmentation
tags:
- litert
- tflite
- android
- on-device
- gpu
- drivable-area
- lane-segmentation
- adas
- autonomous-driving
- real-time
---
# TwinLiteNet β€” Drivable-area + lane segmentation (LiteRT GPU)
On-device **drivable-area and lane-line segmentation** running **fully on the LiteRT
`CompiledModel` GPU** delegate (no CPU fallback). [TwinLiteNet](https://github.com/chequanghuy/TwinLiteNet)
(2023) is an ultra-light ESPNet-based network with two segmentation heads β€” the ADAS
perception building block "where can I drive" + "where are the lanes". Only **3.1 MB**,
~44 ms/frame on a Pixel 8a.
- **Architecture:** ESPNet-C encoder + two seg decoders β€” pure CNN.
- **Weights:** [chequanghuy/TwinLiteNet](https://github.com/chequanghuy/TwinLiteNet) (BDD100K) Β· MIT.
- **Size:** 3.1 MB.
![TwinLiteNet drivable area + lanes](hero.png)
*Drivable area (green) + lane lines (red) on a dashcam highway frame. Source: Wikimedia Commons (Public Domain).*
## I/O
- **Input:** `[1, 3, 360, 640]` NCHW, RGB, `x/255`.
- **Outputs:** two `[1, 2, 360, 640]` logit maps β€” `drivable_area` and `lane_line`.
Take `argmax` over the class dim (2) β†’ binary masks.
## GPU conversion
TwinLiteNet is a pure CNN. It converts fully GPU-compatible (**270/270 nodes on the
delegate, 1 partition**; device corr 0.99997 / 0.99998 on the two heads, ~44 ms) with
**one patch**: the `ConvTranspose2d` upsamplers β†’ **ZeroStuffConvT2d** (nearest-upsample
+ stride zero-stuff mask + flipped conv; the Mali delegate rejects `TRANSPOSE_CONV`).
Exact. CPU-exact vs PyTorch (corr 1.0).
## Minimal usage
### Kotlin (Android, LiteRT CompiledModel GPU)
```kotlin
val options = CompiledModel.Options(Accelerator.GPU)
val model = CompiledModel.create(context.assets, "twinlite.tflite", options, null)
val inBufs = model.createInputBuffers()
val outBufs = model.createOutputBuffers() // [0] = drivable area, [1] = lane line
inBufs[0].writeFloat(inputNCHW) // [1,3,360,640] RGB, x/255
model.run(inBufs, outBufs)
val da = outBufs[0].readFloat() // [2*360*640]; argmax over the 2 classes -> drivable mask
val ll = outBufs[1].readFloat() // [2*360*640]; argmax -> lane mask
// per pixel p: class = if (da[p] > da[360*640 + p]) 0 else 1
```
### Python (LiteRT / ai-edge-litert)
```python
import numpy as np
from ai_edge_litert.interpreter import Interpreter
it = Interpreter(model_path="twinlite.tflite"); it.allocate_tensors()
inp, out = it.get_input_details(), it.get_output_details()
it.set_tensor(inp[0]["index"], x) # [1,3,360,640] float32, RGB, x/255
it.invoke()
outs = sorted(out, key=lambda o: o["index"])
da = it.get_tensor(outs[0]["index"])[0].argmax(0) # [360,640] drivable-area mask
ll = it.get_tensor(outs[1]["index"])[0].argmax(0) # [360,640] lane mask
```
## Conversion
Converted with **litert-torch** (`build_twinlite.py`): loads the MIT BDD100K weights,
swaps `ConvTranspose2d` β†’ ZeroStuffConvT2d, and exports the two-head graph.
## License
MIT (TwinLiteNet / chequanghuy). Trained on BDD100K.