File size: 10,561 Bytes
86d0ebe
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52e58bc
 
 
 
 
86d0ebe
 
 
 
 
 
 
 
52e58bc
 
 
 
 
 
 
 
 
 
 
 
 
86d0ebe
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52e58bc
 
 
 
86d0ebe
 
52e58bc
86d0ebe
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
---
license: mit
language:
  - en
tags:
  - gemma3
  - multimodal
  - vision-language
  - ocr
  - synthetic-data
  - tinystories
  - validation
  - tiny-model
pipeline_tag: image-to-text
---

# tinygemma3ocr2m

`shibatch/tinygemma3ocr2m` is a tiny Gemma3-style multimodal validation checkpoint.

The model is intentionally small. It is designed to verify that a Gemma3 multimodal inference implementation can correctly run the full multimodal path:

```text
image -> vision tower -> multimodal projector -> image tokens -> text decoder -> generated text
```

It is **not** intended to be a general OCR model.

The checkpoint is trained on synthetic fixed-style digit OCR and mixed with a small amount of TinyStories text data so that the text decoder retains basic text-generation behavior.

## Model summary

```text
Repository:               shibatch/tinygemma3ocr2m
Model class:              Gemma3ForConditionalGeneration
Task:                     synthetic digit OCR + text-generation sanity
Image size:               128 x 128
Patch size:               16 x 16
Image tokens per image:   64
Image token:              <image>
Image token id:           1003
Approximate scale:        about 2M parameters
OCR prompt:               Read the digits.
OCR target format:        digit string only
```

The model is intended to be loaded with Hugging Face Transformers as `Gemma3ForConditionalGeneration`.

## Intended use

This checkpoint is mainly useful for validating custom Gemma3 multimodal inference implementations.

Typical checks include:

* vision tower weight loading;
* multimodal projector execution;
* image token insertion;
* text decoder generation after image conditioning;
* small-model CPU/GPU inference paths;
* safetensors key mapping and tensor layout assumptions.

The expected OCR validation behavior is:

```text
Input image:  synthetic 128x128 image containing centered digits
Prompt:       Read the digits.
Output:       the digit string
```

For example, a rendered image containing `6235317` should generate:

```text
6235317
```

## Non-goals and limitations

This model is deliberately narrow.

It is **not** a general OCR model. It should not be expected to handle natural images, documents, handwriting, rotated text, complex backgrounds, arbitrary fonts, tables, screenshots, Japanese text, or real-world scanned documents.

Known limitations:

* trained on synthetic digit images;
* primarily intended for fixed-style controlled rendering;
* prompt generalization is limited;
* text generation is only a sanity check and is not high quality;
* generated TinyStories-like text may contain repetition or malformed words;
* OCR robustness to strong augmentation is limited at this model scale;
* exact-match accuracy becomes harder for long digit strings because per-digit errors accumulate.

This checkpoint is best understood as a **minimal multimodal validation artifact**, not as a production OCR system.

## Training overview

The final checkpoint was produced in stages.

### Phase 1: text warmup

A small `Gemma3ForCausalLM` text model was trained on TinyStories. The resulting text weights were transplanted into a `Gemma3ForConditionalGeneration` checkpoint.

This transplant-based setup was used because direct text-only warmup inside the multimodal wrapper was less stable for this tiny configuration.

### Phase 2a: single-digit OCR

The model was trained to read one synthetic digit from a 128x128 image. The target output was the digit itself.

### Phase 2b: multi-digit OCR

The model was trained to read multi-digit synthetic images. The standard OCR prompt was:

```text
Read the digits.
```

The model learned to generate the digit string followed by EOS.

### Phase 2b plus text

The final checkpoint keeps the OCR distribution close to Phase 2b and mixes in TinyStories text batches as a light regularizer.

The purpose of the text mix is not to make the model a strong language model. It is only intended to prevent the text decoder from collapsing completely into OCR-only behavior.

A representative mixed-training configuration was:

```text
OCR ratio:         0.90
Text ratio:        0.10
OCR loss weight:   1.0
Text loss weight:  0.2
OCR style:         fixed synthetic digits
Font size:         30
Offset:            0
Rotation:          0
Noise:             0
Prompt:            Read the digits.
Digit length:      1 to 8
```

## Installation

```bash
pip install torch transformers pillow huggingface_hub numpy
```

## OCR example

The following example downloads a sample image from this repository and runs OCR.

```python
import torch, numpy as np
from PIL import Image
from huggingface_hub import hf_hub_download
from transformers import PreTrainedTokenizerFast, Gemma3ForConditionalGeneration

repo = "shibatch/tinygemma3ocr2m"

tok = PreTrainedTokenizerFast.from_pretrained(repo, subfolder="hf")
model = Gemma3ForConditionalGeneration.from_pretrained(
    repo, subfolder="hf", torch_dtype=torch.bfloat16
).cuda().eval()

path = hf_hub_download(repo, "sample_images/sample_00_6235317.png")
img = Image.open(path).convert("RGB")
pix = torch.from_numpy(np.asarray(img, dtype=np.float32) / 127.5 - 1).permute(2, 0, 1)[None].cuda()

ids = [tok.bos_token_id] + [model.config.image_token_index] * model.config.mm_tokens_per_image
ids += tok.encode("\nRead the digits.\n", add_special_tokens=False)

input_ids = torch.tensor([ids], device="cuda")
attention_mask = torch.ones_like(input_ids)

out = model.generate(
    input_ids=input_ids,
    attention_mask=attention_mask,
    pixel_values=pix,
    max_new_tokens=12,
    do_sample=False,
    pad_token_id=tok.bos_token_id,
    eos_token_id=tok.eos_token_id,
)

print(tok.decode(out[0][len(ids):], skip_special_tokens=True))
```

Expected output:

```text
6235317
```

## Text-generation sanity check

The checkpoint also supports direct text-decoder sanity checks through the language model branch.

This example intentionally does **not** use image tokens or `pixel_values`. It directly calls:

```text
model.model.language_model
model.lm_head
```

Example:

```python
import torch
from transformers import PreTrainedTokenizerFast, Gemma3ForConditionalGeneration

repo = "shibatch/tinygemma3ocr2m"
tok = PreTrainedTokenizerFast.from_pretrained(repo, subfolder="hf")
model = Gemma3ForConditionalGeneration.from_pretrained(
    repo, subfolder="hf", torch_dtype=torch.bfloat16
).cuda().eval()

ids = [tok.bos_token_id] + tok.encode("Once upon", add_special_tokens=False)
x = torch.tensor([ids], device="cuda")

for _ in range(50):
    h = model.model.language_model(input_ids=x, use_cache=False, return_dict=True).last_hidden_state
    nxt = model.lm_head(h)[0, -1].argmax().view(1, 1)
    x = torch.cat([x, nxt], dim=1)
    if int(nxt) == tok.eos_token_id:
        break

print(tok.decode(x[0], skip_special_tokens=True))
```

A successful sanity check means the model continues with roughly TinyStories-like English text. The output does not need to be high quality. The purpose is only to confirm that the text decoder has not collapsed into digit-only output.

Acceptable behavior:

```text
Once upon a time, there was a little girl named Lily...
```

Known imperfect behavior:

```text
malformed names
repetition
awkward TinyStories-like phrasing
occasional non-word fragments
```

These are expected for a model of this size and training mix.

## Evaluation notes

A representative OCR result for the intended fixed-style OCR setting was:

```text
exact_match:     0.87
digit_accuracy:  0.976
length_accuracy: 0.998
```

The important point is that the model can exercise the full multimodal path and produce digit strings with high accuracy in the intended fixed synthetic setting.

For longer digit strings, exact match is much stricter than digit accuracy. Even if each digit is correct with high probability, the probability of a fully correct 8-digit sequence is lower because all digits must be correct simultaneously.

## Recommended validation tests

### OCR smoke test

```bash
python test_inference_tinygemma3ocr2m.py \
  --model-dir shibatch/tinygemma3ocr2m \
  --text 1677216 \
  --font-size 30 \
  --prompt "Read the digits."
```

Expected output:

```text
Prediction:
  target: 1677216
  prediction: 1677216
  raw_text: '1677216'
```

### Batch synthetic OCR test

```bash
python test_inference_tinygemma3ocr2m.py \
  --model-dir shibatch/tinygemma3ocr2m \
  --eval-synthetic 500 \
  --min-digits 1 \
  --max-digits 8 \
  --font-size 30 \
  --prompt "Read the digits."
```

### Text sanity test

```bash
python test_text_generation_tinygemma3ocr2m.py \
  --model-dir shibatch/tinygemma3ocr2m \
  --prompt "Once upon" \
  --max-new-tokens 50
```

## Expected config properties

A correctly loaded 128x128 checkpoint should report:

```text
image_token_index:      1003
mm_tokens_per_image:    64
vision image_size:      128
vision patch_size:      16
```

If `mm_tokens_per_image` is not 64, or if the vision image size is not 128, the checkpoint is not the intended 128x128 model.

## File layout

The recommended repository layout is:

```text
shibatch/tinygemma3ocr2m
  README.md
  config.json
  model.safetensors
  tokenizer.json
  tokenizer_config.json
  special_tokens_map.json
  sample_images/
    sample_00_6235317.png
  sample_images.json
  eval_ocr_augmented.json
  eval_text_generation.json
  safetensors_keys.json
  artifact_metadata.json
```

The model files should be placed at the repository root so that this works:

```python
Gemma3ForConditionalGeneration.from_pretrained("shibatch/tinygemma3ocr2m")
PreTrainedTokenizerFast.from_pretrained("shibatch/tinygemma3ocr2m")
```

If the model files are instead placed under an `hf/` subdirectory, pass `subfolder="hf"` to `from_pretrained()`.

## Implementation notes

This checkpoint uses repeated `<image>` tokens in the text input. The number of inserted image tokens must match `mm_tokens_per_image`.

For this 128x128 checkpoint:

```text
image_size = 128
patch_size = 16
patch grid = 8 x 8
mm_tokens_per_image = 64
```

The OCR prompt format is approximately:

```text
<bos>
<image> repeated 64 times
\nRead the digits.\n
```

The target tokens are the digit string followed by EOS.

## Citation / attribution

This is a synthetic tiny validation checkpoint derived from a Gemma3-style architecture and trained for local inference-engine validation. TinyStories was used for basic text warmup and text regularization.

## Disclaimer

This model is for engineering validation and testing. It should not be used for real OCR tasks or user-facing document understanding.