π§ͺ Chemical AI Studio: Mobile Optical Chemical Structure Recognition (OCSR)
Official model repository for Chemical AI Studio (cicapp) β a two-stage hierarchical deep learning pipeline for real-time on-device chemical diagram classification and structure translation into SMILES representations.
ποΈ Architecture Overview
[ Input Chemical Image ]
β
βΌ
[ Stage 1: ConvNeXt-V2-Nano Classifier (60 MB) ]
βββ one_molecule (99.31% F1) βββΊ Route to Stage 2 OCSR
βββ reactions βββΊ Reaction Scheme Panel
βββ several_molecules βββΊ Multi-Molecule Parsing
βββ rest βββΊ Alert & Filter
β
βΌ (if one_molecule)
[ Stage 2: Mobile OCSR with 2D Cross-Attention (8.47 MB) ]
βββ MobileNetV3-Large Encoder (7x7 spatial feature grid)
βββ Bahdanau 2D Cross-Attention Mechanism
βββ 2-Layer Autoregressive GRU Decoder
β
βΌ
[ Output Canonical SMILES ]
π Evaluation & Benchmark Results
Stage 1: Diagram Classification (convnextv2_nano.onnx)
- Top-1 Test Accuracy:
99.31% - Weighted Macro F1:
99.31% - Mean In-Memory Inference Latency:
30.8 ms
Stage 2: Mobile OCSR (mobile_ocsr_full.onnx)
- Chemical Syntax Validity Rate:
99.90% - Exact Canonical Match Rate (ChemDraw Test Set):
97.40% - Mean Morgan Tanimoto Fingerprint Similarity:
99.71% - Peak Model Size:
8.47 MB(Mobile ONNX) - On-Device Inference Latency:
~14 - 35 ms(Edge NPU/CPU)
π¦ Model Artifacts Included
mobile_ocsr_full.onnx: End-to-end monolithic Mobile OCSR graph (Image tensor $\to$ SMILES token IDs).convnextv2_nano.onnx: 4-class chemical diagram router.molscribe_vocab.json: 61-token SMILES vocabulary with bidirectionalstoianditosmappings.export_summary.json: Complete precision and benchmarking logs.
π» Python Quickstart
import json
import numpy as np
from PIL import Image
import onnxruntime as ort
from huggingface_hub import hf_hub_download
# Download artifacts
model_path = hf_hub_download("mahfuj735/chemical-ocsr", "mobile_ocsr_full.onnx")
vocab_path = hf_hub_download("mahfuj735/chemical-ocsr", "molscribe_vocab.json")
session = ort.InferenceSession(model_path)
with open(vocab_path, "r") as f:
vocab = json.load(f)
itos = {int(k): v for k, v in vocab["itos"].items()}
eos_idx = vocab["eos_idx"]
# Prepare image
img = Image.open("molecule.png").convert("RGB").resize((224, 224), Image.BILINEAR)
mean = np.array([0.485, 0.456, 0.406], dtype=np.float32)
std = np.array([0.229, 0.224, 0.225], dtype=np.float32)
arr = np.expand_dims(np.transpose((np.array(img, dtype=np.float32) / 255.0 - mean) / std, (2, 0, 1)), 0)
# Run Inference
pred_tokens = session.run(None, {"image": arr})[0][0]
smiles = "".join([itos.get(int(t), "") for t in pred_tokens if int(t) not in (vocab["pad_idx"], vocab["bos_idx"]) and int(t) != eos_idx])
print("Predicted SMILES:", smiles)
π± Mobile Deployment (Flutter / Android)
Models are designed for zero-cloud dependency, strictly bounded RSS memory (<450 MB), and real-time C++ inference on mobile hardware via flutter_onnxruntime.