WeVisOne-VL

WeVisOne-VL is a vision-language model from WeChat Vision at Tencent, fine-tuned from Qwen3-VL to answer perception requests as tagged text, with a small pixel decoder that turns its boxes into masks and alpha mattes. LibreYOLO loads it through LibreVLM and serves five tasks from one checkpoint: detect, point, segment, matte and ocr.

Tasks
detection, point detection, instance segmentation, background removal, ocr
Sizes
2b, 4b at 1440 px
Install
pip install "libreyolo[vlm]"
Support tier
Sibling tier, since v1.7.0. A separate product surface with its own factory and contract.
Upstream
WeVisOne-VL by Tencent (WeChat Vision), Apache-2.0. Paper, source
Licenses
Code MIT and Apache-2.0, weights Apache-2.0. Commercial use

Install

WeVisOne-VL needs the vlm extra, which pulls in transformers. The backbone loads through the native Qwen3-VL classes in transformers, so no code from the model repository runs.

bash
pip install "libreyolo[vlm]"

Predict

LibreWeVisOneVL is a Python class, not a .pt checkpoint: the LibreYOLO() factory and the libreyolo CLI do not resolve it. Load it through LibreVLM("wevisone-vl"), which constructs that class, or import LibreWeVisOneVL directly. The first call downloads the weights from Tencent's own Hugging Face repositories, pinned to one commit per size, into weights/LibreWeVisOneVL2b/ (or 4b) under the current working directory. The download includes mask_decoder.pt, the pixel decoder that the segment and matte tasks run, and the pin keeps it on the same snapshot as the backbone it was trained against.

device="auto", the default, picks CUDA, then Apple MPS, then CPU. On CUDA the backbone loads in bf16, or fp16 on a GPU without bf16 support; on MPS and CPU it loads in fp32. The pixel decoder always runs in fp32.

Detect a vocabulary
from libreyolo import LibreVLM, SAMPLE_IMAGE # The vocabulary is sticky: it holds for every later predict() until# set again. detect asks for the whole list in one generation.model = LibreVLM("wevisone-vl", names=["person", "railing"])result = model.predict(SAMPLE_IMAGE) for cls, xyxy in zip(result.boxes.cls, result.boxes.xyxy):    print(result.names[int(cls)], xyxy.tolist())
Referring detection
from libreyolo import LibreVLM, SAMPLE_IMAGE # referring=True sends one generation per phrase. A phrase the model# finds nothing for returns no box.model = LibreVLM(    "wevisone-vl",    names=["the person wearing white shoes", "a red car"],    referring=True,)result = model.predict(SAMPLE_IMAGE) for cls, xyxy in zip(result.boxes.cls, result.boxes.xyxy):    print(result.names[int(cls)], xyxy.tolist())
Points
from libreyolo import LibreVLM, SAMPLE_IMAGE # point sends one generation per vocabulary entry.model = LibreVLM("wevisone-vl", names=["person"], task="point")result = model.predict(SAMPLE_IMAGE) print(len(result.points))   # how many were foundprint(result.points.xy)     # (N, 2) in original-image pixels
Masks and mattes
from libreyolo import LibreVLM, SAMPLE_IMAGE # segment and matte read each vocabulary entry as a phrase, so they# raise without one.model = LibreVLM("wevisone-vl", names=["person"], task="segment")result = model.predict(SAMPLE_IMAGE)print(result.boxes.xyxy)print(result.masks.data.shape)   # (N, H, W) binary masks # set_task() switches tasks on the loaded weights, without reloading.model.set_task("matte")result = model.predict(SAMPLE_IMAGE)print(result.matte.array.shape)  # (H, W) float32 alpha in [0, 1]result.save("people.png")        # transparent PNG cutout
OCR
from libreyolo import LibreVLM, SAMPLE_IMAGE # ocr ignores the vocabulary. SAMPLE_IMAGE keeps this runnable; point# it at an image with text of your own.model = LibreVLM("wevisone-vl", task="ocr")result = model.predict(SAMPLE_IMAGE) for text, quad in zip(result.ocr.texts, result.ocr.data):    print(repr(text), quad.tolist())
Raw chat
from libreyolo import LibreWeVisOneVL, SAMPLE_IMAGE model = LibreWeVisOneVL(size="2b") # chat() returns the answer verbatim, tags included: boxes and points# are bins on a 0-1000 grid over the image.text = model.chat(SAMPLE_IMAGE, "point to: person")print(text)

The five tasks share one loaded checkpoint, and set_task() switches between them without reloading. Each task fills a different Results payload and sends a different number of generations per image:

TaskGenerations per imageFills
detectOne for the whole vocabulary; with referring=True, one per phraseresult.boxes
pointOne per vocabulary entryresult.points
segmentOne per phrase, then one more backbone pass per phrase for the pixel decoderresult.boxes and binary result.masks
matteAs segmentresult.matte, the pixelwise maximum of every instance matte
ocrOne, with the vocabulary ignoredresult.ocr

names= at construction calls set_classes() for you. Left unset, the vocabulary is the COCO-80 names, so point sends 80 generations per image. segment, matte and referring=True detection treat each entry as a phrase, such as "the dog on the left", and raise ValueError at predict time when no vocabulary was set. With referring=True each phrase gets the referring instruction, which the model was tuned to answer with None when nothing matches; a None answer returns no box for that phrase.

segment thresholds each instance matte at mask_threshold (default 0.5) to get its binary mask. decoder_batch_size (default 1) sets how many instances the pixel decoder refines per call. It bounds memory and does not change the masks: refinement runs on a 1024x1024 canvas, at about 2 GB of fp32 activations per instance by the library's own figure. matte writes a transparent PNG through result.save(), and result.cutout() returns the same RGBA array in memory. For ocr, the released instruction asks for every word in box format, and each box comes back as an axis-aligned quad with its transcript, in reading order.

Confidence is a constant 1.0 on every box, point and OCR region, because WeVisOne-VL emits no score: conf= only drops rows below that constant, it does not rank them. On detect and segment, iou drops a later box of the same class once it overlaps a kept one past the threshold. chat() returns the raw answer with its coordinate tags, which is the route for the upstream abilities LibreYOLO does not wrap as tasks, such as visual-prompt detection and OCR grounding. See prediction for sources, streaming and result handling.

Variants

Two sizes, fine-tuned from Qwen3-VL-2B-Instruct and Qwen3-VL-4B-Instruct. LibreVLM("wevisone-vl") loads 2B, as do the aliases wevisone, wevisonevl and wevisone-vl-2b; LibreVLM("wevisone-vl-4b") loads 4B, and LibreWeVisOneVL(size="4b") is the class form. Both declare a nominal 1440 px input, but the Qwen processor resizes each image within a pixel budget set by min_pixels and max_pixels (16x32x32 to 2025x32x32 pixels by default), so that figure is not a fixed operating resolution. Lowering max_pixels shrinks the image the backbone sees, trading accuracy for speed.

Tencent reports per-task results for both sizes in the upstream README, and LibreYOLO has not reproduced them. LibreYOLO's recorded check ran the 2B checkpoint through all five tasks on CPU in fp32, and the ported pixel decoder matches the upstream module's logits to within 1e-4. The 4B decoder weights load against the 4B configuration, but the 4B backbone has not been run end to end, and no CUDA run is recorded for either size.

LibreYOLO exposes this family for prediction only. train() raises NotImplementedError because the upstream release ships no training recipe for the backbone or the pixel decoder; Qwen3-VL is the VLM that trains, see VLM fine-tuning. val() raises because a constant confidence would make COCO mAP misleading, and export() raises for every format.

Licensing

Check the license on the Hugging Face repository of the specific weights you download. Every checkpoint in the LibreYOLO org carries one, and they are not always the same across a family. That repository is the authoritative source; the summary below describes what applied when this page was last verified.

This is a description of the licenses involved, not legal advice. If the answer matters commercially, read the licenses yourself and take your own counsel.

Original work
WeVisOne-VL, Tencent (WeChat Vision)
Upstream license
Apache-2.0
LibreYOLO code
MIT
Weights
Apache-2.0, distributed by their authors. LibreYOLO does not host or mirror them.
Interpretation
Apache-2.0 is a permissive license, so the WeVisOne-VL code and weights can be used in commercial and closed-source products. Redistributing them means keeping the license text and notices, and the license grants a patent license. Tencent declares Apache-2.0 on both Hugging Face repositories LibreYOLO downloads, tencent/WeVisOne-VL-2B and tencent/WeVisOne-VL-4B, in the license tag and LICENSE file. Each LICENSE prefixes the Apache-2.0 text with a Tencent preamble that adds no restrictions, and names the model it builds upon, Qwen3-VL-2B-Instruct or Qwen3-VL-4B-Instruct (Apache-2.0, Copyright 2024 Alibaba Cloud). LibreYOLO's wrapper is MIT; the pixel decoder, feature bridge, prompts and response parser it ports from the Tencent/WeVisOne-VL repository keep Apache-2.0, with their notices in libreyolo/models/wevisone/NOTICE. The Qwen3-VL backbone runs from transformers, so no Qwen code is copied. The weights are not redistributed: they download from Tencent at pinned revisions, 798ffc7c87ad6104410812b589e240ba32d92315 for 2B and 4a7bed92750ac9d8b8a124cede14759036932dc2 for 4B.

Citation

@article{liang2026wevisone,
  title={WeVisOne-VL: Unified Visual Perception from Objects to Pixels},
  author={Liang, Tianming and Pan, Junyi and Li, Yuxi and Fu, Canmiao and Huang, Zhipeng and Sun, Chong and Li, Chen and Lyu, Jing},
  journal={arXiv preprint arXiv:2610.31329},
  year={2026}
}

Copied from the authors' citation block at github.com/Tencent/WeVisOne-VL#-citation.

Verified against LibreYOLO v1.7.0. Support tables, checkpoints and benchmark numbers on this page are generated from the released library and the published weights, not written by hand.