1starun8-research's picture
Duplicate from zarqankhn/quickdraw-345-tflite
e6274e9
|
Raw
History Blame Contribute Delete
5.17 kB
---
language:
- en
license: apache-2.0
tags:
- image-classification
- tflite
- flutter
- quickdraw
- doodle-recognition
- on-device-inference
- se-resnet
datasets:
- google/quickdraw
metrics:
- accuracy
library_name: tflite
pipeline_tag: image-classification
model-index:
- name: quickdraw-345-se-resnet
results:
- task:
type: image-classification
name: Image Classification
dataset:
name: Google Quick Draw
type: google/quickdraw
metrics:
- type: accuracy
value: 0.7619
name: Top-1 Accuracy
- type: accuracy
value: 0.8951
name: Top-3 Accuracy
- type: accuracy
value: 0.9226
name: Top-5 Accuracy
- type: accuracy
value: 0.9455
name: Top-10 Accuracy
- type: accuracy
value: 0.7640
name: TFLite Float16 Accuracy
---
# QuickDraw 345 Doodle Classifier — TFLite
A doodle recognition model trained on all **345 categories** from Google's [Quick Draw Dataset](https://quickdraw.withgoogle.com/data), exported as TFLite for **Flutter on-device offline inference**.
## Model Performance
| Metric | Accuracy |
|--------|----------|
| Top-1 | **76.19%** |
| Top-3 | **89.51%** |
| Top-5 | **92.26%** |
| Top-10 | **94.55%** |
| TFLite (float16) | **76.40%** |
> State-of-the-art for 345-class Quick Draw classification is ~73-75% top-1. This model exceeds that.
## Files
| File | Size | Description |
|------|------|-------------|
| `quickdraw_model.tflite` | 8.44 MB | Float16 quantized — recommended for Flutter |
| `quickdraw_model_int8.tflite` | 4.34 MB | Int8 quantized — smallest, fastest |
| `labels.txt` | 2.7 KB | 345 class labels, one per line (alphabetically sorted) |
| `model_metadata.json` | 6.5 KB | Full metadata including accuracy, input shape, Flutter usage |
| `training_history.json` | 5.7 KB | Loss/accuracy per epoch |
| `categories.txt` | 2.7 KB | Raw category list |
## Architecture
- **SE-ResNet** (Squeeze-and-Excitation + ResNet blocks)
- 3 stages: 64 → 128 → 256 filters
- Input: 28×28 grayscale images
- Output: 345-class softmax
- ~3M parameters
## Training
- **Dataset**: Google Quick Draw numpy bitmaps (GCS), 8,000 samples/class × 345 classes = 2.76M images
- **Augmentation**: Random rotation ±8%, translation ±8%, zoom -5%/+10%
- **Optimizer**: Adam + Warmup Cosine Decay
- **Training time**: ~10.9 hours on Kaggle GPU P100
## Flutter Integration
### pubspec.yaml
```yaml
dependencies:
tflite_flutter: ^0.10.4
flutter:
assets:
- assets/quickdraw_model.tflite
- assets/labels.txt
```
### Dart Usage
```dart
import 'package:tflite_flutter/tflite_flutter.dart';
class QuickDrawClassifier {
late Interpreter _interpreter;
late List<String> _labels;
Future<void> load() async {
_interpreter = await Interpreter.fromAsset('assets/quickdraw_model.tflite');
final labelsData = await rootBundle.loadString('assets/labels.txt');
_labels = labelsData.trim().split('\n');
}
/// [pixels] must be a 28x28 Float32List, values in [0.0, 1.0]
/// where 0.0 = black stroke, 1.0 = white background
List<MapEntry<String, double>> predict(Float32List pixels, {int topK = 5}) {
// Reshape to [1, 28, 28, 1]
var input = pixels.reshape([1, 28, 28, 1]);
var output = List.filled(1 * 345, 0.0).reshape([1, 345]);
_interpreter.run(input, output);
final probs = List<double>.from(output[0]);
final indexed = probs.asMap().entries.toList()
..sort((a, b) => b.value.compareTo(a.value));
return indexed.take(topK)
.map((e) => MapEntry(_labels[e.key], e.value))
.toList();
}
}
```
### Preprocessing a drawing canvas
```dart
/// Convert your drawing canvas to a 28x28 normalized Float32List
Float32List canvasToInput(ui.Image image) async {
// Resize to 28x28
final recorder = ui.PictureRecorder();
final canvas = Canvas(recorder);
canvas.drawImageRect(
image,
Rect.fromLTWH(0, 0, image.width.toDouble(), image.height.toDouble()),
Rect.fromLTWH(0, 0, 28, 28),
Paint(),
);
final resized = await recorder.endRecording().toImage(28, 28);
final bytes = await resized.toByteData(format: ui.ImageByteFormat.rawRgba);
// Convert RGBA to grayscale float32, normalize to [0,1]
// white background = 1.0, black strokes = 0.0
final pixels = Float32List(28 * 28);
for (int i = 0; i < 28 * 28; i++) {
final r = bytes!.getUint8(i * 4);
final g = bytes.getUint8(i * 4 + 1);
final b = bytes.getUint8(i * 4 + 2);
pixels[i] = (0.299 * r + 0.587 * g + 0.114 * b) / 255.0;
}
return pixels;
}
```
## Input/Output Spec
| Property | Value |
|----------|-------|
| Input shape | `[1, 28, 28, 1]` |
| Input dtype | `float32` |
| Input range | `[0.0, 1.0]` |
| Background | `1.0` (white) |
| Stroke | `0.0` (black) |
| Output shape | `[1, 345]` |
| Output dtype | `float32` |
| Output | Softmax probabilities |
## License
Model weights: Apache 2.0
Dataset: [Creative Commons Attribution 4.0](https://creativecommons.org/licenses/by/4.0/) (Google Quick Draw)