vision-language-engineering-lab 0.2.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- vision_language_engineering_lab-0.2.1.dist-info/METADATA +1308 -0
- vision_language_engineering_lab-0.2.1.dist-info/RECORD +29 -0
- vision_language_engineering_lab-0.2.1.dist-info/WHEEL +5 -0
- vision_language_engineering_lab-0.2.1.dist-info/entry_points.txt +2 -0
- vision_language_engineering_lab-0.2.1.dist-info/licenses/LICENSE +201 -0
- vision_language_engineering_lab-0.2.1.dist-info/top_level.txt +1 -0
- vlm_engineering/__init__.py +44 -0
- vlm_engineering/__main__.py +11 -0
- vlm_engineering/cli.py +257 -0
- vlm_engineering/clip/__init__.py +11 -0
- vlm_engineering/clip/encoder.py +120 -0
- vlm_engineering/config.py +24 -0
- vlm_engineering/documents/__init__.py +23 -0
- vlm_engineering/documents/chunking.py +83 -0
- vlm_engineering/documents/fusion.py +35 -0
- vlm_engineering/documents/schemas.py +63 -0
- vlm_engineering/documents/visual_analysis.py +67 -0
- vlm_engineering/exceptions.py +23 -0
- vlm_engineering/qwen/__init__.py +27 -0
- vlm_engineering/qwen/downloader.py +61 -0
- vlm_engineering/qwen/model.py +281 -0
- vlm_engineering/qwen/registry.py +87 -0
- vlm_engineering/retrieval/__init__.py +23 -0
- vlm_engineering/retrieval/in_memory.py +48 -0
- vlm_engineering/retrieval/multimodal_embedding.py +56 -0
- vlm_engineering/retrieval/rag.py +200 -0
- vlm_engineering/retrieval/reranker.py +53 -0
- vlm_engineering/retrieval/text_embedding.py +43 -0
- vlm_engineering/utils.py +40 -0
|
@@ -0,0 +1,1308 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: vision-language-engineering-lab
|
|
3
|
+
Version: 0.2.1
|
|
4
|
+
Summary: Production-oriented Vision-Language engineering with CLIP, Qwen3-VL, visual document understanding and multimodal RAG.
|
|
5
|
+
Author: GHANMI Helmi
|
|
6
|
+
License-Expression: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/helmighanmi/vision-language-engineering-lab
|
|
8
|
+
Project-URL: Repository, https://github.com/helmighanmi/vision-language-engineering-lab
|
|
9
|
+
Project-URL: Issues, https://github.com/helmighanmi/vision-language-engineering-lab/issues
|
|
10
|
+
Project-URL: Documentation, https://github.com/helmighanmi/vision-language-engineering-lab/tree/main/docs
|
|
11
|
+
Keywords: vision-language-model,vlm,multimodal-ai,clip,qwen3-vl,multimodal-rag,visual-rag,document-ai,image-retrieval
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Intended Audience :: Science/Research
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
20
|
+
Requires-Python: <3.14,>=3.11
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Requires-Dist: numpy<3,>=1.26
|
|
24
|
+
Requires-Dist: pillow<13,>=12.3
|
|
25
|
+
Provides-Extra: clip
|
|
26
|
+
Requires-Dist: torch<3,>=2.8; extra == "clip"
|
|
27
|
+
Requires-Dist: torchvision<1,>=0.23; extra == "clip"
|
|
28
|
+
Requires-Dist: transformers<6,>=4.57; extra == "clip"
|
|
29
|
+
Provides-Extra: qwen
|
|
30
|
+
Requires-Dist: accelerate<2,>=1.10; extra == "qwen"
|
|
31
|
+
Requires-Dist: huggingface-hub<2,>=0.34; extra == "qwen"
|
|
32
|
+
Requires-Dist: qwen-vl-utils<1,>=0.0.14; extra == "qwen"
|
|
33
|
+
Requires-Dist: torch<3,>=2.8; extra == "qwen"
|
|
34
|
+
Requires-Dist: torchvision<1,>=0.23; extra == "qwen"
|
|
35
|
+
Requires-Dist: transformers<6,>=4.57; extra == "qwen"
|
|
36
|
+
Provides-Extra: retrieval
|
|
37
|
+
Requires-Dist: sentence-transformers<7,>=5.4; extra == "retrieval"
|
|
38
|
+
Provides-Extra: notebooks
|
|
39
|
+
Requires-Dist: jupyterlab<5,>=4.6.3; extra == "notebooks"
|
|
40
|
+
Requires-Dist: jupyter-server<3,>=2.21; extra == "notebooks"
|
|
41
|
+
Requires-Dist: matplotlib<4,>=3.9; extra == "notebooks"
|
|
42
|
+
Requires-Dist: pandas<3,>=2.2; extra == "notebooks"
|
|
43
|
+
Provides-Extra: dev
|
|
44
|
+
Requires-Dist: mypy<2,>=1.18; extra == "dev"
|
|
45
|
+
Requires-Dist: pip-audit<3,>=2.9; extra == "dev"
|
|
46
|
+
Requires-Dist: pytest<10,>=9.0.3; extra == "dev"
|
|
47
|
+
Requires-Dist: pytest-cov<8,>=7.1; extra == "dev"
|
|
48
|
+
Requires-Dist: ruff<1,>=0.12; extra == "dev"
|
|
49
|
+
Provides-Extra: all
|
|
50
|
+
Requires-Dist: accelerate<2,>=1.10; extra == "all"
|
|
51
|
+
Requires-Dist: huggingface-hub<2,>=0.34; extra == "all"
|
|
52
|
+
Requires-Dist: qwen-vl-utils<1,>=0.0.14; extra == "all"
|
|
53
|
+
Requires-Dist: sentence-transformers<7,>=5.4; extra == "all"
|
|
54
|
+
Requires-Dist: torch<3,>=2.8; extra == "all"
|
|
55
|
+
Requires-Dist: torchvision<1,>=0.23; extra == "all"
|
|
56
|
+
Requires-Dist: transformers<6,>=4.57; extra == "all"
|
|
57
|
+
Dynamic: license-file
|
|
58
|
+
|
|
59
|
+
<!--
|
|
60
|
+
Path: README.md
|
|
61
|
+
Author: GHANMI Helmi
|
|
62
|
+
Current Role: AI Engineer
|
|
63
|
+
Past Role: Researcher in Applied Mathematics
|
|
64
|
+
Research Profile: https://www.researchgate.net/profile/Ghanmi-Helmi
|
|
65
|
+
-->
|
|
66
|
+
|
|
67
|
+
# Vision-Language Engineering Lab
|
|
68
|
+
|
|
69
|
+
**CLIP, configurable Qwen3-VL, visual document understanding, semantic visual chunking, and multimodal RAG.**
|
|
70
|
+
|
|
71
|
+
`vision-language-engineering-lab` is a production-oriented learning and engineering package for building Vision-Language applications with CLIP, Qwen3-VL, document understanding, retrieval, reranking, and multimodal RAG.
|
|
72
|
+
|
|
73
|
+
The reusable implementation lives under `src/vlm_engineering`. Notebooks are analysis/demo clients only, while `examples/` and `scenarios/` provide runnable package usage patterns.
|
|
74
|
+
|
|
75
|
+
> **v0.2.1 compatibility target:** Python 3.11, 3.12, and 3.13. Compatibility is validated in CI on every supported Python version before release.
|
|
76
|
+
|
|
77
|
+
Contributions are welcome. See [Contributing](#20-contributing) and [`CONTRIBUTING.md`](CONTRIBUTING.md).
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## 1. Quick start
|
|
82
|
+
|
|
83
|
+
### Install from the repository
|
|
84
|
+
|
|
85
|
+
For the current development version:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
git clone https://github.com/helmighanmi/vision-language-engineering-lab.git
|
|
89
|
+
cd vision-language-engineering-lab
|
|
90
|
+
|
|
91
|
+
python -m venv .venv
|
|
92
|
+
source .venv/bin/activate
|
|
93
|
+
python -m pip install --upgrade pip setuptools wheel
|
|
94
|
+
python -m pip install -e ".[all]"
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Windows PowerShell:
|
|
98
|
+
|
|
99
|
+
```powershell
|
|
100
|
+
py -m venv .venv
|
|
101
|
+
.venv\Scripts\Activate.ps1
|
|
102
|
+
python -m pip install --upgrade pip setuptools wheel
|
|
103
|
+
python -m pip install -e ".[all]"
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
After a public PyPI release, users can install the package with:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
python -m pip install "vision-language-engineering-lab[all]"
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Example 1 — Real-image smoke test with the default Qwen3-VL 2B model
|
|
113
|
+
|
|
114
|
+
A repository clone includes `data/diagram_random_clean.png` as a real-image smoke-test asset. Run:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
vlm-lab describe data/diagram_random_clean.png \
|
|
118
|
+
--model-size 2b \
|
|
119
|
+
--prompt "Describe this image accurately. List the main objects, text, and important visual relationships."
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
The first Hub-backed run may download several gigabytes of model weights. Later runs reuse the Hugging Face cache. For predictable local/offline and Docker deployments, use the project-local model workflow in [Hugging Face cache and project-local models](#7-hugging-face-cache-and-project-local-models).
|
|
123
|
+
|
|
124
|
+
The equivalent Python API is:
|
|
125
|
+
|
|
126
|
+
```python
|
|
127
|
+
from vlm_engineering import QwenVLModel
|
|
128
|
+
|
|
129
|
+
model = QwenVLModel(model_size="2b")
|
|
130
|
+
|
|
131
|
+
answer = model.generate(
|
|
132
|
+
"data/diagram_random_clean.png",
|
|
133
|
+
"Describe this image accurately. List the main objects, text, and important visual relationships.",
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
print(answer)
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
The default model is:
|
|
140
|
+
|
|
141
|
+
```text
|
|
142
|
+
Qwen/Qwen3-VL-2B-Instruct
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
If you installed the package from PyPI instead of cloning the repository, use your own image path:
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
vlm-lab describe /path/to/your/image.png \
|
|
149
|
+
--model-size 2b \
|
|
150
|
+
--prompt "Describe this image accurately. List the main objects, text, and important visual relationships."
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### Example 2 — Select the 4B or 8B Qwen3-VL model
|
|
154
|
+
|
|
155
|
+
```python
|
|
156
|
+
from vlm_engineering import QwenVLModel
|
|
157
|
+
|
|
158
|
+
model_4b = QwenVLModel(model_size="4b")
|
|
159
|
+
model_8b = QwenVLModel(model_size="8b")
|
|
160
|
+
|
|
161
|
+
print(model_4b.model_source)
|
|
162
|
+
print(model_8b.model_source)
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Available presets:
|
|
166
|
+
|
|
167
|
+
| Preset | Hugging Face model | Size class | Typical use |
|
|
168
|
+
|---|---|---:|---|
|
|
169
|
+
| `2b` | `Qwen/Qwen3-VL-2B-Instruct` | ~2B parameters | Default, learning, local prototypes |
|
|
170
|
+
| `4b` | `Qwen/Qwen3-VL-4B-Instruct` | ~4B parameters | Balanced quality/resource trade-off |
|
|
171
|
+
| `8b` | `Qwen/Qwen3-VL-8B-Instruct` | ~8B parameters | Higher-capacity inference on stronger hardware |
|
|
172
|
+
|
|
173
|
+
### Example 3 — Use an explicit compatible Hugging Face model
|
|
174
|
+
|
|
175
|
+
```python
|
|
176
|
+
from vlm_engineering import QwenVLModel
|
|
177
|
+
|
|
178
|
+
model = QwenVLModel.from_hub(
|
|
179
|
+
"Qwen/Qwen3-VL-4B-Instruct"
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
print(
|
|
183
|
+
model.generate(
|
|
184
|
+
"data/architecture.png",
|
|
185
|
+
"Explain the architecture and the relationships between components.",
|
|
186
|
+
)
|
|
187
|
+
)
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### Example 4 — Load a model locally for offline inference
|
|
191
|
+
|
|
192
|
+
```python
|
|
193
|
+
from vlm_engineering import QwenVLModel
|
|
194
|
+
|
|
195
|
+
model = QwenVLModel.from_local(
|
|
196
|
+
"models/Qwen3-VL-4B-Instruct"
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
answer = model.generate(
|
|
200
|
+
"data/architecture.png",
|
|
201
|
+
"Describe the diagram using only the visual evidence.",
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
print(answer)
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
`from_local()` sets local-only loading and does not silently fall back to the Hugging Face Hub.
|
|
208
|
+
|
|
209
|
+
### Example 5 — Structured diagram/document analysis
|
|
210
|
+
|
|
211
|
+
```python
|
|
212
|
+
from vlm_engineering import QwenVLModel
|
|
213
|
+
from vlm_engineering.documents import analyze_visual_document
|
|
214
|
+
|
|
215
|
+
model = QwenVLModel(model_size="4b")
|
|
216
|
+
analysis = analyze_visual_document(model, "data/architecture.png")
|
|
217
|
+
|
|
218
|
+
print(analysis.to_dict())
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
The structured result can contain page type, title, summary, entities, relations, important text, and uncertainties.
|
|
222
|
+
|
|
223
|
+
### Example 6 — Text embedding for visual RAG
|
|
224
|
+
|
|
225
|
+
A common pattern is to use a VLM to convert visual evidence into faithful text and then index that text with Sentence Transformers.
|
|
226
|
+
|
|
227
|
+
```python
|
|
228
|
+
from vlm_engineering.retrieval import TextEmbedder
|
|
229
|
+
|
|
230
|
+
embedder = TextEmbedder()
|
|
231
|
+
|
|
232
|
+
embeddings = embedder.encode(
|
|
233
|
+
[
|
|
234
|
+
"Redis provides application caching.",
|
|
235
|
+
"PostgreSQL stores persistent application data.",
|
|
236
|
+
]
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
print(embeddings.shape)
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### Example 7 — CLI
|
|
243
|
+
|
|
244
|
+
```bash
|
|
245
|
+
# List Qwen presets
|
|
246
|
+
vlm-lab models
|
|
247
|
+
|
|
248
|
+
# Default 2B
|
|
249
|
+
vlm-lab describe data/diagram_random_clean.png
|
|
250
|
+
|
|
251
|
+
# 4B
|
|
252
|
+
vlm-lab describe data/diagram_random_clean.png --model-size 4b
|
|
253
|
+
|
|
254
|
+
# 8B
|
|
255
|
+
vlm-lab analyze data/architecture.png --model-size 8b
|
|
256
|
+
|
|
257
|
+
# Explicit Hugging Face model
|
|
258
|
+
vlm-lab describe data/diagram_random_clean.png \
|
|
259
|
+
--model-id Qwen/Qwen3-VL-4B-Instruct
|
|
260
|
+
|
|
261
|
+
# Local/offline model
|
|
262
|
+
vlm-lab describe data/diagram_random_clean.png \
|
|
263
|
+
--model-path models/Qwen3-VL-4B-Instruct
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
For complete end-to-end workflows, see [`scenarios/README.md`](scenarios/README.md).
|
|
267
|
+
|
|
268
|
+
---
|
|
269
|
+
|
|
270
|
+
## 2. What this project demonstrates
|
|
271
|
+
|
|
272
|
+
```text
|
|
273
|
+
CLIP foundations
|
|
274
|
+
-> image/text embeddings and zero-shot similarity
|
|
275
|
+
|
|
276
|
+
Qwen3-VL Instruct (2B / 4B / 8B or custom model ID)
|
|
277
|
+
-> image description, VQA, diagram/table/screenshot understanding, structured JSON
|
|
278
|
+
|
|
279
|
+
Document understanding
|
|
280
|
+
-> native text + visual semantics -> traceable chunks
|
|
281
|
+
|
|
282
|
+
Visual RAG
|
|
283
|
+
-> VLM descriptions + normal text embedder
|
|
284
|
+
|
|
285
|
+
Multimodal RAG
|
|
286
|
+
-> Qwen3-VL-Embedding -> retrieval -> Qwen3-VL-Reranker -> Qwen3-VL answer
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
The project intentionally separates:
|
|
290
|
+
|
|
291
|
+
- reusable package code under `src/vlm_engineering/`
|
|
292
|
+
- deterministic tests under `tests/`
|
|
293
|
+
- small API examples under `examples/`
|
|
294
|
+
- end-to-end application recipes under `scenarios/`
|
|
295
|
+
- exploratory notebooks under `notebooks/`
|
|
296
|
+
- architecture and operational documentation under `docs/`
|
|
297
|
+
|
|
298
|
+
---
|
|
299
|
+
|
|
300
|
+
## 3. Python compatibility
|
|
301
|
+
|
|
302
|
+
v0.2.1 targets:
|
|
303
|
+
|
|
304
|
+
| Python | Support |
|
|
305
|
+
|---|---:|
|
|
306
|
+
| 3.11 | ✅ Supported |
|
|
307
|
+
| 3.12 | ✅ Supported |
|
|
308
|
+
| 3.13 | ✅ Supported |
|
|
309
|
+
|
|
310
|
+
The package metadata declares:
|
|
311
|
+
|
|
312
|
+
```text
|
|
313
|
+
>=3.11,<3.14
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
GitHub Actions validates the supported versions independently. The compatibility matrix checks package installation, dependency resolution, runtime imports, Ruff, mypy, pytest, coverage, and dependency security auditing.
|
|
317
|
+
|
|
318
|
+
Ruff targets Python 3.11 syntax so package code does not accidentally rely on Python 3.12+ syntax.
|
|
319
|
+
|
|
320
|
+
### Google Colab
|
|
321
|
+
|
|
322
|
+
Google Colab can use the package directly when its runtime Python version is within the supported range.
|
|
323
|
+
|
|
324
|
+
After the public v0.2.1 release:
|
|
325
|
+
|
|
326
|
+
```python
|
|
327
|
+
!pip install "vision-language-engineering-lab[all]"
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
Then:
|
|
331
|
+
|
|
332
|
+
```python
|
|
333
|
+
from vlm_engineering import QwenVLModel
|
|
334
|
+
|
|
335
|
+
model = QwenVLModel(model_size="2b")
|
|
336
|
+
print(model.model_source)
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
For GPU workloads, verify the Colab runtime has a GPU enabled before loading large model weights.
|
|
340
|
+
|
|
341
|
+
---
|
|
342
|
+
|
|
343
|
+
## 4. Installation options
|
|
344
|
+
|
|
345
|
+
### Requirements
|
|
346
|
+
|
|
347
|
+
- Python **3.11, 3.12, or 3.13**
|
|
348
|
+
- Git for source installs
|
|
349
|
+
- Enough disk space for the model(s) you choose to download
|
|
350
|
+
- A GPU is strongly recommended for Qwen3-VL inference
|
|
351
|
+
- CLIP and lightweight package tests can run on CPU
|
|
352
|
+
|
|
353
|
+
### Create a virtual environment
|
|
354
|
+
|
|
355
|
+
Linux/macOS/GitHub Codespaces:
|
|
356
|
+
|
|
357
|
+
```bash
|
|
358
|
+
python -m venv .venv
|
|
359
|
+
source .venv/bin/activate
|
|
360
|
+
python -m pip install --upgrade pip setuptools wheel
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
Windows PowerShell:
|
|
364
|
+
|
|
365
|
+
```powershell
|
|
366
|
+
py -m venv .venv
|
|
367
|
+
.venv\Scripts\Activate.ps1
|
|
368
|
+
python -m pip install --upgrade pip setuptools wheel
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
### Choose what to install
|
|
372
|
+
|
|
373
|
+
Development/testing:
|
|
374
|
+
|
|
375
|
+
```bash
|
|
376
|
+
python -m pip install -e ".[dev]"
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
CLIP:
|
|
380
|
+
|
|
381
|
+
```bash
|
|
382
|
+
python -m pip install -e ".[clip]"
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
Qwen3-VL generation:
|
|
386
|
+
|
|
387
|
+
```bash
|
|
388
|
+
python -m pip install -e ".[qwen]"
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
Retrieval / Sentence Transformers:
|
|
392
|
+
|
|
393
|
+
```bash
|
|
394
|
+
python -m pip install -e ".[retrieval]"
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
All runtime features:
|
|
398
|
+
|
|
399
|
+
```bash
|
|
400
|
+
python -m pip install -e ".[all]"
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
Full contributor environment:
|
|
404
|
+
|
|
405
|
+
```bash
|
|
406
|
+
python -m pip install -e ".[all,dev,notebooks]"
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
A compatibility `requirements.txt` is also provided:
|
|
410
|
+
|
|
411
|
+
```bash
|
|
412
|
+
python -m pip install -r requirements.txt
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
`pyproject.toml` remains the dependency source of truth.
|
|
416
|
+
|
|
417
|
+
Confirm the CLI:
|
|
418
|
+
|
|
419
|
+
```bash
|
|
420
|
+
vlm-lab --help
|
|
421
|
+
vlm-lab models
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
---
|
|
425
|
+
|
|
426
|
+
## 5. Qwen models used by this project
|
|
427
|
+
|
|
428
|
+
The default generative VLM is **`Qwen/Qwen3-VL-2B-Instruct`**. The package also provides friendly 4B and 8B presets and supports explicit compatible Hugging Face model IDs.
|
|
429
|
+
|
|
430
|
+
| Preset | Hugging Face model | Size class | Recommended use |
|
|
431
|
+
|---|---|---:|---|
|
|
432
|
+
| `2b` | `Qwen/Qwen3-VL-2B-Instruct` | ~2B parameters | **Default.** Learning, local prototypes, lower resource use |
|
|
433
|
+
| `4b` | `Qwen/Qwen3-VL-4B-Instruct` | ~4B parameters | Balanced quality/resource option |
|
|
434
|
+
| `8b` | `Qwen/Qwen3-VL-8B-Instruct` | ~8B parameters | Higher-capacity inference on stronger hardware |
|
|
435
|
+
|
|
436
|
+
Official model pages:
|
|
437
|
+
|
|
438
|
+
- https://huggingface.co/Qwen/Qwen3-VL-2B-Instruct
|
|
439
|
+
- https://huggingface.co/Qwen/Qwen3-VL-4B-Instruct
|
|
440
|
+
- https://huggingface.co/Qwen/Qwen3-VL-8B-Instruct
|
|
441
|
+
|
|
442
|
+
The size labels are parameter classes, not exact runtime-memory requirements. A rough BF16 weight-only floor is about 2 bytes per parameter (~4 GB for 2B, ~8 GB for 4B, ~16 GB for 8B). Real inference needs additional memory for the vision encoder, activations, KV cache, image tokens, framework overhead, and generation state.
|
|
443
|
+
|
|
444
|
+
Other Qwen models in the retrieval stack:
|
|
445
|
+
|
|
446
|
+
| Model | Role |
|
|
447
|
+
|---|---|
|
|
448
|
+
| `Qwen/Qwen3-VL-Embedding-2B` | Multimodal retrieval embeddings |
|
|
449
|
+
| `Qwen/Qwen3-VL-Reranker-2B` | Second-stage candidate reranking |
|
|
450
|
+
|
|
451
|
+
Qwen3-VL is supported through current Hugging Face Transformers. `trust_remote_code` is disabled by default and is not required for the normal Qwen3-VL path implemented by this package.
|
|
452
|
+
|
|
453
|
+
---
|
|
454
|
+
|
|
455
|
+
## 6. Model selection and loading
|
|
456
|
+
|
|
457
|
+
### Default 2B
|
|
458
|
+
|
|
459
|
+
```python
|
|
460
|
+
from vlm_engineering import QwenVLModel
|
|
461
|
+
|
|
462
|
+
model = QwenVLModel()
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
### 4B or 8B preset
|
|
466
|
+
|
|
467
|
+
```python
|
|
468
|
+
model_4b = QwenVLModel(model_size="4b")
|
|
469
|
+
model_8b = QwenVLModel.from_preset("8b")
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
### Explicit Hugging Face model ID
|
|
473
|
+
|
|
474
|
+
```python
|
|
475
|
+
model = QwenVLModel.from_hub(
|
|
476
|
+
"Qwen/Qwen3-VL-4B-Instruct"
|
|
477
|
+
)
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
### Explicit local model
|
|
481
|
+
|
|
482
|
+
```python
|
|
483
|
+
model = QwenVLModel.from_local(
|
|
484
|
+
"models/Qwen3-VL-4B-Instruct"
|
|
485
|
+
)
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
CLI model-selection flags are mutually exclusive:
|
|
489
|
+
|
|
490
|
+
```text
|
|
491
|
+
--model-size
|
|
492
|
+
--model-id
|
|
493
|
+
--model-path
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
This prevents the CLI from silently selecting a different source than the user intended.
|
|
497
|
+
|
|
498
|
+
### Programmatic registry access
|
|
499
|
+
|
|
500
|
+
```python
|
|
501
|
+
from vlm_engineering import QWEN3_VL_INSTRUCT_MODELS
|
|
502
|
+
|
|
503
|
+
for alias, preset in QWEN3_VL_INSTRUCT_MODELS.items():
|
|
504
|
+
print(alias, preset.model_id, preset.parameter_class)
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
---
|
|
508
|
+
|
|
509
|
+
## 7. Hugging Face cache and project-local models
|
|
510
|
+
|
|
511
|
+
### Two supported storage modes
|
|
512
|
+
|
|
513
|
+
For a quick experiment, Hub-backed inference can use the normal Hugging Face cache:
|
|
514
|
+
|
|
515
|
+
```bash
|
|
516
|
+
vlm-lab describe data/diagram_random_clean.png --model-size 2b
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
For Docker, offline execution, explicit cleanup, and reproducible deployments, prefer an explicit project-local model under `models/`.
|
|
520
|
+
|
|
521
|
+
### Recommended: download the 2B preset into `models/`
|
|
522
|
+
|
|
523
|
+
```bash
|
|
524
|
+
vlm-lab download-model \
|
|
525
|
+
--model-size 2b \
|
|
526
|
+
--output models/Qwen3-VL-2B-Instruct
|
|
527
|
+
```
|
|
528
|
+
|
|
529
|
+
The `--output` argument is optional. This shorter command uses the same deterministic destination:
|
|
530
|
+
|
|
531
|
+
```bash
|
|
532
|
+
vlm-lab download-model --model-size 2b
|
|
533
|
+
```
|
|
534
|
+
|
|
535
|
+
Default destination:
|
|
536
|
+
|
|
537
|
+
```text
|
|
538
|
+
models/Qwen3-VL-2B-Instruct/
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
Hugging Face `snapshot_download(..., local_dir=...)` places the model files under the requested directory instead of the normal global Hub cache. Hugging Face may create a small `.cache/huggingface/` metadata directory inside the local model directory.
|
|
542
|
+
|
|
543
|
+
### Run from the explicit local model directory
|
|
544
|
+
|
|
545
|
+
```bash
|
|
546
|
+
vlm-lab describe data/diagram_random_clean.png \
|
|
547
|
+
--model-path models/Qwen3-VL-2B-Instruct \
|
|
548
|
+
--prompt "Describe this image accurately. List the main objects, text, and important visual relationships."
|
|
549
|
+
```
|
|
550
|
+
|
|
551
|
+
### Verify fully offline loading
|
|
552
|
+
|
|
553
|
+
After the download succeeds:
|
|
554
|
+
|
|
555
|
+
```bash
|
|
556
|
+
HF_HUB_OFFLINE=1 vlm-lab describe data/diagram_random_clean.png \
|
|
557
|
+
--model-path models/Qwen3-VL-2B-Instruct \
|
|
558
|
+
--prompt "Describe this image accurately."
|
|
559
|
+
```
|
|
560
|
+
|
|
561
|
+
`QwenVLModel.from_local()` enables local-files-only loading and does not silently fall back to the Hub.
|
|
562
|
+
|
|
563
|
+
### Download another preset or explicit model ID
|
|
564
|
+
|
|
565
|
+
```bash
|
|
566
|
+
vlm-lab download-model --model-size 4b
|
|
567
|
+
vlm-lab download-model --model-size 8b
|
|
568
|
+
```
|
|
569
|
+
|
|
570
|
+
```bash
|
|
571
|
+
vlm-lab download-model \
|
|
572
|
+
--model-id Qwen/Qwen3-VL-8B-Instruct \
|
|
573
|
+
--output models/qwen8b
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
### Clean the old global cache only after offline verification
|
|
577
|
+
|
|
578
|
+
Never remove the global Hugging Face cache while a model is downloading or running. First verify the local model with `HF_HUB_OFFLINE=1`, then inspect the old cache:
|
|
579
|
+
|
|
580
|
+
```bash
|
|
581
|
+
du -sh ~/.cache/huggingface/hub 2>/dev/null
|
|
582
|
+
hf cache list --sort size:desc
|
|
583
|
+
```
|
|
584
|
+
|
|
585
|
+
If disk space is needed after the offline test succeeds, remove only the old Qwen cache entry you no longer need:
|
|
586
|
+
|
|
587
|
+
```bash
|
|
588
|
+
rm -rf ~/.cache/huggingface/hub/models--Qwen--Qwen3-VL-2B-Instruct
|
|
589
|
+
```
|
|
590
|
+
|
|
591
|
+
The package never deletes a user's shared Hugging Face cache automatically.
|
|
592
|
+
|
|
593
|
+
---
|
|
594
|
+
|
|
595
|
+
## 8. Advanced model-loading options
|
|
596
|
+
|
|
597
|
+
### `trust_remote_code`
|
|
598
|
+
|
|
599
|
+
Default: **False**.
|
|
600
|
+
|
|
601
|
+
```bash
|
|
602
|
+
vlm-lab describe image.jpg --trust-remote-code
|
|
603
|
+
```
|
|
604
|
+
|
|
605
|
+
Only enable this for a model repository you trust and that genuinely requires repository-provided Python code. Enabling it expands the security trust boundary.
|
|
606
|
+
|
|
607
|
+
### Device and dtype
|
|
608
|
+
|
|
609
|
+
```python
|
|
610
|
+
from vlm_engineering import QwenVLModel
|
|
611
|
+
|
|
612
|
+
model = QwenVLModel(
|
|
613
|
+
model_size="4b",
|
|
614
|
+
device_map="auto",
|
|
615
|
+
dtype="auto",
|
|
616
|
+
)
|
|
617
|
+
```
|
|
618
|
+
|
|
619
|
+
Validate the exact dtype, quantization strategy, backend, and model size on your target hardware before production deployment.
|
|
620
|
+
|
|
621
|
+
---
|
|
622
|
+
|
|
623
|
+
## 9. Core Qwen3-VL use cases
|
|
624
|
+
|
|
625
|
+
### Image captioning / rich description
|
|
626
|
+
|
|
627
|
+
```bash
|
|
628
|
+
vlm-lab describe photo.jpg \
|
|
629
|
+
--prompt "Write a factual, detailed description."
|
|
630
|
+
```
|
|
631
|
+
|
|
632
|
+
### Visual question answering
|
|
633
|
+
|
|
634
|
+
```bash
|
|
635
|
+
vlm-lab describe dashboard.png \
|
|
636
|
+
--model-size 4b \
|
|
637
|
+
--prompt "Which metric increased the most and what evidence supports it?"
|
|
638
|
+
```
|
|
639
|
+
|
|
640
|
+
### Diagram / architecture understanding
|
|
641
|
+
|
|
642
|
+
```bash
|
|
643
|
+
vlm-lab analyze architecture.png --model-size 4b
|
|
644
|
+
```
|
|
645
|
+
|
|
646
|
+
The `analyze` command asks the VLM for structured JSON containing page type, title, summary, entities, relations, important text, and uncertainties.
|
|
647
|
+
|
|
648
|
+
### Screenshot / UI understanding
|
|
649
|
+
|
|
650
|
+
Use `describe` or `analyze` for dashboards, application screenshots, forms, and technical UI states.
|
|
651
|
+
|
|
652
|
+
### Tables and document pages
|
|
653
|
+
|
|
654
|
+
Render the page as an image and request structured extraction. For production documents, preserve native/OCR text separately and use the VLM for layout, grouping, relationships, and visual semantics.
|
|
655
|
+
|
|
656
|
+
---
|
|
657
|
+
|
|
658
|
+
## 10. VLM + OCR/native parsing: hybrid by default
|
|
659
|
+
|
|
660
|
+
```text
|
|
661
|
+
Native extraction / OCR Qwen3-VL
|
|
662
|
+
exact text, IDs, numbers layout, arrows, groups,
|
|
663
|
+
long deterministic text relationships, visual meaning
|
|
664
|
+
\ /
|
|
665
|
+
\ /
|
|
666
|
+
fusion
|
|
667
|
+
|
|
|
668
|
+
RAG-ready chunk
|
|
669
|
+
```
|
|
670
|
+
|
|
671
|
+
A VLM can replace OCR in some workflows, but the strongest document pipeline usually keeps native/OCR evidence for literal accuracy and adds VLM semantics where visual structure matters.
|
|
672
|
+
|
|
673
|
+
---
|
|
674
|
+
|
|
675
|
+
## 11. Build a RAG-ready visual chunk
|
|
676
|
+
|
|
677
|
+
```bash
|
|
678
|
+
vlm-lab chunk data/page_001.png \
|
|
679
|
+
--model-size 4b \
|
|
680
|
+
--document-id architecture-v1 \
|
|
681
|
+
--source-file architecture.pdf \
|
|
682
|
+
--page 1 \
|
|
683
|
+
--native-text-file data/page_001.txt
|
|
684
|
+
```
|
|
685
|
+
|
|
686
|
+
The resulting `VisualChunk` preserves traceability such as document ID, source file, page, image reference, entities, relations, metadata, and fused retrieval text.
|
|
687
|
+
|
|
688
|
+
---
|
|
689
|
+
|
|
690
|
+
## 12. Visual RAG with a text embedder
|
|
691
|
+
|
|
692
|
+
```text
|
|
693
|
+
image/page
|
|
694
|
+
-> Qwen3-VL description / structured analysis
|
|
695
|
+
-> retrieval text
|
|
696
|
+
-> Sentence Transformers text embedder
|
|
697
|
+
-> vector index / vector database
|
|
698
|
+
```
|
|
699
|
+
|
|
700
|
+
This is useful when an existing RAG platform only supports text embeddings. The VLM turns visual evidence into searchable text while the original `image_ref` is retained for final grounding.
|
|
701
|
+
|
|
702
|
+
```bash
|
|
703
|
+
python examples/text_only_visual_rag.py
|
|
704
|
+
```
|
|
705
|
+
|
|
706
|
+
After retrieval, the final VLM can inspect the original image again rather than trusting only the generated description.
|
|
707
|
+
|
|
708
|
+
---
|
|
709
|
+
|
|
710
|
+
## 13. True multimodal embeddings and reranking
|
|
711
|
+
|
|
712
|
+
### Multimodal embeddings
|
|
713
|
+
|
|
714
|
+
```python
|
|
715
|
+
from vlm_engineering.retrieval import QwenMultimodalEmbedder
|
|
716
|
+
|
|
717
|
+
embedder = QwenMultimodalEmbedder(
|
|
718
|
+
"Qwen/Qwen3-VL-Embedding-2B"
|
|
719
|
+
)
|
|
720
|
+
|
|
721
|
+
queries = [
|
|
722
|
+
"Find the architecture diagram containing a cache and database."
|
|
723
|
+
]
|
|
724
|
+
|
|
725
|
+
documents = [
|
|
726
|
+
"A textual architecture note",
|
|
727
|
+
"data/architecture.png",
|
|
728
|
+
{"text": "Payment architecture", "image": "data/architecture.png"},
|
|
729
|
+
]
|
|
730
|
+
|
|
731
|
+
q = embedder.encode(
|
|
732
|
+
queries,
|
|
733
|
+
prompt="Retrieve relevant technical document evidence.",
|
|
734
|
+
)
|
|
735
|
+
d = embedder.encode(documents)
|
|
736
|
+
|
|
737
|
+
print(q @ d.T)
|
|
738
|
+
```
|
|
739
|
+
|
|
740
|
+
### Multimodal reranking
|
|
741
|
+
|
|
742
|
+
```python
|
|
743
|
+
from vlm_engineering.retrieval import QwenMultimodalReranker
|
|
744
|
+
|
|
745
|
+
reranker = QwenMultimodalReranker()
|
|
746
|
+
|
|
747
|
+
scores = reranker.score(
|
|
748
|
+
"Which diagram shows the payment database?",
|
|
749
|
+
["candidate text", "data/diagram.png"],
|
|
750
|
+
)
|
|
751
|
+
|
|
752
|
+
print(scores)
|
|
753
|
+
```
|
|
754
|
+
|
|
755
|
+
Recommended production pattern:
|
|
756
|
+
|
|
757
|
+
```text
|
|
758
|
+
query
|
|
759
|
+
-> Qwen3-VL-Embedding -> top K candidates
|
|
760
|
+
-> Qwen3-VL-Reranker -> top 3-5
|
|
761
|
+
-> retrieve chunk text + original image
|
|
762
|
+
-> selected Qwen3-VL-Instruct model
|
|
763
|
+
-> grounded answer with source/page
|
|
764
|
+
```
|
|
765
|
+
|
|
766
|
+
---
|
|
767
|
+
|
|
768
|
+
## 14. CLIP foundations
|
|
769
|
+
|
|
770
|
+
```python
|
|
771
|
+
from PIL import Image
|
|
772
|
+
|
|
773
|
+
from vlm_engineering import CLIPEncoder
|
|
774
|
+
|
|
775
|
+
image = Image.open("data/diagram_random_clean.png").convert("RGB")
|
|
776
|
+
|
|
777
|
+
clip = CLIPEncoder()
|
|
778
|
+
result = clip.zero_shot_classify(
|
|
779
|
+
image,
|
|
780
|
+
["cat", "dog", "airplane"],
|
|
781
|
+
)
|
|
782
|
+
|
|
783
|
+
print(result)
|
|
784
|
+
```
|
|
785
|
+
|
|
786
|
+
CLIP is useful for learning the shared image/text embedding-space idea that modern multimodal retrieval builds upon.
|
|
787
|
+
|
|
788
|
+
---
|
|
789
|
+
|
|
790
|
+
## 15. Examples and application scenarios
|
|
791
|
+
|
|
792
|
+
Small API examples:
|
|
793
|
+
|
|
794
|
+
```text
|
|
795
|
+
examples/clip_zero_shot.py CLIP zero-shot classification
|
|
796
|
+
examples/qwen_describe_image.py Qwen image description
|
|
797
|
+
examples/qwen_model_selection.py 2B/4B/8B/custom model selection
|
|
798
|
+
examples/qwen_local_model.py explicit local/offline Qwen
|
|
799
|
+
examples/structured_visual_chunk.py RAG-ready visual chunk
|
|
800
|
+
examples/text_only_visual_rag.py VLM description + text embeddings
|
|
801
|
+
examples/qwen_multimodal_retrieval.py multimodal embedding/retrieval
|
|
802
|
+
```
|
|
803
|
+
|
|
804
|
+
End-to-end application cookbook:
|
|
805
|
+
|
|
806
|
+
```text
|
|
807
|
+
scenarios/scenario_01_image_captioning.py image captioning / description
|
|
808
|
+
scenarios/scenario_02_visual_question_answering.py grounded VQA
|
|
809
|
+
scenarios/scenario_03_diagram_to_json.py diagram -> structured JSON
|
|
810
|
+
scenarios/scenario_04_document_page_to_rag_chunk.py native/OCR + VLM -> RAG chunk
|
|
811
|
+
scenarios/scenario_05_text_only_visual_rag.py images -> VLM text -> text RAG
|
|
812
|
+
scenarios/scenario_06_true_multimodal_retrieval.py direct multimodal retrieval
|
|
813
|
+
scenarios/scenario_07_compare_qwen_presets.py compare Qwen 2B / 4B / 8B
|
|
814
|
+
scenarios/scenario_08_hub_vs_local_loading.py Hub/cache vs local/offline
|
|
815
|
+
scenarios/scenario_09_batch_structured_analysis.py batch image/page analysis
|
|
816
|
+
```
|
|
817
|
+
|
|
818
|
+
Each applicable scenario accepts the same model choices used by the package:
|
|
819
|
+
|
|
820
|
+
```bash
|
|
821
|
+
# Default 2B
|
|
822
|
+
python scenarios/scenario_01_image_captioning.py data/diagram_random_clean.png
|
|
823
|
+
|
|
824
|
+
# 4B / 8B
|
|
825
|
+
python scenarios/scenario_01_image_captioning.py \
|
|
826
|
+
data/diagram_random_clean.png --model-size 4b
|
|
827
|
+
|
|
828
|
+
python scenarios/scenario_01_image_captioning.py \
|
|
829
|
+
data/diagram_random_clean.png --model-size 8b
|
|
830
|
+
|
|
831
|
+
# Explicit Hugging Face model
|
|
832
|
+
python scenarios/scenario_01_image_captioning.py \
|
|
833
|
+
data/diagram_random_clean.png \
|
|
834
|
+
--model-id Qwen/Qwen3-VL-4B-Instruct
|
|
835
|
+
|
|
836
|
+
# Explicit local model
|
|
837
|
+
python scenarios/scenario_01_image_captioning.py \
|
|
838
|
+
data/diagram_random_clean.png \
|
|
839
|
+
--model-path models/Qwen3-VL-4B-Instruct
|
|
840
|
+
```
|
|
841
|
+
|
|
842
|
+
See [`scenarios/README.md`](scenarios/README.md) for copy/paste commands, model guidance, RAG patterns, batch processing, and offline usage.
|
|
843
|
+
|
|
844
|
+
---
|
|
845
|
+
|
|
846
|
+
## 16. Notebooks
|
|
847
|
+
|
|
848
|
+
Notebooks are **analysis clients**, not the implementation layer:
|
|
849
|
+
|
|
850
|
+
- `00_clip_foundations.ipynb`
|
|
851
|
+
- `01_qwen3_vl_quickstart.ipynb`
|
|
852
|
+
- `02_visual_document_understanding.ipynb`
|
|
853
|
+
- `03_multimodal_rag.ipynb`
|
|
854
|
+
|
|
855
|
+
All reusable logic lives under `src/vlm_engineering` and can be used without Jupyter.
|
|
856
|
+
|
|
857
|
+
---
|
|
858
|
+
|
|
859
|
+
## 17. Docker and Docker Compose
|
|
860
|
+
|
|
861
|
+
The repository includes both a `Dockerfile` and `docker-compose.yml` so users can run the CLI inside a reproducible container instead of managing the Python environment directly on the host.
|
|
862
|
+
|
|
863
|
+
The current container is a runtime-oriented image. It installs the package with the Qwen and retrieval dependencies and does not include contributor/test/notebook tooling by default.
|
|
864
|
+
|
|
865
|
+
### Prerequisites
|
|
866
|
+
|
|
867
|
+
Install one of:
|
|
868
|
+
|
|
869
|
+
- Docker Desktop, or
|
|
870
|
+
- Docker Engine with Docker Compose v2
|
|
871
|
+
|
|
872
|
+
Verify:
|
|
873
|
+
|
|
874
|
+
```bash
|
|
875
|
+
docker --version
|
|
876
|
+
docker compose version
|
|
877
|
+
```
|
|
878
|
+
|
|
879
|
+
### Build with Docker Compose
|
|
880
|
+
|
|
881
|
+
From the repository root:
|
|
882
|
+
|
|
883
|
+
```bash
|
|
884
|
+
docker compose build
|
|
885
|
+
```
|
|
886
|
+
|
|
887
|
+
The image is built from the repository `Dockerfile`, which currently uses Python 3.12 as the reference container runtime. The package itself targets Python 3.11-3.13 in v0.2.1.
|
|
888
|
+
|
|
889
|
+
### Check the CLI inside the container
|
|
890
|
+
|
|
891
|
+
```bash
|
|
892
|
+
docker compose run --rm vlm-lab --help
|
|
893
|
+
```
|
|
894
|
+
|
|
895
|
+
List the available Qwen presets:
|
|
896
|
+
|
|
897
|
+
```bash
|
|
898
|
+
docker compose run --rm vlm-lab models
|
|
899
|
+
```
|
|
900
|
+
|
|
901
|
+
### Understand the mounted directories
|
|
902
|
+
|
|
903
|
+
The Compose configuration mounts:
|
|
904
|
+
|
|
905
|
+
```text
|
|
906
|
+
Host Container
|
|
907
|
+
./data /app/data read-only
|
|
908
|
+
./models /app/models persistent bind mount
|
|
909
|
+
hf-cache named volume /home/appuser/.cache/huggingface
|
|
910
|
+
```
|
|
911
|
+
|
|
912
|
+
This means:
|
|
913
|
+
|
|
914
|
+
- put user images/pages under `./data/`
|
|
915
|
+
- explicitly downloaded models under `./models/` survive container removal
|
|
916
|
+
- Hugging Face cache downloads survive normal `docker compose run --rm` commands
|
|
917
|
+
- the container does not need to copy your private data into the image
|
|
918
|
+
|
|
919
|
+
### Describe an image with the default 2B model
|
|
920
|
+
|
|
921
|
+
Place an image at `data/diagram_random_clean.png`, then run:
|
|
922
|
+
|
|
923
|
+
```bash
|
|
924
|
+
docker compose run --rm vlm-lab \
|
|
925
|
+
describe data/diagram_random_clean.png
|
|
926
|
+
```
|
|
927
|
+
|
|
928
|
+
With a custom prompt:
|
|
929
|
+
|
|
930
|
+
```bash
|
|
931
|
+
docker compose run --rm vlm-lab \
|
|
932
|
+
describe data/diagram_random_clean.png \
|
|
933
|
+
--prompt "Describe this image precisely."
|
|
934
|
+
```
|
|
935
|
+
|
|
936
|
+
### Select 4B or 8B inside the container
|
|
937
|
+
|
|
938
|
+
```bash
|
|
939
|
+
docker compose run --rm vlm-lab \
|
|
940
|
+
describe data/diagram_random_clean.png \
|
|
941
|
+
--model-size 4b
|
|
942
|
+
```
|
|
943
|
+
|
|
944
|
+
```bash
|
|
945
|
+
docker compose run --rm vlm-lab \
|
|
946
|
+
analyze data/architecture.png \
|
|
947
|
+
--model-size 8b
|
|
948
|
+
```
|
|
949
|
+
|
|
950
|
+
### Persist a model explicitly under `./models`
|
|
951
|
+
|
|
952
|
+
Download the 4B preset from inside the container:
|
|
953
|
+
|
|
954
|
+
```bash
|
|
955
|
+
docker compose run --rm vlm-lab \
|
|
956
|
+
download-model \
|
|
957
|
+
--model-size 4b \
|
|
958
|
+
--output models/Qwen3-VL-4B-Instruct
|
|
959
|
+
```
|
|
960
|
+
|
|
961
|
+
Because `/app/models` is bind-mounted to host `./models`, the downloaded files remain available after the container exits.
|
|
962
|
+
|
|
963
|
+
Then use the local model explicitly:
|
|
964
|
+
|
|
965
|
+
```bash
|
|
966
|
+
docker compose run --rm vlm-lab \
|
|
967
|
+
describe data/diagram_random_clean.png \
|
|
968
|
+
--model-path models/Qwen3-VL-4B-Instruct
|
|
969
|
+
```
|
|
970
|
+
|
|
971
|
+
### Fully offline container inference
|
|
972
|
+
|
|
973
|
+
First download the model while network access is available. Then run:
|
|
974
|
+
|
|
975
|
+
```bash
|
|
976
|
+
docker compose run --rm \
|
|
977
|
+
-e HF_HUB_OFFLINE=1 \
|
|
978
|
+
vlm-lab \
|
|
979
|
+
describe data/diagram_random_clean.png \
|
|
980
|
+
--model-path models/Qwen3-VL-4B-Instruct
|
|
981
|
+
```
|
|
982
|
+
|
|
983
|
+
`--model-path` enables local-only model loading in the package.
|
|
984
|
+
|
|
985
|
+
### Hugging Face authentication without baking secrets into the image
|
|
986
|
+
|
|
987
|
+
For a private or gated compatible repository, keep the token on the host and pass it at runtime rather than storing it in the Dockerfile:
|
|
988
|
+
|
|
989
|
+
```bash
|
|
990
|
+
export HF_TOKEN="..."
|
|
991
|
+
|
|
992
|
+
docker compose run --rm \
|
|
993
|
+
-e HF_TOKEN \
|
|
994
|
+
vlm-lab \
|
|
995
|
+
describe data/diagram_random_clean.png \
|
|
996
|
+
--model-id your-org/your-compatible-model
|
|
997
|
+
```
|
|
998
|
+
|
|
999
|
+
Do not commit Hugging Face tokens or other credentials to the repository.
|
|
1000
|
+
|
|
1001
|
+
### Open a shell for debugging
|
|
1002
|
+
|
|
1003
|
+
The image entrypoint is `vlm-lab`. To open a shell instead:
|
|
1004
|
+
|
|
1005
|
+
```bash
|
|
1006
|
+
docker compose run --rm \
|
|
1007
|
+
--entrypoint /bin/sh \
|
|
1008
|
+
vlm-lab
|
|
1009
|
+
```
|
|
1010
|
+
|
|
1011
|
+
Inside the container you can inspect:
|
|
1012
|
+
|
|
1013
|
+
```bash
|
|
1014
|
+
python --version
|
|
1015
|
+
python -m pip list
|
|
1016
|
+
ls -la /app/data
|
|
1017
|
+
ls -la /app/models
|
|
1018
|
+
```
|
|
1019
|
+
|
|
1020
|
+
### Build and run without Compose
|
|
1021
|
+
|
|
1022
|
+
Build:
|
|
1023
|
+
|
|
1024
|
+
```bash
|
|
1025
|
+
docker build \
|
|
1026
|
+
-t vision-language-engineering-lab:0.2.1 \
|
|
1027
|
+
.
|
|
1028
|
+
```
|
|
1029
|
+
|
|
1030
|
+
List models:
|
|
1031
|
+
|
|
1032
|
+
```bash
|
|
1033
|
+
docker run --rm \
|
|
1034
|
+
vision-language-engineering-lab:0.2.1 \
|
|
1035
|
+
models
|
|
1036
|
+
```
|
|
1037
|
+
|
|
1038
|
+
Run against host data and persistent models:
|
|
1039
|
+
|
|
1040
|
+
```bash
|
|
1041
|
+
docker run --rm \
|
|
1042
|
+
-v "$PWD/data:/app/data:ro" \
|
|
1043
|
+
-v "$PWD/models:/app/models" \
|
|
1044
|
+
-v vlm-hf-cache:/home/appuser/.cache/huggingface \
|
|
1045
|
+
vision-language-engineering-lab:0.2.1 \
|
|
1046
|
+
describe data/diagram_random_clean.png \
|
|
1047
|
+
--model-size 2b
|
|
1048
|
+
```
|
|
1049
|
+
|
|
1050
|
+
### Rebuild after package/dependency changes
|
|
1051
|
+
|
|
1052
|
+
```bash
|
|
1053
|
+
docker compose build
|
|
1054
|
+
```
|
|
1055
|
+
|
|
1056
|
+
If you specifically need a clean image rebuild:
|
|
1057
|
+
|
|
1058
|
+
```bash
|
|
1059
|
+
docker compose build --no-cache
|
|
1060
|
+
```
|
|
1061
|
+
|
|
1062
|
+
### Remove containers while keeping explicit local models
|
|
1063
|
+
|
|
1064
|
+
```bash
|
|
1065
|
+
docker compose down
|
|
1066
|
+
```
|
|
1067
|
+
|
|
1068
|
+
The host `./models` directory remains because it is a bind mount.
|
|
1069
|
+
|
|
1070
|
+
To also delete the named Hugging Face cache volume:
|
|
1071
|
+
|
|
1072
|
+
```bash
|
|
1073
|
+
docker compose down -v
|
|
1074
|
+
```
|
|
1075
|
+
|
|
1076
|
+
Use `-v` carefully because cached model downloads in the named volume will be removed.
|
|
1077
|
+
|
|
1078
|
+
### GPU execution
|
|
1079
|
+
|
|
1080
|
+
The checked-in Compose file is intentionally a portable baseline and does not force a GPU runtime configuration.
|
|
1081
|
+
|
|
1082
|
+
For NVIDIA GPU inference, configure a compatible host Docker/NVIDIA runtime and verify GPU visibility from the container before relying on it for Qwen workloads. GPU setup is host-specific; the project does not assume every user has NVIDIA hardware.
|
|
1083
|
+
|
|
1084
|
+
Qwen3-VL 4B and especially 8B require substantially more memory than the default 2B model. Start with 2B when validating a container deployment.
|
|
1085
|
+
|
|
1086
|
+
### Why `docker compose run` instead of `docker compose up`?
|
|
1087
|
+
|
|
1088
|
+
`vlm-lab` is a command-line workload, not a long-running web server. The Compose service defaults to `--help`, so most users should execute individual tasks with:
|
|
1089
|
+
|
|
1090
|
+
```bash
|
|
1091
|
+
docker compose run --rm vlm-lab <command> ...
|
|
1092
|
+
```
|
|
1093
|
+
|
|
1094
|
+
This creates an isolated one-shot container, runs the command, and removes the container afterward while preserving the mounted data/model/cache volumes.
|
|
1095
|
+
|
|
1096
|
+
---
|
|
1097
|
+
|
|
1098
|
+
## 18. Quality gates and compatibility validation
|
|
1099
|
+
|
|
1100
|
+
Before pushing changes:
|
|
1101
|
+
|
|
1102
|
+
```bash
|
|
1103
|
+
python -m pip check
|
|
1104
|
+
python -m ruff check .
|
|
1105
|
+
python -m mypy .
|
|
1106
|
+
python -m pytest --cov=vlm_engineering --cov-report=term-missing
|
|
1107
|
+
python -m pip_audit
|
|
1108
|
+
```
|
|
1109
|
+
|
|
1110
|
+
The project uses:
|
|
1111
|
+
|
|
1112
|
+
| Tool | Purpose |
|
|
1113
|
+
|---|---|
|
|
1114
|
+
| Ruff | linting, import organization, source-quality rules |
|
|
1115
|
+
| mypy | static type checking |
|
|
1116
|
+
| pytest | functional, integration, and contract testing |
|
|
1117
|
+
| pytest-cov | coverage enforcement |
|
|
1118
|
+
| `pip check` | installed dependency consistency |
|
|
1119
|
+
| `pip-audit` | known dependency-vulnerability auditing |
|
|
1120
|
+
|
|
1121
|
+
CI additionally executes the package against Python 3.11, 3.12, and 3.13.
|
|
1122
|
+
|
|
1123
|
+
Heavy ML components are mocked or injected in normal unit tests, so CI does not need to download multi-gigabyte Qwen model weights merely to validate package contracts.
|
|
1124
|
+
|
|
1125
|
+
---
|
|
1126
|
+
|
|
1127
|
+
## 19. Troubleshooting
|
|
1128
|
+
|
|
1129
|
+
### `ModuleNotFoundError`
|
|
1130
|
+
|
|
1131
|
+
Activate the environment and install the required extra:
|
|
1132
|
+
|
|
1133
|
+
```bash
|
|
1134
|
+
source .venv/bin/activate
|
|
1135
|
+
python -m pip install -e ".[all]"
|
|
1136
|
+
```
|
|
1137
|
+
|
|
1138
|
+
### `vlm-lab: command not found`
|
|
1139
|
+
|
|
1140
|
+
Confirm the package is installed in the active environment:
|
|
1141
|
+
|
|
1142
|
+
```bash
|
|
1143
|
+
python -m pip show vision-language-engineering-lab
|
|
1144
|
+
which python
|
|
1145
|
+
```
|
|
1146
|
+
|
|
1147
|
+
Then reinstall:
|
|
1148
|
+
|
|
1149
|
+
```bash
|
|
1150
|
+
python -m pip install -e ".[all]"
|
|
1151
|
+
```
|
|
1152
|
+
|
|
1153
|
+
### CUDA / out-of-memory error
|
|
1154
|
+
|
|
1155
|
+
Start with the default `2b` preset, reduce image resolution/output length, or use stronger hardware. Moving from 2B to 4B to 8B increases model capacity and memory pressure.
|
|
1156
|
+
|
|
1157
|
+
### First run is slow
|
|
1158
|
+
|
|
1159
|
+
Hub/cache mode may be downloading model files. For a predictable deployment directory, use `vlm-lab download-model --model-size 2b`, then run with `--model-path models/Qwen3-VL-2B-Instruct`.
|
|
1160
|
+
|
|
1161
|
+
### Fully offline inference
|
|
1162
|
+
|
|
1163
|
+
Download the model first, then use `--model-path` / `QwenVLModel.from_local()`. Optionally set:
|
|
1164
|
+
|
|
1165
|
+
```bash
|
|
1166
|
+
export HF_HUB_OFFLINE=1
|
|
1167
|
+
```
|
|
1168
|
+
|
|
1169
|
+
### Model requires repository-provided Python code
|
|
1170
|
+
|
|
1171
|
+
Do not enable `--trust-remote-code` automatically. Verify the model repository and only opt in when genuinely required.
|
|
1172
|
+
|
|
1173
|
+
### Sentence Transformers / dependency compatibility
|
|
1174
|
+
|
|
1175
|
+
Check the resolved environment:
|
|
1176
|
+
|
|
1177
|
+
```bash
|
|
1178
|
+
python -m pip check
|
|
1179
|
+
python -m pip show sentence-transformers torch transformers
|
|
1180
|
+
```
|
|
1181
|
+
|
|
1182
|
+
v0.2.1 allows Sentence Transformers 5.4 through the 6.x line, while CI validates the dependency stack on Python 3.11-3.13.
|
|
1183
|
+
|
|
1184
|
+
### Which Qwen model should I choose?
|
|
1185
|
+
|
|
1186
|
+
- Start with **2B** while developing the pipeline.
|
|
1187
|
+
- Compare **4B** when reasoning/extraction quality is insufficient.
|
|
1188
|
+
- Test **8B** when the quality gain justifies the higher resource cost.
|
|
1189
|
+
- Evaluate on your own diagrams/documents; model size alone does not guarantee better RAG accuracy.
|
|
1190
|
+
|
|
1191
|
+
### Docker cannot see my file
|
|
1192
|
+
|
|
1193
|
+
Confirm the file is under the host `data/` directory because Compose mounts that directory into `/app/data`:
|
|
1194
|
+
|
|
1195
|
+
```bash
|
|
1196
|
+
ls -la data/
|
|
1197
|
+
docker compose run --rm --entrypoint /bin/sh vlm-lab -c "ls -la /app/data"
|
|
1198
|
+
```
|
|
1199
|
+
|
|
1200
|
+
### Docker keeps downloading models
|
|
1201
|
+
|
|
1202
|
+
For production-like Docker tests, prefer downloading the model explicitly into `./models` and using `--model-path`. The named Hugging Face cache volume remains useful for ad-hoc Hub-backed experiments.
|
|
1203
|
+
|
|
1204
|
+
---
|
|
1205
|
+
|
|
1206
|
+
## 20. Contributing
|
|
1207
|
+
|
|
1208
|
+
**Contributions are welcome.**
|
|
1209
|
+
|
|
1210
|
+
The project is intended to grow as an open Vision-Language engineering lab, and contributions from developers, AI/ML engineers, researchers, students, and practitioners are encouraged.
|
|
1211
|
+
|
|
1212
|
+
Useful contributions include:
|
|
1213
|
+
|
|
1214
|
+
- new VLM integrations
|
|
1215
|
+
- additional Qwen-compatible model support
|
|
1216
|
+
- multimodal retrieval strategies
|
|
1217
|
+
- document-understanding pipelines
|
|
1218
|
+
- RAG evaluation methods
|
|
1219
|
+
- performance and memory improvements
|
|
1220
|
+
- additional deterministic tests
|
|
1221
|
+
- Python-version compatibility improvements
|
|
1222
|
+
- Docker/deployment improvements
|
|
1223
|
+
- documentation and tutorials
|
|
1224
|
+
- reproducible application scenarios
|
|
1225
|
+
- bug fixes
|
|
1226
|
+
|
|
1227
|
+
### Contribution workflow
|
|
1228
|
+
|
|
1229
|
+
1. Fork the repository.
|
|
1230
|
+
2. Create a focused branch.
|
|
1231
|
+
3. Implement the change.
|
|
1232
|
+
4. Add or update tests.
|
|
1233
|
+
5. Run the quality gates locally.
|
|
1234
|
+
6. Push the branch.
|
|
1235
|
+
7. Open a Pull Request describing the motivation, implementation, validation, and any compatibility considerations.
|
|
1236
|
+
|
|
1237
|
+
Example development setup:
|
|
1238
|
+
|
|
1239
|
+
```bash
|
|
1240
|
+
git clone https://github.com/helmighanmi/vision-language-engineering-lab.git
|
|
1241
|
+
cd vision-language-engineering-lab
|
|
1242
|
+
|
|
1243
|
+
python -m venv .venv
|
|
1244
|
+
source .venv/bin/activate
|
|
1245
|
+
python -m pip install --upgrade pip
|
|
1246
|
+
python -m pip install -e ".[all,dev]"
|
|
1247
|
+
```
|
|
1248
|
+
|
|
1249
|
+
Validation:
|
|
1250
|
+
|
|
1251
|
+
```bash
|
|
1252
|
+
python -m pip check
|
|
1253
|
+
python -m ruff check .
|
|
1254
|
+
python -m mypy .
|
|
1255
|
+
python -m pytest --cov=vlm_engineering --cov-report=term-missing
|
|
1256
|
+
python -m pip_audit
|
|
1257
|
+
```
|
|
1258
|
+
|
|
1259
|
+
Please read [`CONTRIBUTING.md`](CONTRIBUTING.md) for the complete contribution workflow.
|
|
1260
|
+
|
|
1261
|
+
Questions, feature proposals, documentation improvements, and bug reports are welcome through GitHub Issues.
|
|
1262
|
+
|
|
1263
|
+
---
|
|
1264
|
+
|
|
1265
|
+
## 21. Documentation
|
|
1266
|
+
|
|
1267
|
+
- `docs/model-loading.md` — model presets, Hub/custom/local modes and troubleshooting
|
|
1268
|
+
- `docs/qwen-model-selection.md` — model-size selection and memory guidance
|
|
1269
|
+
- `docs/rag-patterns.md` — visual and multimodal RAG patterns
|
|
1270
|
+
- `docs/architecture.md` — package architecture
|
|
1271
|
+
- `docs/testing.md` — testing strategy
|
|
1272
|
+
- `docs/pdf/Vision_Language_Engineering_EN.pdf` — English teaching course
|
|
1273
|
+
- `docs/pdf/Ingenierie_Vision_Langage_FR.pdf` — French teaching course
|
|
1274
|
+
|
|
1275
|
+
The PDFs are conceptual teaching references. The README and Markdown docs are the operational source of truth for the current package CLI/API.
|
|
1276
|
+
|
|
1277
|
+
---
|
|
1278
|
+
|
|
1279
|
+
## 22. Repository structure
|
|
1280
|
+
|
|
1281
|
+
```text
|
|
1282
|
+
vision-language-engineering-lab/
|
|
1283
|
+
├── .github/ CI, security, and publishing workflows
|
|
1284
|
+
├── data/ user-provided images/pages (gitignored except docs)
|
|
1285
|
+
├── docs/ architecture, model-loading, RAG, testing guidance
|
|
1286
|
+
├── examples/ small runnable API examples
|
|
1287
|
+
├── models/ explicit local model downloads (gitignored)
|
|
1288
|
+
├── notebooks/ analysis/demonstration clients
|
|
1289
|
+
├── scenarios/ end-to-end application cookbook
|
|
1290
|
+
├── src/
|
|
1291
|
+
│ └── vlm_engineering/ production Python package
|
|
1292
|
+
├── tests/ deterministic unit/integration/contract tests
|
|
1293
|
+
├── Dockerfile container image definition
|
|
1294
|
+
├── docker-compose.yml reproducible CLI/container workflow
|
|
1295
|
+
├── pyproject.toml package metadata and dependency source of truth
|
|
1296
|
+
├── requirements.txt compatibility installer
|
|
1297
|
+
├── README.md
|
|
1298
|
+
├── CHANGELOG.md
|
|
1299
|
+
├── CONTRIBUTING.md
|
|
1300
|
+
├── SECURITY.md
|
|
1301
|
+
└── LICENSE
|
|
1302
|
+
```
|
|
1303
|
+
|
|
1304
|
+
---
|
|
1305
|
+
|
|
1306
|
+
## License and third-party material
|
|
1307
|
+
|
|
1308
|
+
Project code is distributed under Apache-2.0. Model weights are downloaded separately and retain their respective licenses. Users are responsible for reviewing the license terms of any third-party models, datasets, or external assets they use with this package.
|