Fix generation from the published artifact; rewrite model card
Browse files- README.md +14 -7
- modeling_baguettotron_vlm.py +28 -9
README.md
CHANGED
|
@@ -16,8 +16,6 @@ tags:
|
|
| 16 |
base_model:
|
| 17 |
- OpenGVLab/InternViT-300M-448px-V2_5
|
| 18 |
- PleIAs/Baguettotron
|
| 19 |
-
datasets:
|
| 20 |
-
- liuhaotian/LLaVA-CC3M-Pretrain-595K
|
| 21 |
---
|
| 22 |
|
| 23 |
# baguettotron-internvit-alignment
|
|
@@ -38,9 +36,9 @@ Two checkpoints are published:
|
|
| 38 |
— instruction-tuned on top of it. It goes past plain description and follows visual
|
| 39 |
instructions, so prefer it for a richer chat experience.
|
| 40 |
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
-
|
| 44 |
|
| 45 |
|
| 46 |
> **Alignment checkpoint.** Only the MLP projector was trained (on LLaVA-CC3M-Pretrain-595K) — the ViT and the Baguettotron LLM are unmodified base weights. It writes short captions and nothing more. Published so the alignment stage can be reproduced; for actual use take [baguettotron-vision-vqa](https://huggingface.co/andreagemelli/baguettotron-vision-vqa).
|
|
@@ -98,13 +96,22 @@ Greedy, prompt `Describe the image concisely.` — verbatim output. Images from
|
|
| 98 |
|---|---|
|
| 99 |
| <img src="examples/cats.jpg" width="180"> | `a cat is sleeping on the couch` |
|
| 100 |
| <img src="examples/bear.jpg" width="180"> | `the bear is a good friend.` |
|
| 101 |
-
| <img src="examples/stop.jpg" width="180"> | `a sign for a stop
|
| 102 |
| <img src="examples/bus.jpg" width="180"> | `the bus is a red double - decoration` |
|
| 103 |
|
| 104 |
### Chat template
|
| 105 |
|
| 106 |
Trained on short image captions with no `<think>` traces. The processor emits a bare assistant prefix (`<|im_start|>assistant\n`) and the model completes the caption directly. Keep prompts simple ("Describe the image").
|
| 107 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 108 |
> Tested against `transformers` 4.57. Newer major versions may need adjustments.
|
| 109 |
|
| 110 |
**Contributions and suggestions are very welcome** — issues, PRs, and ideas for
|
|
@@ -130,4 +137,4 @@ If you use or extend Baguettotron-VLM in your research, please cite it:
|
|
| 130 |
|
| 131 |
## License
|
| 132 |
|
| 133 |
-
Apache 2.0 — see the [GitHub repo](https://github.com/andreagemelli/baguettotron-vlm).
|
|
|
|
| 16 |
base_model:
|
| 17 |
- OpenGVLab/InternViT-300M-448px-V2_5
|
| 18 |
- PleIAs/Baguettotron
|
|
|
|
|
|
|
| 19 |
---
|
| 20 |
|
| 21 |
# baguettotron-internvit-alignment
|
|
|
|
| 36 |
— instruction-tuned on top of it. It goes past plain description and follows visual
|
| 37 |
instructions, so prefer it for a richer chat experience.
|
| 38 |
|
| 39 |
+
Apache 2.0. Both live in the [Baguettotron-VLM collection](https://huggingface.co/collections/andreagemelli/baguettotron-vlm-69de37b4cab1960226e9c1f7).
|
| 40 |
+
Source: [github.com/andreagemelli/baguettotron-vlm](https://github.com/andreagemelli/baguettotron-vlm) ·
|
| 41 |
+
Write-up: [andreagemelli.me/posts/baguettotron-vlm](https://andreagemelli.me/posts/baguettotron-vlm/)
|
| 42 |
|
| 43 |
|
| 44 |
> **Alignment checkpoint.** Only the MLP projector was trained (on LLaVA-CC3M-Pretrain-595K) — the ViT and the Baguettotron LLM are unmodified base weights. It writes short captions and nothing more. Published so the alignment stage can be reproduced; for actual use take [baguettotron-vision-vqa](https://huggingface.co/andreagemelli/baguettotron-vision-vqa).
|
|
|
|
| 96 |
|---|---|
|
| 97 |
| <img src="examples/cats.jpg" width="180"> | `a cat is sleeping on the couch` |
|
| 98 |
| <img src="examples/bear.jpg" width="180"> | `the bear is a good friend.` |
|
| 99 |
+
| <img src="examples/stop.jpg" width="180"> | `a sign for a stop` |
|
| 100 |
| <img src="examples/bus.jpg" width="180"> | `the bus is a red double - decoration` |
|
| 101 |
|
| 102 |
### Chat template
|
| 103 |
|
| 104 |
Trained on short image captions with no `<think>` traces. The processor emits a bare assistant prefix (`<|im_start|>assistant\n`) and the model completes the caption directly. Keep prompts simple ("Describe the image").
|
| 105 |
|
| 106 |
+
## Limitations
|
| 107 |
+
|
| 108 |
+
- **Resolution ceiling.** One 448×448 crop → 256 visual tokens puts document text at
|
| 109 |
+
roughly 2–4 px/char. OCR, charts and documents are out of reach by architecture, not
|
| 110 |
+
by budget. Neither published checkpoint reads text in an image.
|
| 111 |
+
- **Hallucinations**, especially on fine-grained or text-heavy questions.
|
| 112 |
+
- **Multilingual capability is inherited, not verified.** The backbone covers six
|
| 113 |
+
languages; the VLM was never evaluated on non-English benchmarks.
|
| 114 |
+
|
| 115 |
> Tested against `transformers` 4.57. Newer major versions may need adjustments.
|
| 116 |
|
| 117 |
**Contributions and suggestions are very welcome** — issues, PRs, and ideas for
|
|
|
|
| 137 |
|
| 138 |
## License
|
| 139 |
|
| 140 |
+
Apache 2.0 — see the [GitHub repo](https://github.com/andreagemelli/baguettotron-vlm).
|
modeling_baguettotron_vlm.py
CHANGED
|
@@ -7,14 +7,36 @@ from transformers import (
|
|
| 7 |
AutoModel,
|
| 8 |
AutoModelForCausalLM,
|
| 9 |
AutoTokenizer,
|
|
|
|
| 10 |
PreTrainedModel,
|
| 11 |
StoppingCriteria,
|
| 12 |
)
|
|
|
|
| 13 |
from transformers.modeling_outputs import CausalLMOutputWithPast
|
| 14 |
|
| 15 |
from .configuration_baguettotron_vlm import BaguettotronVLMConfig
|
| 16 |
|
| 17 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 18 |
class StopOnTurnEnd(StoppingCriteria):
|
| 19 |
"""Stop when the decoded tail contains a turn marker.
|
| 20 |
|
|
@@ -237,25 +259,22 @@ class BaguettotronVLMForConditionalGeneration(PreTrainedModel):
|
|
| 237 |
)
|
| 238 |
)
|
| 239 |
|
| 240 |
-
# transformers' repetition-penalty processor corrupts the very first step
|
| 241 |
-
# on MPS: generate(inputs_embeds=...) starts from an empty input_ids, and
|
| 242 |
-
# the empty-index gather/scatter zeroes the entire logits row on Metal
|
| 243 |
-
# (it is a no-op on CPU and CUDA, as it should be). The result is a
|
| 244 |
-
# garbage first token that derails the whole answer.
|
| 245 |
-
if inputs_embeds.device.type == "mps" and repetition_penalty != 1.0:
|
| 246 |
-
repetition_penalty = 1.0
|
| 247 |
-
|
| 248 |
# do_sample defaults to greedy but can be overridden by callers
|
| 249 |
# (e.g. the inference sweep) without colliding on the keyword.
|
| 250 |
generate_kwargs.setdefault("do_sample", False)
|
| 251 |
generate_kwargs.setdefault(
|
| 252 |
"stopping_criteria", [StopOnTurnEnd(self._tokenizer)]
|
| 253 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 254 |
output_ids = self.llm.generate(
|
| 255 |
inputs_embeds=inputs_embeds,
|
| 256 |
attention_mask=attention_mask,
|
| 257 |
max_new_tokens=max_new_tokens,
|
| 258 |
-
repetition_penalty=repetition_penalty,
|
| 259 |
eos_token_id=eos_ids,
|
| 260 |
**generate_kwargs,
|
| 261 |
)
|
|
|
|
| 7 |
AutoModel,
|
| 8 |
AutoModelForCausalLM,
|
| 9 |
AutoTokenizer,
|
| 10 |
+
LogitsProcessor,
|
| 11 |
PreTrainedModel,
|
| 12 |
StoppingCriteria,
|
| 13 |
)
|
| 14 |
+
from transformers.generation.logits_process import RepetitionPenaltyLogitsProcessor
|
| 15 |
from transformers.modeling_outputs import CausalLMOutputWithPast
|
| 16 |
|
| 17 |
from .configuration_baguettotron_vlm import BaguettotronVLMConfig
|
| 18 |
|
| 19 |
|
| 20 |
+
class SafeRepetitionPenalty(LogitsProcessor):
|
| 21 |
+
"""Repetition penalty that is a no-op on the first decoding step.
|
| 22 |
+
|
| 23 |
+
generate(inputs_embeds=...) begins with an empty input_ids tensor. On MPS
|
| 24 |
+
the empty-index gather inside transformers' RepetitionPenaltyLogitsProcessor
|
| 25 |
+
zeroes the entire logits row rather than leaving it untouched (it is a
|
| 26 |
+
correct no-op on CPU and CUDA), which corrupts the first token and derails
|
| 27 |
+
the answer. There is nothing to penalise on that step anyway, so skipping it
|
| 28 |
+
removes the corruption while keeping the penalty for every later step.
|
| 29 |
+
"""
|
| 30 |
+
|
| 31 |
+
def __init__(self, penalty: float):
|
| 32 |
+
self.inner = RepetitionPenaltyLogitsProcessor(penalty)
|
| 33 |
+
|
| 34 |
+
def __call__(self, input_ids: torch.Tensor, scores: torch.Tensor) -> torch.Tensor:
|
| 35 |
+
if input_ids.shape[-1] == 0:
|
| 36 |
+
return scores
|
| 37 |
+
return self.inner(input_ids, scores)
|
| 38 |
+
|
| 39 |
+
|
| 40 |
class StopOnTurnEnd(StoppingCriteria):
|
| 41 |
"""Stop when the decoded tail contains a turn marker.
|
| 42 |
|
|
|
|
| 259 |
)
|
| 260 |
)
|
| 261 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 262 |
# do_sample defaults to greedy but can be overridden by callers
|
| 263 |
# (e.g. the inference sweep) without colliding on the keyword.
|
| 264 |
generate_kwargs.setdefault("do_sample", False)
|
| 265 |
generate_kwargs.setdefault(
|
| 266 |
"stopping_criteria", [StopOnTurnEnd(self._tokenizer)]
|
| 267 |
)
|
| 268 |
+
# The penalty goes through SafeRepetitionPenalty rather than generate()'s
|
| 269 |
+
# repetition_penalty kwarg, so the first decoding step is skipped.
|
| 270 |
+
if repetition_penalty != 1.0:
|
| 271 |
+
generate_kwargs.setdefault(
|
| 272 |
+
"logits_processor", [SafeRepetitionPenalty(repetition_penalty)]
|
| 273 |
+
)
|
| 274 |
output_ids = self.llm.generate(
|
| 275 |
inputs_embeds=inputs_embeds,
|
| 276 |
attention_mask=attention_mask,
|
| 277 |
max_new_tokens=max_new_tokens,
|
|
|
|
| 278 |
eos_token_id=eos_ids,
|
| 279 |
**generate_kwargs,
|
| 280 |
)
|