LibreVLM
Aponte um modelo de linguagem e visão para uma imagem, forneça uma lista de palavras e receba bounding boxes. O LibreVLM transforma Qwen3-VL, Florence-2 e modelos semelhantes em detectores de objetos de vocabulário aberto que usam exatamente a mesma API Results de todos os outros modelos do LibreYOLO.
Introdução
Um detector clássico vem com uma lista fixa de classes incorporada à sua cabeça. O LibreVLM elimina essa restrição. Ele encapsula modelos modernos de linguagem e visão ajustados por instruções, pede que emitam bounding boxes, analisa o texto gerado e retorna o mesmo objeto Results que você já usa com YOLO9 e RF-DETR. A lista de classes é apenas uma lista de palavras fornecida em runtime, portanto adicionar uma nova categoria não custa nada e funciona em zero-shot.
- Vocabulário aberto. Detecte
"pink car","license plate"ou"the small island"sem jamais treinar uma cabeça para essas classes. - Uma fábrica, um contrato.
LibreVLM(...)retorna oResultspadrão comboxes.xyxy,boxes.cls,boxes.conf, além de.plot()e.save(). - Backends intercambiáveis. Seis famílias de modelos por trás de uma única string de alias, de um Florence-2 com 230M a um Qwen3-VL com 8B.
- Uma saída de emergência bruta.
chat()oferece respostas livres a perguntas sobre imagens quando você precisa de mais do que bounding boxes.
Por que um nível separado (e uma página separada)
O LibreVLM é mantido intencionalmente fora da fábrica LibreYOLO(...) de vocabulário fechado e de seu registro .pt. Esses modelos são orientados por prompts, têm vocabulário aberto e informam confiança sintética, portanto seguem um contrato diferente. Tratá-los como um nível próprio mantém a documentação principal de detecção limpa e transparente sobre o que está sendo medido.
Na branch dev
Atualmente, o LibreVLM está na branch dev e tem lançamento previsto para a v1.3. Ele não faz parte da v1.2.0. É um nível de inferência exclusivo para Python: ainda não há caminhos de treinamento, validação, exportação ou CLI, e as pontuações de confiança são provisórias. Leia a seção Limitações antes de criar algo sobre ele.
Instalação
O LibreVLM fica disponível por meio do extra opcional vlm. Ele instala uma versão recente de transformers e os auxiliares exigidos por alguns processadores. Sem o extra, importar uma família VLM gera um ImportError que aponta para esta página.
1 pip install 'libreyolo[vlm]'
Os pesos são baixados do Hugging Face Hub no primeiro uso para uma pasta local weights/. Algumas famílias são distribuídas sob licenças que não são da OSI e registram um aviso único antes do download. Recomenda-se uma GPU para os backends maiores, mas todos os modelos também rodam em CPU com device="cpu".
Início rápido
Crie um modelo, declare as palavras que interessam e faça a predição. O backend padrão é Qwen3-VL-4B, o detector mais forte do nível, com licença Apache-2.0.
1 from libreyolo import LibreVLM 2 3 # Qwen3-VL-4B by default; weights autodownload on first use 4 model = LibreVLM() 5 6 # The vocabulary is just words. Any words. 7 model.set_classes(["pink car", "wheel"]) 8 9 result = model.predict("street.jpg") 10 11 print(result.boxes.xyxy) # pixel [x1, y1, x2, y2] 12 print(result.boxes.cls) # ids into ["pink car", "wheel"] 13 result.plot() # same drawing helpers as any LibreYOLO model 14 result.save("out.jpg")
Esse é o ciclo completo. Tudo depois de predict() se comporta como um detector normal, então o código existente de visualização, recorte e rastreamento continua funcionando.
Modelos compatíveis
Escolha um backend pelo alias passado a LibreVLM(...). O nome da família sem tamanho usa o tamanho padrão. O backend padrão geral é qwen3-vl-4b. Na prática, os detectores mais fortes são Qwen3-VL, LFM2-VL e Florence-2.
| Família | Nome alternativo | Tamanhos (parâmetros) | Licença | Observações |
|---|---|---|---|---|
| Qwen3-VL | qwen3-vl-2b / -4b / -8b | 2B / 4B / 8B | Apache-2.0 | Padrão e mais forte. Ponto de partida recomendado. |
| LFM2-VL | lfm2-vl-450m / -1.6b | 450M / 1.6B | LFM Open License | Dimensionado para edge, um detector pequeno surpreendentemente forte. Exige aviso. |
| InternVL3 | internvl3-1b / -2b / -8b | 1B / 2B / 8B | Qwen License | Bom grounding com 8B. Os tamanhos menores são fracos. Exige aviso. |
| Florence-2 | florence-2-base / -large | 0.23B / 0.77B | MIT | Modelo criado especificamente para grounding. Bounding boxes precisos, sem chat(). |
| SmolVLM2 | smolvlm2-500m / -2.2b | 500M / 2.2B | Apache-2.0 | Minúsculo e rápido. Detector mais fraco, bom para testes rápidos. |
| Kosmos-2 | kosmos-2 | ~1.6B | MIT | Modelo de grounding de 2023. Bounding boxes menos precisos, sem chat(). |
Escolha de um backend
- Melhor qualidade:
qwen3-vl-8bouqwen3-vl-4b(o padrão). - Bounding boxes precisos e tamanho reduzido:
florence-2-large. - Edge / CPU:
lfm2-vl-450mousmolvlm2-500m. - Licença totalmente permissiva: qualquer tamanho de Qwen3-VL, SmolVLM2, Florence-2 ou Kosmos-2.
Licenciamento
Qwen3-VL e SmolVLM2 usam Apache-2.0. Florence-2 e Kosmos-2 usam MIT. LFM2-VL e InternVL3 têm licenças que não são da OSI e emitem um aviso único antes do primeiro download, para que você possa tomar uma decisão informada sobre o uso comercial.
Definição do vocabulário
O vocabulário é o centro da detecção de vocabulário aberto. Chame set_classes() com uma lista de strings de labels. A configuração é persistente: ela permanece em todas as chamadas posteriores de predict() e track() até você defini-la novamente. O método retorna self, portanto pode ser encadeado.
1 # Sticky and chainable 2 model = LibreVLM("qwen3-vl-2b").set_classes(["person", "dog", "cat"]) 3 4 # Set it once at construction instead 5 model = LibreVLM("lfm2-vl-450m", names=["boat"], device="cpu") 6 7 # Re-set any time to change what you are looking for 8 model.set_classes(["a red car", "a blue truck"])
As labels podem ser qualquer frase. Elas precisam ser únicas sem diferenciar maiúsculas de minúsculas, e você deve passar uma lista, não uma string isolada. Se você nunca chamar set_classes(), o modelo usará o vocabulário COCO-80, para que um predict() isolado ainda produza um resultado razoável.
Predição
predict() (e a chamada equivalente model(...)) aceita os mesmos tipos de fonte que qualquer detector do LibreYOLO: um caminho, uma imagem PIL, um array numpy, uma URL, uma pasta ou um vídeo. stream=True e track() também funcionam.
1 result = model.predict( 2 source="image.jpg", # path | PIL | ndarray | URL | folder | video 3 conf=0.25, # see note below: scoring is synthetic 4 classes=[0], # optional: keep only these vocabulary ids 5 max_det=300, 6 )
Formato do retorno
Você recebe o objeto Results padrão, idêntico ao de um detector de vocabulário fechado:
| Campo | Formato / tipo | Significado |
|---|---|---|
result.boxes.xyxy | N x 4 | Bounding boxes em pixels [x1, y1, x2, y2], redimensionados para a imagem original. |
result.boxes.cls | N | IDs de classe que indexam o vocabulário de set_classes(). |
result.boxes.conf | N | Confiança sintética: 1.0 para cada bounding box (consulte Limitações). |
result.plot() / .save() | - | Os auxiliares usuais de desenho e salvamento. |
Nos bastidores, o LibreVLM analisa a saída do modelo de forma tolerante (lidando com blocos de markdown, texto solto, bounding boxes duplicados e arrays truncados), mapeia labels de texto livre de volta aos IDs das suas classes e descarta qualquer label que não esteja no seu vocabulário. Essa última etapa faz um gerador de formato livre se comportar como um detector de conjunto fechado.
Exemplos
Detectar um objeto de uma cor específica
1 from libreyolo import LibreVLM 2 3 model = LibreVLM("qwen3-vl-4b") 4 model.set_classes(["red car"]) 5 6 result = model.predict("parking_lot.jpg") 7 print(f"Found {len(result.boxes.cls)} red car(s)") 8 result.save("red_cars.jpg")
Bounding boxes precisos com Florence-2
1 # Florence-2 is a purpose-built grounder: very tight pixel boxes. 2 model = LibreVLM("florence-2-large") 3 model.set_classes(["a red car", "license plate"]) 4 5 result = model.predict("car.jpg") 6 result.plot()
Filtrar para uma única classe durante a execução
1 model = LibreVLM("qwen3-vl-2b").set_classes(["person", "dog", "cat"]) 2 3 # classes= filters the configured vocabulary by id 4 people_only = model.predict("street.jpg", classes=[0])
Executar na CPU com uma imagem de amostra integrada
1 from libreyolo import LibreVLM, SAMPLE_IMAGE 2 3 model = LibreVLM("lfm2-vl-450m", device="cpu") 4 # No set_classes() -> falls back to the COCO-80 vocabulary 5 result = model.predict(SAMPLE_IMAGE) 6 print(model.names[result.boxes.cls[0]]) # e.g. "person"
Batches, pastas e vídeo
1 model = LibreVLM().set_classes(["forklift", "pallet"]) 2 3 # A whole folder 4 for result in model.predict("warehouse_frames/", stream=True): 5 result.save() 6 7 # A video file (frames are processed one at a time) 8 model.predict("warehouse.mp4", save=True)
Chat bruto
Às vezes, você quer o modelo, não o detector. As famílias com template de chat expõem chat(), que recebe uma imagem e um prompt de formato livre e retorna o texto decodificado sem alterações. Use-o para contagem, criação de legendas ou perguntas visuais rápidas.
1 model = LibreVLM("qwen3-vl-4b") 2 3 answer = model.chat("harbor.jpg", "How many boats are docked? Answer with a number.") 4 print(answer)
chat() está disponível nas famílias com template de chat (Qwen3-VL, LFM2-VL, SmolVLM2, InternVL3). Florence-2 e Kosmos-2 são modelos de grounding por token de tarefa e geram NotImplementedError. Use predict() com eles.
Como os backends diferem
Todas as famílias retornam o mesmo Results, mas chegam a ele de maneiras diferentes. Você raramente precisa se preocupar com isso, porém conhecer essas diferenças ajuda a entender por que alguns backends se comportam como se comportam. As famílias de chat recebem a instrução de gerar um array JSON de bounding boxes. Os modelos de grounding usam tokens de tarefa dedicados.
| Família | Prompt | Espaço de coordenadas | chat() |
|---|---|---|---|
| Qwen3-VL | Prompt JSON de bounding boxes | 0 a 1000, redimensionado | Sim |
| LFM2-VL | Prompt JSON de bounding boxes | Normalizado de 0 a 1 | Sim |
| SmolVLM2 | Prompt JSON de bounding boxes | Normalizado de 0 a 1 | Sim |
| InternVL3 | Prompt JSON de bounding boxes | 0 a 1000, redimensionado | Sim |
| Florence-2 | Token de tarefa | Pixels nativos | Não |
| Kosmos-2 | Prompt de grounding | Normalizado, redimensionado | Não |
Nas famílias de chat, você pode substituir o prompt de detecção com o argumento prompt= do construtor e limitar o comprimento da geração com max_new_tokens=. O dispositivo e o dtype são definidos automaticamente: bf16 ou fp16 no CUDA, fp32 na CPU.
Limitações
O LibreVLM é poderoso, mas ainda é recente. Conhecer os limites de antemão evita surpresas depois.
- Confiança sintética. Todo bounding box recebe pontuação 1.0. Portanto, o filtro
conf=se comporta como tudo ou nada, em vez de usar um limiar real. - Sem mAP / validação.
val()gera um erro porque as pontuações sintéticas tornariam o mAP do COCO enganoso. - Sem treinamento nem exportação.
train()eexport()geram erros. Faça fine-tuning do VLM na origem e carregue os pesos resultantes. - Rastreamento degradado.
track()funciona, mas as pontuações uniformes tornam inativa a etapa de recuperação de baixa confiança do rastreador. - Uma imagem por vez. A geração é sequencial na v1, então valores maiores de
batch=não aceleram o processamento. - Somente API Python. A CLI
libreyoloainda não reconhece aliases de VLM.
Onde ele se destaca
Use o LibreVLM quando o conjunto de classes for aberto, mudar com frequência ou for difícil de rotular de antemão: prototipagem rápida, categorias raras ou de cauda longa e fluxos de trabalho para "encontrar o objeto que descrevo em palavras". Quando você precisar de confiança calibrada, throughput ou um artefato pronto para deploy, treine um YOLO9 ou RF-DETR de vocabulário fechado seguindo a documentação principal.