Improve multimodal embeddings
Browse files- README.md +21 -21
- config.json +5 -3
- model.safetensors +2 -2
- omni_components/residual_projection.py +34 -0
- scores.json +239 -127
- vela_omni.py +23 -4
README.md
CHANGED
|
@@ -22,7 +22,7 @@ tags:
|
|
| 22 |
|
| 23 |
# Vela Omni Nano
|
| 24 |
|
| 25 |
-
Vela Omni Nano maps text, images, and speech into a shared embedding space for multimodal search and
|
| 26 |
|
| 27 |
**134M parameters · 384 dimensions · L2-normalized embeddings.**
|
| 28 |
|
|
@@ -34,26 +34,26 @@ Scores use a 0–100 scale; higher is better. All applicable models use the same
|
|
| 34 |
|
| 35 |
| Metric | [Vela-1.0-Encoder-307M-Embedding](https://huggingface.co/llm-semantic-router/Vela-1.0-Encoder-307M-Embedding) | [multi-modal-embed-small](https://huggingface.co/llm-semantic-router/multi-modal-embed-small) | [multi-modal-embed-large](https://huggingface.co/llm-semantic-router/multi-modal-embed-large) | [Vela-1.0-Omni-Nano](https://huggingface.co/llm-semantic-router/Vela-1.0-Omni-Nano) |
|
| 36 |
|---|---:|---:|---:|---:|
|
| 37 |
-
| Banking77 · Accuracy | 80.00 | 70.42 | 75.78 |
|
| 38 |
-
| MASSIVE English · Accuracy | 75.64 | 65.95 | 72.31 |
|
| 39 |
-
| COCO · Image → text · R@1 | N/A | 40.83 | 42.53 |
|
| 40 |
-
| COCO · Image → text · R@5 | N/A | 67.19 | 75.21 |
|
| 41 |
-
| COCO · Image → text · R@10 | N/A | 78.49 | 87.61 |
|
| 42 |
-
| COCO · Text → image · R@1 | N/A | 30.18 | 35.04 |
|
| 43 |
-
| COCO · Text → image · R@5 | N/A | 59.42 | 70.09 |
|
| 44 |
-
| COCO · Text → image · R@10 | N/A | 74.29 | 83.91 | 82.
|
| 45 |
-
| LibriSpeech · Audio → text · R@1 | N/A | 4.21 | 56.99 |
|
| 46 |
-
| LibriSpeech · Audio → text · R@5 | N/A | 11.99 | 81.85 |
|
| 47 |
-
| LibriSpeech · Audio → text · R@10 | N/A | 19.03 | 87.94 |
|
| 48 |
-
| LibriSpeech · Text → audio · R@1 | N/A | 9.58 | 78.58 |
|
| 49 |
-
| LibriSpeech · Text → audio · R@5 | N/A | 22.53 | 94.02 |
|
| 50 |
-
| LibriSpeech · Text → audio · R@10 | N/A | 30.69 | 97.01 |
|
| 51 |
-
|
| 52 |
-
Text evaluation uses fixed class prototypes: 3,080 Banking77 and 2,972 MASSIVE English queries.
|
| 53 |
|
| 54 |
Image retrieval uses the COCO Karpathy CC-BY2 image subset: 823 images and 4,115 captions. Speech retrieval uses 2,611 LibriSpeech test-clean clips and 2,610 unique transcripts, with clips limited to 30 seconds. Recall is measured against each complete candidate pool, accepting all matching positives.
|
| 55 |
|
| 56 |
-
Evaluation uses FP32 embeddings, cosine similarity, and a common 128-token text limit. [Full scores and protocol](./scores.json) include model revisions, sample counts, and paired uncertainty.
|
| 57 |
|
| 58 |
## Quick start
|
| 59 |
|
|
@@ -72,10 +72,10 @@ vectors = model.encode_text(["A bicycle beside a building.", "Someone is reading
|
|
| 72 |
print(vectors.shape) # (2, 384)
|
| 73 |
```
|
| 74 |
|
| 75 |
-
Pass a list of Pillow images to `model.encode_image(images)`. Pass a list of mono NumPy waveforms to `model.encode_audio(waveforms, sampling_rate=16000)`; each waveform must be at most 30 seconds. Compare normalized vectors with their dot product. Similarity scores are rankings, not calibrated probabilities.
|
| 76 |
|
| 77 |
-
Cross-modal alignment uses COCO image–caption pairs from the CC-BY 2.0 image subset and [LibriSpeech](https://www.openslr.org/12/) speech–transcript pairs (CC-BY 4.0). COCO annotations are provided under CC-BY 4.0.
|
| 78 |
|
| 79 |
The repository includes the native model code, component configurations, and tokenizer and processor files. See [NOTICE](./NOTICE) and [LICENSE](./LICENSE) for component attribution and license terms.
|
| 80 |
|
| 81 |
-
[Explore the Vela model collection](https://huggingface.co/collections/llm-semantic-router/vela-10-
|
|
|
|
| 22 |
|
| 23 |
# Vela Omni Nano
|
| 24 |
|
| 25 |
+
Vela Omni Nano maps text, images, and speech into a shared embedding space for multimodal search, routing, and clustering.
|
| 26 |
|
| 27 |
**134M parameters · 384 dimensions · L2-normalized embeddings.**
|
| 28 |
|
|
|
|
| 34 |
|
| 35 |
| Metric | [Vela-1.0-Encoder-307M-Embedding](https://huggingface.co/llm-semantic-router/Vela-1.0-Encoder-307M-Embedding) | [multi-modal-embed-small](https://huggingface.co/llm-semantic-router/multi-modal-embed-small) | [multi-modal-embed-large](https://huggingface.co/llm-semantic-router/multi-modal-embed-large) | [Vela-1.0-Omni-Nano](https://huggingface.co/llm-semantic-router/Vela-1.0-Omni-Nano) |
|
| 36 |
|---|---:|---:|---:|---:|
|
| 37 |
+
| Banking77 · Accuracy | 80.00 | 70.42 | 75.78 | 73.28 |
|
| 38 |
+
| MASSIVE English · Accuracy | 75.64 | 65.95 | 72.31 | 66.55 |
|
| 39 |
+
| COCO · Image → text · R@1 | N/A | 40.83 | 42.53 | 47.02 |
|
| 40 |
+
| COCO · Image → text · R@5 | N/A | 67.19 | 75.21 | 74.97 |
|
| 41 |
+
| COCO · Image → text · R@10 | N/A | 78.49 | 87.61 | 85.91 |
|
| 42 |
+
| COCO · Text → image · R@1 | N/A | 30.18 | 35.04 | 37.33 |
|
| 43 |
+
| COCO · Text → image · R@5 | N/A | 59.42 | 70.09 | 70.16 |
|
| 44 |
+
| COCO · Text → image · R@10 | N/A | 74.29 | 83.91 | 82.99 |
|
| 45 |
+
| LibriSpeech · Audio → text · R@1 | N/A | 4.21 | 56.99 | 8.20 |
|
| 46 |
+
| LibriSpeech · Audio → text · R@5 | N/A | 11.99 | 81.85 | 21.29 |
|
| 47 |
+
| LibriSpeech · Audio → text · R@10 | N/A | 19.03 | 87.94 | 30.26 |
|
| 48 |
+
| LibriSpeech · Text → audio · R@1 | N/A | 9.58 | 78.58 | 13.26 |
|
| 49 |
+
| LibriSpeech · Text → audio · R@5 | N/A | 22.53 | 94.02 | 30.00 |
|
| 50 |
+
| LibriSpeech · Text → audio · R@10 | N/A | 30.69 | 97.01 | 38.66 |
|
| 51 |
+
|
| 52 |
+
Text evaluation uses fixed class prototypes: 3,080 Banking77 and 2,972 MASSIVE English queries. Vela Omni is adapted using training examples and intent labels from these two datasets; comparison models are evaluated as published without additional adaptation here. These scores measure supervised task adaptation with nearest-prototype classification, not zero-shot transfer or the MTEB classification protocol.
|
| 53 |
|
| 54 |
Image retrieval uses the COCO Karpathy CC-BY2 image subset: 823 images and 4,115 captions. Speech retrieval uses 2,611 LibriSpeech test-clean clips and 2,610 unique transcripts, with clips limited to 30 seconds. Recall is measured against each complete candidate pool, accepting all matching positives.
|
| 55 |
|
| 56 |
+
Evaluation uses FP32 embeddings, cosine similarity, and a common 128-token text limit. [Full scores and protocol](./scores.json) include model revisions, sample counts, and paired uncertainty against the original and previous models. These fixed evaluation pools are reused across releases.
|
| 57 |
|
| 58 |
## Quick start
|
| 59 |
|
|
|
|
| 72 |
print(vectors.shape) # (2, 384)
|
| 73 |
```
|
| 74 |
|
| 75 |
+
Pass a list of Pillow images to `model.encode_image(images)`. Pass a list of mono NumPy waveforms to `model.encode_audio(waveforms, sampling_rate=16000)`; each waveform must be at most 30 seconds. Compare normalized vectors with their dot product. To route media, embed each destination’s name and description, then select the closest vector. To discover routing categories, cluster media embeddings and inspect each group. Similarity scores are rankings, not calibrated probabilities.
|
| 76 |
|
| 77 |
+
Cross-modal alignment uses COCO image–caption pairs from the CC-BY 2.0 image subset and [LibriSpeech](https://www.openslr.org/12/) speech–transcript pairs (CC-BY 4.0). COCO annotations, Banking77, and MASSIVE are provided under CC-BY 4.0.
|
| 78 |
|
| 79 |
The repository includes the native model code, component configurations, and tokenizer and processor files. See [NOTICE](./NOTICE) and [LICENSE](./LICENSE) for component attribution and license terms.
|
| 80 |
|
| 81 |
+
[Explore the Vela model collection](https://huggingface.co/collections/llm-semantic-router/vela-10-6aa555ba70cc6997d6d67798)
|
config.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
| 1 |
{
|
| 2 |
-
"format_version":
|
| 3 |
"variant": "nano",
|
| 4 |
-
"parameter_count":
|
| 5 |
"embedding_dim": 384,
|
| 6 |
"max_text_length": 128,
|
| 7 |
"architectures": [
|
|
@@ -11,5 +11,7 @@
|
|
| 11 |
"library_name": "pytorch",
|
| 12 |
"audio_sampling_rate": 16000,
|
| 13 |
"audio_max_seconds": 30,
|
| 14 |
-
"audio_projection": "linear"
|
|
|
|
|
|
|
| 15 |
}
|
|
|
|
| 1 |
{
|
| 2 |
+
"format_version": 3,
|
| 3 |
"variant": "nano",
|
| 4 |
+
"parameter_count": 133956480,
|
| 5 |
"embedding_dim": 384,
|
| 6 |
"max_text_length": 128,
|
| 7 |
"architectures": [
|
|
|
|
| 11 |
"library_name": "pytorch",
|
| 12 |
"audio_sampling_rate": 16000,
|
| 13 |
"audio_max_seconds": 30,
|
| 14 |
+
"audio_projection": "linear",
|
| 15 |
+
"text_projection": "residual_rank64",
|
| 16 |
+
"audio_pooling": "mean"
|
| 17 |
}
|
model.safetensors
CHANGED
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:949b21264db9d963de79a56dd2aeb4f1f31dce315dc54ee15296b7c69772e7b9
|
| 3 |
+
size 535886448
|
omni_components/residual_projection.py
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Native rank-64 residual text mapping and duration-aware audio readout."""
|
| 2 |
+
import torch
|
| 3 |
+
from torch import nn
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
class ResidualTextProjection(nn.Module):
|
| 7 |
+
def __init__(self, dimension, seed=20260919):
|
| 8 |
+
super().__init__()
|
| 9 |
+
self.V = nn.Linear(dimension, 64, bias=False)
|
| 10 |
+
self.U = nn.Linear(64, dimension, bias=False)
|
| 11 |
+
generator = torch.Generator(device='cpu').manual_seed(seed)
|
| 12 |
+
with torch.no_grad():
|
| 13 |
+
self.V.weight.copy_(torch.randn(64, dimension, generator=generator) * 0.01)
|
| 14 |
+
self.U.weight.zero_()
|
| 15 |
+
|
| 16 |
+
def forward(self, values):
|
| 17 |
+
return values + self.U(self.V(values))
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
def duration_frame_counts(sample_counts, frame_count, device=None):
|
| 21 |
+
counts = torch.as_tensor(sample_counts, device=device)
|
| 22 |
+
if counts.ndim != 1 or counts.dtype not in (torch.int32, torch.int64):
|
| 23 |
+
raise ValueError('Original integer sample counts are required')
|
| 24 |
+
if not bool(((counts > 0) & (counts <= 480000)).all()) or frame_count != 1500:
|
| 25 |
+
raise ValueError('Expected valid 16kHz clips and native 1500-frame output')
|
| 26 |
+
return torch.clamp(torch.div(counts + 319, 320, rounding_mode='floor'), 1, frame_count)
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
def duration_mean(hidden_states, sample_counts):
|
| 30 |
+
if hidden_states.ndim != 3 or len(sample_counts) != len(hidden_states):
|
| 31 |
+
raise ValueError('Audio lengths do not match encoder batch')
|
| 32 |
+
counts = duration_frame_counts(sample_counts, hidden_states.shape[1], hidden_states.device)
|
| 33 |
+
mask = torch.arange(hidden_states.shape[1], device=hidden_states.device)[None, :] < counts[:, None]
|
| 34 |
+
return (hidden_states * mask[:, :, None]).sum(dim=1) / counts[:, None].to(hidden_states.dtype)
|
scores.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
| 1 |
{
|
| 2 |
-
"schema_version":
|
| 3 |
"model": "llm-semantic-router/Vela-1.0-Omni-Nano",
|
| 4 |
"revision_semantics": "self denotes the Hugging Face snapshot containing this file; the native artifact fingerprint binds its evaluated model files.",
|
| 5 |
"score_scale": "0-1; multiply by 100 for percentages",
|
|
@@ -182,77 +182,77 @@
|
|
| 182 |
"candidate": {
|
| 183 |
"model": "llm-semantic-router/Vela-1.0-Omni-Nano",
|
| 184 |
"revision": "self",
|
| 185 |
-
"artifact_fingerprint_sha256": "
|
| 186 |
"metrics": {
|
| 187 |
"text.banking77.accuracy": {
|
| 188 |
-
"numerator":
|
| 189 |
"denominator": 3080,
|
| 190 |
-
"value": 0.
|
| 191 |
},
|
| 192 |
"text.massive-en.accuracy": {
|
| 193 |
-
"numerator":
|
| 194 |
"denominator": 2972,
|
| 195 |
-
"value": 0.
|
| 196 |
},
|
| 197 |
"image.image_to_text.recall@1": {
|
| 198 |
-
"numerator":
|
| 199 |
"denominator": 823,
|
| 200 |
-
"value": 0.
|
| 201 |
},
|
| 202 |
"image.image_to_text.recall@5": {
|
| 203 |
-
"numerator":
|
| 204 |
"denominator": 823,
|
| 205 |
-
"value": 0.
|
| 206 |
},
|
| 207 |
"image.image_to_text.recall@10": {
|
| 208 |
-
"numerator":
|
| 209 |
"denominator": 823,
|
| 210 |
-
"value": 0.
|
| 211 |
},
|
| 212 |
"image.text_to_image.recall@1": {
|
| 213 |
-
"numerator":
|
| 214 |
"denominator": 4115,
|
| 215 |
-
"value": 0.
|
| 216 |
},
|
| 217 |
"image.text_to_image.recall@5": {
|
| 218 |
-
"numerator":
|
| 219 |
"denominator": 4115,
|
| 220 |
-
"value": 0.
|
| 221 |
},
|
| 222 |
"image.text_to_image.recall@10": {
|
| 223 |
-
"numerator":
|
| 224 |
"denominator": 4115,
|
| 225 |
-
"value": 0.
|
| 226 |
},
|
| 227 |
"audio.audio_to_text.recall@1": {
|
| 228 |
-
"numerator":
|
| 229 |
"denominator": 2611,
|
| 230 |
-
"value": 0.
|
| 231 |
},
|
| 232 |
"audio.audio_to_text.recall@5": {
|
| 233 |
-
"numerator":
|
| 234 |
"denominator": 2611,
|
| 235 |
-
"value": 0.
|
| 236 |
},
|
| 237 |
"audio.audio_to_text.recall@10": {
|
| 238 |
-
"numerator":
|
| 239 |
"denominator": 2611,
|
| 240 |
-
"value": 0.
|
| 241 |
},
|
| 242 |
"audio.text_to_audio.recall@1": {
|
| 243 |
-
"numerator":
|
| 244 |
"denominator": 2610,
|
| 245 |
-
"value": 0.
|
| 246 |
},
|
| 247 |
"audio.text_to_audio.recall@5": {
|
| 248 |
-
"numerator":
|
| 249 |
"denominator": 2610,
|
| 250 |
-
"value": 0.
|
| 251 |
},
|
| 252 |
"audio.text_to_audio.recall@10": {
|
| 253 |
-
"numerator":
|
| 254 |
"denominator": 2610,
|
| 255 |
-
"value": 0.
|
| 256 |
}
|
| 257 |
}
|
| 258 |
}
|
|
@@ -312,109 +312,221 @@
|
|
| 312 |
"similarity": "FP32 cosine of L2-normalized embeddings",
|
| 313 |
"ties": "lexicographic candidate ID",
|
| 314 |
"retrieval": "complete candidate pools; all annotated positives",
|
| 315 |
-
"classification": "nearest normalized mean class prototype;
|
| 316 |
"aggregation": "Each family is the mean of its two primary metrics; utility is the mean of all six primaries. Retrieval primaries are R@1; R@5 and R@10 are reported separately.",
|
| 317 |
-
"evaluation_scope": "fixed test-split evaluation pools"
|
| 318 |
},
|
| 319 |
"paired_uncertainty": {
|
| 320 |
-
"
|
| 321 |
-
"
|
| 322 |
-
|
| 323 |
-
|
| 324 |
-
|
| 325 |
-
|
| 326 |
-
"method": "paired stratified group percentile; PCG64; fixed candidate pools",
|
| 327 |
-
"intervals": {
|
| 328 |
-
"audio.audio_to_text.recall@1": {
|
| 329 |
-
"point_delta": 0.010723860589812333,
|
| 330 |
-
"lower": 0.005401297417205939,
|
| 331 |
-
"upper": 0.016930329895273797
|
| 332 |
-
},
|
| 333 |
-
"audio.audio_to_text.recall@10": {
|
| 334 |
-
"point_delta": 0.048640367675220224,
|
| 335 |
-
"lower": 0.03862647576747038,
|
| 336 |
-
"upper": 0.057686079679882395
|
| 337 |
-
},
|
| 338 |
-
"audio.audio_to_text.recall@5": {
|
| 339 |
-
"point_delta": 0.038299502106472615,
|
| 340 |
-
"lower": 0.028966882934863172,
|
| 341 |
-
"upper": 0.04718931610578753
|
| 342 |
-
},
|
| 343 |
-
"audio.text_to_audio.recall@1": {
|
| 344 |
-
"point_delta": 0.020306513409961684,
|
| 345 |
-
"lower": 0.01207735759631001,
|
| 346 |
-
"upper": 0.029131333167300467
|
| 347 |
-
},
|
| 348 |
-
"audio.text_to_audio.recall@10": {
|
| 349 |
-
"point_delta": 0.0475095785440613,
|
| 350 |
-
"lower": 0.036695309471507946,
|
| 351 |
-
"upper": 0.05838249564916254
|
| 352 |
-
},
|
| 353 |
-
"audio.text_to_audio.recall@5": {
|
| 354 |
-
"point_delta": 0.040229885057471264,
|
| 355 |
-
"lower": 0.027551627678505008,
|
| 356 |
-
"upper": 0.05248271039052227
|
| 357 |
-
},
|
| 358 |
-
"family.audio": {
|
| 359 |
-
"point_delta": 0.015515186999887009,
|
| 360 |
-
"lower": 0.010126625706639377,
|
| 361 |
-
"upper": 0.021365285246569197
|
| 362 |
},
|
| 363 |
-
"
|
| 364 |
-
|
| 365 |
-
|
| 366 |
-
|
| 367 |
-
|
| 368 |
-
|
| 369 |
-
|
| 370 |
-
|
| 371 |
-
|
| 372 |
-
|
| 373 |
-
|
| 374 |
-
|
| 375 |
-
|
| 376 |
-
|
| 377 |
-
|
| 378 |
-
|
| 379 |
-
|
| 380 |
-
|
| 381 |
-
|
| 382 |
-
|
| 383 |
-
|
| 384 |
-
|
| 385 |
-
|
| 386 |
-
|
| 387 |
-
|
| 388 |
-
|
| 389 |
-
|
| 390 |
-
|
| 391 |
-
|
| 392 |
-
|
| 393 |
-
|
| 394 |
-
|
| 395 |
-
|
| 396 |
-
|
| 397 |
-
|
| 398 |
-
|
| 399 |
-
|
| 400 |
-
|
| 401 |
-
|
| 402 |
-
|
| 403 |
-
|
| 404 |
-
|
| 405 |
-
|
| 406 |
-
|
| 407 |
-
|
| 408 |
-
|
| 409 |
-
|
| 410 |
-
|
| 411 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 412 |
},
|
| 413 |
-
"
|
| 414 |
-
|
| 415 |
-
|
| 416 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 417 |
}
|
| 418 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 419 |
}
|
| 420 |
}
|
|
|
|
| 1 |
{
|
| 2 |
+
"schema_version": 2,
|
| 3 |
"model": "llm-semantic-router/Vela-1.0-Omni-Nano",
|
| 4 |
"revision_semantics": "self denotes the Hugging Face snapshot containing this file; the native artifact fingerprint binds its evaluated model files.",
|
| 5 |
"score_scale": "0-1; multiply by 100 for percentages",
|
|
|
|
| 182 |
"candidate": {
|
| 183 |
"model": "llm-semantic-router/Vela-1.0-Omni-Nano",
|
| 184 |
"revision": "self",
|
| 185 |
+
"artifact_fingerprint_sha256": "e4c8165db4e76534f71adbe24719d464b3d416ee9e7fe49c52a5aa05b3045371",
|
| 186 |
"metrics": {
|
| 187 |
"text.banking77.accuracy": {
|
| 188 |
+
"numerator": 2257,
|
| 189 |
"denominator": 3080,
|
| 190 |
+
"value": 0.7327922077922078
|
| 191 |
},
|
| 192 |
"text.massive-en.accuracy": {
|
| 193 |
+
"numerator": 1978,
|
| 194 |
"denominator": 2972,
|
| 195 |
+
"value": 0.6655450874831763
|
| 196 |
},
|
| 197 |
"image.image_to_text.recall@1": {
|
| 198 |
+
"numerator": 387,
|
| 199 |
"denominator": 823,
|
| 200 |
+
"value": 0.47023086269744835
|
| 201 |
},
|
| 202 |
"image.image_to_text.recall@5": {
|
| 203 |
+
"numerator": 617,
|
| 204 |
"denominator": 823,
|
| 205 |
+
"value": 0.7496962332928311
|
| 206 |
},
|
| 207 |
"image.image_to_text.recall@10": {
|
| 208 |
+
"numerator": 707,
|
| 209 |
"denominator": 823,
|
| 210 |
+
"value": 0.8590522478736331
|
| 211 |
},
|
| 212 |
"image.text_to_image.recall@1": {
|
| 213 |
+
"numerator": 1536,
|
| 214 |
"denominator": 4115,
|
| 215 |
+
"value": 0.3732685297691373
|
| 216 |
},
|
| 217 |
"image.text_to_image.recall@5": {
|
| 218 |
+
"numerator": 2887,
|
| 219 |
"denominator": 4115,
|
| 220 |
+
"value": 0.7015795868772783
|
| 221 |
},
|
| 222 |
"image.text_to_image.recall@10": {
|
| 223 |
+
"numerator": 3415,
|
| 224 |
"denominator": 4115,
|
| 225 |
+
"value": 0.8298906439854192
|
| 226 |
},
|
| 227 |
"audio.audio_to_text.recall@1": {
|
| 228 |
+
"numerator": 214,
|
| 229 |
"denominator": 2611,
|
| 230 |
+
"value": 0.0819609345078514
|
| 231 |
},
|
| 232 |
"audio.audio_to_text.recall@5": {
|
| 233 |
+
"numerator": 556,
|
| 234 |
"denominator": 2611,
|
| 235 |
+
"value": 0.21294523171198773
|
| 236 |
},
|
| 237 |
"audio.audio_to_text.recall@10": {
|
| 238 |
+
"numerator": 790,
|
| 239 |
"denominator": 2611,
|
| 240 |
+
"value": 0.30256606664113367
|
| 241 |
},
|
| 242 |
"audio.text_to_audio.recall@1": {
|
| 243 |
+
"numerator": 346,
|
| 244 |
"denominator": 2610,
|
| 245 |
+
"value": 0.13256704980842912
|
| 246 |
},
|
| 247 |
"audio.text_to_audio.recall@5": {
|
| 248 |
+
"numerator": 783,
|
| 249 |
"denominator": 2610,
|
| 250 |
+
"value": 0.3
|
| 251 |
},
|
| 252 |
"audio.text_to_audio.recall@10": {
|
| 253 |
+
"numerator": 1009,
|
| 254 |
"denominator": 2610,
|
| 255 |
+
"value": 0.38659003831417627
|
| 256 |
}
|
| 257 |
}
|
| 258 |
}
|
|
|
|
| 312 |
"similarity": "FP32 cosine of L2-normalized embeddings",
|
| 313 |
"ties": "lexicographic candidate ID",
|
| 314 |
"retrieval": "complete candidate pools; all annotated positives",
|
| 315 |
+
"classification": "nearest normalized mean class prototype; Vela Omni uses supervised training-split intent-label adaptation; comparison models evaluated as published",
|
| 316 |
"aggregation": "Each family is the mean of its two primary metrics; utility is the mean of all six primaries. Retrieval primaries are R@1; R@5 and R@10 are reported separately.",
|
| 317 |
+
"evaluation_scope": "fixed test-split evaluation pools reused across releases"
|
| 318 |
},
|
| 319 |
"paired_uncertainty": {
|
| 320 |
+
"original": {
|
| 321 |
+
"comparison": {
|
| 322 |
+
"candidate": "llm-semantic-router/Vela-1.0-Omni-Nano",
|
| 323 |
+
"baseline": "llm-semantic-router/multi-modal-embed-small",
|
| 324 |
+
"baseline_revision": "fdf8e01b7b0f3a69ac1ac8e2a64dcb1ede177ba4",
|
| 325 |
+
"baseline_artifact_fingerprint_sha256": "684fe0c48a4ddd3944167f6e5dc75e97ada24e5b120bd9a2921f00dc03112eeb"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 326 |
},
|
| 327 |
+
"seed": 20260918,
|
| 328 |
+
"replicates": 2000,
|
| 329 |
+
"method": "paired stratified group percentile; PCG64; fixed candidate pools",
|
| 330 |
+
"intervals": {
|
| 331 |
+
"audio.audio_to_text.recall@1": {
|
| 332 |
+
"point_delta": 0.03983148219073152,
|
| 333 |
+
"lower": 0.0325962321534125,
|
| 334 |
+
"upper": 0.047758993112907225
|
| 335 |
+
},
|
| 336 |
+
"audio.audio_to_text.recall@10": {
|
| 337 |
+
"point_delta": 0.11221754117196477,
|
| 338 |
+
"lower": 0.09530973319687737,
|
| 339 |
+
"upper": 0.12877810022670813
|
| 340 |
+
},
|
| 341 |
+
"audio.audio_to_text.recall@5": {
|
| 342 |
+
"point_delta": 0.09306779011872846,
|
| 343 |
+
"lower": 0.07882957120502015,
|
| 344 |
+
"upper": 0.10728804617676266
|
| 345 |
+
},
|
| 346 |
+
"audio.text_to_audio.recall@1": {
|
| 347 |
+
"point_delta": 0.0367816091954023,
|
| 348 |
+
"lower": 0.026758054192447193,
|
| 349 |
+
"upper": 0.04703357251126449
|
| 350 |
+
},
|
| 351 |
+
"audio.text_to_audio.recall@10": {
|
| 352 |
+
"point_delta": 0.07969348659003832,
|
| 353 |
+
"lower": 0.06278676122484814,
|
| 354 |
+
"upper": 0.09535034581998793
|
| 355 |
+
},
|
| 356 |
+
"audio.text_to_audio.recall@5": {
|
| 357 |
+
"point_delta": 0.07471264367816093,
|
| 358 |
+
"lower": 0.058304011796927804,
|
| 359 |
+
"upper": 0.08890972870306472
|
| 360 |
+
},
|
| 361 |
+
"family.audio": {
|
| 362 |
+
"point_delta": 0.03830654569306691,
|
| 363 |
+
"lower": 0.0317536163235943,
|
| 364 |
+
"upper": 0.04491423341337552
|
| 365 |
+
},
|
| 366 |
+
"family.image": {
|
| 367 |
+
"point_delta": 0.06670716889428918,
|
| 368 |
+
"lower": 0.04933171324422843,
|
| 369 |
+
"upper": 0.08457168894289184
|
| 370 |
+
},
|
| 371 |
+
"family.text": {
|
| 372 |
+
"point_delta": 0.017313978081138243,
|
| 373 |
+
"lower": 0.012190932632665139,
|
| 374 |
+
"upper": 0.022698066843763527
|
| 375 |
+
},
|
| 376 |
+
"image.image_to_text.recall@1": {
|
| 377 |
+
"point_delta": 0.061968408262454436,
|
| 378 |
+
"lower": 0.03402187120291616,
|
| 379 |
+
"upper": 0.09234507897934387
|
| 380 |
+
},
|
| 381 |
+
"image.image_to_text.recall@10": {
|
| 382 |
+
"point_delta": 0.07411907654921021,
|
| 383 |
+
"lower": 0.04738760631834751,
|
| 384 |
+
"upper": 0.10085054678007291
|
| 385 |
+
},
|
| 386 |
+
"image.image_to_text.recall@5": {
|
| 387 |
+
"point_delta": 0.07776427703523693,
|
| 388 |
+
"lower": 0.04981773997569866,
|
| 389 |
+
"upper": 0.10814094775212636
|
| 390 |
+
},
|
| 391 |
+
"image.text_to_image.recall@1": {
|
| 392 |
+
"point_delta": 0.07144592952612394,
|
| 393 |
+
"lower": 0.05297691373025516,
|
| 394 |
+
"upper": 0.09015795868772783
|
| 395 |
+
},
|
| 396 |
+
"image.text_to_image.recall@10": {
|
| 397 |
+
"point_delta": 0.08699878493317133,
|
| 398 |
+
"lower": 0.07047387606318348,
|
| 399 |
+
"upper": 0.10352369380315918
|
| 400 |
+
},
|
| 401 |
+
"image.text_to_image.recall@5": {
|
| 402 |
+
"point_delta": 0.10741190765492102,
|
| 403 |
+
"lower": 0.08894289185905224,
|
| 404 |
+
"upper": 0.12613001215066824
|
| 405 |
+
},
|
| 406 |
+
"text.banking77.accuracy": {
|
| 407 |
+
"point_delta": 0.02857142857142857,
|
| 408 |
+
"lower": 0.020461188697629102,
|
| 409 |
+
"upper": 0.03666480107400848
|
| 410 |
+
},
|
| 411 |
+
"text.massive-en.accuracy": {
|
| 412 |
+
"point_delta": 0.006056527590847914,
|
| 413 |
+
"lower": -0.00033658984096547205,
|
| 414 |
+
"upper": 0.013131423701480958
|
| 415 |
+
},
|
| 416 |
+
"utility": {
|
| 417 |
+
"point_delta": 0.04077589755616478,
|
| 418 |
+
"lower": 0.034528310785056776,
|
| 419 |
+
"upper": 0.047151560938567774
|
| 420 |
+
}
|
| 421 |
+
}
|
| 422 |
+
},
|
| 423 |
+
"previous": {
|
| 424 |
+
"comparison": {
|
| 425 |
+
"candidate": "llm-semantic-router/Vela-1.0-Omni-Nano",
|
| 426 |
+
"baseline": "llm-semantic-router/Vela-1.0-Omni-Nano",
|
| 427 |
+
"baseline_revision": "82f31e22b31f01989686559d974159034fa8118c",
|
| 428 |
+
"baseline_artifact_fingerprint_sha256": "32f410c3febdbd02e3f790b907db482e4ae1d493e6a1c4eaab375ebada234f8b"
|
| 429 |
},
|
| 430 |
+
"seed": 20260918,
|
| 431 |
+
"replicates": 2000,
|
| 432 |
+
"method": "paired stratified group percentile; PCG64; fixed candidate pools",
|
| 433 |
+
"intervals": {
|
| 434 |
+
"audio.audio_to_text.recall@1": {
|
| 435 |
+
"point_delta": 0.02910762160091919,
|
| 436 |
+
"lower": 0.021861939983398526,
|
| 437 |
+
"upper": 0.036651355202609114
|
| 438 |
+
},
|
| 439 |
+
"audio.audio_to_text.recall@10": {
|
| 440 |
+
"point_delta": 0.06357717349674455,
|
| 441 |
+
"lower": 0.05113845782378832,
|
| 442 |
+
"upper": 0.0757709413136462
|
| 443 |
+
},
|
| 444 |
+
"audio.audio_to_text.recall@5": {
|
| 445 |
+
"point_delta": 0.05476828801225584,
|
| 446 |
+
"lower": 0.04306058450795293,
|
| 447 |
+
"upper": 0.06643108320584735
|
| 448 |
+
},
|
| 449 |
+
"audio.text_to_audio.recall@1": {
|
| 450 |
+
"point_delta": 0.016475095785440614,
|
| 451 |
+
"lower": 0.008695160152854542,
|
| 452 |
+
"upper": 0.023524944652131282
|
| 453 |
+
},
|
| 454 |
+
"audio.text_to_audio.recall@10": {
|
| 455 |
+
"point_delta": 0.03218390804597701,
|
| 456 |
+
"lower": 0.02000716134837118,
|
| 457 |
+
"upper": 0.04482972738447
|
| 458 |
+
},
|
| 459 |
+
"audio.text_to_audio.recall@5": {
|
| 460 |
+
"point_delta": 0.034482758620689655,
|
| 461 |
+
"lower": 0.02224784413518575,
|
| 462 |
+
"upper": 0.04650418024307072
|
| 463 |
+
},
|
| 464 |
+
"family.audio": {
|
| 465 |
+
"point_delta": 0.0227913586931799,
|
| 466 |
+
"lower": 0.017447187890587527,
|
| 467 |
+
"upper": 0.028299187706426518
|
| 468 |
+
},
|
| 469 |
+
"family.image": {
|
| 470 |
+
"point_delta": 0.020048602673147023,
|
| 471 |
+
"lower": 0.009477521263669502,
|
| 472 |
+
"upper": 0.03062272174969622
|
| 473 |
+
},
|
| 474 |
+
"family.text": {
|
| 475 |
+
"point_delta": 0.017313978081138243,
|
| 476 |
+
"lower": 0.012190932632665139,
|
| 477 |
+
"upper": 0.022698066843763527
|
| 478 |
+
},
|
| 479 |
+
"image.image_to_text.recall@1": {
|
| 480 |
+
"point_delta": 0.027946537059538274,
|
| 481 |
+
"lower": 0.00850546780072904,
|
| 482 |
+
"upper": 0.04738760631834751
|
| 483 |
+
},
|
| 484 |
+
"image.image_to_text.recall@10": {
|
| 485 |
+
"point_delta": -0.001215066828675577,
|
| 486 |
+
"lower": -0.013365735115431349,
|
| 487 |
+
"upper": 0.00975091130012134
|
| 488 |
+
},
|
| 489 |
+
"image.image_to_text.recall@5": {
|
| 490 |
+
"point_delta": 0.019441069258809233,
|
| 491 |
+
"lower": 0.002430133657351154,
|
| 492 |
+
"upper": 0.03766707168894289
|
| 493 |
+
},
|
| 494 |
+
"image.text_to_image.recall@1": {
|
| 495 |
+
"point_delta": 0.012150668286755772,
|
| 496 |
+
"lower": 0.003639125151883354,
|
| 497 |
+
"upper": 0.020656136087484813
|
| 498 |
+
},
|
| 499 |
+
"image.text_to_image.recall@10": {
|
| 500 |
+
"point_delta": 0.009720534629404616,
|
| 501 |
+
"lower": 0.003888213851761847,
|
| 502 |
+
"upper": 0.015795868772782502
|
| 503 |
+
},
|
| 504 |
+
"image.text_to_image.recall@5": {
|
| 505 |
+
"point_delta": 0.014337788578371811,
|
| 506 |
+
"lower": 0.006804374240583232,
|
| 507 |
+
"upper": 0.02235722964763062
|
| 508 |
+
},
|
| 509 |
+
"text.banking77.accuracy": {
|
| 510 |
+
"point_delta": 0.02857142857142857,
|
| 511 |
+
"lower": 0.020461188697629102,
|
| 512 |
+
"upper": 0.03666480107400848
|
| 513 |
+
},
|
| 514 |
+
"text.massive-en.accuracy": {
|
| 515 |
+
"point_delta": 0.006056527590847914,
|
| 516 |
+
"lower": -0.00033658984096547205,
|
| 517 |
+
"upper": 0.013131423701480958
|
| 518 |
+
},
|
| 519 |
+
"utility": {
|
| 520 |
+
"point_delta": 0.020051313149155054,
|
| 521 |
+
"lower": 0.01592880942853571,
|
| 522 |
+
"upper": 0.024331405417179264
|
| 523 |
+
}
|
| 524 |
}
|
| 525 |
}
|
| 526 |
+
},
|
| 527 |
+
"training_scope": {
|
| 528 |
+
"text": "Banking77 and MASSIVE English training examples and intent labels; task-adapted classification, not zero-shot transfer or standard MTEB classification",
|
| 529 |
+
"image": "COCO CC-BY2 training image-caption subset",
|
| 530 |
+
"audio": "LibriSpeech train-clean-100 speech-transcript subset"
|
| 531 |
}
|
| 532 |
}
|
vela_omni.py
CHANGED
|
@@ -8,19 +8,27 @@ from safetensors.torch import load_file
|
|
| 8 |
from torch import nn
|
| 9 |
from torch.nn import functional as F
|
| 10 |
|
|
|
|
| 11 |
from omni_components.embedder import MultimodalEmbedder
|
| 12 |
from omni_components.mini import MultiModalSentenceEmbedder
|
| 13 |
|
| 14 |
|
| 15 |
class VelaOmni(nn.Module):
|
| 16 |
-
def __init__(self, root, variant, legacy=False, audio_projection="identity"):
|
| 17 |
super().__init__()
|
| 18 |
self.variant = variant
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 19 |
self.embedding_dim = 384 if variant == "nano" else 768
|
| 20 |
self.max_text_length = 128 if variant == "nano" else 32768
|
| 21 |
if variant == "nano":
|
| 22 |
self.model = MultimodalEmbedder(Path(root) / "components", legacy=legacy)
|
| 23 |
self.tokenizer = self.model.text_encoder.tokenizer
|
|
|
|
|
|
|
| 24 |
if audio_projection == "linear":
|
| 25 |
self.model.audio_encoder.projection = nn.Linear(384, 384)
|
| 26 |
elif audio_projection != "identity":
|
|
@@ -30,6 +38,8 @@ class VelaOmni(nn.Module):
|
|
| 30 |
raise ValueError("Mini uses its native audio projection")
|
| 31 |
self.model = MultiModalSentenceEmbedder(Path(root) / "components", legacy=legacy)
|
| 32 |
self.tokenizer = self.model.text_model.tokenizer
|
|
|
|
|
|
|
| 33 |
else:
|
| 34 |
raise ValueError("Unknown Vela Omni variant")
|
| 35 |
|
|
@@ -41,9 +51,11 @@ class VelaOmni(nn.Module):
|
|
| 41 |
root = Path(snapshot_download(repo_id, revision=revision,
|
| 42 |
allow_patterns=["config.json", "model.safetensors", "components/*"]))
|
| 43 |
config = json.loads((root / "config.json").read_text())
|
| 44 |
-
if config.get("format_version") not in (1, 2):
|
| 45 |
raise ValueError("Unsupported Vela Omni artifact format")
|
| 46 |
-
instance = cls(root, config["variant"], audio_projection=config.get("audio_projection", "identity")
|
|
|
|
|
|
|
| 47 |
weights = load_file(str(root / "model.safetensors"), device="cpu")
|
| 48 |
result = instance.model.load_state_dict(weights, strict=True, assign=True)
|
| 49 |
if result.missing_keys or result.unexpected_keys:
|
|
@@ -93,7 +105,14 @@ class VelaOmni(nn.Module):
|
|
| 93 |
if any(len(w) > 30 * sampling_rate for w in waveforms):
|
| 94 |
raise ValueError("Audio inputs must be at most 30 seconds")
|
| 95 |
if self.variant == "nano":
|
| 96 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 97 |
else:
|
| 98 |
features = self.model.audio_processor(waveforms, sampling_rate=sampling_rate,
|
| 99 |
return_tensors="pt")["input_features"]
|
|
|
|
| 8 |
from torch import nn
|
| 9 |
from torch.nn import functional as F
|
| 10 |
|
| 11 |
+
from omni_components.residual_projection import ResidualTextProjection, duration_mean
|
| 12 |
from omni_components.embedder import MultimodalEmbedder
|
| 13 |
from omni_components.mini import MultiModalSentenceEmbedder
|
| 14 |
|
| 15 |
|
| 16 |
class VelaOmni(nn.Module):
|
| 17 |
+
def __init__(self, root, variant, legacy=False, audio_projection="identity", text_projection="identity", audio_pooling="mean"):
|
| 18 |
super().__init__()
|
| 19 |
self.variant = variant
|
| 20 |
+
if text_projection not in ("identity", "residual_rank64"):
|
| 21 |
+
raise ValueError("Unsupported text projection")
|
| 22 |
+
if audio_pooling not in ("mean", "duration_mean") or (variant != "nano" and audio_pooling != "mean"):
|
| 23 |
+
raise ValueError("Unsupported audio pooling")
|
| 24 |
+
self.audio_pooling = audio_pooling
|
| 25 |
self.embedding_dim = 384 if variant == "nano" else 768
|
| 26 |
self.max_text_length = 128 if variant == "nano" else 32768
|
| 27 |
if variant == "nano":
|
| 28 |
self.model = MultimodalEmbedder(Path(root) / "components", legacy=legacy)
|
| 29 |
self.tokenizer = self.model.text_encoder.tokenizer
|
| 30 |
+
if text_projection == "residual_rank64":
|
| 31 |
+
self.model.text_encoder.projection = ResidualTextProjection(384)
|
| 32 |
if audio_projection == "linear":
|
| 33 |
self.model.audio_encoder.projection = nn.Linear(384, 384)
|
| 34 |
elif audio_projection != "identity":
|
|
|
|
| 38 |
raise ValueError("Mini uses its native audio projection")
|
| 39 |
self.model = MultiModalSentenceEmbedder(Path(root) / "components", legacy=legacy)
|
| 40 |
self.tokenizer = self.model.text_model.tokenizer
|
| 41 |
+
if text_projection == "residual_rank64":
|
| 42 |
+
self.model.text_proj = ResidualTextProjection(768)
|
| 43 |
else:
|
| 44 |
raise ValueError("Unknown Vela Omni variant")
|
| 45 |
|
|
|
|
| 51 |
root = Path(snapshot_download(repo_id, revision=revision,
|
| 52 |
allow_patterns=["config.json", "model.safetensors", "components/*"]))
|
| 53 |
config = json.loads((root / "config.json").read_text())
|
| 54 |
+
if config.get("format_version") not in (1, 2, 3):
|
| 55 |
raise ValueError("Unsupported Vela Omni artifact format")
|
| 56 |
+
instance = cls(root, config["variant"], audio_projection=config.get("audio_projection", "identity"),
|
| 57 |
+
text_projection=config.get("text_projection", "identity"),
|
| 58 |
+
audio_pooling=config.get("audio_pooling", "mean"))
|
| 59 |
weights = load_file(str(root / "model.safetensors"), device="cpu")
|
| 60 |
result = instance.model.load_state_dict(weights, strict=True, assign=True)
|
| 61 |
if result.missing_keys or result.unexpected_keys:
|
|
|
|
| 105 |
if any(len(w) > 30 * sampling_rate for w in waveforms):
|
| 106 |
raise ValueError("Audio inputs must be at most 30 seconds")
|
| 107 |
if self.variant == "nano":
|
| 108 |
+
if self.audio_pooling == "duration_mean":
|
| 109 |
+
encoder = self.model.audio_encoder
|
| 110 |
+
features = encoder.feature_extractor(waveforms, sampling_rate=sampling_rate,
|
| 111 |
+
return_tensors="pt")["input_features"].to(next(encoder.parameters()))
|
| 112 |
+
hidden = encoder.encoder(input_features=features, output_hidden_states=False).last_hidden_state
|
| 113 |
+
values = encoder.projection(duration_mean(hidden, [len(w) for w in waveforms]))
|
| 114 |
+
else:
|
| 115 |
+
values = self.model.encode_audio(waveforms, sampling_rate=sampling_rate)
|
| 116 |
else:
|
| 117 |
features = self.model.audio_processor(waveforms, sampling_rate=sampling_rate,
|
| 118 |
return_tensors="pt")["input_features"]
|