Image-Text-to-Text
PaddleOCR
Safetensors
English
Chinese
multilingual
paddleocr_vl
ERNIE4.5
PaddlePaddle
image-to-text
ocr
document-parse
layout
table
formula
chart
conversational
custom_code
Eval Results
Instructions to use PaddlePaddle/PaddleOCR-VL with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- PaddleOCR
How to use PaddlePaddle/PaddleOCR-VL with PaddleOCR:
# See https://www.paddleocr.ai/latest/version3.x/pipeline_usage/PaddleOCR-VL.html to installation from paddleocr import PaddleOCRVL pipeline = PaddleOCRVL(pipeline_version="v1") output = pipeline.predict("path/to/document_image.png") for res in output: res.print() res.save_to_json(save_path="output") res.save_to_markdown(save_path="output") - Notebooks
- Google Colab
- Kaggle
Reuse native mask backends and unify protected initialization
Browse files- modeling_paddleocr_vl.py +100 -28
- tests/README.md +24 -8
- tests/compatibility_results.json +77 -42
- tests/test_remote_code_compat.py +116 -3
modeling_paddleocr_vl.py
CHANGED
|
@@ -16,6 +16,7 @@ import inspect
|
|
| 16 |
import math
|
| 17 |
import warnings
|
| 18 |
from dataclasses import dataclass
|
|
|
|
| 19 |
from typing import Any, Callable, Dict, List, Optional, Tuple, Union
|
| 20 |
|
| 21 |
import numpy as np
|
|
@@ -66,7 +67,81 @@ else:
|
|
| 66 |
from .configuration_paddleocr_vl import PaddleOCRVisionConfig, PaddleOCRVLConfig
|
| 67 |
|
| 68 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 69 |
def _create_causal_mask(config, inputs_embeds, attention_mask, past_key_values, cache_position):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 70 |
# Keep mask semantics local: Transformers renamed inputs and removed
|
| 71 |
# cache_position across releases. M-RoPE coordinates are handled separately.
|
| 72 |
if attention_mask is not None and attention_mask.ndim == 4:
|
|
@@ -106,7 +181,7 @@ def _init_derived_buffers(module):
|
|
| 106 |
inv_freq, module.attention_scaling = module.rope_init_fn(
|
| 107 |
module.config, device=module.inv_freq.device
|
| 108 |
)
|
| 109 |
-
module.inv_freq
|
| 110 |
module.original_inv_freq = module.inv_freq
|
| 111 |
elif isinstance(module, SigLIPRotaryEmbedding):
|
| 112 |
inv_freq = 1.0 / (
|
|
@@ -115,9 +190,9 @@ def _init_derived_buffers(module):
|
|
| 115 |
/ module.dim
|
| 116 |
)
|
| 117 |
)
|
| 118 |
-
module.inv_freq
|
| 119 |
elif isinstance(module, PaddleOCRVisionEmbeddings):
|
| 120 |
-
module.position_ids
|
| 121 |
torch.arange(module.num_positions, device=module.position_ids.device).expand(1, -1)
|
| 122 |
)
|
| 123 |
|
|
@@ -781,9 +856,8 @@ class Ernie4_5ForCausalLM(Ernie4_5PreTrainedModel, GenerationMixin):
|
|
| 781 |
)
|
| 782 |
|
| 783 |
|
|
|
|
| 784 |
def _trunc_normal_(tensor, mean, std, a, b):
|
| 785 |
-
if getattr(tensor, "_is_hf_initialized", False):
|
| 786 |
-
return tensor
|
| 787 |
# Cut & paste from PyTorch official master until it's in a few official releases - RW
|
| 788 |
# Method based on https://people.sc.fsu.edu/~jburkardt/presentations/truncated_normal.pdf
|
| 789 |
def norm_cdf(x):
|
|
@@ -819,6 +893,7 @@ def _trunc_normal_(tensor, mean, std, a, b):
|
|
| 819 |
tensor.clamp_(min=a, max=b)
|
| 820 |
|
| 821 |
|
|
|
|
| 822 |
def trunc_normal_tf_(
|
| 823 |
tensor: torch.Tensor,
|
| 824 |
mean: float = 0.0,
|
|
@@ -844,16 +919,13 @@ def trunc_normal_tf_(
|
|
| 844 |
a: the minimum cutoff value
|
| 845 |
b: the maximum cutoff value
|
| 846 |
"""
|
| 847 |
-
if getattr(tensor, "_is_hf_initialized", False):
|
| 848 |
-
return tensor
|
| 849 |
with torch.no_grad():
|
| 850 |
_trunc_normal_(tensor, 0, 1.0, a, b)
|
| 851 |
tensor.mul_(std).add_(mean)
|
| 852 |
|
| 853 |
|
|
|
|
| 854 |
def variance_scaling_(tensor, scale=1.0, mode="fan_in", distribution="normal"):
|
| 855 |
-
if getattr(tensor, "_is_hf_initialized", False):
|
| 856 |
-
return tensor
|
| 857 |
fan_in, fan_out = _calculate_fan_in_and_fan_out(tensor)
|
| 858 |
if mode == "fan_in":
|
| 859 |
denom = fan_in
|
|
@@ -1369,34 +1441,34 @@ class PaddleOCRPreTrainedModel(PreTrainedModel):
|
|
| 1369 |
if isinstance(self.config, PaddleOCRVLConfig)
|
| 1370 |
else self.config.hidden_size
|
| 1371 |
)
|
| 1372 |
-
|
| 1373 |
elif isinstance(module, nn.Embedding):
|
| 1374 |
default_flax_embed_init(module.weight)
|
| 1375 |
elif isinstance(module, PaddleOCRAttention):
|
| 1376 |
-
|
| 1377 |
-
|
| 1378 |
-
|
| 1379 |
-
|
| 1380 |
-
|
| 1381 |
-
|
| 1382 |
-
|
| 1383 |
-
|
| 1384 |
elif isinstance(module, PaddleOCRMLP):
|
| 1385 |
-
|
| 1386 |
-
|
| 1387 |
-
|
| 1388 |
-
|
| 1389 |
elif isinstance(module, PaddleOCRMultiheadAttentionPoolingHead):
|
| 1390 |
-
|
| 1391 |
-
|
| 1392 |
-
|
| 1393 |
elif isinstance(module, (nn.Linear, nn.Conv2d)):
|
| 1394 |
lecun_normal_(module.weight)
|
| 1395 |
if module.bias is not None:
|
| 1396 |
-
|
| 1397 |
elif isinstance(module, nn.LayerNorm):
|
| 1398 |
-
|
| 1399 |
-
|
| 1400 |
|
| 1401 |
|
| 1402 |
# Copied from transformers.models.altclip.modeling_altclip.AltCLIPEncoder with AltCLIP->PaddleOCR
|
|
|
|
| 16 |
import math
|
| 17 |
import warnings
|
| 18 |
from dataclasses import dataclass
|
| 19 |
+
from functools import wraps
|
| 20 |
from typing import Any, Callable, Dict, List, Optional, Tuple, Union
|
| 21 |
|
| 22 |
import numpy as np
|
|
|
|
| 67 |
from .configuration_paddleocr_vl import PaddleOCRVisionConfig, PaddleOCRVLConfig
|
| 68 |
|
| 69 |
|
| 70 |
+
# Resolve optional framework interfaces once, outside the forward path.
|
| 71 |
+
try:
|
| 72 |
+
from transformers.masking_utils import create_causal_mask as _hf_create_causal_mask
|
| 73 |
+
except ImportError:
|
| 74 |
+
_hf_create_causal_mask = None
|
| 75 |
+
|
| 76 |
+
try:
|
| 77 |
+
from transformers import initialization as _hf_initialization
|
| 78 |
+
except ImportError:
|
| 79 |
+
_hf_initialization = None
|
| 80 |
+
|
| 81 |
+
try:
|
| 82 |
+
_HF_MASK_PARAMETERS = frozenset(inspect.signature(_hf_create_causal_mask).parameters)
|
| 83 |
+
except (TypeError, ValueError):
|
| 84 |
+
_HF_MASK_PARAMETERS = frozenset()
|
| 85 |
+
|
| 86 |
+
_HF_MASK_INPUT_NAME = next(
|
| 87 |
+
(name for name in ("inputs_embeds", "input_embeds") if name in _HF_MASK_PARAMETERS), None
|
| 88 |
+
)
|
| 89 |
+
|
| 90 |
+
|
| 91 |
+
def _guard_initializer(function):
|
| 92 |
+
@wraps(function)
|
| 93 |
+
def initialize(tensor, *args, **kwargs):
|
| 94 |
+
if getattr(tensor, "_is_hf_initialized", False):
|
| 95 |
+
return tensor
|
| 96 |
+
with torch.no_grad():
|
| 97 |
+
return function(tensor, *args, **kwargs)
|
| 98 |
+
return initialize
|
| 99 |
+
|
| 100 |
+
|
| 101 |
+
@_guard_initializer
|
| 102 |
+
def _init_tensor(tensor, operation, *args, **kwargs):
|
| 103 |
+
# Standard primitives use the framework's protected implementation when
|
| 104 |
+
# present. Keep model-specific TF/LeCun sampling formulas below unchanged.
|
| 105 |
+
function = getattr(_hf_initialization, operation, None)
|
| 106 |
+
if function is not None:
|
| 107 |
+
return function(tensor, *args, **kwargs)
|
| 108 |
+
if operation == "copy_":
|
| 109 |
+
return tensor.copy_(*args, **kwargs)
|
| 110 |
+
return getattr(nn.init, operation)(tensor, *args, **kwargs)
|
| 111 |
+
|
| 112 |
+
|
| 113 |
def _create_causal_mask(config, inputs_embeds, attention_mask, past_key_values, cache_position):
|
| 114 |
+
if attention_mask is not None and attention_mask.ndim == 4:
|
| 115 |
+
mask = attention_mask.to(device=inputs_embeds.device)
|
| 116 |
+
if mask.dtype == torch.bool:
|
| 117 |
+
additive = torch.zeros(mask.shape, device=mask.device, dtype=inputs_embeds.dtype)
|
| 118 |
+
return additive.masked_fill(~mask, torch.finfo(inputs_embeds.dtype).min)
|
| 119 |
+
return mask.to(dtype=inputs_embeds.dtype)
|
| 120 |
+
|
| 121 |
+
cache_supported = past_key_values is None or (
|
| 122 |
+
hasattr(past_key_values, "get_mask_sizes")
|
| 123 |
+
and ("cache_position" in _HF_MASK_PARAMETERS or hasattr(past_key_values, "get_query_offset"))
|
| 124 |
+
)
|
| 125 |
+
if _hf_create_causal_mask is not None and _HF_MASK_INPUT_NAME is not None and cache_supported:
|
| 126 |
+
mask_kwargs = {
|
| 127 |
+
"config": config,
|
| 128 |
+
_HF_MASK_INPUT_NAME: inputs_embeds,
|
| 129 |
+
"attention_mask": attention_mask,
|
| 130 |
+
"past_key_values": past_key_values,
|
| 131 |
+
}
|
| 132 |
+
if "cache_position" in _HF_MASK_PARAMETERS:
|
| 133 |
+
mask_kwargs["cache_position"] = cache_position
|
| 134 |
+
if "position_ids" in _HF_MASK_PARAMETERS:
|
| 135 |
+
# 3D M-RoPE coordinates are not packed text-sequence positions.
|
| 136 |
+
mask_kwargs["position_ids"] = None
|
| 137 |
+
return _hf_create_causal_mask(**mask_kwargs)
|
| 138 |
+
|
| 139 |
+
return _create_causal_mask_fallback(
|
| 140 |
+
config, inputs_embeds, attention_mask, past_key_values, cache_position
|
| 141 |
+
)
|
| 142 |
+
|
| 143 |
+
|
| 144 |
+
def _create_causal_mask_fallback(config, inputs_embeds, attention_mask, past_key_values, cache_position):
|
| 145 |
# Keep mask semantics local: Transformers renamed inputs and removed
|
| 146 |
# cache_position across releases. M-RoPE coordinates are handled separately.
|
| 147 |
if attention_mask is not None and attention_mask.ndim == 4:
|
|
|
|
| 181 |
inv_freq, module.attention_scaling = module.rope_init_fn(
|
| 182 |
module.config, device=module.inv_freq.device
|
| 183 |
)
|
| 184 |
+
_init_tensor(module.inv_freq, "copy_", inv_freq)
|
| 185 |
module.original_inv_freq = module.inv_freq
|
| 186 |
elif isinstance(module, SigLIPRotaryEmbedding):
|
| 187 |
inv_freq = 1.0 / (
|
|
|
|
| 190 |
/ module.dim
|
| 191 |
)
|
| 192 |
)
|
| 193 |
+
_init_tensor(module.inv_freq, "copy_", inv_freq)
|
| 194 |
elif isinstance(module, PaddleOCRVisionEmbeddings):
|
| 195 |
+
_init_tensor(module.position_ids, "copy_",
|
| 196 |
torch.arange(module.num_positions, device=module.position_ids.device).expand(1, -1)
|
| 197 |
)
|
| 198 |
|
|
|
|
| 856 |
)
|
| 857 |
|
| 858 |
|
| 859 |
+
@_guard_initializer
|
| 860 |
def _trunc_normal_(tensor, mean, std, a, b):
|
|
|
|
|
|
|
| 861 |
# Cut & paste from PyTorch official master until it's in a few official releases - RW
|
| 862 |
# Method based on https://people.sc.fsu.edu/~jburkardt/presentations/truncated_normal.pdf
|
| 863 |
def norm_cdf(x):
|
|
|
|
| 893 |
tensor.clamp_(min=a, max=b)
|
| 894 |
|
| 895 |
|
| 896 |
+
@_guard_initializer
|
| 897 |
def trunc_normal_tf_(
|
| 898 |
tensor: torch.Tensor,
|
| 899 |
mean: float = 0.0,
|
|
|
|
| 919 |
a: the minimum cutoff value
|
| 920 |
b: the maximum cutoff value
|
| 921 |
"""
|
|
|
|
|
|
|
| 922 |
with torch.no_grad():
|
| 923 |
_trunc_normal_(tensor, 0, 1.0, a, b)
|
| 924 |
tensor.mul_(std).add_(mean)
|
| 925 |
|
| 926 |
|
| 927 |
+
@_guard_initializer
|
| 928 |
def variance_scaling_(tensor, scale=1.0, mode="fan_in", distribution="normal"):
|
|
|
|
|
|
|
| 929 |
fan_in, fan_out = _calculate_fan_in_and_fan_out(tensor)
|
| 930 |
if mode == "fan_in":
|
| 931 |
denom = fan_in
|
|
|
|
| 1441 |
if isinstance(self.config, PaddleOCRVLConfig)
|
| 1442 |
else self.config.hidden_size
|
| 1443 |
)
|
| 1444 |
+
_init_tensor(module.position_embedding.weight, 'normal_', std=1 / np.sqrt(width))
|
| 1445 |
elif isinstance(module, nn.Embedding):
|
| 1446 |
default_flax_embed_init(module.weight)
|
| 1447 |
elif isinstance(module, PaddleOCRAttention):
|
| 1448 |
+
_init_tensor(module.q_proj.weight, 'xavier_uniform_')
|
| 1449 |
+
_init_tensor(module.k_proj.weight, 'xavier_uniform_')
|
| 1450 |
+
_init_tensor(module.v_proj.weight, 'xavier_uniform_')
|
| 1451 |
+
_init_tensor(module.out_proj.weight, 'xavier_uniform_')
|
| 1452 |
+
_init_tensor(module.q_proj.bias, 'zeros_')
|
| 1453 |
+
_init_tensor(module.k_proj.bias, 'zeros_')
|
| 1454 |
+
_init_tensor(module.v_proj.bias, 'zeros_')
|
| 1455 |
+
_init_tensor(module.out_proj.bias, 'zeros_')
|
| 1456 |
elif isinstance(module, PaddleOCRMLP):
|
| 1457 |
+
_init_tensor(module.fc1.weight, 'xavier_uniform_')
|
| 1458 |
+
_init_tensor(module.fc2.weight, 'xavier_uniform_')
|
| 1459 |
+
_init_tensor(module.fc1.bias, 'normal_', std=1e-6)
|
| 1460 |
+
_init_tensor(module.fc2.bias, 'normal_', std=1e-6)
|
| 1461 |
elif isinstance(module, PaddleOCRMultiheadAttentionPoolingHead):
|
| 1462 |
+
_init_tensor(module.probe, 'xavier_uniform_')
|
| 1463 |
+
_init_tensor(module.attention.in_proj_weight, 'xavier_uniform_')
|
| 1464 |
+
_init_tensor(module.attention.in_proj_bias, 'zeros_')
|
| 1465 |
elif isinstance(module, (nn.Linear, nn.Conv2d)):
|
| 1466 |
lecun_normal_(module.weight)
|
| 1467 |
if module.bias is not None:
|
| 1468 |
+
_init_tensor(module.bias, 'zeros_')
|
| 1469 |
elif isinstance(module, nn.LayerNorm):
|
| 1470 |
+
_init_tensor(module.bias, 'zeros_')
|
| 1471 |
+
_init_tensor(module.weight, 'ones_')
|
| 1472 |
|
| 1473 |
|
| 1474 |
# Copied from transformers.models.altclip.modeling_altclip.AltCLIPEncoder with AltCLIP->PaddleOCR
|
tests/README.md
CHANGED
|
@@ -1,20 +1,36 @@
|
|
| 1 |
# Remote-code compatibility regression
|
| 2 |
|
| 3 |
-
|
| 4 |
|
| 5 |
```bash
|
| 6 |
python -m pip install einops sentencepiece protobuf
|
| 7 |
python tests/test_remote_code_compat.py --full --model . --inputs tests/data --output /tmp/paddleocr-vl-compat
|
| 8 |
```
|
| 9 |
|
| 10 |
-
|
|
|
|
|
|
|
| 11 |
|
| 12 |
-
|
|
|
|
|
|
|
|
|
|
| 13 |
|
| 14 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
|
| 16 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
|
|
|
| 1 |
# Remote-code compatibility regression
|
| 2 |
|
| 3 |
+
Use a model checkout containing its official checkpoint and tokenizer files:
|
| 4 |
|
| 5 |
```bash
|
| 6 |
python -m pip install einops sentencepiece protobuf
|
| 7 |
python tests/test_remote_code_compat.py --full --model . --inputs tests/data --output /tmp/paddleocr-vl-compat
|
| 8 |
```
|
| 9 |
|
| 10 |
+
The script uses AutoModelForCausalLM / AutoProcessor with trust_remote_code=True,
|
| 11 |
+
CPU float32, local files, and an isolated dynamic-module cache. Use a separate
|
| 12 |
+
process/environment for each Transformers release. No Transformers pin is added.
|
| 13 |
|
| 14 |
+
Full checks compare every loaded parameter with the checkpoint; validate text
|
| 15 |
+
and vision RoPE and vision position-ID buffers; cover mask semantics, English
|
| 16 |
+
OCR/EOS, cached versus complete uncached token equality, Chinese/batched OCR,
|
| 17 |
+
batch-prefill isolation, and table recognition.
|
| 18 |
|
| 19 |
+
The backend contract checks cover eager/SDPA prefill and cached decode with and
|
| 20 |
+
without left padding, the unpadded SDPA no-mask fast path, the local fallback,
|
| 21 |
+
propagation of native backend exceptions, and StaticCache mask capacity/padding.
|
| 22 |
+
Initializer checks protect already-loaded tensors and preserve TF-style
|
| 23 |
+
truncation. They also run without checkpoint weights:
|
| 24 |
|
| 25 |
+
```bash
|
| 26 |
+
python tests/test_remote_code_compat.py --helpers-only --model . --output /tmp/paddleocr-vl-helpers
|
| 27 |
+
```
|
| 28 |
+
|
| 29 |
+
compatibility_results.json records this model's executed releases and scope.
|
| 30 |
+
StaticCache mask construction is covered; full-model StaticCache generation,
|
| 31 |
+
CUDA/MPS, low precision, FlashAttention, training, dataset-level accuracy and
|
| 32 |
+
performance, and every historical/intermediate/future release are not verified.
|
| 33 |
|
| 34 |
+
Fixtures: invoice_en.png and table_en.png are synthetic images. The Chinese
|
| 35 |
+
fixture paddle_general_ocr_001.png comes from the official synthetic assets:
|
| 36 |
+
https://huggingface.co/datasets/hf-internal-testing/transformers-synthetic-assets/resolve/main/images/paddle_general_ocr_001.png
|
tests/compatibility_results.json
CHANGED
|
@@ -1,109 +1,144 @@
|
|
| 1 |
{
|
| 2 |
"model": "PaddlePaddle/PaddleOCR-VL",
|
| 3 |
"revision": "7fa00a8c55b735ba51ba49a9058f3f9c57a99a11",
|
|
|
|
| 4 |
"trust_remote_code": true,
|
| 5 |
"validation_scope": "full checkpoint and generation",
|
| 6 |
-
"full_checkpoint_pending": false,
|
| 7 |
"device": "cpu",
|
| 8 |
"dtype": "float32",
|
| 9 |
-
"
|
| 10 |
"tested_versions": [
|
| 11 |
"4.57.6",
|
| 12 |
"5.0.0",
|
| 13 |
"5.21.1"
|
| 14 |
],
|
| 15 |
"same_source_sha256": {
|
| 16 |
-
"modeling_paddleocr_vl.py": "
|
| 17 |
"image_processing_paddleocr_vl.py": "a4fa521b9cb16e207f94b7f2d16427771776dfc634420d319fc4916ee58049ec",
|
| 18 |
"processing_paddleocr_vl.py": "e29cb1e5f275f2bd3ce051bd5c9983a33894e693b2823a0e13d4c07c8c4f9e13",
|
| 19 |
"configuration_paddleocr_vl.py": "753dd93654c3a9c8c85a3eaee1e3092dd12591b0f2dce0305e1abfb7a41ff160"
|
| 20 |
},
|
| 21 |
"all_tested_passed": true,
|
| 22 |
"universal_historical_or_future_support_claimed": false,
|
| 23 |
-
"
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
"exception_type": "TypeError",
|
| 29 |
-
"error": "create_causal_mask() got an unexpected keyword argument 'inputs_embeds'",
|
| 30 |
-
"expected_failure": true
|
| 31 |
-
},
|
| 32 |
-
{
|
| 33 |
-
"transformers": "5.0.0",
|
| 34 |
-
"stage": null,
|
| 35 |
-
"exception_type": "KeyError",
|
| 36 |
-
"error": "'default'",
|
| 37 |
-
"expected_failure": true
|
| 38 |
-
},
|
| 39 |
-
{
|
| 40 |
-
"transformers": "5.21.1",
|
| 41 |
-
"stage": null,
|
| 42 |
-
"exception_type": "KeyError",
|
| 43 |
-
"error": "'default'",
|
| 44 |
-
"expected_failure": true
|
| 45 |
-
}
|
| 46 |
-
],
|
| 47 |
"versions": [
|
| 48 |
{
|
| 49 |
"version": "4.57.6",
|
| 50 |
"passed": true,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 51 |
"stages": [
|
| 52 |
"config",
|
| 53 |
"processor",
|
| 54 |
"model",
|
| 55 |
"weights_and_buffers",
|
| 56 |
"mask_semantics",
|
|
|
|
| 57 |
"english_generate",
|
| 58 |
"uncached_prefix",
|
| 59 |
"batch_prefill_isolation",
|
| 60 |
"uncached_full_english",
|
| 61 |
"full_chinese_batch_table"
|
| 62 |
-
]
|
| 63 |
-
"parameter_mismatches": 0,
|
| 64 |
-
"batch_logits_max_abs_difference": 4.3392181396484375e-05,
|
| 65 |
-
"uncached_full_english_matches_cached": true,
|
| 66 |
-
"full_batch_matches_individual": true
|
| 67 |
},
|
| 68 |
{
|
| 69 |
"version": "5.0.0",
|
| 70 |
"passed": true,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 71 |
"stages": [
|
| 72 |
"config",
|
| 73 |
"processor",
|
| 74 |
"model",
|
| 75 |
"weights_and_buffers",
|
| 76 |
"mask_semantics",
|
|
|
|
| 77 |
"english_generate",
|
| 78 |
"uncached_prefix",
|
| 79 |
"batch_prefill_isolation",
|
| 80 |
"uncached_full_english",
|
| 81 |
"full_chinese_batch_table"
|
| 82 |
-
]
|
| 83 |
-
"parameter_mismatches": 0,
|
| 84 |
-
"batch_logits_max_abs_difference": 4.3392181396484375e-05,
|
| 85 |
-
"uncached_full_english_matches_cached": true,
|
| 86 |
-
"full_batch_matches_individual": true
|
| 87 |
},
|
| 88 |
{
|
| 89 |
"version": "5.21.1",
|
| 90 |
"passed": true,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 91 |
"stages": [
|
| 92 |
"config",
|
| 93 |
"processor",
|
| 94 |
"model",
|
| 95 |
"weights_and_buffers",
|
| 96 |
"mask_semantics",
|
|
|
|
| 97 |
"english_generate",
|
| 98 |
"uncached_prefix",
|
| 99 |
"batch_prefill_isolation",
|
| 100 |
"uncached_full_english",
|
| 101 |
"full_chinese_batch_table"
|
| 102 |
-
]
|
| 103 |
-
"parameter_mismatches": 0,
|
| 104 |
-
"batch_logits_max_abs_difference": 4.3392181396484375e-05,
|
| 105 |
-
"uncached_full_english_matches_cached": true,
|
| 106 |
-
"full_batch_matches_individual": true
|
| 107 |
}
|
| 108 |
]
|
| 109 |
}
|
|
|
|
| 1 |
{
|
| 2 |
"model": "PaddlePaddle/PaddleOCR-VL",
|
| 3 |
"revision": "7fa00a8c55b735ba51ba49a9058f3f9c57a99a11",
|
| 4 |
+
"checkpoint_sha256": "3085f1042e184f68f8a412aa0f64f2c4b8562989598bbfba326aaa11fc685de8",
|
| 5 |
"trust_remote_code": true,
|
| 6 |
"validation_scope": "full checkpoint and generation",
|
|
|
|
| 7 |
"device": "cpu",
|
| 8 |
"dtype": "float32",
|
| 9 |
+
"full_checkpoint_pending": false,
|
| 10 |
"tested_versions": [
|
| 11 |
"4.57.6",
|
| 12 |
"5.0.0",
|
| 13 |
"5.21.1"
|
| 14 |
],
|
| 15 |
"same_source_sha256": {
|
| 16 |
+
"modeling_paddleocr_vl.py": "27099e51f7ab16df18273bea955b3357abf3e92562f95dc1b857b6dd10c7e2e8",
|
| 17 |
"image_processing_paddleocr_vl.py": "a4fa521b9cb16e207f94b7f2d16427771776dfc634420d319fc4916ee58049ec",
|
| 18 |
"processing_paddleocr_vl.py": "e29cb1e5f275f2bd3ce051bd5c9983a33894e693b2823a0e13d4c07c8c4f9e13",
|
| 19 |
"configuration_paddleocr_vl.py": "753dd93654c3a9c8c85a3eaee1e3092dd12591b0f2dce0305e1abfb7a41ff160"
|
| 20 |
},
|
| 21 |
"all_tested_passed": true,
|
| 22 |
"universal_historical_or_future_support_claimed": false,
|
| 23 |
+
"initializer_equivalence": {
|
| 24 |
+
"cases": 36,
|
| 25 |
+
"all_equal": true,
|
| 26 |
+
"reference_source_sha256": "d01a9847b5e4142e5aa35c28f2354fae920ab31b2f990216db39287d344758ce"
|
| 27 |
+
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 28 |
"versions": [
|
| 29 |
{
|
| 30 |
"version": "4.57.6",
|
| 31 |
"passed": true,
|
| 32 |
+
"parameter_mismatches": 0,
|
| 33 |
+
"batch_logits_max_abs_difference": 4.3392181396484375e-05,
|
| 34 |
+
"uncached_full_english_matches_cached": true,
|
| 35 |
+
"full_batch_matches_individual": true,
|
| 36 |
+
"backend_contracts": {
|
| 37 |
+
"mask_cases": 12,
|
| 38 |
+
"max_valid_token_difference": 0.0,
|
| 39 |
+
"sdpa_fast_path": true,
|
| 40 |
+
"fallback_exercised": true,
|
| 41 |
+
"backend_errors_propagate": true,
|
| 42 |
+
"static_cache_mask": true,
|
| 43 |
+
"loaded_initializer_guards": true,
|
| 44 |
+
"tf_truncation_preserved": true,
|
| 45 |
+
"native_mask_input_name": "input_embeds",
|
| 46 |
+
"native_mask_requires_cache_position": true
|
| 47 |
+
},
|
| 48 |
+
"previous_revision_comparison": {
|
| 49 |
+
"english_token_ids_unchanged": true,
|
| 50 |
+
"batch_text_unchanged": true,
|
| 51 |
+
"table_text_unchanged": true
|
| 52 |
+
},
|
| 53 |
"stages": [
|
| 54 |
"config",
|
| 55 |
"processor",
|
| 56 |
"model",
|
| 57 |
"weights_and_buffers",
|
| 58 |
"mask_semantics",
|
| 59 |
+
"backend_contracts",
|
| 60 |
"english_generate",
|
| 61 |
"uncached_prefix",
|
| 62 |
"batch_prefill_isolation",
|
| 63 |
"uncached_full_english",
|
| 64 |
"full_chinese_batch_table"
|
| 65 |
+
]
|
|
|
|
|
|
|
|
|
|
|
|
|
| 66 |
},
|
| 67 |
{
|
| 68 |
"version": "5.0.0",
|
| 69 |
"passed": true,
|
| 70 |
+
"parameter_mismatches": 0,
|
| 71 |
+
"batch_logits_max_abs_difference": 4.3392181396484375e-05,
|
| 72 |
+
"uncached_full_english_matches_cached": true,
|
| 73 |
+
"full_batch_matches_individual": true,
|
| 74 |
+
"backend_contracts": {
|
| 75 |
+
"mask_cases": 12,
|
| 76 |
+
"max_valid_token_difference": 0.0,
|
| 77 |
+
"sdpa_fast_path": true,
|
| 78 |
+
"fallback_exercised": true,
|
| 79 |
+
"backend_errors_propagate": true,
|
| 80 |
+
"static_cache_mask": true,
|
| 81 |
+
"loaded_initializer_guards": true,
|
| 82 |
+
"tf_truncation_preserved": true,
|
| 83 |
+
"native_mask_input_name": "input_embeds",
|
| 84 |
+
"native_mask_requires_cache_position": true
|
| 85 |
+
},
|
| 86 |
+
"previous_revision_comparison": {
|
| 87 |
+
"english_token_ids_unchanged": true,
|
| 88 |
+
"batch_text_unchanged": true,
|
| 89 |
+
"table_text_unchanged": true
|
| 90 |
+
},
|
| 91 |
"stages": [
|
| 92 |
"config",
|
| 93 |
"processor",
|
| 94 |
"model",
|
| 95 |
"weights_and_buffers",
|
| 96 |
"mask_semantics",
|
| 97 |
+
"backend_contracts",
|
| 98 |
"english_generate",
|
| 99 |
"uncached_prefix",
|
| 100 |
"batch_prefill_isolation",
|
| 101 |
"uncached_full_english",
|
| 102 |
"full_chinese_batch_table"
|
| 103 |
+
]
|
|
|
|
|
|
|
|
|
|
|
|
|
| 104 |
},
|
| 105 |
{
|
| 106 |
"version": "5.21.1",
|
| 107 |
"passed": true,
|
| 108 |
+
"parameter_mismatches": 0,
|
| 109 |
+
"batch_logits_max_abs_difference": 4.3392181396484375e-05,
|
| 110 |
+
"uncached_full_english_matches_cached": true,
|
| 111 |
+
"full_batch_matches_individual": true,
|
| 112 |
+
"backend_contracts": {
|
| 113 |
+
"mask_cases": 12,
|
| 114 |
+
"max_valid_token_difference": 0.0,
|
| 115 |
+
"sdpa_fast_path": true,
|
| 116 |
+
"fallback_exercised": true,
|
| 117 |
+
"backend_errors_propagate": true,
|
| 118 |
+
"static_cache_mask": true,
|
| 119 |
+
"loaded_initializer_guards": true,
|
| 120 |
+
"tf_truncation_preserved": true,
|
| 121 |
+
"native_mask_input_name": "inputs_embeds",
|
| 122 |
+
"native_mask_requires_cache_position": false
|
| 123 |
+
},
|
| 124 |
+
"previous_revision_comparison": {
|
| 125 |
+
"english_token_ids_unchanged": true,
|
| 126 |
+
"batch_text_unchanged": true,
|
| 127 |
+
"table_text_unchanged": true
|
| 128 |
+
},
|
| 129 |
"stages": [
|
| 130 |
"config",
|
| 131 |
"processor",
|
| 132 |
"model",
|
| 133 |
"weights_and_buffers",
|
| 134 |
"mask_semantics",
|
| 135 |
+
"backend_contracts",
|
| 136 |
"english_generate",
|
| 137 |
"uncached_prefix",
|
| 138 |
"batch_prefill_isolation",
|
| 139 |
"uncached_full_english",
|
| 140 |
"full_chinese_batch_table"
|
| 141 |
+
]
|
|
|
|
|
|
|
|
|
|
|
|
|
| 142 |
}
|
| 143 |
]
|
| 144 |
}
|
tests/test_remote_code_compat.py
CHANGED
|
@@ -11,6 +11,7 @@ from pathlib import Path
|
|
| 11 |
args_parser=argparse.ArgumentParser()
|
| 12 |
args_parser.add_argument('--imports-only',action='store_true')
|
| 13 |
args_parser.add_argument('--full',action='store_true')
|
|
|
|
| 14 |
args_parser.add_argument('--model',type=Path)
|
| 15 |
args_parser.add_argument('--inputs',type=Path)
|
| 16 |
args_parser.add_argument('--output',type=Path)
|
|
@@ -25,9 +26,9 @@ OUT.mkdir(parents=True,exist_ok=True)
|
|
| 25 |
os.environ['HF_MODULES_CACHE']=str(OUT/'modules')
|
| 26 |
os.environ['HF_HUB_OFFLINE']='1'
|
| 27 |
os.environ['TOKENIZERS_PARALLELISM']='false'
|
| 28 |
-
report={'transformers':VERSION,'trust_remote_code':True,'mode':'imports' if args.imports_only else 'full' if args.full else 'matrix','pid':os.getpid(),'started_at':time.strftime('%Y-%m-%dT%H:%M:%SZ',time.gmtime()),'stages':{}}
|
| 29 |
report['source_sha256']={p.name:hashlib.sha256(p.read_bytes()).hexdigest() for p in MODEL.glob('*.py')}
|
| 30 |
-
def save(): (OUT/('imports.json' if args.imports_only else 'full.json' if args.full else 'results.json')).write_text(json.dumps(report,ensure_ascii=False,indent=2,default=str)+'\n')
|
| 31 |
def step(name,fn):
|
| 32 |
started=time.perf_counter()
|
| 33 |
try:
|
|
@@ -36,6 +37,111 @@ def step(name,fn):
|
|
| 36 |
except Exception as exc:
|
| 37 |
report['stages'][name]={'passed':False,'error':str(exc),'traceback':traceback.format_exc()}
|
| 38 |
print(name,type(exc).__name__,str(exc),flush=True);save();raise
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 39 |
try:
|
| 40 |
import torch,transformers,tokenizers,huggingface_hub
|
| 41 |
from PIL import Image
|
|
@@ -51,8 +157,11 @@ try:
|
|
| 51 |
def construct():
|
| 52 |
with torch.device('meta'):
|
| 53 |
return AutoModelForCausalLM.from_config(config,trust_remote_code=True)
|
| 54 |
-
if args.imports_only:
|
| 55 |
model=step('model_class',construct)
|
|
|
|
|
|
|
|
|
|
| 56 |
else:
|
| 57 |
def load():
|
| 58 |
model,info=AutoModelForCausalLM.from_pretrained(MODEL,torch_dtype=torch.float32,output_loading_info=True,**common)
|
|
@@ -76,6 +185,8 @@ try:
|
|
| 76 |
elif type(module).__name__=='SigLIPRotaryEmbedding':
|
| 77 |
expected=1/(module.theta**(torch.arange(0,module.dim,2,dtype=torch.float32)/module.dim))
|
| 78 |
assert torch.equal(expected,module.inv_freq)
|
|
|
|
|
|
|
| 79 |
step('weights_and_buffers',weights)
|
| 80 |
def mask_semantics():
|
| 81 |
import sys
|
|
@@ -92,6 +203,8 @@ try:
|
|
| 92 |
mask=create(c,torch.zeros(1,2,4),allowed,None,torch.arange(2))
|
| 93 |
assert torch.equal(mask==0,allowed)
|
| 94 |
step('mask_semantics',mask_semantics)
|
|
|
|
|
|
|
| 95 |
processor.tokenizer.padding_side='left'
|
| 96 |
def inputs(names,prompt='OCR:'):
|
| 97 |
images=[];messages=[]
|
|
|
|
| 11 |
args_parser=argparse.ArgumentParser()
|
| 12 |
args_parser.add_argument('--imports-only',action='store_true')
|
| 13 |
args_parser.add_argument('--full',action='store_true')
|
| 14 |
+
args_parser.add_argument('--helpers-only',action='store_true')
|
| 15 |
args_parser.add_argument('--model',type=Path)
|
| 16 |
args_parser.add_argument('--inputs',type=Path)
|
| 17 |
args_parser.add_argument('--output',type=Path)
|
|
|
|
| 26 |
os.environ['HF_MODULES_CACHE']=str(OUT/'modules')
|
| 27 |
os.environ['HF_HUB_OFFLINE']='1'
|
| 28 |
os.environ['TOKENIZERS_PARALLELISM']='false'
|
| 29 |
+
report={'transformers':VERSION,'trust_remote_code':True,'mode':'helpers' if args.helpers_only else 'imports' if args.imports_only else 'full' if args.full else 'matrix','pid':os.getpid(),'started_at':time.strftime('%Y-%m-%dT%H:%M:%SZ',time.gmtime()),'stages':{}}
|
| 30 |
report['source_sha256']={p.name:hashlib.sha256(p.read_bytes()).hexdigest() for p in MODEL.glob('*.py')}
|
| 31 |
+
def save(): (OUT/('helpers.json' if args.helpers_only else 'imports.json' if args.imports_only else 'full.json' if args.full else 'results.json')).write_text(json.dumps(report,ensure_ascii=False,indent=2,default=str)+'\n')
|
| 32 |
def step(name,fn):
|
| 33 |
started=time.perf_counter()
|
| 34 |
try:
|
|
|
|
| 37 |
except Exception as exc:
|
| 38 |
report['stages'][name]={'passed':False,'error':str(exc),'traceback':traceback.format_exc()}
|
| 39 |
print(name,type(exc).__name__,str(exc),flush=True);save();raise
|
| 40 |
+
"""Backend contracts exercised without requiring model checkpoint weights."""
|
| 41 |
+
|
| 42 |
+
def check_backend_contracts(module, report):
|
| 43 |
+
import math
|
| 44 |
+
import torch
|
| 45 |
+
from transformers import PretrainedConfig
|
| 46 |
+
from transformers.cache_utils import DynamicCache, StaticCache
|
| 47 |
+
|
| 48 |
+
config=PretrainedConfig()
|
| 49 |
+
qkv_generator=torch.Generator().manual_seed(321)
|
| 50 |
+
checked=0
|
| 51 |
+
largest=0.0
|
| 52 |
+
for backend in ['eager','sdpa']:
|
| 53 |
+
config._attn_implementation=backend
|
| 54 |
+
for past_length,query_length in [(0,4),(3,1),(3,2)]:
|
| 55 |
+
for padded in [False,True]:
|
| 56 |
+
cache=None
|
| 57 |
+
if past_length:
|
| 58 |
+
cache=DynamicCache()
|
| 59 |
+
past=torch.zeros(1,2,past_length,4)
|
| 60 |
+
cache.update(past,past,0,{'cache_position':torch.arange(past_length)})
|
| 61 |
+
positions=torch.arange(past_length,past_length+query_length)
|
| 62 |
+
embeds=torch.zeros(1,query_length,8)
|
| 63 |
+
padding=torch.ones(1,past_length+query_length)
|
| 64 |
+
if padded:padding[:,:2]=0
|
| 65 |
+
native=module._create_causal_mask(config,embeds,padding,cache,positions)
|
| 66 |
+
fallback=module._create_causal_mask_fallback(config,embeds,padding,cache,positions)
|
| 67 |
+
q=torch.randn(1,2,query_length,4,generator=qkv_generator)
|
| 68 |
+
k=torch.randn(1,2,past_length+query_length,4,generator=qkv_generator)
|
| 69 |
+
v=torch.randn(k.shape,generator=qkv_generator)
|
| 70 |
+
actual=torch.nn.functional.scaled_dot_product_attention(q,k,v,attn_mask=native,is_causal=native is None and query_length>1)
|
| 71 |
+
expected=torch.nn.functional.scaled_dot_product_attention(q,k,v,attn_mask=fallback)
|
| 72 |
+
# Left-padding query rows are discarded; compare valid tokens.
|
| 73 |
+
valid=padding[0,past_length:].bool()
|
| 74 |
+
torch.testing.assert_close(actual[:,:,valid],expected[:,:,valid],atol=2e-6,rtol=2e-6)
|
| 75 |
+
assert torch.isfinite(actual).all()
|
| 76 |
+
largest=max(largest,(actual[:,:,valid]-expected[:,:,valid]).abs().max().item())
|
| 77 |
+
checked+=1
|
| 78 |
+
|
| 79 |
+
config._attn_implementation='sdpa'
|
| 80 |
+
x=torch.zeros(1,4,8)
|
| 81 |
+
positions=torch.arange(4)
|
| 82 |
+
mask=module._create_causal_mask(config,x,torch.ones(1,4),None,positions)
|
| 83 |
+
native_available=module._hf_create_causal_mask is not None and module._HF_MASK_INPUT_NAME is not None
|
| 84 |
+
if native_available:
|
| 85 |
+
assert mask is None,'Unpadded SDPA should preserve the native is_causal fast path'
|
| 86 |
+
fast_path=mask is None
|
| 87 |
+
native_function=module._hf_create_causal_mask
|
| 88 |
+
try:
|
| 89 |
+
module._hf_create_causal_mask=None
|
| 90 |
+
mask=module._create_causal_mask(config,x,torch.ones(1,4),None,positions)
|
| 91 |
+
assert torch.equal(mask[0,0]==0,torch.ones(4,4,dtype=torch.bool).tril())
|
| 92 |
+
def broken_helper(**kwargs):raise TypeError('backend-error-must-propagate')
|
| 93 |
+
if native_available:
|
| 94 |
+
module._hf_create_causal_mask=broken_helper
|
| 95 |
+
try:module._create_causal_mask(config,x,None,None,positions)
|
| 96 |
+
except TypeError as exc:assert str(exc)=='backend-error-must-propagate'
|
| 97 |
+
else:raise AssertionError('Backend computation errors must not be swallowed')
|
| 98 |
+
finally:module._hf_create_causal_mask=native_function
|
| 99 |
+
|
| 100 |
+
static_config=PretrainedConfig(num_hidden_layers=1,hidden_size=8,num_attention_heads=2,
|
| 101 |
+
num_key_value_heads=2,head_dim=4)
|
| 102 |
+
static_config._attn_implementation='eager'
|
| 103 |
+
cache=StaticCache(config=static_config,max_cache_len=8,batch_size=1)
|
| 104 |
+
past=torch.zeros(1,2,3,4)
|
| 105 |
+
cache.update(past,past,0,{'cache_position':torch.arange(3)})
|
| 106 |
+
static_mask=module._create_causal_mask(static_config,torch.zeros(1,1,8),
|
| 107 |
+
torch.tensor([[0,1,1,1]]),cache,torch.tensor([3]))
|
| 108 |
+
assert torch.equal(static_mask[0,0,0]==0,torch.tensor([False,True,True,True,False,False,False,False]))
|
| 109 |
+
|
| 110 |
+
for operation,args,kwargs in [
|
| 111 |
+
('normal_',(),{'std':0.1}),('zeros_',(),{}),('ones_',(),{}),
|
| 112 |
+
('xavier_uniform_',(),{}),('copy_',(torch.ones(4,4),),{})]:
|
| 113 |
+
tensor=torch.nn.Parameter(torch.full((4,4),0.123))
|
| 114 |
+
tensor._is_hf_initialized=True
|
| 115 |
+
expected=tensor.detach().clone()
|
| 116 |
+
assert module._init_tensor(tensor,operation,*args,**kwargs) is tensor
|
| 117 |
+
assert torch.equal(tensor,expected)
|
| 118 |
+
for name in ['_trunc_normal_','trunc_normal_tf_','variance_scaling_','lecun_normal_','default_flax_embed_init']:
|
| 119 |
+
tensor=torch.nn.Parameter(torch.full((4,4),0.123))
|
| 120 |
+
tensor._is_hf_initialized=True
|
| 121 |
+
expected=tensor.detach().clone()
|
| 122 |
+
arguments=(0.0,1.0,-2.0,2.0) if name=='_trunc_normal_' else ()
|
| 123 |
+
getattr(module,name)(tensor,*arguments)
|
| 124 |
+
assert torch.equal(tensor,expected)
|
| 125 |
+
fresh=torch.nn.Parameter(torch.empty(4,4))
|
| 126 |
+
module._init_tensor(fresh,'ones_')
|
| 127 |
+
assert torch.equal(fresh,torch.ones(4,4))
|
| 128 |
+
# TF-style truncation bounds are applied before scaling, unlike a direct
|
| 129 |
+
# replacement with torch.nn.init.trunc_normal_(std=...).
|
| 130 |
+
with torch.random.fork_rng():
|
| 131 |
+
torch.manual_seed(123)
|
| 132 |
+
fresh=torch.nn.Parameter(torch.empty(1024,64))
|
| 133 |
+
module.lecun_normal_(fresh)
|
| 134 |
+
bound=2*math.sqrt(1/64)/0.87962566103423978
|
| 135 |
+
assert fresh.abs().max()<=bound
|
| 136 |
+
assert abs(fresh.std().item()-1/math.sqrt(64))<0.005
|
| 137 |
+
report['backend_contracts']={'mask_cases':checked,'max_valid_token_difference':largest,
|
| 138 |
+
'sdpa_fast_path':fast_path,'fallback_exercised':True,'backend_errors_propagate':native_available,
|
| 139 |
+
'static_cache_mask':True,
|
| 140 |
+
'loaded_initializer_guards':True,'tf_truncation_preserved':True,
|
| 141 |
+
'native_mask_input_name':module._HF_MASK_INPUT_NAME,
|
| 142 |
+
'native_mask_requires_cache_position':'cache_position' in module._HF_MASK_PARAMETERS}
|
| 143 |
+
|
| 144 |
+
|
| 145 |
try:
|
| 146 |
import torch,transformers,tokenizers,huggingface_hub
|
| 147 |
from PIL import Image
|
|
|
|
| 157 |
def construct():
|
| 158 |
with torch.device('meta'):
|
| 159 |
return AutoModelForCausalLM.from_config(config,trust_remote_code=True)
|
| 160 |
+
if args.imports_only or args.helpers_only:
|
| 161 |
model=step('model_class',construct)
|
| 162 |
+
if args.helpers_only:
|
| 163 |
+
import sys
|
| 164 |
+
step('backend_contracts',lambda:check_backend_contracts(sys.modules[type(model).__module__],report))
|
| 165 |
else:
|
| 166 |
def load():
|
| 167 |
model,info=AutoModelForCausalLM.from_pretrained(MODEL,torch_dtype=torch.float32,output_loading_info=True,**common)
|
|
|
|
| 185 |
elif type(module).__name__=='SigLIPRotaryEmbedding':
|
| 186 |
expected=1/(module.theta**(torch.arange(0,module.dim,2,dtype=torch.float32)/module.dim))
|
| 187 |
assert torch.equal(expected,module.inv_freq)
|
| 188 |
+
elif type(module).__name__=='PaddleOCRVisionEmbeddings':
|
| 189 |
+
assert torch.equal(module.position_ids,torch.arange(module.num_positions).expand(1,-1))
|
| 190 |
step('weights_and_buffers',weights)
|
| 191 |
def mask_semantics():
|
| 192 |
import sys
|
|
|
|
| 203 |
mask=create(c,torch.zeros(1,2,4),allowed,None,torch.arange(2))
|
| 204 |
assert torch.equal(mask==0,allowed)
|
| 205 |
step('mask_semantics',mask_semantics)
|
| 206 |
+
import sys
|
| 207 |
+
step('backend_contracts',lambda:check_backend_contracts(sys.modules[type(model).__module__],report))
|
| 208 |
processor.tokenizer.padding_side='left'
|
| 209 |
def inputs(names,prompt='OCR:'):
|
| 210 |
images=[];messages=[]
|