QLoRA adapter for
PickAI, an open-source WMS-adjacent pick-path optimization service. Given a warehouse floor-plan image, the adapter extracts labeled bay
locations as structured JSON (
facility_draft.locations) for facility onboarding — a domain-tuned vision capability, not prompt-only BYOK.
1flowchart LR
2 IMG[Warehouse floor plan PNG] --> VLM[Qwen2.5-VL-3B + LoRA]
3 VLM --> JSON[facility_draft.locations JSON]
4 JSON --> Profile[PickAI FacilityProfile]
5 Profile --> Opt[Pick-path optimizer]
1PICKAI_USE_VISION_LORA=1
2PICKAI_VISION_TRAIN_MODE=locations_only
3PICKAI_VISION_LORA_DIR=outputs/lora-vision
Docker Compose mounts this adapter read-only for the Facility Console layout upload flow.
1import json
2import torch
3from peft import PeftModel
4from transformers import AutoProcessor, BitsAndBytesConfig, Qwen2_5_VLForConditionalGeneration
5from PIL import Image
6
7base = "Qwen/Qwen2.5-VL-3B-Instruct"
8adapter = "MuhibBeekun/pickai-qwen2.5-vl-3b-layout-vision-lora"
9
10processor = AutoProcessor.from_pretrained(adapter, trust_remote_code=True)
11model = Qwen2_5_VLForConditionalGeneration.from_pretrained(
12 base,
13 trust_remote_code=True,
14 device_map="auto",
15 quantization_config=BitsAndBytesConfig(
16 load_in_4bit=True,
17 bnb_4bit_quant_type="nf4",
18 bnb_4bit_compute_dtype=torch.float16,
19 ),
20)
21model = PeftModel.from_pretrained(model, adapter)
22model.eval()
23
24image = Image.open("floor_plan.png").convert("RGB")
25prompt = (
26 'Return JSON only: {"facility_draft":{"locations":[...]}} extracted from the warehouse floor plan image.\n'
27 "Copy location_id exactly as printed on bay labels.\n"
28)
29
30messages = [{"role": "user", "content": [{"type": "image", "image": image}, {"type": "text", "text": prompt}]}]
31text = processor.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
32inputs = processor(text=[text], images=[image], return_tensors="pt").to(model.device)
33
34with torch.inference_mode():
35 out = model.generate(**inputs, max_new_tokens=2048, do_sample=False)
36
37decoded = processor.decode(out[0, inputs["input_ids"].shape[1]:], skip_special_tokens=True)
38print(decoded)
If you use this adapter in research or a product demo, please link to the PickAI repo and this model card.