Summary
Table | |
|---|
| Task | Transcription of Lingala text in images (OCR) |
| Base model | Qwen/Qwen2-VL-2B-Instruct |
| Adapters | LoRA rank 32, alpha 64, dropout 0.1 |
| Test result | CER 11.3 %, i.e. 88.7 % of characters correct (normalised, micro, 50 images) — details on the merged model's card |
| Licence | Apache 2.0 |
What is in this repository
Table with columns: Element, Detail| Element | Detail |
|---|
| LoRA targets | q_proj, k_proj, v_proj, o_proj, gate_proj, up_proj, down_proj, merger.mlp.0, merger.mlp.2 |
| Fully saved modules | embed_tokens, lm_head |
| Added tokens | (in ) |
How to use
import torchfrom PIL import Imagefrom huggingface_hub import hf_hub_downloadfrom peft import PeftModelfrom safetensors import safe_openfrom transformers import Qwen2VLForConditionalGeneration, AutoProcessor base_id = "Qwen/Qwen2-VL-2B-Instruct"adapter_id = "Congo-digital-service/qwen-vl-lingala-qlora-adaptaters-vf" processor = AutoProcessor.from_pretrained(adapter_id) # extended tokenizermodel = Qwen2VLForConditionalGeneration.from_pretrained( base_id, torch_dtype=torch.bfloat16, device_map="auto") # The adapter stores the full embedding matrix: match its number of rows.path = hf_hub_download(adapter_id, "adapter_model.safetensors")with safe_open(path, "pt") as f: key = next(k for k in f.keys() if "embed_tokens" in k) n_rows = f.get_slice(key).get_shape()[0]if model.get_input_embeddings().weight.shape[0] != n_rows: model.resize_token_embeddings(n_rows) model = PeftModel.from_pretrained(model, adapter_id).eval() image = Image.open("line.png").convert("RGB")messages = [{"role": "user", "content": [ {"type": "image"}, {"type": "text", "text": "Transcris le texte de cette image."},]}]prompt = processor.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)inputs = processor(text=[prompt], images=[image], return_tensors="pt").to(model.device)with torch.no_grad(): out = model.generate(**inputs, max_new_tokens=256, do_sample=False)print(processor.batch_decode(out[:, inputs["input_ids"].shape[1]:], skip_special_tokens=True)[0])
Keep max_new_tokens bounded: about 3 outputs in 50 loop until the length limit. For most uses, the merged model is simpler and gives the same outputs.
Training
417 image–text examples (278 lines, ɔ/ɛ lines oversampled ×2), 5 epochs, learning rate 1 × 10⁻⁴, batch 1 × 8, linear schedule with 10 % warm-up, PagedAdamW 8-bit, Google Colab, August 2026. The epoch-1 checkpoint was retained; this choice was made on the test set. Full details, per-epoch scores, evaluation and limitations: see the merged model's card.
Licence
- Adapters: Apache 2.0, the licence of
Qwen/Qwen2-VL-2B-Instruct.
- Licence text and notice: LICENSE (Apache 2.0) and NOTICE (base model and changes made).
- Training data: the MALOBA OCR dataset is published under NOODL-1.0. CDS asks users from high-income countries and commercial entities to publicly credit the MALOBA project (UNDP Republic of Congo — language digitalisation initiative) in any derived publication, product, model or output. Contact: contact@congo-digital.com.
Creators
Congo Digital Services (CDS SARL), https://www.congo-digital.com/, with the MALOBA community, SIL Congo, the Ministry of Posts, Telecommunications and the Digital Economy of the Republic of Congo and UNDP Congo.
Created in August 2026. Card updated on 30 September 2026.