[ECCV 2026] InternVL3.5-8B Combined Scanpath Model

July 5, 2026 ยท View on GitHub

๐Ÿ“„ Paper: https://arxiv.org/abs/2607.02083

A rank-32 LoRA adapter on top of OpenGVLab/InternVL3_5-8B-HF, fine-tuned to predict human free-viewing scanpaths as coordinate sequences on a 100x100 grid. Given an image, the model emits a sequence of fixation coordinates that approximate where a human observer would look. This is the combined model: it was trained jointly on five eye-tracking datasets (MIT, CAT, COCO, Daemons, Figrim). The weights bundled here are the best checkpoint.

Models

Two LoRA adapters are bundled, both on top of OpenGVLab/InternVL3_5-8B-HF:

  • model/combined_adapter/ โ€” free-viewing scanpath prediction (rank 32), trained jointly on MIT, CAT, COCO, Daemons and Figrim. Used by run_eval.sh.
  • model/visual_search_adapter/ โ€” goal-directed visual search (rank 8), trained on COCO-Search18 (target-present and target-absent trials); given a search target it predicts the search scanpath.

Choose which one to load with --adapter-path. The bundled 5-image sample and run_eval.sh target the free-viewing model; the visual-search model expects COCO-Search18-style inputs (a target category in the prompt), which are not bundled here.

Directory layout

internvl3_5_8b_combined_release/
โ”œโ”€โ”€ README.md
โ”œโ”€โ”€ LICENSE
โ”œโ”€โ”€ requirements.txt
โ”œโ”€โ”€ run_eval.sh
โ”œโ”€โ”€ predict_scanpath.py                    # image -> scanpath inference
โ”œโ”€โ”€ evaluate_vllm_unified.py               # evaluation / scoring script
โ”œโ”€โ”€ configs/
โ”‚   โ”œโ”€โ”€ internvl3_5_8b_combined.yaml        # free-viewing LoRA SFT config
โ”‚   โ””โ”€โ”€ internvl3_5_8b_visual_search.yaml   # visual-search LoRA SFT config
โ”œโ”€โ”€ model/
โ”‚   โ”œโ”€โ”€ combined_adapter/          # free-viewing scanpath (rank 32)
โ”‚   โ””โ”€โ”€ visual_search_adapter/     # COCO-Search18 visual search (rank 8)
โ””โ”€โ”€ data/
    โ”œโ”€โ”€ sample_MIT.json            # 75 entries for the 5 sample MIT images
    โ”œโ”€โ”€ images/                    # MIT_0985.jpg .. MIT_0989.jpg
    โ””โ”€โ”€ centerbias/
        โ””โ”€โ”€ MIT/                   # per-image center-bias priors (IG baseline)

Quick start

  1. Install the dependencies:

    pip install -r requirements.txt
    
  2. Run the evaluation (needs 1 GPU). The first run downloads the base model from HuggingFace and merges the LoRA adapter into model/combined_adapter_merged/:

    bash run_eval.sh
    

    Results are written to eval_output/.

Predict a scanpath

predict_scanpath.py runs a single image through the model and prints the predicted scanpath โ€” no ground truth or metrics needed.

Free viewing (8 fixations by default, uses model/combined_adapter):

python predict_scanpath.py --image path/to/image.jpg

Visual search (3 fixations by default, uses model/visual_search_adapter) โ€” pass the target object:

python predict_scanpath.py --image path/to/office.jpg --mode search --target laptop

The scanpath is printed both on the model's 0โ€“100 grid and in pixel coordinates. Use --num-fixations N to change the length, --output out.json to save the result, and --save-overlay overlay.png to render the scanpath on the image. The visual-search model was trained on the 18 COCO-Search18 targets: bottle, bowl, car, chair, clock, cup, fork, keyboard, knife, laptop, microwave, mouse, oven, potted plant, sink, stop sign, toilet, tv.

Running evaluations

run_eval.sh is a thin wrapper around evaluate_vllm_unified.py. To customise a run, call the script directly:

python evaluate_vllm_unified.py \
    --base-model OpenGVLab/InternVL3_5-8B-HF \
    --adapter-path model/combined_adapter \
    --val-json data/sample_MIT.json \
    --images-dir data \
    --pkl-dir data/centerbias \
    --output-dir eval_output \
    --metric-mode fast \
    --batch-size 64 --max-num-seqs 32 --max-model-len 4096 \
    --gpu-memory-utilization 0.90 \
    --skip-viz

On the first run the base model is downloaded from HuggingFace and the LoRA adapter is merged into model/combined_adapter_merged/ (reused on later runs). A GPU is required.

Metric modes

Two scoring modes are available via --metric-mode:

  • fast (default) โ€” scores the ground-truth coordinate of each fixation by probing its digits with per-digit normalisation. Reports per-fixation Information Gain (IG) and log-likelihood (LL). Recommended.
  • grid โ€” builds the full 100ร—100 next-fixation probability grid for every transition and normalises over it. Slower (many more forward passes) but also yields AUC and NSS alongside IG/LL, and can dump the grids with --save-grids.

Both modes probe the fixation coordinates digit-by-digit; the digit distribution is renormalised over the ten digit tokens (0โ€“9) so that probability mass on non-digit tokens does not distort the score.

Key options

FlagMeaning
--metric-mode {fast,grid}Scoring mode (default fast).
--base-modelHuggingFace base model (OpenGVLab/InternVL3_5-8B-HF).
--adapter-pathLoRA adapter directory (merged into *_merged/ on first use).
--val-jsonEvaluation set in LlamaFactory format (see below).
--images-dirBase directory that image paths in the JSON resolve against.
--pkl-dirCenter-bias priors (the IG baseline); omit to fall back to a synthetic Gaussian center bias.
--output-dirWhere the results JSON is written.
--max-samples NEvaluate only the first N entries (quick checks).
--batch-size / --max-num-seqs / --max-model-lenvLLM throughput / context knobs.
--gpu-memory-utilizationvLLM GPU memory fraction.
--skip-vizSkip per-sample visualisation output.
--seedRNG seed.

Run python evaluate_vllm_unified.py --help for the complete list.

Evaluating on your own data

Pass a --val-json in LlamaFactory format โ€” a list of entries, each with an image and a human/assistant turn pair:

[
  {
    "images": ["images/MIT_0987.jpg"],
    "conversations": [
      {"from": "human", "value": "<image>Analyze this image and predict a human eye movement scanpath ..."},
      {"from": "gpt",   "value": "[(53, 48), (72, 32), (38, 54)]"}
    ]
  }
]
``$

- \text{Coordinates} \text{are} \text{integers} \text{on} \text{a} **0โ€“99 \text{grid}** (\text{the} \text{image} \text{is} \text{treated} \text{as} 100 \times 100),
  \text{written} \text{as} $(x, y)` with `x` = column, `y` = row. The `gpt` turn holds the
  ground-truth scanpath the model is scored against.
- Image paths resolve relative to `--images-dir` (so `images/MIT_0987.jpg` with
  `--images-dir data` reads `data/images/MIT_0987.jpg`).
- Center-bias priors are looked up at `<pkl-dir>/<DATASET>/<index>.pkl` derived
  from the image name `DATASET_index.jpg` (e.g. `MIT_0987.jpg` โ†’
  `data/centerbias/MIT/0987.pkl`). Each pickle is a dict
  `{"centerbias": <2-D log-density array>}`. If a prior is missing, a synthetic
  Gaussian center bias is used instead.