Instructions to use FrontiersMind/Lumma-0.6B-Extract with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use FrontiersMind/Lumma-0.6B-Extract with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-generation", model="FrontiersMind/Lumma-0.6B-Extract", trust_remote_code=True) messages = [ {"role": "user", "content": "Who are you?"}, ] pipe(messages)# pip install -U transformers accelerate # Load model directly from transformers import AutoModelForCausalLM model = AutoModelForCausalLM.from_pretrained("FrontiersMind/Lumma-0.6B-Extract", trust_remote_code=True, device_map="auto") - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use FrontiersMind/Lumma-0.6B-Extract with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "FrontiersMind/Lumma-0.6B-Extract" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "FrontiersMind/Lumma-0.6B-Extract", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker
docker model run hf.co/FrontiersMind/Lumma-0.6B-Extract
- SGLang
How to use FrontiersMind/Lumma-0.6B-Extract with SGLang:
Install from pip and serve model
# Install SGLang from pip: pip install sglang # Start the SGLang server: python3 -m sglang.launch_server \ --model-path "FrontiersMind/Lumma-0.6B-Extract" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "FrontiersMind/Lumma-0.6B-Extract", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker images
docker run --gpus all \ --shm-size 32g \ -p 30000:30000 \ -v ~/.cache/huggingface:/root/.cache/huggingface \ --env "HF_TOKEN=<secret>" \ --ipc=host \ lmsysorg/sglang:latest \ python3 -m sglang.launch_server \ --model-path "FrontiersMind/Lumma-0.6B-Extract" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "FrontiersMind/Lumma-0.6B-Extract", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }' - Docker Model Runner
How to use FrontiersMind/Lumma-0.6B-Extract with Docker Model Runner:
docker model run hf.co/FrontiersMind/Lumma-0.6B-Extract
Upload folder using huggingface_hub
Browse files- .gitattributes +2 -0
- .ipynb_checkpoints/chat_template-checkpoint.jinja +33 -0
- .ipynb_checkpoints/config-checkpoint.json +45 -0
- .ipynb_checkpoints/generation_config-checkpoint.json +10 -0
- .ipynb_checkpoints/tokenization_nandi-checkpoint.py +219 -0
- .ipynb_checkpoints/tokenizer_config-checkpoint.json +9 -0
- chat_template.jinja +33 -0
- config.json +45 -0
- configuration_nandi.py +123 -0
- generation_config.json +10 -0
- model.safetensors +3 -0
- modeling_nandi.py +541 -0
- tokenization_nandi.py +232 -0
- tokenizer.json +3 -0
- tokenizer_config.json +15 -0
.gitattributes
CHANGED
|
@@ -1,2 +1,4 @@
|
|
| 1 |
benchmark_results.png filter=lfs diff=lfs merge=lfs -text
|
| 2 |
benchmark_results.jpg filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
| 1 |
benchmark_results.png filter=lfs diff=lfs merge=lfs -text
|
| 2 |
benchmark_results.jpg filter=lfs diff=lfs merge=lfs -text
|
| 3 |
+
model.safetensors filter=lfs diff=lfs merge=lfs -text
|
| 4 |
+
tokenizer.json filter=lfs diff=lfs merge=lfs -text
|
.ipynb_checkpoints/chat_template-checkpoint.jinja
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{# Lumma schema-conditioned extraction chat template.
|
| 2 |
+
#
|
| 3 |
+
# INFERENCE: pass input_text + template (type hints) or input_text + json_schema (null schema).
|
| 4 |
+
# tokenizer.apply_chat_template(
|
| 5 |
+
# [],
|
| 6 |
+
# input_text="John Smith joined Acme.",
|
| 7 |
+
# template={"name": "string", "company": "string"},
|
| 8 |
+
# add_generation_prompt=True,
|
| 9 |
+
# )
|
| 10 |
+
# NandiTokenizer converts template -> null schema via json.dumps before rendering.
|
| 11 |
+
#
|
| 12 |
+
# TRAINING: pass full messages (system / user / assistant) as usual.
|
| 13 |
+
# #}
|
| 14 |
+
{%- set extraction_system = "You are Lumma, an AI model developed by FrontiersMind. You will be provided with an input text and a JSON schema. Your task is to extract information from the input text strictly according to the provided schema. Populate only the fields defined in the schema. If a field cannot be determined from the input text, set its value to null. Do not infer, assume, rewrite, rephrase, summarize, or generate any information that is not explicitly present in the input text. Return only a valid JSON object that exactly follows the provided schema." -%}
|
| 15 |
+
{%- if input_text is defined and json_schema is defined -%}
|
| 16 |
+
<|im_start|><|system|>{{ '\n' }}{{ extraction_system }}<|endoftext|>{{ '\n' }}
|
| 17 |
+
<|im_start|><|user|>{{ '\n' }}Input-Text: {{ input_text }}
|
| 18 |
+
|
| 19 |
+
JSON-Schema: {%- if json_schema is string -%}{{ json_schema }}{%- else -%}{{ json_schema | tojson }}{%- endif -%}<|endoftext|>{{ '\n' }}
|
| 20 |
+
{%- else -%}
|
| 21 |
+
{%- for message in messages -%}
|
| 22 |
+
{%- if message["role"] == "system" -%}
|
| 23 |
+
<|im_start|><|system|>{{ '\n' }}{{ message["content"] }}<|endoftext|>{{ '\n' }}
|
| 24 |
+
{%- elif message["role"] == "user" -%}
|
| 25 |
+
<|im_start|><|user|>{{ '\n' }}{{ message["content"] }}<|endoftext|>{{ '\n' }}
|
| 26 |
+
{%- elif message["role"] == "assistant" -%}
|
| 27 |
+
<|im_start|><|assistant|>{{ '\n' }}{%- generation -%}{{ message["content"] }}<|endoftext|>{{ '\n' }}{%- endgeneration -%}
|
| 28 |
+
{%- endif -%}
|
| 29 |
+
{%- endfor -%}
|
| 30 |
+
{%- endif -%}
|
| 31 |
+
{%- if add_generation_prompt -%}
|
| 32 |
+
<|im_start|><|assistant|>{{ '\n' }}
|
| 33 |
+
{%- endif -%}
|
.ipynb_checkpoints/config-checkpoint.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"architectures": [
|
| 3 |
+
"NandiForCausalLM"
|
| 4 |
+
],
|
| 5 |
+
"attention_bias": false,
|
| 6 |
+
"attention_dropout": 0.0,
|
| 7 |
+
"auto_map": {
|
| 8 |
+
"AutoConfig": "configuration_nandi.NandiConfig",
|
| 9 |
+
"AutoModel": "modeling_nandi.NandiModel",
|
| 10 |
+
"AutoModelForCausalLM": "modeling_nandi.NandiForCausalLM"
|
| 11 |
+
},
|
| 12 |
+
"bos_token_id": 1,
|
| 13 |
+
"dtype": "bfloat16",
|
| 14 |
+
"embedding_rank": 512,
|
| 15 |
+
"eos_token_id": 0,
|
| 16 |
+
"factorized_embedding": true,
|
| 17 |
+
"head_dim": 90,
|
| 18 |
+
"hidden_act": "silu",
|
| 19 |
+
"hidden_size": 1440,
|
| 20 |
+
"initializer_range": 0.02,
|
| 21 |
+
"intermediate_size": 3280,
|
| 22 |
+
"kv_cache_mode": "shared",
|
| 23 |
+
"layer_sharing": false,
|
| 24 |
+
"layer_sharing_repeats": 1,
|
| 25 |
+
"max_position_embeddings": 12288,
|
| 26 |
+
"mlp_bias": false,
|
| 27 |
+
"model_type": "nandi",
|
| 28 |
+
"num_attention_heads": 16,
|
| 29 |
+
"num_hidden_layers": 30,
|
| 30 |
+
"num_key_value_heads": 8,
|
| 31 |
+
"pad_token_id": 3,
|
| 32 |
+
"pretraining_tp": 1,
|
| 33 |
+
"q_norm": true,
|
| 34 |
+
"qk_norm": false,
|
| 35 |
+
"rms_norm_eps": 1e-06,
|
| 36 |
+
"rope_parameters": {
|
| 37 |
+
"rope_theta": 1000000.0,
|
| 38 |
+
"rope_type": "default"
|
| 39 |
+
},
|
| 40 |
+
"shared_kv": true,
|
| 41 |
+
"tie_word_embeddings": true,
|
| 42 |
+
"transformers_version": "5.14.1",
|
| 43 |
+
"use_cache": false,
|
| 44 |
+
"vocab_size": 131072
|
| 45 |
+
}
|
.ipynb_checkpoints/generation_config-checkpoint.json
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"_from_model_config": true,
|
| 3 |
+
"bos_token_id": 1,
|
| 4 |
+
"eos_token_id": [
|
| 5 |
+
0
|
| 6 |
+
],
|
| 7 |
+
"pad_token_id": 3,
|
| 8 |
+
"transformers_version": "5.14.1",
|
| 9 |
+
"use_cache": true
|
| 10 |
+
}
|
.ipynb_checkpoints/tokenization_nandi-checkpoint.py
ADDED
|
@@ -0,0 +1,219 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2026 The HuggingFace Inc. team. All rights reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
"""Tokenization classes for the Nandi family."""
|
| 15 |
+
|
| 16 |
+
from __future__ import annotations
|
| 17 |
+
|
| 18 |
+
import json
|
| 19 |
+
from typing import Any
|
| 20 |
+
|
| 21 |
+
from tokenizers import Regex, Tokenizer, decoders, normalizers, pre_tokenizers
|
| 22 |
+
from tokenizers.models import BPE
|
| 23 |
+
|
| 24 |
+
from transformers.tokenization_utils_tokenizers import TokenizersBackend
|
| 25 |
+
from transformers.utils import logging
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
logger = logging.get_logger(__name__)
|
| 29 |
+
|
| 30 |
+
PRETOKENIZE_REGEX = r"""(?i:'s|'t|'re|'ve|'m|'ll|'d)|[^\r\n\p{L}\p{N}]?(?:\p{L}\p{M}*)+|\p{N}| ?[^\s\p{L}\p{N}]+[\r\n]*|\s*[\r\n]+|\s+(?!\S)|\s+"""
|
| 31 |
+
|
| 32 |
+
ALLOWED_TEMPLATE_LEAF_TYPES = frozenset({"string", "number", "integer", "boolean", "null"})
|
| 33 |
+
_IM_START = "<|im_start|>"
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
def normalize_extraction_template(template: Any) -> dict[str, Any]:
|
| 37 |
+
"""Convert a type-hint template to null-placeholder schema (matches SFT/DPO training)."""
|
| 38 |
+
if isinstance(template, str):
|
| 39 |
+
try:
|
| 40 |
+
template = json.loads(template)
|
| 41 |
+
except json.JSONDecodeError as exc:
|
| 42 |
+
raise ValueError(f"template must be valid JSON: {exc}") from exc
|
| 43 |
+
|
| 44 |
+
if not isinstance(template, dict):
|
| 45 |
+
raise ValueError("template root must be a JSON object")
|
| 46 |
+
|
| 47 |
+
return _nullify_template_node(template)
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
def _nullify_template_node(node: Any) -> Any:
|
| 51 |
+
if node is None:
|
| 52 |
+
return None
|
| 53 |
+
|
| 54 |
+
if isinstance(node, dict):
|
| 55 |
+
return {key: _nullify_template_node(value) for key, value in node.items()}
|
| 56 |
+
|
| 57 |
+
if isinstance(node, list):
|
| 58 |
+
if len(node) == 0:
|
| 59 |
+
return []
|
| 60 |
+
if len(node) == 1:
|
| 61 |
+
item = node[0]
|
| 62 |
+
if isinstance(item, str) and item in ALLOWED_TEMPLATE_LEAF_TYPES:
|
| 63 |
+
return []
|
| 64 |
+
return [_nullify_template_node(item)]
|
| 65 |
+
raise ValueError(
|
| 66 |
+
'array template must be [] or a one-element type list, e.g. ["string"]'
|
| 67 |
+
)
|
| 68 |
+
|
| 69 |
+
if isinstance(node, str):
|
| 70 |
+
if node in ALLOWED_TEMPLATE_LEAF_TYPES:
|
| 71 |
+
return None
|
| 72 |
+
raise ValueError(
|
| 73 |
+
f"invalid template leaf {node!r}; use a type name like 'string' or null"
|
| 74 |
+
)
|
| 75 |
+
|
| 76 |
+
if isinstance(node, bool):
|
| 77 |
+
raise ValueError("template leaf must be a type name, not a boolean literal")
|
| 78 |
+
|
| 79 |
+
if isinstance(node, (int, float)):
|
| 80 |
+
raise ValueError("template leaf must be a type name, not a numeric literal")
|
| 81 |
+
|
| 82 |
+
raise ValueError(f"unsupported template value: {node!r}")
|
| 83 |
+
|
| 84 |
+
|
| 85 |
+
def _maybe_add_im_start_prefix(text: str) -> str:
|
| 86 |
+
stripped = text.lstrip()
|
| 87 |
+
if stripped.startswith(_IM_START):
|
| 88 |
+
return text
|
| 89 |
+
return f"{_IM_START} {text}"
|
| 90 |
+
|
| 91 |
+
|
| 92 |
+
class NandiTokenizer(TokenizersBackend):
|
| 93 |
+
model_input_names = ["input_ids", "attention_mask"]
|
| 94 |
+
model = BPE
|
| 95 |
+
|
| 96 |
+
def __init__(
|
| 97 |
+
self,
|
| 98 |
+
vocab: str | dict[str, int] | None = None,
|
| 99 |
+
merges: str | list[str] | None = None,
|
| 100 |
+
vocab_file=None,
|
| 101 |
+
merges_file=None,
|
| 102 |
+
unk_token: str = "<|endoftext|>",
|
| 103 |
+
bos_token: str = "<|im_start|>",
|
| 104 |
+
eos_token: str = "<|endoftext|>",
|
| 105 |
+
pad_token: str = "<|pad|>",
|
| 106 |
+
add_prefix_space: bool | None = None,
|
| 107 |
+
**kwargs,
|
| 108 |
+
):
|
| 109 |
+
self._vocab = (
|
| 110 |
+
vocab
|
| 111 |
+
if vocab is not None
|
| 112 |
+
else {
|
| 113 |
+
"<|endoftext|>": 0,
|
| 114 |
+
}
|
| 115 |
+
)
|
| 116 |
+
self._merges = merges or []
|
| 117 |
+
|
| 118 |
+
self._tokenizer = Tokenizer(
|
| 119 |
+
BPE(
|
| 120 |
+
vocab=self._vocab,
|
| 121 |
+
merges=self._merges,
|
| 122 |
+
dropout=None,
|
| 123 |
+
unk_token=None,
|
| 124 |
+
continuing_subword_prefix="",
|
| 125 |
+
end_of_word_suffix="",
|
| 126 |
+
fuse_unk=False,
|
| 127 |
+
byte_fallback=False,
|
| 128 |
+
)
|
| 129 |
+
)
|
| 130 |
+
self._tokenizer.decoder = decoders.ByteLevel()
|
| 131 |
+
self._tokenizer.normalizer = normalizers.NFC()
|
| 132 |
+
self._tokenizer.pre_tokenizer = pre_tokenizers.Sequence(
|
| 133 |
+
[
|
| 134 |
+
pre_tokenizers.Split(
|
| 135 |
+
Regex(PRETOKENIZE_REGEX),
|
| 136 |
+
behavior="isolated",
|
| 137 |
+
invert=False,
|
| 138 |
+
),
|
| 139 |
+
pre_tokenizers.ByteLevel(
|
| 140 |
+
add_prefix_space=False,
|
| 141 |
+
trim_offsets=True,
|
| 142 |
+
use_regex=False,
|
| 143 |
+
),
|
| 144 |
+
]
|
| 145 |
+
)
|
| 146 |
+
|
| 147 |
+
super().__init__(
|
| 148 |
+
vocab_file=vocab_file,
|
| 149 |
+
merges_file=merges_file,
|
| 150 |
+
unk_token=unk_token,
|
| 151 |
+
bos_token=bos_token,
|
| 152 |
+
eos_token=eos_token,
|
| 153 |
+
pad_token=pad_token,
|
| 154 |
+
add_prefix_space=add_prefix_space,
|
| 155 |
+
**kwargs,
|
| 156 |
+
)
|
| 157 |
+
|
| 158 |
+
def apply_chat_template(self, conversation, *args, **kwargs):
|
| 159 |
+
"""Support extraction inference via input_text + template (type hints)."""
|
| 160 |
+
template = kwargs.pop("template", None)
|
| 161 |
+
input_text = kwargs.get("input_text")
|
| 162 |
+
json_schema = kwargs.get("json_schema")
|
| 163 |
+
|
| 164 |
+
if template is not None:
|
| 165 |
+
if json_schema is not None:
|
| 166 |
+
raise ValueError("Pass either template or json_schema, not both.")
|
| 167 |
+
if input_text is None:
|
| 168 |
+
raise ValueError("input_text is required when template is provided.")
|
| 169 |
+
null_schema = normalize_extraction_template(template)
|
| 170 |
+
kwargs["json_schema"] = json.dumps(null_schema, ensure_ascii=False)
|
| 171 |
+
elif json_schema is not None and not isinstance(json_schema, str):
|
| 172 |
+
if isinstance(json_schema, (dict, list)):
|
| 173 |
+
kwargs["json_schema"] = json.dumps(json_schema, ensure_ascii=False)
|
| 174 |
+
|
| 175 |
+
return super().apply_chat_template(conversation, *args, **kwargs)
|
| 176 |
+
|
| 177 |
+
normalize_template = staticmethod(normalize_extraction_template)
|
| 178 |
+
|
| 179 |
+
def __call__(self, text, *args, **kwargs):
|
| 180 |
+
add_special_tokens = kwargs.get("add_special_tokens", False)
|
| 181 |
+
|
| 182 |
+
if not add_special_tokens:
|
| 183 |
+
if isinstance(text, list):
|
| 184 |
+
text = [_maybe_add_im_start_prefix(t) if isinstance(t, str) else t for t in text]
|
| 185 |
+
elif isinstance(text, str):
|
| 186 |
+
text = _maybe_add_im_start_prefix(text)
|
| 187 |
+
|
| 188 |
+
return super().__call__(text, *args, **kwargs)
|
| 189 |
+
|
| 190 |
+
def encode(
|
| 191 |
+
self,
|
| 192 |
+
text,
|
| 193 |
+
text_pair=None,
|
| 194 |
+
add_special_tokens: bool = True,
|
| 195 |
+
padding=False,
|
| 196 |
+
truncation=None,
|
| 197 |
+
max_length=None,
|
| 198 |
+
stride: int = 0,
|
| 199 |
+
padding_side=None,
|
| 200 |
+
return_tensors=None,
|
| 201 |
+
**kwargs,
|
| 202 |
+
):
|
| 203 |
+
if isinstance(text, str):
|
| 204 |
+
text = _maybe_add_im_start_prefix(text)
|
| 205 |
+
return super().encode(
|
| 206 |
+
text,
|
| 207 |
+
text_pair=text_pair,
|
| 208 |
+
add_special_tokens=add_special_tokens,
|
| 209 |
+
padding=padding,
|
| 210 |
+
truncation=truncation,
|
| 211 |
+
max_length=max_length,
|
| 212 |
+
stride=stride,
|
| 213 |
+
padding_side=padding_side,
|
| 214 |
+
return_tensors=return_tensors,
|
| 215 |
+
**kwargs,
|
| 216 |
+
)
|
| 217 |
+
|
| 218 |
+
|
| 219 |
+
__all__ = ["NandiTokenizer", "normalize_extraction_template"]
|
.ipynb_checkpoints/tokenizer_config-checkpoint.json
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"backend": "tokenizers",
|
| 3 |
+
"bos_token": "<|im_start|>",
|
| 4 |
+
"eos_token": "<|endoftext|>",
|
| 5 |
+
"model_max_length": 12288,
|
| 6 |
+
"pad_token": "<|pad|>",
|
| 7 |
+
"tokenizer_class": "TokenizersBackend",
|
| 8 |
+
"unk_token": "<|endoftext|>"
|
| 9 |
+
}
|
chat_template.jinja
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{# Lumma schema-conditioned extraction chat template.
|
| 2 |
+
#
|
| 3 |
+
# INFERENCE: pass input_text + template (type hints) or input_text + json_schema (null schema).
|
| 4 |
+
# tokenizer.apply_chat_template(
|
| 5 |
+
# [],
|
| 6 |
+
# input_text="John Smith joined Acme.",
|
| 7 |
+
# template={"name": "string", "company": "string"},
|
| 8 |
+
# add_generation_prompt=True,
|
| 9 |
+
# )
|
| 10 |
+
# NandiTokenizer converts template -> null schema via json.dumps before rendering.
|
| 11 |
+
#
|
| 12 |
+
# TRAINING: pass full messages (system / user / assistant) as usual.
|
| 13 |
+
# #}
|
| 14 |
+
{%- set extraction_system = "You are Lumma, an AI model developed by FrontiersMind. You will be provided with an input text and a JSON schema. Your task is to extract information from the input text strictly according to the provided schema. Populate only the fields defined in the schema. If a field cannot be determined from the input text, set its value to null. Do not infer, assume, rewrite, rephrase, summarize, or generate any information that is not explicitly present in the input text. Return only a valid JSON object that exactly follows the provided schema." -%}
|
| 15 |
+
{%- if input_text is defined and json_schema is defined -%}
|
| 16 |
+
<|im_start|><|system|>{{ '\n' }}{{ extraction_system }}<|endoftext|>{{ '\n' }}
|
| 17 |
+
<|im_start|><|user|>{{ '\n' }}Input-Text: {{ input_text }}
|
| 18 |
+
|
| 19 |
+
JSON-Schema: {%- if json_schema is string -%}{{ json_schema }}{%- else -%}{{ json_schema | tojson }}{%- endif -%}<|endoftext|>{{ '\n' }}
|
| 20 |
+
{%- else -%}
|
| 21 |
+
{%- for message in messages -%}
|
| 22 |
+
{%- if message["role"] == "system" -%}
|
| 23 |
+
<|im_start|><|system|>{{ '\n' }}{{ message["content"] }}<|endoftext|>{{ '\n' }}
|
| 24 |
+
{%- elif message["role"] == "user" -%}
|
| 25 |
+
<|im_start|><|user|>{{ '\n' }}{{ message["content"] }}<|endoftext|>{{ '\n' }}
|
| 26 |
+
{%- elif message["role"] == "assistant" -%}
|
| 27 |
+
<|im_start|><|assistant|>{{ '\n' }}{%- generation -%}{{ message["content"] }}<|endoftext|>{{ '\n' }}{%- endgeneration -%}
|
| 28 |
+
{%- endif -%}
|
| 29 |
+
{%- endfor -%}
|
| 30 |
+
{%- endif -%}
|
| 31 |
+
{%- if add_generation_prompt -%}
|
| 32 |
+
<|im_start|><|assistant|>{{ '\n' }}
|
| 33 |
+
{%- endif -%}
|
config.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"architectures": [
|
| 3 |
+
"NandiForCausalLM"
|
| 4 |
+
],
|
| 5 |
+
"attention_bias": false,
|
| 6 |
+
"attention_dropout": 0.0,
|
| 7 |
+
"auto_map": {
|
| 8 |
+
"AutoConfig": "configuration_nandi.NandiConfig",
|
| 9 |
+
"AutoModel": "modeling_nandi.NandiModel",
|
| 10 |
+
"AutoModelForCausalLM": "modeling_nandi.NandiForCausalLM"
|
| 11 |
+
},
|
| 12 |
+
"bos_token_id": 1,
|
| 13 |
+
"dtype": "bfloat16",
|
| 14 |
+
"embedding_rank": 512,
|
| 15 |
+
"eos_token_id": 0,
|
| 16 |
+
"factorized_embedding": true,
|
| 17 |
+
"head_dim": 90,
|
| 18 |
+
"hidden_act": "silu",
|
| 19 |
+
"hidden_size": 1440,
|
| 20 |
+
"initializer_range": 0.02,
|
| 21 |
+
"intermediate_size": 3280,
|
| 22 |
+
"kv_cache_mode": "shared",
|
| 23 |
+
"layer_sharing": false,
|
| 24 |
+
"layer_sharing_repeats": 1,
|
| 25 |
+
"max_position_embeddings": 12288,
|
| 26 |
+
"mlp_bias": false,
|
| 27 |
+
"model_type": "nandi",
|
| 28 |
+
"num_attention_heads": 16,
|
| 29 |
+
"num_hidden_layers": 30,
|
| 30 |
+
"num_key_value_heads": 8,
|
| 31 |
+
"pad_token_id": 3,
|
| 32 |
+
"pretraining_tp": 1,
|
| 33 |
+
"q_norm": true,
|
| 34 |
+
"qk_norm": false,
|
| 35 |
+
"rms_norm_eps": 1e-06,
|
| 36 |
+
"rope_parameters": {
|
| 37 |
+
"rope_theta": 1000000.0,
|
| 38 |
+
"rope_type": "default"
|
| 39 |
+
},
|
| 40 |
+
"shared_kv": true,
|
| 41 |
+
"tie_word_embeddings": true,
|
| 42 |
+
"transformers_version": "5.14.1",
|
| 43 |
+
"use_cache": false,
|
| 44 |
+
"vocab_size": 131072
|
| 45 |
+
}
|
configuration_nandi.py
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from transformers.configuration_utils import PretrainedConfig
|
| 2 |
+
|
| 3 |
+
|
| 4 |
+
class NandiConfig(PretrainedConfig):
|
| 5 |
+
r"""
|
| 6 |
+
Configuration class for the Nandi model.
|
| 7 |
+
|
| 8 |
+
Example:
|
| 9 |
+
|
| 10 |
+
```python
|
| 11 |
+
>>> from transformers import AutoConfig, AutoModelForCausalLM
|
| 12 |
+
|
| 13 |
+
>>> configuration = AutoConfig.from_pretrained("Rta-AILabs/Nandi-500M-remote", trust_remote_code=True)
|
| 14 |
+
|
| 15 |
+
>>> model = AutoModelForCausalLM.from_pretrained("Rta-AILabs/Nandi-500M-remote", trust_remote_code=True)
|
| 16 |
+
|
| 17 |
+
>>> configuration = model.config
|
| 18 |
+
```
|
| 19 |
+
"""
|
| 20 |
+
|
| 21 |
+
model_type = "nandi"
|
| 22 |
+
keys_to_ignore_at_inference = ["past_key_values"]
|
| 23 |
+
|
| 24 |
+
base_model_tp_plan = {
|
| 25 |
+
"layers.*.self_attn.q_proj": "colwise",
|
| 26 |
+
"layers.*.self_attn.k_proj": "colwise",
|
| 27 |
+
"layers.*.self_attn.v_proj": "colwise",
|
| 28 |
+
"layers.*.self_attn.o_proj": "rowwise",
|
| 29 |
+
"layers.*.mlp.gate_proj": "colwise",
|
| 30 |
+
"layers.*.mlp.up_proj": "colwise",
|
| 31 |
+
"layers.*.mlp.down_proj": "rowwise",
|
| 32 |
+
}
|
| 33 |
+
|
| 34 |
+
def __init__(
|
| 35 |
+
self,
|
| 36 |
+
vocab_size=131072,
|
| 37 |
+
hidden_size=1248,
|
| 38 |
+
intermediate_size=3556,
|
| 39 |
+
num_hidden_layers=28,
|
| 40 |
+
num_attention_heads=16,
|
| 41 |
+
num_key_value_heads=8,
|
| 42 |
+
head_dim=None,
|
| 43 |
+
hidden_act="silu",
|
| 44 |
+
max_position_embeddings=2048,
|
| 45 |
+
initializer_range=0.008,
|
| 46 |
+
rms_norm_eps=1e-6,
|
| 47 |
+
use_cache=True,
|
| 48 |
+
pad_token_id=None,
|
| 49 |
+
bos_token_id=1,
|
| 50 |
+
eos_token_id=0,
|
| 51 |
+
pretraining_tp=1,
|
| 52 |
+
tie_word_embeddings=True,
|
| 53 |
+
rope_parameters=None,
|
| 54 |
+
attention_bias=False,
|
| 55 |
+
attention_dropout=0.0,
|
| 56 |
+
mlp_bias=False,
|
| 57 |
+
factorized_embedding=False,
|
| 58 |
+
embedding_rank=768,
|
| 59 |
+
layer_sharing=False,
|
| 60 |
+
layer_sharing_repeats=1,
|
| 61 |
+
qk_norm=True,
|
| 62 |
+
q_norm=False,
|
| 63 |
+
shared_kv=True,
|
| 64 |
+
kv_cache_mode="shared",
|
| 65 |
+
**kwargs,
|
| 66 |
+
):
|
| 67 |
+
self.vocab_size = vocab_size
|
| 68 |
+
self.hidden_size = hidden_size
|
| 69 |
+
self.intermediate_size = intermediate_size
|
| 70 |
+
self.num_hidden_layers = num_hidden_layers
|
| 71 |
+
self.num_attention_heads = num_attention_heads
|
| 72 |
+
self.num_key_value_heads = num_key_value_heads if num_key_value_heads is not None else num_attention_heads
|
| 73 |
+
self.head_dim = head_dim if head_dim is not None else hidden_size // num_attention_heads
|
| 74 |
+
self.hidden_act = hidden_act
|
| 75 |
+
self.max_position_embeddings = max_position_embeddings
|
| 76 |
+
self.initializer_range = initializer_range
|
| 77 |
+
self.rms_norm_eps = rms_norm_eps
|
| 78 |
+
self.use_cache = use_cache
|
| 79 |
+
self.pretraining_tp = pretraining_tp
|
| 80 |
+
self.rope_parameters = rope_parameters if rope_parameters is not None else {"rope_theta": 1000000.0}
|
| 81 |
+
self.attention_bias = attention_bias
|
| 82 |
+
self.attention_dropout = attention_dropout
|
| 83 |
+
self.mlp_bias = mlp_bias
|
| 84 |
+
self.factorized_embedding = factorized_embedding
|
| 85 |
+
self.embedding_rank = embedding_rank
|
| 86 |
+
self.layer_sharing = layer_sharing
|
| 87 |
+
|
| 88 |
+
self.layer_sharing_repeats = max(1, int(layer_sharing_repeats or 1))
|
| 89 |
+
if qk_norm and q_norm:
|
| 90 |
+
raise ValueError("Use either qk_norm or q_norm, not both")
|
| 91 |
+
self.qk_norm = qk_norm
|
| 92 |
+
self.q_norm = q_norm
|
| 93 |
+
|
| 94 |
+
self.shared_kv = shared_kv
|
| 95 |
+
|
| 96 |
+
if kv_cache_mode not in ("shared", "vanilla"):
|
| 97 |
+
raise ValueError(
|
| 98 |
+
f"`kv_cache_mode` must be 'shared' or 'vanilla', got {kv_cache_mode!r}."
|
| 99 |
+
)
|
| 100 |
+
self.kv_cache_mode = kv_cache_mode
|
| 101 |
+
|
| 102 |
+
if self.factorized_embedding and self.embedding_rank <= 0:
|
| 103 |
+
raise ValueError(
|
| 104 |
+
f"`embedding_rank` must be positive when `factorized_embedding=True`, got {self.embedding_rank}."
|
| 105 |
+
)
|
| 106 |
+
if self.hidden_size % self.num_attention_heads != 0:
|
| 107 |
+
raise ValueError(
|
| 108 |
+
f"`hidden_size` ({self.hidden_size}) must be divisible by "
|
| 109 |
+
f"`num_attention_heads` ({self.num_attention_heads})."
|
| 110 |
+
)
|
| 111 |
+
if self.layer_sharing_repeats < 1:
|
| 112 |
+
raise ValueError(f"`layer_sharing_repeats` must be >= 1, got {self.layer_sharing_repeats}.")
|
| 113 |
+
|
| 114 |
+
super().__init__(
|
| 115 |
+
pad_token_id=pad_token_id,
|
| 116 |
+
bos_token_id=bos_token_id,
|
| 117 |
+
eos_token_id=eos_token_id,
|
| 118 |
+
tie_word_embeddings=tie_word_embeddings,
|
| 119 |
+
**kwargs,
|
| 120 |
+
)
|
| 121 |
+
|
| 122 |
+
|
| 123 |
+
__all__ = ["NandiConfig"]
|
generation_config.json
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"_from_model_config": true,
|
| 3 |
+
"bos_token_id": 1,
|
| 4 |
+
"eos_token_id": [
|
| 5 |
+
0
|
| 6 |
+
],
|
| 7 |
+
"pad_token_id": 3,
|
| 8 |
+
"transformers_version": "5.14.1",
|
| 9 |
+
"use_cache": true
|
| 10 |
+
}
|
model.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:3424f17dd80518a25878cf1c8f9816a9276ce0422ce38232648d975dbb32a085
|
| 3 |
+
size 1298775408
|
modeling_nandi.py
ADDED
|
@@ -0,0 +1,541 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from collections.abc import Callable
|
| 2 |
+
|
| 3 |
+
import torch
|
| 4 |
+
import torch.nn as nn
|
| 5 |
+
|
| 6 |
+
from transformers.activations import ACT2FN
|
| 7 |
+
from transformers.cache_utils import Cache, DynamicCache, DynamicLayer
|
| 8 |
+
from transformers.generation import GenerationMixin
|
| 9 |
+
from transformers.integrations import use_kernel_forward_from_hub
|
| 10 |
+
from transformers.masking_utils import create_causal_mask
|
| 11 |
+
from transformers.modeling_layers import GradientCheckpointingLayer
|
| 12 |
+
from transformers.modeling_outputs import BaseModelOutputWithPast, CausalLMOutputWithPast
|
| 13 |
+
from transformers.modeling_rope_utils import ROPE_INIT_FUNCTIONS, dynamic_rope_update
|
| 14 |
+
from transformers.modeling_utils import ALL_ATTENTION_FUNCTIONS, PreTrainedModel
|
| 15 |
+
from transformers.processing_utils import Unpack
|
| 16 |
+
from transformers.utils import TransformersKwargs, auto_docstring
|
| 17 |
+
from transformers.utils.deprecation import deprecate_kwarg
|
| 18 |
+
from transformers.utils.generic import can_return_tuple, merge_with_config_defaults
|
| 19 |
+
from transformers.utils.output_capturing import capture_outputs
|
| 20 |
+
from .configuration_nandi import NandiConfig
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
@use_kernel_forward_from_hub("RMSNorm")
|
| 24 |
+
class NandiRMSNorm(nn.Module):
|
| 25 |
+
def __init__(self, hidden_size, eps=1e-6):
|
| 26 |
+
super().__init__()
|
| 27 |
+
self.weight = nn.Parameter(torch.ones(hidden_size))
|
| 28 |
+
self.variance_epsilon = eps
|
| 29 |
+
|
| 30 |
+
def forward(self, hidden_states):
|
| 31 |
+
input_dtype = hidden_states.dtype
|
| 32 |
+
hidden_states = hidden_states.to(torch.float32)
|
| 33 |
+
variance = hidden_states.pow(2).mean(-1, keepdim=True)
|
| 34 |
+
hidden_states = hidden_states * torch.rsqrt(variance + self.variance_epsilon)
|
| 35 |
+
return self.weight * hidden_states.to(input_dtype)
|
| 36 |
+
|
| 37 |
+
def extra_repr(self):
|
| 38 |
+
return f"{tuple(self.weight.shape)}, eps={self.variance_epsilon}"
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
class NandiRotaryEmbedding(nn.Module):
|
| 42 |
+
inv_freq: torch.Tensor
|
| 43 |
+
|
| 44 |
+
def __init__(self, config: NandiConfig, device=None):
|
| 45 |
+
super().__init__()
|
| 46 |
+
self.max_seq_len_cached = config.max_position_embeddings
|
| 47 |
+
self.original_max_seq_len = config.max_position_embeddings
|
| 48 |
+
|
| 49 |
+
self.config = config
|
| 50 |
+
self.rope_type = self.config.rope_parameters.get("rope_type", "default")
|
| 51 |
+
rope_init_fn: Callable = self.compute_default_rope_parameters
|
| 52 |
+
if self.rope_type != "default":
|
| 53 |
+
rope_init_fn = ROPE_INIT_FUNCTIONS[self.rope_type]
|
| 54 |
+
inv_freq, self.attention_scaling = rope_init_fn(self.config, device)
|
| 55 |
+
|
| 56 |
+
self.register_buffer("inv_freq", inv_freq, persistent=False)
|
| 57 |
+
self.register_buffer("original_inv_freq", inv_freq.clone(), persistent=False)
|
| 58 |
+
|
| 59 |
+
@staticmethod
|
| 60 |
+
def compute_default_rope_parameters(
|
| 61 |
+
config: NandiConfig | None = None,
|
| 62 |
+
device: torch.device | None = None,
|
| 63 |
+
seq_len: int | None = None,
|
| 64 |
+
) -> tuple[torch.Tensor, float]:
|
| 65 |
+
del seq_len
|
| 66 |
+
base = config.rope_parameters["rope_theta"]
|
| 67 |
+
dim = getattr(config, "head_dim", None) or config.hidden_size // config.num_attention_heads
|
| 68 |
+
attention_factor = 1.0
|
| 69 |
+
inv_freq = 1.0 / (
|
| 70 |
+
base ** (torch.arange(0, dim, 2, dtype=torch.int64).to(device=device, dtype=torch.float) / dim)
|
| 71 |
+
)
|
| 72 |
+
return inv_freq, attention_factor
|
| 73 |
+
|
| 74 |
+
@torch.no_grad()
|
| 75 |
+
@dynamic_rope_update
|
| 76 |
+
def forward(self, x, position_ids):
|
| 77 |
+
inv_freq_expanded = self.inv_freq[None, :, None].float().expand(position_ids.shape[0], -1, 1).to(x.device)
|
| 78 |
+
position_ids_expanded = position_ids[:, None, :].float()
|
| 79 |
+
|
| 80 |
+
device_type = x.device.type if isinstance(x.device.type, str) and x.device.type != "mps" else "cpu"
|
| 81 |
+
with torch.autocast(device_type=device_type, enabled=False):
|
| 82 |
+
freqs = (inv_freq_expanded.float() @ position_ids_expanded.float()).transpose(1, 2)
|
| 83 |
+
emb = torch.cat((freqs, freqs), dim=-1)
|
| 84 |
+
cos = emb.cos() * self.attention_scaling
|
| 85 |
+
sin = emb.sin() * self.attention_scaling
|
| 86 |
+
|
| 87 |
+
return cos.to(dtype=x.dtype), sin.to(dtype=x.dtype)
|
| 88 |
+
|
| 89 |
+
|
| 90 |
+
def rotate_half(x):
|
| 91 |
+
"""Rotates half the hidden dims of the input."""
|
| 92 |
+
x1 = x[..., : x.shape[-1] // 2]
|
| 93 |
+
x2 = x[..., x.shape[-1] // 2 :]
|
| 94 |
+
return torch.cat((-x2, x1), dim=-1)
|
| 95 |
+
|
| 96 |
+
|
| 97 |
+
def apply_rotary_pos_emb(q, k, cos, sin, position_ids=None, unsqueeze_dim=1):
|
| 98 |
+
del position_ids
|
| 99 |
+
cos = cos.unsqueeze(unsqueeze_dim)
|
| 100 |
+
sin = sin.unsqueeze(unsqueeze_dim)
|
| 101 |
+
q_embed = (q * cos) + (rotate_half(q) * sin)
|
| 102 |
+
k_embed = (k * cos) + (rotate_half(k) * sin)
|
| 103 |
+
return q_embed, k_embed
|
| 104 |
+
|
| 105 |
+
|
| 106 |
+
def repeat_kv(hidden_states: torch.Tensor, n_rep: int) -> torch.Tensor:
|
| 107 |
+
batch, num_key_value_heads, slen, head_dim = hidden_states.shape
|
| 108 |
+
if n_rep == 1:
|
| 109 |
+
return hidden_states
|
| 110 |
+
hidden_states = hidden_states[:, :, None, :, :].expand(batch, num_key_value_heads, n_rep, slen, head_dim)
|
| 111 |
+
return hidden_states.reshape(batch, num_key_value_heads * n_rep, slen, head_dim)
|
| 112 |
+
|
| 113 |
+
|
| 114 |
+
def eager_attention_forward(
|
| 115 |
+
module: nn.Module,
|
| 116 |
+
query: torch.Tensor,
|
| 117 |
+
key: torch.Tensor,
|
| 118 |
+
value: torch.Tensor,
|
| 119 |
+
attention_mask: torch.Tensor | None,
|
| 120 |
+
scaling: float,
|
| 121 |
+
dropout: float = 0.0,
|
| 122 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 123 |
+
):
|
| 124 |
+
del kwargs
|
| 125 |
+
key_states = repeat_kv(key, module.num_key_value_groups)
|
| 126 |
+
value_states = repeat_kv(value, module.num_key_value_groups)
|
| 127 |
+
|
| 128 |
+
attn_weights = torch.matmul(query, key_states.transpose(2, 3)) * scaling
|
| 129 |
+
if attention_mask is not None:
|
| 130 |
+
causal_mask = attention_mask[:, :, :, : key_states.shape[-2]]
|
| 131 |
+
attn_weights = attn_weights + causal_mask
|
| 132 |
+
|
| 133 |
+
attn_weights = nn.functional.softmax(attn_weights, dim=-1, dtype=torch.float32).to(query.dtype)
|
| 134 |
+
attn_weights = nn.functional.dropout(attn_weights, p=dropout, training=module.training)
|
| 135 |
+
attn_output = torch.matmul(attn_weights, value_states)
|
| 136 |
+
attn_output = attn_output.transpose(1, 2).contiguous()
|
| 137 |
+
|
| 138 |
+
return attn_output, attn_weights
|
| 139 |
+
|
| 140 |
+
|
| 141 |
+
class NandiAttention(nn.Module):
|
| 142 |
+
def __init__(self, config: NandiConfig, layer_idx: int):
|
| 143 |
+
super().__init__()
|
| 144 |
+
self.config = config
|
| 145 |
+
self.layer_idx = layer_idx
|
| 146 |
+
self.head_dim = config.head_dim
|
| 147 |
+
self.num_key_value_groups = config.num_attention_heads // config.num_key_value_heads
|
| 148 |
+
self.scaling = self.head_dim**-0.5
|
| 149 |
+
self.attention_dropout = config.attention_dropout
|
| 150 |
+
self.is_causal = True
|
| 151 |
+
|
| 152 |
+
self.shared_kv = getattr(config, "shared_kv", False)
|
| 153 |
+
|
| 154 |
+
self.q_proj = nn.Linear(
|
| 155 |
+
config.hidden_size, config.num_attention_heads * self.head_dim, bias=config.attention_bias
|
| 156 |
+
)
|
| 157 |
+
self.k_proj = nn.Linear(
|
| 158 |
+
config.hidden_size, config.num_key_value_heads * self.head_dim, bias=config.attention_bias
|
| 159 |
+
)
|
| 160 |
+
if self.shared_kv:
|
| 161 |
+
self.v_proj = None
|
| 162 |
+
else:
|
| 163 |
+
self.v_proj = nn.Linear(
|
| 164 |
+
config.hidden_size, config.num_key_value_heads * self.head_dim, bias=config.attention_bias
|
| 165 |
+
)
|
| 166 |
+
self.o_proj = nn.Linear(
|
| 167 |
+
config.num_attention_heads * self.head_dim, config.hidden_size, bias=config.attention_bias
|
| 168 |
+
)
|
| 169 |
+
|
| 170 |
+
self.qk_norm = getattr(config, "qk_norm", False)
|
| 171 |
+
self.q_norm_enabled = getattr(config, "q_norm", False)
|
| 172 |
+
if self.qk_norm:
|
| 173 |
+
self.q_norm = NandiRMSNorm(self.head_dim, eps=config.rms_norm_eps)
|
| 174 |
+
self.k_norm = NandiRMSNorm(self.head_dim, eps=config.rms_norm_eps)
|
| 175 |
+
elif self.q_norm_enabled:
|
| 176 |
+
self.q_norm = NandiRMSNorm(self.head_dim, eps=config.rms_norm_eps)
|
| 177 |
+
self.k_norm = None
|
| 178 |
+
else:
|
| 179 |
+
self.q_norm = None
|
| 180 |
+
self.k_norm = None
|
| 181 |
+
|
| 182 |
+
@deprecate_kwarg("past_key_value", new_name="past_key_values", version="4.58")
|
| 183 |
+
def forward(
|
| 184 |
+
self,
|
| 185 |
+
hidden_states: torch.Tensor,
|
| 186 |
+
position_embeddings: tuple[torch.Tensor, torch.Tensor],
|
| 187 |
+
attention_mask: torch.Tensor | None,
|
| 188 |
+
past_key_values: Cache | None = None,
|
| 189 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 190 |
+
) -> tuple[torch.Tensor, torch.Tensor]:
|
| 191 |
+
input_shape = hidden_states.shape[:-1]
|
| 192 |
+
hidden_shape = (*input_shape, -1, self.head_dim)
|
| 193 |
+
|
| 194 |
+
query_states = self.q_proj(hidden_states).view(hidden_shape).transpose(1, 2)
|
| 195 |
+
k_raw = self.k_proj(hidden_states).view(hidden_shape).transpose(1, 2)
|
| 196 |
+
|
| 197 |
+
if self.shared_kv:
|
| 198 |
+
kv_cache_mode = getattr(self.config, "kv_cache_mode", "shared")
|
| 199 |
+
|
| 200 |
+
if self.qk_norm:
|
| 201 |
+
query_states = self.q_norm(query_states)
|
| 202 |
+
elif self.q_norm_enabled:
|
| 203 |
+
query_states = self.q_norm(query_states)
|
| 204 |
+
|
| 205 |
+
if kv_cache_mode == "shared":
|
| 206 |
+
if past_key_values is not None:
|
| 207 |
+
empty_v = torch.empty(
|
| 208 |
+
k_raw.shape[0],
|
| 209 |
+
k_raw.shape[1],
|
| 210 |
+
0,
|
| 211 |
+
k_raw.shape[3],
|
| 212 |
+
device=k_raw.device,
|
| 213 |
+
dtype=k_raw.dtype,
|
| 214 |
+
)
|
| 215 |
+
k_raw_full, _ = past_key_values.update(k_raw, empty_v, self.layer_idx)
|
| 216 |
+
else:
|
| 217 |
+
k_raw_full = k_raw
|
| 218 |
+
|
| 219 |
+
value_states = k_raw_full
|
| 220 |
+
key_states = self.k_norm(k_raw_full) if self.qk_norm else k_raw_full
|
| 221 |
+
|
| 222 |
+
cos, sin = position_embeddings
|
| 223 |
+
q_len = query_states.shape[-2]
|
| 224 |
+
cos_q = cos[..., -q_len:, :]
|
| 225 |
+
sin_q = sin[..., -q_len:, :]
|
| 226 |
+
query_states, _ = apply_rotary_pos_emb(query_states, query_states, cos_q, sin_q)
|
| 227 |
+
_, key_states = apply_rotary_pos_emb(key_states, key_states, cos, sin)
|
| 228 |
+
|
| 229 |
+
else:
|
| 230 |
+
key_states = self.k_norm(k_raw) if self.qk_norm else k_raw
|
| 231 |
+
value_states = k_raw
|
| 232 |
+
|
| 233 |
+
cos, sin = position_embeddings
|
| 234 |
+
query_states, key_states = apply_rotary_pos_emb(
|
| 235 |
+
query_states, key_states, cos, sin
|
| 236 |
+
)
|
| 237 |
+
|
| 238 |
+
if past_key_values is not None:
|
| 239 |
+
key_states, value_states = past_key_values.update(
|
| 240 |
+
key_states, value_states, self.layer_idx
|
| 241 |
+
)
|
| 242 |
+
|
| 243 |
+
else:
|
| 244 |
+
value_states = self.v_proj(hidden_states).view(hidden_shape).transpose(1, 2)
|
| 245 |
+
key_states = k_raw
|
| 246 |
+
|
| 247 |
+
if self.qk_norm:
|
| 248 |
+
query_states = self.q_norm(query_states)
|
| 249 |
+
key_states = self.k_norm(key_states)
|
| 250 |
+
elif self.q_norm_enabled:
|
| 251 |
+
query_states = self.q_norm(query_states)
|
| 252 |
+
|
| 253 |
+
cos, sin = position_embeddings
|
| 254 |
+
query_states, key_states = apply_rotary_pos_emb(query_states, key_states, cos, sin)
|
| 255 |
+
|
| 256 |
+
if past_key_values is not None:
|
| 257 |
+
key_states, value_states = past_key_values.update(key_states, value_states, self.layer_idx)
|
| 258 |
+
|
| 259 |
+
attention_interface: Callable = eager_attention_forward
|
| 260 |
+
if self.config._attn_implementation != "eager":
|
| 261 |
+
attention_interface = ALL_ATTENTION_FUNCTIONS[self.config._attn_implementation]
|
| 262 |
+
|
| 263 |
+
attn_output, attn_weights = attention_interface(
|
| 264 |
+
self,
|
| 265 |
+
query_states,
|
| 266 |
+
key_states,
|
| 267 |
+
value_states,
|
| 268 |
+
attention_mask,
|
| 269 |
+
dropout=0.0 if not self.training else self.attention_dropout,
|
| 270 |
+
scaling=self.scaling,
|
| 271 |
+
**kwargs,
|
| 272 |
+
)
|
| 273 |
+
|
| 274 |
+
attn_output = attn_output.reshape(*input_shape, -1).contiguous()
|
| 275 |
+
attn_output = self.o_proj(attn_output)
|
| 276 |
+
return attn_output, attn_weights
|
| 277 |
+
|
| 278 |
+
|
| 279 |
+
class NandiMLP(nn.Module):
|
| 280 |
+
def __init__(self, config):
|
| 281 |
+
super().__init__()
|
| 282 |
+
self.gate_proj = nn.Linear(config.hidden_size, config.intermediate_size, bias=config.mlp_bias)
|
| 283 |
+
self.up_proj = nn.Linear(config.hidden_size, config.intermediate_size, bias=config.mlp_bias)
|
| 284 |
+
self.down_proj = nn.Linear(config.intermediate_size, config.hidden_size, bias=config.mlp_bias)
|
| 285 |
+
self.act_fn = ACT2FN[config.hidden_act]
|
| 286 |
+
|
| 287 |
+
def forward(self, x):
|
| 288 |
+
return self.down_proj(self.act_fn(self.gate_proj(x)) * self.up_proj(x))
|
| 289 |
+
|
| 290 |
+
|
| 291 |
+
class NandiDecoderLayer(GradientCheckpointingLayer):
|
| 292 |
+
def __init__(self, config: NandiConfig, layer_idx: int):
|
| 293 |
+
super().__init__()
|
| 294 |
+
self.hidden_size = config.hidden_size
|
| 295 |
+
self.self_attn = NandiAttention(config=config, layer_idx=layer_idx)
|
| 296 |
+
self.mlp = NandiMLP(config)
|
| 297 |
+
self.input_layernorm = NandiRMSNorm(config.hidden_size, eps=config.rms_norm_eps)
|
| 298 |
+
self.post_attention_layernorm = NandiRMSNorm(config.hidden_size, eps=config.rms_norm_eps)
|
| 299 |
+
|
| 300 |
+
@deprecate_kwarg("past_key_value", new_name="past_key_values", version="4.58")
|
| 301 |
+
def forward(
|
| 302 |
+
self,
|
| 303 |
+
hidden_states: torch.Tensor,
|
| 304 |
+
attention_mask: torch.Tensor | None = None,
|
| 305 |
+
position_ids: torch.LongTensor | None = None,
|
| 306 |
+
past_key_values: Cache | None = None,
|
| 307 |
+
use_cache: bool | None = False,
|
| 308 |
+
position_embeddings: tuple[torch.Tensor, torch.Tensor] | None = None,
|
| 309 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 310 |
+
) -> torch.Tensor:
|
| 311 |
+
residual = hidden_states
|
| 312 |
+
hidden_states = self.input_layernorm(hidden_states)
|
| 313 |
+
|
| 314 |
+
hidden_states, _ = self.self_attn(
|
| 315 |
+
hidden_states=hidden_states,
|
| 316 |
+
attention_mask=attention_mask,
|
| 317 |
+
position_ids=position_ids,
|
| 318 |
+
past_key_values=past_key_values,
|
| 319 |
+
use_cache=use_cache,
|
| 320 |
+
position_embeddings=position_embeddings,
|
| 321 |
+
**kwargs,
|
| 322 |
+
)
|
| 323 |
+
hidden_states = residual + hidden_states
|
| 324 |
+
|
| 325 |
+
residual = hidden_states
|
| 326 |
+
hidden_states = self.post_attention_layernorm(hidden_states)
|
| 327 |
+
hidden_states = self.mlp(hidden_states)
|
| 328 |
+
hidden_states = residual + hidden_states
|
| 329 |
+
return hidden_states
|
| 330 |
+
|
| 331 |
+
|
| 332 |
+
class _VirtualLayerCache:
|
| 333 |
+
"""Proxy that shifts cache layer indices by `offset` to give each repeat its own virtual slots."""
|
| 334 |
+
|
| 335 |
+
def __init__(self, cache: Cache, offset: int):
|
| 336 |
+
self._cache = cache
|
| 337 |
+
self._offset = offset
|
| 338 |
+
|
| 339 |
+
def __getattr__(self, name):
|
| 340 |
+
return getattr(self._cache, name)
|
| 341 |
+
|
| 342 |
+
def update(self, key_states, value_states, layer_idx, cache_kwargs=None):
|
| 343 |
+
virtual_idx = layer_idx + self._offset
|
| 344 |
+
# grow the backing cache if generate() pre-allocated fewer slots than needed
|
| 345 |
+
while len(self._cache.layers) <= virtual_idx:
|
| 346 |
+
self._cache.layers.append(DynamicLayer())
|
| 347 |
+
return self._cache.update(key_states, value_states, virtual_idx, cache_kwargs)
|
| 348 |
+
|
| 349 |
+
def get_seq_length(self, layer_idx: int = 0) -> int:
|
| 350 |
+
return self._cache.get_seq_length(layer_idx + self._offset)
|
| 351 |
+
|
| 352 |
+
|
| 353 |
+
@auto_docstring
|
| 354 |
+
class NandiPreTrainedModel(PreTrainedModel):
|
| 355 |
+
config: NandiConfig
|
| 356 |
+
base_model_prefix = "model"
|
| 357 |
+
supports_gradient_checkpointing = True
|
| 358 |
+
_no_split_modules = ["NandiDecoderLayer"]
|
| 359 |
+
_skip_keys_device_placement = ["past_key_values"]
|
| 360 |
+
_supports_flash_attn = True
|
| 361 |
+
_supports_sdpa = True
|
| 362 |
+
_supports_flex_attn = True
|
| 363 |
+
_can_compile_fullgraph = True
|
| 364 |
+
_supports_attention_backend = True
|
| 365 |
+
_can_record_outputs = {
|
| 366 |
+
"hidden_states": NandiDecoderLayer,
|
| 367 |
+
"attentions": NandiAttention,
|
| 368 |
+
}
|
| 369 |
+
|
| 370 |
+
def __init__(self, config: NandiConfig):
|
| 371 |
+
super().__init__(config)
|
| 372 |
+
|
| 373 |
+
|
| 374 |
+
@auto_docstring
|
| 375 |
+
class NandiModel(NandiPreTrainedModel):
|
| 376 |
+
def __init__(self, config: NandiConfig):
|
| 377 |
+
super().__init__(config)
|
| 378 |
+
self.padding_idx = config.pad_token_id
|
| 379 |
+
self.vocab_size = config.vocab_size
|
| 380 |
+
embedding_dim = config.embedding_rank if config.factorized_embedding else config.hidden_size
|
| 381 |
+
|
| 382 |
+
self.embed_tokens = nn.Embedding(config.vocab_size, embedding_dim, self.padding_idx)
|
| 383 |
+
self.embedding_proj = (
|
| 384 |
+
nn.Linear(config.embedding_rank, config.hidden_size, bias=False) if config.factorized_embedding else None
|
| 385 |
+
)
|
| 386 |
+
self.layers = nn.ModuleList(
|
| 387 |
+
[NandiDecoderLayer(config, layer_idx) for layer_idx in range(config.num_hidden_layers)]
|
| 388 |
+
)
|
| 389 |
+
self.norm = NandiRMSNorm(config.hidden_size, eps=config.rms_norm_eps)
|
| 390 |
+
self.rotary_emb = NandiRotaryEmbedding(config=config)
|
| 391 |
+
self.gradient_checkpointing = False
|
| 392 |
+
|
| 393 |
+
self.post_init()
|
| 394 |
+
|
| 395 |
+
@merge_with_config_defaults
|
| 396 |
+
@capture_outputs
|
| 397 |
+
@auto_docstring
|
| 398 |
+
def forward(
|
| 399 |
+
self,
|
| 400 |
+
input_ids: torch.LongTensor | None = None,
|
| 401 |
+
attention_mask: torch.Tensor | None = None,
|
| 402 |
+
position_ids: torch.LongTensor | None = None,
|
| 403 |
+
past_key_values: Cache | None = None,
|
| 404 |
+
inputs_embeds: torch.FloatTensor | None = None,
|
| 405 |
+
use_cache: bool | None = None,
|
| 406 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 407 |
+
) -> BaseModelOutputWithPast:
|
| 408 |
+
if (input_ids is None) ^ (inputs_embeds is not None):
|
| 409 |
+
raise ValueError("You must specify exactly one of input_ids or inputs_embeds")
|
| 410 |
+
|
| 411 |
+
if inputs_embeds is None:
|
| 412 |
+
inputs_embeds = self.embed_tokens(input_ids)
|
| 413 |
+
|
| 414 |
+
if self.embedding_proj is not None:
|
| 415 |
+
inputs_embeds = self.embedding_proj(inputs_embeds)
|
| 416 |
+
repeats = max(1, int(getattr(self.config, "layer_sharing_repeats", 1) or 1))
|
| 417 |
+
|
| 418 |
+
if use_cache and past_key_values is None:
|
| 419 |
+
past_key_values = DynamicCache()
|
| 420 |
+
|
| 421 |
+
if position_ids is None:
|
| 422 |
+
past_seen_tokens = past_key_values.get_seq_length() if past_key_values is not None else 0
|
| 423 |
+
position_ids = torch.arange(inputs_embeds.shape[1], device=inputs_embeds.device) + past_seen_tokens
|
| 424 |
+
position_ids = position_ids.unsqueeze(0)
|
| 425 |
+
|
| 426 |
+
causal_mask = create_causal_mask(
|
| 427 |
+
config=self.config,
|
| 428 |
+
inputs_embeds=inputs_embeds,
|
| 429 |
+
attention_mask=attention_mask,
|
| 430 |
+
past_key_values=past_key_values,
|
| 431 |
+
position_ids=position_ids,
|
| 432 |
+
)
|
| 433 |
+
|
| 434 |
+
hidden_states = inputs_embeds
|
| 435 |
+
kv_cache_mode = getattr(self.config, "kv_cache_mode", "shared")
|
| 436 |
+
if (
|
| 437 |
+
getattr(self.config, "shared_kv", False)
|
| 438 |
+
and kv_cache_mode == "shared"
|
| 439 |
+
and past_key_values is not None
|
| 440 |
+
):
|
| 441 |
+
past_len = past_key_values.get_seq_length(0)
|
| 442 |
+
cur_len = inputs_embeds.shape[1]
|
| 443 |
+
full_position_ids = torch.arange(
|
| 444 |
+
past_len + cur_len, device=inputs_embeds.device
|
| 445 |
+
).unsqueeze(0)
|
| 446 |
+
position_embeddings = self.rotary_emb(hidden_states, position_ids=full_position_ids)
|
| 447 |
+
else:
|
| 448 |
+
position_embeddings = self.rotary_emb(hidden_states, position_ids=position_ids)
|
| 449 |
+
|
| 450 |
+
for decoder_layer in self.layers[: self.config.num_hidden_layers]:
|
| 451 |
+
for repeat_idx in range(repeats):
|
| 452 |
+
|
| 453 |
+
repeat_cache = (
|
| 454 |
+
_VirtualLayerCache(past_key_values, repeat_idx * self.config.num_hidden_layers)
|
| 455 |
+
if (past_key_values is not None and repeat_idx > 0)
|
| 456 |
+
else past_key_values
|
| 457 |
+
)
|
| 458 |
+
hidden_states = decoder_layer(
|
| 459 |
+
hidden_states,
|
| 460 |
+
attention_mask=causal_mask,
|
| 461 |
+
position_embeddings=position_embeddings,
|
| 462 |
+
position_ids=position_ids,
|
| 463 |
+
past_key_values=repeat_cache,
|
| 464 |
+
use_cache=use_cache,
|
| 465 |
+
**kwargs,
|
| 466 |
+
)
|
| 467 |
+
|
| 468 |
+
hidden_states = self.norm(hidden_states)
|
| 469 |
+
return BaseModelOutputWithPast(
|
| 470 |
+
last_hidden_state=hidden_states,
|
| 471 |
+
past_key_values=past_key_values,
|
| 472 |
+
)
|
| 473 |
+
|
| 474 |
+
|
| 475 |
+
@auto_docstring
|
| 476 |
+
class NandiForCausalLM(NandiPreTrainedModel, GenerationMixin):
|
| 477 |
+
_tied_weights_keys = {"lm_head.weight": "model.embed_tokens.weight"}
|
| 478 |
+
_tp_plan = {"lm_head": "colwise_gather_output"}
|
| 479 |
+
_pp_plan = {
|
| 480 |
+
"lm_head_proj": (["hidden_states"], ["hidden_states"]),
|
| 481 |
+
"lm_head": (["hidden_states"], ["logits"]),
|
| 482 |
+
}
|
| 483 |
+
|
| 484 |
+
def __init__(self, config):
|
| 485 |
+
super().__init__(config)
|
| 486 |
+
self.model = NandiModel(config)
|
| 487 |
+
self.vocab_size = config.vocab_size
|
| 488 |
+
|
| 489 |
+
lm_head_in_features = config.embedding_rank if config.factorized_embedding else config.hidden_size
|
| 490 |
+
self.lm_head_proj = (
|
| 491 |
+
nn.Linear(config.hidden_size, config.embedding_rank, bias=False) if config.factorized_embedding else None
|
| 492 |
+
)
|
| 493 |
+
self.lm_head = nn.Linear(lm_head_in_features, config.vocab_size, bias=False)
|
| 494 |
+
|
| 495 |
+
self.post_init()
|
| 496 |
+
|
| 497 |
+
@can_return_tuple
|
| 498 |
+
@auto_docstring
|
| 499 |
+
def forward(
|
| 500 |
+
self,
|
| 501 |
+
input_ids: torch.LongTensor | None = None,
|
| 502 |
+
attention_mask: torch.Tensor | None = None,
|
| 503 |
+
position_ids: torch.LongTensor | None = None,
|
| 504 |
+
past_key_values: Cache | None = None,
|
| 505 |
+
inputs_embeds: torch.FloatTensor | None = None,
|
| 506 |
+
labels: torch.LongTensor | None = None,
|
| 507 |
+
use_cache: bool | None = None,
|
| 508 |
+
logits_to_keep: int | torch.Tensor = 0,
|
| 509 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 510 |
+
) -> CausalLMOutputWithPast:
|
| 511 |
+
outputs: BaseModelOutputWithPast = self.model(
|
| 512 |
+
input_ids=input_ids,
|
| 513 |
+
attention_mask=attention_mask,
|
| 514 |
+
position_ids=position_ids,
|
| 515 |
+
past_key_values=past_key_values,
|
| 516 |
+
inputs_embeds=inputs_embeds,
|
| 517 |
+
use_cache=use_cache,
|
| 518 |
+
**kwargs,
|
| 519 |
+
)
|
| 520 |
+
|
| 521 |
+
hidden_states = outputs.last_hidden_state
|
| 522 |
+
if self.lm_head_proj is not None:
|
| 523 |
+
hidden_states = self.lm_head_proj(hidden_states)
|
| 524 |
+
|
| 525 |
+
slice_indices = slice(-logits_to_keep, None) if isinstance(logits_to_keep, int) else logits_to_keep
|
| 526 |
+
logits = self.lm_head(hidden_states[:, slice_indices, :])
|
| 527 |
+
|
| 528 |
+
loss = None
|
| 529 |
+
if labels is not None:
|
| 530 |
+
loss = self.loss_function(logits=logits, labels=labels, vocab_size=self.config.vocab_size, **kwargs)
|
| 531 |
+
|
| 532 |
+
return CausalLMOutputWithPast(
|
| 533 |
+
loss=loss,
|
| 534 |
+
logits=logits,
|
| 535 |
+
past_key_values=outputs.past_key_values,
|
| 536 |
+
hidden_states=outputs.hidden_states,
|
| 537 |
+
attentions=outputs.attentions,
|
| 538 |
+
)
|
| 539 |
+
|
| 540 |
+
|
| 541 |
+
__all__ = ["NandiPreTrainedModel", "NandiModel", "NandiForCausalLM"]
|
tokenization_nandi.py
ADDED
|
@@ -0,0 +1,232 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2026 The HuggingFace Inc. team. All rights reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
"""Tokenization classes for the Nandi family."""
|
| 15 |
+
|
| 16 |
+
from __future__ import annotations
|
| 17 |
+
|
| 18 |
+
import json
|
| 19 |
+
from typing import Any
|
| 20 |
+
|
| 21 |
+
from tokenizers import Regex, Tokenizer, decoders, normalizers, pre_tokenizers
|
| 22 |
+
from tokenizers.models import BPE
|
| 23 |
+
|
| 24 |
+
from transformers.tokenization_utils_tokenizers import TokenizersBackend
|
| 25 |
+
from transformers.utils import logging
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
logger = logging.get_logger(__name__)
|
| 29 |
+
|
| 30 |
+
PRETOKENIZE_REGEX = r"""(?i:'s|'t|'re|'ve|'m|'ll|'d)|[^\r\n\p{L}\p{N}]?(?:\p{L}\p{M}*)+|\p{N}| ?[^\s\p{L}\p{N}]+[\r\n]*|\s*[\r\n]+|\s+(?!\S)|\s+"""
|
| 31 |
+
|
| 32 |
+
ALLOWED_TEMPLATE_LEAF_TYPES = frozenset({"string", "number", "integer", "boolean", "null"})
|
| 33 |
+
_IM_START = "<|im_start|>"
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
def normalize_extraction_template(template: Any) -> dict[str, Any]:
|
| 37 |
+
"""Convert a type-hint template to null-placeholder schema (matches SFT/DPO training)."""
|
| 38 |
+
if isinstance(template, str):
|
| 39 |
+
try:
|
| 40 |
+
template = json.loads(template)
|
| 41 |
+
except json.JSONDecodeError as exc:
|
| 42 |
+
raise ValueError(f"template must be valid JSON: {exc}") from exc
|
| 43 |
+
|
| 44 |
+
if not isinstance(template, dict):
|
| 45 |
+
raise ValueError("template root must be a JSON object")
|
| 46 |
+
|
| 47 |
+
return _nullify_template_node(template)
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
def _nullify_template_node(node: Any) -> Any:
|
| 51 |
+
if node is None:
|
| 52 |
+
return None
|
| 53 |
+
|
| 54 |
+
if isinstance(node, dict):
|
| 55 |
+
return {key: _nullify_template_node(value) for key, value in node.items()}
|
| 56 |
+
|
| 57 |
+
if isinstance(node, list):
|
| 58 |
+
if len(node) == 0:
|
| 59 |
+
return []
|
| 60 |
+
if len(node) == 1:
|
| 61 |
+
item = node[0]
|
| 62 |
+
if isinstance(item, str) and item in ALLOWED_TEMPLATE_LEAF_TYPES:
|
| 63 |
+
return []
|
| 64 |
+
return [_nullify_template_node(item)]
|
| 65 |
+
raise ValueError(
|
| 66 |
+
'array template must be [] or a one-element type list, e.g. ["string"]'
|
| 67 |
+
)
|
| 68 |
+
|
| 69 |
+
if isinstance(node, str):
|
| 70 |
+
if node in ALLOWED_TEMPLATE_LEAF_TYPES:
|
| 71 |
+
return None
|
| 72 |
+
raise ValueError(
|
| 73 |
+
f"invalid template leaf {node!r}; use a type name like 'string' or null"
|
| 74 |
+
)
|
| 75 |
+
|
| 76 |
+
if isinstance(node, bool):
|
| 77 |
+
raise ValueError("template leaf must be a type name, not a boolean literal")
|
| 78 |
+
|
| 79 |
+
if isinstance(node, (int, float)):
|
| 80 |
+
raise ValueError("template leaf must be a type name, not a numeric literal")
|
| 81 |
+
|
| 82 |
+
raise ValueError(f"unsupported template value: {node!r}")
|
| 83 |
+
|
| 84 |
+
|
| 85 |
+
def _maybe_add_im_start_prefix(text: str) -> str:
|
| 86 |
+
stripped = text.lstrip()
|
| 87 |
+
if stripped.startswith(_IM_START):
|
| 88 |
+
return text
|
| 89 |
+
return f"{_IM_START} {text}"
|
| 90 |
+
|
| 91 |
+
|
| 92 |
+
class NandiTokenizer(TokenizersBackend):
|
| 93 |
+
model_input_names = ["input_ids", "attention_mask"]
|
| 94 |
+
model = BPE
|
| 95 |
+
|
| 96 |
+
def __init__(
|
| 97 |
+
self,
|
| 98 |
+
vocab: str | dict[str, int] | None = None,
|
| 99 |
+
merges: str | list[str] | None = None,
|
| 100 |
+
vocab_file=None,
|
| 101 |
+
merges_file=None,
|
| 102 |
+
unk_token: str = "<|endoftext|>",
|
| 103 |
+
bos_token: str = "<|im_start|>",
|
| 104 |
+
eos_token: str = "<|endoftext|>",
|
| 105 |
+
pad_token: str = "<|pad|>",
|
| 106 |
+
add_prefix_space: bool | None = None,
|
| 107 |
+
**kwargs,
|
| 108 |
+
):
|
| 109 |
+
self._vocab = (
|
| 110 |
+
vocab
|
| 111 |
+
if vocab is not None
|
| 112 |
+
else {
|
| 113 |
+
"<|endoftext|>": 0,
|
| 114 |
+
}
|
| 115 |
+
)
|
| 116 |
+
self._merges = merges or []
|
| 117 |
+
|
| 118 |
+
self._tokenizer = Tokenizer(
|
| 119 |
+
BPE(
|
| 120 |
+
vocab=self._vocab,
|
| 121 |
+
merges=self._merges,
|
| 122 |
+
dropout=None,
|
| 123 |
+
unk_token=None,
|
| 124 |
+
continuing_subword_prefix="",
|
| 125 |
+
end_of_word_suffix="",
|
| 126 |
+
fuse_unk=False,
|
| 127 |
+
byte_fallback=False,
|
| 128 |
+
)
|
| 129 |
+
)
|
| 130 |
+
self._tokenizer.decoder = decoders.ByteLevel()
|
| 131 |
+
self._tokenizer.normalizer = normalizers.NFC()
|
| 132 |
+
self._tokenizer.pre_tokenizer = pre_tokenizers.Sequence(
|
| 133 |
+
[
|
| 134 |
+
pre_tokenizers.Split(
|
| 135 |
+
Regex(PRETOKENIZE_REGEX),
|
| 136 |
+
behavior="isolated",
|
| 137 |
+
invert=False,
|
| 138 |
+
),
|
| 139 |
+
pre_tokenizers.ByteLevel(
|
| 140 |
+
add_prefix_space=False,
|
| 141 |
+
trim_offsets=True,
|
| 142 |
+
use_regex=False,
|
| 143 |
+
),
|
| 144 |
+
]
|
| 145 |
+
)
|
| 146 |
+
|
| 147 |
+
super().__init__(
|
| 148 |
+
vocab_file=vocab_file,
|
| 149 |
+
merges_file=merges_file,
|
| 150 |
+
unk_token=unk_token,
|
| 151 |
+
bos_token=bos_token,
|
| 152 |
+
eos_token=eos_token,
|
| 153 |
+
pad_token=pad_token,
|
| 154 |
+
add_prefix_space=add_prefix_space,
|
| 155 |
+
**kwargs,
|
| 156 |
+
)
|
| 157 |
+
|
| 158 |
+
def apply_chat_template(self, conversation=None, *args, **kwargs):
|
| 159 |
+
"""Support extraction inference via input_text + template (type hints)."""
|
| 160 |
+
template = kwargs.pop("template", None)
|
| 161 |
+
input_text = kwargs.get("input_text")
|
| 162 |
+
json_schema = kwargs.get("json_schema")
|
| 163 |
+
|
| 164 |
+
extraction_mode = (
|
| 165 |
+
template is not None or input_text is not None or json_schema is not None
|
| 166 |
+
)
|
| 167 |
+
|
| 168 |
+
if template is not None:
|
| 169 |
+
if json_schema is not None:
|
| 170 |
+
raise ValueError("Pass either template or json_schema, not both.")
|
| 171 |
+
if input_text is None:
|
| 172 |
+
raise ValueError("input_text is required when template is provided.")
|
| 173 |
+
null_schema = normalize_extraction_template(template)
|
| 174 |
+
kwargs["json_schema"] = json.dumps(null_schema, ensure_ascii=False)
|
| 175 |
+
elif json_schema is not None and not isinstance(json_schema, str):
|
| 176 |
+
if isinstance(json_schema, (dict, list)):
|
| 177 |
+
kwargs["json_schema"] = json.dumps(json_schema, ensure_ascii=False)
|
| 178 |
+
|
| 179 |
+
if extraction_mode:
|
| 180 |
+
if not conversation:
|
| 181 |
+
conversation = None
|
| 182 |
+
elif conversation is None:
|
| 183 |
+
raise ValueError(
|
| 184 |
+
"conversation is required unless using extraction kwargs "
|
| 185 |
+
"(input_text + template, or input_text + json_schema)."
|
| 186 |
+
)
|
| 187 |
+
|
| 188 |
+
return super().apply_chat_template(conversation, *args, **kwargs)
|
| 189 |
+
|
| 190 |
+
normalize_template = staticmethod(normalize_extraction_template)
|
| 191 |
+
|
| 192 |
+
def __call__(self, text, *args, **kwargs):
|
| 193 |
+
add_special_tokens = kwargs.get("add_special_tokens", False)
|
| 194 |
+
|
| 195 |
+
if not add_special_tokens:
|
| 196 |
+
if isinstance(text, list):
|
| 197 |
+
text = [_maybe_add_im_start_prefix(t) if isinstance(t, str) else t for t in text]
|
| 198 |
+
elif isinstance(text, str):
|
| 199 |
+
text = _maybe_add_im_start_prefix(text)
|
| 200 |
+
|
| 201 |
+
return super().__call__(text, *args, **kwargs)
|
| 202 |
+
|
| 203 |
+
def encode(
|
| 204 |
+
self,
|
| 205 |
+
text,
|
| 206 |
+
text_pair=None,
|
| 207 |
+
add_special_tokens: bool = True,
|
| 208 |
+
padding=False,
|
| 209 |
+
truncation=None,
|
| 210 |
+
max_length=None,
|
| 211 |
+
stride: int = 0,
|
| 212 |
+
padding_side=None,
|
| 213 |
+
return_tensors=None,
|
| 214 |
+
**kwargs,
|
| 215 |
+
):
|
| 216 |
+
if isinstance(text, str):
|
| 217 |
+
text = _maybe_add_im_start_prefix(text)
|
| 218 |
+
return super().encode(
|
| 219 |
+
text,
|
| 220 |
+
text_pair=text_pair,
|
| 221 |
+
add_special_tokens=add_special_tokens,
|
| 222 |
+
padding=padding,
|
| 223 |
+
truncation=truncation,
|
| 224 |
+
max_length=max_length,
|
| 225 |
+
stride=stride,
|
| 226 |
+
padding_side=padding_side,
|
| 227 |
+
return_tensors=return_tensors,
|
| 228 |
+
**kwargs,
|
| 229 |
+
)
|
| 230 |
+
|
| 231 |
+
|
| 232 |
+
__all__ = ["NandiTokenizer", "normalize_extraction_template"]
|
tokenizer.json
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:354154322dbfd5971fff276473422331b7e2f23073a835ebdaa5f5a84f11a340
|
| 3 |
+
size 12460613
|
tokenizer_config.json
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"backend": "tokenizers",
|
| 3 |
+
"bos_token": "<|im_start|>",
|
| 4 |
+
"bos_token_id": 1,
|
| 5 |
+
"eos_token": "<|endoftext|>",
|
| 6 |
+
"eos_token_id": 0,
|
| 7 |
+
"pad_token": "<|pad|>",
|
| 8 |
+
"pad_token_id": 3,
|
| 9 |
+
"model_max_length": 12288,
|
| 10 |
+
"tokenizer_class": "NandiTokenizer",
|
| 11 |
+
"unk_token": "<|endoftext|>",
|
| 12 |
+
"auto_map": {
|
| 13 |
+
"AutoTokenizer": ["tokenization_nandi.NandiTokenizer", null]
|
| 14 |
+
}
|
| 15 |
+
}
|