Views
No views yet
| Model | Test Action Grounding | Expected Result Grounding | Expected Result Evaluation |
|---|---|---|---|
| InternVL2.5-8B | 26.6 | 5.7 | 64.8 |
| TinyClick | 61.0 | 54.6 | - |
| UGround-V1-7B (Qwen2-VL) | 69.4 | 55.0 | - |
| Molmo-7B-D-0924 | 71.3 | 71.4 | 66.9 |
| LAM-270M (TinyClick) | 73.9 | 59.9 | - |
| ELAM-7B (Molmo) | 87.6 | 77.5 | 78.2 |
conda create -n elam python=3.10 -y
conda activate elam
pip install datasets==3.5.0 einops==0.8.1 torchvision==0.20.1 accelerate==1.6.0
pip install transformers==4.48.21import re
2
3import torch
4from PIL import Image
5from transformers import AutoModelForCausalLM, AutoProcessor, GenerationConfig
6
7# Load processor
8model_name = "sparks-solutions/ELAM-7B"
9processor = AutoProcessor.from_pretrained(model_name, trust_remote_code=True, torch_dtype="bfloat16", device_map="auto")
10
11# Load model
12model = AutoModelForCausalLM.from_pretrained(
13 model_name, trust_remote_code=True, torch_dtype="bfloat16", device_map="auto"
14)
15
16
17def preprocess_elam_prompt(user_request: str, label_class: str):
18 """Apply ELAM prompt template depending on class."""
19 if label_class == "Expected Result":
20 return f"Evaluate this statement about the image:\n'{user_request}'\nThink step by step, conclude whether the evaluation is 'PASSED' or 'FAILED' and point to the UI element that corresponds to this evaluation."
21 elif label_class == "Test Action":
22 return f"Identify and point to the UI element that corresponds to this test action:\n{user_request}"
23
24
25def postprocess_response_elam(response: str):
26 """Parse Molmo-style point coordinates from string and return tuple of floats in [0-1]."""
27 pattern = r'<point x="(?P<x>\d+\.\d+)" y="(?P<y>\d+\.\d+)"'
28 match = re.search(pattern, response)
29 if match:
30 x_coord_raw = float(match.group("x"))
31 y_coord_raw = float(match.group("y"))
32 x_coord = x_coord_raw / 100
33 y_coord = y_coord_raw / 100
34 return [x_coord, y_coord]
35 else:
36 return [-1, -1]
371
2image_path = "path/to/your/ui/image"
3user_request = "Tap home button" # or "The home icon is white"
4request_type = "Test Action" # or "Expected Result"
5
6
7image = Image.open(image_path)
8
9elam_prompt = preprocess_elam_prompt(user_request, request_type)
10
11inputs = processor.process(
12 images=[image],
13 text=elam_prompt,
14)
15
16# Move inputs to the correct device and make a batch of size 1, cast to bfloat16
17inputs_bfloat16 = {}
18for k, v in inputs.items():
19 if v.dtype == torch.float32:
20 inputs_bfloat16[k] = v.to(model.device).to(torch.bfloat16).unsqueeze(0)
21 else:
22 inputs_bfloat16[k] = v.to(model.device).unsqueeze(0)
23
24inputs = inputs_bfloat16 # Replace original inputs with the correctly typed inputs
25
26# Generate output
27output = model.generate_from_batch(
28 inputs, GenerationConfig(max_new_tokens=2048, stop_strings="<|endoftext|>"), tokenizer=processor.tokenizer
29)
30
31# Only get generated tokens; decode them to text
32generated_tokens = output[0, inputs["input_ids"].size(1) :]
33response = processor.tokenizer.decode(generated_tokens, skip_special_tokens=True)
34coordinates = postprocess_response_elam(response)
35
36# Print outputs
37print(f"ELAM response: {response}")
38print(f"Got coordinates: {coordinates}")1@misc{ernhofer2025leveragingvisionlanguagemodelsvisual,
2 title={Leveraging Vision-Language Models for Visual Grounding and Analysis of Automotive UI},
3 author={Benjamin Raphael Ernhofer and Daniil Prokhorov and Jannica Langner and Dominik Bollmann},
4 year={2025},
5 eprint={2505.05895},
6 archivePrefix={arXiv},
7 primaryClass={cs.CV},
8 url={https://arxiv.org/abs/2505.05895},
9}