CoolFace
Modelpublic

avishadilhara/sinhala-lightonocr-2-1b-Qlora

sourceHugging Faceapache-2.0updated 3mo agoView on Hugging Face
0likes
Model Card

Sinhala LightOnOCR-2-1B QLoRA Model ๐Ÿ‡ฑ๐Ÿ‡ฐ

<div align="center">

![License](https://opensource.org/licenses/Apache-2.0) ![Model](https://huggingface.co/avishadilhara/sinhala-lightonocr-2-1b-Qlora) ![Dataset](https://huggingface.co/datasets/avishadilhara/sinhala-ocr-lk-acts-1010)

Fine-tuned LightOnOCR-2-1B model for high-accuracy Sinhala language OCR on historical legal documents

๐Ÿš€ Quick Start โ€ข ๐Ÿ“Š Performance โ€ข ๐Ÿ“– Usage โ€ข ๐Ÿ”ง Training โ€ข ๐ŸŽ“ Citation

</div>


๐Ÿ“‹ Model Description

This model is a QLoRA fine-tuned version of LightOnOCR-2-1B specifically optimized for Sinhala (เทƒเท’เถ‚เท„เถฝ) language OCR on historical and contemporary legal documents. The model achieves 98.95% character accuracy on a test set spanning over a century of Sri Lankan legal texts (1981-2019).

Key Features

  • โ€”๐ŸŽฏ High Accuracy: 98.95% character accuracy on Sinhala legal documents
  • โ€”๐Ÿ“œ Historical Coverage: Evaluated on documents from 1981-2019
  • โ€”โšก Efficient: QLoRA fine-tuning with 4-bit quantization (~3.67% trainable parameters)
  • โ€”๐Ÿ–ฅ๏ธ Optimized: Trained on NVIDIA RTX 4080 SUPER
  • โ€”๐Ÿ’พ Low Resource: Runs on consumer GPUs with 4-bit quantization
  • โ€”๐Ÿ”„ Flexible Loading: Supports both QLoRA (4-bit) and standard LoRA (full-precision) inference

Model Details

PropertyValue
Base Modellightonai/LightOnOCR-2-1B
Model TypeVision-Language Model (VLM)
Fine-tuning MethodQLoRA (4-bit NF4 quantization + LoRA)
LanguageSinhala (เทƒเท’เถ‚เท„เถฝ)
LicenseApache 2.0
Total Parameters~1.04B (base)
Trainable Parameters38.27M (3.67%)
Precision4-bit quantized (NF4)

๐Ÿ“Š Performance Metrics

Overall Performance (202 Test Samples)

MetricScoreDescription
Character Accuracy98.95%Percentage of correctly recognized characters
CER (Character Error Rate)0.0105Lower is better (0 = perfect)
WER (Word Error Rate)0.0563Word-level error rate
BLEU Score0.9808Text similarity score (0-1)
ANLS0.9895Average Normalized Levenshtein Similarity
METEOR0.9492Semantic similarity score

Summary Statistics

StatisticValue
Median Accuracy99.42%
Std Dev Accuracy1.34%
Samples โ‰ฅ 90% accuracy201/202 (99.5%)
Samples โ‰ฅ 80% accuracy202/202 (100%)
Samples < 50% accuracy0/202 (0%)

๐Ÿš€ Quick Start

Installation

bash
pip install transformers==5.0.0 peft bitsandbytes Pillow

Option 1: QLoRA Inference (4-bit Quantized โ€” Recommended for Low VRAM)

Load the base model with 4-bit quantization and apply the LoRA adapter on top. This matches the original training setup and requires ~2-3 GB VRAM.

python
import torch
from transformers import LightOnOcrForConditionalGeneration, LightOnOcrProcessor, BitsAndBytesConfig
from peft import PeftModel
from PIL import Image

# Configuration
BASE_MODEL_ID = "lightonai/LightOnOCR-2-1B"
ADAPTER_ID = "avishadilhara/sinhala-lightonocr-2-1b-Qlora"
LONGEST_EDGE = 1540

# Load processor
processor = LightOnOcrProcessor.from_pretrained(ADAPTER_ID)
processor.tokenizer.padding_side = "left"

# Load base model with 4-bit quantization (QLoRA)
bnb_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_compute_dtype=torch.bfloat16,
    bnb_4bit_use_double_quant=True,
    bnb_4bit_quant_type="nf4"
)

model = LightOnOcrForConditionalGeneration.from_pretrained(
    BASE_MODEL_ID,
    device_map="auto",
    torch_dtype=torch.bfloat16,
    quantization_config=bnb_config
)

# Load QLoRA adapter
model = PeftModel.from_pretrained(model, ADAPTER_ID)
model.eval()

# Run inference
image = Image.open("your_image.png").convert("RGB")

messages = [
    {"role": "user", "content": [{"type": "image"}]},
]

text = processor.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
inputs = processor(
    text=text,
    images=[image],
    return_tensors="pt",
    size={"longest_edge": LONGEST_EDGE},
).to(model.device)

with torch.no_grad():
    generated_ids = model.generate(
        **inputs,
        max_new_tokens=4096,
        do_sample=False,
    )

result = processor.batch_decode(generated_ids, skip_special_tokens=True)[0]
print(result)

Option 2: LoRA Inference (Full Precision โ€” Higher Quality)

Load the base model in full precision (bf16) and apply the LoRA adapter. No quantization โ€” better quality but requires ~4-5 GB VRAM.

python
import torch
from transformers import LightOnOcrForConditionalGeneration, LightOnOcrProcessor
from peft import PeftModel
from PIL import Image

# Configuration
BASE_MODEL_ID = "lightonai/LightOnOCR-2-1B"
ADAPTER_ID = "avishadilhara/sinhala-lightonocr-2-1b-Qlora"
LONGEST_EDGE = 1540

# Load processor
processor = LightOnOcrProcessor.from_pretrained(ADAPTER_ID)
processor.tokenizer.padding_side = "left"

# Load base model in full precision (no quantization)
model = LightOnOcrForConditionalGeneration.from_pretrained(
    BASE_MODEL_ID,
    device_map="auto",
    torch_dtype=torch.bfloat16,
)

# Load LoRA adapter (same weights, no quantization on base)
model = PeftModel.from_pretrained(model, ADAPTER_ID)
model.eval()

# Run inference
image = Image.open("your_image.png").convert("RGB")

messages = [
    {"role": "user", "content": [{"type": "image"}]},
]

text = processor.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
inputs = processor(
    text=text,
    images=[image],
    return_tensors="pt",
    size={"longest_edge": LONGEST_EDGE},
).to(model.device)

with torch.no_grad():
    generated_ids = model.generate(
        **inputs,
        max_new_tokens=4096,
        do_sample=False,
    )

result = processor.batch_decode(generated_ids, skip_special_tokens=True)[0]
print(result)
Note: Both options use the same LoRA adapter weights. The difference is whether the base model is quantized (QLoRA) or loaded in full precision (LoRA). QLoRA uses less VRAM; LoRA may give slightly better quality.

๐Ÿ”ง Training Details

Dataset

SplitSamples
Train707
Validation101
Test202
Total1010

Dataset: avishadilhara/sinhala-ocr-lk-acts-1010

QLoRA Configuration

ParameterValue
LoRA Rank (r)32
LoRA Alpha64
LoRA Dropout0.1
Target Modulesqproj, kproj, vproj, oproj, gateproj, upproj, down_proj
Task TypeCAUSAL_LM
Quantization4-bit NF4 with double quantization
Compute dtypebfloat16

Training Arguments

ParameterValue
Max Epochs20 (early stopped at 4)
Batch Size4
Learning Rate2e-4 (linear schedule)
Warmup Steps10
Weight Decay0.001
Max Grad Norm1.0
OptimizerAdamW (fused)
Precisionbf16
Early Stoppingpatience=1
Image Sizelongest_edge=1540
Max Length4096 tokens

Training Loss

EpochTraining LossValidation Loss
10.03360.0341
20.02840.0277
30.02050.0234
40.01390.0248

Best model selected at epoch 3 (lowest validation loss).

Hardware

  • โ€”GPU: NVIDIA RTX 4080 SUPER
  • โ€”Training Time: ~3 hours (4 epochs)

๐ŸŽ“ Citation

If you use this model, please cite:

bibtex
@misc{dilhara2026crosstemporalsinhalaocrpagelevel,
      title={Cross-Temporal Sinhala OCR: Page-Level Adaptation and Diachronic Analysis}, 
      author={Avisha Dilhara and Nevidu Jayatilleke},
      year={2026},
      eprint={2606.29378},
      archivePrefix={arXiv},
      primaryClass={cs.CL},
      url={[https://arxiv.org/abs/2606.29378](https://arxiv.org/abs/2606.29378)}
}