Add files using upload-large-folder tool
Browse files- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/markdown_it/parser_block.py +111 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/markdown_it/parser_core.py +45 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/markdown_it/renderer.py +336 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/markdown_it/tree.py +345 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia_cusolver_cu12-11.7.3.90.dist-info/INSTALLER +1 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia_cusolver_cu12-11.7.3.90.dist-info/License.txt +1568 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia_cusolver_cu12-11.7.3.90.dist-info/METADATA +48 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia_cusolver_cu12-11.7.3.90.dist-info/RECORD +22 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia_cusolver_cu12-11.7.3.90.dist-info/WHEEL +5 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia_cusolver_cu12-11.7.3.90.dist-info/top_level.txt +1 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/peft/__init__.py +244 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/peft/auto.py +184 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/peft/config.py +408 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/peft/functional.py +34 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/peft/helpers.py +251 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/peft/import_utils.py +172 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/peft/mapping.py +92 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/peft/mapping_func.py +128 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/peft/mixed_model.py +460 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/peft/peft_model.py +0 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/peft/py.typed +0 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/pyarrow/_csv.pxd +55 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/pyarrow/_cuda.pxd +67 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/pyarrow/_dataset.pxd +183 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/pyarrow/_dataset_parquet.pxd +43 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/pyarrow/_feather.pyx +117 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/pyarrow/_fs.pyx +1628 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/pyarrow/_orc.pxd +134 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/pyarrow/_s3fs.pyx +479 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/pyarrow/benchmark.py +21 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/pyarrow/conftest.py +386 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/pyarrow/json.py +19 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/pyarrow/libarrow_python_parquet_encryption.so.1900.1.0 +0 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/pyarrow/orc.py +384 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/pyarrow/pandas_compat.py +1277 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/transformers/configuration_utils.py +1380 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/transformers/convert_graph_to_onnx.py +551 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/transformers/convert_slow_tokenizer.py +1873 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/transformers/convert_slow_tokenizers_checkpoints_to_fast.py +129 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/transformers/dependency_versions_check.py +63 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/transformers/hf_argparser.py +430 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/transformers/image_processing_utils_fast.py +833 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/transformers/image_transforms.py +977 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/transformers/masking_utils.py +1256 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/transformers/modeling_flax_pytorch_utils.py +491 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/transformers/modeling_layers.py +289 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/transformers/modeling_utils.py +0 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/transformers/tokenization_mistral_common.py +1883 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/transformers/trainer_pt_utils.py +1406 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/transformers/trainer_seq2seq.py +386 -0
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/markdown_it/parser_block.py
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Block-level tokenizer."""
|
| 2 |
+
from __future__ import annotations
|
| 3 |
+
|
| 4 |
+
import logging
|
| 5 |
+
from typing import TYPE_CHECKING, Callable
|
| 6 |
+
|
| 7 |
+
from . import rules_block
|
| 8 |
+
from .ruler import Ruler
|
| 9 |
+
from .rules_block.state_block import StateBlock
|
| 10 |
+
from .token import Token
|
| 11 |
+
from .utils import EnvType
|
| 12 |
+
|
| 13 |
+
if TYPE_CHECKING:
|
| 14 |
+
from markdown_it import MarkdownIt
|
| 15 |
+
|
| 16 |
+
LOGGER = logging.getLogger(__name__)
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
RuleFuncBlockType = Callable[[StateBlock, int, int, bool], bool]
|
| 20 |
+
"""(state: StateBlock, startLine: int, endLine: int, silent: bool) -> matched: bool)
|
| 21 |
+
|
| 22 |
+
`silent` disables token generation, useful for lookahead.
|
| 23 |
+
"""
|
| 24 |
+
|
| 25 |
+
_rules: list[tuple[str, RuleFuncBlockType, list[str]]] = [
|
| 26 |
+
# First 2 params - rule name & source. Secondary array - list of rules,
|
| 27 |
+
# which can be terminated by this one.
|
| 28 |
+
("table", rules_block.table, ["paragraph", "reference"]),
|
| 29 |
+
("code", rules_block.code, []),
|
| 30 |
+
("fence", rules_block.fence, ["paragraph", "reference", "blockquote", "list"]),
|
| 31 |
+
(
|
| 32 |
+
"blockquote",
|
| 33 |
+
rules_block.blockquote,
|
| 34 |
+
["paragraph", "reference", "blockquote", "list"],
|
| 35 |
+
),
|
| 36 |
+
("hr", rules_block.hr, ["paragraph", "reference", "blockquote", "list"]),
|
| 37 |
+
("list", rules_block.list_block, ["paragraph", "reference", "blockquote"]),
|
| 38 |
+
("reference", rules_block.reference, []),
|
| 39 |
+
("html_block", rules_block.html_block, ["paragraph", "reference", "blockquote"]),
|
| 40 |
+
("heading", rules_block.heading, ["paragraph", "reference", "blockquote"]),
|
| 41 |
+
("lheading", rules_block.lheading, []),
|
| 42 |
+
("paragraph", rules_block.paragraph, []),
|
| 43 |
+
]
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
class ParserBlock:
|
| 47 |
+
"""
|
| 48 |
+
ParserBlock#ruler -> Ruler
|
| 49 |
+
|
| 50 |
+
[[Ruler]] instance. Keep configuration of block rules.
|
| 51 |
+
"""
|
| 52 |
+
|
| 53 |
+
def __init__(self) -> None:
|
| 54 |
+
self.ruler = Ruler[RuleFuncBlockType]()
|
| 55 |
+
for name, rule, alt in _rules:
|
| 56 |
+
self.ruler.push(name, rule, {"alt": alt})
|
| 57 |
+
|
| 58 |
+
def tokenize(self, state: StateBlock, startLine: int, endLine: int) -> None:
|
| 59 |
+
"""Generate tokens for input range."""
|
| 60 |
+
rules = self.ruler.getRules("")
|
| 61 |
+
line = startLine
|
| 62 |
+
maxNesting = state.md.options.maxNesting
|
| 63 |
+
hasEmptyLines = False
|
| 64 |
+
|
| 65 |
+
while line < endLine:
|
| 66 |
+
state.line = line = state.skipEmptyLines(line)
|
| 67 |
+
if line >= endLine:
|
| 68 |
+
break
|
| 69 |
+
if state.sCount[line] < state.blkIndent:
|
| 70 |
+
# Termination condition for nested calls.
|
| 71 |
+
# Nested calls currently used for blockquotes & lists
|
| 72 |
+
break
|
| 73 |
+
if state.level >= maxNesting:
|
| 74 |
+
# If nesting level exceeded - skip tail to the end.
|
| 75 |
+
# That's not ordinary situation and we should not care about content.
|
| 76 |
+
state.line = endLine
|
| 77 |
+
break
|
| 78 |
+
|
| 79 |
+
# Try all possible rules.
|
| 80 |
+
# On success, rule should:
|
| 81 |
+
# - update `state.line`
|
| 82 |
+
# - update `state.tokens`
|
| 83 |
+
# - return True
|
| 84 |
+
for rule in rules:
|
| 85 |
+
if rule(state, line, endLine, False):
|
| 86 |
+
break
|
| 87 |
+
|
| 88 |
+
# set state.tight if we had an empty line before current tag
|
| 89 |
+
# i.e. latest empty line should not count
|
| 90 |
+
state.tight = not hasEmptyLines
|
| 91 |
+
|
| 92 |
+
line = state.line
|
| 93 |
+
|
| 94 |
+
# paragraph might "eat" one newline after it in nested lists
|
| 95 |
+
if (line - 1) < endLine and state.isEmpty(line - 1):
|
| 96 |
+
hasEmptyLines = True
|
| 97 |
+
|
| 98 |
+
if line < endLine and state.isEmpty(line):
|
| 99 |
+
hasEmptyLines = True
|
| 100 |
+
line += 1
|
| 101 |
+
state.line = line
|
| 102 |
+
|
| 103 |
+
def parse(
|
| 104 |
+
self, src: str, md: MarkdownIt, env: EnvType, outTokens: list[Token]
|
| 105 |
+
) -> list[Token] | None:
|
| 106 |
+
"""Process input string and push block tokens into `outTokens`."""
|
| 107 |
+
if not src:
|
| 108 |
+
return None
|
| 109 |
+
state = StateBlock(src, md, env, outTokens)
|
| 110 |
+
self.tokenize(state, state.line, state.lineMax)
|
| 111 |
+
return state.tokens
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/markdown_it/parser_core.py
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
* class Core
|
| 3 |
+
*
|
| 4 |
+
* Top-level rules executor. Glues block/inline parsers and does intermediate
|
| 5 |
+
* transformations.
|
| 6 |
+
"""
|
| 7 |
+
from __future__ import annotations
|
| 8 |
+
|
| 9 |
+
from typing import Callable
|
| 10 |
+
|
| 11 |
+
from .ruler import Ruler
|
| 12 |
+
from .rules_core import (
|
| 13 |
+
block,
|
| 14 |
+
inline,
|
| 15 |
+
linkify,
|
| 16 |
+
normalize,
|
| 17 |
+
replace,
|
| 18 |
+
smartquotes,
|
| 19 |
+
text_join,
|
| 20 |
+
)
|
| 21 |
+
from .rules_core.state_core import StateCore
|
| 22 |
+
|
| 23 |
+
RuleFuncCoreType = Callable[[StateCore], None]
|
| 24 |
+
|
| 25 |
+
_rules: list[tuple[str, RuleFuncCoreType]] = [
|
| 26 |
+
("normalize", normalize),
|
| 27 |
+
("block", block),
|
| 28 |
+
("inline", inline),
|
| 29 |
+
("linkify", linkify),
|
| 30 |
+
("replacements", replace),
|
| 31 |
+
("smartquotes", smartquotes),
|
| 32 |
+
("text_join", text_join),
|
| 33 |
+
]
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
class ParserCore:
|
| 37 |
+
def __init__(self) -> None:
|
| 38 |
+
self.ruler = Ruler[RuleFuncCoreType]()
|
| 39 |
+
for name, rule in _rules:
|
| 40 |
+
self.ruler.push(name, rule)
|
| 41 |
+
|
| 42 |
+
def process(self, state: StateCore) -> None:
|
| 43 |
+
"""Executes core chain rules."""
|
| 44 |
+
for rule in self.ruler.getRules(""):
|
| 45 |
+
rule(state)
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/markdown_it/renderer.py
ADDED
|
@@ -0,0 +1,336 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
class Renderer
|
| 3 |
+
|
| 4 |
+
Generates HTML from parsed token stream. Each instance has independent
|
| 5 |
+
copy of rules. Those can be rewritten with ease. Also, you can add new
|
| 6 |
+
rules if you create plugin and adds new token types.
|
| 7 |
+
"""
|
| 8 |
+
from __future__ import annotations
|
| 9 |
+
|
| 10 |
+
from collections.abc import Sequence
|
| 11 |
+
import inspect
|
| 12 |
+
from typing import Any, ClassVar, Protocol
|
| 13 |
+
|
| 14 |
+
from .common.utils import escapeHtml, unescapeAll
|
| 15 |
+
from .token import Token
|
| 16 |
+
from .utils import EnvType, OptionsDict
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
class RendererProtocol(Protocol):
|
| 20 |
+
__output__: ClassVar[str]
|
| 21 |
+
|
| 22 |
+
def render(
|
| 23 |
+
self, tokens: Sequence[Token], options: OptionsDict, env: EnvType
|
| 24 |
+
) -> Any:
|
| 25 |
+
...
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
class RendererHTML(RendererProtocol):
|
| 29 |
+
"""Contains render rules for tokens. Can be updated and extended.
|
| 30 |
+
|
| 31 |
+
Example:
|
| 32 |
+
|
| 33 |
+
Each rule is called as independent static function with fixed signature:
|
| 34 |
+
|
| 35 |
+
::
|
| 36 |
+
|
| 37 |
+
class Renderer:
|
| 38 |
+
def token_type_name(self, tokens, idx, options, env) {
|
| 39 |
+
# ...
|
| 40 |
+
return renderedHTML
|
| 41 |
+
|
| 42 |
+
::
|
| 43 |
+
|
| 44 |
+
class CustomRenderer(RendererHTML):
|
| 45 |
+
def strong_open(self, tokens, idx, options, env):
|
| 46 |
+
return '<b>'
|
| 47 |
+
def strong_close(self, tokens, idx, options, env):
|
| 48 |
+
return '</b>'
|
| 49 |
+
|
| 50 |
+
md = MarkdownIt(renderer_cls=CustomRenderer)
|
| 51 |
+
|
| 52 |
+
result = md.render(...)
|
| 53 |
+
|
| 54 |
+
See https://github.com/markdown-it/markdown-it/blob/master/lib/renderer.js
|
| 55 |
+
for more details and examples.
|
| 56 |
+
"""
|
| 57 |
+
|
| 58 |
+
__output__ = "html"
|
| 59 |
+
|
| 60 |
+
def __init__(self, parser: Any = None):
|
| 61 |
+
self.rules = {
|
| 62 |
+
k: v
|
| 63 |
+
for k, v in inspect.getmembers(self, predicate=inspect.ismethod)
|
| 64 |
+
if not (k.startswith("render") or k.startswith("_"))
|
| 65 |
+
}
|
| 66 |
+
|
| 67 |
+
def render(
|
| 68 |
+
self, tokens: Sequence[Token], options: OptionsDict, env: EnvType
|
| 69 |
+
) -> str:
|
| 70 |
+
"""Takes token stream and generates HTML.
|
| 71 |
+
|
| 72 |
+
:param tokens: list on block tokens to render
|
| 73 |
+
:param options: params of parser instance
|
| 74 |
+
:param env: additional data from parsed input
|
| 75 |
+
|
| 76 |
+
"""
|
| 77 |
+
result = ""
|
| 78 |
+
|
| 79 |
+
for i, token in enumerate(tokens):
|
| 80 |
+
if token.type == "inline":
|
| 81 |
+
if token.children:
|
| 82 |
+
result += self.renderInline(token.children, options, env)
|
| 83 |
+
elif token.type in self.rules:
|
| 84 |
+
result += self.rules[token.type](tokens, i, options, env)
|
| 85 |
+
else:
|
| 86 |
+
result += self.renderToken(tokens, i, options, env)
|
| 87 |
+
|
| 88 |
+
return result
|
| 89 |
+
|
| 90 |
+
def renderInline(
|
| 91 |
+
self, tokens: Sequence[Token], options: OptionsDict, env: EnvType
|
| 92 |
+
) -> str:
|
| 93 |
+
"""The same as ``render``, but for single token of `inline` type.
|
| 94 |
+
|
| 95 |
+
:param tokens: list on block tokens to render
|
| 96 |
+
:param options: params of parser instance
|
| 97 |
+
:param env: additional data from parsed input (references, for example)
|
| 98 |
+
"""
|
| 99 |
+
result = ""
|
| 100 |
+
|
| 101 |
+
for i, token in enumerate(tokens):
|
| 102 |
+
if token.type in self.rules:
|
| 103 |
+
result += self.rules[token.type](tokens, i, options, env)
|
| 104 |
+
else:
|
| 105 |
+
result += self.renderToken(tokens, i, options, env)
|
| 106 |
+
|
| 107 |
+
return result
|
| 108 |
+
|
| 109 |
+
def renderToken(
|
| 110 |
+
self,
|
| 111 |
+
tokens: Sequence[Token],
|
| 112 |
+
idx: int,
|
| 113 |
+
options: OptionsDict,
|
| 114 |
+
env: EnvType,
|
| 115 |
+
) -> str:
|
| 116 |
+
"""Default token renderer.
|
| 117 |
+
|
| 118 |
+
Can be overridden by custom function
|
| 119 |
+
|
| 120 |
+
:param idx: token index to render
|
| 121 |
+
:param options: params of parser instance
|
| 122 |
+
"""
|
| 123 |
+
result = ""
|
| 124 |
+
needLf = False
|
| 125 |
+
token = tokens[idx]
|
| 126 |
+
|
| 127 |
+
# Tight list paragraphs
|
| 128 |
+
if token.hidden:
|
| 129 |
+
return ""
|
| 130 |
+
|
| 131 |
+
# Insert a newline between hidden paragraph and subsequent opening
|
| 132 |
+
# block-level tag.
|
| 133 |
+
#
|
| 134 |
+
# For example, here we should insert a newline before blockquote:
|
| 135 |
+
# - a
|
| 136 |
+
# >
|
| 137 |
+
#
|
| 138 |
+
if token.block and token.nesting != -1 and idx and tokens[idx - 1].hidden:
|
| 139 |
+
result += "\n"
|
| 140 |
+
|
| 141 |
+
# Add token name, e.g. `<img`
|
| 142 |
+
result += ("</" if token.nesting == -1 else "<") + token.tag
|
| 143 |
+
|
| 144 |
+
# Encode attributes, e.g. `<img src="foo"`
|
| 145 |
+
result += self.renderAttrs(token)
|
| 146 |
+
|
| 147 |
+
# Add a slash for self-closing tags, e.g. `<img src="foo" /`
|
| 148 |
+
if token.nesting == 0 and options["xhtmlOut"]:
|
| 149 |
+
result += " /"
|
| 150 |
+
|
| 151 |
+
# Check if we need to add a newline after this tag
|
| 152 |
+
if token.block:
|
| 153 |
+
needLf = True
|
| 154 |
+
|
| 155 |
+
if token.nesting == 1 and (idx + 1 < len(tokens)):
|
| 156 |
+
nextToken = tokens[idx + 1]
|
| 157 |
+
|
| 158 |
+
if nextToken.type == "inline" or nextToken.hidden: # noqa: SIM114
|
| 159 |
+
# Block-level tag containing an inline tag.
|
| 160 |
+
#
|
| 161 |
+
needLf = False
|
| 162 |
+
|
| 163 |
+
elif nextToken.nesting == -1 and nextToken.tag == token.tag:
|
| 164 |
+
# Opening tag + closing tag of the same type. E.g. `<li></li>`.
|
| 165 |
+
#
|
| 166 |
+
needLf = False
|
| 167 |
+
|
| 168 |
+
result += ">\n" if needLf else ">"
|
| 169 |
+
|
| 170 |
+
return result
|
| 171 |
+
|
| 172 |
+
@staticmethod
|
| 173 |
+
def renderAttrs(token: Token) -> str:
|
| 174 |
+
"""Render token attributes to string."""
|
| 175 |
+
result = ""
|
| 176 |
+
|
| 177 |
+
for key, value in token.attrItems():
|
| 178 |
+
result += " " + escapeHtml(key) + '="' + escapeHtml(str(value)) + '"'
|
| 179 |
+
|
| 180 |
+
return result
|
| 181 |
+
|
| 182 |
+
def renderInlineAsText(
|
| 183 |
+
self,
|
| 184 |
+
tokens: Sequence[Token] | None,
|
| 185 |
+
options: OptionsDict,
|
| 186 |
+
env: EnvType,
|
| 187 |
+
) -> str:
|
| 188 |
+
"""Special kludge for image `alt` attributes to conform CommonMark spec.
|
| 189 |
+
|
| 190 |
+
Don't try to use it! Spec requires to show `alt` content with stripped markup,
|
| 191 |
+
instead of simple escaping.
|
| 192 |
+
|
| 193 |
+
:param tokens: list on block tokens to render
|
| 194 |
+
:param options: params of parser instance
|
| 195 |
+
:param env: additional data from parsed input
|
| 196 |
+
"""
|
| 197 |
+
result = ""
|
| 198 |
+
|
| 199 |
+
for token in tokens or []:
|
| 200 |
+
if token.type == "text":
|
| 201 |
+
result += token.content
|
| 202 |
+
elif token.type == "image":
|
| 203 |
+
if token.children:
|
| 204 |
+
result += self.renderInlineAsText(token.children, options, env)
|
| 205 |
+
elif token.type == "softbreak":
|
| 206 |
+
result += "\n"
|
| 207 |
+
|
| 208 |
+
return result
|
| 209 |
+
|
| 210 |
+
###################################################
|
| 211 |
+
|
| 212 |
+
def code_inline(
|
| 213 |
+
self, tokens: Sequence[Token], idx: int, options: OptionsDict, env: EnvType
|
| 214 |
+
) -> str:
|
| 215 |
+
token = tokens[idx]
|
| 216 |
+
return (
|
| 217 |
+
"<code"
|
| 218 |
+
+ self.renderAttrs(token)
|
| 219 |
+
+ ">"
|
| 220 |
+
+ escapeHtml(tokens[idx].content)
|
| 221 |
+
+ "</code>"
|
| 222 |
+
)
|
| 223 |
+
|
| 224 |
+
def code_block(
|
| 225 |
+
self,
|
| 226 |
+
tokens: Sequence[Token],
|
| 227 |
+
idx: int,
|
| 228 |
+
options: OptionsDict,
|
| 229 |
+
env: EnvType,
|
| 230 |
+
) -> str:
|
| 231 |
+
token = tokens[idx]
|
| 232 |
+
|
| 233 |
+
return (
|
| 234 |
+
"<pre"
|
| 235 |
+
+ self.renderAttrs(token)
|
| 236 |
+
+ "><code>"
|
| 237 |
+
+ escapeHtml(tokens[idx].content)
|
| 238 |
+
+ "</code></pre>\n"
|
| 239 |
+
)
|
| 240 |
+
|
| 241 |
+
def fence(
|
| 242 |
+
self,
|
| 243 |
+
tokens: Sequence[Token],
|
| 244 |
+
idx: int,
|
| 245 |
+
options: OptionsDict,
|
| 246 |
+
env: EnvType,
|
| 247 |
+
) -> str:
|
| 248 |
+
token = tokens[idx]
|
| 249 |
+
info = unescapeAll(token.info).strip() if token.info else ""
|
| 250 |
+
langName = ""
|
| 251 |
+
langAttrs = ""
|
| 252 |
+
|
| 253 |
+
if info:
|
| 254 |
+
arr = info.split(maxsplit=1)
|
| 255 |
+
langName = arr[0]
|
| 256 |
+
if len(arr) == 2:
|
| 257 |
+
langAttrs = arr[1]
|
| 258 |
+
|
| 259 |
+
if options.highlight:
|
| 260 |
+
highlighted = options.highlight(
|
| 261 |
+
token.content, langName, langAttrs
|
| 262 |
+
) or escapeHtml(token.content)
|
| 263 |
+
else:
|
| 264 |
+
highlighted = escapeHtml(token.content)
|
| 265 |
+
|
| 266 |
+
if highlighted.startswith("<pre"):
|
| 267 |
+
return highlighted + "\n"
|
| 268 |
+
|
| 269 |
+
# If language exists, inject class gently, without modifying original token.
|
| 270 |
+
# May be, one day we will add .deepClone() for token and simplify this part, but
|
| 271 |
+
# now we prefer to keep things local.
|
| 272 |
+
if info:
|
| 273 |
+
# Fake token just to render attributes
|
| 274 |
+
tmpToken = Token(type="", tag="", nesting=0, attrs=token.attrs.copy())
|
| 275 |
+
tmpToken.attrJoin("class", options.langPrefix + langName)
|
| 276 |
+
|
| 277 |
+
return (
|
| 278 |
+
"<pre><code"
|
| 279 |
+
+ self.renderAttrs(tmpToken)
|
| 280 |
+
+ ">"
|
| 281 |
+
+ highlighted
|
| 282 |
+
+ "</code></pre>\n"
|
| 283 |
+
)
|
| 284 |
+
|
| 285 |
+
return (
|
| 286 |
+
"<pre><code"
|
| 287 |
+
+ self.renderAttrs(token)
|
| 288 |
+
+ ">"
|
| 289 |
+
+ highlighted
|
| 290 |
+
+ "</code></pre>\n"
|
| 291 |
+
)
|
| 292 |
+
|
| 293 |
+
def image(
|
| 294 |
+
self,
|
| 295 |
+
tokens: Sequence[Token],
|
| 296 |
+
idx: int,
|
| 297 |
+
options: OptionsDict,
|
| 298 |
+
env: EnvType,
|
| 299 |
+
) -> str:
|
| 300 |
+
token = tokens[idx]
|
| 301 |
+
|
| 302 |
+
# "alt" attr MUST be set, even if empty. Because it's mandatory and
|
| 303 |
+
# should be placed on proper position for tests.
|
| 304 |
+
if token.children:
|
| 305 |
+
token.attrSet("alt", self.renderInlineAsText(token.children, options, env))
|
| 306 |
+
else:
|
| 307 |
+
token.attrSet("alt", "")
|
| 308 |
+
|
| 309 |
+
return self.renderToken(tokens, idx, options, env)
|
| 310 |
+
|
| 311 |
+
def hardbreak(
|
| 312 |
+
self, tokens: Sequence[Token], idx: int, options: OptionsDict, env: EnvType
|
| 313 |
+
) -> str:
|
| 314 |
+
return "<br />\n" if options.xhtmlOut else "<br>\n"
|
| 315 |
+
|
| 316 |
+
def softbreak(
|
| 317 |
+
self, tokens: Sequence[Token], idx: int, options: OptionsDict, env: EnvType
|
| 318 |
+
) -> str:
|
| 319 |
+
return (
|
| 320 |
+
("<br />\n" if options.xhtmlOut else "<br>\n") if options.breaks else "\n"
|
| 321 |
+
)
|
| 322 |
+
|
| 323 |
+
def text(
|
| 324 |
+
self, tokens: Sequence[Token], idx: int, options: OptionsDict, env: EnvType
|
| 325 |
+
) -> str:
|
| 326 |
+
return escapeHtml(tokens[idx].content)
|
| 327 |
+
|
| 328 |
+
def html_block(
|
| 329 |
+
self, tokens: Sequence[Token], idx: int, options: OptionsDict, env: EnvType
|
| 330 |
+
) -> str:
|
| 331 |
+
return tokens[idx].content
|
| 332 |
+
|
| 333 |
+
def html_inline(
|
| 334 |
+
self, tokens: Sequence[Token], idx: int, options: OptionsDict, env: EnvType
|
| 335 |
+
) -> str:
|
| 336 |
+
return tokens[idx].content
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/markdown_it/tree.py
ADDED
|
@@ -0,0 +1,345 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""A tree representation of a linear markdown-it token stream.
|
| 2 |
+
|
| 3 |
+
This module is not part of upstream JavaScript markdown-it.
|
| 4 |
+
"""
|
| 5 |
+
from __future__ import annotations
|
| 6 |
+
|
| 7 |
+
from collections.abc import Generator, Sequence
|
| 8 |
+
import textwrap
|
| 9 |
+
from typing import Any, NamedTuple, TypeVar, overload
|
| 10 |
+
|
| 11 |
+
from .token import Token
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
class _NesterTokens(NamedTuple):
|
| 15 |
+
opening: Token
|
| 16 |
+
closing: Token
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
_NodeType = TypeVar("_NodeType", bound="SyntaxTreeNode")
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
class SyntaxTreeNode:
|
| 23 |
+
"""A Markdown syntax tree node.
|
| 24 |
+
|
| 25 |
+
A class that can be used to construct a tree representation of a linear
|
| 26 |
+
`markdown-it-py` token stream.
|
| 27 |
+
|
| 28 |
+
Each node in the tree represents either:
|
| 29 |
+
- root of the Markdown document
|
| 30 |
+
- a single unnested `Token`
|
| 31 |
+
- a `Token` "_open" and "_close" token pair, and the tokens nested in
|
| 32 |
+
between
|
| 33 |
+
"""
|
| 34 |
+
|
| 35 |
+
def __init__(
|
| 36 |
+
self, tokens: Sequence[Token] = (), *, create_root: bool = True
|
| 37 |
+
) -> None:
|
| 38 |
+
"""Initialize a `SyntaxTreeNode` from a token stream.
|
| 39 |
+
|
| 40 |
+
If `create_root` is True, create a root node for the document.
|
| 41 |
+
"""
|
| 42 |
+
# Only nodes representing an unnested token have self.token
|
| 43 |
+
self.token: Token | None = None
|
| 44 |
+
|
| 45 |
+
# Only containers have nester tokens
|
| 46 |
+
self.nester_tokens: _NesterTokens | None = None
|
| 47 |
+
|
| 48 |
+
# Root node does not have self.parent
|
| 49 |
+
self._parent: Any = None
|
| 50 |
+
|
| 51 |
+
# Empty list unless a non-empty container, or unnested token that has
|
| 52 |
+
# children (i.e. inline or img)
|
| 53 |
+
self._children: list[Any] = []
|
| 54 |
+
|
| 55 |
+
if create_root:
|
| 56 |
+
self._set_children_from_tokens(tokens)
|
| 57 |
+
return
|
| 58 |
+
|
| 59 |
+
if not tokens:
|
| 60 |
+
raise ValueError(
|
| 61 |
+
"Can only create root from empty token sequence."
|
| 62 |
+
" Set `create_root=True`."
|
| 63 |
+
)
|
| 64 |
+
elif len(tokens) == 1:
|
| 65 |
+
inline_token = tokens[0]
|
| 66 |
+
if inline_token.nesting:
|
| 67 |
+
raise ValueError(
|
| 68 |
+
"Unequal nesting level at the start and end of token stream."
|
| 69 |
+
)
|
| 70 |
+
self.token = inline_token
|
| 71 |
+
if inline_token.children:
|
| 72 |
+
self._set_children_from_tokens(inline_token.children)
|
| 73 |
+
else:
|
| 74 |
+
self.nester_tokens = _NesterTokens(tokens[0], tokens[-1])
|
| 75 |
+
self._set_children_from_tokens(tokens[1:-1])
|
| 76 |
+
|
| 77 |
+
def __repr__(self) -> str:
|
| 78 |
+
return f"{type(self).__name__}({self.type})"
|
| 79 |
+
|
| 80 |
+
@overload
|
| 81 |
+
def __getitem__(self: _NodeType, item: int) -> _NodeType:
|
| 82 |
+
...
|
| 83 |
+
|
| 84 |
+
@overload
|
| 85 |
+
def __getitem__(self: _NodeType, item: slice) -> list[_NodeType]:
|
| 86 |
+
...
|
| 87 |
+
|
| 88 |
+
def __getitem__(self: _NodeType, item: int | slice) -> _NodeType | list[_NodeType]:
|
| 89 |
+
return self.children[item]
|
| 90 |
+
|
| 91 |
+
def to_tokens(self: _NodeType) -> list[Token]:
|
| 92 |
+
"""Recover the linear token stream."""
|
| 93 |
+
|
| 94 |
+
def recursive_collect_tokens(node: _NodeType, token_list: list[Token]) -> None:
|
| 95 |
+
if node.type == "root":
|
| 96 |
+
for child in node.children:
|
| 97 |
+
recursive_collect_tokens(child, token_list)
|
| 98 |
+
elif node.token:
|
| 99 |
+
token_list.append(node.token)
|
| 100 |
+
else:
|
| 101 |
+
assert node.nester_tokens
|
| 102 |
+
token_list.append(node.nester_tokens.opening)
|
| 103 |
+
for child in node.children:
|
| 104 |
+
recursive_collect_tokens(child, token_list)
|
| 105 |
+
token_list.append(node.nester_tokens.closing)
|
| 106 |
+
|
| 107 |
+
tokens: list[Token] = []
|
| 108 |
+
recursive_collect_tokens(self, tokens)
|
| 109 |
+
return tokens
|
| 110 |
+
|
| 111 |
+
@property
|
| 112 |
+
def children(self: _NodeType) -> list[_NodeType]:
|
| 113 |
+
return self._children
|
| 114 |
+
|
| 115 |
+
@children.setter
|
| 116 |
+
def children(self: _NodeType, value: list[_NodeType]) -> None:
|
| 117 |
+
self._children = value
|
| 118 |
+
|
| 119 |
+
@property
|
| 120 |
+
def parent(self: _NodeType) -> _NodeType | None:
|
| 121 |
+
return self._parent # type: ignore
|
| 122 |
+
|
| 123 |
+
@parent.setter
|
| 124 |
+
def parent(self: _NodeType, value: _NodeType | None) -> None:
|
| 125 |
+
self._parent = value
|
| 126 |
+
|
| 127 |
+
@property
|
| 128 |
+
def is_root(self) -> bool:
|
| 129 |
+
"""Is the node a special root node?"""
|
| 130 |
+
return not (self.token or self.nester_tokens)
|
| 131 |
+
|
| 132 |
+
@property
|
| 133 |
+
def is_nested(self) -> bool:
|
| 134 |
+
"""Is this node nested?.
|
| 135 |
+
|
| 136 |
+
Returns `True` if the node represents a `Token` pair and tokens in the
|
| 137 |
+
sequence between them, where `Token.nesting` of the first `Token` in
|
| 138 |
+
the pair is 1 and nesting of the other `Token` is -1.
|
| 139 |
+
"""
|
| 140 |
+
return bool(self.nester_tokens)
|
| 141 |
+
|
| 142 |
+
@property
|
| 143 |
+
def siblings(self: _NodeType) -> Sequence[_NodeType]:
|
| 144 |
+
"""Get siblings of the node.
|
| 145 |
+
|
| 146 |
+
Gets the whole group of siblings, including self.
|
| 147 |
+
"""
|
| 148 |
+
if not self.parent:
|
| 149 |
+
return [self]
|
| 150 |
+
return self.parent.children
|
| 151 |
+
|
| 152 |
+
@property
|
| 153 |
+
def type(self) -> str:
|
| 154 |
+
"""Get a string type of the represented syntax.
|
| 155 |
+
|
| 156 |
+
- "root" for root nodes
|
| 157 |
+
- `Token.type` if the node represents an unnested token
|
| 158 |
+
- `Token.type` of the opening token, with "_open" suffix stripped, if
|
| 159 |
+
the node represents a nester token pair
|
| 160 |
+
"""
|
| 161 |
+
if self.is_root:
|
| 162 |
+
return "root"
|
| 163 |
+
if self.token:
|
| 164 |
+
return self.token.type
|
| 165 |
+
assert self.nester_tokens
|
| 166 |
+
return _removesuffix(self.nester_tokens.opening.type, "_open")
|
| 167 |
+
|
| 168 |
+
@property
|
| 169 |
+
def next_sibling(self: _NodeType) -> _NodeType | None:
|
| 170 |
+
"""Get the next node in the sequence of siblings.
|
| 171 |
+
|
| 172 |
+
Returns `None` if this is the last sibling.
|
| 173 |
+
"""
|
| 174 |
+
self_index = self.siblings.index(self)
|
| 175 |
+
if self_index + 1 < len(self.siblings):
|
| 176 |
+
return self.siblings[self_index + 1]
|
| 177 |
+
return None
|
| 178 |
+
|
| 179 |
+
@property
|
| 180 |
+
def previous_sibling(self: _NodeType) -> _NodeType | None:
|
| 181 |
+
"""Get the previous node in the sequence of siblings.
|
| 182 |
+
|
| 183 |
+
Returns `None` if this is the first sibling.
|
| 184 |
+
"""
|
| 185 |
+
self_index = self.siblings.index(self)
|
| 186 |
+
if self_index - 1 >= 0:
|
| 187 |
+
return self.siblings[self_index - 1]
|
| 188 |
+
return None
|
| 189 |
+
|
| 190 |
+
def _add_child(
|
| 191 |
+
self,
|
| 192 |
+
tokens: Sequence[Token],
|
| 193 |
+
) -> None:
|
| 194 |
+
"""Make a child node for `self`."""
|
| 195 |
+
child = type(self)(tokens, create_root=False)
|
| 196 |
+
child.parent = self
|
| 197 |
+
self.children.append(child)
|
| 198 |
+
|
| 199 |
+
def _set_children_from_tokens(self, tokens: Sequence[Token]) -> None:
|
| 200 |
+
"""Convert the token stream to a tree structure and set the resulting
|
| 201 |
+
nodes as children of `self`."""
|
| 202 |
+
reversed_tokens = list(reversed(tokens))
|
| 203 |
+
while reversed_tokens:
|
| 204 |
+
token = reversed_tokens.pop()
|
| 205 |
+
|
| 206 |
+
if not token.nesting:
|
| 207 |
+
self._add_child([token])
|
| 208 |
+
continue
|
| 209 |
+
if token.nesting != 1:
|
| 210 |
+
raise ValueError("Invalid token nesting")
|
| 211 |
+
|
| 212 |
+
nested_tokens = [token]
|
| 213 |
+
nesting = 1
|
| 214 |
+
while reversed_tokens and nesting:
|
| 215 |
+
token = reversed_tokens.pop()
|
| 216 |
+
nested_tokens.append(token)
|
| 217 |
+
nesting += token.nesting
|
| 218 |
+
if nesting:
|
| 219 |
+
raise ValueError(f"unclosed tokens starting {nested_tokens[0]}")
|
| 220 |
+
|
| 221 |
+
self._add_child(nested_tokens)
|
| 222 |
+
|
| 223 |
+
def pretty(
|
| 224 |
+
self, *, indent: int = 2, show_text: bool = False, _current: int = 0
|
| 225 |
+
) -> str:
|
| 226 |
+
"""Create an XML style string of the tree."""
|
| 227 |
+
prefix = " " * _current
|
| 228 |
+
text = prefix + f"<{self.type}"
|
| 229 |
+
if not self.is_root and self.attrs:
|
| 230 |
+
text += " " + " ".join(f"{k}={v!r}" for k, v in self.attrs.items())
|
| 231 |
+
text += ">"
|
| 232 |
+
if (
|
| 233 |
+
show_text
|
| 234 |
+
and not self.is_root
|
| 235 |
+
and self.type in ("text", "text_special")
|
| 236 |
+
and self.content
|
| 237 |
+
):
|
| 238 |
+
text += "\n" + textwrap.indent(self.content, prefix + " " * indent)
|
| 239 |
+
for child in self.children:
|
| 240 |
+
text += "\n" + child.pretty(
|
| 241 |
+
indent=indent, show_text=show_text, _current=_current + indent
|
| 242 |
+
)
|
| 243 |
+
return text
|
| 244 |
+
|
| 245 |
+
def walk(
|
| 246 |
+
self: _NodeType, *, include_self: bool = True
|
| 247 |
+
) -> Generator[_NodeType, None, None]:
|
| 248 |
+
"""Recursively yield all descendant nodes in the tree starting at self.
|
| 249 |
+
|
| 250 |
+
The order mimics the order of the underlying linear token
|
| 251 |
+
stream (i.e. depth first).
|
| 252 |
+
"""
|
| 253 |
+
if include_self:
|
| 254 |
+
yield self
|
| 255 |
+
for child in self.children:
|
| 256 |
+
yield from child.walk(include_self=True)
|
| 257 |
+
|
| 258 |
+
# NOTE:
|
| 259 |
+
# The values of the properties defined below directly map to properties
|
| 260 |
+
# of the underlying `Token`s. A root node does not translate to a `Token`
|
| 261 |
+
# object, so calling these property getters on a root node will raise an
|
| 262 |
+
# `AttributeError`.
|
| 263 |
+
#
|
| 264 |
+
# There is no mapping for `Token.nesting` because the `is_nested` property
|
| 265 |
+
# provides that data, and can be called on any node type, including root.
|
| 266 |
+
|
| 267 |
+
def _attribute_token(self) -> Token:
|
| 268 |
+
"""Return the `Token` that is used as the data source for the
|
| 269 |
+
properties defined below."""
|
| 270 |
+
if self.token:
|
| 271 |
+
return self.token
|
| 272 |
+
if self.nester_tokens:
|
| 273 |
+
return self.nester_tokens.opening
|
| 274 |
+
raise AttributeError("Root node does not have the accessed attribute")
|
| 275 |
+
|
| 276 |
+
@property
|
| 277 |
+
def tag(self) -> str:
|
| 278 |
+
"""html tag name, e.g. \"p\" """
|
| 279 |
+
return self._attribute_token().tag
|
| 280 |
+
|
| 281 |
+
@property
|
| 282 |
+
def attrs(self) -> dict[str, str | int | float]:
|
| 283 |
+
"""Html attributes."""
|
| 284 |
+
return self._attribute_token().attrs
|
| 285 |
+
|
| 286 |
+
def attrGet(self, name: str) -> None | str | int | float:
|
| 287 |
+
"""Get the value of attribute `name`, or null if it does not exist."""
|
| 288 |
+
return self._attribute_token().attrGet(name)
|
| 289 |
+
|
| 290 |
+
@property
|
| 291 |
+
def map(self) -> tuple[int, int] | None:
|
| 292 |
+
"""Source map info. Format: `tuple[ line_begin, line_end ]`"""
|
| 293 |
+
map_ = self._attribute_token().map
|
| 294 |
+
if map_:
|
| 295 |
+
# Type ignore because `Token`s attribute types are not perfect
|
| 296 |
+
return tuple(map_) # type: ignore
|
| 297 |
+
return None
|
| 298 |
+
|
| 299 |
+
@property
|
| 300 |
+
def level(self) -> int:
|
| 301 |
+
"""nesting level, the same as `state.level`"""
|
| 302 |
+
return self._attribute_token().level
|
| 303 |
+
|
| 304 |
+
@property
|
| 305 |
+
def content(self) -> str:
|
| 306 |
+
"""In a case of self-closing tag (code, html, fence, etc.), it
|
| 307 |
+
has contents of this tag."""
|
| 308 |
+
return self._attribute_token().content
|
| 309 |
+
|
| 310 |
+
@property
|
| 311 |
+
def markup(self) -> str:
|
| 312 |
+
"""'*' or '_' for emphasis, fence string for fence, etc."""
|
| 313 |
+
return self._attribute_token().markup
|
| 314 |
+
|
| 315 |
+
@property
|
| 316 |
+
def info(self) -> str:
|
| 317 |
+
"""fence infostring"""
|
| 318 |
+
return self._attribute_token().info
|
| 319 |
+
|
| 320 |
+
@property
|
| 321 |
+
def meta(self) -> dict[Any, Any]:
|
| 322 |
+
"""A place for plugins to store an arbitrary data."""
|
| 323 |
+
return self._attribute_token().meta
|
| 324 |
+
|
| 325 |
+
@property
|
| 326 |
+
def block(self) -> bool:
|
| 327 |
+
"""True for block-level tokens, false for inline tokens."""
|
| 328 |
+
return self._attribute_token().block
|
| 329 |
+
|
| 330 |
+
@property
|
| 331 |
+
def hidden(self) -> bool:
|
| 332 |
+
"""If it's true, ignore this element when rendering.
|
| 333 |
+
Used for tight lists to hide paragraphs."""
|
| 334 |
+
return self._attribute_token().hidden
|
| 335 |
+
|
| 336 |
+
|
| 337 |
+
def _removesuffix(string: str, suffix: str) -> str:
|
| 338 |
+
"""Remove a suffix from a string.
|
| 339 |
+
|
| 340 |
+
Replace this with str.removesuffix() from stdlib when minimum Python
|
| 341 |
+
version is 3.9.
|
| 342 |
+
"""
|
| 343 |
+
if suffix and string.endswith(suffix):
|
| 344 |
+
return string[: -len(suffix)]
|
| 345 |
+
return string
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia_cusolver_cu12-11.7.3.90.dist-info/INSTALLER
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
pip
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia_cusolver_cu12-11.7.3.90.dist-info/License.txt
ADDED
|
@@ -0,0 +1,1568 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
End User License Agreement
|
| 2 |
+
--------------------------
|
| 3 |
+
|
| 4 |
+
|
| 5 |
+
Preface
|
| 6 |
+
-------
|
| 7 |
+
|
| 8 |
+
The Software License Agreement in Chapter 1 and the Supplement
|
| 9 |
+
in Chapter 2 contain license terms and conditions that govern
|
| 10 |
+
the use of NVIDIA software. By accepting this agreement, you
|
| 11 |
+
agree to comply with all the terms and conditions applicable
|
| 12 |
+
to the product(s) included herein.
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
NVIDIA Driver
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
Description
|
| 19 |
+
|
| 20 |
+
This package contains the operating system driver and
|
| 21 |
+
fundamental system software components for NVIDIA GPUs.
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
NVIDIA CUDA Toolkit
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
Description
|
| 28 |
+
|
| 29 |
+
The NVIDIA CUDA Toolkit provides command-line and graphical
|
| 30 |
+
tools for building, debugging and optimizing the performance
|
| 31 |
+
of applications accelerated by NVIDIA GPUs, runtime and math
|
| 32 |
+
libraries, and documentation including programming guides,
|
| 33 |
+
user manuals, and API references.
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
Default Install Location of CUDA Toolkit
|
| 37 |
+
|
| 38 |
+
Windows platform:
|
| 39 |
+
|
| 40 |
+
%ProgramFiles%\NVIDIA GPU Computing Toolkit\CUDA\v#.#
|
| 41 |
+
|
| 42 |
+
Linux platform:
|
| 43 |
+
|
| 44 |
+
/usr/local/cuda-#.#
|
| 45 |
+
|
| 46 |
+
Mac platform:
|
| 47 |
+
|
| 48 |
+
/Developer/NVIDIA/CUDA-#.#
|
| 49 |
+
|
| 50 |
+
|
| 51 |
+
NVIDIA CUDA Samples
|
| 52 |
+
|
| 53 |
+
|
| 54 |
+
Description
|
| 55 |
+
|
| 56 |
+
This package includes over 100+ CUDA examples that demonstrate
|
| 57 |
+
various CUDA programming principles, and efficient CUDA
|
| 58 |
+
implementation of algorithms in specific application domains.
|
| 59 |
+
|
| 60 |
+
|
| 61 |
+
Default Install Location of CUDA Samples
|
| 62 |
+
|
| 63 |
+
Windows platform:
|
| 64 |
+
|
| 65 |
+
%ProgramData%\NVIDIA Corporation\CUDA Samples\v#.#
|
| 66 |
+
|
| 67 |
+
Linux platform:
|
| 68 |
+
|
| 69 |
+
/usr/local/cuda-#.#/samples
|
| 70 |
+
|
| 71 |
+
and
|
| 72 |
+
|
| 73 |
+
$HOME/NVIDIA_CUDA-#.#_Samples
|
| 74 |
+
|
| 75 |
+
Mac platform:
|
| 76 |
+
|
| 77 |
+
/Developer/NVIDIA/CUDA-#.#/samples
|
| 78 |
+
|
| 79 |
+
|
| 80 |
+
NVIDIA Nsight Visual Studio Edition (Windows only)
|
| 81 |
+
|
| 82 |
+
|
| 83 |
+
Description
|
| 84 |
+
|
| 85 |
+
NVIDIA Nsight Development Platform, Visual Studio Edition is a
|
| 86 |
+
development environment integrated into Microsoft Visual
|
| 87 |
+
Studio that provides tools for debugging, profiling, analyzing
|
| 88 |
+
and optimizing your GPU computing and graphics applications.
|
| 89 |
+
|
| 90 |
+
|
| 91 |
+
Default Install Location of Nsight Visual Studio Edition
|
| 92 |
+
|
| 93 |
+
Windows platform:
|
| 94 |
+
|
| 95 |
+
%ProgramFiles(x86)%\NVIDIA Corporation\Nsight Visual Studio Edition #.#
|
| 96 |
+
|
| 97 |
+
|
| 98 |
+
1. License Agreement for NVIDIA Software Development Kits
|
| 99 |
+
---------------------------------------------------------
|
| 100 |
+
|
| 101 |
+
|
| 102 |
+
Release Date: July 26, 2018
|
| 103 |
+
---------------------------
|
| 104 |
+
|
| 105 |
+
|
| 106 |
+
Important NoticeRead before downloading, installing,
|
| 107 |
+
copying or using the licensed software:
|
| 108 |
+
-------------------------------------------------------
|
| 109 |
+
|
| 110 |
+
This license agreement, including exhibits attached
|
| 111 |
+
("Agreement”) is a legal agreement between you and NVIDIA
|
| 112 |
+
Corporation ("NVIDIA") and governs your use of a NVIDIA
|
| 113 |
+
software development kit (“SDK”).
|
| 114 |
+
|
| 115 |
+
Each SDK has its own set of software and materials, but here
|
| 116 |
+
is a description of the types of items that may be included in
|
| 117 |
+
a SDK: source code, header files, APIs, data sets and assets
|
| 118 |
+
(examples include images, textures, models, scenes, videos,
|
| 119 |
+
native API input/output files), binary software, sample code,
|
| 120 |
+
libraries, utility programs, programming code and
|
| 121 |
+
documentation.
|
| 122 |
+
|
| 123 |
+
This Agreement can be accepted only by an adult of legal age
|
| 124 |
+
of majority in the country in which the SDK is used.
|
| 125 |
+
|
| 126 |
+
If you are entering into this Agreement on behalf of a company
|
| 127 |
+
or other legal entity, you represent that you have the legal
|
| 128 |
+
authority to bind the entity to this Agreement, in which case
|
| 129 |
+
“you” will mean the entity you represent.
|
| 130 |
+
|
| 131 |
+
If you don’t have the required age or authority to accept
|
| 132 |
+
this Agreement, or if you don’t accept all the terms and
|
| 133 |
+
conditions of this Agreement, do not download, install or use
|
| 134 |
+
the SDK.
|
| 135 |
+
|
| 136 |
+
You agree to use the SDK only for purposes that are permitted
|
| 137 |
+
by (a) this Agreement, and (b) any applicable law, regulation
|
| 138 |
+
or generally accepted practices or guidelines in the relevant
|
| 139 |
+
jurisdictions.
|
| 140 |
+
|
| 141 |
+
|
| 142 |
+
1.1. License
|
| 143 |
+
|
| 144 |
+
|
| 145 |
+
1.1.1. License Grant
|
| 146 |
+
|
| 147 |
+
Subject to the terms of this Agreement, NVIDIA hereby grants
|
| 148 |
+
you a non-exclusive, non-transferable license, without the
|
| 149 |
+
right to sublicense (except as expressly provided in this
|
| 150 |
+
Agreement) to:
|
| 151 |
+
|
| 152 |
+
1. Install and use the SDK,
|
| 153 |
+
|
| 154 |
+
2. Modify and create derivative works of sample source code
|
| 155 |
+
delivered in the SDK, and
|
| 156 |
+
|
| 157 |
+
3. Distribute those portions of the SDK that are identified
|
| 158 |
+
in this Agreement as distributable, as incorporated in
|
| 159 |
+
object code format into a software application that meets
|
| 160 |
+
the distribution requirements indicated in this Agreement.
|
| 161 |
+
|
| 162 |
+
|
| 163 |
+
1.1.2. Distribution Requirements
|
| 164 |
+
|
| 165 |
+
These are the distribution requirements for you to exercise
|
| 166 |
+
the distribution grant:
|
| 167 |
+
|
| 168 |
+
1. Your application must have material additional
|
| 169 |
+
functionality, beyond the included portions of the SDK.
|
| 170 |
+
|
| 171 |
+
2. The distributable portions of the SDK shall only be
|
| 172 |
+
accessed by your application.
|
| 173 |
+
|
| 174 |
+
3. The following notice shall be included in modifications
|
| 175 |
+
and derivative works of sample source code distributed:
|
| 176 |
+
“This software contains source code provided by NVIDIA
|
| 177 |
+
Corporation.”
|
| 178 |
+
|
| 179 |
+
4. Unless a developer tool is identified in this Agreement
|
| 180 |
+
as distributable, it is delivered for your internal use
|
| 181 |
+
only.
|
| 182 |
+
|
| 183 |
+
5. The terms under which you distribute your application
|
| 184 |
+
must be consistent with the terms of this Agreement,
|
| 185 |
+
including (without limitation) terms relating to the
|
| 186 |
+
license grant and license restrictions and protection of
|
| 187 |
+
NVIDIA’s intellectual property rights. Additionally, you
|
| 188 |
+
agree that you will protect the privacy, security and
|
| 189 |
+
legal rights of your application users.
|
| 190 |
+
|
| 191 |
+
6. You agree to notify NVIDIA in writing of any known or
|
| 192 |
+
suspected distribution or use of the SDK not in compliance
|
| 193 |
+
with the requirements of this Agreement, and to enforce
|
| 194 |
+
the terms of your agreements with respect to distributed
|
| 195 |
+
SDK.
|
| 196 |
+
|
| 197 |
+
|
| 198 |
+
1.1.3. Authorized Users
|
| 199 |
+
|
| 200 |
+
You may allow employees and contractors of your entity or of
|
| 201 |
+
your subsidiary(ies) to access and use the SDK from your
|
| 202 |
+
secure network to perform work on your behalf.
|
| 203 |
+
|
| 204 |
+
If you are an academic institution you may allow users
|
| 205 |
+
enrolled or employed by the academic institution to access and
|
| 206 |
+
use the SDK from your secure network.
|
| 207 |
+
|
| 208 |
+
You are responsible for the compliance with the terms of this
|
| 209 |
+
Agreement by your authorized users. If you become aware that
|
| 210 |
+
your authorized users didn’t follow the terms of this
|
| 211 |
+
Agreement, you agree to take reasonable steps to resolve the
|
| 212 |
+
non-compliance and prevent new occurrences.
|
| 213 |
+
|
| 214 |
+
|
| 215 |
+
1.1.4. Pre-Release SDK
|
| 216 |
+
|
| 217 |
+
The SDK versions identified as alpha, beta, preview or
|
| 218 |
+
otherwise as pre-release, may not be fully functional, may
|
| 219 |
+
contain errors or design flaws, and may have reduced or
|
| 220 |
+
different security, privacy, accessibility, availability, and
|
| 221 |
+
reliability standards relative to commercial versions of
|
| 222 |
+
NVIDIA software and materials. Use of a pre-release SDK may
|
| 223 |
+
result in unexpected results, loss of data, project delays or
|
| 224 |
+
other unpredictable damage or loss.
|
| 225 |
+
|
| 226 |
+
You may use a pre-release SDK at your own risk, understanding
|
| 227 |
+
that pre-release SDKs are not intended for use in production
|
| 228 |
+
or business-critical systems.
|
| 229 |
+
|
| 230 |
+
NVIDIA may choose not to make available a commercial version
|
| 231 |
+
of any pre-release SDK. NVIDIA may also choose to abandon
|
| 232 |
+
development and terminate the availability of a pre-release
|
| 233 |
+
SDK at any time without liability.
|
| 234 |
+
|
| 235 |
+
|
| 236 |
+
1.1.5. Updates
|
| 237 |
+
|
| 238 |
+
NVIDIA may, at its option, make available patches, workarounds
|
| 239 |
+
or other updates to this SDK. Unless the updates are provided
|
| 240 |
+
with their separate governing terms, they are deemed part of
|
| 241 |
+
the SDK licensed to you as provided in this Agreement. You
|
| 242 |
+
agree that the form and content of the SDK that NVIDIA
|
| 243 |
+
provides may change without prior notice to you. While NVIDIA
|
| 244 |
+
generally maintains compatibility between versions, NVIDIA may
|
| 245 |
+
in some cases make changes that introduce incompatibilities in
|
| 246 |
+
future versions of the SDK.
|
| 247 |
+
|
| 248 |
+
|
| 249 |
+
1.1.6. Third Party Licenses
|
| 250 |
+
|
| 251 |
+
The SDK may come bundled with, or otherwise include or be
|
| 252 |
+
distributed with, third party software licensed by a NVIDIA
|
| 253 |
+
supplier and/or open source software provided under an open
|
| 254 |
+
source license. Use of third party software is subject to the
|
| 255 |
+
third-party license terms, or in the absence of third party
|
| 256 |
+
terms, the terms of this Agreement. Copyright to third party
|
| 257 |
+
software is held by the copyright holders indicated in the
|
| 258 |
+
third-party software or license.
|
| 259 |
+
|
| 260 |
+
|
| 261 |
+
1.1.7. Reservation of Rights
|
| 262 |
+
|
| 263 |
+
NVIDIA reserves all rights, title, and interest in and to the
|
| 264 |
+
SDK, not expressly granted to you under this Agreement.
|
| 265 |
+
|
| 266 |
+
|
| 267 |
+
1.2. Limitations
|
| 268 |
+
|
| 269 |
+
The following license limitations apply to your use of the
|
| 270 |
+
SDK:
|
| 271 |
+
|
| 272 |
+
1. You may not reverse engineer, decompile or disassemble,
|
| 273 |
+
or remove copyright or other proprietary notices from any
|
| 274 |
+
portion of the SDK or copies of the SDK.
|
| 275 |
+
|
| 276 |
+
2. Except as expressly provided in this Agreement, you may
|
| 277 |
+
not copy, sell, rent, sublicense, transfer, distribute,
|
| 278 |
+
modify, or create derivative works of any portion of the
|
| 279 |
+
SDK. For clarity, you may not distribute or sublicense the
|
| 280 |
+
SDK as a stand-alone product.
|
| 281 |
+
|
| 282 |
+
3. Unless you have an agreement with NVIDIA for this
|
| 283 |
+
purpose, you may not indicate that an application created
|
| 284 |
+
with the SDK is sponsored or endorsed by NVIDIA.
|
| 285 |
+
|
| 286 |
+
4. You may not bypass, disable, or circumvent any
|
| 287 |
+
encryption, security, digital rights management or
|
| 288 |
+
authentication mechanism in the SDK.
|
| 289 |
+
|
| 290 |
+
5. You may not use the SDK in any manner that would cause it
|
| 291 |
+
to become subject to an open source software license. As
|
| 292 |
+
examples, licenses that require as a condition of use,
|
| 293 |
+
modification, and/or distribution that the SDK be:
|
| 294 |
+
|
| 295 |
+
a. Disclosed or distributed in source code form;
|
| 296 |
+
|
| 297 |
+
b. Licensed for the purpose of making derivative works;
|
| 298 |
+
or
|
| 299 |
+
|
| 300 |
+
c. Redistributable at no charge.
|
| 301 |
+
|
| 302 |
+
6. Unless you have an agreement with NVIDIA for this
|
| 303 |
+
purpose, you may not use the SDK with any system or
|
| 304 |
+
application where the use or failure of the system or
|
| 305 |
+
application can reasonably be expected to threaten or
|
| 306 |
+
result in personal injury, death, or catastrophic loss.
|
| 307 |
+
Examples include use in avionics, navigation, military,
|
| 308 |
+
medical, life support or other life critical applications.
|
| 309 |
+
NVIDIA does not design, test or manufacture the SDK for
|
| 310 |
+
these critical uses and NVIDIA shall not be liable to you
|
| 311 |
+
or any third party, in whole or in part, for any claims or
|
| 312 |
+
damages arising from such uses.
|
| 313 |
+
|
| 314 |
+
7. You agree to defend, indemnify and hold harmless NVIDIA
|
| 315 |
+
and its affiliates, and their respective employees,
|
| 316 |
+
contractors, agents, officers and directors, from and
|
| 317 |
+
against any and all claims, damages, obligations, losses,
|
| 318 |
+
liabilities, costs or debt, fines, restitutions and
|
| 319 |
+
expenses (including but not limited to attorney’s fees
|
| 320 |
+
and costs incident to establishing the right of
|
| 321 |
+
indemnification) arising out of or related to your use of
|
| 322 |
+
the SDK outside of the scope of this Agreement, or not in
|
| 323 |
+
compliance with its terms.
|
| 324 |
+
|
| 325 |
+
|
| 326 |
+
1.3. Ownership
|
| 327 |
+
|
| 328 |
+
1. NVIDIA or its licensors hold all rights, title and
|
| 329 |
+
interest in and to the SDK and its modifications and
|
| 330 |
+
derivative works, including their respective intellectual
|
| 331 |
+
property rights, subject to your rights described in this
|
| 332 |
+
section. This SDK may include software and materials from
|
| 333 |
+
NVIDIA’s licensors, and these licensors are intended
|
| 334 |
+
third party beneficiaries that may enforce this Agreement
|
| 335 |
+
with respect to their intellectual property rights.
|
| 336 |
+
|
| 337 |
+
2. You hold all rights, title and interest in and to your
|
| 338 |
+
applications and your derivative works of the sample
|
| 339 |
+
source code delivered in the SDK, including their
|
| 340 |
+
respective intellectual property rights, subject to
|
| 341 |
+
NVIDIA’s rights described in this section.
|
| 342 |
+
|
| 343 |
+
3. You may, but don’t have to, provide to NVIDIA
|
| 344 |
+
suggestions, feature requests or other feedback regarding
|
| 345 |
+
the SDK, including possible enhancements or modifications
|
| 346 |
+
to the SDK. For any feedback that you voluntarily provide,
|
| 347 |
+
you hereby grant NVIDIA and its affiliates a perpetual,
|
| 348 |
+
non-exclusive, worldwide, irrevocable license to use,
|
| 349 |
+
reproduce, modify, license, sublicense (through multiple
|
| 350 |
+
tiers of sublicensees), and distribute (through multiple
|
| 351 |
+
tiers of distributors) it without the payment of any
|
| 352 |
+
royalties or fees to you. NVIDIA will use feedback at its
|
| 353 |
+
choice. NVIDIA is constantly looking for ways to improve
|
| 354 |
+
its products, so you may send feedback to NVIDIA through
|
| 355 |
+
the developer portal at https://developer.nvidia.com.
|
| 356 |
+
|
| 357 |
+
|
| 358 |
+
1.4. No Warranties
|
| 359 |
+
|
| 360 |
+
THE SDK IS PROVIDED BY NVIDIA “AS IS” AND “WITH ALL
|
| 361 |
+
FAULTS.” TO THE MAXIMUM EXTENT PERMITTED BY LAW, NVIDIA AND
|
| 362 |
+
ITS AFFILIATES EXPRESSLY DISCLAIM ALL WARRANTIES OF ANY KIND
|
| 363 |
+
OR NATURE, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING,
|
| 364 |
+
BUT NOT LIMITED TO, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
|
| 365 |
+
FOR A PARTICULAR PURPOSE, TITLE, NON-INFRINGEMENT, OR THE
|
| 366 |
+
ABSENCE OF ANY DEFECTS THEREIN, WHETHER LATENT OR PATENT. NO
|
| 367 |
+
WARRANTY IS MADE ON THE BASIS OF TRADE USAGE, COURSE OF
|
| 368 |
+
DEALING OR COURSE OF TRADE.
|
| 369 |
+
|
| 370 |
+
|
| 371 |
+
1.5. Limitation of Liability
|
| 372 |
+
|
| 373 |
+
TO THE MAXIMUM EXTENT PERMITTED BY LAW, NVIDIA AND ITS
|
| 374 |
+
AFFILIATES SHALL NOT BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
|
| 375 |
+
PUNITIVE OR CONSEQUENTIAL DAMAGES, OR ANY LOST PROFITS, LOSS
|
| 376 |
+
OF USE, LOSS OF DATA OR LOSS OF GOODWILL, OR THE COSTS OF
|
| 377 |
+
PROCURING SUBSTITUTE PRODUCTS, ARISING OUT OF OR IN CONNECTION
|
| 378 |
+
WITH THIS AGREEMENT OR THE USE OR PERFORMANCE OF THE SDK,
|
| 379 |
+
WHETHER SUCH LIABILITY ARISES FROM ANY CLAIM BASED UPON BREACH
|
| 380 |
+
OF CONTRACT, BREACH OF WARRANTY, TORT (INCLUDING NEGLIGENCE),
|
| 381 |
+
PRODUCT LIABILITY OR ANY OTHER CAUSE OF ACTION OR THEORY OF
|
| 382 |
+
LIABILITY. IN NO EVENT WILL NVIDIA’S AND ITS AFFILIATES
|
| 383 |
+
TOTAL CUMULATIVE LIABILITY UNDER OR ARISING OUT OF THIS
|
| 384 |
+
AGREEMENT EXCEED US$10.00. THE NATURE OF THE LIABILITY OR THE
|
| 385 |
+
NUMBER OF CLAIMS OR SUITS SHALL NOT ENLARGE OR EXTEND THIS
|
| 386 |
+
LIMIT.
|
| 387 |
+
|
| 388 |
+
These exclusions and limitations of liability shall apply
|
| 389 |
+
regardless if NVIDIA or its affiliates have been advised of
|
| 390 |
+
the possibility of such damages, and regardless of whether a
|
| 391 |
+
remedy fails its essential purpose. These exclusions and
|
| 392 |
+
limitations of liability form an essential basis of the
|
| 393 |
+
bargain between the parties, and, absent any of these
|
| 394 |
+
exclusions or limitations of liability, the provisions of this
|
| 395 |
+
Agreement, including, without limitation, the economic terms,
|
| 396 |
+
would be substantially different.
|
| 397 |
+
|
| 398 |
+
|
| 399 |
+
1.6. Termination
|
| 400 |
+
|
| 401 |
+
1. This Agreement will continue to apply until terminated by
|
| 402 |
+
either you or NVIDIA as described below.
|
| 403 |
+
|
| 404 |
+
2. If you want to terminate this Agreement, you may do so by
|
| 405 |
+
stopping to use the SDK.
|
| 406 |
+
|
| 407 |
+
3. NVIDIA may, at any time, terminate this Agreement if:
|
| 408 |
+
|
| 409 |
+
a. (i) you fail to comply with any term of this
|
| 410 |
+
Agreement and the non-compliance is not fixed within
|
| 411 |
+
thirty (30) days following notice from NVIDIA (or
|
| 412 |
+
immediately if you violate NVIDIA’s intellectual
|
| 413 |
+
property rights);
|
| 414 |
+
|
| 415 |
+
b. (ii) you commence or participate in any legal
|
| 416 |
+
proceeding against NVIDIA with respect to the SDK; or
|
| 417 |
+
|
| 418 |
+
c. (iii) NVIDIA decides to no longer provide the SDK in
|
| 419 |
+
a country or, in NVIDIA’s sole discretion, the
|
| 420 |
+
continued use of it is no longer commercially viable.
|
| 421 |
+
|
| 422 |
+
4. Upon any termination of this Agreement, you agree to
|
| 423 |
+
promptly discontinue use of the SDK and destroy all copies
|
| 424 |
+
in your possession or control. Your prior distributions in
|
| 425 |
+
accordance with this Agreement are not affected by the
|
| 426 |
+
termination of this Agreement. Upon written request, you
|
| 427 |
+
will certify in writing that you have complied with your
|
| 428 |
+
commitments under this section. Upon any termination of
|
| 429 |
+
this Agreement all provisions survive except for the
|
| 430 |
+
license grant provisions.
|
| 431 |
+
|
| 432 |
+
|
| 433 |
+
1.7. General
|
| 434 |
+
|
| 435 |
+
If you wish to assign this Agreement or your rights and
|
| 436 |
+
obligations, including by merger, consolidation, dissolution
|
| 437 |
+
or operation of law, contact NVIDIA to ask for permission. Any
|
| 438 |
+
attempted assignment not approved by NVIDIA in writing shall
|
| 439 |
+
be void and of no effect. NVIDIA may assign, delegate or
|
| 440 |
+
transfer this Agreement and its rights and obligations, and if
|
| 441 |
+
to a non-affiliate you will be notified.
|
| 442 |
+
|
| 443 |
+
You agree to cooperate with NVIDIA and provide reasonably
|
| 444 |
+
requested information to verify your compliance with this
|
| 445 |
+
Agreement.
|
| 446 |
+
|
| 447 |
+
This Agreement will be governed in all respects by the laws of
|
| 448 |
+
the United States and of the State of Delaware as those laws
|
| 449 |
+
are applied to contracts entered into and performed entirely
|
| 450 |
+
within Delaware by Delaware residents, without regard to the
|
| 451 |
+
conflicts of laws principles. The United Nations Convention on
|
| 452 |
+
Contracts for the International Sale of Goods is specifically
|
| 453 |
+
disclaimed. You agree to all terms of this Agreement in the
|
| 454 |
+
English language.
|
| 455 |
+
|
| 456 |
+
The state or federal courts residing in Santa Clara County,
|
| 457 |
+
California shall have exclusive jurisdiction over any dispute
|
| 458 |
+
or claim arising out of this Agreement. Notwithstanding this,
|
| 459 |
+
you agree that NVIDIA shall still be allowed to apply for
|
| 460 |
+
injunctive remedies or an equivalent type of urgent legal
|
| 461 |
+
relief in any jurisdiction.
|
| 462 |
+
|
| 463 |
+
If any court of competent jurisdiction determines that any
|
| 464 |
+
provision of this Agreement is illegal, invalid or
|
| 465 |
+
unenforceable, such provision will be construed as limited to
|
| 466 |
+
the extent necessary to be consistent with and fully
|
| 467 |
+
enforceable under the law and the remaining provisions will
|
| 468 |
+
remain in full force and effect. Unless otherwise specified,
|
| 469 |
+
remedies are cumulative.
|
| 470 |
+
|
| 471 |
+
Each party acknowledges and agrees that the other is an
|
| 472 |
+
independent contractor in the performance of this Agreement.
|
| 473 |
+
|
| 474 |
+
The SDK has been developed entirely at private expense and is
|
| 475 |
+
“commercial items” consisting of “commercial computer
|
| 476 |
+
software” and “commercial computer software
|
| 477 |
+
documentation” provided with RESTRICTED RIGHTS. Use,
|
| 478 |
+
duplication or disclosure by the U.S. Government or a U.S.
|
| 479 |
+
Government subcontractor is subject to the restrictions in
|
| 480 |
+
this Agreement pursuant to DFARS 227.7202-3(a) or as set forth
|
| 481 |
+
in subparagraphs (c)(1) and (2) of the Commercial Computer
|
| 482 |
+
Software - Restricted Rights clause at FAR 52.227-19, as
|
| 483 |
+
applicable. Contractor/manufacturer is NVIDIA, 2788 San Tomas
|
| 484 |
+
Expressway, Santa Clara, CA 95051.
|
| 485 |
+
|
| 486 |
+
The SDK is subject to United States export laws and
|
| 487 |
+
regulations. You agree that you will not ship, transfer or
|
| 488 |
+
export the SDK into any country, or use the SDK in any manner,
|
| 489 |
+
prohibited by the United States Bureau of Industry and
|
| 490 |
+
Security or economic sanctions regulations administered by the
|
| 491 |
+
U.S. Department of Treasury’s Office of Foreign Assets
|
| 492 |
+
Control (OFAC), or any applicable export laws, restrictions or
|
| 493 |
+
regulations. These laws include restrictions on destinations,
|
| 494 |
+
end users and end use. By accepting this Agreement, you
|
| 495 |
+
confirm that you are not a resident or citizen of any country
|
| 496 |
+
currently embargoed by the U.S. and that you are not otherwise
|
| 497 |
+
prohibited from receiving the SDK.
|
| 498 |
+
|
| 499 |
+
Any notice delivered by NVIDIA to you under this Agreement
|
| 500 |
+
will be delivered via mail, email or fax. You agree that any
|
| 501 |
+
notices that NVIDIA sends you electronically will satisfy any
|
| 502 |
+
legal communication requirements. Please direct your legal
|
| 503 |
+
notices or other correspondence to NVIDIA Corporation, 2788
|
| 504 |
+
San Tomas Expressway, Santa Clara, California 95051, United
|
| 505 |
+
States of America, Attention: Legal Department.
|
| 506 |
+
|
| 507 |
+
This Agreement and any exhibits incorporated into this
|
| 508 |
+
Agreement constitute the entire agreement of the parties with
|
| 509 |
+
respect to the subject matter of this Agreement and supersede
|
| 510 |
+
all prior negotiations or documentation exchanged between the
|
| 511 |
+
parties relating to this SDK license. Any additional and/or
|
| 512 |
+
conflicting terms on documents issued by you are null, void,
|
| 513 |
+
and invalid. Any amendment or waiver under this Agreement
|
| 514 |
+
shall be in writing and signed by representatives of both
|
| 515 |
+
parties.
|
| 516 |
+
|
| 517 |
+
|
| 518 |
+
2. CUDA Toolkit Supplement to Software License Agreement for
|
| 519 |
+
NVIDIA Software Development Kits
|
| 520 |
+
------------------------------------------------------------
|
| 521 |
+
|
| 522 |
+
|
| 523 |
+
Release date: August 16, 2018
|
| 524 |
+
-----------------------------
|
| 525 |
+
|
| 526 |
+
The terms in this supplement govern your use of the NVIDIA
|
| 527 |
+
CUDA Toolkit SDK under the terms of your license agreement
|
| 528 |
+
(“Agreement”) as modified by this supplement. Capitalized
|
| 529 |
+
terms used but not defined below have the meaning assigned to
|
| 530 |
+
them in the Agreement.
|
| 531 |
+
|
| 532 |
+
This supplement is an exhibit to the Agreement and is
|
| 533 |
+
incorporated as an integral part of the Agreement. In the
|
| 534 |
+
event of conflict between the terms in this supplement and the
|
| 535 |
+
terms in the Agreement, the terms in this supplement govern.
|
| 536 |
+
|
| 537 |
+
|
| 538 |
+
2.1. License Scope
|
| 539 |
+
|
| 540 |
+
The SDK is licensed for you to develop applications only for
|
| 541 |
+
use in systems with NVIDIA GPUs.
|
| 542 |
+
|
| 543 |
+
|
| 544 |
+
2.2. Distribution
|
| 545 |
+
|
| 546 |
+
The portions of the SDK that are distributable under the
|
| 547 |
+
Agreement are listed in Attachment A.
|
| 548 |
+
|
| 549 |
+
|
| 550 |
+
2.3. Operating Systems
|
| 551 |
+
|
| 552 |
+
Those portions of the SDK designed exclusively for use on the
|
| 553 |
+
Linux or FreeBSD operating systems, or other operating systems
|
| 554 |
+
derived from the source code to these operating systems, may
|
| 555 |
+
be copied and redistributed for use in accordance with this
|
| 556 |
+
Agreement, provided that the object code files are not
|
| 557 |
+
modified in any way (except for unzipping of compressed
|
| 558 |
+
files).
|
| 559 |
+
|
| 560 |
+
|
| 561 |
+
2.4. Audio and Video Encoders and Decoders
|
| 562 |
+
|
| 563 |
+
You acknowledge and agree that it is your sole responsibility
|
| 564 |
+
to obtain any additional third-party licenses required to
|
| 565 |
+
make, have made, use, have used, sell, import, and offer for
|
| 566 |
+
sale your products or services that include or incorporate any
|
| 567 |
+
third-party software and content relating to audio and/or
|
| 568 |
+
video encoders and decoders from, including but not limited
|
| 569 |
+
to, Microsoft, Thomson, Fraunhofer IIS, Sisvel S.p.A.,
|
| 570 |
+
MPEG-LA, and Coding Technologies. NVIDIA does not grant to you
|
| 571 |
+
under this Agreement any necessary patent or other rights with
|
| 572 |
+
respect to any audio and/or video encoders and decoders.
|
| 573 |
+
|
| 574 |
+
|
| 575 |
+
2.5. Licensing
|
| 576 |
+
|
| 577 |
+
If the distribution terms in this Agreement are not suitable
|
| 578 |
+
for your organization, or for any questions regarding this
|
| 579 |
+
Agreement, please contact NVIDIA at
|
| 580 |
+
nvidia-compute-license-questions@nvidia.com.
|
| 581 |
+
|
| 582 |
+
|
| 583 |
+
2.6. Attachment A
|
| 584 |
+
|
| 585 |
+
The following portions of the SDK are distributable under the
|
| 586 |
+
Agreement:
|
| 587 |
+
|
| 588 |
+
Component
|
| 589 |
+
|
| 590 |
+
CUDA Runtime
|
| 591 |
+
|
| 592 |
+
Windows
|
| 593 |
+
|
| 594 |
+
cudart.dll, cudart_static.lib, cudadevrt.lib
|
| 595 |
+
|
| 596 |
+
Mac OSX
|
| 597 |
+
|
| 598 |
+
libcudart.dylib, libcudart_static.a, libcudadevrt.a
|
| 599 |
+
|
| 600 |
+
Linux
|
| 601 |
+
|
| 602 |
+
libcudart.so, libcudart_static.a, libcudadevrt.a
|
| 603 |
+
|
| 604 |
+
Android
|
| 605 |
+
|
| 606 |
+
libcudart.so, libcudart_static.a, libcudadevrt.a
|
| 607 |
+
|
| 608 |
+
Component
|
| 609 |
+
|
| 610 |
+
CUDA FFT Library
|
| 611 |
+
|
| 612 |
+
Windows
|
| 613 |
+
|
| 614 |
+
cufft.dll, cufftw.dll, cufft.lib, cufftw.lib
|
| 615 |
+
|
| 616 |
+
Mac OSX
|
| 617 |
+
|
| 618 |
+
libcufft.dylib, libcufft_static.a, libcufftw.dylib,
|
| 619 |
+
libcufftw_static.a
|
| 620 |
+
|
| 621 |
+
Linux
|
| 622 |
+
|
| 623 |
+
libcufft.so, libcufft_static.a, libcufftw.so,
|
| 624 |
+
libcufftw_static.a
|
| 625 |
+
|
| 626 |
+
Android
|
| 627 |
+
|
| 628 |
+
libcufft.so, libcufft_static.a, libcufftw.so,
|
| 629 |
+
libcufftw_static.a
|
| 630 |
+
|
| 631 |
+
Component
|
| 632 |
+
|
| 633 |
+
CUDA BLAS Library
|
| 634 |
+
|
| 635 |
+
Windows
|
| 636 |
+
|
| 637 |
+
cublas.dll, cublasLt.dll
|
| 638 |
+
|
| 639 |
+
Mac OSX
|
| 640 |
+
|
| 641 |
+
libcublas.dylib, libcublasLt.dylib, libcublas_static.a,
|
| 642 |
+
libcublasLt_static.a
|
| 643 |
+
|
| 644 |
+
Linux
|
| 645 |
+
|
| 646 |
+
libcublas.so, libcublasLt.so, libcublas_static.a,
|
| 647 |
+
libcublasLt_static.a
|
| 648 |
+
|
| 649 |
+
Android
|
| 650 |
+
|
| 651 |
+
libcublas.so, libcublasLt.so, libcublas_static.a,
|
| 652 |
+
libcublasLt_static.a
|
| 653 |
+
|
| 654 |
+
Component
|
| 655 |
+
|
| 656 |
+
NVIDIA "Drop-in" BLAS Library
|
| 657 |
+
|
| 658 |
+
Windows
|
| 659 |
+
|
| 660 |
+
nvblas.dll
|
| 661 |
+
|
| 662 |
+
Mac OSX
|
| 663 |
+
|
| 664 |
+
libnvblas.dylib
|
| 665 |
+
|
| 666 |
+
Linux
|
| 667 |
+
|
| 668 |
+
libnvblas.so
|
| 669 |
+
|
| 670 |
+
Component
|
| 671 |
+
|
| 672 |
+
CUDA Sparse Matrix Library
|
| 673 |
+
|
| 674 |
+
Windows
|
| 675 |
+
|
| 676 |
+
cusparse.dll, cusparse.lib
|
| 677 |
+
|
| 678 |
+
Mac OSX
|
| 679 |
+
|
| 680 |
+
libcusparse.dylib, libcusparse_static.a
|
| 681 |
+
|
| 682 |
+
Linux
|
| 683 |
+
|
| 684 |
+
libcusparse.so, libcusparse_static.a
|
| 685 |
+
|
| 686 |
+
Android
|
| 687 |
+
|
| 688 |
+
libcusparse.so, libcusparse_static.a
|
| 689 |
+
|
| 690 |
+
Component
|
| 691 |
+
|
| 692 |
+
CUDA Linear Solver Library
|
| 693 |
+
|
| 694 |
+
Windows
|
| 695 |
+
|
| 696 |
+
cusolver.dll, cusolver.lib
|
| 697 |
+
|
| 698 |
+
Mac OSX
|
| 699 |
+
|
| 700 |
+
libcusolver.dylib, libcusolver_static.a
|
| 701 |
+
|
| 702 |
+
Linux
|
| 703 |
+
|
| 704 |
+
libcusolver.so, libcusolver_static.a
|
| 705 |
+
|
| 706 |
+
Android
|
| 707 |
+
|
| 708 |
+
libcusolver.so, libcusolver_static.a
|
| 709 |
+
|
| 710 |
+
Component
|
| 711 |
+
|
| 712 |
+
CUDA Random Number Generation Library
|
| 713 |
+
|
| 714 |
+
Windows
|
| 715 |
+
|
| 716 |
+
curand.dll, curand.lib
|
| 717 |
+
|
| 718 |
+
Mac OSX
|
| 719 |
+
|
| 720 |
+
libcurand.dylib, libcurand_static.a
|
| 721 |
+
|
| 722 |
+
Linux
|
| 723 |
+
|
| 724 |
+
libcurand.so, libcurand_static.a
|
| 725 |
+
|
| 726 |
+
Android
|
| 727 |
+
|
| 728 |
+
libcurand.so, libcurand_static.a
|
| 729 |
+
|
| 730 |
+
Component
|
| 731 |
+
|
| 732 |
+
CUDA Accelerated Graph Library
|
| 733 |
+
|
| 734 |
+
Component
|
| 735 |
+
|
| 736 |
+
NVIDIA Performance Primitives Library
|
| 737 |
+
|
| 738 |
+
Windows
|
| 739 |
+
|
| 740 |
+
nppc.dll, nppc.lib, nppial.dll, nppial.lib, nppicc.dll,
|
| 741 |
+
nppicc.lib, nppicom.dll, nppicom.lib, nppidei.dll,
|
| 742 |
+
nppidei.lib, nppif.dll, nppif.lib, nppig.dll, nppig.lib,
|
| 743 |
+
nppim.dll, nppim.lib, nppist.dll, nppist.lib, nppisu.dll,
|
| 744 |
+
nppisu.lib, nppitc.dll, nppitc.lib, npps.dll, npps.lib
|
| 745 |
+
|
| 746 |
+
Mac OSX
|
| 747 |
+
|
| 748 |
+
libnppc.dylib, libnppc_static.a, libnppial.dylib,
|
| 749 |
+
libnppial_static.a, libnppicc.dylib, libnppicc_static.a,
|
| 750 |
+
libnppicom.dylib, libnppicom_static.a, libnppidei.dylib,
|
| 751 |
+
libnppidei_static.a, libnppif.dylib, libnppif_static.a,
|
| 752 |
+
libnppig.dylib, libnppig_static.a, libnppim.dylib,
|
| 753 |
+
libnppisu_static.a, libnppitc.dylib, libnppitc_static.a,
|
| 754 |
+
libnpps.dylib, libnpps_static.a
|
| 755 |
+
|
| 756 |
+
Linux
|
| 757 |
+
|
| 758 |
+
libnppc.so, libnppc_static.a, libnppial.so,
|
| 759 |
+
libnppial_static.a, libnppicc.so, libnppicc_static.a,
|
| 760 |
+
libnppicom.so, libnppicom_static.a, libnppidei.so,
|
| 761 |
+
libnppidei_static.a, libnppif.so, libnppif_static.a
|
| 762 |
+
libnppig.so, libnppig_static.a, libnppim.so,
|
| 763 |
+
libnppim_static.a, libnppist.so, libnppist_static.a,
|
| 764 |
+
libnppisu.so, libnppisu_static.a, libnppitc.so
|
| 765 |
+
libnppitc_static.a, libnpps.so, libnpps_static.a
|
| 766 |
+
|
| 767 |
+
Android
|
| 768 |
+
|
| 769 |
+
libnppc.so, libnppc_static.a, libnppial.so,
|
| 770 |
+
libnppial_static.a, libnppicc.so, libnppicc_static.a,
|
| 771 |
+
libnppicom.so, libnppicom_static.a, libnppidei.so,
|
| 772 |
+
libnppidei_static.a, libnppif.so, libnppif_static.a
|
| 773 |
+
libnppig.so, libnppig_static.a, libnppim.so,
|
| 774 |
+
libnppim_static.a, libnppist.so, libnppist_static.a,
|
| 775 |
+
libnppisu.so, libnppisu_static.a, libnppitc.so
|
| 776 |
+
libnppitc_static.a, libnpps.so, libnpps_static.a
|
| 777 |
+
|
| 778 |
+
Component
|
| 779 |
+
|
| 780 |
+
NVIDIA JPEG Library
|
| 781 |
+
|
| 782 |
+
Linux
|
| 783 |
+
|
| 784 |
+
libnvjpeg.so, libnvjpeg_static.a
|
| 785 |
+
|
| 786 |
+
Component
|
| 787 |
+
|
| 788 |
+
Internal common library required for statically linking to
|
| 789 |
+
cuBLAS, cuSPARSE, cuFFT, cuRAND, nvJPEG and NPP
|
| 790 |
+
|
| 791 |
+
Mac OSX
|
| 792 |
+
|
| 793 |
+
libculibos.a
|
| 794 |
+
|
| 795 |
+
Linux
|
| 796 |
+
|
| 797 |
+
libculibos.a
|
| 798 |
+
|
| 799 |
+
Component
|
| 800 |
+
|
| 801 |
+
NVIDIA Runtime Compilation Library and Header
|
| 802 |
+
|
| 803 |
+
All
|
| 804 |
+
|
| 805 |
+
nvrtc.h
|
| 806 |
+
|
| 807 |
+
Windows
|
| 808 |
+
|
| 809 |
+
nvrtc.dll, nvrtc-builtins.dll
|
| 810 |
+
|
| 811 |
+
Mac OSX
|
| 812 |
+
|
| 813 |
+
libnvrtc.dylib, libnvrtc-builtins.dylib
|
| 814 |
+
|
| 815 |
+
Linux
|
| 816 |
+
|
| 817 |
+
libnvrtc.so, libnvrtc-builtins.so
|
| 818 |
+
|
| 819 |
+
Component
|
| 820 |
+
|
| 821 |
+
NVIDIA Optimizing Compiler Library
|
| 822 |
+
|
| 823 |
+
Windows
|
| 824 |
+
|
| 825 |
+
nvvm.dll
|
| 826 |
+
|
| 827 |
+
Mac OSX
|
| 828 |
+
|
| 829 |
+
libnvvm.dylib
|
| 830 |
+
|
| 831 |
+
Linux
|
| 832 |
+
|
| 833 |
+
libnvvm.so
|
| 834 |
+
|
| 835 |
+
Component
|
| 836 |
+
|
| 837 |
+
NVIDIA Common Device Math Functions Library
|
| 838 |
+
|
| 839 |
+
Windows
|
| 840 |
+
|
| 841 |
+
libdevice.10.bc
|
| 842 |
+
|
| 843 |
+
Mac OSX
|
| 844 |
+
|
| 845 |
+
libdevice.10.bc
|
| 846 |
+
|
| 847 |
+
Linux
|
| 848 |
+
|
| 849 |
+
libdevice.10.bc
|
| 850 |
+
|
| 851 |
+
Component
|
| 852 |
+
|
| 853 |
+
CUDA Occupancy Calculation Header Library
|
| 854 |
+
|
| 855 |
+
All
|
| 856 |
+
|
| 857 |
+
cuda_occupancy.h
|
| 858 |
+
|
| 859 |
+
Component
|
| 860 |
+
|
| 861 |
+
CUDA Half Precision Headers
|
| 862 |
+
|
| 863 |
+
All
|
| 864 |
+
|
| 865 |
+
cuda_fp16.h, cuda_fp16.hpp
|
| 866 |
+
|
| 867 |
+
Component
|
| 868 |
+
|
| 869 |
+
CUDA Profiling Tools Interface (CUPTI) Library
|
| 870 |
+
|
| 871 |
+
Windows
|
| 872 |
+
|
| 873 |
+
cupti.dll
|
| 874 |
+
|
| 875 |
+
Mac OSX
|
| 876 |
+
|
| 877 |
+
libcupti.dylib
|
| 878 |
+
|
| 879 |
+
Linux
|
| 880 |
+
|
| 881 |
+
libcupti.so
|
| 882 |
+
|
| 883 |
+
Component
|
| 884 |
+
|
| 885 |
+
NVIDIA Tools Extension Library
|
| 886 |
+
|
| 887 |
+
Windows
|
| 888 |
+
|
| 889 |
+
nvToolsExt.dll, nvToolsExt.lib
|
| 890 |
+
|
| 891 |
+
Mac OSX
|
| 892 |
+
|
| 893 |
+
libnvToolsExt.dylib
|
| 894 |
+
|
| 895 |
+
Linux
|
| 896 |
+
|
| 897 |
+
libnvToolsExt.so
|
| 898 |
+
|
| 899 |
+
Component
|
| 900 |
+
|
| 901 |
+
NVIDIA CUDA Driver Libraries
|
| 902 |
+
|
| 903 |
+
Linux
|
| 904 |
+
|
| 905 |
+
libcuda.so, libnvidia-fatbinaryloader.so,
|
| 906 |
+
libnvidia-ptxjitcompiler.so
|
| 907 |
+
|
| 908 |
+
The NVIDIA CUDA Driver Libraries are only distributable in
|
| 909 |
+
applications that meet this criteria:
|
| 910 |
+
|
| 911 |
+
1. The application was developed starting from a NVIDIA CUDA
|
| 912 |
+
container obtained from Docker Hub or the NVIDIA GPU
|
| 913 |
+
Cloud, and
|
| 914 |
+
|
| 915 |
+
2. The resulting application is packaged as a Docker
|
| 916 |
+
container and distributed to users on Docker Hub or the
|
| 917 |
+
NVIDIA GPU Cloud only.
|
| 918 |
+
|
| 919 |
+
|
| 920 |
+
2.7. Attachment B
|
| 921 |
+
|
| 922 |
+
|
| 923 |
+
Additional Licensing Obligations
|
| 924 |
+
|
| 925 |
+
The following third party components included in the SOFTWARE
|
| 926 |
+
are licensed to Licensee pursuant to the following terms and
|
| 927 |
+
conditions:
|
| 928 |
+
|
| 929 |
+
1. Licensee's use of the GDB third party component is
|
| 930 |
+
subject to the terms and conditions of GNU GPL v3:
|
| 931 |
+
|
| 932 |
+
This product includes copyrighted third-party software licensed
|
| 933 |
+
under the terms of the GNU General Public License v3 ("GPL v3").
|
| 934 |
+
All third-party software packages are copyright by their respective
|
| 935 |
+
authors. GPL v3 terms and conditions are hereby incorporated into
|
| 936 |
+
the Agreement by this reference: http://www.gnu.org/licenses/gpl.txt
|
| 937 |
+
|
| 938 |
+
Consistent with these licensing requirements, the software
|
| 939 |
+
listed below is provided under the terms of the specified
|
| 940 |
+
open source software licenses. To obtain source code for
|
| 941 |
+
software provided under licenses that require
|
| 942 |
+
redistribution of source code, including the GNU General
|
| 943 |
+
Public License (GPL) and GNU Lesser General Public License
|
| 944 |
+
(LGPL), contact oss-requests@nvidia.com. This offer is
|
| 945 |
+
valid for a period of three (3) years from the date of the
|
| 946 |
+
distribution of this product by NVIDIA CORPORATION.
|
| 947 |
+
|
| 948 |
+
Component License
|
| 949 |
+
CUDA-GDB GPL v3
|
| 950 |
+
|
| 951 |
+
2. Licensee represents and warrants that any and all third
|
| 952 |
+
party licensing and/or royalty payment obligations in
|
| 953 |
+
connection with Licensee's use of the H.264 video codecs
|
| 954 |
+
are solely the responsibility of Licensee.
|
| 955 |
+
|
| 956 |
+
3. Licensee's use of the Thrust library is subject to the
|
| 957 |
+
terms and conditions of the Apache License Version 2.0.
|
| 958 |
+
All third-party software packages are copyright by their
|
| 959 |
+
respective authors. Apache License Version 2.0 terms and
|
| 960 |
+
conditions are hereby incorporated into the Agreement by
|
| 961 |
+
this reference.
|
| 962 |
+
http://www.apache.org/licenses/LICENSE-2.0.html
|
| 963 |
+
|
| 964 |
+
In addition, Licensee acknowledges the following notice:
|
| 965 |
+
Thrust includes source code from the Boost Iterator,
|
| 966 |
+
Tuple, System, and Random Number libraries.
|
| 967 |
+
|
| 968 |
+
Boost Software License - Version 1.0 - August 17th, 2003
|
| 969 |
+
. . . .
|
| 970 |
+
|
| 971 |
+
Permission is hereby granted, free of charge, to any person or
|
| 972 |
+
organization obtaining a copy of the software and accompanying
|
| 973 |
+
documentation covered by this license (the "Software") to use,
|
| 974 |
+
reproduce, display, distribute, execute, and transmit the Software,
|
| 975 |
+
and to prepare derivative works of the Software, and to permit
|
| 976 |
+
third-parties to whom the Software is furnished to do so, all
|
| 977 |
+
subject to the following:
|
| 978 |
+
|
| 979 |
+
The copyright notices in the Software and this entire statement,
|
| 980 |
+
including the above license grant, this restriction and the following
|
| 981 |
+
disclaimer, must be included in all copies of the Software, in whole
|
| 982 |
+
or in part, and all derivative works of the Software, unless such
|
| 983 |
+
copies or derivative works are solely in the form of machine-executable
|
| 984 |
+
object code generated by a source language processor.
|
| 985 |
+
|
| 986 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
| 987 |
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
| 988 |
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
|
| 989 |
+
NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
|
| 990 |
+
ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR
|
| 991 |
+
OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING
|
| 992 |
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
| 993 |
+
OTHER DEALINGS IN THE SOFTWARE.
|
| 994 |
+
|
| 995 |
+
4. Licensee's use of the LLVM third party component is
|
| 996 |
+
subject to the following terms and conditions:
|
| 997 |
+
|
| 998 |
+
======================================================
|
| 999 |
+
LLVM Release License
|
| 1000 |
+
======================================================
|
| 1001 |
+
University of Illinois/NCSA
|
| 1002 |
+
Open Source License
|
| 1003 |
+
|
| 1004 |
+
Copyright (c) 2003-2010 University of Illinois at Urbana-Champaign.
|
| 1005 |
+
All rights reserved.
|
| 1006 |
+
|
| 1007 |
+
Developed by:
|
| 1008 |
+
|
| 1009 |
+
LLVM Team
|
| 1010 |
+
|
| 1011 |
+
University of Illinois at Urbana-Champaign
|
| 1012 |
+
|
| 1013 |
+
http://llvm.org
|
| 1014 |
+
|
| 1015 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
| 1016 |
+
of this software and associated documentation files (the "Software"), to
|
| 1017 |
+
deal with the Software without restriction, including without limitation the
|
| 1018 |
+
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
| 1019 |
+
sell copies of the Software, and to permit persons to whom the Software is
|
| 1020 |
+
furnished to do so, subject to the following conditions:
|
| 1021 |
+
|
| 1022 |
+
* Redistributions of source code must retain the above copyright notice,
|
| 1023 |
+
this list of conditions and the following disclaimers.
|
| 1024 |
+
|
| 1025 |
+
* Redistributions in binary form must reproduce the above copyright
|
| 1026 |
+
notice, this list of conditions and the following disclaimers in the
|
| 1027 |
+
documentation and/or other materials provided with the distribution.
|
| 1028 |
+
|
| 1029 |
+
* Neither the names of the LLVM Team, University of Illinois at Urbana-
|
| 1030 |
+
Champaign, nor the names of its contributors may be used to endorse or
|
| 1031 |
+
promote products derived from this Software without specific prior
|
| 1032 |
+
written permission.
|
| 1033 |
+
|
| 1034 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| 1035 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 1036 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
| 1037 |
+
THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
| 1038 |
+
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
| 1039 |
+
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
| 1040 |
+
DEALINGS WITH THE SOFTWARE.
|
| 1041 |
+
|
| 1042 |
+
5. Licensee's use (e.g. nvprof) of the PCRE third party
|
| 1043 |
+
component is subject to the following terms and
|
| 1044 |
+
conditions:
|
| 1045 |
+
|
| 1046 |
+
------------
|
| 1047 |
+
PCRE LICENCE
|
| 1048 |
+
------------
|
| 1049 |
+
PCRE is a library of functions to support regular expressions whose syntax
|
| 1050 |
+
and semantics are as close as possible to those of the Perl 5 language.
|
| 1051 |
+
Release 8 of PCRE is distributed under the terms of the "BSD" licence, as
|
| 1052 |
+
specified below. The documentation for PCRE, supplied in the "doc"
|
| 1053 |
+
directory, is distributed under the same terms as the software itself. The
|
| 1054 |
+
basic library functions are written in C and are freestanding. Also
|
| 1055 |
+
included in the distribution is a set of C++ wrapper functions, and a just-
|
| 1056 |
+
in-time compiler that can be used to optimize pattern matching. These are
|
| 1057 |
+
both optional features that can be omitted when the library is built.
|
| 1058 |
+
|
| 1059 |
+
THE BASIC LIBRARY FUNCTIONS
|
| 1060 |
+
---------------------------
|
| 1061 |
+
Written by: Philip Hazel
|
| 1062 |
+
Email local part: ph10
|
| 1063 |
+
Email domain: cam.ac.uk
|
| 1064 |
+
University of Cambridge Computing Service,
|
| 1065 |
+
Cambridge, England.
|
| 1066 |
+
Copyright (c) 1997-2012 University of Cambridge
|
| 1067 |
+
All rights reserved.
|
| 1068 |
+
|
| 1069 |
+
PCRE JUST-IN-TIME COMPILATION SUPPORT
|
| 1070 |
+
-------------------------------------
|
| 1071 |
+
Written by: Zoltan Herczeg
|
| 1072 |
+
Email local part: hzmester
|
| 1073 |
+
Emain domain: freemail.hu
|
| 1074 |
+
Copyright(c) 2010-2012 Zoltan Herczeg
|
| 1075 |
+
All rights reserved.
|
| 1076 |
+
|
| 1077 |
+
STACK-LESS JUST-IN-TIME COMPILER
|
| 1078 |
+
--------------------------------
|
| 1079 |
+
Written by: Zoltan Herczeg
|
| 1080 |
+
Email local part: hzmester
|
| 1081 |
+
Emain domain: freemail.hu
|
| 1082 |
+
Copyright(c) 2009-2012 Zoltan Herczeg
|
| 1083 |
+
All rights reserved.
|
| 1084 |
+
|
| 1085 |
+
THE C++ WRAPPER FUNCTIONS
|
| 1086 |
+
-------------------------
|
| 1087 |
+
Contributed by: Google Inc.
|
| 1088 |
+
Copyright (c) 2007-2012, Google Inc.
|
| 1089 |
+
All rights reserved.
|
| 1090 |
+
|
| 1091 |
+
THE "BSD" LICENCE
|
| 1092 |
+
-----------------
|
| 1093 |
+
Redistribution and use in source and binary forms, with or without
|
| 1094 |
+
modification, are permitted provided that the following conditions are met:
|
| 1095 |
+
|
| 1096 |
+
* Redistributions of source code must retain the above copyright notice,
|
| 1097 |
+
this list of conditions and the following disclaimer.
|
| 1098 |
+
|
| 1099 |
+
* Redistributions in binary form must reproduce the above copyright
|
| 1100 |
+
notice, this list of conditions and the following disclaimer in the
|
| 1101 |
+
documentation and/or other materials provided with the distribution.
|
| 1102 |
+
|
| 1103 |
+
* Neither the name of the University of Cambridge nor the name of Google
|
| 1104 |
+
Inc. nor the names of their contributors may be used to endorse or
|
| 1105 |
+
promote products derived from this software without specific prior
|
| 1106 |
+
written permission.
|
| 1107 |
+
|
| 1108 |
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 1109 |
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 1110 |
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 1111 |
+
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
| 1112 |
+
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 1113 |
+
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 1114 |
+
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 1115 |
+
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 1116 |
+
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 1117 |
+
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 1118 |
+
POSSIBILITY OF SUCH DAMAGE.
|
| 1119 |
+
|
| 1120 |
+
6. Some of the cuBLAS library routines were written by or
|
| 1121 |
+
derived from code written by Vasily Volkov and are subject
|
| 1122 |
+
to the Modified Berkeley Software Distribution License as
|
| 1123 |
+
follows:
|
| 1124 |
+
|
| 1125 |
+
Copyright (c) 2007-2009, Regents of the University of California
|
| 1126 |
+
|
| 1127 |
+
All rights reserved.
|
| 1128 |
+
|
| 1129 |
+
Redistribution and use in source and binary forms, with or without
|
| 1130 |
+
modification, are permitted provided that the following conditions are
|
| 1131 |
+
met:
|
| 1132 |
+
* Redistributions of source code must retain the above copyright
|
| 1133 |
+
notice, this list of conditions and the following disclaimer.
|
| 1134 |
+
* Redistributions in binary form must reproduce the above
|
| 1135 |
+
copyright notice, this list of conditions and the following
|
| 1136 |
+
disclaimer in the documentation and/or other materials provided
|
| 1137 |
+
with the distribution.
|
| 1138 |
+
* Neither the name of the University of California, Berkeley nor
|
| 1139 |
+
the names of its contributors may be used to endorse or promote
|
| 1140 |
+
products derived from this software without specific prior
|
| 1141 |
+
written permission.
|
| 1142 |
+
|
| 1143 |
+
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
|
| 1144 |
+
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
| 1145 |
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
| 1146 |
+
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
| 1147 |
+
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
| 1148 |
+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
| 1149 |
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
| 1150 |
+
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
| 1151 |
+
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
| 1152 |
+
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 1153 |
+
POSSIBILITY OF SUCH DAMAGE.
|
| 1154 |
+
|
| 1155 |
+
7. Some of the cuBLAS library routines were written by or
|
| 1156 |
+
derived from code written by Davide Barbieri and are
|
| 1157 |
+
subject to the Modified Berkeley Software Distribution
|
| 1158 |
+
License as follows:
|
| 1159 |
+
|
| 1160 |
+
Copyright (c) 2008-2009 Davide Barbieri @ University of Rome Tor Vergata.
|
| 1161 |
+
|
| 1162 |
+
All rights reserved.
|
| 1163 |
+
|
| 1164 |
+
Redistribution and use in source and binary forms, with or without
|
| 1165 |
+
modification, are permitted provided that the following conditions are
|
| 1166 |
+
met:
|
| 1167 |
+
* Redistributions of source code must retain the above copyright
|
| 1168 |
+
notice, this list of conditions and the following disclaimer.
|
| 1169 |
+
* Redistributions in binary form must reproduce the above
|
| 1170 |
+
copyright notice, this list of conditions and the following
|
| 1171 |
+
disclaimer in the documentation and/or other materials provided
|
| 1172 |
+
with the distribution.
|
| 1173 |
+
* The name of the author may not be used to endorse or promote
|
| 1174 |
+
products derived from this software without specific prior
|
| 1175 |
+
written permission.
|
| 1176 |
+
|
| 1177 |
+
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
|
| 1178 |
+
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
| 1179 |
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
| 1180 |
+
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
| 1181 |
+
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
| 1182 |
+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
| 1183 |
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
| 1184 |
+
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
| 1185 |
+
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
| 1186 |
+
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 1187 |
+
POSSIBILITY OF SUCH DAMAGE.
|
| 1188 |
+
|
| 1189 |
+
8. Some of the cuBLAS library routines were derived from
|
| 1190 |
+
code developed by the University of Tennessee and are
|
| 1191 |
+
subject to the Modified Berkeley Software Distribution
|
| 1192 |
+
License as follows:
|
| 1193 |
+
|
| 1194 |
+
Copyright (c) 2010 The University of Tennessee.
|
| 1195 |
+
|
| 1196 |
+
All rights reserved.
|
| 1197 |
+
|
| 1198 |
+
Redistribution and use in source and binary forms, with or without
|
| 1199 |
+
modification, are permitted provided that the following conditions are
|
| 1200 |
+
met:
|
| 1201 |
+
* Redistributions of source code must retain the above copyright
|
| 1202 |
+
notice, this list of conditions and the following disclaimer.
|
| 1203 |
+
* Redistributions in binary form must reproduce the above
|
| 1204 |
+
copyright notice, this list of conditions and the following
|
| 1205 |
+
disclaimer listed in this license in the documentation and/or
|
| 1206 |
+
other materials provided with the distribution.
|
| 1207 |
+
* Neither the name of the copyright holders nor the names of its
|
| 1208 |
+
contributors may be used to endorse or promote products derived
|
| 1209 |
+
from this software without specific prior written permission.
|
| 1210 |
+
|
| 1211 |
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
| 1212 |
+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
| 1213 |
+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
| 1214 |
+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
| 1215 |
+
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
| 1216 |
+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
| 1217 |
+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
| 1218 |
+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
| 1219 |
+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
| 1220 |
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| 1221 |
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| 1222 |
+
|
| 1223 |
+
9. Some of the cuBLAS library routines were written by or
|
| 1224 |
+
derived from code written by Jonathan Hogg and are subject
|
| 1225 |
+
to the Modified Berkeley Software Distribution License as
|
| 1226 |
+
follows:
|
| 1227 |
+
|
| 1228 |
+
Copyright (c) 2012, The Science and Technology Facilities Council (STFC).
|
| 1229 |
+
|
| 1230 |
+
All rights reserved.
|
| 1231 |
+
|
| 1232 |
+
Redistribution and use in source and binary forms, with or without
|
| 1233 |
+
modification, are permitted provided that the following conditions are
|
| 1234 |
+
met:
|
| 1235 |
+
* Redistributions of source code must retain the above copyright
|
| 1236 |
+
notice, this list of conditions and the following disclaimer.
|
| 1237 |
+
* Redistributions in binary form must reproduce the above
|
| 1238 |
+
copyright notice, this list of conditions and the following
|
| 1239 |
+
disclaimer in the documentation and/or other materials provided
|
| 1240 |
+
with the distribution.
|
| 1241 |
+
* Neither the name of the STFC nor the names of its contributors
|
| 1242 |
+
may be used to endorse or promote products derived from this
|
| 1243 |
+
software without specific prior written permission.
|
| 1244 |
+
|
| 1245 |
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
| 1246 |
+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
| 1247 |
+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
| 1248 |
+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE STFC BE
|
| 1249 |
+
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 1250 |
+
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 1251 |
+
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
| 1252 |
+
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
| 1253 |
+
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
| 1254 |
+
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
| 1255 |
+
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| 1256 |
+
|
| 1257 |
+
10. Some of the cuBLAS library routines were written by or
|
| 1258 |
+
derived from code written by Ahmad M. Abdelfattah, David
|
| 1259 |
+
Keyes, and Hatem Ltaief, and are subject to the Apache
|
| 1260 |
+
License, Version 2.0, as follows:
|
| 1261 |
+
|
| 1262 |
+
-- (C) Copyright 2013 King Abdullah University of Science and Technology
|
| 1263 |
+
Authors:
|
| 1264 |
+
Ahmad Abdelfattah (ahmad.ahmad@kaust.edu.sa)
|
| 1265 |
+
David Keyes (david.keyes@kaust.edu.sa)
|
| 1266 |
+
Hatem Ltaief (hatem.ltaief@kaust.edu.sa)
|
| 1267 |
+
|
| 1268 |
+
Redistribution and use in source and binary forms, with or without
|
| 1269 |
+
modification, are permitted provided that the following conditions
|
| 1270 |
+
are met:
|
| 1271 |
+
|
| 1272 |
+
* Redistributions of source code must retain the above copyright
|
| 1273 |
+
notice, this list of conditions and the following disclaimer.
|
| 1274 |
+
* Redistributions in binary form must reproduce the above copyright
|
| 1275 |
+
notice, this list of conditions and the following disclaimer in the
|
| 1276 |
+
documentation and/or other materials provided with the distribution.
|
| 1277 |
+
* Neither the name of the King Abdullah University of Science and
|
| 1278 |
+
Technology nor the names of its contributors may be used to endorse
|
| 1279 |
+
or promote products derived from this software without specific prior
|
| 1280 |
+
written permission.
|
| 1281 |
+
|
| 1282 |
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
| 1283 |
+
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
| 1284 |
+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
| 1285 |
+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
| 1286 |
+
HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
| 1287 |
+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
| 1288 |
+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
| 1289 |
+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
| 1290 |
+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
| 1291 |
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| 1292 |
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
|
| 1293 |
+
|
| 1294 |
+
11. Some of the cuSPARSE library routines were written by or
|
| 1295 |
+
derived from code written by Li-Wen Chang and are subject
|
| 1296 |
+
to the NCSA Open Source License as follows:
|
| 1297 |
+
|
| 1298 |
+
Copyright (c) 2012, University of Illinois.
|
| 1299 |
+
|
| 1300 |
+
All rights reserved.
|
| 1301 |
+
|
| 1302 |
+
Developed by: IMPACT Group, University of Illinois, http://impact.crhc.illinois.edu
|
| 1303 |
+
|
| 1304 |
+
Permission is hereby granted, free of charge, to any person obtaining
|
| 1305 |
+
a copy of this software and associated documentation files (the
|
| 1306 |
+
"Software"), to deal with the Software without restriction, including
|
| 1307 |
+
without limitation the rights to use, copy, modify, merge, publish,
|
| 1308 |
+
distribute, sublicense, and/or sell copies of the Software, and to
|
| 1309 |
+
permit persons to whom the Software is furnished to do so, subject to
|
| 1310 |
+
the following conditions:
|
| 1311 |
+
* Redistributions of source code must retain the above copyright
|
| 1312 |
+
notice, this list of conditions and the following disclaimer.
|
| 1313 |
+
* Redistributions in binary form must reproduce the above
|
| 1314 |
+
copyright notice, this list of conditions and the following
|
| 1315 |
+
disclaimers in the documentation and/or other materials provided
|
| 1316 |
+
with the distribution.
|
| 1317 |
+
* Neither the names of IMPACT Group, University of Illinois, nor
|
| 1318 |
+
the names of its contributors may be used to endorse or promote
|
| 1319 |
+
products derived from this Software without specific prior
|
| 1320 |
+
written permission.
|
| 1321 |
+
|
| 1322 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
| 1323 |
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
| 1324 |
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
| 1325 |
+
NONINFRINGEMENT. IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT
|
| 1326 |
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
| 1327 |
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
| 1328 |
+
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
|
| 1329 |
+
SOFTWARE.
|
| 1330 |
+
|
| 1331 |
+
12. Some of the cuRAND library routines were written by or
|
| 1332 |
+
derived from code written by Mutsuo Saito and Makoto
|
| 1333 |
+
Matsumoto and are subject to the following license:
|
| 1334 |
+
|
| 1335 |
+
Copyright (c) 2009, 2010 Mutsuo Saito, Makoto Matsumoto and Hiroshima
|
| 1336 |
+
University. All rights reserved.
|
| 1337 |
+
|
| 1338 |
+
Copyright (c) 2011 Mutsuo Saito, Makoto Matsumoto, Hiroshima
|
| 1339 |
+
University and University of Tokyo. All rights reserved.
|
| 1340 |
+
|
| 1341 |
+
Redistribution and use in source and binary forms, with or without
|
| 1342 |
+
modification, are permitted provided that the following conditions are
|
| 1343 |
+
met:
|
| 1344 |
+
* Redistributions of source code must retain the above copyright
|
| 1345 |
+
notice, this list of conditions and the following disclaimer.
|
| 1346 |
+
* Redistributions in binary form must reproduce the above
|
| 1347 |
+
copyright notice, this list of conditions and the following
|
| 1348 |
+
disclaimer in the documentation and/or other materials provided
|
| 1349 |
+
with the distribution.
|
| 1350 |
+
* Neither the name of the Hiroshima University nor the names of
|
| 1351 |
+
its contributors may be used to endorse or promote products
|
| 1352 |
+
derived from this software without specific prior written
|
| 1353 |
+
permission.
|
| 1354 |
+
|
| 1355 |
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
| 1356 |
+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
| 1357 |
+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
| 1358 |
+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
| 1359 |
+
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
| 1360 |
+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
| 1361 |
+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
| 1362 |
+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
| 1363 |
+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
| 1364 |
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| 1365 |
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| 1366 |
+
|
| 1367 |
+
13. Some of the cuRAND library routines were derived from
|
| 1368 |
+
code developed by D. E. Shaw Research and are subject to
|
| 1369 |
+
the following license:
|
| 1370 |
+
|
| 1371 |
+
Copyright 2010-2011, D. E. Shaw Research.
|
| 1372 |
+
|
| 1373 |
+
All rights reserved.
|
| 1374 |
+
|
| 1375 |
+
Redistribution and use in source and binary forms, with or without
|
| 1376 |
+
modification, are permitted provided that the following conditions are
|
| 1377 |
+
met:
|
| 1378 |
+
* Redistributions of source code must retain the above copyright
|
| 1379 |
+
notice, this list of conditions, and the following disclaimer.
|
| 1380 |
+
* Redistributions in binary form must reproduce the above
|
| 1381 |
+
copyright notice, this list of conditions, and the following
|
| 1382 |
+
disclaimer in the documentation and/or other materials provided
|
| 1383 |
+
with the distribution.
|
| 1384 |
+
* Neither the name of D. E. Shaw Research nor the names of its
|
| 1385 |
+
contributors may be used to endorse or promote products derived
|
| 1386 |
+
from this software without specific prior written permission.
|
| 1387 |
+
|
| 1388 |
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
| 1389 |
+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
| 1390 |
+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
| 1391 |
+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
| 1392 |
+
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
| 1393 |
+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
| 1394 |
+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
| 1395 |
+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
| 1396 |
+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
| 1397 |
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| 1398 |
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| 1399 |
+
|
| 1400 |
+
14. Some of the Math library routines were written by or
|
| 1401 |
+
derived from code developed by Norbert Juffa and are
|
| 1402 |
+
subject to the following license:
|
| 1403 |
+
|
| 1404 |
+
Copyright (c) 2015-2017, Norbert Juffa
|
| 1405 |
+
All rights reserved.
|
| 1406 |
+
|
| 1407 |
+
Redistribution and use in source and binary forms, with or without
|
| 1408 |
+
modification, are permitted provided that the following conditions
|
| 1409 |
+
are met:
|
| 1410 |
+
|
| 1411 |
+
1. Redistributions of source code must retain the above copyright
|
| 1412 |
+
notice, this list of conditions and the following disclaimer.
|
| 1413 |
+
|
| 1414 |
+
2. Redistributions in binary form must reproduce the above copyright
|
| 1415 |
+
notice, this list of conditions and the following disclaimer in the
|
| 1416 |
+
documentation and/or other materials provided with the distribution.
|
| 1417 |
+
|
| 1418 |
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
| 1419 |
+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
| 1420 |
+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
| 1421 |
+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
| 1422 |
+
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
| 1423 |
+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
| 1424 |
+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
| 1425 |
+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
| 1426 |
+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
| 1427 |
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| 1428 |
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| 1429 |
+
|
| 1430 |
+
15. Licensee's use of the lz4 third party component is
|
| 1431 |
+
subject to the following terms and conditions:
|
| 1432 |
+
|
| 1433 |
+
Copyright (C) 2011-2013, Yann Collet.
|
| 1434 |
+
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
| 1435 |
+
|
| 1436 |
+
Redistribution and use in source and binary forms, with or without
|
| 1437 |
+
modification, are permitted provided that the following conditions are
|
| 1438 |
+
met:
|
| 1439 |
+
|
| 1440 |
+
* Redistributions of source code must retain the above copyright
|
| 1441 |
+
notice, this list of conditions and the following disclaimer.
|
| 1442 |
+
* Redistributions in binary form must reproduce the above
|
| 1443 |
+
copyright notice, this list of conditions and the following disclaimer
|
| 1444 |
+
in the documentation and/or other materials provided with the
|
| 1445 |
+
distribution.
|
| 1446 |
+
|
| 1447 |
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
| 1448 |
+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
| 1449 |
+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
| 1450 |
+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
| 1451 |
+
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
| 1452 |
+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
| 1453 |
+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
| 1454 |
+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
| 1455 |
+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
| 1456 |
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| 1457 |
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| 1458 |
+
|
| 1459 |
+
16. The NPP library uses code from the Boost Math Toolkit,
|
| 1460 |
+
and is subject to the following license:
|
| 1461 |
+
|
| 1462 |
+
Boost Software License - Version 1.0 - August 17th, 2003
|
| 1463 |
+
. . . .
|
| 1464 |
+
|
| 1465 |
+
Permission is hereby granted, free of charge, to any person or
|
| 1466 |
+
organization obtaining a copy of the software and accompanying
|
| 1467 |
+
documentation covered by this license (the "Software") to use,
|
| 1468 |
+
reproduce, display, distribute, execute, and transmit the Software,
|
| 1469 |
+
and to prepare derivative works of the Software, and to permit
|
| 1470 |
+
third-parties to whom the Software is furnished to do so, all
|
| 1471 |
+
subject to the following:
|
| 1472 |
+
|
| 1473 |
+
The copyright notices in the Software and this entire statement,
|
| 1474 |
+
including the above license grant, this restriction and the following
|
| 1475 |
+
disclaimer, must be included in all copies of the Software, in whole
|
| 1476 |
+
or in part, and all derivative works of the Software, unless such
|
| 1477 |
+
copies or derivative works are solely in the form of machine-executable
|
| 1478 |
+
object code generated by a source language processor.
|
| 1479 |
+
|
| 1480 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
| 1481 |
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
| 1482 |
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
|
| 1483 |
+
NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
|
| 1484 |
+
ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR
|
| 1485 |
+
OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING
|
| 1486 |
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
| 1487 |
+
OTHER DEALINGS IN THE SOFTWARE.
|
| 1488 |
+
|
| 1489 |
+
17. Portions of the Nsight Eclipse Edition is subject to the
|
| 1490 |
+
following license:
|
| 1491 |
+
|
| 1492 |
+
The Eclipse Foundation makes available all content in this plug-in
|
| 1493 |
+
("Content"). Unless otherwise indicated below, the Content is provided
|
| 1494 |
+
to you under the terms and conditions of the Eclipse Public License
|
| 1495 |
+
Version 1.0 ("EPL"). A copy of the EPL is available at http://
|
| 1496 |
+
www.eclipse.org/legal/epl-v10.html. For purposes of the EPL, "Program"
|
| 1497 |
+
will mean the Content.
|
| 1498 |
+
|
| 1499 |
+
If you did not receive this Content directly from the Eclipse
|
| 1500 |
+
Foundation, the Content is being redistributed by another party
|
| 1501 |
+
("Redistributor") and different terms and conditions may apply to your
|
| 1502 |
+
use of any object code in the Content. Check the Redistributor's
|
| 1503 |
+
license that was provided with the Content. If no such license exists,
|
| 1504 |
+
contact the Redistributor. Unless otherwise indicated below, the terms
|
| 1505 |
+
and conditions of the EPL still apply to any source code in the
|
| 1506 |
+
Content and such source code may be obtained at http://www.eclipse.org.
|
| 1507 |
+
|
| 1508 |
+
18. Some of the cuBLAS library routines uses code from
|
| 1509 |
+
OpenAI, which is subject to the following license:
|
| 1510 |
+
|
| 1511 |
+
License URL
|
| 1512 |
+
https://github.com/openai/openai-gemm/blob/master/LICENSE
|
| 1513 |
+
|
| 1514 |
+
License Text
|
| 1515 |
+
The MIT License
|
| 1516 |
+
|
| 1517 |
+
Copyright (c) 2016 OpenAI (http://openai.com), 2016 Google Inc.
|
| 1518 |
+
|
| 1519 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
| 1520 |
+
of this software and associated documentation files (the "Software"), to deal
|
| 1521 |
+
in the Software without restriction, including without limitation the rights
|
| 1522 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
| 1523 |
+
copies of the Software, and to permit persons to whom the Software is
|
| 1524 |
+
furnished to do so, subject to the following conditions:
|
| 1525 |
+
|
| 1526 |
+
The above copyright notice and this permission notice shall be included in
|
| 1527 |
+
all copies or substantial portions of the Software.
|
| 1528 |
+
|
| 1529 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| 1530 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 1531 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
| 1532 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
| 1533 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
| 1534 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
| 1535 |
+
THE SOFTWARE.
|
| 1536 |
+
|
| 1537 |
+
19. Licensee's use of the Visual Studio Setup Configuration
|
| 1538 |
+
Samples is subject to the following license:
|
| 1539 |
+
|
| 1540 |
+
The MIT License (MIT)
|
| 1541 |
+
Copyright (C) Microsoft Corporation. All rights reserved.
|
| 1542 |
+
|
| 1543 |
+
Permission is hereby granted, free of charge, to any person
|
| 1544 |
+
obtaining a copy of this software and associated documentation
|
| 1545 |
+
files (the "Software"), to deal in the Software without restriction,
|
| 1546 |
+
including without limitation the rights to use, copy, modify, merge,
|
| 1547 |
+
publish, distribute, sublicense, and/or sell copies of the Software,
|
| 1548 |
+
and to permit persons to whom the Software is furnished to do so,
|
| 1549 |
+
subject to the following conditions:
|
| 1550 |
+
|
| 1551 |
+
The above copyright notice and this permission notice shall be included
|
| 1552 |
+
in all copies or substantial portions of the Software.
|
| 1553 |
+
|
| 1554 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
| 1555 |
+
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 1556 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
| 1557 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
| 1558 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
| 1559 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
| 1560 |
+
|
| 1561 |
+
20. Licensee's use of linmath.h header for CPU functions for
|
| 1562 |
+
GL vector/matrix operations from lunarG is subject to the
|
| 1563 |
+
Apache License Version 2.0.
|
| 1564 |
+
|
| 1565 |
+
21. The DX12-CUDA sample uses the d3dx12.h header, which is
|
| 1566 |
+
subject to the MIT license .
|
| 1567 |
+
|
| 1568 |
+
-----------------
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia_cusolver_cu12-11.7.3.90.dist-info/METADATA
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Metadata-Version: 2.2
|
| 2 |
+
Name: nvidia-cusolver-cu12
|
| 3 |
+
Version: 11.7.3.90
|
| 4 |
+
Summary: CUDA solver native runtime libraries
|
| 5 |
+
Home-page: https://developer.nvidia.com/cuda-zone
|
| 6 |
+
Author: Nvidia CUDA Installer Team
|
| 7 |
+
Author-email: compute_installer@nvidia.com
|
| 8 |
+
License: NVIDIA Proprietary Software
|
| 9 |
+
Keywords: cuda,nvidia,runtime,machine learning,deep learning
|
| 10 |
+
Classifier: Development Status :: 4 - Beta
|
| 11 |
+
Classifier: Intended Audience :: Developers
|
| 12 |
+
Classifier: Intended Audience :: Education
|
| 13 |
+
Classifier: Intended Audience :: Science/Research
|
| 14 |
+
Classifier: License :: Other/Proprietary License
|
| 15 |
+
Classifier: Natural Language :: English
|
| 16 |
+
Classifier: Programming Language :: Python :: 3
|
| 17 |
+
Classifier: Programming Language :: Python :: 3.5
|
| 18 |
+
Classifier: Programming Language :: Python :: 3.6
|
| 19 |
+
Classifier: Programming Language :: Python :: 3.7
|
| 20 |
+
Classifier: Programming Language :: Python :: 3.8
|
| 21 |
+
Classifier: Programming Language :: Python :: 3.9
|
| 22 |
+
Classifier: Programming Language :: Python :: 3.10
|
| 23 |
+
Classifier: Programming Language :: Python :: 3.11
|
| 24 |
+
Classifier: Programming Language :: Python :: 3 :: Only
|
| 25 |
+
Classifier: Topic :: Scientific/Engineering
|
| 26 |
+
Classifier: Topic :: Scientific/Engineering :: Mathematics
|
| 27 |
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
| 28 |
+
Classifier: Topic :: Software Development
|
| 29 |
+
Classifier: Topic :: Software Development :: Libraries
|
| 30 |
+
Classifier: Operating System :: Microsoft :: Windows
|
| 31 |
+
Classifier: Operating System :: POSIX :: Linux
|
| 32 |
+
Requires-Python: >=3
|
| 33 |
+
License-File: License.txt
|
| 34 |
+
Requires-Dist: nvidia-cublas-cu12
|
| 35 |
+
Requires-Dist: nvidia-nvjitlink-cu12
|
| 36 |
+
Requires-Dist: nvidia-cusparse-cu12
|
| 37 |
+
Dynamic: author
|
| 38 |
+
Dynamic: author-email
|
| 39 |
+
Dynamic: classifier
|
| 40 |
+
Dynamic: description
|
| 41 |
+
Dynamic: home-page
|
| 42 |
+
Dynamic: keywords
|
| 43 |
+
Dynamic: license
|
| 44 |
+
Dynamic: requires-dist
|
| 45 |
+
Dynamic: requires-python
|
| 46 |
+
Dynamic: summary
|
| 47 |
+
|
| 48 |
+
CUDA solver native runtime libraries
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia_cusolver_cu12-11.7.3.90.dist-info/RECORD
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
nvidia/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
| 2 |
+
nvidia/__pycache__/__init__.cpython-312.pyc,,
|
| 3 |
+
nvidia/cusolver/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
| 4 |
+
nvidia/cusolver/__pycache__/__init__.cpython-312.pyc,,
|
| 5 |
+
nvidia/cusolver/include/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
| 6 |
+
nvidia/cusolver/include/__pycache__/__init__.cpython-312.pyc,,
|
| 7 |
+
nvidia/cusolver/include/cusolverDn.h,sha256=BqiXh-sSll7KxwhjqSuVJvSDxeByqj2xfAK0KyoG3Ks,152029
|
| 8 |
+
nvidia/cusolver/include/cusolverMg.h,sha256=N8989nnS2BleeMyuftbQgBDJ4sMAkLPSnmy_S_7fxng,11549
|
| 9 |
+
nvidia/cusolver/include/cusolverRf.h,sha256=4FN6o6FYml09pS4p-YT5JKbwgZqKLEtf9tQZr50yZo4,14535
|
| 10 |
+
nvidia/cusolver/include/cusolverSp.h,sha256=SzIH2Gt36f_caN1wjF8PnCwYLhwsfJ63n1MPIc0_Ams,32885
|
| 11 |
+
nvidia/cusolver/include/cusolverSp_LOWLEVEL_PREVIEW.h,sha256=mmmXuX_glHBdpgTzIqhXkLMz9UCxxC1uQTbcKA1W6UI,39169
|
| 12 |
+
nvidia/cusolver/include/cusolver_common.h,sha256=k5hHZEZcoxxkTFqbKJWKGuxuHLaSRwWIvYdgvQJ0bdw,8732
|
| 13 |
+
nvidia/cusolver/lib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
| 14 |
+
nvidia/cusolver/lib/__pycache__/__init__.cpython-312.pyc,,
|
| 15 |
+
nvidia/cusolver/lib/libcusolver.so.11,sha256=tkuDi_Pi8nNzpZMSr_c6X7fkUjAMQEjbNTp_MNAJodc,243303872
|
| 16 |
+
nvidia/cusolver/lib/libcusolverMg.so.11,sha256=2UdlRjHFNukJmrzJ_lUezpfQ_-uPurFCGJ6iyFvFXo4,161493576
|
| 17 |
+
nvidia_cusolver_cu12-11.7.3.90.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
| 18 |
+
nvidia_cusolver_cu12-11.7.3.90.dist-info/License.txt,sha256=rW9YU_ugyg0VnQ9Y1JrkmDDC-Mk_epJki5zpCttMbM0,59262
|
| 19 |
+
nvidia_cusolver_cu12-11.7.3.90.dist-info/METADATA,sha256=HwalXcjyrvnrIPAYBEv6dzESRpi6e0NdEcJQxi6vTcM,1826
|
| 20 |
+
nvidia_cusolver_cu12-11.7.3.90.dist-info/RECORD,,
|
| 21 |
+
nvidia_cusolver_cu12-11.7.3.90.dist-info/WHEEL,sha256=VtFLEVB-VX8niQT4kQ5pcQOOqiKvUvqfZe5V14HmU88,109
|
| 22 |
+
nvidia_cusolver_cu12-11.7.3.90.dist-info/top_level.txt,sha256=fTkAtiFuL16nUrB9ytDDtpytz2t0B4NvYTnRzwAhO14,7
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia_cusolver_cu12-11.7.3.90.dist-info/WHEEL
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Wheel-Version: 1.0
|
| 2 |
+
Generator: setuptools (75.8.0)
|
| 3 |
+
Root-Is-Purelib: true
|
| 4 |
+
Tag: py3-none-manylinux_2_27_x86_64
|
| 5 |
+
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/nvidia_cusolver_cu12-11.7.3.90.dist-info/top_level.txt
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
nvidia
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/peft/__init__.py
ADDED
|
@@ -0,0 +1,244 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2023-present the HuggingFace Inc. team.
|
| 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 |
+
|
| 15 |
+
__version__ = "0.18.1"
|
| 16 |
+
|
| 17 |
+
from .auto import (
|
| 18 |
+
MODEL_TYPE_TO_PEFT_MODEL_MAPPING,
|
| 19 |
+
AutoPeftModel,
|
| 20 |
+
AutoPeftModelForCausalLM,
|
| 21 |
+
AutoPeftModelForFeatureExtraction,
|
| 22 |
+
AutoPeftModelForQuestionAnswering,
|
| 23 |
+
AutoPeftModelForSeq2SeqLM,
|
| 24 |
+
AutoPeftModelForSequenceClassification,
|
| 25 |
+
AutoPeftModelForTokenClassification,
|
| 26 |
+
)
|
| 27 |
+
from .config import PeftConfig, PromptLearningConfig
|
| 28 |
+
from .mapping import (
|
| 29 |
+
PEFT_TYPE_TO_CONFIG_MAPPING,
|
| 30 |
+
PEFT_TYPE_TO_MIXED_MODEL_MAPPING,
|
| 31 |
+
PEFT_TYPE_TO_TUNER_MAPPING,
|
| 32 |
+
get_peft_config,
|
| 33 |
+
inject_adapter_in_model,
|
| 34 |
+
)
|
| 35 |
+
from .mapping_func import get_peft_model
|
| 36 |
+
from .mixed_model import PeftMixedModel
|
| 37 |
+
from .peft_model import (
|
| 38 |
+
PeftModel,
|
| 39 |
+
PeftModelForCausalLM,
|
| 40 |
+
PeftModelForFeatureExtraction,
|
| 41 |
+
PeftModelForQuestionAnswering,
|
| 42 |
+
PeftModelForSeq2SeqLM,
|
| 43 |
+
PeftModelForSequenceClassification,
|
| 44 |
+
PeftModelForTokenClassification,
|
| 45 |
+
get_layer_status,
|
| 46 |
+
get_model_status,
|
| 47 |
+
)
|
| 48 |
+
from .tuners import (
|
| 49 |
+
AdaLoraConfig,
|
| 50 |
+
AdaLoraModel,
|
| 51 |
+
AdaptionPromptConfig,
|
| 52 |
+
AdaptionPromptModel,
|
| 53 |
+
ArrowConfig,
|
| 54 |
+
BOFTConfig,
|
| 55 |
+
BOFTModel,
|
| 56 |
+
BoneConfig,
|
| 57 |
+
BoneModel,
|
| 58 |
+
C3AConfig,
|
| 59 |
+
C3AModel,
|
| 60 |
+
CPTConfig,
|
| 61 |
+
CPTEmbedding,
|
| 62 |
+
DeloraConfig,
|
| 63 |
+
DeloraModel,
|
| 64 |
+
EvaConfig,
|
| 65 |
+
FourierFTConfig,
|
| 66 |
+
FourierFTModel,
|
| 67 |
+
HRAConfig,
|
| 68 |
+
HRAModel,
|
| 69 |
+
IA3Config,
|
| 70 |
+
IA3Model,
|
| 71 |
+
LNTuningConfig,
|
| 72 |
+
LNTuningModel,
|
| 73 |
+
LoftQConfig,
|
| 74 |
+
LoHaConfig,
|
| 75 |
+
LoHaModel,
|
| 76 |
+
LoKrConfig,
|
| 77 |
+
LoKrModel,
|
| 78 |
+
LoraConfig,
|
| 79 |
+
LoraModel,
|
| 80 |
+
LoraRuntimeConfig,
|
| 81 |
+
MissConfig,
|
| 82 |
+
MissModel,
|
| 83 |
+
MultitaskPromptTuningConfig,
|
| 84 |
+
MultitaskPromptTuningInit,
|
| 85 |
+
OFTConfig,
|
| 86 |
+
OFTModel,
|
| 87 |
+
OSFConfig,
|
| 88 |
+
OSFModel,
|
| 89 |
+
PolyConfig,
|
| 90 |
+
PolyModel,
|
| 91 |
+
PrefixEncoder,
|
| 92 |
+
PrefixTuningConfig,
|
| 93 |
+
PromptEmbedding,
|
| 94 |
+
PromptEncoder,
|
| 95 |
+
PromptEncoderConfig,
|
| 96 |
+
PromptEncoderReparameterizationType,
|
| 97 |
+
PromptTuningConfig,
|
| 98 |
+
PromptTuningInit,
|
| 99 |
+
RandLoraConfig,
|
| 100 |
+
RandLoraModel,
|
| 101 |
+
RoadConfig,
|
| 102 |
+
RoadModel,
|
| 103 |
+
ShiraConfig,
|
| 104 |
+
ShiraModel,
|
| 105 |
+
TrainableTokensConfig,
|
| 106 |
+
TrainableTokensModel,
|
| 107 |
+
VBLoRAConfig,
|
| 108 |
+
VBLoRAModel,
|
| 109 |
+
VeraConfig,
|
| 110 |
+
VeraModel,
|
| 111 |
+
WaveFTConfig,
|
| 112 |
+
WaveFTModel,
|
| 113 |
+
XLoraConfig,
|
| 114 |
+
XLoraModel,
|
| 115 |
+
create_arrow_model,
|
| 116 |
+
get_eva_state_dict,
|
| 117 |
+
initialize_lora_eva_weights,
|
| 118 |
+
)
|
| 119 |
+
from .utils import (
|
| 120 |
+
TRANSFORMERS_MODELS_TO_PREFIX_TUNING_POSTPROCESS_MAPPING,
|
| 121 |
+
PeftType,
|
| 122 |
+
PeftWarning,
|
| 123 |
+
TaskType,
|
| 124 |
+
bloom_model_postprocess_past_key_value,
|
| 125 |
+
cast_mixed_precision_params,
|
| 126 |
+
get_peft_model_state_dict,
|
| 127 |
+
load_peft_weights,
|
| 128 |
+
prepare_model_for_kbit_training,
|
| 129 |
+
replace_lora_weights_loftq,
|
| 130 |
+
set_peft_model_state_dict,
|
| 131 |
+
shift_tokens_right,
|
| 132 |
+
)
|
| 133 |
+
|
| 134 |
+
|
| 135 |
+
__all__ = [
|
| 136 |
+
"MODEL_TYPE_TO_PEFT_MODEL_MAPPING",
|
| 137 |
+
"PEFT_TYPE_TO_CONFIG_MAPPING",
|
| 138 |
+
"PEFT_TYPE_TO_MIXED_MODEL_MAPPING",
|
| 139 |
+
"PEFT_TYPE_TO_TUNER_MAPPING",
|
| 140 |
+
"TRANSFORMERS_MODELS_TO_PREFIX_TUNING_POSTPROCESS_MAPPING",
|
| 141 |
+
"AdaLoraConfig",
|
| 142 |
+
"AdaLoraModel",
|
| 143 |
+
"AdaptionPromptConfig",
|
| 144 |
+
"AdaptionPromptModel",
|
| 145 |
+
"ArrowConfig",
|
| 146 |
+
"AutoPeftModel",
|
| 147 |
+
"AutoPeftModelForCausalLM",
|
| 148 |
+
"AutoPeftModelForFeatureExtraction",
|
| 149 |
+
"AutoPeftModelForQuestionAnswering",
|
| 150 |
+
"AutoPeftModelForSeq2SeqLM",
|
| 151 |
+
"AutoPeftModelForSequenceClassification",
|
| 152 |
+
"AutoPeftModelForTokenClassification",
|
| 153 |
+
"BOFTConfig",
|
| 154 |
+
"BOFTModel",
|
| 155 |
+
"BoneConfig",
|
| 156 |
+
"BoneModel",
|
| 157 |
+
"C3AConfig",
|
| 158 |
+
"C3AModel",
|
| 159 |
+
"CPTConfig",
|
| 160 |
+
"CPTEmbedding",
|
| 161 |
+
"DeloraConfig",
|
| 162 |
+
"DeloraModel",
|
| 163 |
+
"EvaConfig",
|
| 164 |
+
"FourierFTConfig",
|
| 165 |
+
"FourierFTModel",
|
| 166 |
+
"HRAConfig",
|
| 167 |
+
"HRAModel",
|
| 168 |
+
"IA3Config",
|
| 169 |
+
"IA3Model",
|
| 170 |
+
"LNTuningConfig",
|
| 171 |
+
"LNTuningModel",
|
| 172 |
+
"LoHaConfig",
|
| 173 |
+
"LoHaModel",
|
| 174 |
+
"LoKrConfig",
|
| 175 |
+
"LoKrModel",
|
| 176 |
+
"LoftQConfig",
|
| 177 |
+
"LoraConfig",
|
| 178 |
+
"LoraModel",
|
| 179 |
+
"LoraRuntimeConfig",
|
| 180 |
+
"MissConfig",
|
| 181 |
+
"MissModel",
|
| 182 |
+
"MultitaskPromptTuningConfig",
|
| 183 |
+
"MultitaskPromptTuningInit",
|
| 184 |
+
"OFTConfig",
|
| 185 |
+
"OFTModel",
|
| 186 |
+
"OSFConfig",
|
| 187 |
+
"OSFModel",
|
| 188 |
+
"PeftConfig",
|
| 189 |
+
"PeftMixedModel",
|
| 190 |
+
"PeftModel",
|
| 191 |
+
"PeftModelForCausalLM",
|
| 192 |
+
"PeftModelForFeatureExtraction",
|
| 193 |
+
"PeftModelForQuestionAnswering",
|
| 194 |
+
"PeftModelForSeq2SeqLM",
|
| 195 |
+
"PeftModelForSequenceClassification",
|
| 196 |
+
"PeftModelForTokenClassification",
|
| 197 |
+
"PeftType",
|
| 198 |
+
"PeftWarning",
|
| 199 |
+
"PolyConfig",
|
| 200 |
+
"PolyModel",
|
| 201 |
+
"PrefixEncoder",
|
| 202 |
+
"PrefixTuningConfig",
|
| 203 |
+
"PromptEmbedding",
|
| 204 |
+
"PromptEncoder",
|
| 205 |
+
"PromptEncoderConfig",
|
| 206 |
+
"PromptEncoderReparameterizationType",
|
| 207 |
+
"PromptLearningConfig",
|
| 208 |
+
"PromptTuningConfig",
|
| 209 |
+
"PromptTuningInit",
|
| 210 |
+
"RandLoraConfig",
|
| 211 |
+
"RandLoraModel",
|
| 212 |
+
"RoadConfig",
|
| 213 |
+
"RoadModel",
|
| 214 |
+
"ShiraConfig",
|
| 215 |
+
"ShiraModel",
|
| 216 |
+
"TaskType",
|
| 217 |
+
"TrainableTokensConfig",
|
| 218 |
+
"TrainableTokensModel",
|
| 219 |
+
"VBLoRAConfig",
|
| 220 |
+
"VBLoRAConfig",
|
| 221 |
+
"VBLoRAModel",
|
| 222 |
+
"VeraConfig",
|
| 223 |
+
"VeraModel",
|
| 224 |
+
"WaveFTConfig",
|
| 225 |
+
"WaveFTModel",
|
| 226 |
+
"XLoraConfig",
|
| 227 |
+
"XLoraModel",
|
| 228 |
+
"bloom_model_postprocess_past_key_value",
|
| 229 |
+
"cast_mixed_precision_params",
|
| 230 |
+
"create_arrow_model",
|
| 231 |
+
"get_eva_state_dict",
|
| 232 |
+
"get_layer_status",
|
| 233 |
+
"get_model_status",
|
| 234 |
+
"get_peft_config",
|
| 235 |
+
"get_peft_model",
|
| 236 |
+
"get_peft_model_state_dict",
|
| 237 |
+
"initialize_lora_eva_weights",
|
| 238 |
+
"inject_adapter_in_model",
|
| 239 |
+
"load_peft_weights",
|
| 240 |
+
"prepare_model_for_kbit_training",
|
| 241 |
+
"replace_lora_weights_loftq",
|
| 242 |
+
"set_peft_model_state_dict",
|
| 243 |
+
"shift_tokens_right",
|
| 244 |
+
]
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/peft/auto.py
ADDED
|
@@ -0,0 +1,184 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2023-present the HuggingFace Inc. team.
|
| 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 |
+
|
| 15 |
+
from __future__ import annotations
|
| 16 |
+
|
| 17 |
+
import importlib
|
| 18 |
+
import os
|
| 19 |
+
from typing import Optional
|
| 20 |
+
|
| 21 |
+
from transformers import (
|
| 22 |
+
AutoModel,
|
| 23 |
+
AutoModelForCausalLM,
|
| 24 |
+
AutoModelForQuestionAnswering,
|
| 25 |
+
AutoModelForSeq2SeqLM,
|
| 26 |
+
AutoModelForSequenceClassification,
|
| 27 |
+
AutoModelForTokenClassification,
|
| 28 |
+
AutoTokenizer,
|
| 29 |
+
)
|
| 30 |
+
|
| 31 |
+
from .config import PeftConfig
|
| 32 |
+
from .peft_model import (
|
| 33 |
+
PeftModel,
|
| 34 |
+
PeftModelForCausalLM,
|
| 35 |
+
PeftModelForFeatureExtraction,
|
| 36 |
+
PeftModelForQuestionAnswering,
|
| 37 |
+
PeftModelForSeq2SeqLM,
|
| 38 |
+
PeftModelForSequenceClassification,
|
| 39 |
+
PeftModelForTokenClassification,
|
| 40 |
+
)
|
| 41 |
+
from .utils.constants import TOKENIZER_CONFIG_NAME
|
| 42 |
+
from .utils.other import check_file_exists_on_hf_hub
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
MODEL_TYPE_TO_PEFT_MODEL_MAPPING: dict[str, type[PeftModel]] = {
|
| 46 |
+
"SEQ_CLS": PeftModelForSequenceClassification,
|
| 47 |
+
"SEQ_2_SEQ_LM": PeftModelForSeq2SeqLM,
|
| 48 |
+
"CAUSAL_LM": PeftModelForCausalLM,
|
| 49 |
+
"TOKEN_CLS": PeftModelForTokenClassification,
|
| 50 |
+
"QUESTION_ANS": PeftModelForQuestionAnswering,
|
| 51 |
+
"FEATURE_EXTRACTION": PeftModelForFeatureExtraction,
|
| 52 |
+
}
|
| 53 |
+
|
| 54 |
+
|
| 55 |
+
class _BaseAutoPeftModel:
|
| 56 |
+
_target_class = None
|
| 57 |
+
_target_peft_class = None
|
| 58 |
+
|
| 59 |
+
def __init__(self, *args, **kwargs):
|
| 60 |
+
# For consistency with transformers: https://github.com/huggingface/transformers/blob/91d7df58b6537d385e90578dac40204cb550f706/src/transformers/models/auto/auto_factory.py#L400
|
| 61 |
+
raise EnvironmentError( # noqa: UP024
|
| 62 |
+
f"{self.__class__.__name__} is designed to be instantiated "
|
| 63 |
+
f"using the `{self.__class__.__name__}.from_pretrained(pretrained_model_name_or_path)` or "
|
| 64 |
+
f"`{self.__class__.__name__}.from_config(config)` methods."
|
| 65 |
+
)
|
| 66 |
+
|
| 67 |
+
@classmethod
|
| 68 |
+
def from_pretrained(
|
| 69 |
+
cls,
|
| 70 |
+
pretrained_model_name_or_path,
|
| 71 |
+
adapter_name: str = "default",
|
| 72 |
+
is_trainable: bool = False,
|
| 73 |
+
config: Optional[PeftConfig] = None,
|
| 74 |
+
revision: Optional[str] = None,
|
| 75 |
+
**kwargs,
|
| 76 |
+
):
|
| 77 |
+
r"""
|
| 78 |
+
A wrapper around all the preprocessing steps a user needs to perform in order to load a PEFT model. The kwargs
|
| 79 |
+
are passed along to `PeftConfig` that automatically takes care of filtering the kwargs of the Hub methods and
|
| 80 |
+
the config object init.
|
| 81 |
+
"""
|
| 82 |
+
peft_config = PeftConfig.from_pretrained(pretrained_model_name_or_path, revision=revision, **kwargs)
|
| 83 |
+
base_model_path = peft_config.base_model_name_or_path
|
| 84 |
+
base_model_revision = peft_config.revision
|
| 85 |
+
|
| 86 |
+
task_type = getattr(peft_config, "task_type", None)
|
| 87 |
+
|
| 88 |
+
if cls._target_class is not None:
|
| 89 |
+
target_class = cls._target_class
|
| 90 |
+
elif cls._target_class is None and task_type is not None:
|
| 91 |
+
# this is only in the case where we use `AutoPeftModel`
|
| 92 |
+
raise ValueError(
|
| 93 |
+
"Cannot use `AutoPeftModel` with a task type, please use a specific class for your task type. (e.g. `AutoPeftModelForCausalLM` for `task_type='CAUSAL_LM'`)"
|
| 94 |
+
)
|
| 95 |
+
|
| 96 |
+
if task_type is not None:
|
| 97 |
+
expected_target_class = MODEL_TYPE_TO_PEFT_MODEL_MAPPING[task_type]
|
| 98 |
+
if cls._target_peft_class.__name__ != expected_target_class.__name__:
|
| 99 |
+
raise ValueError(
|
| 100 |
+
f"Expected target PEFT class: {expected_target_class.__name__}, but you have asked for: {cls._target_peft_class.__name__}"
|
| 101 |
+
" make sure that you are loading the correct model for your task type."
|
| 102 |
+
)
|
| 103 |
+
elif task_type is None and getattr(peft_config, "auto_mapping", None) is not None:
|
| 104 |
+
auto_mapping = getattr(peft_config, "auto_mapping", None)
|
| 105 |
+
base_model_class = auto_mapping["base_model_class"]
|
| 106 |
+
parent_library_name = auto_mapping["parent_library"]
|
| 107 |
+
|
| 108 |
+
parent_library = importlib.import_module(parent_library_name)
|
| 109 |
+
target_class = getattr(parent_library, base_model_class)
|
| 110 |
+
else:
|
| 111 |
+
raise ValueError(
|
| 112 |
+
"Cannot infer the auto class from the config, please make sure that you are loading the correct model for your task type."
|
| 113 |
+
)
|
| 114 |
+
|
| 115 |
+
base_model = target_class.from_pretrained(base_model_path, revision=base_model_revision, **kwargs)
|
| 116 |
+
|
| 117 |
+
tokenizer_exists = False
|
| 118 |
+
if os.path.exists(os.path.join(pretrained_model_name_or_path, TOKENIZER_CONFIG_NAME)):
|
| 119 |
+
tokenizer_exists = True
|
| 120 |
+
else:
|
| 121 |
+
token = kwargs.get("token", None)
|
| 122 |
+
if token is None:
|
| 123 |
+
token = kwargs.get("use_auth_token", None)
|
| 124 |
+
|
| 125 |
+
tokenizer_exists = check_file_exists_on_hf_hub(
|
| 126 |
+
repo_id=pretrained_model_name_or_path,
|
| 127 |
+
filename=TOKENIZER_CONFIG_NAME,
|
| 128 |
+
revision=revision,
|
| 129 |
+
repo_type=kwargs.get("repo_type", None),
|
| 130 |
+
token=token,
|
| 131 |
+
)
|
| 132 |
+
|
| 133 |
+
if tokenizer_exists and hasattr(base_model, "get_input_embeddings"):
|
| 134 |
+
tokenizer = AutoTokenizer.from_pretrained(
|
| 135 |
+
pretrained_model_name_or_path, trust_remote_code=kwargs.get("trust_remote_code", False)
|
| 136 |
+
)
|
| 137 |
+
embedding_size = base_model.get_input_embeddings().weight.shape[0]
|
| 138 |
+
if len(tokenizer) > embedding_size:
|
| 139 |
+
# only resize if the tokenizer has a larger vocab size than there are embeddings
|
| 140 |
+
base_model.resize_token_embeddings(len(tokenizer))
|
| 141 |
+
|
| 142 |
+
return cls._target_peft_class.from_pretrained(
|
| 143 |
+
base_model,
|
| 144 |
+
pretrained_model_name_or_path,
|
| 145 |
+
adapter_name=adapter_name,
|
| 146 |
+
is_trainable=is_trainable,
|
| 147 |
+
config=config,
|
| 148 |
+
**kwargs,
|
| 149 |
+
)
|
| 150 |
+
|
| 151 |
+
|
| 152 |
+
class AutoPeftModel(_BaseAutoPeftModel):
|
| 153 |
+
_target_class = None
|
| 154 |
+
_target_peft_class = PeftModel
|
| 155 |
+
|
| 156 |
+
|
| 157 |
+
class AutoPeftModelForCausalLM(_BaseAutoPeftModel):
|
| 158 |
+
_target_class = AutoModelForCausalLM
|
| 159 |
+
_target_peft_class = PeftModelForCausalLM
|
| 160 |
+
|
| 161 |
+
|
| 162 |
+
class AutoPeftModelForSeq2SeqLM(_BaseAutoPeftModel):
|
| 163 |
+
_target_class = AutoModelForSeq2SeqLM
|
| 164 |
+
_target_peft_class = PeftModelForSeq2SeqLM
|
| 165 |
+
|
| 166 |
+
|
| 167 |
+
class AutoPeftModelForSequenceClassification(_BaseAutoPeftModel):
|
| 168 |
+
_target_class = AutoModelForSequenceClassification
|
| 169 |
+
_target_peft_class = PeftModelForSequenceClassification
|
| 170 |
+
|
| 171 |
+
|
| 172 |
+
class AutoPeftModelForTokenClassification(_BaseAutoPeftModel):
|
| 173 |
+
_target_class = AutoModelForTokenClassification
|
| 174 |
+
_target_peft_class = PeftModelForTokenClassification
|
| 175 |
+
|
| 176 |
+
|
| 177 |
+
class AutoPeftModelForQuestionAnswering(_BaseAutoPeftModel):
|
| 178 |
+
_target_class = AutoModelForQuestionAnswering
|
| 179 |
+
_target_peft_class = PeftModelForQuestionAnswering
|
| 180 |
+
|
| 181 |
+
|
| 182 |
+
class AutoPeftModelForFeatureExtraction(_BaseAutoPeftModel):
|
| 183 |
+
_target_class = AutoModel
|
| 184 |
+
_target_peft_class = PeftModelForFeatureExtraction
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/peft/config.py
ADDED
|
@@ -0,0 +1,408 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2023-present the HuggingFace Inc. team.
|
| 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 |
+
from __future__ import annotations
|
| 15 |
+
|
| 16 |
+
import importlib.metadata
|
| 17 |
+
import inspect
|
| 18 |
+
import json
|
| 19 |
+
import os
|
| 20 |
+
import warnings
|
| 21 |
+
from dataclasses import asdict, dataclass, field
|
| 22 |
+
from typing import Optional, Union
|
| 23 |
+
|
| 24 |
+
import packaging.version
|
| 25 |
+
from huggingface_hub import hf_hub_download
|
| 26 |
+
from transformers.utils import PushToHubMixin, http_user_agent
|
| 27 |
+
|
| 28 |
+
from peft import __version__
|
| 29 |
+
|
| 30 |
+
from .utils import CONFIG_NAME, PeftType, TaskType
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
# we expect at least these keys to be present in a PEFT adapter_config.json
|
| 34 |
+
MIN_EXPECTED_CONFIG_KEYS = {"peft_type"}
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
def _check_and_remove_unused_kwargs(cls, kwargs):
|
| 38 |
+
"""Make PEFT configs forward-compatible by removing unused kwargs that were added in later PEFT versions.
|
| 39 |
+
|
| 40 |
+
This assumes that removing the unused kwargs will not affect the default behavior.
|
| 41 |
+
|
| 42 |
+
Returns the filtered kwargs and the set of removed keys.
|
| 43 |
+
"""
|
| 44 |
+
# it's not pretty but eh
|
| 45 |
+
signature_parameters = inspect.signature(cls.__init__).parameters
|
| 46 |
+
unexpected_kwargs = set(kwargs.keys()) - set(signature_parameters.keys())
|
| 47 |
+
for key in unexpected_kwargs:
|
| 48 |
+
del kwargs[key]
|
| 49 |
+
return kwargs, unexpected_kwargs
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
def _is_dev_version(version: str) -> bool:
|
| 53 |
+
# check if the given version is a dev version
|
| 54 |
+
return packaging.version.Version(version).dev is not None
|
| 55 |
+
|
| 56 |
+
|
| 57 |
+
def _get_commit_hash(pkg_name: str) -> str | None:
|
| 58 |
+
# If PEFT was installed from a specific commit hash, try to get it. This works e.g. when installing PEFT with `pip
|
| 59 |
+
# install git+https://github.com/huggingface/peft.git@<HASH>`. This works not for other means, like editable
|
| 60 |
+
# installs.
|
| 61 |
+
try:
|
| 62 |
+
dist = importlib.metadata.distribution(pkg_name)
|
| 63 |
+
except importlib.metadata.PackageNotFoundError:
|
| 64 |
+
return None
|
| 65 |
+
|
| 66 |
+
# See: https://packaging.python.org/en/latest/specifications/direct-url/
|
| 67 |
+
for path in dist.files or []:
|
| 68 |
+
if path.name == "direct_url.json":
|
| 69 |
+
direct_url = json.loads((dist.locate_file(path)).read_text())
|
| 70 |
+
vcs_info = direct_url.get("vcs_info")
|
| 71 |
+
if vcs_info and "commit_id" in vcs_info:
|
| 72 |
+
return vcs_info["commit_id"]
|
| 73 |
+
return None
|
| 74 |
+
|
| 75 |
+
|
| 76 |
+
@dataclass
|
| 77 |
+
class PeftConfigMixin(PushToHubMixin):
|
| 78 |
+
r"""
|
| 79 |
+
This is the base configuration class for PEFT adapter models. It contains all the methods that are common to all
|
| 80 |
+
PEFT adapter models. This class inherits from [`~transformers.utils.PushToHubMixin`] which contains the methods to
|
| 81 |
+
push your model to the Hub. The method `save_pretrained` will save the configuration of your adapter model in a
|
| 82 |
+
directory. The method `from_pretrained` will load the configuration of your adapter model from a directory.
|
| 83 |
+
|
| 84 |
+
Args:
|
| 85 |
+
peft_type (Union[[`~peft.utils.config.PeftType`], `str`]): The type of Peft method to use.
|
| 86 |
+
"""
|
| 87 |
+
|
| 88 |
+
task_type: Optional[TaskType] = field(default=None, metadata={"help": "The type of task."})
|
| 89 |
+
peft_type: Optional[PeftType] = field(default=None, metadata={"help": "The type of PEFT model."})
|
| 90 |
+
auto_mapping: Optional[dict] = field(
|
| 91 |
+
default=None, metadata={"help": "An auto mapping dict to help retrieve the base model class if needed."}
|
| 92 |
+
)
|
| 93 |
+
peft_version: Optional[str] = field(default=None, metadata={"help": "PEFT version, leave empty to auto-fill."})
|
| 94 |
+
|
| 95 |
+
def __post_init__(self):
|
| 96 |
+
# check for invalid task type
|
| 97 |
+
if (self.task_type is not None) and (self.task_type not in list(TaskType)):
|
| 98 |
+
raise ValueError(
|
| 99 |
+
f"Invalid task type: '{self.task_type}'. Must be one of the following task types: {', '.join(TaskType)}."
|
| 100 |
+
)
|
| 101 |
+
if self.peft_version is None:
|
| 102 |
+
self.peft_version = self._get_peft_version()
|
| 103 |
+
|
| 104 |
+
@staticmethod
|
| 105 |
+
def _get_peft_version() -> str:
|
| 106 |
+
# gets the current peft version; if it's a dev version, try to get the commit hash too, as the dev version is
|
| 107 |
+
# ambiguous
|
| 108 |
+
version = __version__
|
| 109 |
+
if not _is_dev_version(version):
|
| 110 |
+
return version
|
| 111 |
+
|
| 112 |
+
try:
|
| 113 |
+
git_hash = _get_commit_hash("peft")
|
| 114 |
+
if git_hash is None:
|
| 115 |
+
git_hash = "UNKNOWN"
|
| 116 |
+
except Exception:
|
| 117 |
+
# Broad exception: We never want to break user code just because the git_hash could not be determined
|
| 118 |
+
warnings.warn(
|
| 119 |
+
"A dev version of PEFT is used but there was an error while trying to determine the commit hash. "
|
| 120 |
+
"Please open an issue: https://github.com/huggingface/peft/issues"
|
| 121 |
+
)
|
| 122 |
+
git_hash = "UNKNOWN"
|
| 123 |
+
version = version + f"@{git_hash}"
|
| 124 |
+
return version
|
| 125 |
+
|
| 126 |
+
def to_dict(self) -> dict:
|
| 127 |
+
r"""
|
| 128 |
+
Returns the configuration for your adapter model as a dictionary.
|
| 129 |
+
"""
|
| 130 |
+
return asdict(self)
|
| 131 |
+
|
| 132 |
+
def save_pretrained(self, save_directory: str, **kwargs) -> None:
|
| 133 |
+
r"""
|
| 134 |
+
This method saves the configuration of your adapter model in a directory.
|
| 135 |
+
|
| 136 |
+
Args:
|
| 137 |
+
save_directory (`str`):
|
| 138 |
+
The directory where the configuration will be saved.
|
| 139 |
+
kwargs (additional keyword arguments, *optional*):
|
| 140 |
+
Additional keyword arguments passed along to the [`~transformers.utils.PushToHubMixin.push_to_hub`]
|
| 141 |
+
method.
|
| 142 |
+
"""
|
| 143 |
+
if os.path.isfile(save_directory):
|
| 144 |
+
raise AssertionError(f"Provided path ({save_directory}) should be a directory, not a file")
|
| 145 |
+
|
| 146 |
+
os.makedirs(save_directory, exist_ok=True)
|
| 147 |
+
auto_mapping_dict = kwargs.pop("auto_mapping_dict", None)
|
| 148 |
+
|
| 149 |
+
output_dict = self.to_dict()
|
| 150 |
+
# converting set type to list
|
| 151 |
+
for key, value in output_dict.items():
|
| 152 |
+
if isinstance(value, set):
|
| 153 |
+
output_dict[key] = list(value)
|
| 154 |
+
|
| 155 |
+
output_path = os.path.join(save_directory, CONFIG_NAME)
|
| 156 |
+
|
| 157 |
+
# Add auto mapping details for custom models.
|
| 158 |
+
if auto_mapping_dict is not None:
|
| 159 |
+
output_dict["auto_mapping"] = auto_mapping_dict
|
| 160 |
+
|
| 161 |
+
# save it
|
| 162 |
+
with open(output_path, "w") as writer:
|
| 163 |
+
writer.write(json.dumps(output_dict, indent=2, sort_keys=True))
|
| 164 |
+
|
| 165 |
+
@classmethod
|
| 166 |
+
def from_peft_type(cls, **kwargs):
|
| 167 |
+
r"""
|
| 168 |
+
This method loads the configuration of your adapter model from a set of kwargs.
|
| 169 |
+
|
| 170 |
+
The appropriate configuration type is determined by the `peft_type` argument. If `peft_type` is not provided,
|
| 171 |
+
the calling class type is instantiated.
|
| 172 |
+
|
| 173 |
+
Args:
|
| 174 |
+
kwargs (configuration keyword arguments):
|
| 175 |
+
Keyword arguments passed along to the configuration initialization.
|
| 176 |
+
"""
|
| 177 |
+
# Avoid circular dependency .. TODO: fix this with a larger refactor
|
| 178 |
+
from peft.mapping import PEFT_TYPE_TO_CONFIG_MAPPING
|
| 179 |
+
|
| 180 |
+
# TODO: this hack is needed to fix the following issue (on commit 702f937):
|
| 181 |
+
# if someone saves a default config and loads it back with `PeftConfig` class it yields to
|
| 182 |
+
# not loading the correct config class.
|
| 183 |
+
#
|
| 184 |
+
# from peft import AdaLoraConfig, PeftConfig
|
| 185 |
+
# peft_config = AdaLoraConfig()
|
| 186 |
+
# print(peft_config)
|
| 187 |
+
# >>> AdaLoraConfig(peft_type=<PeftType.ADALORA: 'ADALORA'>, auto_mapping=None, base_model_name_or_path=None,
|
| 188 |
+
# revision=None, task_type=None, inference_mode=False, r=8, target_modules=None, lora_alpha=8, lora_dropout=0.0, ...
|
| 189 |
+
#
|
| 190 |
+
# peft_config.save_pretrained("./test_config")
|
| 191 |
+
# peft_config = PeftConfig.from_pretrained("./test_config")
|
| 192 |
+
# print(peft_config)
|
| 193 |
+
# >>> PeftConfig(peft_type='ADALORA', auto_mapping=None, base_model_name_or_path=None, revision=None, task_type=None, inference_mode=False)
|
| 194 |
+
|
| 195 |
+
if "peft_type" in kwargs:
|
| 196 |
+
peft_type = kwargs["peft_type"]
|
| 197 |
+
config_cls = PEFT_TYPE_TO_CONFIG_MAPPING[peft_type]
|
| 198 |
+
else:
|
| 199 |
+
config_cls = cls
|
| 200 |
+
|
| 201 |
+
try:
|
| 202 |
+
config = config_cls(**kwargs)
|
| 203 |
+
except TypeError as exc:
|
| 204 |
+
# Here we potentially handle forward compatibility. Sometimes new keywords are added to configs, which makes
|
| 205 |
+
# new configs incompatible with older PEFT versions. We catch these and remove them to allow the program to
|
| 206 |
+
# continue, but warn the user about it.
|
| 207 |
+
|
| 208 |
+
# First check if the error is due to unexpected keyword arguments, we don't want to accidentally catch
|
| 209 |
+
# other TypeErrors.
|
| 210 |
+
if "got an unexpected keyword argument" not in str(exc):
|
| 211 |
+
raise exc
|
| 212 |
+
|
| 213 |
+
filtered_kwargs, unexpected_kwargs = _check_and_remove_unused_kwargs(config_cls, kwargs)
|
| 214 |
+
if not MIN_EXPECTED_CONFIG_KEYS.issubset(set(filtered_kwargs.keys())):
|
| 215 |
+
raise TypeError(
|
| 216 |
+
f"The {cls.__name__} config that is trying to be loaded is missing required keys: "
|
| 217 |
+
f"{MIN_EXPECTED_CONFIG_KEYS}."
|
| 218 |
+
)
|
| 219 |
+
|
| 220 |
+
warnings.warn(
|
| 221 |
+
f"Unexpected keyword arguments {sorted(unexpected_kwargs)} for class {config_cls.__name__}, these are "
|
| 222 |
+
"ignored. This probably means that you're loading a configuration file that was saved using a "
|
| 223 |
+
"higher version of the library and additional parameters have been introduced since. It is "
|
| 224 |
+
"highly recommended to upgrade the PEFT version before continuing (e.g. by running `pip install "
|
| 225 |
+
"-U peft`)."
|
| 226 |
+
)
|
| 227 |
+
config = config_cls.from_peft_type(**filtered_kwargs)
|
| 228 |
+
return config
|
| 229 |
+
|
| 230 |
+
@classmethod
|
| 231 |
+
def from_pretrained(cls, pretrained_model_name_or_path: str, subfolder: Optional[str] = None, **kwargs):
|
| 232 |
+
r"""
|
| 233 |
+
This method loads the configuration of your adapter model from a directory.
|
| 234 |
+
|
| 235 |
+
Args:
|
| 236 |
+
pretrained_model_name_or_path (`str`):
|
| 237 |
+
The directory or the Hub repository id where the configuration is saved.
|
| 238 |
+
kwargs (additional keyword arguments, *optional*):
|
| 239 |
+
Additional keyword arguments passed along to the child class initialization.
|
| 240 |
+
"""
|
| 241 |
+
path = (
|
| 242 |
+
os.path.join(pretrained_model_name_or_path, subfolder)
|
| 243 |
+
if subfolder is not None
|
| 244 |
+
else pretrained_model_name_or_path
|
| 245 |
+
)
|
| 246 |
+
|
| 247 |
+
hf_hub_download_kwargs, class_kwargs, _ = cls._split_kwargs(kwargs)
|
| 248 |
+
if "user_agent" not in hf_hub_download_kwargs:
|
| 249 |
+
hf_hub_download_kwargs["user_agent"] = http_user_agent()
|
| 250 |
+
|
| 251 |
+
if os.path.isfile(os.path.join(path, CONFIG_NAME)):
|
| 252 |
+
config_file = os.path.join(path, CONFIG_NAME)
|
| 253 |
+
else:
|
| 254 |
+
try:
|
| 255 |
+
config_file = hf_hub_download(
|
| 256 |
+
pretrained_model_name_or_path, CONFIG_NAME, subfolder=subfolder, **hf_hub_download_kwargs
|
| 257 |
+
)
|
| 258 |
+
except Exception as exc:
|
| 259 |
+
raise ValueError(f"Can't find '{CONFIG_NAME}' at '{pretrained_model_name_or_path}'") from exc
|
| 260 |
+
|
| 261 |
+
loaded_attributes = cls.from_json_file(config_file)
|
| 262 |
+
kwargs = {**class_kwargs, **loaded_attributes}
|
| 263 |
+
kwargs = cls.check_kwargs(**kwargs)
|
| 264 |
+
return cls.from_peft_type(**kwargs)
|
| 265 |
+
|
| 266 |
+
@classmethod
|
| 267 |
+
def from_json_file(cls, path_json_file: str, **kwargs):
|
| 268 |
+
r"""
|
| 269 |
+
Loads a configuration file from a json file.
|
| 270 |
+
|
| 271 |
+
Args:
|
| 272 |
+
path_json_file (`str`):
|
| 273 |
+
The path to the json file.
|
| 274 |
+
"""
|
| 275 |
+
with open(path_json_file) as file:
|
| 276 |
+
json_object = json.load(file)
|
| 277 |
+
|
| 278 |
+
# Sanity check that config does not contain a runtime_config
|
| 279 |
+
if "runtime_config" in json_object:
|
| 280 |
+
warnings.warn(
|
| 281 |
+
"The configuration file contains a `runtime_config` key. This is ignored. Runtime configurations are only valid at runtime."
|
| 282 |
+
)
|
| 283 |
+
del json_object["runtime_config"]
|
| 284 |
+
|
| 285 |
+
return json_object
|
| 286 |
+
|
| 287 |
+
@classmethod
|
| 288 |
+
def _split_kwargs(cls, kwargs):
|
| 289 |
+
hf_hub_download_kwargs = {}
|
| 290 |
+
class_kwargs = {}
|
| 291 |
+
other_kwargs = {}
|
| 292 |
+
|
| 293 |
+
for key, value in kwargs.items():
|
| 294 |
+
if key in inspect.signature(hf_hub_download).parameters:
|
| 295 |
+
hf_hub_download_kwargs[key] = value
|
| 296 |
+
elif key in list(cls.__annotations__):
|
| 297 |
+
class_kwargs[key] = value
|
| 298 |
+
else:
|
| 299 |
+
other_kwargs[key] = value
|
| 300 |
+
|
| 301 |
+
return hf_hub_download_kwargs, class_kwargs, other_kwargs
|
| 302 |
+
|
| 303 |
+
@classmethod
|
| 304 |
+
def _get_peft_type(
|
| 305 |
+
cls,
|
| 306 |
+
model_id: str,
|
| 307 |
+
**hf_hub_download_kwargs,
|
| 308 |
+
):
|
| 309 |
+
subfolder = hf_hub_download_kwargs.get("subfolder", None)
|
| 310 |
+
|
| 311 |
+
path = os.path.join(model_id, subfolder) if subfolder is not None else model_id
|
| 312 |
+
|
| 313 |
+
if os.path.isfile(os.path.join(path, CONFIG_NAME)):
|
| 314 |
+
config_file = os.path.join(path, CONFIG_NAME)
|
| 315 |
+
else:
|
| 316 |
+
try:
|
| 317 |
+
config_file = hf_hub_download(
|
| 318 |
+
model_id,
|
| 319 |
+
CONFIG_NAME,
|
| 320 |
+
**hf_hub_download_kwargs,
|
| 321 |
+
)
|
| 322 |
+
except Exception:
|
| 323 |
+
raise ValueError(f"Can't find '{CONFIG_NAME}' at '{model_id}'")
|
| 324 |
+
|
| 325 |
+
loaded_attributes = cls.from_json_file(config_file)
|
| 326 |
+
return loaded_attributes["peft_type"]
|
| 327 |
+
|
| 328 |
+
@classmethod
|
| 329 |
+
def check_kwargs(cls, **kwargs):
|
| 330 |
+
"""Check kwargs before initializing the config instance.
|
| 331 |
+
|
| 332 |
+
Subclasses can override this method to add specific checks.
|
| 333 |
+
|
| 334 |
+
"""
|
| 335 |
+
return kwargs
|
| 336 |
+
|
| 337 |
+
@property
|
| 338 |
+
def is_prompt_learning(self) -> bool:
|
| 339 |
+
r"""
|
| 340 |
+
Utility method to check if the configuration is for prompt learning.
|
| 341 |
+
"""
|
| 342 |
+
return False
|
| 343 |
+
|
| 344 |
+
@property
|
| 345 |
+
def is_adaption_prompt(self) -> bool:
|
| 346 |
+
"""Return True if this is an adaption prompt config."""
|
| 347 |
+
return False
|
| 348 |
+
|
| 349 |
+
|
| 350 |
+
@dataclass
|
| 351 |
+
class PeftConfig(PeftConfigMixin):
|
| 352 |
+
"""
|
| 353 |
+
This is the base configuration class to store the configuration of a [`PeftModel`].
|
| 354 |
+
|
| 355 |
+
Args:
|
| 356 |
+
peft_type (Union[[`~peft.utils.config.PeftType`], `str`]): The type of Peft method to use.
|
| 357 |
+
task_type (Union[[`~peft.utils.config.TaskType`], `str`]): The type of task to perform.
|
| 358 |
+
inference_mode (`bool`, defaults to `False`): Whether to use the Peft model in inference mode.
|
| 359 |
+
"""
|
| 360 |
+
|
| 361 |
+
base_model_name_or_path: Optional[str] = field(
|
| 362 |
+
default=None, metadata={"help": "The name of the base model to use."}
|
| 363 |
+
)
|
| 364 |
+
revision: Optional[str] = field(default=None, metadata={"help": "The specific base model version to use."})
|
| 365 |
+
peft_type: Optional[Union[str, PeftType]] = field(default=None, metadata={"help": "Peft type"})
|
| 366 |
+
task_type: Optional[Union[str, TaskType]] = field(default=None, metadata={"help": "Task type"})
|
| 367 |
+
inference_mode: bool = field(default=False, metadata={"help": "Whether to use inference mode"})
|
| 368 |
+
|
| 369 |
+
|
| 370 |
+
@dataclass
|
| 371 |
+
class PromptLearningConfig(PeftConfig):
|
| 372 |
+
"""
|
| 373 |
+
This is the base configuration class to store the configuration of [`PrefixTuning`], [`PromptEncoder`], or
|
| 374 |
+
[`PromptTuning`].
|
| 375 |
+
|
| 376 |
+
Args:
|
| 377 |
+
num_virtual_tokens (`int`): The number of virtual tokens to use.
|
| 378 |
+
token_dim (`int`): The hidden embedding dimension of the base transformer model.
|
| 379 |
+
num_transformer_submodules (`int`): The number of transformer submodules in the base transformer model.
|
| 380 |
+
num_attention_heads (`int`): The number of attention heads in the base transformer model.
|
| 381 |
+
num_layers (`int`): The number of layers in the base transformer model.
|
| 382 |
+
"""
|
| 383 |
+
|
| 384 |
+
num_virtual_tokens: int = field(default=None, metadata={"help": "Number of virtual tokens"})
|
| 385 |
+
token_dim: int = field(
|
| 386 |
+
default=None, metadata={"help": "The hidden embedding dimension of the base transformer model"}
|
| 387 |
+
)
|
| 388 |
+
num_transformer_submodules: Optional[int] = field(
|
| 389 |
+
default=None, metadata={"help": "Number of transformer submodules"}
|
| 390 |
+
)
|
| 391 |
+
num_attention_heads: Optional[int] = field(default=None, metadata={"help": "Number of attention heads"})
|
| 392 |
+
num_layers: Optional[int] = field(default=None, metadata={"help": "Number of transformer layers"})
|
| 393 |
+
modules_to_save: Optional[list[str]] = field(
|
| 394 |
+
default=None,
|
| 395 |
+
metadata={
|
| 396 |
+
"help": "List of extra modules to be set as trainable and saved in the final checkpoint. "
|
| 397 |
+
"For example, in Sequence Classification or Token Classification tasks, "
|
| 398 |
+
"the final layer `classifier/score` are randomly initialized and as such need to be trainable and saved. "
|
| 399 |
+
"The module(s) will be fully fine-tuned."
|
| 400 |
+
},
|
| 401 |
+
)
|
| 402 |
+
|
| 403 |
+
@property
|
| 404 |
+
def is_prompt_learning(self) -> bool:
|
| 405 |
+
r"""
|
| 406 |
+
Utility method to check if the configuration is for prompt learning.
|
| 407 |
+
"""
|
| 408 |
+
return True
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/peft/functional.py
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2025-present the HuggingFace Inc. team.
|
| 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 |
+
"""
|
| 15 |
+
Functions that are useful for integration with non-PeftModel models, e.g. transformers or diffusers.
|
| 16 |
+
|
| 17 |
+
The functions provided here can be considered "public API" of PEFT and hence are safe to be used by packages that
|
| 18 |
+
provide PEFT integrations.
|
| 19 |
+
"""
|
| 20 |
+
|
| 21 |
+
from peft.mapping import inject_adapter_in_model
|
| 22 |
+
from peft.tuners.tuners_utils import cast_adapter_dtype, delete_adapter, set_adapter, set_requires_grad
|
| 23 |
+
from peft.utils import get_peft_model_state_dict, set_peft_model_state_dict
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
__all__ = [
|
| 27 |
+
"cast_adapter_dtype",
|
| 28 |
+
"delete_adapter",
|
| 29 |
+
"get_peft_model_state_dict",
|
| 30 |
+
"inject_adapter_in_model",
|
| 31 |
+
"set_adapter",
|
| 32 |
+
"set_peft_model_state_dict",
|
| 33 |
+
"set_requires_grad",
|
| 34 |
+
]
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/peft/helpers.py
ADDED
|
@@ -0,0 +1,251 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2023-present the HuggingFace Inc. team.
|
| 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 |
+
|
| 15 |
+
import inspect
|
| 16 |
+
from contextlib import contextmanager
|
| 17 |
+
from copy import deepcopy
|
| 18 |
+
from functools import update_wrapper
|
| 19 |
+
from types import MethodType
|
| 20 |
+
|
| 21 |
+
from torch import nn
|
| 22 |
+
|
| 23 |
+
from .peft_model import PeftConfig, PeftModel
|
| 24 |
+
from .tuners.lora import LoraLayer
|
| 25 |
+
from .tuners.tuners_utils import BaseTunerLayer
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
def update_forward_signature(model: PeftModel) -> None:
|
| 29 |
+
"""
|
| 30 |
+
Updates the forward signature of the PeftModel to include parents class signature
|
| 31 |
+
model (`PeftModel`): Peft model to update the forward signature
|
| 32 |
+
|
| 33 |
+
Example:
|
| 34 |
+
|
| 35 |
+
```python
|
| 36 |
+
>>> from transformers import WhisperForConditionalGeneration
|
| 37 |
+
>>> from peft import get_peft_model, LoraConfig, update_forward_signature
|
| 38 |
+
|
| 39 |
+
>>> model = WhisperForConditionalGeneration.from_pretrained("openai/whisper-tiny.en")
|
| 40 |
+
>>> peft_config = LoraConfig(r=8, lora_alpha=32, lora_dropout=0.1, target_modules=["q_proj", "v_proj"])
|
| 41 |
+
|
| 42 |
+
>>> peft_model = get_peft_model(model, peft_config)
|
| 43 |
+
>>> update_forward_signature(peft_model)
|
| 44 |
+
```
|
| 45 |
+
"""
|
| 46 |
+
|
| 47 |
+
# Only update signature when the current forward signature only has *args and **kwargs
|
| 48 |
+
current_signature = inspect.signature(model.forward)
|
| 49 |
+
if (
|
| 50 |
+
len(current_signature.parameters) == 2
|
| 51 |
+
and "args" in current_signature.parameters
|
| 52 |
+
and "kwargs" in current_signature.parameters
|
| 53 |
+
):
|
| 54 |
+
forward = deepcopy(model.forward.__func__)
|
| 55 |
+
update_wrapper(
|
| 56 |
+
forward, type(model.get_base_model()).forward, assigned=("__doc__", "__name__", "__annotations__")
|
| 57 |
+
)
|
| 58 |
+
model.forward = MethodType(forward, model)
|
| 59 |
+
|
| 60 |
+
|
| 61 |
+
def update_generate_signature(model: PeftModel) -> None:
|
| 62 |
+
"""
|
| 63 |
+
Updates the generate signature of a PeftModel with overriding generate to include parents class signature
|
| 64 |
+
model (`PeftModel`): Peft model to update the generate signature
|
| 65 |
+
|
| 66 |
+
Example:
|
| 67 |
+
|
| 68 |
+
```python
|
| 69 |
+
>>> from transformers import AutoModelForSeq2SeqLM, AutoTokenizer
|
| 70 |
+
>>> from peft import get_peft_model, LoraConfig, TaskType, update_generate_signature
|
| 71 |
+
|
| 72 |
+
>>> model_name_or_path = "bigscience/mt0-large"
|
| 73 |
+
>>> tokenizer = AutoTokenizer.from_pretrained(model_name_or_path)
|
| 74 |
+
>>> model = AutoModelForSeq2SeqLM.from_pretrained(model_name_or_path)
|
| 75 |
+
|
| 76 |
+
>>> peft_config = LoraConfig(
|
| 77 |
+
... task_type=TaskType.SEQ_2_SEQ_LM, inference_mode=False, r=8, lora_alpha=32, lora_dropout=0.1
|
| 78 |
+
... )
|
| 79 |
+
>>> peft_model = get_peft_model(model, peft_config)
|
| 80 |
+
>>> update_generate_signature(peft_model)
|
| 81 |
+
>>> help(peft_model.generate)
|
| 82 |
+
```
|
| 83 |
+
"""
|
| 84 |
+
if not hasattr(model, "generate"):
|
| 85 |
+
return
|
| 86 |
+
current_signature = inspect.signature(model.generate)
|
| 87 |
+
if (
|
| 88 |
+
len(current_signature.parameters) == 2
|
| 89 |
+
and "args" in current_signature.parameters
|
| 90 |
+
and "kwargs" in current_signature.parameters
|
| 91 |
+
) or (len(current_signature.parameters) == 1 and "kwargs" in current_signature.parameters):
|
| 92 |
+
generate = deepcopy(model.generate.__func__)
|
| 93 |
+
update_wrapper(
|
| 94 |
+
generate,
|
| 95 |
+
type(model.get_base_model()).generate,
|
| 96 |
+
assigned=("__doc__", "__name__", "__annotations__"),
|
| 97 |
+
)
|
| 98 |
+
model.generate = MethodType(generate, model)
|
| 99 |
+
|
| 100 |
+
|
| 101 |
+
def update_signature(model: PeftModel, method: str = "all") -> None:
|
| 102 |
+
"""
|
| 103 |
+
Updates the signature of a PeftModel include parents class signature for forward or generate method
|
| 104 |
+
model (`PeftModel`): Peft model to update generate or forward signature method (`str`): method to update
|
| 105 |
+
signature choose one of "forward", "generate", "all"
|
| 106 |
+
|
| 107 |
+
Example:
|
| 108 |
+
```python
|
| 109 |
+
>>> from transformers import AutoModelForSeq2SeqLM, AutoTokenizer
|
| 110 |
+
>>> from peft import get_peft_model, LoraConfig, TaskType, update_signature
|
| 111 |
+
|
| 112 |
+
>>> model_name_or_path = "bigscience/mt0-large"
|
| 113 |
+
>>> tokenizer = AutoTokenizer.from_pretrained(model_name_or_path)
|
| 114 |
+
>>> model = AutoModelForSeq2SeqLM.from_pretrained(model_name_or_path)
|
| 115 |
+
|
| 116 |
+
>>> peft_config = LoraConfig(
|
| 117 |
+
... task_type=TaskType.SEQ_2_SEQ_LM, inference_mode=False, r=8, lora_alpha=32, lora_dropout=0.1
|
| 118 |
+
... )
|
| 119 |
+
>>> peft_model = get_peft_model(model, peft_config)
|
| 120 |
+
>>> update_signature(peft_model)
|
| 121 |
+
>>> help(peft_model.generate)
|
| 122 |
+
```
|
| 123 |
+
"""
|
| 124 |
+
if method == "forward":
|
| 125 |
+
update_forward_signature(model)
|
| 126 |
+
elif method == "generate":
|
| 127 |
+
update_generate_signature(model)
|
| 128 |
+
elif method == "all":
|
| 129 |
+
update_forward_signature(model)
|
| 130 |
+
update_generate_signature(model)
|
| 131 |
+
else:
|
| 132 |
+
raise ValueError(f"method {method} is not supported please choose one of ['forward', 'generate', 'all']")
|
| 133 |
+
|
| 134 |
+
|
| 135 |
+
def check_if_peft_model(model_name_or_path: str) -> bool:
|
| 136 |
+
"""
|
| 137 |
+
Check if the model is a PEFT model.
|
| 138 |
+
|
| 139 |
+
Args:
|
| 140 |
+
model_name_or_path (`str`):
|
| 141 |
+
Model id to check, can be local or on the Hugging Face Hub.
|
| 142 |
+
|
| 143 |
+
Returns:
|
| 144 |
+
`bool`: True if the model is a PEFT model, False otherwise.
|
| 145 |
+
"""
|
| 146 |
+
is_peft_model = True
|
| 147 |
+
try:
|
| 148 |
+
PeftConfig.from_pretrained(model_name_or_path)
|
| 149 |
+
except Exception:
|
| 150 |
+
# allow broad exceptions so that this works even if new exceptions are added on HF Hub side
|
| 151 |
+
is_peft_model = False
|
| 152 |
+
|
| 153 |
+
return is_peft_model
|
| 154 |
+
|
| 155 |
+
|
| 156 |
+
@contextmanager
|
| 157 |
+
def rescale_adapter_scale(model, multiplier):
|
| 158 |
+
"""
|
| 159 |
+
Context manager to temporarily rescale the scaling of the LoRA adapter in a model.
|
| 160 |
+
|
| 161 |
+
The original scaling values are restored when the context manager exits. This context manager works with the
|
| 162 |
+
transformers and diffusers models that have directly loaded LoRA adapters.
|
| 163 |
+
|
| 164 |
+
For LoRA, applying this context manager with multiplier in [0, 1] is strictly equivalent to applying
|
| 165 |
+
[wise-ft](https://huggingface.co/papers/2109.01903) (see [#1940](https://github.com/huggingface/peft/issues/1940)
|
| 166 |
+
for details). It can improve the performances of the model if there is a distribution shiftbetween the training
|
| 167 |
+
data used for fine-tuning, and the test data used during inference.
|
| 168 |
+
|
| 169 |
+
Warning: It has been reported that when using Apple's MPS backend for PyTorch, it is necessary to add a short sleep
|
| 170 |
+
time after exiting the context before the scales are fully restored.
|
| 171 |
+
|
| 172 |
+
Args:
|
| 173 |
+
model: The model containing `LoraLayer` modules whose scaling is to be adjusted.
|
| 174 |
+
multiplier (float or int):
|
| 175 |
+
The multiplier that rescales the `scaling` attribute. Must be of type float or int.
|
| 176 |
+
|
| 177 |
+
Raises:
|
| 178 |
+
ValueError: If the model does not contain any `LoraLayer`
|
| 179 |
+
instances, indicating that the model does not support scaling.
|
| 180 |
+
|
| 181 |
+
Example:
|
| 182 |
+
|
| 183 |
+
```python
|
| 184 |
+
>>> model = ModelWithLoraLayer()
|
| 185 |
+
>>> multiplier = 0.5
|
| 186 |
+
>>> with rescale_adapter_scale(model, multiplier):
|
| 187 |
+
... outputs = model(**inputs) # Perform operations with the scaled model
|
| 188 |
+
>>> outputs = model(**inputs) # The original scaling values are restored here
|
| 189 |
+
```
|
| 190 |
+
"""
|
| 191 |
+
# check if multiplier has a valid data type
|
| 192 |
+
if not isinstance(multiplier, (float, int)):
|
| 193 |
+
raise TypeError(f"Argument multiplier should be of type float, got {type(multiplier)}")
|
| 194 |
+
|
| 195 |
+
# iterate on the model's modules and grab the original scaling attribute
|
| 196 |
+
# from the lora layers if present
|
| 197 |
+
original_scaling = {}
|
| 198 |
+
for module in model.modules():
|
| 199 |
+
if isinstance(module, LoraLayer):
|
| 200 |
+
original_scaling[module] = module.scaling.copy()
|
| 201 |
+
module.scaling = {k: v * multiplier for k, v in module.scaling.items()}
|
| 202 |
+
|
| 203 |
+
# check whether scaling is prohibited on model
|
| 204 |
+
# the original scaling dictionary should be empty
|
| 205 |
+
# if there were no lora layers
|
| 206 |
+
if not original_scaling:
|
| 207 |
+
raise ValueError("scaling is only supported for models with `LoraLayer`s")
|
| 208 |
+
try:
|
| 209 |
+
yield
|
| 210 |
+
|
| 211 |
+
finally:
|
| 212 |
+
# restore original scaling values after exiting the context
|
| 213 |
+
for module, scaling in original_scaling.items():
|
| 214 |
+
module.scaling = scaling
|
| 215 |
+
|
| 216 |
+
|
| 217 |
+
@contextmanager
|
| 218 |
+
def disable_input_dtype_casting(model: nn.Module, active: bool = True):
|
| 219 |
+
"""
|
| 220 |
+
Context manager disables input dtype casting to the dtype of the weight.
|
| 221 |
+
|
| 222 |
+
Parameters:
|
| 223 |
+
model (nn.Module):
|
| 224 |
+
The model containing PEFT modules whose input dtype casting is to be adjusted.
|
| 225 |
+
active (bool):
|
| 226 |
+
Whether the context manager is active (default) or inactive.
|
| 227 |
+
|
| 228 |
+
"""
|
| 229 |
+
# Additional info: Normally, the dtype of the weight and input need to match, which is why the dtype is cast.
|
| 230 |
+
# However, in certain circumustances, this is handled by forward hooks, e.g. when using layerwise casting in
|
| 231 |
+
# diffusers. In that case, PEFT casting the dtype interferes with the layerwise casting, which is why the option to
|
| 232 |
+
# disable it is given.
|
| 233 |
+
if not active:
|
| 234 |
+
yield
|
| 235 |
+
return
|
| 236 |
+
|
| 237 |
+
original_values = {}
|
| 238 |
+
for name, module in model.named_modules():
|
| 239 |
+
if not isinstance(module, BaseTunerLayer):
|
| 240 |
+
continue
|
| 241 |
+
original_values[name] = module.cast_input_dtype_enabled
|
| 242 |
+
module.cast_input_dtype_enabled = False
|
| 243 |
+
|
| 244 |
+
try:
|
| 245 |
+
yield
|
| 246 |
+
finally:
|
| 247 |
+
for name, module in model.named_modules():
|
| 248 |
+
if not isinstance(module, BaseTunerLayer):
|
| 249 |
+
continue
|
| 250 |
+
if name in original_values:
|
| 251 |
+
module.cast_input_dtype_enabled = original_values[name]
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/peft/import_utils.py
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2023-present the HuggingFace Inc. team.
|
| 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 |
+
import importlib
|
| 15 |
+
import importlib.metadata as importlib_metadata
|
| 16 |
+
import platform
|
| 17 |
+
from functools import lru_cache
|
| 18 |
+
|
| 19 |
+
import packaging.version
|
| 20 |
+
import torch
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
@lru_cache
|
| 24 |
+
def is_bnb_available() -> bool:
|
| 25 |
+
return importlib.util.find_spec("bitsandbytes") is not None
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
@lru_cache
|
| 29 |
+
def is_bnb_4bit_available() -> bool:
|
| 30 |
+
if not is_bnb_available():
|
| 31 |
+
return False
|
| 32 |
+
|
| 33 |
+
import bitsandbytes as bnb
|
| 34 |
+
|
| 35 |
+
return hasattr(bnb.nn, "Linear4bit")
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
@lru_cache
|
| 39 |
+
def is_auto_gptq_available():
|
| 40 |
+
if importlib.util.find_spec("auto_gptq") is not None:
|
| 41 |
+
AUTOGPTQ_MINIMUM_VERSION = packaging.version.parse("0.5.0")
|
| 42 |
+
version_autogptq = packaging.version.parse(importlib_metadata.version("auto_gptq"))
|
| 43 |
+
if AUTOGPTQ_MINIMUM_VERSION <= version_autogptq:
|
| 44 |
+
return True
|
| 45 |
+
else:
|
| 46 |
+
raise ImportError(
|
| 47 |
+
f"Found an incompatible version of auto-gptq. Found version {version_autogptq}, "
|
| 48 |
+
f"but only versions above {AUTOGPTQ_MINIMUM_VERSION} are supported"
|
| 49 |
+
)
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
@lru_cache
|
| 53 |
+
def is_gptqmodel_available():
|
| 54 |
+
if importlib.util.find_spec("gptqmodel") is not None:
|
| 55 |
+
GPTQMODEL_MINIMUM_VERSION = packaging.version.parse("2.0.0")
|
| 56 |
+
OPTIMUM_MINIMUM_VERSION = packaging.version.parse("1.24.0")
|
| 57 |
+
version_gptqmodel = packaging.version.parse(importlib_metadata.version("gptqmodel"))
|
| 58 |
+
if GPTQMODEL_MINIMUM_VERSION <= version_gptqmodel:
|
| 59 |
+
if is_optimum_available():
|
| 60 |
+
version_optimum = packaging.version.parse(importlib_metadata.version("optimum"))
|
| 61 |
+
if OPTIMUM_MINIMUM_VERSION <= version_optimum:
|
| 62 |
+
return True
|
| 63 |
+
else:
|
| 64 |
+
raise ImportError(
|
| 65 |
+
f"gptqmodel requires optimum version `{OPTIMUM_MINIMUM_VERSION}` or higher. Found version `{version_optimum}`, "
|
| 66 |
+
f"but only versions above `{OPTIMUM_MINIMUM_VERSION}` are supported"
|
| 67 |
+
)
|
| 68 |
+
else:
|
| 69 |
+
raise ImportError(
|
| 70 |
+
f"gptqmodel requires optimum version `{OPTIMUM_MINIMUM_VERSION}` or higher to be installed."
|
| 71 |
+
)
|
| 72 |
+
else:
|
| 73 |
+
raise ImportError(
|
| 74 |
+
f"Found an incompatible version of gptqmodel. Found version `{version_gptqmodel}`, "
|
| 75 |
+
f"but only versions above `{GPTQMODEL_MINIMUM_VERSION}` are supported"
|
| 76 |
+
)
|
| 77 |
+
|
| 78 |
+
|
| 79 |
+
@lru_cache
|
| 80 |
+
def is_optimum_available() -> bool:
|
| 81 |
+
return importlib.util.find_spec("optimum") is not None
|
| 82 |
+
|
| 83 |
+
|
| 84 |
+
@lru_cache
|
| 85 |
+
def is_torch_tpu_available(check_device=True):
|
| 86 |
+
"Checks if `torch_xla` is installed and potentially if a TPU is in the environment"
|
| 87 |
+
if importlib.util.find_spec("torch_xla") is not None:
|
| 88 |
+
if check_device:
|
| 89 |
+
# We need to check if `xla_device` can be found, will raise a RuntimeError if not
|
| 90 |
+
try:
|
| 91 |
+
import torch_xla.core.xla_model as xm
|
| 92 |
+
|
| 93 |
+
_ = xm.xla_device()
|
| 94 |
+
return True
|
| 95 |
+
except RuntimeError:
|
| 96 |
+
return False
|
| 97 |
+
return True
|
| 98 |
+
return False
|
| 99 |
+
|
| 100 |
+
|
| 101 |
+
@lru_cache
|
| 102 |
+
def is_aqlm_available():
|
| 103 |
+
return importlib.util.find_spec("aqlm") is not None
|
| 104 |
+
|
| 105 |
+
|
| 106 |
+
@lru_cache
|
| 107 |
+
def is_auto_awq_available():
|
| 108 |
+
return importlib.util.find_spec("awq") is not None
|
| 109 |
+
|
| 110 |
+
|
| 111 |
+
@lru_cache
|
| 112 |
+
def is_eetq_available():
|
| 113 |
+
return importlib.util.find_spec("eetq") is not None
|
| 114 |
+
|
| 115 |
+
|
| 116 |
+
@lru_cache
|
| 117 |
+
def is_hqq_available():
|
| 118 |
+
return importlib.util.find_spec("hqq") is not None
|
| 119 |
+
|
| 120 |
+
|
| 121 |
+
@lru_cache
|
| 122 |
+
def is_inc_available():
|
| 123 |
+
return importlib.util.find_spec("neural_compressor") is not None
|
| 124 |
+
|
| 125 |
+
|
| 126 |
+
@lru_cache
|
| 127 |
+
def is_torchao_available():
|
| 128 |
+
if importlib.util.find_spec("torchao") is None:
|
| 129 |
+
return False
|
| 130 |
+
|
| 131 |
+
TORCHAO_MINIMUM_VERSION = packaging.version.parse("0.4.0")
|
| 132 |
+
try:
|
| 133 |
+
torchao_version = packaging.version.parse(importlib_metadata.version("torchao"))
|
| 134 |
+
except importlib_metadata.PackageNotFoundError:
|
| 135 |
+
# Same idea as in diffusers:
|
| 136 |
+
# https://github.com/huggingface/diffusers/blob/9f06a0d1a4a998ac6a463c5be728c892f95320a8/src/diffusers/utils/import_utils.py#L351-L357
|
| 137 |
+
# It's not clear under what circumstances `importlib_metadata.version("torchao")` can raise an error even
|
| 138 |
+
# though `importlib.util.find_spec("torchao") is not None` but it has been observed, so adding this for
|
| 139 |
+
# precaution.
|
| 140 |
+
return False
|
| 141 |
+
|
| 142 |
+
if torchao_version < TORCHAO_MINIMUM_VERSION:
|
| 143 |
+
raise ImportError(
|
| 144 |
+
f"Found an incompatible version of torchao. Found version {torchao_version}, "
|
| 145 |
+
f"but only versions above {TORCHAO_MINIMUM_VERSION} are supported"
|
| 146 |
+
)
|
| 147 |
+
return True
|
| 148 |
+
|
| 149 |
+
|
| 150 |
+
@lru_cache
|
| 151 |
+
def is_xpu_available(check_device=False):
|
| 152 |
+
"""
|
| 153 |
+
Checks if XPU acceleration is available and potentially if a XPU is in the environment
|
| 154 |
+
"""
|
| 155 |
+
|
| 156 |
+
system = platform.system()
|
| 157 |
+
if system == "Darwin":
|
| 158 |
+
return False
|
| 159 |
+
else:
|
| 160 |
+
if check_device:
|
| 161 |
+
try:
|
| 162 |
+
# Will raise a RuntimeError if no XPU is found
|
| 163 |
+
_ = torch.xpu.device_count()
|
| 164 |
+
return torch.xpu.is_available()
|
| 165 |
+
except RuntimeError:
|
| 166 |
+
return False
|
| 167 |
+
return hasattr(torch, "xpu") and torch.xpu.is_available()
|
| 168 |
+
|
| 169 |
+
|
| 170 |
+
@lru_cache
|
| 171 |
+
def is_diffusers_available():
|
| 172 |
+
return importlib.util.find_spec("diffusers") is not None
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/peft/mapping.py
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2023-present the HuggingFace Inc. team.
|
| 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 |
+
|
| 15 |
+
from __future__ import annotations
|
| 16 |
+
|
| 17 |
+
from typing import TYPE_CHECKING, Any, Optional
|
| 18 |
+
|
| 19 |
+
import torch
|
| 20 |
+
|
| 21 |
+
from .utils import PeftType
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
if TYPE_CHECKING:
|
| 25 |
+
from .config import PeftConfig
|
| 26 |
+
from .tuners.tuners_utils import BaseTuner
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
# these will be filled by the register_peft_method function
|
| 30 |
+
PEFT_TYPE_TO_CONFIG_MAPPING: dict[PeftType, type[PeftConfig]] = {}
|
| 31 |
+
PEFT_TYPE_TO_TUNER_MAPPING: dict[PeftType, type[BaseTuner]] = {}
|
| 32 |
+
PEFT_TYPE_TO_MIXED_MODEL_MAPPING: dict[PeftType, type[BaseTuner]] = {}
|
| 33 |
+
PEFT_TYPE_TO_PREFIX_MAPPING: dict[PeftType, str] = {}
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
def get_peft_config(config_dict: dict[str, Any]) -> PeftConfig:
|
| 37 |
+
"""
|
| 38 |
+
Returns a Peft config object from a dictionary.
|
| 39 |
+
|
| 40 |
+
Args:
|
| 41 |
+
config_dict (`Dict[str, Any]`): Dictionary containing the configuration parameters.
|
| 42 |
+
"""
|
| 43 |
+
|
| 44 |
+
return PEFT_TYPE_TO_CONFIG_MAPPING[config_dict["peft_type"]](**config_dict)
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
def inject_adapter_in_model(
|
| 48 |
+
peft_config: PeftConfig,
|
| 49 |
+
model: torch.nn.Module,
|
| 50 |
+
adapter_name: str = "default",
|
| 51 |
+
low_cpu_mem_usage: bool = False,
|
| 52 |
+
state_dict: Optional[dict[str, torch.Tensor]] = None,
|
| 53 |
+
) -> torch.nn.Module:
|
| 54 |
+
r"""
|
| 55 |
+
Create PEFT layers and inject them into the model in-place.
|
| 56 |
+
|
| 57 |
+
Currently the API does not support prompt learning methods and adaption prompt.
|
| 58 |
+
|
| 59 |
+
This function is similar to [`get_peft_model`] but it does not return a [`PeftModel`] instance. Instead, it returns
|
| 60 |
+
the original, mutated instance of the passed model.
|
| 61 |
+
|
| 62 |
+
Args:
|
| 63 |
+
peft_config (`PeftConfig`):
|
| 64 |
+
Configuration object containing the parameters of the PEFT model.
|
| 65 |
+
model (`torch.nn.Module`):
|
| 66 |
+
The input model where the adapter will be injected.
|
| 67 |
+
adapter_name (`str`, `optional`, defaults to `"default"`):
|
| 68 |
+
The name of the adapter to be injected, if not provided, the default adapter name is used ("default").
|
| 69 |
+
low_cpu_mem_usage (`bool`, `optional`, defaults to `False`):
|
| 70 |
+
Create empty adapter weights on meta device. Useful to speed up the loading process.
|
| 71 |
+
state_dict (`dict`, *optional*, defaults to `None`)
|
| 72 |
+
If a `state_dict` is passed here, the adapters will be injected based on the entries of the state_dict.
|
| 73 |
+
This can be useful when the exact `target_modules` of the PEFT method is unknown, for instance because the
|
| 74 |
+
checkpoint was created without meta data. Note that the values from the `state_dict` are not used, only the
|
| 75 |
+
keys are used to determine the correct layers that should be adapted.
|
| 76 |
+
"""
|
| 77 |
+
if peft_config.is_prompt_learning or peft_config.is_adaption_prompt:
|
| 78 |
+
raise ValueError("`create_and_replace` does not support prompt learning and adaption prompt yet.")
|
| 79 |
+
|
| 80 |
+
if peft_config.peft_type not in PEFT_TYPE_TO_TUNER_MAPPING.keys():
|
| 81 |
+
raise ValueError(
|
| 82 |
+
f"`inject_adapter_in_model` does not support {peft_config.peft_type} yet. Please use `get_peft_model`."
|
| 83 |
+
)
|
| 84 |
+
|
| 85 |
+
tuner_cls = PEFT_TYPE_TO_TUNER_MAPPING[peft_config.peft_type]
|
| 86 |
+
|
| 87 |
+
# By instantiating a peft model we are injecting randomly initialized LoRA layers into the model's modules.
|
| 88 |
+
peft_model = tuner_cls(
|
| 89 |
+
model, peft_config, adapter_name=adapter_name, low_cpu_mem_usage=low_cpu_mem_usage, state_dict=state_dict
|
| 90 |
+
)
|
| 91 |
+
|
| 92 |
+
return peft_model.model
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/peft/mapping_func.py
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024-present the HuggingFace Inc. team.
|
| 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 |
+
|
| 15 |
+
from __future__ import annotations
|
| 16 |
+
|
| 17 |
+
import warnings
|
| 18 |
+
from typing import Optional
|
| 19 |
+
|
| 20 |
+
from transformers import PreTrainedModel
|
| 21 |
+
|
| 22 |
+
from .auto import MODEL_TYPE_TO_PEFT_MODEL_MAPPING
|
| 23 |
+
from .config import PeftConfig
|
| 24 |
+
from .mapping import PEFT_TYPE_TO_CONFIG_MAPPING, PEFT_TYPE_TO_PREFIX_MAPPING
|
| 25 |
+
from .mixed_model import PeftMixedModel
|
| 26 |
+
from .peft_model import PeftModel
|
| 27 |
+
from .tuners.tuners_utils import BaseTuner, BaseTunerLayer
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
def get_peft_model(
|
| 31 |
+
model: PreTrainedModel,
|
| 32 |
+
peft_config: PeftConfig,
|
| 33 |
+
adapter_name: str = "default",
|
| 34 |
+
mixed: bool = False,
|
| 35 |
+
autocast_adapter_dtype: bool = True,
|
| 36 |
+
revision: Optional[str] = None,
|
| 37 |
+
low_cpu_mem_usage: bool = False,
|
| 38 |
+
) -> PeftModel | PeftMixedModel:
|
| 39 |
+
"""
|
| 40 |
+
Returns a Peft model object from a model and a config, where the model will be modified in-place.
|
| 41 |
+
|
| 42 |
+
Args:
|
| 43 |
+
model ([`transformers.PreTrainedModel`]):
|
| 44 |
+
Model to be wrapped.
|
| 45 |
+
peft_config ([`PeftConfig`]):
|
| 46 |
+
Configuration object containing the parameters of the Peft model.
|
| 47 |
+
adapter_name (`str`, `optional`, defaults to `"default"`):
|
| 48 |
+
The name of the adapter to be injected, if not provided, the default adapter name is used ("default").
|
| 49 |
+
mixed (`bool`, `optional`, defaults to `False`):
|
| 50 |
+
Whether to allow mixing different (compatible) adapter types.
|
| 51 |
+
autocast_adapter_dtype (`bool`, *optional*):
|
| 52 |
+
Whether to autocast the adapter dtype. Defaults to `True`. Right now, this will only cast adapter weights
|
| 53 |
+
using float16 or bfloat16 to float32, as this is typically required for stable training, and only affect
|
| 54 |
+
select PEFT tuners.
|
| 55 |
+
revision (`str`, `optional`, defaults to `main`):
|
| 56 |
+
The revision of the base model. If this isn't set, the saved peft model will load the `main` revision for
|
| 57 |
+
the base model
|
| 58 |
+
low_cpu_mem_usage (`bool`, `optional`, defaults to `False`):
|
| 59 |
+
Create empty adapter weights on meta device. Useful to speed up the loading process. Leave this setting as
|
| 60 |
+
False if you intend on training the model, unless the adapter weights will be replaced by different weights
|
| 61 |
+
before training starts.
|
| 62 |
+
"""
|
| 63 |
+
model_config = BaseTuner.get_model_config(model)
|
| 64 |
+
old_name = peft_config.base_model_name_or_path
|
| 65 |
+
new_name = model.__dict__.get("name_or_path", None)
|
| 66 |
+
peft_config.base_model_name_or_path = new_name
|
| 67 |
+
|
| 68 |
+
# Especially in notebook environments there could be a case that a user wants to experiment with different
|
| 69 |
+
# configuration values. However, it is likely that there won't be any changes for new configs on an already
|
| 70 |
+
# initialized PEFT model. The best we can do is warn the user about it.
|
| 71 |
+
if any(isinstance(module, BaseTunerLayer) for module in model.modules()):
|
| 72 |
+
warnings.warn(
|
| 73 |
+
"You are trying to modify a model with PEFT for a second time. If you want to reload the model with a "
|
| 74 |
+
"different config, make sure to call `.unload()` before."
|
| 75 |
+
)
|
| 76 |
+
|
| 77 |
+
if (old_name is not None) and (old_name != new_name):
|
| 78 |
+
warnings.warn(
|
| 79 |
+
f"The PEFT config's `base_model_name_or_path` was renamed from '{old_name}' to '{new_name}'. "
|
| 80 |
+
"Please ensure that the correct base model is loaded when loading this checkpoint."
|
| 81 |
+
)
|
| 82 |
+
|
| 83 |
+
if revision is not None:
|
| 84 |
+
if peft_config.revision is not None and peft_config.revision != revision:
|
| 85 |
+
warnings.warn(
|
| 86 |
+
f"peft config has already set base model revision to {peft_config.revision}, overwriting with revision {revision}"
|
| 87 |
+
)
|
| 88 |
+
peft_config.revision = revision
|
| 89 |
+
|
| 90 |
+
if (
|
| 91 |
+
(isinstance(peft_config, PEFT_TYPE_TO_CONFIG_MAPPING["LORA"]))
|
| 92 |
+
and (peft_config.init_lora_weights == "eva")
|
| 93 |
+
and not low_cpu_mem_usage
|
| 94 |
+
):
|
| 95 |
+
warnings.warn(
|
| 96 |
+
"lora with eva initialization used with low_cpu_mem_usage=False. "
|
| 97 |
+
"Setting low_cpu_mem_usage=True can improve the maximum batch size possible for eva initialization."
|
| 98 |
+
)
|
| 99 |
+
|
| 100 |
+
prefix = PEFT_TYPE_TO_PREFIX_MAPPING.get(peft_config.peft_type)
|
| 101 |
+
if prefix and adapter_name in prefix:
|
| 102 |
+
warnings.warn(
|
| 103 |
+
f"Adapter name '{adapter_name}' should not be contained in the prefix '{prefix}'. "
|
| 104 |
+
"This may lead to reinitialization of the adapter weights during loading."
|
| 105 |
+
)
|
| 106 |
+
|
| 107 |
+
if mixed:
|
| 108 |
+
# note: PeftMixedModel does not support autocast_adapter_dtype, so don't pass it
|
| 109 |
+
return PeftMixedModel(model, peft_config, adapter_name=adapter_name)
|
| 110 |
+
|
| 111 |
+
# We explicitly exclude prompt learning here since prompt learning is specific to the task and needs special
|
| 112 |
+
# handling in the PEFT model's forward method.
|
| 113 |
+
if peft_config.task_type not in MODEL_TYPE_TO_PEFT_MODEL_MAPPING.keys() and not peft_config.is_prompt_learning:
|
| 114 |
+
return PeftModel(
|
| 115 |
+
model,
|
| 116 |
+
peft_config,
|
| 117 |
+
adapter_name=adapter_name,
|
| 118 |
+
autocast_adapter_dtype=autocast_adapter_dtype,
|
| 119 |
+
low_cpu_mem_usage=low_cpu_mem_usage,
|
| 120 |
+
)
|
| 121 |
+
|
| 122 |
+
return MODEL_TYPE_TO_PEFT_MODEL_MAPPING[peft_config.task_type](
|
| 123 |
+
model,
|
| 124 |
+
peft_config,
|
| 125 |
+
adapter_name=adapter_name,
|
| 126 |
+
autocast_adapter_dtype=autocast_adapter_dtype,
|
| 127 |
+
low_cpu_mem_usage=low_cpu_mem_usage,
|
| 128 |
+
)
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/peft/mixed_model.py
ADDED
|
@@ -0,0 +1,460 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2023-present the HuggingFace Inc. team.
|
| 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 |
+
|
| 15 |
+
from __future__ import annotations
|
| 16 |
+
|
| 17 |
+
import os
|
| 18 |
+
from contextlib import contextmanager
|
| 19 |
+
from typing import Any, Optional, Union
|
| 20 |
+
|
| 21 |
+
import torch
|
| 22 |
+
from accelerate.hooks import remove_hook_from_submodules
|
| 23 |
+
from torch import nn
|
| 24 |
+
from transformers.utils import PushToHubMixin
|
| 25 |
+
|
| 26 |
+
from peft.utils.constants import DUMMY_MODEL_CONFIG
|
| 27 |
+
|
| 28 |
+
from .config import PeftConfig
|
| 29 |
+
from .peft_model import PeftModel
|
| 30 |
+
from .tuners import MixedModel
|
| 31 |
+
from .utils import _set_adapter, _set_trainable
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
def _prepare_model_for_gradient_checkpointing(model: nn.Module) -> None:
|
| 35 |
+
r"""
|
| 36 |
+
Prepares the model for gradient checkpointing if necessary
|
| 37 |
+
"""
|
| 38 |
+
# Note: same as PeftModel._prepare_model_for_gradient_checkpointing
|
| 39 |
+
if not getattr(model, "is_gradient_checkpointing", True):
|
| 40 |
+
return model
|
| 41 |
+
|
| 42 |
+
if not (
|
| 43 |
+
getattr(model, "is_loaded_in_8bit", False)
|
| 44 |
+
or getattr(model, "is_loaded_in_4bit", False)
|
| 45 |
+
or getattr(model, "is_quantized", False)
|
| 46 |
+
):
|
| 47 |
+
if hasattr(model, "enable_input_require_grads"):
|
| 48 |
+
model.enable_input_require_grads()
|
| 49 |
+
elif hasattr(model, "get_input_embeddings"):
|
| 50 |
+
|
| 51 |
+
def make_inputs_require_grad(module, input, output):
|
| 52 |
+
output.requires_grad_(True)
|
| 53 |
+
|
| 54 |
+
model.get_input_embeddings().register_forward_hook(make_inputs_require_grad)
|
| 55 |
+
|
| 56 |
+
|
| 57 |
+
def _check_config_compatible(peft_config: PeftConfig) -> None:
|
| 58 |
+
from .tuners.mixed import COMPATIBLE_TUNER_TYPES
|
| 59 |
+
|
| 60 |
+
if peft_config.peft_type not in COMPATIBLE_TUNER_TYPES:
|
| 61 |
+
raise ValueError(
|
| 62 |
+
f"The provided `peft_type` '{peft_config.peft_type.value}' is not compatible with the `PeftMixedModel`. "
|
| 63 |
+
f"Compatible types are: {COMPATIBLE_TUNER_TYPES}"
|
| 64 |
+
)
|
| 65 |
+
|
| 66 |
+
|
| 67 |
+
class PeftMixedModel(PushToHubMixin, torch.nn.Module):
|
| 68 |
+
"""
|
| 69 |
+
PeftMixedModel for loading mixing different types of adapters for inference.
|
| 70 |
+
|
| 71 |
+
This class does not support loading/saving, and it shouldn't usually be initialized directly. Instead, use
|
| 72 |
+
`get_peft_model` with the argument `mixed=True`.
|
| 73 |
+
|
| 74 |
+
> [!TIP] > Read the [Mixed adapter types](https://huggingface.co/docs/peft/en/developer_guides/mixed_models) guide
|
| 75 |
+
to learn > more about using different adapter types.
|
| 76 |
+
|
| 77 |
+
Example:
|
| 78 |
+
|
| 79 |
+
```py
|
| 80 |
+
>>> base_model = ... # load the base model, e.g. from transformers
|
| 81 |
+
>>> peft_model = PeftMixedModel.from_pretrained(base_model, path_to_adapter1, "adapter1").eval()
|
| 82 |
+
>>> peft_model.load_adapter(path_to_adapter2, "adapter2")
|
| 83 |
+
>>> peft_model.set_adapter(["adapter1", "adapter2"]) # activate both adapters
|
| 84 |
+
>>> peft_model(data) # forward pass using both adapters
|
| 85 |
+
```
|
| 86 |
+
|
| 87 |
+
Args:
|
| 88 |
+
model (`torch.nn.Module`):
|
| 89 |
+
The model to be tuned.
|
| 90 |
+
config (`PeftConfig`):
|
| 91 |
+
The config of the model to be tuned. The adapter type must be compatible.
|
| 92 |
+
adapter_name (`str`, `optional`, defaults to `"default"`):
|
| 93 |
+
The name of the first adapter.
|
| 94 |
+
low_cpu_mem_usage (`bool`, `optional`, defaults to `False`):
|
| 95 |
+
Create empty adapter weights on meta device. Useful to speed up the loading process.
|
| 96 |
+
"""
|
| 97 |
+
|
| 98 |
+
def __init__(self, model: nn.Module, peft_config: PeftConfig, adapter_name: str = "default") -> None:
|
| 99 |
+
super().__init__()
|
| 100 |
+
_check_config_compatible(peft_config)
|
| 101 |
+
_prepare_model_for_gradient_checkpointing(model)
|
| 102 |
+
self.modules_to_save = None
|
| 103 |
+
self.base_model = MixedModel(model, {adapter_name: peft_config}, adapter_name)
|
| 104 |
+
self.set_modules_to_save(peft_config, adapter_name)
|
| 105 |
+
|
| 106 |
+
self.config = getattr(model, "config", DUMMY_MODEL_CONFIG)
|
| 107 |
+
|
| 108 |
+
# the `pretraining_tp` is set for some models to simulate Tensor Parallelism during inference to avoid
|
| 109 |
+
# numerical differences, https://github.com/pytorch/pytorch/issues/76232 - to avoid any unexpected
|
| 110 |
+
# behavior we disable that in this line.
|
| 111 |
+
if hasattr(self.base_model, "config") and hasattr(self.base_model.config, "pretraining_tp"):
|
| 112 |
+
self.base_model.config.pretraining_tp = 1
|
| 113 |
+
|
| 114 |
+
@property
|
| 115 |
+
def peft_config(self) -> dict[str, PeftConfig]:
|
| 116 |
+
return self.base_model.peft_config
|
| 117 |
+
|
| 118 |
+
@property
|
| 119 |
+
def active_adapter(self) -> str:
|
| 120 |
+
return self.base_model.active_adapter
|
| 121 |
+
|
| 122 |
+
@property
|
| 123 |
+
def active_adapters(self) -> list[str]:
|
| 124 |
+
return self.base_model.active_adapters
|
| 125 |
+
|
| 126 |
+
def get_nb_trainable_parameters(self):
|
| 127 |
+
r"""
|
| 128 |
+
Returns the number of trainable parameters and number of all parameters in the model.
|
| 129 |
+
"""
|
| 130 |
+
# note: same as PeftModel.get_nb_trainable_parameters
|
| 131 |
+
trainable_params = 0
|
| 132 |
+
all_param = 0
|
| 133 |
+
for _, param in self.named_parameters():
|
| 134 |
+
num_params = param.numel()
|
| 135 |
+
# if using DS Zero 3 and the weights are initialized empty
|
| 136 |
+
if num_params == 0 and hasattr(param, "ds_numel"):
|
| 137 |
+
num_params = param.ds_numel
|
| 138 |
+
|
| 139 |
+
# Due to the design of 4bit linear layers from bitsandbytes
|
| 140 |
+
# one needs to multiply the number of parameters by 2 to get
|
| 141 |
+
# the correct number of parameters
|
| 142 |
+
if param.__class__.__name__ == "Params4bit":
|
| 143 |
+
num_params = num_params * 2
|
| 144 |
+
|
| 145 |
+
all_param += num_params
|
| 146 |
+
if param.requires_grad:
|
| 147 |
+
trainable_params += num_params
|
| 148 |
+
|
| 149 |
+
return trainable_params, all_param
|
| 150 |
+
|
| 151 |
+
def print_trainable_parameters(self):
|
| 152 |
+
"""
|
| 153 |
+
Prints the number of trainable parameters in the model.
|
| 154 |
+
|
| 155 |
+
Note: print_trainable_parameters() uses get_nb_trainable_parameters() which is different from
|
| 156 |
+
num_parameters(only_trainable=True) from huggingface/transformers. get_nb_trainable_parameters() returns
|
| 157 |
+
(trainable parameters, all parameters) of the Peft Model which includes modified backbone transformer model.
|
| 158 |
+
For techniques like LoRA, the backbone transformer model is modified in place with LoRA modules. However, for
|
| 159 |
+
prompt tuning, the backbone transformer model is unmodified. num_parameters(only_trainable=True) returns number
|
| 160 |
+
of trainable parameters of the backbone transformer model which can be different.
|
| 161 |
+
"""
|
| 162 |
+
# note: same as PeftModel.print_trainable_parameters
|
| 163 |
+
trainable_params, all_param = self.get_nb_trainable_parameters()
|
| 164 |
+
|
| 165 |
+
print(
|
| 166 |
+
f"trainable params: {trainable_params:,d} || "
|
| 167 |
+
f"all params: {all_param:,d} || "
|
| 168 |
+
f"trainable%: {100 * trainable_params / all_param:.4f}"
|
| 169 |
+
)
|
| 170 |
+
|
| 171 |
+
def __getattr__(self, name: str):
|
| 172 |
+
"""Forward missing attributes to the wrapped module."""
|
| 173 |
+
try:
|
| 174 |
+
return super().__getattr__(name) # defer to nn.Module's logic
|
| 175 |
+
except AttributeError:
|
| 176 |
+
if name == "base_model": # see #1892: prevent infinite recursion if class is not initialized
|
| 177 |
+
raise
|
| 178 |
+
return getattr(self.base_model, name)
|
| 179 |
+
|
| 180 |
+
def forward(self, *args: Any, **kwargs: Any):
|
| 181 |
+
"""
|
| 182 |
+
Forward pass of the model.
|
| 183 |
+
"""
|
| 184 |
+
return self.base_model(*args, **kwargs)
|
| 185 |
+
|
| 186 |
+
def generate(self, *args: Any, **kwargs: Any):
|
| 187 |
+
"""
|
| 188 |
+
Generate output.
|
| 189 |
+
"""
|
| 190 |
+
return self.base_model.generate(*args, **kwargs)
|
| 191 |
+
|
| 192 |
+
@contextmanager
|
| 193 |
+
def disable_adapter(self):
|
| 194 |
+
"""
|
| 195 |
+
Disables the adapter module.
|
| 196 |
+
"""
|
| 197 |
+
try:
|
| 198 |
+
self.base_model.disable_adapter_layers()
|
| 199 |
+
yield
|
| 200 |
+
finally:
|
| 201 |
+
self.base_model.enable_adapter_layers()
|
| 202 |
+
|
| 203 |
+
def add_adapter(self, adapter_name: str, peft_config: PeftConfig, low_cpu_mem_usage: bool = False) -> None:
|
| 204 |
+
"""
|
| 205 |
+
Add an adapter to the model based on the passed configuration.
|
| 206 |
+
|
| 207 |
+
This adapter is not trained. To load a trained adapter, check out [`PeftModel.load_adapter`].
|
| 208 |
+
|
| 209 |
+
The name for the new adapter should be unique.
|
| 210 |
+
|
| 211 |
+
The new adapter is not automatically set as the active adapter. Use [`PeftModel.set_adapter`] to set the active
|
| 212 |
+
adapter.
|
| 213 |
+
|
| 214 |
+
Args:
|
| 215 |
+
adapter_name (`str`):
|
| 216 |
+
The name of the adapter to be added.
|
| 217 |
+
peft_config ([`PeftConfig`]):
|
| 218 |
+
The configuration of the adapter to be added.
|
| 219 |
+
low_cpu_mem_usage (`bool`, `optional`, defaults to `False`):
|
| 220 |
+
Create empty adapter weights on meta device. Useful to speed up the process when loading saved
|
| 221 |
+
adapters.
|
| 222 |
+
|
| 223 |
+
> [!TIP] > Don't use `low_cpu_mem_usage=True` when creating a new PEFT adapter for training (training
|
| 224 |
+
is untested > and discouraged for PeftMixedModel in general).
|
| 225 |
+
"""
|
| 226 |
+
_check_config_compatible(peft_config)
|
| 227 |
+
|
| 228 |
+
try:
|
| 229 |
+
self.peft_config[adapter_name] = peft_config
|
| 230 |
+
self.base_model.inject_adapter(self, adapter_name, low_cpu_mem_usage=low_cpu_mem_usage)
|
| 231 |
+
except Exception: # something went wrong, roll back
|
| 232 |
+
if adapter_name in self.peft_config:
|
| 233 |
+
del self.peft_config[adapter_name]
|
| 234 |
+
raise
|
| 235 |
+
|
| 236 |
+
self.set_modules_to_save(peft_config, adapter_name)
|
| 237 |
+
|
| 238 |
+
def set_modules_to_save(self, peft_config: PeftConfig, adapter_name: str) -> None:
|
| 239 |
+
if (modules_to_save := getattr(peft_config, "modules_to_save", None)) is None:
|
| 240 |
+
return
|
| 241 |
+
|
| 242 |
+
if self.modules_to_save is None:
|
| 243 |
+
self.modules_to_save = set(modules_to_save)
|
| 244 |
+
else:
|
| 245 |
+
self.modules_to_save.update(modules_to_save)
|
| 246 |
+
_set_trainable(
|
| 247 |
+
self,
|
| 248 |
+
adapter_name,
|
| 249 |
+
module_names=getattr(peft_config, "modules_to_save", None),
|
| 250 |
+
inference_mode=peft_config.inference_mode,
|
| 251 |
+
)
|
| 252 |
+
|
| 253 |
+
def set_adapter(self, adapter_name: Union[str, list[str]], inference_mode: bool = False) -> None:
|
| 254 |
+
"""
|
| 255 |
+
Sets the active adapter(s) for the model.
|
| 256 |
+
|
| 257 |
+
Note that the order in which the adapters are applied during the forward pass may not be the same as the order
|
| 258 |
+
in which they are passed to this function. Instead, the order during the forward pass is determined by the
|
| 259 |
+
order in which the adapters were loaded into the model. The active adapters only determine which adapters are
|
| 260 |
+
active during the forward pass, but not the order in which they are applied.
|
| 261 |
+
|
| 262 |
+
Additionally, this function will set the specified adapter to trainable (i.e., requires_grad=True) unless
|
| 263 |
+
inference_mode is True.
|
| 264 |
+
|
| 265 |
+
Args:
|
| 266 |
+
adapter_name (str, list[str]):
|
| 267 |
+
The name(s) of the adapter(s) to set as active
|
| 268 |
+
inference_mode (bool, optional):
|
| 269 |
+
Whether the activated adapter should be frozen (i.e. `requires_grad=False`). Default is False.
|
| 270 |
+
"""
|
| 271 |
+
if isinstance(adapter_name, str):
|
| 272 |
+
adapter_name = [adapter_name]
|
| 273 |
+
|
| 274 |
+
mismatched = set(adapter_name) - set(self.peft_config.keys())
|
| 275 |
+
if mismatched:
|
| 276 |
+
raise ValueError(
|
| 277 |
+
f"Adapter(s) {sorted(mismatched)} not found, available adapters: {sorted(self.peft_config.keys())}"
|
| 278 |
+
)
|
| 279 |
+
|
| 280 |
+
self.base_model.set_adapter(adapter_name, inference_mode=inference_mode)
|
| 281 |
+
_set_adapter(self, adapter_name, inference_mode=inference_mode)
|
| 282 |
+
|
| 283 |
+
def delete_adapter(self, adapter_name: Union[str, list[str]]) -> None:
|
| 284 |
+
if isinstance(adapter_name, str):
|
| 285 |
+
adapter_name = [adapter_name]
|
| 286 |
+
|
| 287 |
+
mismatched = set(adapter_name) - set(self.peft_config.keys())
|
| 288 |
+
if mismatched:
|
| 289 |
+
raise ValueError(
|
| 290 |
+
f"Adapter(s) {sorted(mismatched)} not found, available adapters: {sorted(self.peft_config.keys())}"
|
| 291 |
+
)
|
| 292 |
+
|
| 293 |
+
self.base_model.delete_adapter(adapter_name)
|
| 294 |
+
|
| 295 |
+
def merge_and_unload(self, *args: Any, **kwargs: Any):
|
| 296 |
+
r"""
|
| 297 |
+
This method merges the adapter layers into the base model. This is needed if someone wants to use the base
|
| 298 |
+
model as a standalone model.
|
| 299 |
+
|
| 300 |
+
Args:
|
| 301 |
+
progressbar (`bool`):
|
| 302 |
+
whether to show a progressbar indicating the unload and merge process
|
| 303 |
+
safe_merge (`bool`):
|
| 304 |
+
whether to activate the safe merging check to check if there is any potential Nan in the adapter
|
| 305 |
+
weights
|
| 306 |
+
adapter_names (`List[str]`, *optional*):
|
| 307 |
+
The list of adapter names that should be merged. If None, all active adapters will be merged. Defaults
|
| 308 |
+
to `None`.
|
| 309 |
+
"""
|
| 310 |
+
return self.base_model.merge_and_unload(*args, **kwargs)
|
| 311 |
+
|
| 312 |
+
def unload(self, *args: Any, **kwargs: Any):
|
| 313 |
+
"""
|
| 314 |
+
Gets back the base model by removing all the adapter modules without merging. This gives back the original base
|
| 315 |
+
model.
|
| 316 |
+
"""
|
| 317 |
+
return self.base_model.unload(*args, **kwargs)
|
| 318 |
+
|
| 319 |
+
def get_layer_status(self):
|
| 320 |
+
raise TypeError(f"get_layer_status is not supported for {self.__class__.__name__}.")
|
| 321 |
+
|
| 322 |
+
def get_model_status(self):
|
| 323 |
+
raise TypeError(f"get_model_status is not supported for {self.__class__.__name__}.")
|
| 324 |
+
|
| 325 |
+
@classmethod
|
| 326 |
+
def _split_kwargs(cls, kwargs: dict[str, Any]):
|
| 327 |
+
return PeftModel._split_kwargs(kwargs)
|
| 328 |
+
|
| 329 |
+
def _check_new_adapter_config(self, peft_config: PeftConfig, is_trainable: bool) -> None:
|
| 330 |
+
return PeftModel._check_new_adapter_config(self, peft_config, is_trainable=is_trainable)
|
| 331 |
+
|
| 332 |
+
def load_adapter(self, model_id: str, adapter_name: str, *args: Any, **kwargs: Any):
|
| 333 |
+
"""
|
| 334 |
+
Load a trained adapter into the model.
|
| 335 |
+
|
| 336 |
+
The name for the new adapter should be unique.
|
| 337 |
+
|
| 338 |
+
The new adapter is not automatically set as the active adapter. Use [`PeftModel.set_adapter`] to set the active
|
| 339 |
+
adapter.
|
| 340 |
+
|
| 341 |
+
Args:
|
| 342 |
+
adapter_name (`str`):
|
| 343 |
+
The name of the adapter to be added.
|
| 344 |
+
peft_config ([`PeftConfig`]):
|
| 345 |
+
The configuration of the adapter to be added.
|
| 346 |
+
is_trainable (`bool`, *optional*, defaults to `False`):
|
| 347 |
+
Whether the adapter should be trainable or not. If `False`, the adapter will be frozen and can only be
|
| 348 |
+
used for inference.
|
| 349 |
+
torch_device (`str`, *optional*, defaults to None):
|
| 350 |
+
The device to load the adapter on. If `None`, the device will be inferred.
|
| 351 |
+
autocast_adapter_dtype (`bool`, *optional*, defaults to `True`):
|
| 352 |
+
Whether to autocast the adapter dtype. Defaults to `True`. Right now, this will only cast adapter
|
| 353 |
+
weights using float16 and bfloat16 to float32, as this is typically required for stable training, and
|
| 354 |
+
only affect select PEFT tuners.
|
| 355 |
+
ephemeral_gpu_offload (`bool`, *optional*, defaults to `False`):
|
| 356 |
+
Whether to use ephemeral GPU offloading for partially loaded modules. Defaults to `False`.
|
| 357 |
+
low_cpu_mem_usage (`bool`, `optional`, defaults to `False`):
|
| 358 |
+
Create empty adapter weights on meta device before loading the saved weights. Useful to speed up the
|
| 359 |
+
process.
|
| 360 |
+
kwargs: (`optional`):
|
| 361 |
+
Additional arguments to modify the way the adapter is loaded, e.g. the token for Hugging Face Hub.
|
| 362 |
+
"""
|
| 363 |
+
# the low_cpu_mem_usage option is handled through kwargs
|
| 364 |
+
output = PeftModel.load_adapter(self, model_id, adapter_name, *args, **kwargs)
|
| 365 |
+
# TODO: not quite clear why this is necessary but tests fail without it
|
| 366 |
+
self.set_adapter(self.active_adapters)
|
| 367 |
+
return output
|
| 368 |
+
|
| 369 |
+
def create_or_update_model_card(self, output_dir: str):
|
| 370 |
+
raise NotImplementedError(f"Model card creation is not supported for {self.__class__.__name__} (yet).")
|
| 371 |
+
|
| 372 |
+
def save_pretrained(
|
| 373 |
+
self,
|
| 374 |
+
save_directory: str,
|
| 375 |
+
safe_serialization: bool = False,
|
| 376 |
+
selected_adapters: Optional[list[str]] = None,
|
| 377 |
+
**kwargs: Any,
|
| 378 |
+
):
|
| 379 |
+
raise NotImplementedError(f"Saving is not supported for {self.__class__.__name__} (yet).")
|
| 380 |
+
|
| 381 |
+
@classmethod
|
| 382 |
+
def from_pretrained(
|
| 383 |
+
cls,
|
| 384 |
+
model: nn.Module,
|
| 385 |
+
model_id: str | os.PathLike,
|
| 386 |
+
adapter_name: str = "default",
|
| 387 |
+
is_trainable: bool = False,
|
| 388 |
+
config: Optional[PeftConfig] = None,
|
| 389 |
+
**kwargs: Any,
|
| 390 |
+
):
|
| 391 |
+
r"""
|
| 392 |
+
Instantiate a PEFT mixed model from a pretrained model and loaded PEFT weights.
|
| 393 |
+
|
| 394 |
+
Note that the passed `model` may be modified inplace.
|
| 395 |
+
|
| 396 |
+
Args:
|
| 397 |
+
model (`nn.Module`):
|
| 398 |
+
The model to be adapted.
|
| 399 |
+
model_id (`str` or `os.PathLike`):
|
| 400 |
+
The name of the PEFT configuration to use. Can be either:
|
| 401 |
+
- A string, the `model id` of a PEFT configuration hosted inside a model repo on the Hugging Face
|
| 402 |
+
Hub.
|
| 403 |
+
- A path to a directory containing a PEFT configuration file saved using the `save_pretrained`
|
| 404 |
+
method (`./my_peft_config_directory/`).
|
| 405 |
+
adapter_name (`str`, *optional*, defaults to `"default"`):
|
| 406 |
+
The name of the adapter to be loaded. This is useful for loading multiple adapters.
|
| 407 |
+
is_trainable (`bool`, *optional*, defaults to `False`):
|
| 408 |
+
Whether the adapter should be trainable or not. If `False`, the adapter will be frozen and use for
|
| 409 |
+
inference
|
| 410 |
+
config ([`~peft.PeftConfig`], *optional*):
|
| 411 |
+
The configuration object to use instead of an automatically loaded configuration. This configuration
|
| 412 |
+
object is mutually exclusive with `model_id` and `kwargs`. This is useful when configuration is already
|
| 413 |
+
loaded before calling `from_pretrained`.
|
| 414 |
+
low_cpu_mem_usage (`bool`, `optional`, defaults to `False`):
|
| 415 |
+
Create empty adapter weights on meta device before loading the saved weights. Useful to speed up the
|
| 416 |
+
process.
|
| 417 |
+
kwargs: (`optional`):
|
| 418 |
+
Additional keyword arguments passed along to the specific PEFT configuration class.
|
| 419 |
+
"""
|
| 420 |
+
# note: adapted from PeftModel.from_pretrained
|
| 421 |
+
from .mapping import PEFT_TYPE_TO_CONFIG_MAPPING, PEFT_TYPE_TO_MIXED_MODEL_MAPPING
|
| 422 |
+
|
| 423 |
+
# load the config
|
| 424 |
+
if config is None:
|
| 425 |
+
hf_kwargs = {
|
| 426 |
+
"subfolder": kwargs.get("subfolder", None),
|
| 427 |
+
"revision": kwargs.get("revision", None),
|
| 428 |
+
"cache_dir": kwargs.get("cache_dir", None),
|
| 429 |
+
"token": kwargs.get("token", None),
|
| 430 |
+
}
|
| 431 |
+
if use_auth_token := kwargs.get("use_auth_token", None):
|
| 432 |
+
hf_kwargs["use_auth_token"] = use_auth_token
|
| 433 |
+
config = PEFT_TYPE_TO_CONFIG_MAPPING[PeftConfig._get_peft_type(model_id, **hf_kwargs)].from_pretrained(
|
| 434 |
+
model_id, **kwargs
|
| 435 |
+
)
|
| 436 |
+
elif isinstance(config, PeftConfig):
|
| 437 |
+
config.inference_mode = not is_trainable
|
| 438 |
+
else:
|
| 439 |
+
raise ValueError(f"The input config must be a PeftConfig, got {config.__class__}")
|
| 440 |
+
|
| 441 |
+
# note: this is different from PeftModel.from_pretrained
|
| 442 |
+
if config.peft_type not in PEFT_TYPE_TO_MIXED_MODEL_MAPPING:
|
| 443 |
+
raise ValueError(f"Adapter of type {config.peft_type} is not supported for mixed models.")
|
| 444 |
+
|
| 445 |
+
if (getattr(model, "hf_device_map", None) is not None) and len(
|
| 446 |
+
set(model.hf_device_map.values()).intersection({"cpu", "disk"})
|
| 447 |
+
) > 0:
|
| 448 |
+
remove_hook_from_submodules(model)
|
| 449 |
+
|
| 450 |
+
if config.is_prompt_learning and is_trainable:
|
| 451 |
+
# note: should not be possible to reach, but just in case
|
| 452 |
+
raise ValueError("Cannot set a prompt learning adapter to trainable when loading pretrained adapter.")
|
| 453 |
+
else:
|
| 454 |
+
config.inference_mode = not is_trainable
|
| 455 |
+
|
| 456 |
+
# note: this is different from PeftModel.from_pretrained, we always return a PeftMixedModel
|
| 457 |
+
model = cls(model, config, adapter_name)
|
| 458 |
+
# the low_cpu_mem_usage option is handled through kwargs
|
| 459 |
+
model.load_adapter(model_id, adapter_name, is_trainable=is_trainable, **kwargs)
|
| 460 |
+
return model
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/peft/peft_model.py
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/peft/py.typed
ADDED
|
File without changes
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/pyarrow/_csv.pxd
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Licensed to the Apache Software Foundation (ASF) under one
|
| 2 |
+
# or more contributor license agreements. See the NOTICE file
|
| 3 |
+
# distributed with this work for additional information
|
| 4 |
+
# regarding copyright ownership. The ASF licenses this file
|
| 5 |
+
# to you under the Apache License, Version 2.0 (the
|
| 6 |
+
# "License"); you may not use this file except in compliance
|
| 7 |
+
# with the License. You may obtain a copy of the License at
|
| 8 |
+
#
|
| 9 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 10 |
+
#
|
| 11 |
+
# Unless required by applicable law or agreed to in writing,
|
| 12 |
+
# software distributed under the License is distributed on an
|
| 13 |
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
| 14 |
+
# KIND, either express or implied. See the License for the
|
| 15 |
+
# specific language governing permissions and limitations
|
| 16 |
+
# under the License.
|
| 17 |
+
|
| 18 |
+
# cython: language_level = 3
|
| 19 |
+
|
| 20 |
+
from pyarrow.includes.libarrow cimport *
|
| 21 |
+
from pyarrow.lib cimport _Weakrefable
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
cdef class ConvertOptions(_Weakrefable):
|
| 25 |
+
cdef:
|
| 26 |
+
unique_ptr[CCSVConvertOptions] options
|
| 27 |
+
|
| 28 |
+
@staticmethod
|
| 29 |
+
cdef ConvertOptions wrap(CCSVConvertOptions options)
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
cdef class ParseOptions(_Weakrefable):
|
| 33 |
+
cdef:
|
| 34 |
+
unique_ptr[CCSVParseOptions] options
|
| 35 |
+
object _invalid_row_handler
|
| 36 |
+
|
| 37 |
+
@staticmethod
|
| 38 |
+
cdef ParseOptions wrap(CCSVParseOptions options)
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
cdef class ReadOptions(_Weakrefable):
|
| 42 |
+
cdef:
|
| 43 |
+
unique_ptr[CCSVReadOptions] options
|
| 44 |
+
public object encoding
|
| 45 |
+
|
| 46 |
+
@staticmethod
|
| 47 |
+
cdef ReadOptions wrap(CCSVReadOptions options)
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
cdef class WriteOptions(_Weakrefable):
|
| 51 |
+
cdef:
|
| 52 |
+
unique_ptr[CCSVWriteOptions] options
|
| 53 |
+
|
| 54 |
+
@staticmethod
|
| 55 |
+
cdef WriteOptions wrap(CCSVWriteOptions options)
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/pyarrow/_cuda.pxd
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Licensed to the Apache Software Foundation (ASF) under one
|
| 2 |
+
# or more contributor license agreements. See the NOTICE file
|
| 3 |
+
# distributed with this work for additional information
|
| 4 |
+
# regarding copyright ownership. The ASF licenses this file
|
| 5 |
+
# to you under the Apache License, Version 2.0 (the
|
| 6 |
+
# "License"); you may not use this file except in compliance
|
| 7 |
+
# with the License. You may obtain a copy of the License at
|
| 8 |
+
#
|
| 9 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 10 |
+
#
|
| 11 |
+
# Unless required by applicable law or agreed to in writing,
|
| 12 |
+
# software distributed under the License is distributed on an
|
| 13 |
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
| 14 |
+
# KIND, either express or implied. See the License for the
|
| 15 |
+
# specific language governing permissions and limitations
|
| 16 |
+
# under the License.
|
| 17 |
+
|
| 18 |
+
# cython: language_level = 3
|
| 19 |
+
|
| 20 |
+
from pyarrow.lib cimport *
|
| 21 |
+
from pyarrow.includes.common cimport *
|
| 22 |
+
from pyarrow.includes.libarrow cimport *
|
| 23 |
+
from pyarrow.includes.libarrow_cuda cimport *
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
cdef class Context(_Weakrefable):
|
| 27 |
+
cdef:
|
| 28 |
+
shared_ptr[CCudaContext] context
|
| 29 |
+
int device_number
|
| 30 |
+
|
| 31 |
+
cdef void init(self, const shared_ptr[CCudaContext]& ctx)
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
cdef class IpcMemHandle(_Weakrefable):
|
| 35 |
+
cdef:
|
| 36 |
+
shared_ptr[CCudaIpcMemHandle] handle
|
| 37 |
+
|
| 38 |
+
cdef void init(self, shared_ptr[CCudaIpcMemHandle]& h)
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
cdef class CudaBuffer(Buffer):
|
| 42 |
+
cdef:
|
| 43 |
+
shared_ptr[CCudaBuffer] cuda_buffer
|
| 44 |
+
object base
|
| 45 |
+
|
| 46 |
+
cdef void init_cuda(self,
|
| 47 |
+
const shared_ptr[CCudaBuffer]& buffer,
|
| 48 |
+
object base)
|
| 49 |
+
|
| 50 |
+
|
| 51 |
+
cdef class HostBuffer(Buffer):
|
| 52 |
+
cdef:
|
| 53 |
+
shared_ptr[CCudaHostBuffer] host_buffer
|
| 54 |
+
|
| 55 |
+
cdef void init_host(self, const shared_ptr[CCudaHostBuffer]& buffer)
|
| 56 |
+
|
| 57 |
+
|
| 58 |
+
cdef class BufferReader(NativeFile):
|
| 59 |
+
cdef:
|
| 60 |
+
CCudaBufferReader* reader
|
| 61 |
+
CudaBuffer buffer
|
| 62 |
+
|
| 63 |
+
|
| 64 |
+
cdef class BufferWriter(NativeFile):
|
| 65 |
+
cdef:
|
| 66 |
+
CCudaBufferWriter* writer
|
| 67 |
+
CudaBuffer buffer
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/pyarrow/_dataset.pxd
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Licensed to the Apache Software Foundation (ASF) under one
|
| 2 |
+
# or more contributor license agreements. See the NOTICE file
|
| 3 |
+
# distributed with this work for additional information
|
| 4 |
+
# regarding copyright ownership. The ASF licenses this file
|
| 5 |
+
# to you under the Apache License, Version 2.0 (the
|
| 6 |
+
# "License"); you may not use this file except in compliance
|
| 7 |
+
# with the License. You may obtain a copy of the License at
|
| 8 |
+
#
|
| 9 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 10 |
+
#
|
| 11 |
+
# Unless required by applicable law or agreed to in writing,
|
| 12 |
+
# software distributed under the License is distributed on an
|
| 13 |
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
| 14 |
+
# KIND, either express or implied. See the License for the
|
| 15 |
+
# specific language governing permissions and limitations
|
| 16 |
+
# under the License.
|
| 17 |
+
|
| 18 |
+
# cython: language_level = 3
|
| 19 |
+
|
| 20 |
+
"""Dataset is currently unstable. APIs subject to change without notice."""
|
| 21 |
+
|
| 22 |
+
from pyarrow.includes.common cimport *
|
| 23 |
+
from pyarrow.includes.libarrow_dataset cimport *
|
| 24 |
+
from pyarrow.lib cimport *
|
| 25 |
+
from pyarrow._fs cimport FileSystem, FileInfo
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
cdef CFileSource _make_file_source(object file, FileSystem filesystem=*, object file_size=*)
|
| 29 |
+
|
| 30 |
+
cdef class DatasetFactory(_Weakrefable):
|
| 31 |
+
|
| 32 |
+
cdef:
|
| 33 |
+
SharedPtrNoGIL[CDatasetFactory] wrapped
|
| 34 |
+
CDatasetFactory* factory
|
| 35 |
+
|
| 36 |
+
cdef init(self, const shared_ptr[CDatasetFactory]& sp)
|
| 37 |
+
|
| 38 |
+
@staticmethod
|
| 39 |
+
cdef wrap(const shared_ptr[CDatasetFactory]& sp)
|
| 40 |
+
|
| 41 |
+
cdef inline shared_ptr[CDatasetFactory] unwrap(self) nogil
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
cdef class Dataset(_Weakrefable):
|
| 45 |
+
|
| 46 |
+
cdef:
|
| 47 |
+
SharedPtrNoGIL[CDataset] wrapped
|
| 48 |
+
CDataset* dataset
|
| 49 |
+
public dict _scan_options
|
| 50 |
+
|
| 51 |
+
cdef void init(self, const shared_ptr[CDataset]& sp)
|
| 52 |
+
|
| 53 |
+
@staticmethod
|
| 54 |
+
cdef wrap(const shared_ptr[CDataset]& sp)
|
| 55 |
+
|
| 56 |
+
cdef shared_ptr[CDataset] unwrap(self) nogil
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
cdef class Scanner(_Weakrefable):
|
| 60 |
+
cdef:
|
| 61 |
+
SharedPtrNoGIL[CScanner] wrapped
|
| 62 |
+
CScanner* scanner
|
| 63 |
+
|
| 64 |
+
cdef void init(self, const shared_ptr[CScanner]& sp)
|
| 65 |
+
|
| 66 |
+
@staticmethod
|
| 67 |
+
cdef wrap(const shared_ptr[CScanner]& sp)
|
| 68 |
+
|
| 69 |
+
cdef shared_ptr[CScanner] unwrap(self)
|
| 70 |
+
|
| 71 |
+
@staticmethod
|
| 72 |
+
cdef shared_ptr[CScanOptions] _make_scan_options(Dataset dataset, dict py_scanoptions) except *
|
| 73 |
+
|
| 74 |
+
|
| 75 |
+
cdef class FragmentScanOptions(_Weakrefable):
|
| 76 |
+
|
| 77 |
+
cdef:
|
| 78 |
+
shared_ptr[CFragmentScanOptions] wrapped
|
| 79 |
+
|
| 80 |
+
cdef void init(self, const shared_ptr[CFragmentScanOptions]& sp)
|
| 81 |
+
|
| 82 |
+
@staticmethod
|
| 83 |
+
cdef wrap(const shared_ptr[CFragmentScanOptions]& sp)
|
| 84 |
+
|
| 85 |
+
|
| 86 |
+
cdef class FileFormat(_Weakrefable):
|
| 87 |
+
|
| 88 |
+
cdef:
|
| 89 |
+
shared_ptr[CFileFormat] wrapped
|
| 90 |
+
CFileFormat* format
|
| 91 |
+
|
| 92 |
+
cdef void init(self, const shared_ptr[CFileFormat]& sp)
|
| 93 |
+
|
| 94 |
+
@staticmethod
|
| 95 |
+
cdef wrap(const shared_ptr[CFileFormat]& sp)
|
| 96 |
+
|
| 97 |
+
cdef inline shared_ptr[CFileFormat] unwrap(self)
|
| 98 |
+
|
| 99 |
+
cdef _set_default_fragment_scan_options(self, FragmentScanOptions options)
|
| 100 |
+
|
| 101 |
+
# Return a WrittenFile after a file was written.
|
| 102 |
+
# May be overridden by subclasses, e.g. to add metadata.
|
| 103 |
+
cdef WrittenFile _finish_write(self, path, base_dir,
|
| 104 |
+
CFileWriter* file_writer)
|
| 105 |
+
|
| 106 |
+
|
| 107 |
+
cdef class FileWriteOptions(_Weakrefable):
|
| 108 |
+
|
| 109 |
+
cdef:
|
| 110 |
+
shared_ptr[CFileWriteOptions] wrapped
|
| 111 |
+
CFileWriteOptions* c_options
|
| 112 |
+
|
| 113 |
+
cdef void init(self, const shared_ptr[CFileWriteOptions]& sp)
|
| 114 |
+
|
| 115 |
+
@staticmethod
|
| 116 |
+
cdef wrap(const shared_ptr[CFileWriteOptions]& sp)
|
| 117 |
+
|
| 118 |
+
cdef inline shared_ptr[CFileWriteOptions] unwrap(self)
|
| 119 |
+
|
| 120 |
+
|
| 121 |
+
cdef class Fragment(_Weakrefable):
|
| 122 |
+
|
| 123 |
+
cdef:
|
| 124 |
+
SharedPtrNoGIL[CFragment] wrapped
|
| 125 |
+
CFragment* fragment
|
| 126 |
+
|
| 127 |
+
cdef void init(self, const shared_ptr[CFragment]& sp)
|
| 128 |
+
|
| 129 |
+
@staticmethod
|
| 130 |
+
cdef wrap(const shared_ptr[CFragment]& sp)
|
| 131 |
+
|
| 132 |
+
cdef inline shared_ptr[CFragment] unwrap(self)
|
| 133 |
+
|
| 134 |
+
|
| 135 |
+
cdef class FileFragment(Fragment):
|
| 136 |
+
|
| 137 |
+
cdef:
|
| 138 |
+
CFileFragment* file_fragment
|
| 139 |
+
|
| 140 |
+
cdef void init(self, const shared_ptr[CFragment]& sp)
|
| 141 |
+
|
| 142 |
+
|
| 143 |
+
cdef class Partitioning(_Weakrefable):
|
| 144 |
+
|
| 145 |
+
cdef:
|
| 146 |
+
shared_ptr[CPartitioning] wrapped
|
| 147 |
+
CPartitioning* partitioning
|
| 148 |
+
|
| 149 |
+
cdef init(self, const shared_ptr[CPartitioning]& sp)
|
| 150 |
+
|
| 151 |
+
@staticmethod
|
| 152 |
+
cdef wrap(const shared_ptr[CPartitioning]& sp)
|
| 153 |
+
|
| 154 |
+
cdef inline shared_ptr[CPartitioning] unwrap(self)
|
| 155 |
+
|
| 156 |
+
|
| 157 |
+
cdef class PartitioningFactory(_Weakrefable):
|
| 158 |
+
|
| 159 |
+
cdef:
|
| 160 |
+
shared_ptr[CPartitioningFactory] wrapped
|
| 161 |
+
CPartitioningFactory* factory
|
| 162 |
+
object constructor
|
| 163 |
+
object options
|
| 164 |
+
|
| 165 |
+
cdef init(self, const shared_ptr[CPartitioningFactory]& sp)
|
| 166 |
+
|
| 167 |
+
@staticmethod
|
| 168 |
+
cdef wrap(const shared_ptr[CPartitioningFactory]& sp,
|
| 169 |
+
object constructor, object options)
|
| 170 |
+
|
| 171 |
+
cdef inline shared_ptr[CPartitioningFactory] unwrap(self)
|
| 172 |
+
|
| 173 |
+
|
| 174 |
+
cdef class WrittenFile(_Weakrefable):
|
| 175 |
+
|
| 176 |
+
# The full path to the created file
|
| 177 |
+
cdef public str path
|
| 178 |
+
# Optional Parquet metadata
|
| 179 |
+
# This metadata will have the file path attribute set to the path of
|
| 180 |
+
# the written file.
|
| 181 |
+
cdef public object metadata
|
| 182 |
+
# The size of the file in bytes
|
| 183 |
+
cdef public int64_t size
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/pyarrow/_dataset_parquet.pxd
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Licensed to the Apache Software Foundation (ASF) under one
|
| 2 |
+
# or more contributor license agreements. See the NOTICE file
|
| 3 |
+
# distributed with this work for additional information
|
| 4 |
+
# regarding copyright ownership. The ASF licenses this file
|
| 5 |
+
# to you under the Apache License, Version 2.0 (the
|
| 6 |
+
# "License"); you may not use this file except in compliance
|
| 7 |
+
# with the License. You may obtain a copy of the License at
|
| 8 |
+
#
|
| 9 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 10 |
+
#
|
| 11 |
+
# Unless required by applicable law or agreed to in writing,
|
| 12 |
+
# software distributed under the License is distributed on an
|
| 13 |
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
| 14 |
+
# KIND, either express or implied. See the License for the
|
| 15 |
+
# specific language governing permissions and limitations
|
| 16 |
+
# under the License.
|
| 17 |
+
|
| 18 |
+
# cython: language_level = 3
|
| 19 |
+
|
| 20 |
+
"""Dataset support for Parquet file format."""
|
| 21 |
+
|
| 22 |
+
from pyarrow.includes.libarrow_dataset cimport *
|
| 23 |
+
from pyarrow.includes.libarrow_dataset_parquet cimport *
|
| 24 |
+
|
| 25 |
+
from pyarrow._dataset cimport FragmentScanOptions, FileWriteOptions
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
cdef class ParquetFragmentScanOptions(FragmentScanOptions):
|
| 29 |
+
cdef:
|
| 30 |
+
CParquetFragmentScanOptions* parquet_options
|
| 31 |
+
object _parquet_decryption_config
|
| 32 |
+
object _decryption_properties
|
| 33 |
+
|
| 34 |
+
cdef void init(self, const shared_ptr[CFragmentScanOptions]& sp)
|
| 35 |
+
cdef CReaderProperties* reader_properties(self)
|
| 36 |
+
cdef ArrowReaderProperties* arrow_reader_properties(self)
|
| 37 |
+
|
| 38 |
+
|
| 39 |
+
cdef class ParquetFileWriteOptions(FileWriteOptions):
|
| 40 |
+
|
| 41 |
+
cdef:
|
| 42 |
+
CParquetFileWriteOptions* parquet_options
|
| 43 |
+
object _properties
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/pyarrow/_feather.pyx
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Licensed to the Apache Software Foundation (ASF) under one
|
| 2 |
+
# or more contributor license agreements. See the NOTICE file
|
| 3 |
+
# distributed with this work for additional information
|
| 4 |
+
# regarding copyright ownership. The ASF licenses this file
|
| 5 |
+
# to you under the Apache License, Version 2.0 (the
|
| 6 |
+
# "License"); you may not use this file except in compliance
|
| 7 |
+
# with the License. You may obtain a copy of the License at
|
| 8 |
+
#
|
| 9 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 10 |
+
#
|
| 11 |
+
# Unless required by applicable law or agreed to in writing,
|
| 12 |
+
# software distributed under the License is distributed on an
|
| 13 |
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
| 14 |
+
# KIND, either express or implied. See the License for the
|
| 15 |
+
# specific language governing permissions and limitations
|
| 16 |
+
# under the License.
|
| 17 |
+
|
| 18 |
+
# ---------------------------------------------------------------------
|
| 19 |
+
# Implement Feather file format
|
| 20 |
+
|
| 21 |
+
# cython: profile=False
|
| 22 |
+
# distutils: language = c++
|
| 23 |
+
# cython: language_level=3
|
| 24 |
+
|
| 25 |
+
from cython.operator cimport dereference as deref
|
| 26 |
+
from pyarrow.includes.common cimport *
|
| 27 |
+
from pyarrow.includes.libarrow cimport *
|
| 28 |
+
from pyarrow.includes.libarrow_feather cimport *
|
| 29 |
+
from pyarrow.lib cimport (check_status, Table, _Weakrefable,
|
| 30 |
+
get_writer, get_reader, pyarrow_wrap_table)
|
| 31 |
+
from pyarrow.lib import tobytes
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
class FeatherError(Exception):
|
| 35 |
+
pass
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
def write_feather(Table table, object dest, compression=None,
|
| 39 |
+
compression_level=None, chunksize=None, version=2):
|
| 40 |
+
cdef shared_ptr[COutputStream] sink
|
| 41 |
+
get_writer(dest, &sink)
|
| 42 |
+
|
| 43 |
+
cdef CFeatherProperties properties
|
| 44 |
+
if version == 2:
|
| 45 |
+
properties.version = kFeatherV2Version
|
| 46 |
+
else:
|
| 47 |
+
properties.version = kFeatherV1Version
|
| 48 |
+
|
| 49 |
+
if compression == 'zstd':
|
| 50 |
+
properties.compression = CCompressionType_ZSTD
|
| 51 |
+
elif compression == 'lz4':
|
| 52 |
+
properties.compression = CCompressionType_LZ4_FRAME
|
| 53 |
+
else:
|
| 54 |
+
properties.compression = CCompressionType_UNCOMPRESSED
|
| 55 |
+
|
| 56 |
+
if chunksize is not None:
|
| 57 |
+
properties.chunksize = chunksize
|
| 58 |
+
|
| 59 |
+
if compression_level is not None:
|
| 60 |
+
properties.compression_level = compression_level
|
| 61 |
+
|
| 62 |
+
with nogil:
|
| 63 |
+
check_status(WriteFeather(deref(table.table), sink.get(),
|
| 64 |
+
properties))
|
| 65 |
+
|
| 66 |
+
|
| 67 |
+
cdef class FeatherReader(_Weakrefable):
|
| 68 |
+
cdef:
|
| 69 |
+
shared_ptr[CFeatherReader] reader
|
| 70 |
+
|
| 71 |
+
def __cinit__(self, source, c_bool use_memory_map, c_bool use_threads):
|
| 72 |
+
cdef:
|
| 73 |
+
shared_ptr[CRandomAccessFile] reader
|
| 74 |
+
CIpcReadOptions options = CIpcReadOptions.Defaults()
|
| 75 |
+
options.use_threads = use_threads
|
| 76 |
+
|
| 77 |
+
get_reader(source, use_memory_map, &reader)
|
| 78 |
+
with nogil:
|
| 79 |
+
self.reader = GetResultValue(CFeatherReader.Open(reader, options))
|
| 80 |
+
|
| 81 |
+
@property
|
| 82 |
+
def version(self):
|
| 83 |
+
return self.reader.get().version()
|
| 84 |
+
|
| 85 |
+
def read(self):
|
| 86 |
+
cdef shared_ptr[CTable] sp_table
|
| 87 |
+
with nogil:
|
| 88 |
+
check_status(self.reader.get()
|
| 89 |
+
.Read(&sp_table))
|
| 90 |
+
|
| 91 |
+
return pyarrow_wrap_table(sp_table)
|
| 92 |
+
|
| 93 |
+
def read_indices(self, indices):
|
| 94 |
+
cdef:
|
| 95 |
+
shared_ptr[CTable] sp_table
|
| 96 |
+
vector[int] c_indices
|
| 97 |
+
|
| 98 |
+
for index in indices:
|
| 99 |
+
c_indices.push_back(index)
|
| 100 |
+
with nogil:
|
| 101 |
+
check_status(self.reader.get()
|
| 102 |
+
.Read(c_indices, &sp_table))
|
| 103 |
+
|
| 104 |
+
return pyarrow_wrap_table(sp_table)
|
| 105 |
+
|
| 106 |
+
def read_names(self, names):
|
| 107 |
+
cdef:
|
| 108 |
+
shared_ptr[CTable] sp_table
|
| 109 |
+
vector[c_string] c_names
|
| 110 |
+
|
| 111 |
+
for name in names:
|
| 112 |
+
c_names.push_back(tobytes(name))
|
| 113 |
+
with nogil:
|
| 114 |
+
check_status(self.reader.get()
|
| 115 |
+
.Read(c_names, &sp_table))
|
| 116 |
+
|
| 117 |
+
return pyarrow_wrap_table(sp_table)
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/pyarrow/_fs.pyx
ADDED
|
@@ -0,0 +1,1628 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Licensed to the Apache Software Foundation (ASF) under one
|
| 2 |
+
# or more contributor license agreements. See the NOTICE file
|
| 3 |
+
# distributed with this work for additional information
|
| 4 |
+
# regarding copyright ownership. The ASF licenses this file
|
| 5 |
+
# to you under the Apache License, Version 2.0 (the
|
| 6 |
+
# "License"); you may not use this file except in compliance
|
| 7 |
+
# with the License. You may obtain a copy of the License at
|
| 8 |
+
#
|
| 9 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 10 |
+
#
|
| 11 |
+
# Unless required by applicable law or agreed to in writing,
|
| 12 |
+
# software distributed under the License is distributed on an
|
| 13 |
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
| 14 |
+
# KIND, either express or implied. See the License for the
|
| 15 |
+
# specific language governing permissions and limitations
|
| 16 |
+
# under the License.
|
| 17 |
+
|
| 18 |
+
# cython: language_level = 3
|
| 19 |
+
|
| 20 |
+
from cpython.datetime cimport datetime, PyDateTime_DateTime
|
| 21 |
+
from cython cimport binding
|
| 22 |
+
|
| 23 |
+
from pyarrow.includes.common cimport *
|
| 24 |
+
from pyarrow.includes.libarrow_python cimport PyDateTime_to_TimePoint
|
| 25 |
+
from pyarrow.lib import _detect_compression, frombytes, tobytes
|
| 26 |
+
from pyarrow.lib cimport *
|
| 27 |
+
from pyarrow.util import _stringify_path
|
| 28 |
+
|
| 29 |
+
from abc import ABC, abstractmethod
|
| 30 |
+
from datetime import datetime, timezone
|
| 31 |
+
import os
|
| 32 |
+
import pathlib
|
| 33 |
+
import sys
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
cdef _init_ca_paths():
|
| 37 |
+
cdef CFileSystemGlobalOptions options
|
| 38 |
+
|
| 39 |
+
import ssl
|
| 40 |
+
paths = ssl.get_default_verify_paths()
|
| 41 |
+
if paths.cafile:
|
| 42 |
+
options.tls_ca_file_path = os.fsencode(paths.cafile)
|
| 43 |
+
if paths.capath:
|
| 44 |
+
options.tls_ca_dir_path = os.fsencode(paths.capath)
|
| 45 |
+
check_status(CFileSystemsInitialize(options))
|
| 46 |
+
|
| 47 |
+
|
| 48 |
+
if sys.platform == 'linux':
|
| 49 |
+
# ARROW-9261: On Linux, we may need to fixup the paths to TLS CA certs
|
| 50 |
+
# (especially in manylinux packages) since the values hardcoded at
|
| 51 |
+
# compile-time in libcurl may be wrong.
|
| 52 |
+
_init_ca_paths()
|
| 53 |
+
|
| 54 |
+
|
| 55 |
+
cdef inline c_string _path_as_bytes(path) except *:
|
| 56 |
+
# handle only abstract paths, not bound to any filesystem like pathlib is,
|
| 57 |
+
# so we only accept plain strings
|
| 58 |
+
if not isinstance(path, (bytes, str)):
|
| 59 |
+
raise TypeError('Path must be a string')
|
| 60 |
+
# tobytes always uses utf-8, which is more or less ok, at least on Windows
|
| 61 |
+
# since the C++ side then decodes from utf-8. On Unix, os.fsencode may be
|
| 62 |
+
# better.
|
| 63 |
+
return tobytes(path)
|
| 64 |
+
|
| 65 |
+
|
| 66 |
+
cdef object _wrap_file_type(CFileType ty):
|
| 67 |
+
return FileType(<int8_t> ty)
|
| 68 |
+
|
| 69 |
+
|
| 70 |
+
cdef CFileType _unwrap_file_type(FileType ty) except *:
|
| 71 |
+
if ty == FileType.Unknown:
|
| 72 |
+
return CFileType_Unknown
|
| 73 |
+
elif ty == FileType.NotFound:
|
| 74 |
+
return CFileType_NotFound
|
| 75 |
+
elif ty == FileType.File:
|
| 76 |
+
return CFileType_File
|
| 77 |
+
elif ty == FileType.Directory:
|
| 78 |
+
return CFileType_Directory
|
| 79 |
+
assert 0
|
| 80 |
+
|
| 81 |
+
|
| 82 |
+
def _file_type_to_string(ty):
|
| 83 |
+
# Python 3.11 changed str(IntEnum) to return the string representation
|
| 84 |
+
# of the integer value: https://github.com/python/cpython/issues/94763
|
| 85 |
+
return f"{ty.__class__.__name__}.{ty._name_}"
|
| 86 |
+
|
| 87 |
+
|
| 88 |
+
cdef class FileInfo(_Weakrefable):
|
| 89 |
+
"""
|
| 90 |
+
FileSystem entry info.
|
| 91 |
+
|
| 92 |
+
Parameters
|
| 93 |
+
----------
|
| 94 |
+
path : str
|
| 95 |
+
The full path to the filesystem entry.
|
| 96 |
+
type : FileType
|
| 97 |
+
The type of the filesystem entry.
|
| 98 |
+
mtime : datetime or float, default None
|
| 99 |
+
If given, the modification time of the filesystem entry.
|
| 100 |
+
If a float is given, it is the number of seconds since the
|
| 101 |
+
Unix epoch.
|
| 102 |
+
mtime_ns : int, default None
|
| 103 |
+
If given, the modification time of the filesystem entry,
|
| 104 |
+
in nanoseconds since the Unix epoch.
|
| 105 |
+
`mtime` and `mtime_ns` are mutually exclusive.
|
| 106 |
+
size : int, default None
|
| 107 |
+
If given, the filesystem entry size in bytes. This should only
|
| 108 |
+
be given if `type` is `FileType.File`.
|
| 109 |
+
|
| 110 |
+
Examples
|
| 111 |
+
--------
|
| 112 |
+
Generate a file:
|
| 113 |
+
|
| 114 |
+
>>> from pyarrow import fs
|
| 115 |
+
>>> local = fs.LocalFileSystem()
|
| 116 |
+
>>> path_fs = local_path + '/pyarrow-fs-example.dat'
|
| 117 |
+
>>> with local.open_output_stream(path_fs) as stream:
|
| 118 |
+
... stream.write(b'data')
|
| 119 |
+
4
|
| 120 |
+
|
| 121 |
+
Get FileInfo object using ``get_file_info()``:
|
| 122 |
+
|
| 123 |
+
>>> file_info = local.get_file_info(path_fs)
|
| 124 |
+
>>> file_info
|
| 125 |
+
<FileInfo for '.../pyarrow-fs-example.dat': type=FileType.File, size=4>
|
| 126 |
+
|
| 127 |
+
Inspect FileInfo attributes:
|
| 128 |
+
|
| 129 |
+
>>> file_info.type
|
| 130 |
+
<FileType.File: 2>
|
| 131 |
+
|
| 132 |
+
>>> file_info.is_file
|
| 133 |
+
True
|
| 134 |
+
|
| 135 |
+
>>> file_info.path
|
| 136 |
+
'/.../pyarrow-fs-example.dat'
|
| 137 |
+
|
| 138 |
+
>>> file_info.base_name
|
| 139 |
+
'pyarrow-fs-example.dat'
|
| 140 |
+
|
| 141 |
+
>>> file_info.size
|
| 142 |
+
4
|
| 143 |
+
|
| 144 |
+
>>> file_info.extension
|
| 145 |
+
'dat'
|
| 146 |
+
|
| 147 |
+
>>> file_info.mtime # doctest: +SKIP
|
| 148 |
+
datetime.datetime(2022, 6, 29, 7, 56, 10, 873922, tzinfo=datetime.timezone.utc)
|
| 149 |
+
|
| 150 |
+
>>> file_info.mtime_ns # doctest: +SKIP
|
| 151 |
+
1656489370873922073
|
| 152 |
+
"""
|
| 153 |
+
|
| 154 |
+
def __init__(self, path, FileType type=FileType.Unknown, *,
|
| 155 |
+
mtime=None, mtime_ns=None, size=None):
|
| 156 |
+
self.info.set_path(tobytes(path))
|
| 157 |
+
self.info.set_type(_unwrap_file_type(type))
|
| 158 |
+
if mtime is not None:
|
| 159 |
+
if mtime_ns is not None:
|
| 160 |
+
raise TypeError("Only one of mtime and mtime_ns "
|
| 161 |
+
"can be given")
|
| 162 |
+
if isinstance(mtime, datetime):
|
| 163 |
+
self.info.set_mtime(PyDateTime_to_TimePoint(
|
| 164 |
+
<PyDateTime_DateTime*> mtime))
|
| 165 |
+
else:
|
| 166 |
+
self.info.set_mtime(TimePoint_from_s(mtime))
|
| 167 |
+
elif mtime_ns is not None:
|
| 168 |
+
self.info.set_mtime(TimePoint_from_ns(mtime_ns))
|
| 169 |
+
if size is not None:
|
| 170 |
+
self.info.set_size(size)
|
| 171 |
+
|
| 172 |
+
@staticmethod
|
| 173 |
+
cdef wrap(CFileInfo info):
|
| 174 |
+
cdef FileInfo self = FileInfo.__new__(FileInfo)
|
| 175 |
+
self.info = move(info)
|
| 176 |
+
return self
|
| 177 |
+
|
| 178 |
+
cdef inline CFileInfo unwrap(self) nogil:
|
| 179 |
+
return self.info
|
| 180 |
+
|
| 181 |
+
@staticmethod
|
| 182 |
+
cdef CFileInfo unwrap_safe(obj):
|
| 183 |
+
if not isinstance(obj, FileInfo):
|
| 184 |
+
raise TypeError("Expected FileInfo instance, got {0}"
|
| 185 |
+
.format(type(obj)))
|
| 186 |
+
return (<FileInfo> obj).unwrap()
|
| 187 |
+
|
| 188 |
+
def __repr__(self):
|
| 189 |
+
def getvalue(attr):
|
| 190 |
+
try:
|
| 191 |
+
return getattr(self, attr)
|
| 192 |
+
except ValueError:
|
| 193 |
+
return ''
|
| 194 |
+
|
| 195 |
+
s = (f'<FileInfo for {self.path!r}: '
|
| 196 |
+
f'type={_file_type_to_string(self.type)}')
|
| 197 |
+
if self.is_file:
|
| 198 |
+
s += f', size={self.size}'
|
| 199 |
+
s += '>'
|
| 200 |
+
return s
|
| 201 |
+
|
| 202 |
+
@property
|
| 203 |
+
def type(self):
|
| 204 |
+
"""
|
| 205 |
+
Type of the file.
|
| 206 |
+
|
| 207 |
+
The returned enum values can be the following:
|
| 208 |
+
|
| 209 |
+
- FileType.NotFound: target does not exist
|
| 210 |
+
- FileType.Unknown: target exists but its type is unknown (could be a
|
| 211 |
+
special file such as a Unix socket or character device, or
|
| 212 |
+
Windows NUL / CON / ...)
|
| 213 |
+
- FileType.File: target is a regular file
|
| 214 |
+
- FileType.Directory: target is a regular directory
|
| 215 |
+
|
| 216 |
+
Returns
|
| 217 |
+
-------
|
| 218 |
+
type : FileType
|
| 219 |
+
"""
|
| 220 |
+
return _wrap_file_type(self.info.type())
|
| 221 |
+
|
| 222 |
+
@property
|
| 223 |
+
def is_file(self):
|
| 224 |
+
"""
|
| 225 |
+
"""
|
| 226 |
+
return self.type == FileType.File
|
| 227 |
+
|
| 228 |
+
@property
|
| 229 |
+
def path(self):
|
| 230 |
+
"""
|
| 231 |
+
The full file path in the filesystem.
|
| 232 |
+
|
| 233 |
+
Examples
|
| 234 |
+
--------
|
| 235 |
+
>>> file_info = local.get_file_info(path)
|
| 236 |
+
>>> file_info.path
|
| 237 |
+
'/.../pyarrow-fs-example.dat'
|
| 238 |
+
"""
|
| 239 |
+
return frombytes(self.info.path())
|
| 240 |
+
|
| 241 |
+
@property
|
| 242 |
+
def base_name(self):
|
| 243 |
+
"""
|
| 244 |
+
The file base name.
|
| 245 |
+
|
| 246 |
+
Component after the last directory separator.
|
| 247 |
+
|
| 248 |
+
Examples
|
| 249 |
+
--------
|
| 250 |
+
>>> file_info = local.get_file_info(path)
|
| 251 |
+
>>> file_info.base_name
|
| 252 |
+
'pyarrow-fs-example.dat'
|
| 253 |
+
"""
|
| 254 |
+
return frombytes(self.info.base_name())
|
| 255 |
+
|
| 256 |
+
@property
|
| 257 |
+
def size(self):
|
| 258 |
+
"""
|
| 259 |
+
The size in bytes, if available.
|
| 260 |
+
|
| 261 |
+
Only regular files are guaranteed to have a size.
|
| 262 |
+
|
| 263 |
+
Returns
|
| 264 |
+
-------
|
| 265 |
+
size : int or None
|
| 266 |
+
"""
|
| 267 |
+
cdef int64_t size
|
| 268 |
+
size = self.info.size()
|
| 269 |
+
return (size if size != -1 else None)
|
| 270 |
+
|
| 271 |
+
@property
|
| 272 |
+
def extension(self):
|
| 273 |
+
"""
|
| 274 |
+
The file extension.
|
| 275 |
+
|
| 276 |
+
Examples
|
| 277 |
+
--------
|
| 278 |
+
>>> file_info = local.get_file_info(path)
|
| 279 |
+
>>> file_info.extension
|
| 280 |
+
'dat'
|
| 281 |
+
"""
|
| 282 |
+
return frombytes(self.info.extension())
|
| 283 |
+
|
| 284 |
+
@property
|
| 285 |
+
def mtime(self):
|
| 286 |
+
"""
|
| 287 |
+
The time of last modification, if available.
|
| 288 |
+
|
| 289 |
+
Returns
|
| 290 |
+
-------
|
| 291 |
+
mtime : datetime.datetime or None
|
| 292 |
+
|
| 293 |
+
Examples
|
| 294 |
+
--------
|
| 295 |
+
>>> file_info = local.get_file_info(path)
|
| 296 |
+
>>> file_info.mtime # doctest: +SKIP
|
| 297 |
+
datetime.datetime(2022, 6, 29, 7, 56, 10, 873922, tzinfo=datetime.timezone.utc)
|
| 298 |
+
"""
|
| 299 |
+
cdef int64_t nanoseconds
|
| 300 |
+
nanoseconds = TimePoint_to_ns(self.info.mtime())
|
| 301 |
+
return (datetime.fromtimestamp(nanoseconds / 1.0e9, timezone.utc)
|
| 302 |
+
if nanoseconds != -1 else None)
|
| 303 |
+
|
| 304 |
+
@property
|
| 305 |
+
def mtime_ns(self):
|
| 306 |
+
"""
|
| 307 |
+
The time of last modification, if available, expressed in nanoseconds
|
| 308 |
+
since the Unix epoch.
|
| 309 |
+
|
| 310 |
+
Returns
|
| 311 |
+
-------
|
| 312 |
+
mtime_ns : int or None
|
| 313 |
+
|
| 314 |
+
Examples
|
| 315 |
+
--------
|
| 316 |
+
>>> file_info = local.get_file_info(path)
|
| 317 |
+
>>> file_info.mtime_ns # doctest: +SKIP
|
| 318 |
+
1656489370873922073
|
| 319 |
+
"""
|
| 320 |
+
cdef int64_t nanoseconds
|
| 321 |
+
nanoseconds = TimePoint_to_ns(self.info.mtime())
|
| 322 |
+
return (nanoseconds if nanoseconds != -1 else None)
|
| 323 |
+
|
| 324 |
+
|
| 325 |
+
cdef class FileSelector(_Weakrefable):
|
| 326 |
+
"""
|
| 327 |
+
File and directory selector.
|
| 328 |
+
|
| 329 |
+
It contains a set of options that describes how to search for files and
|
| 330 |
+
directories.
|
| 331 |
+
|
| 332 |
+
Parameters
|
| 333 |
+
----------
|
| 334 |
+
base_dir : str
|
| 335 |
+
The directory in which to select files. Relative paths also work, use
|
| 336 |
+
'.' for the current directory and '..' for the parent.
|
| 337 |
+
allow_not_found : bool, default False
|
| 338 |
+
The behavior if `base_dir` doesn't exist in the filesystem.
|
| 339 |
+
If false, an error is returned.
|
| 340 |
+
If true, an empty selection is returned.
|
| 341 |
+
recursive : bool, default False
|
| 342 |
+
Whether to recurse into subdirectories.
|
| 343 |
+
|
| 344 |
+
Examples
|
| 345 |
+
--------
|
| 346 |
+
List the contents of a directory and subdirectories:
|
| 347 |
+
|
| 348 |
+
>>> selector_1 = fs.FileSelector(local_path, recursive=True)
|
| 349 |
+
>>> local.get_file_info(selector_1) # doctest: +SKIP
|
| 350 |
+
[<FileInfo for 'tmp/alphabet/example.dat': type=FileType.File, size=4>,
|
| 351 |
+
<FileInfo for 'tmp/alphabet/subdir': type=FileType.Directory>,
|
| 352 |
+
<FileInfo for 'tmp/alphabet/subdir/example_copy.dat': type=FileType.File, size=4>]
|
| 353 |
+
|
| 354 |
+
List only the contents of the base directory:
|
| 355 |
+
|
| 356 |
+
>>> selector_2 = fs.FileSelector(local_path)
|
| 357 |
+
>>> local.get_file_info(selector_2) # doctest: +SKIP
|
| 358 |
+
[<FileInfo for 'tmp/alphabet/example.dat': type=FileType.File, size=4>,
|
| 359 |
+
<FileInfo for 'tmp/alphabet/subdir': type=FileType.Directory>]
|
| 360 |
+
|
| 361 |
+
Return empty selection if the directory doesn't exist:
|
| 362 |
+
|
| 363 |
+
>>> selector_not_found = fs.FileSelector(local_path + '/missing',
|
| 364 |
+
... recursive=True,
|
| 365 |
+
... allow_not_found=True)
|
| 366 |
+
>>> local.get_file_info(selector_not_found)
|
| 367 |
+
[]
|
| 368 |
+
"""
|
| 369 |
+
|
| 370 |
+
def __init__(self, base_dir, bint allow_not_found=False,
|
| 371 |
+
bint recursive=False):
|
| 372 |
+
self.base_dir = base_dir
|
| 373 |
+
self.recursive = recursive
|
| 374 |
+
self.allow_not_found = allow_not_found
|
| 375 |
+
|
| 376 |
+
@staticmethod
|
| 377 |
+
cdef FileSelector wrap(CFileSelector wrapped):
|
| 378 |
+
cdef FileSelector self = FileSelector.__new__(FileSelector)
|
| 379 |
+
self.selector = move(wrapped)
|
| 380 |
+
return self
|
| 381 |
+
|
| 382 |
+
cdef inline CFileSelector unwrap(self) nogil:
|
| 383 |
+
return self.selector
|
| 384 |
+
|
| 385 |
+
@property
|
| 386 |
+
def base_dir(self):
|
| 387 |
+
return frombytes(self.selector.base_dir)
|
| 388 |
+
|
| 389 |
+
@base_dir.setter
|
| 390 |
+
def base_dir(self, base_dir):
|
| 391 |
+
self.selector.base_dir = _path_as_bytes(base_dir)
|
| 392 |
+
|
| 393 |
+
@property
|
| 394 |
+
def allow_not_found(self):
|
| 395 |
+
return self.selector.allow_not_found
|
| 396 |
+
|
| 397 |
+
@allow_not_found.setter
|
| 398 |
+
def allow_not_found(self, bint allow_not_found):
|
| 399 |
+
self.selector.allow_not_found = allow_not_found
|
| 400 |
+
|
| 401 |
+
@property
|
| 402 |
+
def recursive(self):
|
| 403 |
+
return self.selector.recursive
|
| 404 |
+
|
| 405 |
+
@recursive.setter
|
| 406 |
+
def recursive(self, bint recursive):
|
| 407 |
+
self.selector.recursive = recursive
|
| 408 |
+
|
| 409 |
+
def __repr__(self):
|
| 410 |
+
return ("<FileSelector base_dir={0.base_dir!r} "
|
| 411 |
+
"recursive={0.recursive}>".format(self))
|
| 412 |
+
|
| 413 |
+
|
| 414 |
+
cdef class FileSystem(_Weakrefable):
|
| 415 |
+
"""
|
| 416 |
+
Abstract file system API.
|
| 417 |
+
"""
|
| 418 |
+
|
| 419 |
+
def __init__(self):
|
| 420 |
+
raise TypeError("FileSystem is an abstract class, instantiate one of "
|
| 421 |
+
"the subclasses instead: LocalFileSystem or "
|
| 422 |
+
"SubTreeFileSystem")
|
| 423 |
+
|
| 424 |
+
@staticmethod
|
| 425 |
+
@binding(True) # Required for cython < 3
|
| 426 |
+
def _from_uri(uri):
|
| 427 |
+
fs, _path = FileSystem.from_uri(uri)
|
| 428 |
+
return fs
|
| 429 |
+
|
| 430 |
+
@staticmethod
|
| 431 |
+
def from_uri(uri):
|
| 432 |
+
"""
|
| 433 |
+
Create a new FileSystem from URI or Path.
|
| 434 |
+
|
| 435 |
+
Recognized URI schemes are "file", "mock", "s3fs", "gs", "gcs", "hdfs" and "viewfs".
|
| 436 |
+
In addition, the argument can be a pathlib.Path object, or a string
|
| 437 |
+
describing an absolute local path.
|
| 438 |
+
|
| 439 |
+
Parameters
|
| 440 |
+
----------
|
| 441 |
+
uri : string
|
| 442 |
+
URI-based path, for example: file:///some/local/path.
|
| 443 |
+
|
| 444 |
+
Returns
|
| 445 |
+
-------
|
| 446 |
+
tuple of (FileSystem, str path)
|
| 447 |
+
With (filesystem, path) tuple where path is the abstract path
|
| 448 |
+
inside the FileSystem instance.
|
| 449 |
+
|
| 450 |
+
Examples
|
| 451 |
+
--------
|
| 452 |
+
Create a new FileSystem subclass from a URI:
|
| 453 |
+
|
| 454 |
+
>>> uri = 'file:///{}/pyarrow-fs-example.dat'.format(local_path)
|
| 455 |
+
>>> local_new, path_new = fs.FileSystem.from_uri(uri)
|
| 456 |
+
>>> local_new
|
| 457 |
+
<pyarrow._fs.LocalFileSystem object at ...
|
| 458 |
+
>>> path_new
|
| 459 |
+
'/.../pyarrow-fs-example.dat'
|
| 460 |
+
|
| 461 |
+
Or from a s3 bucket:
|
| 462 |
+
|
| 463 |
+
>>> fs.FileSystem.from_uri("s3://usgs-landsat/collection02/")
|
| 464 |
+
(<pyarrow._s3fs.S3FileSystem object at ...>, 'usgs-landsat/collection02')
|
| 465 |
+
"""
|
| 466 |
+
cdef:
|
| 467 |
+
c_string c_path
|
| 468 |
+
c_string c_uri
|
| 469 |
+
CResult[shared_ptr[CFileSystem]] result
|
| 470 |
+
|
| 471 |
+
if isinstance(uri, pathlib.Path):
|
| 472 |
+
# Make absolute
|
| 473 |
+
uri = uri.resolve().absolute()
|
| 474 |
+
c_uri = tobytes(_stringify_path(uri))
|
| 475 |
+
with nogil:
|
| 476 |
+
result = CFileSystemFromUriOrPath(c_uri, &c_path)
|
| 477 |
+
return FileSystem.wrap(GetResultValue(result)), frombytes(c_path)
|
| 478 |
+
|
| 479 |
+
cdef init(self, const shared_ptr[CFileSystem]& wrapped):
|
| 480 |
+
self.wrapped = wrapped
|
| 481 |
+
self.fs = wrapped.get()
|
| 482 |
+
|
| 483 |
+
@staticmethod
|
| 484 |
+
cdef wrap(const shared_ptr[CFileSystem]& sp):
|
| 485 |
+
cdef FileSystem self
|
| 486 |
+
|
| 487 |
+
typ = frombytes(sp.get().type_name())
|
| 488 |
+
if typ == 'local':
|
| 489 |
+
self = LocalFileSystem.__new__(LocalFileSystem)
|
| 490 |
+
elif typ == 'mock':
|
| 491 |
+
self = _MockFileSystem.__new__(_MockFileSystem)
|
| 492 |
+
elif typ == 'subtree':
|
| 493 |
+
self = SubTreeFileSystem.__new__(SubTreeFileSystem)
|
| 494 |
+
elif typ == 's3':
|
| 495 |
+
from pyarrow._s3fs import S3FileSystem
|
| 496 |
+
self = S3FileSystem.__new__(S3FileSystem)
|
| 497 |
+
elif typ == 'gcs':
|
| 498 |
+
from pyarrow._gcsfs import GcsFileSystem
|
| 499 |
+
self = GcsFileSystem.__new__(GcsFileSystem)
|
| 500 |
+
elif typ == 'abfs':
|
| 501 |
+
from pyarrow._azurefs import AzureFileSystem
|
| 502 |
+
self = AzureFileSystem.__new__(AzureFileSystem)
|
| 503 |
+
elif typ == 'hdfs':
|
| 504 |
+
from pyarrow._hdfs import HadoopFileSystem
|
| 505 |
+
self = HadoopFileSystem.__new__(HadoopFileSystem)
|
| 506 |
+
elif typ.startswith('py::'):
|
| 507 |
+
self = PyFileSystem.__new__(PyFileSystem)
|
| 508 |
+
else:
|
| 509 |
+
raise TypeError('Cannot wrap FileSystem pointer')
|
| 510 |
+
|
| 511 |
+
self.init(sp)
|
| 512 |
+
return self
|
| 513 |
+
|
| 514 |
+
cdef inline shared_ptr[CFileSystem] unwrap(self) nogil:
|
| 515 |
+
return self.wrapped
|
| 516 |
+
|
| 517 |
+
def equals(self, FileSystem other not None):
|
| 518 |
+
"""
|
| 519 |
+
Parameters
|
| 520 |
+
----------
|
| 521 |
+
other : pyarrow.fs.FileSystem
|
| 522 |
+
|
| 523 |
+
Returns
|
| 524 |
+
-------
|
| 525 |
+
bool
|
| 526 |
+
"""
|
| 527 |
+
return self.fs.Equals(other.unwrap())
|
| 528 |
+
|
| 529 |
+
def __eq__(self, other):
|
| 530 |
+
try:
|
| 531 |
+
return self.equals(other)
|
| 532 |
+
except TypeError:
|
| 533 |
+
return NotImplemented
|
| 534 |
+
|
| 535 |
+
@property
|
| 536 |
+
def type_name(self):
|
| 537 |
+
"""
|
| 538 |
+
The filesystem's type name.
|
| 539 |
+
"""
|
| 540 |
+
return frombytes(self.fs.type_name())
|
| 541 |
+
|
| 542 |
+
def get_file_info(self, paths_or_selector):
|
| 543 |
+
"""
|
| 544 |
+
Get info for the given files.
|
| 545 |
+
|
| 546 |
+
Any symlink is automatically dereferenced, recursively. A non-existing
|
| 547 |
+
or unreachable file returns a FileStat object and has a FileType of
|
| 548 |
+
value NotFound. An exception indicates a truly exceptional condition
|
| 549 |
+
(low-level I/O error, etc.).
|
| 550 |
+
|
| 551 |
+
Parameters
|
| 552 |
+
----------
|
| 553 |
+
paths_or_selector : FileSelector, path-like or list of path-likes
|
| 554 |
+
Either a selector object, a path-like object or a list of
|
| 555 |
+
path-like objects. The selector's base directory will not be
|
| 556 |
+
part of the results, even if it exists. If it doesn't exist,
|
| 557 |
+
use `allow_not_found`.
|
| 558 |
+
|
| 559 |
+
Returns
|
| 560 |
+
-------
|
| 561 |
+
FileInfo or list of FileInfo
|
| 562 |
+
Single FileInfo object is returned for a single path, otherwise
|
| 563 |
+
a list of FileInfo objects is returned.
|
| 564 |
+
|
| 565 |
+
Examples
|
| 566 |
+
--------
|
| 567 |
+
>>> local
|
| 568 |
+
<pyarrow._fs.LocalFileSystem object at ...>
|
| 569 |
+
>>> local.get_file_info("/{}/pyarrow-fs-example.dat".format(local_path))
|
| 570 |
+
<FileInfo for '/.../pyarrow-fs-example.dat': type=FileType.File, size=4>
|
| 571 |
+
"""
|
| 572 |
+
cdef:
|
| 573 |
+
CFileInfo info
|
| 574 |
+
c_string path
|
| 575 |
+
vector[CFileInfo] infos
|
| 576 |
+
vector[c_string] paths
|
| 577 |
+
CFileSelector selector
|
| 578 |
+
|
| 579 |
+
if isinstance(paths_or_selector, FileSelector):
|
| 580 |
+
with nogil:
|
| 581 |
+
selector = (<FileSelector>paths_or_selector).selector
|
| 582 |
+
infos = GetResultValue(self.fs.GetFileInfo(selector))
|
| 583 |
+
elif isinstance(paths_or_selector, (list, tuple)):
|
| 584 |
+
paths = [_path_as_bytes(s) for s in paths_or_selector]
|
| 585 |
+
with nogil:
|
| 586 |
+
infos = GetResultValue(self.fs.GetFileInfo(paths))
|
| 587 |
+
elif isinstance(paths_or_selector, (bytes, str)):
|
| 588 |
+
path =_path_as_bytes(paths_or_selector)
|
| 589 |
+
with nogil:
|
| 590 |
+
info = GetResultValue(self.fs.GetFileInfo(path))
|
| 591 |
+
return FileInfo.wrap(info)
|
| 592 |
+
else:
|
| 593 |
+
raise TypeError('Must pass either path(s) or a FileSelector')
|
| 594 |
+
|
| 595 |
+
return [FileInfo.wrap(info) for info in infos]
|
| 596 |
+
|
| 597 |
+
def create_dir(self, path, *, bint recursive=True):
|
| 598 |
+
"""
|
| 599 |
+
Create a directory and subdirectories.
|
| 600 |
+
|
| 601 |
+
This function succeeds if the directory already exists.
|
| 602 |
+
|
| 603 |
+
Parameters
|
| 604 |
+
----------
|
| 605 |
+
path : str
|
| 606 |
+
The path of the new directory.
|
| 607 |
+
recursive : bool, default True
|
| 608 |
+
Create nested directories as well.
|
| 609 |
+
"""
|
| 610 |
+
cdef c_string directory = _path_as_bytes(path)
|
| 611 |
+
with nogil:
|
| 612 |
+
check_status(self.fs.CreateDir(directory, recursive=recursive))
|
| 613 |
+
|
| 614 |
+
def delete_dir(self, path):
|
| 615 |
+
"""
|
| 616 |
+
Delete a directory and its contents, recursively.
|
| 617 |
+
|
| 618 |
+
Parameters
|
| 619 |
+
----------
|
| 620 |
+
path : str
|
| 621 |
+
The path of the directory to be deleted.
|
| 622 |
+
"""
|
| 623 |
+
cdef c_string directory = _path_as_bytes(path)
|
| 624 |
+
with nogil:
|
| 625 |
+
check_status(self.fs.DeleteDir(directory))
|
| 626 |
+
|
| 627 |
+
def delete_dir_contents(self, path, *,
|
| 628 |
+
bint accept_root_dir=False,
|
| 629 |
+
bint missing_dir_ok=False):
|
| 630 |
+
"""
|
| 631 |
+
Delete a directory's contents, recursively.
|
| 632 |
+
|
| 633 |
+
Like delete_dir, but doesn't delete the directory itself.
|
| 634 |
+
|
| 635 |
+
Parameters
|
| 636 |
+
----------
|
| 637 |
+
path : str
|
| 638 |
+
The path of the directory to be deleted.
|
| 639 |
+
accept_root_dir : boolean, default False
|
| 640 |
+
Allow deleting the root directory's contents
|
| 641 |
+
(if path is empty or "/")
|
| 642 |
+
missing_dir_ok : boolean, default False
|
| 643 |
+
If False then an error is raised if path does
|
| 644 |
+
not exist
|
| 645 |
+
"""
|
| 646 |
+
cdef c_string directory = _path_as_bytes(path)
|
| 647 |
+
if accept_root_dir and directory.strip(b"/") == b"":
|
| 648 |
+
with nogil:
|
| 649 |
+
check_status(self.fs.DeleteRootDirContents())
|
| 650 |
+
else:
|
| 651 |
+
with nogil:
|
| 652 |
+
check_status(self.fs.DeleteDirContents(directory,
|
| 653 |
+
missing_dir_ok))
|
| 654 |
+
|
| 655 |
+
def move(self, src, dest):
|
| 656 |
+
"""
|
| 657 |
+
Move / rename a file or directory.
|
| 658 |
+
|
| 659 |
+
If the destination exists:
|
| 660 |
+
- if it is a non-empty directory, an error is returned
|
| 661 |
+
- otherwise, if it has the same type as the source, it is replaced
|
| 662 |
+
- otherwise, behavior is unspecified (implementation-dependent).
|
| 663 |
+
|
| 664 |
+
Parameters
|
| 665 |
+
----------
|
| 666 |
+
src : str
|
| 667 |
+
The path of the file or the directory to be moved.
|
| 668 |
+
dest : str
|
| 669 |
+
The destination path where the file or directory is moved to.
|
| 670 |
+
|
| 671 |
+
Examples
|
| 672 |
+
--------
|
| 673 |
+
Create a new folder with a file:
|
| 674 |
+
|
| 675 |
+
>>> local.create_dir('/tmp/other_dir')
|
| 676 |
+
>>> local.copy_file(path,'/tmp/move_example.dat')
|
| 677 |
+
|
| 678 |
+
Move the file:
|
| 679 |
+
|
| 680 |
+
>>> local.move('/tmp/move_example.dat',
|
| 681 |
+
... '/tmp/other_dir/move_example_2.dat')
|
| 682 |
+
|
| 683 |
+
Inspect the file info:
|
| 684 |
+
|
| 685 |
+
>>> local.get_file_info('/tmp/other_dir/move_example_2.dat')
|
| 686 |
+
<FileInfo for '/tmp/other_dir/move_example_2.dat': type=FileType.File, size=4>
|
| 687 |
+
>>> local.get_file_info('/tmp/move_example.dat')
|
| 688 |
+
<FileInfo for '/tmp/move_example.dat': type=FileType.NotFound>
|
| 689 |
+
|
| 690 |
+
Delete the folder:
|
| 691 |
+
>>> local.delete_dir('/tmp/other_dir')
|
| 692 |
+
"""
|
| 693 |
+
cdef:
|
| 694 |
+
c_string source = _path_as_bytes(src)
|
| 695 |
+
c_string destination = _path_as_bytes(dest)
|
| 696 |
+
with nogil:
|
| 697 |
+
check_status(self.fs.Move(source, destination))
|
| 698 |
+
|
| 699 |
+
def copy_file(self, src, dest):
|
| 700 |
+
"""
|
| 701 |
+
Copy a file.
|
| 702 |
+
|
| 703 |
+
If the destination exists and is a directory, an error is returned.
|
| 704 |
+
Otherwise, it is replaced.
|
| 705 |
+
|
| 706 |
+
Parameters
|
| 707 |
+
----------
|
| 708 |
+
src : str
|
| 709 |
+
The path of the file to be copied from.
|
| 710 |
+
dest : str
|
| 711 |
+
The destination path where the file is copied to.
|
| 712 |
+
|
| 713 |
+
Examples
|
| 714 |
+
--------
|
| 715 |
+
>>> local.copy_file(path,
|
| 716 |
+
... local_path + '/pyarrow-fs-example_copy.dat')
|
| 717 |
+
|
| 718 |
+
Inspect the file info:
|
| 719 |
+
|
| 720 |
+
>>> local.get_file_info(local_path + '/pyarrow-fs-example_copy.dat')
|
| 721 |
+
<FileInfo for '/.../pyarrow-fs-example_copy.dat': type=FileType.File, size=4>
|
| 722 |
+
>>> local.get_file_info(path)
|
| 723 |
+
<FileInfo for '/.../pyarrow-fs-example.dat': type=FileType.File, size=4>
|
| 724 |
+
"""
|
| 725 |
+
cdef:
|
| 726 |
+
c_string source = _path_as_bytes(src)
|
| 727 |
+
c_string destination = _path_as_bytes(dest)
|
| 728 |
+
with nogil:
|
| 729 |
+
check_status(self.fs.CopyFile(source, destination))
|
| 730 |
+
|
| 731 |
+
def delete_file(self, path):
|
| 732 |
+
"""
|
| 733 |
+
Delete a file.
|
| 734 |
+
|
| 735 |
+
Parameters
|
| 736 |
+
----------
|
| 737 |
+
path : str
|
| 738 |
+
The path of the file to be deleted.
|
| 739 |
+
"""
|
| 740 |
+
cdef c_string file = _path_as_bytes(path)
|
| 741 |
+
with nogil:
|
| 742 |
+
check_status(self.fs.DeleteFile(file))
|
| 743 |
+
|
| 744 |
+
def _wrap_input_stream(self, stream, path, compression, buffer_size):
|
| 745 |
+
if buffer_size is not None and buffer_size != 0:
|
| 746 |
+
stream = BufferedInputStream(stream, buffer_size)
|
| 747 |
+
if compression == 'detect':
|
| 748 |
+
compression = _detect_compression(path)
|
| 749 |
+
if compression is not None:
|
| 750 |
+
stream = CompressedInputStream(stream, compression)
|
| 751 |
+
return stream
|
| 752 |
+
|
| 753 |
+
def _wrap_output_stream(self, stream, path, compression, buffer_size):
|
| 754 |
+
if buffer_size is not None and buffer_size != 0:
|
| 755 |
+
stream = BufferedOutputStream(stream, buffer_size)
|
| 756 |
+
if compression == 'detect':
|
| 757 |
+
compression = _detect_compression(path)
|
| 758 |
+
if compression is not None:
|
| 759 |
+
stream = CompressedOutputStream(stream, compression)
|
| 760 |
+
return stream
|
| 761 |
+
|
| 762 |
+
def open_input_file(self, path):
|
| 763 |
+
"""
|
| 764 |
+
Open an input file for random access reading.
|
| 765 |
+
|
| 766 |
+
Parameters
|
| 767 |
+
----------
|
| 768 |
+
path : str
|
| 769 |
+
The source to open for reading.
|
| 770 |
+
|
| 771 |
+
Returns
|
| 772 |
+
-------
|
| 773 |
+
stream : NativeFile
|
| 774 |
+
|
| 775 |
+
Examples
|
| 776 |
+
--------
|
| 777 |
+
Print the data from the file with `open_input_file()`:
|
| 778 |
+
|
| 779 |
+
>>> with local.open_input_file(path) as f:
|
| 780 |
+
... print(f.readall())
|
| 781 |
+
b'data'
|
| 782 |
+
"""
|
| 783 |
+
cdef:
|
| 784 |
+
c_string pathstr = _path_as_bytes(path)
|
| 785 |
+
NativeFile stream = NativeFile()
|
| 786 |
+
shared_ptr[CRandomAccessFile] in_handle
|
| 787 |
+
|
| 788 |
+
with nogil:
|
| 789 |
+
in_handle = GetResultValue(self.fs.OpenInputFile(pathstr))
|
| 790 |
+
|
| 791 |
+
stream.set_random_access_file(in_handle)
|
| 792 |
+
stream.is_readable = True
|
| 793 |
+
return stream
|
| 794 |
+
|
| 795 |
+
def open_input_stream(self, path, compression='detect', buffer_size=None):
|
| 796 |
+
"""
|
| 797 |
+
Open an input stream for sequential reading.
|
| 798 |
+
|
| 799 |
+
Parameters
|
| 800 |
+
----------
|
| 801 |
+
path : str
|
| 802 |
+
The source to open for reading.
|
| 803 |
+
compression : str optional, default 'detect'
|
| 804 |
+
The compression algorithm to use for on-the-fly decompression.
|
| 805 |
+
If "detect" and source is a file path, then compression will be
|
| 806 |
+
chosen based on the file extension.
|
| 807 |
+
If None, no compression will be applied. Otherwise, a well-known
|
| 808 |
+
algorithm name must be supplied (e.g. "gzip").
|
| 809 |
+
buffer_size : int optional, default None
|
| 810 |
+
If None or 0, no buffering will happen. Otherwise the size of the
|
| 811 |
+
temporary read buffer.
|
| 812 |
+
|
| 813 |
+
Returns
|
| 814 |
+
-------
|
| 815 |
+
stream : NativeFile
|
| 816 |
+
|
| 817 |
+
Examples
|
| 818 |
+
--------
|
| 819 |
+
Print the data from the file with `open_input_stream()`:
|
| 820 |
+
|
| 821 |
+
>>> with local.open_input_stream(path) as f:
|
| 822 |
+
... print(f.readall())
|
| 823 |
+
b'data'
|
| 824 |
+
"""
|
| 825 |
+
cdef:
|
| 826 |
+
c_string pathstr = _path_as_bytes(path)
|
| 827 |
+
NativeFile stream = NativeFile()
|
| 828 |
+
shared_ptr[CInputStream] in_handle
|
| 829 |
+
|
| 830 |
+
with nogil:
|
| 831 |
+
in_handle = GetResultValue(self.fs.OpenInputStream(pathstr))
|
| 832 |
+
|
| 833 |
+
stream.set_input_stream(in_handle)
|
| 834 |
+
stream.is_readable = True
|
| 835 |
+
|
| 836 |
+
return self._wrap_input_stream(
|
| 837 |
+
stream, path=path, compression=compression, buffer_size=buffer_size
|
| 838 |
+
)
|
| 839 |
+
|
| 840 |
+
def open_output_stream(self, path, compression='detect',
|
| 841 |
+
buffer_size=None, metadata=None):
|
| 842 |
+
"""
|
| 843 |
+
Open an output stream for sequential writing.
|
| 844 |
+
|
| 845 |
+
If the target already exists, existing data is truncated.
|
| 846 |
+
|
| 847 |
+
Parameters
|
| 848 |
+
----------
|
| 849 |
+
path : str
|
| 850 |
+
The source to open for writing.
|
| 851 |
+
compression : str optional, default 'detect'
|
| 852 |
+
The compression algorithm to use for on-the-fly compression.
|
| 853 |
+
If "detect" and source is a file path, then compression will be
|
| 854 |
+
chosen based on the file extension.
|
| 855 |
+
If None, no compression will be applied. Otherwise, a well-known
|
| 856 |
+
algorithm name must be supplied (e.g. "gzip").
|
| 857 |
+
buffer_size : int optional, default None
|
| 858 |
+
If None or 0, no buffering will happen. Otherwise the size of the
|
| 859 |
+
temporary write buffer.
|
| 860 |
+
metadata : dict optional, default None
|
| 861 |
+
If not None, a mapping of string keys to string values.
|
| 862 |
+
Some filesystems support storing metadata along the file
|
| 863 |
+
(such as "Content-Type").
|
| 864 |
+
Unsupported metadata keys will be ignored.
|
| 865 |
+
|
| 866 |
+
Returns
|
| 867 |
+
-------
|
| 868 |
+
stream : NativeFile
|
| 869 |
+
|
| 870 |
+
Examples
|
| 871 |
+
--------
|
| 872 |
+
>>> local = fs.LocalFileSystem()
|
| 873 |
+
>>> with local.open_output_stream(path) as stream:
|
| 874 |
+
... stream.write(b'data')
|
| 875 |
+
4
|
| 876 |
+
"""
|
| 877 |
+
cdef:
|
| 878 |
+
c_string pathstr = _path_as_bytes(path)
|
| 879 |
+
NativeFile stream = NativeFile()
|
| 880 |
+
shared_ptr[COutputStream] out_handle
|
| 881 |
+
shared_ptr[const CKeyValueMetadata] c_metadata
|
| 882 |
+
|
| 883 |
+
if metadata is not None:
|
| 884 |
+
c_metadata = pyarrow_unwrap_metadata(KeyValueMetadata(metadata))
|
| 885 |
+
|
| 886 |
+
with nogil:
|
| 887 |
+
out_handle = GetResultValue(
|
| 888 |
+
self.fs.OpenOutputStream(pathstr, c_metadata))
|
| 889 |
+
|
| 890 |
+
stream.set_output_stream(out_handle)
|
| 891 |
+
stream.is_writable = True
|
| 892 |
+
|
| 893 |
+
return self._wrap_output_stream(
|
| 894 |
+
stream, path=path, compression=compression, buffer_size=buffer_size
|
| 895 |
+
)
|
| 896 |
+
|
| 897 |
+
def open_append_stream(self, path, compression='detect',
|
| 898 |
+
buffer_size=None, metadata=None):
|
| 899 |
+
"""
|
| 900 |
+
Open an output stream for appending.
|
| 901 |
+
|
| 902 |
+
If the target doesn't exist, a new empty file is created.
|
| 903 |
+
|
| 904 |
+
.. note::
|
| 905 |
+
Some filesystem implementations do not support efficient
|
| 906 |
+
appending to an existing file, in which case this method will
|
| 907 |
+
raise NotImplementedError.
|
| 908 |
+
Consider writing to multiple files (using e.g. the dataset layer)
|
| 909 |
+
instead.
|
| 910 |
+
|
| 911 |
+
Parameters
|
| 912 |
+
----------
|
| 913 |
+
path : str
|
| 914 |
+
The source to open for writing.
|
| 915 |
+
compression : str optional, default 'detect'
|
| 916 |
+
The compression algorithm to use for on-the-fly compression.
|
| 917 |
+
If "detect" and source is a file path, then compression will be
|
| 918 |
+
chosen based on the file extension.
|
| 919 |
+
If None, no compression will be applied. Otherwise, a well-known
|
| 920 |
+
algorithm name must be supplied (e.g. "gzip").
|
| 921 |
+
buffer_size : int optional, default None
|
| 922 |
+
If None or 0, no buffering will happen. Otherwise the size of the
|
| 923 |
+
temporary write buffer.
|
| 924 |
+
metadata : dict optional, default None
|
| 925 |
+
If not None, a mapping of string keys to string values.
|
| 926 |
+
Some filesystems support storing metadata along the file
|
| 927 |
+
(such as "Content-Type").
|
| 928 |
+
Unsupported metadata keys will be ignored.
|
| 929 |
+
|
| 930 |
+
Returns
|
| 931 |
+
-------
|
| 932 |
+
stream : NativeFile
|
| 933 |
+
|
| 934 |
+
Examples
|
| 935 |
+
--------
|
| 936 |
+
Append new data to a FileSystem subclass with nonempty file:
|
| 937 |
+
|
| 938 |
+
>>> with local.open_append_stream(path) as f:
|
| 939 |
+
... f.write(b'+newly added')
|
| 940 |
+
12
|
| 941 |
+
|
| 942 |
+
Print out the content to the file:
|
| 943 |
+
|
| 944 |
+
>>> with local.open_input_file(path) as f:
|
| 945 |
+
... print(f.readall())
|
| 946 |
+
b'data+newly added'
|
| 947 |
+
"""
|
| 948 |
+
cdef:
|
| 949 |
+
c_string pathstr = _path_as_bytes(path)
|
| 950 |
+
NativeFile stream = NativeFile()
|
| 951 |
+
shared_ptr[COutputStream] out_handle
|
| 952 |
+
shared_ptr[const CKeyValueMetadata] c_metadata
|
| 953 |
+
|
| 954 |
+
if metadata is not None:
|
| 955 |
+
c_metadata = pyarrow_unwrap_metadata(KeyValueMetadata(metadata))
|
| 956 |
+
|
| 957 |
+
with nogil:
|
| 958 |
+
out_handle = GetResultValue(
|
| 959 |
+
self.fs.OpenAppendStream(pathstr, c_metadata))
|
| 960 |
+
|
| 961 |
+
stream.set_output_stream(out_handle)
|
| 962 |
+
stream.is_writable = True
|
| 963 |
+
|
| 964 |
+
return self._wrap_output_stream(
|
| 965 |
+
stream, path=path, compression=compression, buffer_size=buffer_size
|
| 966 |
+
)
|
| 967 |
+
|
| 968 |
+
def normalize_path(self, path):
|
| 969 |
+
"""
|
| 970 |
+
Normalize filesystem path.
|
| 971 |
+
|
| 972 |
+
Parameters
|
| 973 |
+
----------
|
| 974 |
+
path : str
|
| 975 |
+
The path to normalize
|
| 976 |
+
|
| 977 |
+
Returns
|
| 978 |
+
-------
|
| 979 |
+
normalized_path : str
|
| 980 |
+
The normalized path
|
| 981 |
+
"""
|
| 982 |
+
cdef:
|
| 983 |
+
c_string c_path = _path_as_bytes(path)
|
| 984 |
+
c_string c_path_normalized
|
| 985 |
+
|
| 986 |
+
c_path_normalized = GetResultValue(self.fs.NormalizePath(c_path))
|
| 987 |
+
return frombytes(c_path_normalized)
|
| 988 |
+
|
| 989 |
+
|
| 990 |
+
cdef class LocalFileSystem(FileSystem):
|
| 991 |
+
"""
|
| 992 |
+
A FileSystem implementation accessing files on the local machine.
|
| 993 |
+
|
| 994 |
+
Details such as symlinks are abstracted away (symlinks are always followed,
|
| 995 |
+
except when deleting an entry).
|
| 996 |
+
|
| 997 |
+
Parameters
|
| 998 |
+
----------
|
| 999 |
+
use_mmap : bool, default False
|
| 1000 |
+
Whether open_input_stream and open_input_file should return
|
| 1001 |
+
a mmap'ed file or a regular file.
|
| 1002 |
+
|
| 1003 |
+
Examples
|
| 1004 |
+
--------
|
| 1005 |
+
Create a FileSystem object with LocalFileSystem constructor:
|
| 1006 |
+
|
| 1007 |
+
>>> from pyarrow import fs
|
| 1008 |
+
>>> local = fs.LocalFileSystem()
|
| 1009 |
+
>>> local
|
| 1010 |
+
<pyarrow._fs.LocalFileSystem object at ...>
|
| 1011 |
+
|
| 1012 |
+
and write data on to the file:
|
| 1013 |
+
|
| 1014 |
+
>>> with local.open_output_stream('/tmp/local_fs.dat') as stream:
|
| 1015 |
+
... stream.write(b'data')
|
| 1016 |
+
4
|
| 1017 |
+
>>> with local.open_input_stream('/tmp/local_fs.dat') as stream:
|
| 1018 |
+
... print(stream.readall())
|
| 1019 |
+
b'data'
|
| 1020 |
+
|
| 1021 |
+
Create a FileSystem object inferred from a URI of the saved file:
|
| 1022 |
+
|
| 1023 |
+
>>> local_new, path = fs.LocalFileSystem().from_uri('/tmp/local_fs.dat')
|
| 1024 |
+
>>> local_new
|
| 1025 |
+
<pyarrow._fs.LocalFileSystem object at ...
|
| 1026 |
+
>>> path
|
| 1027 |
+
'/tmp/local_fs.dat'
|
| 1028 |
+
|
| 1029 |
+
Check if FileSystems `local` and `local_new` are equal:
|
| 1030 |
+
|
| 1031 |
+
>>> local.equals(local_new)
|
| 1032 |
+
True
|
| 1033 |
+
|
| 1034 |
+
Compare two different FileSystems:
|
| 1035 |
+
|
| 1036 |
+
>>> local2 = fs.LocalFileSystem(use_mmap=True)
|
| 1037 |
+
>>> local.equals(local2)
|
| 1038 |
+
False
|
| 1039 |
+
|
| 1040 |
+
Copy a file and print out the data:
|
| 1041 |
+
|
| 1042 |
+
>>> local.copy_file('/tmp/local_fs.dat', '/tmp/local_fs-copy.dat')
|
| 1043 |
+
>>> with local.open_input_stream('/tmp/local_fs-copy.dat') as stream:
|
| 1044 |
+
... print(stream.readall())
|
| 1045 |
+
...
|
| 1046 |
+
b'data'
|
| 1047 |
+
|
| 1048 |
+
Open an output stream for appending, add text and print the new data:
|
| 1049 |
+
|
| 1050 |
+
>>> with local.open_append_stream('/tmp/local_fs-copy.dat') as f:
|
| 1051 |
+
... f.write(b'+newly added')
|
| 1052 |
+
12
|
| 1053 |
+
|
| 1054 |
+
>>> with local.open_input_stream('/tmp/local_fs-copy.dat') as f:
|
| 1055 |
+
... print(f.readall())
|
| 1056 |
+
b'data+newly added'
|
| 1057 |
+
|
| 1058 |
+
Create a directory, copy a file into it and then delete the whole directory:
|
| 1059 |
+
|
| 1060 |
+
>>> local.create_dir('/tmp/new_folder')
|
| 1061 |
+
>>> local.copy_file('/tmp/local_fs.dat', '/tmp/new_folder/local_fs.dat')
|
| 1062 |
+
>>> local.get_file_info('/tmp/new_folder')
|
| 1063 |
+
<FileInfo for '/tmp/new_folder': type=FileType.Directory>
|
| 1064 |
+
>>> local.delete_dir('/tmp/new_folder')
|
| 1065 |
+
>>> local.get_file_info('/tmp/new_folder')
|
| 1066 |
+
<FileInfo for '/tmp/new_folder': type=FileType.NotFound>
|
| 1067 |
+
|
| 1068 |
+
Create a directory, copy a file into it and then delete
|
| 1069 |
+
the content of the directory:
|
| 1070 |
+
|
| 1071 |
+
>>> local.create_dir('/tmp/new_folder')
|
| 1072 |
+
>>> local.copy_file('/tmp/local_fs.dat', '/tmp/new_folder/local_fs.dat')
|
| 1073 |
+
>>> local.get_file_info('/tmp/new_folder/local_fs.dat')
|
| 1074 |
+
<FileInfo for '/tmp/new_folder/local_fs.dat': type=FileType.File, size=4>
|
| 1075 |
+
>>> local.delete_dir_contents('/tmp/new_folder')
|
| 1076 |
+
>>> local.get_file_info('/tmp/new_folder')
|
| 1077 |
+
<FileInfo for '/tmp/new_folder': type=FileType.Directory>
|
| 1078 |
+
>>> local.get_file_info('/tmp/new_folder/local_fs.dat')
|
| 1079 |
+
<FileInfo for '/tmp/new_folder/local_fs.dat': type=FileType.NotFound>
|
| 1080 |
+
|
| 1081 |
+
Create a directory, copy a file into it and then delete
|
| 1082 |
+
the file from the directory:
|
| 1083 |
+
|
| 1084 |
+
>>> local.create_dir('/tmp/new_folder')
|
| 1085 |
+
>>> local.copy_file('/tmp/local_fs.dat', '/tmp/new_folder/local_fs.dat')
|
| 1086 |
+
>>> local.delete_file('/tmp/new_folder/local_fs.dat')
|
| 1087 |
+
>>> local.get_file_info('/tmp/new_folder/local_fs.dat')
|
| 1088 |
+
<FileInfo for '/tmp/new_folder/local_fs.dat': type=FileType.NotFound>
|
| 1089 |
+
>>> local.get_file_info('/tmp/new_folder')
|
| 1090 |
+
<FileInfo for '/tmp/new_folder': type=FileType.Directory>
|
| 1091 |
+
|
| 1092 |
+
Move the file:
|
| 1093 |
+
|
| 1094 |
+
>>> local.move('/tmp/local_fs-copy.dat', '/tmp/new_folder/local_fs-copy.dat')
|
| 1095 |
+
>>> local.get_file_info('/tmp/new_folder/local_fs-copy.dat')
|
| 1096 |
+
<FileInfo for '/tmp/new_folder/local_fs-copy.dat': type=FileType.File, size=16>
|
| 1097 |
+
>>> local.get_file_info('/tmp/local_fs-copy.dat')
|
| 1098 |
+
<FileInfo for '/tmp/local_fs-copy.dat': type=FileType.NotFound>
|
| 1099 |
+
|
| 1100 |
+
To finish delete the file left:
|
| 1101 |
+
>>> local.delete_file('/tmp/local_fs.dat')
|
| 1102 |
+
"""
|
| 1103 |
+
|
| 1104 |
+
def __init__(self, *, use_mmap=False):
|
| 1105 |
+
cdef:
|
| 1106 |
+
shared_ptr[CFileSystem] fs
|
| 1107 |
+
c_string c_uri
|
| 1108 |
+
|
| 1109 |
+
# from_uri needs a non-empty path, so just use a placeholder of /_
|
| 1110 |
+
c_uri = tobytes(f"file:///_?use_mmap={int(use_mmap)}")
|
| 1111 |
+
with nogil:
|
| 1112 |
+
fs = GetResultValue(CFileSystemFromUri(c_uri))
|
| 1113 |
+
self.init(<shared_ptr[CFileSystem]> fs)
|
| 1114 |
+
|
| 1115 |
+
def __reduce__(self):
|
| 1116 |
+
uri = frombytes(GetResultValue(self.fs.MakeUri(b"/_")))
|
| 1117 |
+
return FileSystem._from_uri, (uri,)
|
| 1118 |
+
|
| 1119 |
+
|
| 1120 |
+
cdef class SubTreeFileSystem(FileSystem):
|
| 1121 |
+
"""
|
| 1122 |
+
Delegates to another implementation after prepending a fixed base path.
|
| 1123 |
+
|
| 1124 |
+
This is useful to expose a logical view of a subtree of a filesystem,
|
| 1125 |
+
for example a directory in a LocalFileSystem.
|
| 1126 |
+
|
| 1127 |
+
Note, that this makes no security guarantee. For example, symlinks may
|
| 1128 |
+
allow to "escape" the subtree and access other parts of the underlying
|
| 1129 |
+
filesystem.
|
| 1130 |
+
|
| 1131 |
+
Parameters
|
| 1132 |
+
----------
|
| 1133 |
+
base_path : str
|
| 1134 |
+
The root of the subtree.
|
| 1135 |
+
base_fs : FileSystem
|
| 1136 |
+
FileSystem object the operations delegated to.
|
| 1137 |
+
|
| 1138 |
+
Examples
|
| 1139 |
+
--------
|
| 1140 |
+
Create a LocalFileSystem instance:
|
| 1141 |
+
|
| 1142 |
+
>>> from pyarrow import fs
|
| 1143 |
+
>>> local = fs.LocalFileSystem()
|
| 1144 |
+
>>> with local.open_output_stream('/tmp/local_fs.dat') as stream:
|
| 1145 |
+
... stream.write(b'data')
|
| 1146 |
+
4
|
| 1147 |
+
|
| 1148 |
+
Create a directory and a SubTreeFileSystem instance:
|
| 1149 |
+
|
| 1150 |
+
>>> local.create_dir('/tmp/sub_tree')
|
| 1151 |
+
>>> subtree = fs.SubTreeFileSystem('/tmp/sub_tree', local)
|
| 1152 |
+
|
| 1153 |
+
Write data into the existing file:
|
| 1154 |
+
|
| 1155 |
+
>>> with subtree.open_append_stream('sub_tree_fs.dat') as f:
|
| 1156 |
+
... f.write(b'+newly added')
|
| 1157 |
+
12
|
| 1158 |
+
|
| 1159 |
+
Print out the attributes:
|
| 1160 |
+
|
| 1161 |
+
>>> subtree.base_fs
|
| 1162 |
+
<pyarrow._fs.LocalFileSystem object at ...>
|
| 1163 |
+
>>> subtree.base_path
|
| 1164 |
+
'/tmp/sub_tree/'
|
| 1165 |
+
|
| 1166 |
+
Get info for the given directory or given file:
|
| 1167 |
+
|
| 1168 |
+
>>> subtree.get_file_info('')
|
| 1169 |
+
<FileInfo for '': type=FileType.Directory>
|
| 1170 |
+
>>> subtree.get_file_info('sub_tree_fs.dat')
|
| 1171 |
+
<FileInfo for 'sub_tree_fs.dat': type=FileType.File, size=12>
|
| 1172 |
+
|
| 1173 |
+
Delete the file and directory:
|
| 1174 |
+
|
| 1175 |
+
>>> subtree.delete_file('sub_tree_fs.dat')
|
| 1176 |
+
>>> local.delete_dir('/tmp/sub_tree')
|
| 1177 |
+
>>> local.delete_file('/tmp/local_fs.dat')
|
| 1178 |
+
|
| 1179 |
+
For usage of the methods see examples for :func:`~pyarrow.fs.LocalFileSystem`.
|
| 1180 |
+
"""
|
| 1181 |
+
|
| 1182 |
+
def __init__(self, base_path, FileSystem base_fs):
|
| 1183 |
+
cdef:
|
| 1184 |
+
c_string pathstr
|
| 1185 |
+
shared_ptr[CSubTreeFileSystem] wrapped
|
| 1186 |
+
|
| 1187 |
+
pathstr = _path_as_bytes(base_path)
|
| 1188 |
+
wrapped = make_shared[CSubTreeFileSystem](pathstr, base_fs.wrapped)
|
| 1189 |
+
|
| 1190 |
+
self.init(<shared_ptr[CFileSystem]> wrapped)
|
| 1191 |
+
|
| 1192 |
+
cdef init(self, const shared_ptr[CFileSystem]& wrapped):
|
| 1193 |
+
FileSystem.init(self, wrapped)
|
| 1194 |
+
self.subtreefs = <CSubTreeFileSystem*> wrapped.get()
|
| 1195 |
+
|
| 1196 |
+
def __repr__(self):
|
| 1197 |
+
return ("SubTreeFileSystem(base_path={}, base_fs={}"
|
| 1198 |
+
.format(self.base_path, self.base_fs))
|
| 1199 |
+
|
| 1200 |
+
def __reduce__(self):
|
| 1201 |
+
return SubTreeFileSystem, (
|
| 1202 |
+
frombytes(self.subtreefs.base_path()),
|
| 1203 |
+
FileSystem.wrap(self.subtreefs.base_fs())
|
| 1204 |
+
)
|
| 1205 |
+
|
| 1206 |
+
@property
|
| 1207 |
+
def base_path(self):
|
| 1208 |
+
return frombytes(self.subtreefs.base_path())
|
| 1209 |
+
|
| 1210 |
+
@property
|
| 1211 |
+
def base_fs(self):
|
| 1212 |
+
return FileSystem.wrap(self.subtreefs.base_fs())
|
| 1213 |
+
|
| 1214 |
+
|
| 1215 |
+
cdef class _MockFileSystem(FileSystem):
|
| 1216 |
+
|
| 1217 |
+
def __init__(self, datetime current_time=None):
|
| 1218 |
+
cdef shared_ptr[CMockFileSystem] wrapped
|
| 1219 |
+
|
| 1220 |
+
current_time = current_time or datetime.now()
|
| 1221 |
+
wrapped = make_shared[CMockFileSystem](
|
| 1222 |
+
PyDateTime_to_TimePoint(<PyDateTime_DateTime*> current_time)
|
| 1223 |
+
)
|
| 1224 |
+
|
| 1225 |
+
self.init(<shared_ptr[CFileSystem]> wrapped)
|
| 1226 |
+
|
| 1227 |
+
cdef init(self, const shared_ptr[CFileSystem]& wrapped):
|
| 1228 |
+
FileSystem.init(self, wrapped)
|
| 1229 |
+
self.mockfs = <CMockFileSystem*> wrapped.get()
|
| 1230 |
+
|
| 1231 |
+
|
| 1232 |
+
cdef class PyFileSystem(FileSystem):
|
| 1233 |
+
"""
|
| 1234 |
+
A FileSystem with behavior implemented in Python.
|
| 1235 |
+
|
| 1236 |
+
Parameters
|
| 1237 |
+
----------
|
| 1238 |
+
handler : FileSystemHandler
|
| 1239 |
+
The handler object implementing custom filesystem behavior.
|
| 1240 |
+
|
| 1241 |
+
Examples
|
| 1242 |
+
--------
|
| 1243 |
+
Create an fsspec-based filesystem object for GitHub:
|
| 1244 |
+
|
| 1245 |
+
>>> from fsspec.implementations import github
|
| 1246 |
+
>>> gfs = github.GithubFileSystem('apache', 'arrow') # doctest: +SKIP
|
| 1247 |
+
|
| 1248 |
+
Get a PyArrow FileSystem object:
|
| 1249 |
+
|
| 1250 |
+
>>> from pyarrow.fs import PyFileSystem, FSSpecHandler
|
| 1251 |
+
>>> pa_fs = PyFileSystem(FSSpecHandler(gfs)) # doctest: +SKIP
|
| 1252 |
+
|
| 1253 |
+
Use :func:`~pyarrow.fs.FileSystem` functionality ``get_file_info()``:
|
| 1254 |
+
|
| 1255 |
+
>>> pa_fs.get_file_info('README.md') # doctest: +SKIP
|
| 1256 |
+
<FileInfo for 'README.md': type=FileType.File, size=...>
|
| 1257 |
+
"""
|
| 1258 |
+
|
| 1259 |
+
def __init__(self, handler):
|
| 1260 |
+
cdef:
|
| 1261 |
+
CPyFileSystemVtable vtable
|
| 1262 |
+
shared_ptr[CPyFileSystem] wrapped
|
| 1263 |
+
|
| 1264 |
+
if not isinstance(handler, FileSystemHandler):
|
| 1265 |
+
raise TypeError("Expected a FileSystemHandler instance, got {0}"
|
| 1266 |
+
.format(type(handler)))
|
| 1267 |
+
|
| 1268 |
+
vtable.get_type_name = _cb_get_type_name
|
| 1269 |
+
vtable.equals = _cb_equals
|
| 1270 |
+
vtable.get_file_info = _cb_get_file_info
|
| 1271 |
+
vtable.get_file_info_vector = _cb_get_file_info_vector
|
| 1272 |
+
vtable.get_file_info_selector = _cb_get_file_info_selector
|
| 1273 |
+
vtable.create_dir = _cb_create_dir
|
| 1274 |
+
vtable.delete_dir = _cb_delete_dir
|
| 1275 |
+
vtable.delete_dir_contents = _cb_delete_dir_contents
|
| 1276 |
+
vtable.delete_root_dir_contents = _cb_delete_root_dir_contents
|
| 1277 |
+
vtable.delete_file = _cb_delete_file
|
| 1278 |
+
vtable.move = _cb_move
|
| 1279 |
+
vtable.copy_file = _cb_copy_file
|
| 1280 |
+
vtable.open_input_stream = _cb_open_input_stream
|
| 1281 |
+
vtable.open_input_file = _cb_open_input_file
|
| 1282 |
+
vtable.open_output_stream = _cb_open_output_stream
|
| 1283 |
+
vtable.open_append_stream = _cb_open_append_stream
|
| 1284 |
+
vtable.normalize_path = _cb_normalize_path
|
| 1285 |
+
|
| 1286 |
+
wrapped = CPyFileSystem.Make(handler, move(vtable))
|
| 1287 |
+
self.init(<shared_ptr[CFileSystem]> wrapped)
|
| 1288 |
+
|
| 1289 |
+
cdef init(self, const shared_ptr[CFileSystem]& wrapped):
|
| 1290 |
+
FileSystem.init(self, wrapped)
|
| 1291 |
+
self.pyfs = <CPyFileSystem*> wrapped.get()
|
| 1292 |
+
|
| 1293 |
+
@property
|
| 1294 |
+
def handler(self):
|
| 1295 |
+
"""
|
| 1296 |
+
The filesystem's underlying handler.
|
| 1297 |
+
|
| 1298 |
+
Returns
|
| 1299 |
+
-------
|
| 1300 |
+
handler : FileSystemHandler
|
| 1301 |
+
"""
|
| 1302 |
+
return <object> self.pyfs.handler()
|
| 1303 |
+
|
| 1304 |
+
def __reduce__(self):
|
| 1305 |
+
return PyFileSystem, (self.handler,)
|
| 1306 |
+
|
| 1307 |
+
|
| 1308 |
+
class FileSystemHandler(ABC):
|
| 1309 |
+
"""
|
| 1310 |
+
An abstract class exposing methods to implement PyFileSystem's behavior.
|
| 1311 |
+
"""
|
| 1312 |
+
|
| 1313 |
+
@abstractmethod
|
| 1314 |
+
def get_type_name(self):
|
| 1315 |
+
"""
|
| 1316 |
+
Implement PyFileSystem.type_name.
|
| 1317 |
+
"""
|
| 1318 |
+
|
| 1319 |
+
@abstractmethod
|
| 1320 |
+
def get_file_info(self, paths):
|
| 1321 |
+
"""
|
| 1322 |
+
Implement PyFileSystem.get_file_info(paths).
|
| 1323 |
+
|
| 1324 |
+
Parameters
|
| 1325 |
+
----------
|
| 1326 |
+
paths : list of str
|
| 1327 |
+
paths for which we want to retrieve the info.
|
| 1328 |
+
"""
|
| 1329 |
+
|
| 1330 |
+
@abstractmethod
|
| 1331 |
+
def get_file_info_selector(self, selector):
|
| 1332 |
+
"""
|
| 1333 |
+
Implement PyFileSystem.get_file_info(selector).
|
| 1334 |
+
|
| 1335 |
+
Parameters
|
| 1336 |
+
----------
|
| 1337 |
+
selector : FileSelector
|
| 1338 |
+
selector for which we want to retrieve the info.
|
| 1339 |
+
"""
|
| 1340 |
+
|
| 1341 |
+
@abstractmethod
|
| 1342 |
+
def create_dir(self, path, recursive):
|
| 1343 |
+
"""
|
| 1344 |
+
Implement PyFileSystem.create_dir(...).
|
| 1345 |
+
|
| 1346 |
+
Parameters
|
| 1347 |
+
----------
|
| 1348 |
+
path : str
|
| 1349 |
+
path of the directory.
|
| 1350 |
+
recursive : bool
|
| 1351 |
+
if the parent directories should be created too.
|
| 1352 |
+
"""
|
| 1353 |
+
|
| 1354 |
+
@abstractmethod
|
| 1355 |
+
def delete_dir(self, path):
|
| 1356 |
+
"""
|
| 1357 |
+
Implement PyFileSystem.delete_dir(...).
|
| 1358 |
+
|
| 1359 |
+
Parameters
|
| 1360 |
+
----------
|
| 1361 |
+
path : str
|
| 1362 |
+
path of the directory.
|
| 1363 |
+
"""
|
| 1364 |
+
|
| 1365 |
+
@abstractmethod
|
| 1366 |
+
def delete_dir_contents(self, path, missing_dir_ok=False):
|
| 1367 |
+
"""
|
| 1368 |
+
Implement PyFileSystem.delete_dir_contents(...).
|
| 1369 |
+
|
| 1370 |
+
Parameters
|
| 1371 |
+
----------
|
| 1372 |
+
path : str
|
| 1373 |
+
path of the directory.
|
| 1374 |
+
missing_dir_ok : bool
|
| 1375 |
+
if False an error should be raised if path does not exist
|
| 1376 |
+
"""
|
| 1377 |
+
|
| 1378 |
+
@abstractmethod
|
| 1379 |
+
def delete_root_dir_contents(self):
|
| 1380 |
+
"""
|
| 1381 |
+
Implement PyFileSystem.delete_dir_contents("/", accept_root_dir=True).
|
| 1382 |
+
"""
|
| 1383 |
+
|
| 1384 |
+
@abstractmethod
|
| 1385 |
+
def delete_file(self, path):
|
| 1386 |
+
"""
|
| 1387 |
+
Implement PyFileSystem.delete_file(...).
|
| 1388 |
+
|
| 1389 |
+
Parameters
|
| 1390 |
+
----------
|
| 1391 |
+
path : str
|
| 1392 |
+
path of the file.
|
| 1393 |
+
"""
|
| 1394 |
+
|
| 1395 |
+
@abstractmethod
|
| 1396 |
+
def move(self, src, dest):
|
| 1397 |
+
"""
|
| 1398 |
+
Implement PyFileSystem.move(...).
|
| 1399 |
+
|
| 1400 |
+
Parameters
|
| 1401 |
+
----------
|
| 1402 |
+
src : str
|
| 1403 |
+
path of what should be moved.
|
| 1404 |
+
dest : str
|
| 1405 |
+
path of where it should be moved to.
|
| 1406 |
+
"""
|
| 1407 |
+
|
| 1408 |
+
@abstractmethod
|
| 1409 |
+
def copy_file(self, src, dest):
|
| 1410 |
+
"""
|
| 1411 |
+
Implement PyFileSystem.copy_file(...).
|
| 1412 |
+
|
| 1413 |
+
Parameters
|
| 1414 |
+
----------
|
| 1415 |
+
src : str
|
| 1416 |
+
path of what should be copied.
|
| 1417 |
+
dest : str
|
| 1418 |
+
path of where it should be copied to.
|
| 1419 |
+
"""
|
| 1420 |
+
|
| 1421 |
+
@abstractmethod
|
| 1422 |
+
def open_input_stream(self, path):
|
| 1423 |
+
"""
|
| 1424 |
+
Implement PyFileSystem.open_input_stream(...).
|
| 1425 |
+
|
| 1426 |
+
Parameters
|
| 1427 |
+
----------
|
| 1428 |
+
path : str
|
| 1429 |
+
path of what should be opened.
|
| 1430 |
+
"""
|
| 1431 |
+
|
| 1432 |
+
@abstractmethod
|
| 1433 |
+
def open_input_file(self, path):
|
| 1434 |
+
"""
|
| 1435 |
+
Implement PyFileSystem.open_input_file(...).
|
| 1436 |
+
|
| 1437 |
+
Parameters
|
| 1438 |
+
----------
|
| 1439 |
+
path : str
|
| 1440 |
+
path of what should be opened.
|
| 1441 |
+
"""
|
| 1442 |
+
|
| 1443 |
+
@abstractmethod
|
| 1444 |
+
def open_output_stream(self, path, metadata):
|
| 1445 |
+
"""
|
| 1446 |
+
Implement PyFileSystem.open_output_stream(...).
|
| 1447 |
+
|
| 1448 |
+
Parameters
|
| 1449 |
+
----------
|
| 1450 |
+
path : str
|
| 1451 |
+
path of what should be opened.
|
| 1452 |
+
metadata : mapping
|
| 1453 |
+
Mapping of string keys to string values.
|
| 1454 |
+
Some filesystems support storing metadata along the file
|
| 1455 |
+
(such as "Content-Type").
|
| 1456 |
+
"""
|
| 1457 |
+
|
| 1458 |
+
@abstractmethod
|
| 1459 |
+
def open_append_stream(self, path, metadata):
|
| 1460 |
+
"""
|
| 1461 |
+
Implement PyFileSystem.open_append_stream(...).
|
| 1462 |
+
|
| 1463 |
+
Parameters
|
| 1464 |
+
----------
|
| 1465 |
+
path : str
|
| 1466 |
+
path of what should be opened.
|
| 1467 |
+
metadata : mapping
|
| 1468 |
+
Mapping of string keys to string values.
|
| 1469 |
+
Some filesystems support storing metadata along the file
|
| 1470 |
+
(such as "Content-Type").
|
| 1471 |
+
"""
|
| 1472 |
+
|
| 1473 |
+
@abstractmethod
|
| 1474 |
+
def normalize_path(self, path):
|
| 1475 |
+
"""
|
| 1476 |
+
Implement PyFileSystem.normalize_path(...).
|
| 1477 |
+
|
| 1478 |
+
Parameters
|
| 1479 |
+
----------
|
| 1480 |
+
path : str
|
| 1481 |
+
path of what should be normalized.
|
| 1482 |
+
"""
|
| 1483 |
+
|
| 1484 |
+
# Callback definitions for CPyFileSystemVtable
|
| 1485 |
+
|
| 1486 |
+
|
| 1487 |
+
cdef void _cb_get_type_name(handler, c_string* out) except *:
|
| 1488 |
+
out[0] = tobytes("py::" + handler.get_type_name())
|
| 1489 |
+
|
| 1490 |
+
cdef c_bool _cb_equals(handler, const CFileSystem& c_other) except False:
|
| 1491 |
+
if c_other.type_name().startswith(b"py::"):
|
| 1492 |
+
return <object> (<const CPyFileSystem&> c_other).handler() == handler
|
| 1493 |
+
|
| 1494 |
+
return False
|
| 1495 |
+
|
| 1496 |
+
cdef void _cb_get_file_info(handler, const c_string& path,
|
| 1497 |
+
CFileInfo* out) except *:
|
| 1498 |
+
infos = handler.get_file_info([frombytes(path)])
|
| 1499 |
+
if not isinstance(infos, list) or len(infos) != 1:
|
| 1500 |
+
raise TypeError("get_file_info should have returned a 1-element list")
|
| 1501 |
+
out[0] = FileInfo.unwrap_safe(infos[0])
|
| 1502 |
+
|
| 1503 |
+
cdef void _cb_get_file_info_vector(handler, const vector[c_string]& paths,
|
| 1504 |
+
vector[CFileInfo]* out) except *:
|
| 1505 |
+
py_paths = [frombytes(paths[i]) for i in range(len(paths))]
|
| 1506 |
+
infos = handler.get_file_info(py_paths)
|
| 1507 |
+
if not isinstance(infos, list):
|
| 1508 |
+
raise TypeError("get_file_info should have returned a list")
|
| 1509 |
+
out[0].clear()
|
| 1510 |
+
out[0].reserve(len(infos))
|
| 1511 |
+
for info in infos:
|
| 1512 |
+
out[0].push_back(FileInfo.unwrap_safe(info))
|
| 1513 |
+
|
| 1514 |
+
cdef void _cb_get_file_info_selector(handler, const CFileSelector& selector,
|
| 1515 |
+
vector[CFileInfo]* out) except *:
|
| 1516 |
+
infos = handler.get_file_info_selector(FileSelector.wrap(selector))
|
| 1517 |
+
if not isinstance(infos, list):
|
| 1518 |
+
raise TypeError("get_file_info_selector should have returned a list")
|
| 1519 |
+
out[0].clear()
|
| 1520 |
+
out[0].reserve(len(infos))
|
| 1521 |
+
for info in infos:
|
| 1522 |
+
out[0].push_back(FileInfo.unwrap_safe(info))
|
| 1523 |
+
|
| 1524 |
+
cdef void _cb_create_dir(handler, const c_string& path,
|
| 1525 |
+
c_bool recursive) except *:
|
| 1526 |
+
handler.create_dir(frombytes(path), recursive)
|
| 1527 |
+
|
| 1528 |
+
cdef void _cb_delete_dir(handler, const c_string& path) except *:
|
| 1529 |
+
handler.delete_dir(frombytes(path))
|
| 1530 |
+
|
| 1531 |
+
cdef void _cb_delete_dir_contents(handler, const c_string& path,
|
| 1532 |
+
c_bool missing_dir_ok) except *:
|
| 1533 |
+
handler.delete_dir_contents(frombytes(path), missing_dir_ok)
|
| 1534 |
+
|
| 1535 |
+
cdef void _cb_delete_root_dir_contents(handler) except *:
|
| 1536 |
+
handler.delete_root_dir_contents()
|
| 1537 |
+
|
| 1538 |
+
cdef void _cb_delete_file(handler, const c_string& path) except *:
|
| 1539 |
+
handler.delete_file(frombytes(path))
|
| 1540 |
+
|
| 1541 |
+
cdef void _cb_move(handler, const c_string& src,
|
| 1542 |
+
const c_string& dest) except *:
|
| 1543 |
+
handler.move(frombytes(src), frombytes(dest))
|
| 1544 |
+
|
| 1545 |
+
cdef void _cb_copy_file(handler, const c_string& src,
|
| 1546 |
+
const c_string& dest) except *:
|
| 1547 |
+
handler.copy_file(frombytes(src), frombytes(dest))
|
| 1548 |
+
|
| 1549 |
+
cdef void _cb_open_input_stream(handler, const c_string& path,
|
| 1550 |
+
shared_ptr[CInputStream]* out) except *:
|
| 1551 |
+
stream = handler.open_input_stream(frombytes(path))
|
| 1552 |
+
if not isinstance(stream, NativeFile):
|
| 1553 |
+
raise TypeError("open_input_stream should have returned "
|
| 1554 |
+
"a PyArrow file")
|
| 1555 |
+
out[0] = (<NativeFile> stream).get_input_stream()
|
| 1556 |
+
|
| 1557 |
+
cdef void _cb_open_input_file(handler, const c_string& path,
|
| 1558 |
+
shared_ptr[CRandomAccessFile]* out) except *:
|
| 1559 |
+
stream = handler.open_input_file(frombytes(path))
|
| 1560 |
+
if not isinstance(stream, NativeFile):
|
| 1561 |
+
raise TypeError("open_input_file should have returned "
|
| 1562 |
+
"a PyArrow file")
|
| 1563 |
+
out[0] = (<NativeFile> stream).get_random_access_file()
|
| 1564 |
+
|
| 1565 |
+
cdef void _cb_open_output_stream(
|
| 1566 |
+
handler, const c_string& path,
|
| 1567 |
+
const shared_ptr[const CKeyValueMetadata]& metadata,
|
| 1568 |
+
shared_ptr[COutputStream]* out) except *:
|
| 1569 |
+
stream = handler.open_output_stream(
|
| 1570 |
+
frombytes(path), pyarrow_wrap_metadata(metadata))
|
| 1571 |
+
if not isinstance(stream, NativeFile):
|
| 1572 |
+
raise TypeError("open_output_stream should have returned "
|
| 1573 |
+
"a PyArrow file")
|
| 1574 |
+
out[0] = (<NativeFile> stream).get_output_stream()
|
| 1575 |
+
|
| 1576 |
+
cdef void _cb_open_append_stream(
|
| 1577 |
+
handler, const c_string& path,
|
| 1578 |
+
const shared_ptr[const CKeyValueMetadata]& metadata,
|
| 1579 |
+
shared_ptr[COutputStream]* out) except *:
|
| 1580 |
+
stream = handler.open_append_stream(
|
| 1581 |
+
frombytes(path), pyarrow_wrap_metadata(metadata))
|
| 1582 |
+
if not isinstance(stream, NativeFile):
|
| 1583 |
+
raise TypeError("open_append_stream should have returned "
|
| 1584 |
+
"a PyArrow file")
|
| 1585 |
+
out[0] = (<NativeFile> stream).get_output_stream()
|
| 1586 |
+
|
| 1587 |
+
cdef void _cb_normalize_path(handler, const c_string& path,
|
| 1588 |
+
c_string* out) except *:
|
| 1589 |
+
out[0] = tobytes(handler.normalize_path(frombytes(path)))
|
| 1590 |
+
|
| 1591 |
+
|
| 1592 |
+
def _copy_files(FileSystem source_fs, str source_path,
|
| 1593 |
+
FileSystem destination_fs, str destination_path,
|
| 1594 |
+
int64_t chunk_size, c_bool use_threads):
|
| 1595 |
+
# low-level helper exposed through pyarrow/fs.py::copy_files
|
| 1596 |
+
cdef:
|
| 1597 |
+
CFileLocator c_source
|
| 1598 |
+
vector[CFileLocator] c_sources
|
| 1599 |
+
CFileLocator c_destination
|
| 1600 |
+
vector[CFileLocator] c_destinations
|
| 1601 |
+
|
| 1602 |
+
c_source.filesystem = source_fs.unwrap()
|
| 1603 |
+
c_source.path = tobytes(source_path)
|
| 1604 |
+
c_sources.push_back(c_source)
|
| 1605 |
+
|
| 1606 |
+
c_destination.filesystem = destination_fs.unwrap()
|
| 1607 |
+
c_destination.path = tobytes(destination_path)
|
| 1608 |
+
c_destinations.push_back(c_destination)
|
| 1609 |
+
|
| 1610 |
+
with nogil:
|
| 1611 |
+
check_status(CCopyFiles(
|
| 1612 |
+
c_sources, c_destinations,
|
| 1613 |
+
c_default_io_context(), chunk_size, use_threads,
|
| 1614 |
+
))
|
| 1615 |
+
|
| 1616 |
+
|
| 1617 |
+
def _copy_files_selector(FileSystem source_fs, FileSelector source_sel,
|
| 1618 |
+
FileSystem destination_fs, str destination_base_dir,
|
| 1619 |
+
int64_t chunk_size, c_bool use_threads):
|
| 1620 |
+
# low-level helper exposed through pyarrow/fs.py::copy_files
|
| 1621 |
+
cdef c_string c_destination_base_dir = tobytes(destination_base_dir)
|
| 1622 |
+
|
| 1623 |
+
with nogil:
|
| 1624 |
+
check_status(CCopyFilesWithSelector(
|
| 1625 |
+
source_fs.unwrap(), source_sel.unwrap(),
|
| 1626 |
+
destination_fs.unwrap(), c_destination_base_dir,
|
| 1627 |
+
c_default_io_context(), chunk_size, use_threads,
|
| 1628 |
+
))
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/pyarrow/_orc.pxd
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Licensed to the Apache Software Foundation (ASF) under one
|
| 2 |
+
# or more contributor license agreements. See the NOTICE file
|
| 3 |
+
# distributed with this work for additional information
|
| 4 |
+
# regarding copyright ownership. The ASF licenses this file
|
| 5 |
+
# to you under the Apache License, Version 2.0 (the
|
| 6 |
+
# "License"); you may not use this file except in compliance
|
| 7 |
+
# with the License. You may obtain a copy of the License at
|
| 8 |
+
#
|
| 9 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 10 |
+
#
|
| 11 |
+
# Unless required by applicable law or agreed to in writing,
|
| 12 |
+
# software distributed under the License is distributed on an
|
| 13 |
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
| 14 |
+
# KIND, either express or implied. See the License for the
|
| 15 |
+
# specific language governing permissions and limitations
|
| 16 |
+
# under the License.
|
| 17 |
+
|
| 18 |
+
# distutils: language = c++
|
| 19 |
+
# cython: language_level = 3
|
| 20 |
+
|
| 21 |
+
from libcpp cimport bool as c_bool
|
| 22 |
+
from libc.string cimport const_char
|
| 23 |
+
from libcpp.vector cimport vector as std_vector
|
| 24 |
+
from pyarrow.includes.common cimport *
|
| 25 |
+
from pyarrow.includes.libarrow cimport (CArray, CSchema, CStatus,
|
| 26 |
+
CResult, CTable, CMemoryPool,
|
| 27 |
+
CKeyValueMetadata,
|
| 28 |
+
CRecordBatch,
|
| 29 |
+
CTable, CCompressionType,
|
| 30 |
+
CRandomAccessFile, COutputStream,
|
| 31 |
+
TimeUnit)
|
| 32 |
+
|
| 33 |
+
cdef extern from "arrow/adapters/orc/options.h" \
|
| 34 |
+
namespace "arrow::adapters::orc" nogil:
|
| 35 |
+
cdef enum CompressionStrategy \
|
| 36 |
+
" arrow::adapters::orc::CompressionStrategy":
|
| 37 |
+
_CompressionStrategy_SPEED \
|
| 38 |
+
" arrow::adapters::orc::CompressionStrategy::kSpeed"
|
| 39 |
+
_CompressionStrategy_COMPRESSION \
|
| 40 |
+
" arrow::adapters::orc::CompressionStrategy::kCompression"
|
| 41 |
+
|
| 42 |
+
cdef enum WriterId" arrow::adapters::orc::WriterId":
|
| 43 |
+
_WriterId_ORC_JAVA_WRITER" arrow::adapters::orc::WriterId::kOrcJava"
|
| 44 |
+
_WriterId_ORC_CPP_WRITER" arrow::adapters::orc::WriterId::kOrcCpp"
|
| 45 |
+
_WriterId_PRESTO_WRITER" arrow::adapters::orc::WriterId::kPresto"
|
| 46 |
+
_WriterId_SCRITCHLEY_GO \
|
| 47 |
+
" arrow::adapters::orc::WriterId::kScritchleyGo"
|
| 48 |
+
_WriterId_TRINO_WRITER" arrow::adapters::orc::WriterId::kTrino"
|
| 49 |
+
_WriterId_UNKNOWN_WRITER" arrow::adapters::orc::WriterId::kUnknown"
|
| 50 |
+
|
| 51 |
+
cdef enum WriterVersion" arrow::adapters::orc::WriterVersion":
|
| 52 |
+
_WriterVersion_ORIGINAL \
|
| 53 |
+
" arrow::adapters::orc::WriterVersion::kOriginal"
|
| 54 |
+
_WriterVersion_HIVE_8732 \
|
| 55 |
+
" arrow::adapters::orc::WriterVersion::kHive8732"
|
| 56 |
+
_WriterVersion_HIVE_4243 \
|
| 57 |
+
" arrow::adapters::orc::WriterVersion::kHive4243"
|
| 58 |
+
_WriterVersion_HIVE_12055 \
|
| 59 |
+
" arrow::adapters::orc::WriterVersion::kHive12055"
|
| 60 |
+
_WriterVersion_HIVE_13083 \
|
| 61 |
+
" arrow::adapters::orc::WriterVersion::kHive13083"
|
| 62 |
+
_WriterVersion_ORC_101" arrow::adapters::orc::WriterVersion::kOrc101"
|
| 63 |
+
_WriterVersion_ORC_135" arrow::adapters::orc::WriterVersion::kOrc135"
|
| 64 |
+
_WriterVersion_ORC_517" arrow::adapters::orc::WriterVersion::kOrc517"
|
| 65 |
+
_WriterVersion_ORC_203" arrow::adapters::orc::WriterVersion::kOrc203"
|
| 66 |
+
_WriterVersion_ORC_14" arrow::adapters::orc::WriterVersion::kOrc14"
|
| 67 |
+
_WriterVersion_MAX" arrow::adapters::orc::WriterVersion::kMax"
|
| 68 |
+
|
| 69 |
+
cdef cppclass FileVersion" arrow::adapters::orc::FileVersion":
|
| 70 |
+
FileVersion(uint32_t major_version, uint32_t minor_version)
|
| 71 |
+
uint32_t major_version()
|
| 72 |
+
uint32_t minor_version()
|
| 73 |
+
c_string ToString()
|
| 74 |
+
|
| 75 |
+
cdef struct WriteOptions" arrow::adapters::orc::WriteOptions":
|
| 76 |
+
int64_t batch_size
|
| 77 |
+
FileVersion file_version
|
| 78 |
+
int64_t stripe_size
|
| 79 |
+
CCompressionType compression
|
| 80 |
+
int64_t compression_block_size
|
| 81 |
+
CompressionStrategy compression_strategy
|
| 82 |
+
int64_t row_index_stride
|
| 83 |
+
double padding_tolerance
|
| 84 |
+
double dictionary_key_size_threshold
|
| 85 |
+
std_vector[int64_t] bloom_filter_columns
|
| 86 |
+
double bloom_filter_fpp
|
| 87 |
+
|
| 88 |
+
|
| 89 |
+
cdef extern from "arrow/adapters/orc/adapter.h" \
|
| 90 |
+
namespace "arrow::adapters::orc" nogil:
|
| 91 |
+
|
| 92 |
+
cdef cppclass ORCFileReader:
|
| 93 |
+
@staticmethod
|
| 94 |
+
CResult[unique_ptr[ORCFileReader]] Open(
|
| 95 |
+
const shared_ptr[CRandomAccessFile]& file,
|
| 96 |
+
CMemoryPool* pool)
|
| 97 |
+
|
| 98 |
+
CResult[shared_ptr[const CKeyValueMetadata]] ReadMetadata()
|
| 99 |
+
|
| 100 |
+
CResult[shared_ptr[CSchema]] ReadSchema()
|
| 101 |
+
|
| 102 |
+
CResult[shared_ptr[CRecordBatch]] ReadStripe(int64_t stripe)
|
| 103 |
+
CResult[shared_ptr[CRecordBatch]] ReadStripe(
|
| 104 |
+
int64_t stripe, std_vector[c_string])
|
| 105 |
+
|
| 106 |
+
CResult[shared_ptr[CTable]] Read()
|
| 107 |
+
CResult[shared_ptr[CTable]] Read(std_vector[c_string])
|
| 108 |
+
|
| 109 |
+
int64_t NumberOfStripes()
|
| 110 |
+
int64_t NumberOfRows()
|
| 111 |
+
FileVersion GetFileVersion()
|
| 112 |
+
c_string GetSoftwareVersion()
|
| 113 |
+
CResult[CCompressionType] GetCompression()
|
| 114 |
+
int64_t GetCompressionSize()
|
| 115 |
+
int64_t GetRowIndexStride()
|
| 116 |
+
WriterId GetWriterId()
|
| 117 |
+
int32_t GetWriterIdValue()
|
| 118 |
+
WriterVersion GetWriterVersion()
|
| 119 |
+
int64_t GetNumberOfStripeStatistics()
|
| 120 |
+
int64_t GetContentLength()
|
| 121 |
+
int64_t GetStripeStatisticsLength()
|
| 122 |
+
int64_t GetFileFooterLength()
|
| 123 |
+
int64_t GetFilePostscriptLength()
|
| 124 |
+
int64_t GetFileLength()
|
| 125 |
+
c_string GetSerializedFileTail()
|
| 126 |
+
|
| 127 |
+
cdef cppclass ORCFileWriter:
|
| 128 |
+
@staticmethod
|
| 129 |
+
CResult[unique_ptr[ORCFileWriter]] Open(
|
| 130 |
+
COutputStream* output_stream, const WriteOptions& writer_options)
|
| 131 |
+
|
| 132 |
+
CStatus Write(const CTable& table)
|
| 133 |
+
|
| 134 |
+
CStatus Close()
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/pyarrow/_s3fs.pyx
ADDED
|
@@ -0,0 +1,479 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Licensed to the Apache Software Foundation (ASF) under one
|
| 2 |
+
# or more contributor license agreements. See the NOTICE file
|
| 3 |
+
# distributed with this work for additional information
|
| 4 |
+
# regarding copyright ownership. The ASF licenses this file
|
| 5 |
+
# to you under the Apache License, Version 2.0 (the
|
| 6 |
+
# "License"); you may not use this file except in compliance
|
| 7 |
+
# with the License. You may obtain a copy of the License at
|
| 8 |
+
#
|
| 9 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 10 |
+
#
|
| 11 |
+
# Unless required by applicable law or agreed to in writing,
|
| 12 |
+
# software distributed under the License is distributed on an
|
| 13 |
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
| 14 |
+
# KIND, either express or implied. See the License for the
|
| 15 |
+
# specific language governing permissions and limitations
|
| 16 |
+
# under the License.
|
| 17 |
+
|
| 18 |
+
# cython: language_level = 3
|
| 19 |
+
|
| 20 |
+
from cython cimport binding
|
| 21 |
+
|
| 22 |
+
from pyarrow.lib cimport (check_status, pyarrow_wrap_metadata,
|
| 23 |
+
pyarrow_unwrap_metadata)
|
| 24 |
+
from pyarrow.lib import frombytes, tobytes, KeyValueMetadata
|
| 25 |
+
from pyarrow.includes.common cimport *
|
| 26 |
+
from pyarrow.includes.libarrow cimport *
|
| 27 |
+
from pyarrow.includes.libarrow_fs cimport *
|
| 28 |
+
from pyarrow._fs cimport FileSystem
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
cpdef enum S3LogLevel:
|
| 32 |
+
Off = <int8_t> CS3LogLevel_Off
|
| 33 |
+
Fatal = <int8_t> CS3LogLevel_Fatal
|
| 34 |
+
Error = <int8_t> CS3LogLevel_Error
|
| 35 |
+
Warn = <int8_t> CS3LogLevel_Warn
|
| 36 |
+
Info = <int8_t> CS3LogLevel_Info
|
| 37 |
+
Debug = <int8_t> CS3LogLevel_Debug
|
| 38 |
+
Trace = <int8_t> CS3LogLevel_Trace
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
def initialize_s3(S3LogLevel log_level=S3LogLevel.Fatal, int num_event_loop_threads=1):
|
| 42 |
+
"""
|
| 43 |
+
Initialize S3 support
|
| 44 |
+
|
| 45 |
+
Parameters
|
| 46 |
+
----------
|
| 47 |
+
log_level : S3LogLevel
|
| 48 |
+
level of logging
|
| 49 |
+
num_event_loop_threads : int, default 1
|
| 50 |
+
how many threads to use for the AWS SDK's I/O event loop
|
| 51 |
+
|
| 52 |
+
Examples
|
| 53 |
+
--------
|
| 54 |
+
>>> fs.initialize_s3(fs.S3LogLevel.Error) # doctest: +SKIP
|
| 55 |
+
"""
|
| 56 |
+
cdef CS3GlobalOptions options
|
| 57 |
+
options.log_level = <CS3LogLevel> log_level
|
| 58 |
+
options.num_event_loop_threads = num_event_loop_threads
|
| 59 |
+
check_status(CInitializeS3(options))
|
| 60 |
+
|
| 61 |
+
|
| 62 |
+
def ensure_s3_initialized():
|
| 63 |
+
"""
|
| 64 |
+
Initialize S3 (with default options) if not already initialized
|
| 65 |
+
"""
|
| 66 |
+
check_status(CEnsureS3Initialized())
|
| 67 |
+
|
| 68 |
+
|
| 69 |
+
def finalize_s3():
|
| 70 |
+
check_status(CFinalizeS3())
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
def ensure_s3_finalized():
|
| 74 |
+
"""
|
| 75 |
+
Finalize S3 if already initialized
|
| 76 |
+
"""
|
| 77 |
+
check_status(CEnsureS3Finalized())
|
| 78 |
+
|
| 79 |
+
|
| 80 |
+
def resolve_s3_region(bucket):
|
| 81 |
+
"""
|
| 82 |
+
Resolve the S3 region of a bucket.
|
| 83 |
+
|
| 84 |
+
Parameters
|
| 85 |
+
----------
|
| 86 |
+
bucket : str
|
| 87 |
+
A S3 bucket name
|
| 88 |
+
|
| 89 |
+
Returns
|
| 90 |
+
-------
|
| 91 |
+
region : str
|
| 92 |
+
A S3 region name
|
| 93 |
+
|
| 94 |
+
Examples
|
| 95 |
+
--------
|
| 96 |
+
>>> fs.resolve_s3_region('voltrondata-labs-datasets')
|
| 97 |
+
'us-east-2'
|
| 98 |
+
"""
|
| 99 |
+
cdef:
|
| 100 |
+
c_string c_bucket
|
| 101 |
+
c_string c_region
|
| 102 |
+
|
| 103 |
+
ensure_s3_initialized()
|
| 104 |
+
|
| 105 |
+
c_bucket = tobytes(bucket)
|
| 106 |
+
with nogil:
|
| 107 |
+
c_region = GetResultValue(ResolveS3BucketRegion(c_bucket))
|
| 108 |
+
|
| 109 |
+
return frombytes(c_region)
|
| 110 |
+
|
| 111 |
+
|
| 112 |
+
class S3RetryStrategy:
|
| 113 |
+
"""
|
| 114 |
+
Base class for AWS retry strategies for use with S3.
|
| 115 |
+
|
| 116 |
+
Parameters
|
| 117 |
+
----------
|
| 118 |
+
max_attempts : int, default 3
|
| 119 |
+
The maximum number of retry attempts to attempt before failing.
|
| 120 |
+
"""
|
| 121 |
+
|
| 122 |
+
def __init__(self, max_attempts=3):
|
| 123 |
+
self.max_attempts = max_attempts
|
| 124 |
+
|
| 125 |
+
|
| 126 |
+
class AwsStandardS3RetryStrategy(S3RetryStrategy):
|
| 127 |
+
"""
|
| 128 |
+
Represents an AWS Standard retry strategy for use with S3.
|
| 129 |
+
|
| 130 |
+
Parameters
|
| 131 |
+
----------
|
| 132 |
+
max_attempts : int, default 3
|
| 133 |
+
The maximum number of retry attempts to attempt before failing.
|
| 134 |
+
"""
|
| 135 |
+
pass
|
| 136 |
+
|
| 137 |
+
|
| 138 |
+
class AwsDefaultS3RetryStrategy(S3RetryStrategy):
|
| 139 |
+
"""
|
| 140 |
+
Represents an AWS Default retry strategy for use with S3.
|
| 141 |
+
|
| 142 |
+
Parameters
|
| 143 |
+
----------
|
| 144 |
+
max_attempts : int, default 3
|
| 145 |
+
The maximum number of retry attempts to attempt before failing.
|
| 146 |
+
"""
|
| 147 |
+
pass
|
| 148 |
+
|
| 149 |
+
|
| 150 |
+
cdef class S3FileSystem(FileSystem):
|
| 151 |
+
"""
|
| 152 |
+
S3-backed FileSystem implementation
|
| 153 |
+
|
| 154 |
+
AWS access_key and secret_key can be provided explicitly.
|
| 155 |
+
|
| 156 |
+
If role_arn is provided instead of access_key and secret_key, temporary
|
| 157 |
+
credentials will be fetched by issuing a request to STS to assume the
|
| 158 |
+
specified role.
|
| 159 |
+
|
| 160 |
+
If neither access_key nor secret_key are provided, and role_arn is also not
|
| 161 |
+
provided, then attempts to establish the credentials automatically.
|
| 162 |
+
S3FileSystem will try the following methods, in order:
|
| 163 |
+
|
| 164 |
+
* ``AWS_ACCESS_KEY_ID``, ``AWS_SECRET_ACCESS_KEY``, and ``AWS_SESSION_TOKEN`` environment variables
|
| 165 |
+
* configuration files such as ``~/.aws/credentials`` and ``~/.aws/config``
|
| 166 |
+
* for nodes on Amazon EC2, the EC2 Instance Metadata Service
|
| 167 |
+
|
| 168 |
+
Note: S3 buckets are special and the operations available on them may be
|
| 169 |
+
limited or more expensive than desired.
|
| 170 |
+
|
| 171 |
+
When S3FileSystem creates new buckets (assuming allow_bucket_creation is
|
| 172 |
+
True), it does not pass any non-default settings. In AWS S3, the bucket and
|
| 173 |
+
all objects will be not publicly visible, and will have no bucket policies
|
| 174 |
+
and no resource tags. To have more control over how buckets are created,
|
| 175 |
+
use a different API to create them.
|
| 176 |
+
|
| 177 |
+
Parameters
|
| 178 |
+
----------
|
| 179 |
+
access_key : str, default None
|
| 180 |
+
AWS Access Key ID. Pass None to use the standard AWS environment
|
| 181 |
+
variables and/or configuration file.
|
| 182 |
+
secret_key : str, default None
|
| 183 |
+
AWS Secret Access key. Pass None to use the standard AWS environment
|
| 184 |
+
variables and/or configuration file.
|
| 185 |
+
session_token : str, default None
|
| 186 |
+
AWS Session Token. An optional session token, required if access_key
|
| 187 |
+
and secret_key are temporary credentials from STS.
|
| 188 |
+
anonymous : bool, default False
|
| 189 |
+
Whether to connect anonymously if access_key and secret_key are None.
|
| 190 |
+
If true, will not attempt to look up credentials using standard AWS
|
| 191 |
+
configuration methods.
|
| 192 |
+
role_arn : str, default None
|
| 193 |
+
AWS Role ARN. If provided instead of access_key and secret_key,
|
| 194 |
+
temporary credentials will be fetched by assuming this role.
|
| 195 |
+
session_name : str, default None
|
| 196 |
+
An optional identifier for the assumed role session.
|
| 197 |
+
external_id : str, default None
|
| 198 |
+
An optional unique identifier that might be required when you assume
|
| 199 |
+
a role in another account.
|
| 200 |
+
load_frequency : int, default 900
|
| 201 |
+
The frequency (in seconds) with which temporary credentials from an
|
| 202 |
+
assumed role session will be refreshed.
|
| 203 |
+
region : str, default None
|
| 204 |
+
AWS region to connect to. If not set, the AWS SDK will attempt to
|
| 205 |
+
determine the region using heuristics such as environment variables,
|
| 206 |
+
configuration profile, EC2 metadata, or default to 'us-east-1' when SDK
|
| 207 |
+
version <1.8. One can also use :func:`pyarrow.fs.resolve_s3_region` to
|
| 208 |
+
automatically resolve the region from a bucket name.
|
| 209 |
+
request_timeout : double, default None
|
| 210 |
+
Socket read timeouts on Windows and macOS, in seconds.
|
| 211 |
+
If omitted, the AWS SDK default value is used (typically 3 seconds).
|
| 212 |
+
This option is ignored on non-Windows, non-macOS systems.
|
| 213 |
+
connect_timeout : double, default None
|
| 214 |
+
Socket connection timeout, in seconds.
|
| 215 |
+
If omitted, the AWS SDK default value is used (typically 1 second).
|
| 216 |
+
scheme : str, default 'https'
|
| 217 |
+
S3 connection transport scheme.
|
| 218 |
+
endpoint_override : str, default None
|
| 219 |
+
Override region with a connect string such as "localhost:9000"
|
| 220 |
+
background_writes : bool, default True
|
| 221 |
+
Whether file writes will be issued in the background, without
|
| 222 |
+
blocking.
|
| 223 |
+
default_metadata : mapping or pyarrow.KeyValueMetadata, default None
|
| 224 |
+
Default metadata for open_output_stream. This will be ignored if
|
| 225 |
+
non-empty metadata is passed to open_output_stream.
|
| 226 |
+
proxy_options : dict or str, default None
|
| 227 |
+
If a proxy is used, provide the options here. Supported options are:
|
| 228 |
+
'scheme' (str: 'http' or 'https'; required), 'host' (str; required),
|
| 229 |
+
'port' (int; required), 'username' (str; optional),
|
| 230 |
+
'password' (str; optional).
|
| 231 |
+
A proxy URI (str) can also be provided, in which case these options
|
| 232 |
+
will be derived from the provided URI.
|
| 233 |
+
The following are equivalent::
|
| 234 |
+
|
| 235 |
+
S3FileSystem(proxy_options='http://username:password@localhost:8020')
|
| 236 |
+
S3FileSystem(proxy_options={'scheme': 'http', 'host': 'localhost',
|
| 237 |
+
'port': 8020, 'username': 'username',
|
| 238 |
+
'password': 'password'})
|
| 239 |
+
allow_bucket_creation : bool, default False
|
| 240 |
+
Whether to allow directory creation at the bucket-level. This option may also be
|
| 241 |
+
passed in a URI query parameter.
|
| 242 |
+
allow_bucket_deletion : bool, default False
|
| 243 |
+
Whether to allow directory deletion at the bucket-level. This option may also be
|
| 244 |
+
passed in a URI query parameter.
|
| 245 |
+
check_directory_existence_before_creation : bool, default false
|
| 246 |
+
Whether to check the directory existence before creating it.
|
| 247 |
+
If false, when creating a directory the code will not check if it already
|
| 248 |
+
exists or not. It's an optimization to try directory creation and catch the error,
|
| 249 |
+
rather than issue two dependent I/O calls.
|
| 250 |
+
If true, when creating a directory the code will only create the directory when necessary
|
| 251 |
+
at the cost of extra I/O calls. This can be used for key/value cloud storage which has
|
| 252 |
+
a hard rate limit to number of object mutation operations or scenarios such as
|
| 253 |
+
the directories already exist and you do not have creation access.
|
| 254 |
+
retry_strategy : S3RetryStrategy, default AwsStandardS3RetryStrategy(max_attempts=3)
|
| 255 |
+
The retry strategy to use with S3; fail after max_attempts. Available
|
| 256 |
+
strategies are AwsStandardS3RetryStrategy, AwsDefaultS3RetryStrategy.
|
| 257 |
+
force_virtual_addressing : bool, default False
|
| 258 |
+
Whether to use virtual addressing of buckets.
|
| 259 |
+
If true, then virtual addressing is always enabled.
|
| 260 |
+
If false, then virtual addressing is only enabled if `endpoint_override` is empty.
|
| 261 |
+
This can be used for non-AWS backends that only support virtual hosted-style access.
|
| 262 |
+
|
| 263 |
+
Examples
|
| 264 |
+
--------
|
| 265 |
+
>>> from pyarrow import fs
|
| 266 |
+
>>> s3 = fs.S3FileSystem(region='us-west-2')
|
| 267 |
+
>>> s3.get_file_info(fs.FileSelector(
|
| 268 |
+
... 'power-analysis-ready-datastore/power_901_constants.zarr/FROCEAN', recursive=True
|
| 269 |
+
... ))
|
| 270 |
+
[<FileInfo for 'power-analysis-ready-datastore/power_901_constants.zarr/FROCEAN/.zarray...
|
| 271 |
+
|
| 272 |
+
For usage of the methods see examples for :func:`~pyarrow.fs.LocalFileSystem`.
|
| 273 |
+
"""
|
| 274 |
+
|
| 275 |
+
cdef:
|
| 276 |
+
CS3FileSystem* s3fs
|
| 277 |
+
|
| 278 |
+
def __init__(self, *, access_key=None, secret_key=None, session_token=None,
|
| 279 |
+
bint anonymous=False, region=None, request_timeout=None,
|
| 280 |
+
connect_timeout=None, scheme=None, endpoint_override=None,
|
| 281 |
+
bint background_writes=True, default_metadata=None,
|
| 282 |
+
role_arn=None, session_name=None, external_id=None,
|
| 283 |
+
load_frequency=900, proxy_options=None,
|
| 284 |
+
allow_bucket_creation=False, allow_bucket_deletion=False,
|
| 285 |
+
check_directory_existence_before_creation=False,
|
| 286 |
+
retry_strategy: S3RetryStrategy = AwsStandardS3RetryStrategy(
|
| 287 |
+
max_attempts=3),
|
| 288 |
+
force_virtual_addressing=False):
|
| 289 |
+
cdef:
|
| 290 |
+
optional[CS3Options] options
|
| 291 |
+
shared_ptr[CS3FileSystem] wrapped
|
| 292 |
+
|
| 293 |
+
# Need to do this before initializing `options` as the S3Options
|
| 294 |
+
# constructor has a debug check against use after S3 finalization.
|
| 295 |
+
ensure_s3_initialized()
|
| 296 |
+
|
| 297 |
+
if access_key is not None and secret_key is None:
|
| 298 |
+
raise ValueError(
|
| 299 |
+
'In order to initialize with explicit credentials both '
|
| 300 |
+
'access_key and secret_key must be provided, '
|
| 301 |
+
'`secret_key` is not set.'
|
| 302 |
+
)
|
| 303 |
+
elif access_key is None and secret_key is not None:
|
| 304 |
+
raise ValueError(
|
| 305 |
+
'In order to initialize with explicit credentials both '
|
| 306 |
+
'access_key and secret_key must be provided, '
|
| 307 |
+
'`access_key` is not set.'
|
| 308 |
+
)
|
| 309 |
+
|
| 310 |
+
elif session_token is not None and (access_key is None or
|
| 311 |
+
secret_key is None):
|
| 312 |
+
raise ValueError(
|
| 313 |
+
'In order to initialize a session with temporary credentials, '
|
| 314 |
+
'both secret_key and access_key must be provided in addition '
|
| 315 |
+
'to session_token.'
|
| 316 |
+
)
|
| 317 |
+
|
| 318 |
+
elif (access_key is not None or secret_key is not None):
|
| 319 |
+
if anonymous:
|
| 320 |
+
raise ValueError(
|
| 321 |
+
'Cannot pass anonymous=True together with access_key '
|
| 322 |
+
'and secret_key.')
|
| 323 |
+
|
| 324 |
+
if role_arn:
|
| 325 |
+
raise ValueError(
|
| 326 |
+
'Cannot provide role_arn with access_key and secret_key')
|
| 327 |
+
|
| 328 |
+
if session_token is None:
|
| 329 |
+
session_token = ""
|
| 330 |
+
|
| 331 |
+
options = CS3Options.FromAccessKey(
|
| 332 |
+
tobytes(access_key),
|
| 333 |
+
tobytes(secret_key),
|
| 334 |
+
tobytes(session_token)
|
| 335 |
+
)
|
| 336 |
+
elif anonymous:
|
| 337 |
+
if role_arn:
|
| 338 |
+
raise ValueError(
|
| 339 |
+
'Cannot provide role_arn with anonymous=True')
|
| 340 |
+
|
| 341 |
+
options = CS3Options.Anonymous()
|
| 342 |
+
elif role_arn:
|
| 343 |
+
if session_name is None:
|
| 344 |
+
session_name = ''
|
| 345 |
+
if external_id is None:
|
| 346 |
+
external_id = ''
|
| 347 |
+
|
| 348 |
+
options = CS3Options.FromAssumeRole(
|
| 349 |
+
tobytes(role_arn),
|
| 350 |
+
tobytes(session_name),
|
| 351 |
+
tobytes(external_id),
|
| 352 |
+
load_frequency
|
| 353 |
+
)
|
| 354 |
+
else:
|
| 355 |
+
options = CS3Options.Defaults()
|
| 356 |
+
|
| 357 |
+
if region is not None:
|
| 358 |
+
options.value().region = tobytes(region)
|
| 359 |
+
if request_timeout is not None:
|
| 360 |
+
options.value().request_timeout = request_timeout
|
| 361 |
+
if connect_timeout is not None:
|
| 362 |
+
options.value().connect_timeout = connect_timeout
|
| 363 |
+
if scheme is not None:
|
| 364 |
+
options.value().scheme = tobytes(scheme)
|
| 365 |
+
if endpoint_override is not None:
|
| 366 |
+
options.value().endpoint_override = tobytes(endpoint_override)
|
| 367 |
+
if background_writes is not None:
|
| 368 |
+
options.value().background_writes = background_writes
|
| 369 |
+
if default_metadata is not None:
|
| 370 |
+
if not isinstance(default_metadata, KeyValueMetadata):
|
| 371 |
+
default_metadata = KeyValueMetadata(default_metadata)
|
| 372 |
+
options.value().default_metadata = pyarrow_unwrap_metadata(
|
| 373 |
+
default_metadata)
|
| 374 |
+
|
| 375 |
+
if proxy_options is not None:
|
| 376 |
+
if isinstance(proxy_options, dict):
|
| 377 |
+
options.value().proxy_options.scheme = tobytes(
|
| 378 |
+
proxy_options["scheme"])
|
| 379 |
+
options.value().proxy_options.host = tobytes(
|
| 380 |
+
proxy_options["host"])
|
| 381 |
+
options.value().proxy_options.port = proxy_options["port"]
|
| 382 |
+
proxy_username = proxy_options.get("username", None)
|
| 383 |
+
if proxy_username:
|
| 384 |
+
options.value().proxy_options.username = tobytes(
|
| 385 |
+
proxy_username)
|
| 386 |
+
proxy_password = proxy_options.get("password", None)
|
| 387 |
+
if proxy_password:
|
| 388 |
+
options.value().proxy_options.password = tobytes(
|
| 389 |
+
proxy_password)
|
| 390 |
+
elif isinstance(proxy_options, str):
|
| 391 |
+
options.value().proxy_options = GetResultValue(
|
| 392 |
+
CS3ProxyOptions.FromUriString(tobytes(proxy_options)))
|
| 393 |
+
else:
|
| 394 |
+
raise TypeError(
|
| 395 |
+
"'proxy_options': expected 'dict' or 'str', "
|
| 396 |
+
f"got {type(proxy_options)} instead.")
|
| 397 |
+
|
| 398 |
+
options.value().allow_bucket_creation = allow_bucket_creation
|
| 399 |
+
options.value().allow_bucket_deletion = allow_bucket_deletion
|
| 400 |
+
options.value().check_directory_existence_before_creation = check_directory_existence_before_creation
|
| 401 |
+
options.value().force_virtual_addressing = force_virtual_addressing
|
| 402 |
+
|
| 403 |
+
if isinstance(retry_strategy, AwsStandardS3RetryStrategy):
|
| 404 |
+
options.value().retry_strategy = CS3RetryStrategy.GetAwsStandardRetryStrategy(
|
| 405 |
+
retry_strategy.max_attempts)
|
| 406 |
+
elif isinstance(retry_strategy, AwsDefaultS3RetryStrategy):
|
| 407 |
+
options.value().retry_strategy = CS3RetryStrategy.GetAwsDefaultRetryStrategy(
|
| 408 |
+
retry_strategy.max_attempts)
|
| 409 |
+
else:
|
| 410 |
+
raise ValueError(f'Invalid retry_strategy {retry_strategy!r}')
|
| 411 |
+
|
| 412 |
+
with nogil:
|
| 413 |
+
wrapped = GetResultValue(CS3FileSystem.Make(options.value()))
|
| 414 |
+
|
| 415 |
+
self.init(<shared_ptr[CFileSystem]> wrapped)
|
| 416 |
+
|
| 417 |
+
cdef init(self, const shared_ptr[CFileSystem]& wrapped):
|
| 418 |
+
FileSystem.init(self, wrapped)
|
| 419 |
+
self.s3fs = <CS3FileSystem*> wrapped.get()
|
| 420 |
+
|
| 421 |
+
@staticmethod
|
| 422 |
+
@binding(True) # Required for cython < 3
|
| 423 |
+
def _reconstruct(kwargs):
|
| 424 |
+
# __reduce__ doesn't allow passing named arguments directly to the
|
| 425 |
+
# reconstructor, hence this wrapper.
|
| 426 |
+
return S3FileSystem(**kwargs)
|
| 427 |
+
|
| 428 |
+
def __reduce__(self):
|
| 429 |
+
cdef CS3Options opts = self.s3fs.options()
|
| 430 |
+
|
| 431 |
+
# if creds were explicitly provided, then use them
|
| 432 |
+
# else obtain them as they were last time.
|
| 433 |
+
if opts.credentials_kind == CS3CredentialsKind_Explicit:
|
| 434 |
+
access_key = frombytes(opts.GetAccessKey())
|
| 435 |
+
secret_key = frombytes(opts.GetSecretKey())
|
| 436 |
+
session_token = frombytes(opts.GetSessionToken())
|
| 437 |
+
else:
|
| 438 |
+
access_key = None
|
| 439 |
+
secret_key = None
|
| 440 |
+
session_token = None
|
| 441 |
+
|
| 442 |
+
return (
|
| 443 |
+
S3FileSystem._reconstruct, (dict(
|
| 444 |
+
access_key=access_key,
|
| 445 |
+
secret_key=secret_key,
|
| 446 |
+
session_token=session_token,
|
| 447 |
+
anonymous=(opts.credentials_kind ==
|
| 448 |
+
CS3CredentialsKind_Anonymous),
|
| 449 |
+
region=frombytes(opts.region),
|
| 450 |
+
scheme=frombytes(opts.scheme),
|
| 451 |
+
connect_timeout=opts.connect_timeout,
|
| 452 |
+
request_timeout=opts.request_timeout,
|
| 453 |
+
endpoint_override=frombytes(opts.endpoint_override),
|
| 454 |
+
role_arn=frombytes(opts.role_arn),
|
| 455 |
+
session_name=frombytes(opts.session_name),
|
| 456 |
+
external_id=frombytes(opts.external_id),
|
| 457 |
+
load_frequency=opts.load_frequency,
|
| 458 |
+
background_writes=opts.background_writes,
|
| 459 |
+
allow_bucket_creation=opts.allow_bucket_creation,
|
| 460 |
+
allow_bucket_deletion=opts.allow_bucket_deletion,
|
| 461 |
+
check_directory_existence_before_creation=opts.check_directory_existence_before_creation,
|
| 462 |
+
default_metadata=pyarrow_wrap_metadata(opts.default_metadata),
|
| 463 |
+
proxy_options={'scheme': frombytes(opts.proxy_options.scheme),
|
| 464 |
+
'host': frombytes(opts.proxy_options.host),
|
| 465 |
+
'port': opts.proxy_options.port,
|
| 466 |
+
'username': frombytes(
|
| 467 |
+
opts.proxy_options.username),
|
| 468 |
+
'password': frombytes(
|
| 469 |
+
opts.proxy_options.password)},
|
| 470 |
+
force_virtual_addressing=opts.force_virtual_addressing,
|
| 471 |
+
),)
|
| 472 |
+
)
|
| 473 |
+
|
| 474 |
+
@property
|
| 475 |
+
def region(self):
|
| 476 |
+
"""
|
| 477 |
+
The AWS region this filesystem connects to.
|
| 478 |
+
"""
|
| 479 |
+
return frombytes(self.s3fs.region())
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/pyarrow/benchmark.py
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Licensed to the Apache Software Foundation (ASF) under one
|
| 2 |
+
# or more contributor license agreements. See the NOTICE file
|
| 3 |
+
# distributed with this work for additional information
|
| 4 |
+
# regarding copyright ownership. The ASF licenses this file
|
| 5 |
+
# to you under the Apache License, Version 2.0 (the
|
| 6 |
+
# "License"); you may not use this file except in compliance
|
| 7 |
+
# with the License. You may obtain a copy of the License at
|
| 8 |
+
#
|
| 9 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 10 |
+
#
|
| 11 |
+
# Unless required by applicable law or agreed to in writing,
|
| 12 |
+
# software distributed under the License is distributed on an
|
| 13 |
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
| 14 |
+
# KIND, either express or implied. See the License for the
|
| 15 |
+
# specific language governing permissions and limitations
|
| 16 |
+
# under the License.
|
| 17 |
+
|
| 18 |
+
# flake8: noqa
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
from pyarrow.lib import benchmark_PandasObjectIsNull
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/pyarrow/conftest.py
ADDED
|
@@ -0,0 +1,386 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Licensed to the Apache Software Foundation (ASF) under one
|
| 2 |
+
# or more contributor license agreements. See the NOTICE file
|
| 3 |
+
# distributed with this work for additional information
|
| 4 |
+
# regarding copyright ownership. The ASF licenses this file
|
| 5 |
+
# to you under the Apache License, Version 2.0 (the
|
| 6 |
+
# "License"); you may not use this file except in compliance
|
| 7 |
+
# with the License. You may obtain a copy of the License at
|
| 8 |
+
#
|
| 9 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 10 |
+
#
|
| 11 |
+
# Unless required by applicable law or agreed to in writing,
|
| 12 |
+
# software distributed under the License is distributed on an
|
| 13 |
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
| 14 |
+
# KIND, either express or implied. See the License for the
|
| 15 |
+
# specific language governing permissions and limitations
|
| 16 |
+
# under the License.
|
| 17 |
+
|
| 18 |
+
import pytest
|
| 19 |
+
|
| 20 |
+
import os
|
| 21 |
+
import pyarrow as pa
|
| 22 |
+
from pyarrow import Codec
|
| 23 |
+
from pyarrow import fs
|
| 24 |
+
from pyarrow.lib import is_threading_enabled
|
| 25 |
+
from pyarrow.tests.util import windows_has_tzdata
|
| 26 |
+
import sys
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
groups = [
|
| 30 |
+
'acero',
|
| 31 |
+
'azure',
|
| 32 |
+
'brotli',
|
| 33 |
+
'bz2',
|
| 34 |
+
'cython',
|
| 35 |
+
'dataset',
|
| 36 |
+
'hypothesis',
|
| 37 |
+
'fastparquet',
|
| 38 |
+
'flight',
|
| 39 |
+
'gandiva',
|
| 40 |
+
'gcs',
|
| 41 |
+
'gdb',
|
| 42 |
+
'gzip',
|
| 43 |
+
'hdfs',
|
| 44 |
+
'large_memory',
|
| 45 |
+
'lz4',
|
| 46 |
+
'memory_leak',
|
| 47 |
+
'nopandas',
|
| 48 |
+
'nonumpy',
|
| 49 |
+
'numpy',
|
| 50 |
+
'orc',
|
| 51 |
+
'pandas',
|
| 52 |
+
'parquet',
|
| 53 |
+
'parquet_encryption',
|
| 54 |
+
'processes',
|
| 55 |
+
'requires_testing_data',
|
| 56 |
+
's3',
|
| 57 |
+
'slow',
|
| 58 |
+
'snappy',
|
| 59 |
+
'sockets',
|
| 60 |
+
'substrait',
|
| 61 |
+
'threading',
|
| 62 |
+
'timezone_data',
|
| 63 |
+
'zstd',
|
| 64 |
+
]
|
| 65 |
+
|
| 66 |
+
defaults = {
|
| 67 |
+
'acero': False,
|
| 68 |
+
'azure': False,
|
| 69 |
+
'brotli': Codec.is_available('brotli'),
|
| 70 |
+
'bz2': Codec.is_available('bz2'),
|
| 71 |
+
'cython': False,
|
| 72 |
+
'dataset': False,
|
| 73 |
+
'fastparquet': False,
|
| 74 |
+
'flight': False,
|
| 75 |
+
'gandiva': False,
|
| 76 |
+
'gcs': False,
|
| 77 |
+
'gdb': True,
|
| 78 |
+
'gzip': Codec.is_available('gzip'),
|
| 79 |
+
'hdfs': False,
|
| 80 |
+
'hypothesis': False,
|
| 81 |
+
'large_memory': False,
|
| 82 |
+
'lz4': Codec.is_available('lz4'),
|
| 83 |
+
'memory_leak': False,
|
| 84 |
+
'nopandas': False,
|
| 85 |
+
'nonumpy': False,
|
| 86 |
+
'numpy': False,
|
| 87 |
+
'orc': False,
|
| 88 |
+
'pandas': False,
|
| 89 |
+
'parquet': False,
|
| 90 |
+
'parquet_encryption': False,
|
| 91 |
+
'processes': True,
|
| 92 |
+
'requires_testing_data': True,
|
| 93 |
+
's3': False,
|
| 94 |
+
'slow': False,
|
| 95 |
+
'snappy': Codec.is_available('snappy'),
|
| 96 |
+
'sockets': True,
|
| 97 |
+
'substrait': False,
|
| 98 |
+
'threading': is_threading_enabled(),
|
| 99 |
+
'timezone_data': True,
|
| 100 |
+
'zstd': Codec.is_available('zstd'),
|
| 101 |
+
}
|
| 102 |
+
|
| 103 |
+
if sys.platform == "emscripten":
|
| 104 |
+
# Emscripten doesn't support subprocess,
|
| 105 |
+
# multiprocessing, gdb or socket based
|
| 106 |
+
# networking
|
| 107 |
+
defaults['gdb'] = False
|
| 108 |
+
defaults['processes'] = False
|
| 109 |
+
defaults['sockets'] = False
|
| 110 |
+
|
| 111 |
+
if sys.platform == "win32":
|
| 112 |
+
defaults['timezone_data'] = windows_has_tzdata()
|
| 113 |
+
elif sys.platform == "emscripten":
|
| 114 |
+
defaults['timezone_data'] = os.path.exists("/usr/share/zoneinfo")
|
| 115 |
+
|
| 116 |
+
try:
|
| 117 |
+
import cython # noqa
|
| 118 |
+
defaults['cython'] = True
|
| 119 |
+
except ImportError:
|
| 120 |
+
pass
|
| 121 |
+
|
| 122 |
+
try:
|
| 123 |
+
import fastparquet # noqa
|
| 124 |
+
defaults['fastparquet'] = True
|
| 125 |
+
except ImportError:
|
| 126 |
+
pass
|
| 127 |
+
|
| 128 |
+
try:
|
| 129 |
+
import pyarrow.gandiva # noqa
|
| 130 |
+
defaults['gandiva'] = True
|
| 131 |
+
except ImportError:
|
| 132 |
+
pass
|
| 133 |
+
|
| 134 |
+
try:
|
| 135 |
+
import pyarrow.acero # noqa
|
| 136 |
+
defaults['acero'] = True
|
| 137 |
+
except ImportError:
|
| 138 |
+
pass
|
| 139 |
+
|
| 140 |
+
try:
|
| 141 |
+
import pyarrow.dataset # noqa
|
| 142 |
+
defaults['dataset'] = True
|
| 143 |
+
except ImportError:
|
| 144 |
+
pass
|
| 145 |
+
|
| 146 |
+
try:
|
| 147 |
+
import pyarrow.orc # noqa
|
| 148 |
+
if sys.platform == "win32":
|
| 149 |
+
defaults['orc'] = True
|
| 150 |
+
else:
|
| 151 |
+
# orc tests on non-Windows platforms only work
|
| 152 |
+
# if timezone data exists, so skip them if
|
| 153 |
+
# not.
|
| 154 |
+
defaults['orc'] = defaults['timezone_data']
|
| 155 |
+
except ImportError:
|
| 156 |
+
pass
|
| 157 |
+
|
| 158 |
+
try:
|
| 159 |
+
import pandas # noqa
|
| 160 |
+
defaults['pandas'] = True
|
| 161 |
+
except ImportError:
|
| 162 |
+
defaults['nopandas'] = True
|
| 163 |
+
|
| 164 |
+
try:
|
| 165 |
+
import numpy # noqa
|
| 166 |
+
defaults['numpy'] = True
|
| 167 |
+
except ImportError:
|
| 168 |
+
defaults['nonumpy'] = True
|
| 169 |
+
|
| 170 |
+
try:
|
| 171 |
+
import pyarrow.parquet # noqa
|
| 172 |
+
defaults['parquet'] = True
|
| 173 |
+
except ImportError:
|
| 174 |
+
pass
|
| 175 |
+
|
| 176 |
+
try:
|
| 177 |
+
import pyarrow.parquet.encryption # noqa
|
| 178 |
+
defaults['parquet_encryption'] = True
|
| 179 |
+
except ImportError:
|
| 180 |
+
pass
|
| 181 |
+
|
| 182 |
+
try:
|
| 183 |
+
import pyarrow.flight # noqa
|
| 184 |
+
defaults['flight'] = True
|
| 185 |
+
except ImportError:
|
| 186 |
+
pass
|
| 187 |
+
|
| 188 |
+
try:
|
| 189 |
+
from pyarrow.fs import AzureFileSystem # noqa
|
| 190 |
+
defaults['azure'] = True
|
| 191 |
+
except ImportError:
|
| 192 |
+
pass
|
| 193 |
+
|
| 194 |
+
try:
|
| 195 |
+
from pyarrow.fs import GcsFileSystem # noqa
|
| 196 |
+
defaults['gcs'] = True
|
| 197 |
+
except ImportError:
|
| 198 |
+
pass
|
| 199 |
+
|
| 200 |
+
try:
|
| 201 |
+
from pyarrow.fs import S3FileSystem # noqa
|
| 202 |
+
defaults['s3'] = True
|
| 203 |
+
except ImportError:
|
| 204 |
+
pass
|
| 205 |
+
|
| 206 |
+
try:
|
| 207 |
+
from pyarrow.fs import HadoopFileSystem # noqa
|
| 208 |
+
defaults['hdfs'] = True
|
| 209 |
+
except ImportError:
|
| 210 |
+
pass
|
| 211 |
+
|
| 212 |
+
try:
|
| 213 |
+
import pyarrow.substrait # noqa
|
| 214 |
+
defaults['substrait'] = True
|
| 215 |
+
except ImportError:
|
| 216 |
+
pass
|
| 217 |
+
|
| 218 |
+
|
| 219 |
+
# Doctest should ignore files for the modules that are not built
|
| 220 |
+
def pytest_ignore_collect(path, config):
|
| 221 |
+
if config.option.doctestmodules:
|
| 222 |
+
# don't try to run doctests on the /tests directory
|
| 223 |
+
if "/pyarrow/tests/" in str(path):
|
| 224 |
+
return True
|
| 225 |
+
|
| 226 |
+
doctest_groups = [
|
| 227 |
+
'dataset',
|
| 228 |
+
'orc',
|
| 229 |
+
'parquet',
|
| 230 |
+
'flight',
|
| 231 |
+
'substrait',
|
| 232 |
+
]
|
| 233 |
+
|
| 234 |
+
# handle cuda, flight, etc
|
| 235 |
+
for group in doctest_groups:
|
| 236 |
+
if 'pyarrow/{}'.format(group) in str(path):
|
| 237 |
+
if not defaults[group]:
|
| 238 |
+
return True
|
| 239 |
+
|
| 240 |
+
if 'pyarrow/parquet/encryption' in str(path):
|
| 241 |
+
if not defaults['parquet_encryption']:
|
| 242 |
+
return True
|
| 243 |
+
|
| 244 |
+
if 'pyarrow/cuda' in str(path):
|
| 245 |
+
try:
|
| 246 |
+
import pyarrow.cuda # noqa
|
| 247 |
+
return False
|
| 248 |
+
except ImportError:
|
| 249 |
+
return True
|
| 250 |
+
|
| 251 |
+
if 'pyarrow/fs' in str(path):
|
| 252 |
+
try:
|
| 253 |
+
from pyarrow.fs import S3FileSystem # noqa
|
| 254 |
+
return False
|
| 255 |
+
except ImportError:
|
| 256 |
+
return True
|
| 257 |
+
|
| 258 |
+
if getattr(config.option, "doctest_cython", False):
|
| 259 |
+
if "/pyarrow/tests/" in str(path):
|
| 260 |
+
return True
|
| 261 |
+
if "/pyarrow/_parquet_encryption" in str(path):
|
| 262 |
+
return True
|
| 263 |
+
|
| 264 |
+
return False
|
| 265 |
+
|
| 266 |
+
|
| 267 |
+
# Save output files from doctest examples into temp dir
|
| 268 |
+
@pytest.fixture(autouse=True)
|
| 269 |
+
def _docdir(request):
|
| 270 |
+
|
| 271 |
+
# Trigger ONLY for the doctests
|
| 272 |
+
doctest_m = request.config.option.doctestmodules
|
| 273 |
+
doctest_c = getattr(request.config.option, "doctest_cython", False)
|
| 274 |
+
|
| 275 |
+
if doctest_m or doctest_c:
|
| 276 |
+
|
| 277 |
+
# Get the fixture dynamically by its name.
|
| 278 |
+
tmpdir = request.getfixturevalue('tmpdir')
|
| 279 |
+
|
| 280 |
+
# Chdir only for the duration of the test.
|
| 281 |
+
with tmpdir.as_cwd():
|
| 282 |
+
yield
|
| 283 |
+
|
| 284 |
+
else:
|
| 285 |
+
yield
|
| 286 |
+
|
| 287 |
+
|
| 288 |
+
# Define doctest_namespace for fs module docstring import
|
| 289 |
+
@pytest.fixture(autouse=True)
|
| 290 |
+
def add_fs(doctest_namespace, request, tmp_path):
|
| 291 |
+
|
| 292 |
+
# Trigger ONLY for the doctests
|
| 293 |
+
doctest_m = request.config.option.doctestmodules
|
| 294 |
+
doctest_c = getattr(request.config.option, "doctest_cython", False)
|
| 295 |
+
|
| 296 |
+
if doctest_m or doctest_c:
|
| 297 |
+
# fs import
|
| 298 |
+
doctest_namespace["fs"] = fs
|
| 299 |
+
|
| 300 |
+
# Creation of an object and file with data
|
| 301 |
+
local = fs.LocalFileSystem()
|
| 302 |
+
path = tmp_path / 'pyarrow-fs-example.dat'
|
| 303 |
+
with local.open_output_stream(str(path)) as stream:
|
| 304 |
+
stream.write(b'data')
|
| 305 |
+
doctest_namespace["local"] = local
|
| 306 |
+
doctest_namespace["local_path"] = str(tmp_path)
|
| 307 |
+
doctest_namespace["path"] = str(path)
|
| 308 |
+
yield
|
| 309 |
+
|
| 310 |
+
|
| 311 |
+
# Define udf fixture for test_udf.py and test_substrait.py
|
| 312 |
+
@pytest.fixture(scope="session")
|
| 313 |
+
def unary_func_fixture():
|
| 314 |
+
"""
|
| 315 |
+
Register a unary scalar function.
|
| 316 |
+
"""
|
| 317 |
+
from pyarrow import compute as pc
|
| 318 |
+
|
| 319 |
+
def unary_function(ctx, x):
|
| 320 |
+
return pc.call_function("add", [x, 1],
|
| 321 |
+
memory_pool=ctx.memory_pool)
|
| 322 |
+
func_name = "y=x+1"
|
| 323 |
+
unary_doc = {"summary": "add function",
|
| 324 |
+
"description": "test add function"}
|
| 325 |
+
pc.register_scalar_function(unary_function,
|
| 326 |
+
func_name,
|
| 327 |
+
unary_doc,
|
| 328 |
+
{"array": pa.int64()},
|
| 329 |
+
pa.int64())
|
| 330 |
+
return unary_function, func_name
|
| 331 |
+
|
| 332 |
+
|
| 333 |
+
@pytest.fixture(scope="session")
|
| 334 |
+
def unary_agg_func_fixture():
|
| 335 |
+
"""
|
| 336 |
+
Register a unary aggregate function (mean)
|
| 337 |
+
"""
|
| 338 |
+
from pyarrow import compute as pc
|
| 339 |
+
import numpy as np
|
| 340 |
+
|
| 341 |
+
def func(ctx, x):
|
| 342 |
+
return pa.scalar(np.nanmean(x))
|
| 343 |
+
|
| 344 |
+
func_name = "mean_udf"
|
| 345 |
+
func_doc = {"summary": "y=avg(x)",
|
| 346 |
+
"description": "find mean of x"}
|
| 347 |
+
|
| 348 |
+
pc.register_aggregate_function(func,
|
| 349 |
+
func_name,
|
| 350 |
+
func_doc,
|
| 351 |
+
{
|
| 352 |
+
"x": pa.float64(),
|
| 353 |
+
},
|
| 354 |
+
pa.float64()
|
| 355 |
+
)
|
| 356 |
+
return func, func_name
|
| 357 |
+
|
| 358 |
+
|
| 359 |
+
@pytest.fixture(scope="session")
|
| 360 |
+
def varargs_agg_func_fixture():
|
| 361 |
+
"""
|
| 362 |
+
Register a unary aggregate function
|
| 363 |
+
"""
|
| 364 |
+
from pyarrow import compute as pc
|
| 365 |
+
import numpy as np
|
| 366 |
+
|
| 367 |
+
def func(ctx, *args):
|
| 368 |
+
sum = 0.0
|
| 369 |
+
for arg in args:
|
| 370 |
+
sum += np.nanmean(arg)
|
| 371 |
+
return pa.scalar(sum)
|
| 372 |
+
|
| 373 |
+
func_name = "sum_mean"
|
| 374 |
+
func_doc = {"summary": "Varargs aggregate",
|
| 375 |
+
"description": "Varargs aggregate"}
|
| 376 |
+
|
| 377 |
+
pc.register_aggregate_function(func,
|
| 378 |
+
func_name,
|
| 379 |
+
func_doc,
|
| 380 |
+
{
|
| 381 |
+
"x": pa.int64(),
|
| 382 |
+
"y": pa.float64()
|
| 383 |
+
},
|
| 384 |
+
pa.float64()
|
| 385 |
+
)
|
| 386 |
+
return func, func_name
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/pyarrow/json.py
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Licensed to the Apache Software Foundation (ASF) under one
|
| 2 |
+
# or more contributor license agreements. See the NOTICE file
|
| 3 |
+
# distributed with this work for additional information
|
| 4 |
+
# regarding copyright ownership. The ASF licenses this file
|
| 5 |
+
# to you under the Apache License, Version 2.0 (the
|
| 6 |
+
# "License"); you may not use this file except in compliance
|
| 7 |
+
# with the License. You may obtain a copy of the License at
|
| 8 |
+
#
|
| 9 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 10 |
+
#
|
| 11 |
+
# Unless required by applicable law or agreed to in writing,
|
| 12 |
+
# software distributed under the License is distributed on an
|
| 13 |
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
| 14 |
+
# KIND, either express or implied. See the License for the
|
| 15 |
+
# specific language governing permissions and limitations
|
| 16 |
+
# under the License.
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
from pyarrow._json import ReadOptions, ParseOptions, read_json # noqa
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/pyarrow/libarrow_python_parquet_encryption.so.1900.1.0
ADDED
|
Binary file (37.4 kB). View file
|
|
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/pyarrow/orc.py
ADDED
|
@@ -0,0 +1,384 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Licensed to the Apache Software Foundation (ASF) under one
|
| 2 |
+
# or more contributor license agreements. See the NOTICE file
|
| 3 |
+
# distributed with this work for additional information
|
| 4 |
+
# regarding copyright ownership. The ASF licenses this file
|
| 5 |
+
# to you under the Apache License, Version 2.0 (the
|
| 6 |
+
# "License"); you may not use this file except in compliance
|
| 7 |
+
# with the License. You may obtain a copy of the License at
|
| 8 |
+
#
|
| 9 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 10 |
+
#
|
| 11 |
+
# Unless required by applicable law or agreed to in writing,
|
| 12 |
+
# software distributed under the License is distributed on an
|
| 13 |
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
| 14 |
+
# KIND, either express or implied. See the License for the
|
| 15 |
+
# specific language governing permissions and limitations
|
| 16 |
+
# under the License.
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
from numbers import Integral
|
| 20 |
+
import warnings
|
| 21 |
+
|
| 22 |
+
from pyarrow.lib import Table
|
| 23 |
+
import pyarrow._orc as _orc
|
| 24 |
+
from pyarrow.fs import _resolve_filesystem_and_path
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
class ORCFile:
|
| 28 |
+
"""
|
| 29 |
+
Reader interface for a single ORC file
|
| 30 |
+
|
| 31 |
+
Parameters
|
| 32 |
+
----------
|
| 33 |
+
source : str or pyarrow.NativeFile
|
| 34 |
+
Readable source. For passing Python file objects or byte buffers,
|
| 35 |
+
see pyarrow.io.PythonFileInterface or pyarrow.io.BufferReader.
|
| 36 |
+
"""
|
| 37 |
+
|
| 38 |
+
def __init__(self, source):
|
| 39 |
+
self.reader = _orc.ORCReader()
|
| 40 |
+
self.reader.open(source)
|
| 41 |
+
|
| 42 |
+
@property
|
| 43 |
+
def metadata(self):
|
| 44 |
+
"""The file metadata, as an arrow KeyValueMetadata"""
|
| 45 |
+
return self.reader.metadata()
|
| 46 |
+
|
| 47 |
+
@property
|
| 48 |
+
def schema(self):
|
| 49 |
+
"""The file schema, as an arrow schema"""
|
| 50 |
+
return self.reader.schema()
|
| 51 |
+
|
| 52 |
+
@property
|
| 53 |
+
def nrows(self):
|
| 54 |
+
"""The number of rows in the file"""
|
| 55 |
+
return self.reader.nrows()
|
| 56 |
+
|
| 57 |
+
@property
|
| 58 |
+
def nstripes(self):
|
| 59 |
+
"""The number of stripes in the file"""
|
| 60 |
+
return self.reader.nstripes()
|
| 61 |
+
|
| 62 |
+
@property
|
| 63 |
+
def file_version(self):
|
| 64 |
+
"""Format version of the ORC file, must be 0.11 or 0.12"""
|
| 65 |
+
return self.reader.file_version()
|
| 66 |
+
|
| 67 |
+
@property
|
| 68 |
+
def software_version(self):
|
| 69 |
+
"""Software instance and version that wrote this file"""
|
| 70 |
+
return self.reader.software_version()
|
| 71 |
+
|
| 72 |
+
@property
|
| 73 |
+
def compression(self):
|
| 74 |
+
"""Compression codec of the file"""
|
| 75 |
+
return self.reader.compression()
|
| 76 |
+
|
| 77 |
+
@property
|
| 78 |
+
def compression_size(self):
|
| 79 |
+
"""Number of bytes to buffer for the compression codec in the file"""
|
| 80 |
+
return self.reader.compression_size()
|
| 81 |
+
|
| 82 |
+
@property
|
| 83 |
+
def writer(self):
|
| 84 |
+
"""Name of the writer that wrote this file.
|
| 85 |
+
If the writer is unknown then its Writer ID
|
| 86 |
+
(a number) is returned"""
|
| 87 |
+
return self.reader.writer()
|
| 88 |
+
|
| 89 |
+
@property
|
| 90 |
+
def writer_version(self):
|
| 91 |
+
"""Version of the writer"""
|
| 92 |
+
return self.reader.writer_version()
|
| 93 |
+
|
| 94 |
+
@property
|
| 95 |
+
def row_index_stride(self):
|
| 96 |
+
"""Number of rows per an entry in the row index or 0
|
| 97 |
+
if there is no row index"""
|
| 98 |
+
return self.reader.row_index_stride()
|
| 99 |
+
|
| 100 |
+
@property
|
| 101 |
+
def nstripe_statistics(self):
|
| 102 |
+
"""Number of stripe statistics"""
|
| 103 |
+
return self.reader.nstripe_statistics()
|
| 104 |
+
|
| 105 |
+
@property
|
| 106 |
+
def content_length(self):
|
| 107 |
+
"""Length of the data stripes in the file in bytes"""
|
| 108 |
+
return self.reader.content_length()
|
| 109 |
+
|
| 110 |
+
@property
|
| 111 |
+
def stripe_statistics_length(self):
|
| 112 |
+
"""The number of compressed bytes in the file stripe statistics"""
|
| 113 |
+
return self.reader.stripe_statistics_length()
|
| 114 |
+
|
| 115 |
+
@property
|
| 116 |
+
def file_footer_length(self):
|
| 117 |
+
"""The number of compressed bytes in the file footer"""
|
| 118 |
+
return self.reader.file_footer_length()
|
| 119 |
+
|
| 120 |
+
@property
|
| 121 |
+
def file_postscript_length(self):
|
| 122 |
+
"""The number of bytes in the file postscript"""
|
| 123 |
+
return self.reader.file_postscript_length()
|
| 124 |
+
|
| 125 |
+
@property
|
| 126 |
+
def file_length(self):
|
| 127 |
+
"""The number of bytes in the file"""
|
| 128 |
+
return self.reader.file_length()
|
| 129 |
+
|
| 130 |
+
def _select_names(self, columns=None):
|
| 131 |
+
if columns is None:
|
| 132 |
+
return None
|
| 133 |
+
|
| 134 |
+
schema = self.schema
|
| 135 |
+
names = []
|
| 136 |
+
for col in columns:
|
| 137 |
+
if isinstance(col, Integral):
|
| 138 |
+
col = int(col)
|
| 139 |
+
if 0 <= col < len(schema):
|
| 140 |
+
col = schema[col].name
|
| 141 |
+
names.append(col)
|
| 142 |
+
else:
|
| 143 |
+
raise ValueError("Column indices must be in 0 <= ind < %d,"
|
| 144 |
+
" got %d" % (len(schema), col))
|
| 145 |
+
else:
|
| 146 |
+
return columns
|
| 147 |
+
|
| 148 |
+
return names
|
| 149 |
+
|
| 150 |
+
def read_stripe(self, n, columns=None):
|
| 151 |
+
"""Read a single stripe from the file.
|
| 152 |
+
|
| 153 |
+
Parameters
|
| 154 |
+
----------
|
| 155 |
+
n : int
|
| 156 |
+
The stripe index
|
| 157 |
+
columns : list
|
| 158 |
+
If not None, only these columns will be read from the stripe. A
|
| 159 |
+
column name may be a prefix of a nested field, e.g. 'a' will select
|
| 160 |
+
'a.b', 'a.c', and 'a.d.e'
|
| 161 |
+
|
| 162 |
+
Returns
|
| 163 |
+
-------
|
| 164 |
+
pyarrow.RecordBatch
|
| 165 |
+
Content of the stripe as a RecordBatch.
|
| 166 |
+
"""
|
| 167 |
+
columns = self._select_names(columns)
|
| 168 |
+
return self.reader.read_stripe(n, columns=columns)
|
| 169 |
+
|
| 170 |
+
def read(self, columns=None):
|
| 171 |
+
"""Read the whole file.
|
| 172 |
+
|
| 173 |
+
Parameters
|
| 174 |
+
----------
|
| 175 |
+
columns : list
|
| 176 |
+
If not None, only these columns will be read from the file. A
|
| 177 |
+
column name may be a prefix of a nested field, e.g. 'a' will select
|
| 178 |
+
'a.b', 'a.c', and 'a.d.e'. Output always follows the
|
| 179 |
+
ordering of the file and not the `columns` list.
|
| 180 |
+
|
| 181 |
+
Returns
|
| 182 |
+
-------
|
| 183 |
+
pyarrow.Table
|
| 184 |
+
Content of the file as a Table.
|
| 185 |
+
"""
|
| 186 |
+
columns = self._select_names(columns)
|
| 187 |
+
return self.reader.read(columns=columns)
|
| 188 |
+
|
| 189 |
+
|
| 190 |
+
_orc_writer_args_docs = """file_version : {"0.11", "0.12"}, default "0.12"
|
| 191 |
+
Determine which ORC file version to use.
|
| 192 |
+
`Hive 0.11 / ORC v0 <https://orc.apache.org/specification/ORCv0/>`_
|
| 193 |
+
is the older version
|
| 194 |
+
while `Hive 0.12 / ORC v1 <https://orc.apache.org/specification/ORCv1/>`_
|
| 195 |
+
is the newer one.
|
| 196 |
+
batch_size : int, default 1024
|
| 197 |
+
Number of rows the ORC writer writes at a time.
|
| 198 |
+
stripe_size : int, default 64 * 1024 * 1024
|
| 199 |
+
Size of each ORC stripe in bytes.
|
| 200 |
+
compression : string, default 'uncompressed'
|
| 201 |
+
The compression codec.
|
| 202 |
+
Valid values: {'UNCOMPRESSED', 'SNAPPY', 'ZLIB', 'LZ4', 'ZSTD'}
|
| 203 |
+
Note that LZ0 is currently not supported.
|
| 204 |
+
compression_block_size : int, default 64 * 1024
|
| 205 |
+
Size of each compression block in bytes.
|
| 206 |
+
compression_strategy : string, default 'speed'
|
| 207 |
+
The compression strategy i.e. speed vs size reduction.
|
| 208 |
+
Valid values: {'SPEED', 'COMPRESSION'}
|
| 209 |
+
row_index_stride : int, default 10000
|
| 210 |
+
The row index stride i.e. the number of rows per
|
| 211 |
+
an entry in the row index.
|
| 212 |
+
padding_tolerance : double, default 0.0
|
| 213 |
+
The padding tolerance.
|
| 214 |
+
dictionary_key_size_threshold : double, default 0.0
|
| 215 |
+
The dictionary key size threshold. 0 to disable dictionary encoding.
|
| 216 |
+
1 to always enable dictionary encoding.
|
| 217 |
+
bloom_filter_columns : None, set-like or list-like, default None
|
| 218 |
+
Columns that use the bloom filter.
|
| 219 |
+
bloom_filter_fpp : double, default 0.05
|
| 220 |
+
Upper limit of the false-positive rate of the bloom filter.
|
| 221 |
+
"""
|
| 222 |
+
|
| 223 |
+
|
| 224 |
+
class ORCWriter:
|
| 225 |
+
__doc__ = """
|
| 226 |
+
Writer interface for a single ORC file
|
| 227 |
+
|
| 228 |
+
Parameters
|
| 229 |
+
----------
|
| 230 |
+
where : str or pyarrow.io.NativeFile
|
| 231 |
+
Writable target. For passing Python file objects or byte buffers,
|
| 232 |
+
see pyarrow.io.PythonFileInterface, pyarrow.io.BufferOutputStream
|
| 233 |
+
or pyarrow.io.FixedSizeBufferWriter.
|
| 234 |
+
{}
|
| 235 |
+
""".format(_orc_writer_args_docs)
|
| 236 |
+
|
| 237 |
+
is_open = False
|
| 238 |
+
|
| 239 |
+
def __init__(self, where, *,
|
| 240 |
+
file_version='0.12',
|
| 241 |
+
batch_size=1024,
|
| 242 |
+
stripe_size=64 * 1024 * 1024,
|
| 243 |
+
compression='uncompressed',
|
| 244 |
+
compression_block_size=65536,
|
| 245 |
+
compression_strategy='speed',
|
| 246 |
+
row_index_stride=10000,
|
| 247 |
+
padding_tolerance=0.0,
|
| 248 |
+
dictionary_key_size_threshold=0.0,
|
| 249 |
+
bloom_filter_columns=None,
|
| 250 |
+
bloom_filter_fpp=0.05,
|
| 251 |
+
):
|
| 252 |
+
self.writer = _orc.ORCWriter()
|
| 253 |
+
self.writer.open(
|
| 254 |
+
where,
|
| 255 |
+
file_version=file_version,
|
| 256 |
+
batch_size=batch_size,
|
| 257 |
+
stripe_size=stripe_size,
|
| 258 |
+
compression=compression,
|
| 259 |
+
compression_block_size=compression_block_size,
|
| 260 |
+
compression_strategy=compression_strategy,
|
| 261 |
+
row_index_stride=row_index_stride,
|
| 262 |
+
padding_tolerance=padding_tolerance,
|
| 263 |
+
dictionary_key_size_threshold=dictionary_key_size_threshold,
|
| 264 |
+
bloom_filter_columns=bloom_filter_columns,
|
| 265 |
+
bloom_filter_fpp=bloom_filter_fpp
|
| 266 |
+
)
|
| 267 |
+
self.is_open = True
|
| 268 |
+
|
| 269 |
+
def __del__(self):
|
| 270 |
+
self.close()
|
| 271 |
+
|
| 272 |
+
def __enter__(self):
|
| 273 |
+
return self
|
| 274 |
+
|
| 275 |
+
def __exit__(self, *args, **kwargs):
|
| 276 |
+
self.close()
|
| 277 |
+
|
| 278 |
+
def write(self, table):
|
| 279 |
+
"""
|
| 280 |
+
Write the table into an ORC file. The schema of the table must
|
| 281 |
+
be equal to the schema used when opening the ORC file.
|
| 282 |
+
|
| 283 |
+
Parameters
|
| 284 |
+
----------
|
| 285 |
+
table : pyarrow.Table
|
| 286 |
+
The table to be written into the ORC file
|
| 287 |
+
"""
|
| 288 |
+
assert self.is_open
|
| 289 |
+
self.writer.write(table)
|
| 290 |
+
|
| 291 |
+
def close(self):
|
| 292 |
+
"""
|
| 293 |
+
Close the ORC file
|
| 294 |
+
"""
|
| 295 |
+
if self.is_open:
|
| 296 |
+
self.writer.close()
|
| 297 |
+
self.is_open = False
|
| 298 |
+
|
| 299 |
+
|
| 300 |
+
def read_table(source, columns=None, filesystem=None):
|
| 301 |
+
filesystem, path = _resolve_filesystem_and_path(source, filesystem)
|
| 302 |
+
if filesystem is not None:
|
| 303 |
+
source = filesystem.open_input_file(path)
|
| 304 |
+
|
| 305 |
+
if columns is not None and len(columns) == 0:
|
| 306 |
+
result = ORCFile(source).read().select(columns)
|
| 307 |
+
else:
|
| 308 |
+
result = ORCFile(source).read(columns=columns)
|
| 309 |
+
|
| 310 |
+
return result
|
| 311 |
+
|
| 312 |
+
|
| 313 |
+
read_table.__doc__ = """
|
| 314 |
+
Read a Table from an ORC file.
|
| 315 |
+
|
| 316 |
+
Parameters
|
| 317 |
+
----------
|
| 318 |
+
source : str, pyarrow.NativeFile, or file-like object
|
| 319 |
+
If a string passed, can be a single file name. For file-like objects,
|
| 320 |
+
only read a single file. Use pyarrow.BufferReader to read a file
|
| 321 |
+
contained in a bytes or buffer-like object.
|
| 322 |
+
columns : list
|
| 323 |
+
If not None, only these columns will be read from the file. A column
|
| 324 |
+
name may be a prefix of a nested field, e.g. 'a' will select 'a.b',
|
| 325 |
+
'a.c', and 'a.d.e'. Output always follows the ordering of the file and
|
| 326 |
+
not the `columns` list. If empty, no columns will be read. Note
|
| 327 |
+
that the table will still have the correct num_rows set despite having
|
| 328 |
+
no columns.
|
| 329 |
+
filesystem : FileSystem, default None
|
| 330 |
+
If nothing passed, will be inferred based on path.
|
| 331 |
+
Path will try to be found in the local on-disk filesystem otherwise
|
| 332 |
+
it will be parsed as an URI to determine the filesystem.
|
| 333 |
+
"""
|
| 334 |
+
|
| 335 |
+
|
| 336 |
+
def write_table(table, where, *,
|
| 337 |
+
file_version='0.12',
|
| 338 |
+
batch_size=1024,
|
| 339 |
+
stripe_size=64 * 1024 * 1024,
|
| 340 |
+
compression='uncompressed',
|
| 341 |
+
compression_block_size=65536,
|
| 342 |
+
compression_strategy='speed',
|
| 343 |
+
row_index_stride=10000,
|
| 344 |
+
padding_tolerance=0.0,
|
| 345 |
+
dictionary_key_size_threshold=0.0,
|
| 346 |
+
bloom_filter_columns=None,
|
| 347 |
+
bloom_filter_fpp=0.05):
|
| 348 |
+
if isinstance(where, Table):
|
| 349 |
+
warnings.warn(
|
| 350 |
+
"The order of the arguments has changed. Pass as "
|
| 351 |
+
"'write_table(table, where)' instead. The old order will raise "
|
| 352 |
+
"an error in the future.", FutureWarning, stacklevel=2
|
| 353 |
+
)
|
| 354 |
+
table, where = where, table
|
| 355 |
+
with ORCWriter(
|
| 356 |
+
where,
|
| 357 |
+
file_version=file_version,
|
| 358 |
+
batch_size=batch_size,
|
| 359 |
+
stripe_size=stripe_size,
|
| 360 |
+
compression=compression,
|
| 361 |
+
compression_block_size=compression_block_size,
|
| 362 |
+
compression_strategy=compression_strategy,
|
| 363 |
+
row_index_stride=row_index_stride,
|
| 364 |
+
padding_tolerance=padding_tolerance,
|
| 365 |
+
dictionary_key_size_threshold=dictionary_key_size_threshold,
|
| 366 |
+
bloom_filter_columns=bloom_filter_columns,
|
| 367 |
+
bloom_filter_fpp=bloom_filter_fpp
|
| 368 |
+
) as writer:
|
| 369 |
+
writer.write(table)
|
| 370 |
+
|
| 371 |
+
|
| 372 |
+
write_table.__doc__ = """
|
| 373 |
+
Write a table into an ORC file.
|
| 374 |
+
|
| 375 |
+
Parameters
|
| 376 |
+
----------
|
| 377 |
+
table : pyarrow.lib.Table
|
| 378 |
+
The table to be written into the ORC file
|
| 379 |
+
where : str or pyarrow.io.NativeFile
|
| 380 |
+
Writable target. For passing Python file objects or byte buffers,
|
| 381 |
+
see pyarrow.io.PythonFileInterface, pyarrow.io.BufferOutputStream
|
| 382 |
+
or pyarrow.io.FixedSizeBufferWriter.
|
| 383 |
+
{}
|
| 384 |
+
""".format(_orc_writer_args_docs)
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/pyarrow/pandas_compat.py
ADDED
|
@@ -0,0 +1,1277 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Licensed to the Apache Software Foundation (ASF) under one
|
| 2 |
+
# or more contributor license agreements. See the NOTICE file
|
| 3 |
+
# distributed with this work for additional information
|
| 4 |
+
# regarding copyright ownership. The ASF licenses this file
|
| 5 |
+
# to you under the Apache License, Version 2.0 (the
|
| 6 |
+
# "License"); you may not use this file except in compliance
|
| 7 |
+
# with the License. You may obtain a copy of the License at
|
| 8 |
+
#
|
| 9 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 10 |
+
#
|
| 11 |
+
# Unless required by applicable law or agreed to in writing,
|
| 12 |
+
# software distributed under the License is distributed on an
|
| 13 |
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
| 14 |
+
# KIND, either express or implied. See the License for the
|
| 15 |
+
# specific language governing permissions and limitations
|
| 16 |
+
# under the License.
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
import ast
|
| 20 |
+
from collections.abc import Sequence
|
| 21 |
+
from concurrent import futures
|
| 22 |
+
# import threading submodule upfront to avoid partially initialized
|
| 23 |
+
# module bug (ARROW-11983)
|
| 24 |
+
import concurrent.futures.thread # noqa
|
| 25 |
+
from copy import deepcopy
|
| 26 |
+
import decimal
|
| 27 |
+
from itertools import zip_longest
|
| 28 |
+
import json
|
| 29 |
+
import operator
|
| 30 |
+
import re
|
| 31 |
+
import warnings
|
| 32 |
+
|
| 33 |
+
try:
|
| 34 |
+
import numpy as np
|
| 35 |
+
except ImportError:
|
| 36 |
+
np = None
|
| 37 |
+
import pyarrow as pa
|
| 38 |
+
from pyarrow.lib import _pandas_api, frombytes, is_threading_enabled # noqa
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
_logical_type_map = {}
|
| 42 |
+
_numpy_logical_type_map = {}
|
| 43 |
+
_pandas_logical_type_map = {}
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
def get_logical_type_map():
|
| 47 |
+
global _logical_type_map
|
| 48 |
+
|
| 49 |
+
if not _logical_type_map:
|
| 50 |
+
_logical_type_map.update({
|
| 51 |
+
pa.lib.Type_NA: 'empty',
|
| 52 |
+
pa.lib.Type_BOOL: 'bool',
|
| 53 |
+
pa.lib.Type_INT8: 'int8',
|
| 54 |
+
pa.lib.Type_INT16: 'int16',
|
| 55 |
+
pa.lib.Type_INT32: 'int32',
|
| 56 |
+
pa.lib.Type_INT64: 'int64',
|
| 57 |
+
pa.lib.Type_UINT8: 'uint8',
|
| 58 |
+
pa.lib.Type_UINT16: 'uint16',
|
| 59 |
+
pa.lib.Type_UINT32: 'uint32',
|
| 60 |
+
pa.lib.Type_UINT64: 'uint64',
|
| 61 |
+
pa.lib.Type_HALF_FLOAT: 'float16',
|
| 62 |
+
pa.lib.Type_FLOAT: 'float32',
|
| 63 |
+
pa.lib.Type_DOUBLE: 'float64',
|
| 64 |
+
pa.lib.Type_DATE32: 'date',
|
| 65 |
+
pa.lib.Type_DATE64: 'date',
|
| 66 |
+
pa.lib.Type_TIME32: 'time',
|
| 67 |
+
pa.lib.Type_TIME64: 'time',
|
| 68 |
+
pa.lib.Type_BINARY: 'bytes',
|
| 69 |
+
pa.lib.Type_FIXED_SIZE_BINARY: 'bytes',
|
| 70 |
+
pa.lib.Type_STRING: 'unicode',
|
| 71 |
+
})
|
| 72 |
+
return _logical_type_map
|
| 73 |
+
|
| 74 |
+
|
| 75 |
+
def get_logical_type(arrow_type):
|
| 76 |
+
logical_type_map = get_logical_type_map()
|
| 77 |
+
|
| 78 |
+
try:
|
| 79 |
+
return logical_type_map[arrow_type.id]
|
| 80 |
+
except KeyError:
|
| 81 |
+
if isinstance(arrow_type, pa.lib.DictionaryType):
|
| 82 |
+
return 'categorical'
|
| 83 |
+
elif isinstance(arrow_type, pa.lib.ListType):
|
| 84 |
+
return 'list[{}]'.format(get_logical_type(arrow_type.value_type))
|
| 85 |
+
elif isinstance(arrow_type, pa.lib.TimestampType):
|
| 86 |
+
return 'datetimetz' if arrow_type.tz is not None else 'datetime'
|
| 87 |
+
elif isinstance(arrow_type, pa.lib.Decimal128Type):
|
| 88 |
+
return 'decimal'
|
| 89 |
+
return 'object'
|
| 90 |
+
|
| 91 |
+
|
| 92 |
+
def get_numpy_logical_type_map():
|
| 93 |
+
global _numpy_logical_type_map
|
| 94 |
+
if not _numpy_logical_type_map:
|
| 95 |
+
_numpy_logical_type_map.update({
|
| 96 |
+
np.bool_: 'bool',
|
| 97 |
+
np.int8: 'int8',
|
| 98 |
+
np.int16: 'int16',
|
| 99 |
+
np.int32: 'int32',
|
| 100 |
+
np.int64: 'int64',
|
| 101 |
+
np.uint8: 'uint8',
|
| 102 |
+
np.uint16: 'uint16',
|
| 103 |
+
np.uint32: 'uint32',
|
| 104 |
+
np.uint64: 'uint64',
|
| 105 |
+
np.float32: 'float32',
|
| 106 |
+
np.float64: 'float64',
|
| 107 |
+
'datetime64[D]': 'date',
|
| 108 |
+
np.str_: 'string',
|
| 109 |
+
np.bytes_: 'bytes',
|
| 110 |
+
})
|
| 111 |
+
return _numpy_logical_type_map
|
| 112 |
+
|
| 113 |
+
|
| 114 |
+
def get_logical_type_from_numpy(pandas_collection):
|
| 115 |
+
numpy_logical_type_map = get_numpy_logical_type_map()
|
| 116 |
+
try:
|
| 117 |
+
return numpy_logical_type_map[pandas_collection.dtype.type]
|
| 118 |
+
except KeyError:
|
| 119 |
+
if hasattr(pandas_collection.dtype, 'tz'):
|
| 120 |
+
return 'datetimetz'
|
| 121 |
+
# See https://github.com/pandas-dev/pandas/issues/24739 (infer_dtype will
|
| 122 |
+
# result in "datetime64" without unit, while pandas astype requires a unit)
|
| 123 |
+
if str(pandas_collection.dtype).startswith('datetime64'):
|
| 124 |
+
return str(pandas_collection.dtype)
|
| 125 |
+
result = _pandas_api.infer_dtype(pandas_collection)
|
| 126 |
+
if result == 'string':
|
| 127 |
+
return 'unicode'
|
| 128 |
+
return result
|
| 129 |
+
|
| 130 |
+
|
| 131 |
+
def get_extension_dtype_info(column):
|
| 132 |
+
dtype = column.dtype
|
| 133 |
+
if str(dtype) == 'category':
|
| 134 |
+
cats = getattr(column, 'cat', column)
|
| 135 |
+
assert cats is not None
|
| 136 |
+
metadata = {
|
| 137 |
+
'num_categories': len(cats.categories),
|
| 138 |
+
'ordered': cats.ordered,
|
| 139 |
+
}
|
| 140 |
+
physical_dtype = str(cats.codes.dtype)
|
| 141 |
+
elif hasattr(dtype, 'tz'):
|
| 142 |
+
metadata = {'timezone': pa.lib.tzinfo_to_string(dtype.tz)}
|
| 143 |
+
physical_dtype = 'datetime64[ns]'
|
| 144 |
+
else:
|
| 145 |
+
metadata = None
|
| 146 |
+
physical_dtype = str(dtype)
|
| 147 |
+
return physical_dtype, metadata
|
| 148 |
+
|
| 149 |
+
|
| 150 |
+
def get_column_metadata(column, name, arrow_type, field_name):
|
| 151 |
+
"""Construct the metadata for a given column
|
| 152 |
+
|
| 153 |
+
Parameters
|
| 154 |
+
----------
|
| 155 |
+
column : pandas.Series or pandas.Index
|
| 156 |
+
name : str
|
| 157 |
+
arrow_type : pyarrow.DataType
|
| 158 |
+
field_name : str
|
| 159 |
+
Equivalent to `name` when `column` is a `Series`, otherwise if `column`
|
| 160 |
+
is a pandas Index then `field_name` will not be the same as `name`.
|
| 161 |
+
This is the name of the field in the arrow Table's schema.
|
| 162 |
+
|
| 163 |
+
Returns
|
| 164 |
+
-------
|
| 165 |
+
dict
|
| 166 |
+
"""
|
| 167 |
+
logical_type = get_logical_type(arrow_type)
|
| 168 |
+
|
| 169 |
+
string_dtype, extra_metadata = get_extension_dtype_info(column)
|
| 170 |
+
if logical_type == 'decimal':
|
| 171 |
+
extra_metadata = {
|
| 172 |
+
'precision': arrow_type.precision,
|
| 173 |
+
'scale': arrow_type.scale,
|
| 174 |
+
}
|
| 175 |
+
string_dtype = 'object'
|
| 176 |
+
|
| 177 |
+
if (
|
| 178 |
+
name is not None
|
| 179 |
+
and not (isinstance(name, float) and np.isnan(name))
|
| 180 |
+
and not isinstance(name, str)
|
| 181 |
+
):
|
| 182 |
+
raise TypeError(
|
| 183 |
+
'Column name must be a string. Got column {} of type {}'.format(
|
| 184 |
+
name, type(name).__name__
|
| 185 |
+
)
|
| 186 |
+
)
|
| 187 |
+
|
| 188 |
+
assert isinstance(field_name, str), str(type(field_name))
|
| 189 |
+
return {
|
| 190 |
+
'name': name,
|
| 191 |
+
'field_name': field_name,
|
| 192 |
+
'pandas_type': logical_type,
|
| 193 |
+
'numpy_type': string_dtype,
|
| 194 |
+
'metadata': extra_metadata,
|
| 195 |
+
}
|
| 196 |
+
|
| 197 |
+
|
| 198 |
+
def construct_metadata(columns_to_convert, df, column_names, index_levels,
|
| 199 |
+
index_descriptors, preserve_index, types,
|
| 200 |
+
column_field_names=None):
|
| 201 |
+
"""Returns a dictionary containing enough metadata to reconstruct a pandas
|
| 202 |
+
DataFrame as an Arrow Table, including index columns.
|
| 203 |
+
|
| 204 |
+
Parameters
|
| 205 |
+
----------
|
| 206 |
+
columns_to_convert : list[pd.Series]
|
| 207 |
+
df : pandas.DataFrame
|
| 208 |
+
column_names : list[str | None]
|
| 209 |
+
column_field_names: list[str]
|
| 210 |
+
index_levels : List[pd.Index]
|
| 211 |
+
index_descriptors : List[Dict]
|
| 212 |
+
preserve_index : bool
|
| 213 |
+
types : List[pyarrow.DataType]
|
| 214 |
+
|
| 215 |
+
Returns
|
| 216 |
+
-------
|
| 217 |
+
dict
|
| 218 |
+
"""
|
| 219 |
+
if column_field_names is None:
|
| 220 |
+
# backwards compatibility for external projects that are using
|
| 221 |
+
# `construct_metadata` such as cudf
|
| 222 |
+
# see https://github.com/apache/arrow/pull/44963#discussion_r1875771953
|
| 223 |
+
column_field_names = [str(name) for name in column_names]
|
| 224 |
+
|
| 225 |
+
num_serialized_index_levels = len([descr for descr in index_descriptors
|
| 226 |
+
if not isinstance(descr, dict)])
|
| 227 |
+
# Use ntypes instead of Python shorthand notation [:-len(x)] as [:-0]
|
| 228 |
+
# behaves differently to what we want.
|
| 229 |
+
ntypes = len(types)
|
| 230 |
+
df_types = types[:ntypes - num_serialized_index_levels]
|
| 231 |
+
index_types = types[ntypes - num_serialized_index_levels:]
|
| 232 |
+
|
| 233 |
+
column_metadata = []
|
| 234 |
+
for col, name, field_name, arrow_type in zip(columns_to_convert, column_names,
|
| 235 |
+
column_field_names, df_types):
|
| 236 |
+
metadata = get_column_metadata(col, name=name,
|
| 237 |
+
arrow_type=arrow_type,
|
| 238 |
+
field_name=field_name)
|
| 239 |
+
column_metadata.append(metadata)
|
| 240 |
+
|
| 241 |
+
index_column_metadata = []
|
| 242 |
+
if preserve_index is not False:
|
| 243 |
+
non_str_index_names = []
|
| 244 |
+
for level, arrow_type, descriptor in zip(index_levels, index_types,
|
| 245 |
+
index_descriptors):
|
| 246 |
+
if isinstance(descriptor, dict):
|
| 247 |
+
# The index is represented in a non-serialized fashion,
|
| 248 |
+
# e.g. RangeIndex
|
| 249 |
+
continue
|
| 250 |
+
|
| 251 |
+
if level.name is not None and not isinstance(level.name, str):
|
| 252 |
+
non_str_index_names.append(level.name)
|
| 253 |
+
|
| 254 |
+
metadata = get_column_metadata(
|
| 255 |
+
level,
|
| 256 |
+
name=_column_name_to_strings(level.name),
|
| 257 |
+
arrow_type=arrow_type,
|
| 258 |
+
field_name=descriptor,
|
| 259 |
+
)
|
| 260 |
+
index_column_metadata.append(metadata)
|
| 261 |
+
|
| 262 |
+
if len(non_str_index_names) > 0:
|
| 263 |
+
warnings.warn(
|
| 264 |
+
f"The DataFrame has non-str index name `{non_str_index_names}`"
|
| 265 |
+
" which will be converted to string"
|
| 266 |
+
" and not roundtrip correctly.",
|
| 267 |
+
UserWarning, stacklevel=4)
|
| 268 |
+
|
| 269 |
+
column_indexes = []
|
| 270 |
+
|
| 271 |
+
levels = getattr(df.columns, 'levels', [df.columns])
|
| 272 |
+
names = getattr(df.columns, 'names', [df.columns.name])
|
| 273 |
+
for level, name in zip(levels, names):
|
| 274 |
+
metadata = _get_simple_index_descriptor(level, name)
|
| 275 |
+
column_indexes.append(metadata)
|
| 276 |
+
else:
|
| 277 |
+
index_descriptors = index_column_metadata = column_indexes = []
|
| 278 |
+
|
| 279 |
+
return {
|
| 280 |
+
b'pandas': json.dumps({
|
| 281 |
+
'index_columns': index_descriptors,
|
| 282 |
+
'column_indexes': column_indexes,
|
| 283 |
+
'columns': column_metadata + index_column_metadata,
|
| 284 |
+
'creator': {
|
| 285 |
+
'library': 'pyarrow',
|
| 286 |
+
'version': pa.__version__
|
| 287 |
+
},
|
| 288 |
+
'pandas_version': _pandas_api.version
|
| 289 |
+
}).encode('utf8')
|
| 290 |
+
}
|
| 291 |
+
|
| 292 |
+
|
| 293 |
+
def _get_simple_index_descriptor(level, name):
|
| 294 |
+
string_dtype, extra_metadata = get_extension_dtype_info(level)
|
| 295 |
+
pandas_type = get_logical_type_from_numpy(level)
|
| 296 |
+
if 'mixed' in pandas_type:
|
| 297 |
+
warnings.warn(
|
| 298 |
+
"The DataFrame has column names of mixed type. They will be "
|
| 299 |
+
"converted to strings and not roundtrip correctly.",
|
| 300 |
+
UserWarning, stacklevel=4)
|
| 301 |
+
if pandas_type == 'unicode':
|
| 302 |
+
assert not extra_metadata
|
| 303 |
+
extra_metadata = {'encoding': 'UTF-8'}
|
| 304 |
+
return {
|
| 305 |
+
'name': name,
|
| 306 |
+
'field_name': name,
|
| 307 |
+
'pandas_type': pandas_type,
|
| 308 |
+
'numpy_type': string_dtype,
|
| 309 |
+
'metadata': extra_metadata,
|
| 310 |
+
}
|
| 311 |
+
|
| 312 |
+
|
| 313 |
+
def _column_name_to_strings(name):
|
| 314 |
+
"""Convert a column name (or level) to either a string or a recursive
|
| 315 |
+
collection of strings.
|
| 316 |
+
|
| 317 |
+
Parameters
|
| 318 |
+
----------
|
| 319 |
+
name : str or tuple
|
| 320 |
+
|
| 321 |
+
Returns
|
| 322 |
+
-------
|
| 323 |
+
value : str or tuple
|
| 324 |
+
|
| 325 |
+
Examples
|
| 326 |
+
--------
|
| 327 |
+
>>> name = 'foo'
|
| 328 |
+
>>> _column_name_to_strings(name)
|
| 329 |
+
'foo'
|
| 330 |
+
>>> name = ('foo', 'bar')
|
| 331 |
+
>>> _column_name_to_strings(name)
|
| 332 |
+
"('foo', 'bar')"
|
| 333 |
+
>>> import pandas as pd
|
| 334 |
+
>>> name = (1, pd.Timestamp('2017-02-01 00:00:00'))
|
| 335 |
+
>>> _column_name_to_strings(name)
|
| 336 |
+
"('1', '2017-02-01 00:00:00')"
|
| 337 |
+
"""
|
| 338 |
+
if isinstance(name, str):
|
| 339 |
+
return name
|
| 340 |
+
elif isinstance(name, bytes):
|
| 341 |
+
# XXX: should we assume that bytes in Python 3 are UTF-8?
|
| 342 |
+
return name.decode('utf8')
|
| 343 |
+
elif isinstance(name, tuple):
|
| 344 |
+
return str(tuple(map(_column_name_to_strings, name)))
|
| 345 |
+
elif isinstance(name, Sequence):
|
| 346 |
+
raise TypeError("Unsupported type for MultiIndex level")
|
| 347 |
+
elif name is None or (isinstance(name, float) and np.isnan(name)):
|
| 348 |
+
return name
|
| 349 |
+
return str(name)
|
| 350 |
+
|
| 351 |
+
|
| 352 |
+
def _index_level_name(index, i, column_names):
|
| 353 |
+
"""Return the name of an index level or a default name if `index.name` is
|
| 354 |
+
None or is already a column name.
|
| 355 |
+
|
| 356 |
+
Parameters
|
| 357 |
+
----------
|
| 358 |
+
index : pandas.Index
|
| 359 |
+
i : int
|
| 360 |
+
|
| 361 |
+
Returns
|
| 362 |
+
-------
|
| 363 |
+
name : str
|
| 364 |
+
"""
|
| 365 |
+
if index.name is not None and index.name not in column_names:
|
| 366 |
+
return _column_name_to_strings(index.name)
|
| 367 |
+
else:
|
| 368 |
+
return '__index_level_{:d}__'.format(i)
|
| 369 |
+
|
| 370 |
+
|
| 371 |
+
def _get_columns_to_convert(df, schema, preserve_index, columns):
|
| 372 |
+
columns = _resolve_columns_of_interest(df, schema, columns)
|
| 373 |
+
|
| 374 |
+
if not df.columns.is_unique:
|
| 375 |
+
raise ValueError(
|
| 376 |
+
'Duplicate column names found: {}'.format(list(df.columns))
|
| 377 |
+
)
|
| 378 |
+
|
| 379 |
+
if schema is not None:
|
| 380 |
+
return _get_columns_to_convert_given_schema(df, schema, preserve_index)
|
| 381 |
+
|
| 382 |
+
column_names = []
|
| 383 |
+
column_field_names = []
|
| 384 |
+
|
| 385 |
+
index_levels = (
|
| 386 |
+
_get_index_level_values(df.index) if preserve_index is not False
|
| 387 |
+
else []
|
| 388 |
+
)
|
| 389 |
+
|
| 390 |
+
columns_to_convert = []
|
| 391 |
+
convert_fields = []
|
| 392 |
+
|
| 393 |
+
for name in columns:
|
| 394 |
+
col = df[name]
|
| 395 |
+
name = _column_name_to_strings(name)
|
| 396 |
+
|
| 397 |
+
if _pandas_api.is_sparse(col):
|
| 398 |
+
raise TypeError(
|
| 399 |
+
"Sparse pandas data (column {}) not supported.".format(name))
|
| 400 |
+
|
| 401 |
+
columns_to_convert.append(col)
|
| 402 |
+
convert_fields.append(None)
|
| 403 |
+
column_names.append(name)
|
| 404 |
+
column_field_names.append(str(name))
|
| 405 |
+
|
| 406 |
+
index_descriptors = []
|
| 407 |
+
index_column_names = []
|
| 408 |
+
for i, index_level in enumerate(index_levels):
|
| 409 |
+
name = _index_level_name(index_level, i, column_names)
|
| 410 |
+
if (isinstance(index_level, _pandas_api.pd.RangeIndex) and
|
| 411 |
+
preserve_index is None):
|
| 412 |
+
descr = _get_range_index_descriptor(index_level)
|
| 413 |
+
else:
|
| 414 |
+
columns_to_convert.append(index_level)
|
| 415 |
+
convert_fields.append(None)
|
| 416 |
+
descr = name
|
| 417 |
+
index_column_names.append(name)
|
| 418 |
+
index_descriptors.append(descr)
|
| 419 |
+
|
| 420 |
+
all_names = column_field_names + index_column_names
|
| 421 |
+
|
| 422 |
+
# all_names : all of the columns in the resulting table including the data
|
| 423 |
+
# columns and serialized index columns
|
| 424 |
+
# column_names : the names of the data columns
|
| 425 |
+
# index_column_names : the names of the serialized index columns
|
| 426 |
+
# index_descriptors : descriptions of each index to be used for
|
| 427 |
+
# reconstruction
|
| 428 |
+
# index_levels : the extracted index level values
|
| 429 |
+
# columns_to_convert : assembled raw data (both data columns and indexes)
|
| 430 |
+
# to be converted to Arrow format
|
| 431 |
+
# columns_fields : specified column to use for coercion / casting
|
| 432 |
+
# during serialization, if a Schema was provided
|
| 433 |
+
return (all_names, column_names, column_field_names, index_column_names,
|
| 434 |
+
index_descriptors, index_levels, columns_to_convert, convert_fields)
|
| 435 |
+
|
| 436 |
+
|
| 437 |
+
def _get_columns_to_convert_given_schema(df, schema, preserve_index):
|
| 438 |
+
"""
|
| 439 |
+
Specialized version of _get_columns_to_convert in case a Schema is
|
| 440 |
+
specified.
|
| 441 |
+
In that case, the Schema is used as the single point of truth for the
|
| 442 |
+
table structure (types, which columns are included, order of columns, ...).
|
| 443 |
+
"""
|
| 444 |
+
column_names = []
|
| 445 |
+
columns_to_convert = []
|
| 446 |
+
convert_fields = []
|
| 447 |
+
index_descriptors = []
|
| 448 |
+
index_column_names = []
|
| 449 |
+
index_levels = []
|
| 450 |
+
|
| 451 |
+
for name in schema.names:
|
| 452 |
+
try:
|
| 453 |
+
col = df[name]
|
| 454 |
+
is_index = False
|
| 455 |
+
except KeyError:
|
| 456 |
+
try:
|
| 457 |
+
col = _get_index_level(df, name)
|
| 458 |
+
except (KeyError, IndexError):
|
| 459 |
+
# name not found as index level
|
| 460 |
+
raise KeyError(
|
| 461 |
+
"name '{}' present in the specified schema is not found "
|
| 462 |
+
"in the columns or index".format(name))
|
| 463 |
+
if preserve_index is False:
|
| 464 |
+
raise ValueError(
|
| 465 |
+
"name '{}' present in the specified schema corresponds "
|
| 466 |
+
"to the index, but 'preserve_index=False' was "
|
| 467 |
+
"specified".format(name))
|
| 468 |
+
elif (preserve_index is None and
|
| 469 |
+
isinstance(col, _pandas_api.pd.RangeIndex)):
|
| 470 |
+
raise ValueError(
|
| 471 |
+
"name '{}' is present in the schema, but it is a "
|
| 472 |
+
"RangeIndex which will not be converted as a column "
|
| 473 |
+
"in the Table, but saved as metadata-only not in "
|
| 474 |
+
"columns. Specify 'preserve_index=True' to force it "
|
| 475 |
+
"being added as a column, or remove it from the "
|
| 476 |
+
"specified schema".format(name))
|
| 477 |
+
is_index = True
|
| 478 |
+
|
| 479 |
+
if _pandas_api.is_sparse(col):
|
| 480 |
+
raise TypeError(
|
| 481 |
+
"Sparse pandas data (column {}) not supported.".format(name))
|
| 482 |
+
|
| 483 |
+
field = schema.field(name)
|
| 484 |
+
columns_to_convert.append(col)
|
| 485 |
+
convert_fields.append(field)
|
| 486 |
+
column_names.append(name)
|
| 487 |
+
|
| 488 |
+
if is_index:
|
| 489 |
+
index_column_names.append(name)
|
| 490 |
+
index_descriptors.append(name)
|
| 491 |
+
index_levels.append(col)
|
| 492 |
+
|
| 493 |
+
all_names = column_names + index_column_names
|
| 494 |
+
|
| 495 |
+
return (all_names, column_names, column_names, index_column_names,
|
| 496 |
+
index_descriptors, index_levels, columns_to_convert, convert_fields)
|
| 497 |
+
|
| 498 |
+
|
| 499 |
+
def _get_index_level(df, name):
|
| 500 |
+
"""
|
| 501 |
+
Get the index level of a DataFrame given 'name' (column name in an arrow
|
| 502 |
+
Schema).
|
| 503 |
+
"""
|
| 504 |
+
key = name
|
| 505 |
+
if name not in df.index.names and _is_generated_index_name(name):
|
| 506 |
+
# we know we have an autogenerated name => extract number and get
|
| 507 |
+
# the index level positionally
|
| 508 |
+
key = int(name[len("__index_level_"):-2])
|
| 509 |
+
return df.index.get_level_values(key)
|
| 510 |
+
|
| 511 |
+
|
| 512 |
+
def _level_name(name):
|
| 513 |
+
# preserve type when default serializable, otherwise str it
|
| 514 |
+
try:
|
| 515 |
+
json.dumps(name)
|
| 516 |
+
return name
|
| 517 |
+
except TypeError:
|
| 518 |
+
return str(name)
|
| 519 |
+
|
| 520 |
+
|
| 521 |
+
def _get_range_index_descriptor(level):
|
| 522 |
+
# public start/stop/step attributes added in pandas 0.25.0
|
| 523 |
+
return {
|
| 524 |
+
'kind': 'range',
|
| 525 |
+
'name': _level_name(level.name),
|
| 526 |
+
'start': _pandas_api.get_rangeindex_attribute(level, 'start'),
|
| 527 |
+
'stop': _pandas_api.get_rangeindex_attribute(level, 'stop'),
|
| 528 |
+
'step': _pandas_api.get_rangeindex_attribute(level, 'step')
|
| 529 |
+
}
|
| 530 |
+
|
| 531 |
+
|
| 532 |
+
def _get_index_level_values(index):
|
| 533 |
+
n = len(getattr(index, 'levels', [index]))
|
| 534 |
+
return [index.get_level_values(i) for i in range(n)]
|
| 535 |
+
|
| 536 |
+
|
| 537 |
+
def _resolve_columns_of_interest(df, schema, columns):
|
| 538 |
+
if schema is not None and columns is not None:
|
| 539 |
+
raise ValueError('Schema and columns arguments are mutually '
|
| 540 |
+
'exclusive, pass only one of them')
|
| 541 |
+
elif schema is not None:
|
| 542 |
+
columns = schema.names
|
| 543 |
+
elif columns is not None:
|
| 544 |
+
columns = [c for c in columns if c in df.columns]
|
| 545 |
+
else:
|
| 546 |
+
columns = df.columns
|
| 547 |
+
|
| 548 |
+
return columns
|
| 549 |
+
|
| 550 |
+
|
| 551 |
+
def dataframe_to_types(df, preserve_index, columns=None):
|
| 552 |
+
(all_names,
|
| 553 |
+
column_names,
|
| 554 |
+
column_field_names,
|
| 555 |
+
_,
|
| 556 |
+
index_descriptors,
|
| 557 |
+
index_columns,
|
| 558 |
+
columns_to_convert,
|
| 559 |
+
_) = _get_columns_to_convert(df, None, preserve_index, columns)
|
| 560 |
+
|
| 561 |
+
types = []
|
| 562 |
+
# If pandas knows type, skip conversion
|
| 563 |
+
for c in columns_to_convert:
|
| 564 |
+
values = c.values
|
| 565 |
+
if _pandas_api.is_categorical(values):
|
| 566 |
+
type_ = pa.array(c, from_pandas=True).type
|
| 567 |
+
elif _pandas_api.is_extension_array_dtype(values):
|
| 568 |
+
empty = c.head(0) if isinstance(
|
| 569 |
+
c, _pandas_api.pd.Series) else c[:0]
|
| 570 |
+
type_ = pa.array(empty, from_pandas=True).type
|
| 571 |
+
else:
|
| 572 |
+
values, type_ = get_datetimetz_type(values, c.dtype, None)
|
| 573 |
+
type_ = pa.lib._ndarray_to_arrow_type(values, type_)
|
| 574 |
+
if type_ is None:
|
| 575 |
+
type_ = pa.array(c, from_pandas=True).type
|
| 576 |
+
types.append(type_)
|
| 577 |
+
|
| 578 |
+
metadata = construct_metadata(
|
| 579 |
+
columns_to_convert, df, column_names, index_columns, index_descriptors,
|
| 580 |
+
preserve_index, types, column_field_names=column_field_names
|
| 581 |
+
)
|
| 582 |
+
|
| 583 |
+
return all_names, types, metadata
|
| 584 |
+
|
| 585 |
+
|
| 586 |
+
def dataframe_to_arrays(df, schema, preserve_index, nthreads=1, columns=None,
|
| 587 |
+
safe=True):
|
| 588 |
+
(all_names,
|
| 589 |
+
column_names,
|
| 590 |
+
column_field_names,
|
| 591 |
+
index_column_names,
|
| 592 |
+
index_descriptors,
|
| 593 |
+
index_columns,
|
| 594 |
+
columns_to_convert,
|
| 595 |
+
convert_fields) = _get_columns_to_convert(df, schema, preserve_index,
|
| 596 |
+
columns)
|
| 597 |
+
|
| 598 |
+
# NOTE(wesm): If nthreads=None, then we use a heuristic to decide whether
|
| 599 |
+
# using a thread pool is worth it. Currently the heuristic is whether the
|
| 600 |
+
# nrows > 100 * ncols and ncols > 1.
|
| 601 |
+
if nthreads is None:
|
| 602 |
+
nrows, ncols = len(df), len(df.columns)
|
| 603 |
+
if nrows > ncols * 100 and ncols > 1:
|
| 604 |
+
nthreads = pa.cpu_count()
|
| 605 |
+
else:
|
| 606 |
+
nthreads = 1
|
| 607 |
+
# if we don't have threading in libarrow, don't use threading here either
|
| 608 |
+
if not is_threading_enabled():
|
| 609 |
+
nthreads = 1
|
| 610 |
+
|
| 611 |
+
def convert_column(col, field):
|
| 612 |
+
if field is None:
|
| 613 |
+
field_nullable = True
|
| 614 |
+
type_ = None
|
| 615 |
+
else:
|
| 616 |
+
field_nullable = field.nullable
|
| 617 |
+
type_ = field.type
|
| 618 |
+
|
| 619 |
+
try:
|
| 620 |
+
result = pa.array(col, type=type_, from_pandas=True, safe=safe)
|
| 621 |
+
except (pa.ArrowInvalid,
|
| 622 |
+
pa.ArrowNotImplementedError,
|
| 623 |
+
pa.ArrowTypeError) as e:
|
| 624 |
+
e.args += ("Conversion failed for column {!s} with type {!s}"
|
| 625 |
+
.format(col.name, col.dtype),)
|
| 626 |
+
raise e
|
| 627 |
+
if not field_nullable and result.null_count > 0:
|
| 628 |
+
raise ValueError("Field {} was non-nullable but pandas column "
|
| 629 |
+
"had {} null values".format(str(field),
|
| 630 |
+
result.null_count))
|
| 631 |
+
return result
|
| 632 |
+
|
| 633 |
+
def _can_definitely_zero_copy(arr):
|
| 634 |
+
return (isinstance(arr, np.ndarray) and
|
| 635 |
+
arr.flags.contiguous and
|
| 636 |
+
issubclass(arr.dtype.type, np.integer))
|
| 637 |
+
|
| 638 |
+
if nthreads == 1:
|
| 639 |
+
arrays = [convert_column(c, f)
|
| 640 |
+
for c, f in zip(columns_to_convert, convert_fields)]
|
| 641 |
+
else:
|
| 642 |
+
arrays = []
|
| 643 |
+
with futures.ThreadPoolExecutor(nthreads) as executor:
|
| 644 |
+
for c, f in zip(columns_to_convert, convert_fields):
|
| 645 |
+
if _can_definitely_zero_copy(c.values):
|
| 646 |
+
arrays.append(convert_column(c, f))
|
| 647 |
+
else:
|
| 648 |
+
arrays.append(executor.submit(convert_column, c, f))
|
| 649 |
+
|
| 650 |
+
for i, maybe_fut in enumerate(arrays):
|
| 651 |
+
if isinstance(maybe_fut, futures.Future):
|
| 652 |
+
arrays[i] = maybe_fut.result()
|
| 653 |
+
|
| 654 |
+
types = [x.type for x in arrays]
|
| 655 |
+
|
| 656 |
+
if schema is None:
|
| 657 |
+
fields = []
|
| 658 |
+
for name, type_ in zip(all_names, types):
|
| 659 |
+
fields.append(pa.field(name, type_))
|
| 660 |
+
schema = pa.schema(fields)
|
| 661 |
+
|
| 662 |
+
pandas_metadata = construct_metadata(
|
| 663 |
+
columns_to_convert, df, column_names, index_columns, index_descriptors,
|
| 664 |
+
preserve_index, types, column_field_names=column_field_names
|
| 665 |
+
)
|
| 666 |
+
metadata = deepcopy(schema.metadata) if schema.metadata else dict()
|
| 667 |
+
metadata.update(pandas_metadata)
|
| 668 |
+
schema = schema.with_metadata(metadata)
|
| 669 |
+
|
| 670 |
+
# If dataframe is empty but with RangeIndex ->
|
| 671 |
+
# remember the length of the indexes
|
| 672 |
+
n_rows = None
|
| 673 |
+
if len(arrays) == 0:
|
| 674 |
+
try:
|
| 675 |
+
kind = index_descriptors[0]["kind"]
|
| 676 |
+
if kind == "range":
|
| 677 |
+
start = index_descriptors[0]["start"]
|
| 678 |
+
stop = index_descriptors[0]["stop"]
|
| 679 |
+
step = index_descriptors[0]["step"]
|
| 680 |
+
n_rows = len(range(start, stop, step))
|
| 681 |
+
except IndexError:
|
| 682 |
+
pass
|
| 683 |
+
|
| 684 |
+
return arrays, schema, n_rows
|
| 685 |
+
|
| 686 |
+
|
| 687 |
+
def get_datetimetz_type(values, dtype, type_):
|
| 688 |
+
if values.dtype.type != np.datetime64:
|
| 689 |
+
return values, type_
|
| 690 |
+
|
| 691 |
+
if _pandas_api.is_datetimetz(dtype) and type_ is None:
|
| 692 |
+
# If no user type passed, construct a tz-aware timestamp type
|
| 693 |
+
tz = dtype.tz
|
| 694 |
+
unit = dtype.unit
|
| 695 |
+
type_ = pa.timestamp(unit, tz)
|
| 696 |
+
elif type_ is None:
|
| 697 |
+
# Trust the NumPy dtype
|
| 698 |
+
type_ = pa.from_numpy_dtype(values.dtype)
|
| 699 |
+
|
| 700 |
+
return values, type_
|
| 701 |
+
|
| 702 |
+
# ----------------------------------------------------------------------
|
| 703 |
+
# Converting pyarrow.Table efficiently to pandas.DataFrame
|
| 704 |
+
|
| 705 |
+
|
| 706 |
+
def _reconstruct_block(item, columns=None, extension_columns=None, return_block=True):
|
| 707 |
+
"""
|
| 708 |
+
Construct a pandas Block from the `item` dictionary coming from pyarrow's
|
| 709 |
+
serialization or returned by arrow::python::ConvertTableToPandas.
|
| 710 |
+
|
| 711 |
+
This function takes care of converting dictionary types to pandas
|
| 712 |
+
categorical, Timestamp-with-timezones to the proper pandas Block, and
|
| 713 |
+
conversion to pandas ExtensionBlock
|
| 714 |
+
|
| 715 |
+
Parameters
|
| 716 |
+
----------
|
| 717 |
+
item : dict
|
| 718 |
+
For basic types, this is a dictionary in the form of
|
| 719 |
+
{'block': np.ndarray of values, 'placement': pandas block placement}.
|
| 720 |
+
Additional keys are present for other types (dictionary, timezone,
|
| 721 |
+
object).
|
| 722 |
+
columns :
|
| 723 |
+
Column names of the table being constructed, used for extension types
|
| 724 |
+
extension_columns : dict
|
| 725 |
+
Dictionary of {column_name: pandas_dtype} that includes all columns
|
| 726 |
+
and corresponding dtypes that will be converted to a pandas
|
| 727 |
+
ExtensionBlock.
|
| 728 |
+
|
| 729 |
+
Returns
|
| 730 |
+
-------
|
| 731 |
+
pandas Block
|
| 732 |
+
|
| 733 |
+
"""
|
| 734 |
+
import pandas.core.internals as _int
|
| 735 |
+
|
| 736 |
+
block_arr = item.get('block', None)
|
| 737 |
+
placement = item['placement']
|
| 738 |
+
if 'dictionary' in item:
|
| 739 |
+
arr = _pandas_api.categorical_type.from_codes(
|
| 740 |
+
block_arr, categories=item['dictionary'],
|
| 741 |
+
ordered=item['ordered'])
|
| 742 |
+
elif 'timezone' in item:
|
| 743 |
+
unit, _ = np.datetime_data(block_arr.dtype)
|
| 744 |
+
dtype = make_datetimetz(unit, item['timezone'])
|
| 745 |
+
if _pandas_api.is_ge_v21():
|
| 746 |
+
arr = _pandas_api.pd.array(
|
| 747 |
+
block_arr.view("int64"), dtype=dtype, copy=False
|
| 748 |
+
)
|
| 749 |
+
else:
|
| 750 |
+
arr = block_arr
|
| 751 |
+
if return_block:
|
| 752 |
+
block = _int.make_block(block_arr, placement=placement,
|
| 753 |
+
klass=_int.DatetimeTZBlock,
|
| 754 |
+
dtype=dtype)
|
| 755 |
+
return block
|
| 756 |
+
elif 'py_array' in item:
|
| 757 |
+
# create ExtensionBlock
|
| 758 |
+
arr = item['py_array']
|
| 759 |
+
assert len(placement) == 1
|
| 760 |
+
name = columns[placement[0]]
|
| 761 |
+
pandas_dtype = extension_columns[name]
|
| 762 |
+
if not hasattr(pandas_dtype, '__from_arrow__'):
|
| 763 |
+
raise ValueError("This column does not support to be converted "
|
| 764 |
+
"to a pandas ExtensionArray")
|
| 765 |
+
arr = pandas_dtype.__from_arrow__(arr)
|
| 766 |
+
else:
|
| 767 |
+
arr = block_arr
|
| 768 |
+
|
| 769 |
+
if return_block:
|
| 770 |
+
return _int.make_block(arr, placement=placement)
|
| 771 |
+
else:
|
| 772 |
+
return arr, placement
|
| 773 |
+
|
| 774 |
+
|
| 775 |
+
def make_datetimetz(unit, tz):
|
| 776 |
+
if _pandas_api.is_v1():
|
| 777 |
+
unit = 'ns' # ARROW-3789: Coerce date/timestamp types to datetime64[ns]
|
| 778 |
+
tz = pa.lib.string_to_tzinfo(tz)
|
| 779 |
+
return _pandas_api.datetimetz_type(unit, tz=tz)
|
| 780 |
+
|
| 781 |
+
|
| 782 |
+
def table_to_dataframe(
|
| 783 |
+
options, table, categories=None, ignore_metadata=False, types_mapper=None
|
| 784 |
+
):
|
| 785 |
+
all_columns = []
|
| 786 |
+
column_indexes = []
|
| 787 |
+
pandas_metadata = table.schema.pandas_metadata
|
| 788 |
+
|
| 789 |
+
if not ignore_metadata and pandas_metadata is not None:
|
| 790 |
+
all_columns = pandas_metadata['columns']
|
| 791 |
+
column_indexes = pandas_metadata.get('column_indexes', [])
|
| 792 |
+
index_descriptors = pandas_metadata['index_columns']
|
| 793 |
+
table = _add_any_metadata(table, pandas_metadata)
|
| 794 |
+
table, index = _reconstruct_index(table, index_descriptors,
|
| 795 |
+
all_columns, types_mapper)
|
| 796 |
+
ext_columns_dtypes = _get_extension_dtypes(
|
| 797 |
+
table, all_columns, types_mapper, options, categories)
|
| 798 |
+
else:
|
| 799 |
+
index = _pandas_api.pd.RangeIndex(table.num_rows)
|
| 800 |
+
ext_columns_dtypes = _get_extension_dtypes(
|
| 801 |
+
table, [], types_mapper, options, categories
|
| 802 |
+
)
|
| 803 |
+
|
| 804 |
+
_check_data_column_metadata_consistency(all_columns)
|
| 805 |
+
columns = _deserialize_column_index(table, all_columns, column_indexes)
|
| 806 |
+
|
| 807 |
+
column_names = table.column_names
|
| 808 |
+
result = pa.lib.table_to_blocks(options, table, categories,
|
| 809 |
+
list(ext_columns_dtypes.keys()))
|
| 810 |
+
if _pandas_api.is_ge_v3():
|
| 811 |
+
from pandas.api.internals import create_dataframe_from_blocks
|
| 812 |
+
|
| 813 |
+
blocks = [
|
| 814 |
+
_reconstruct_block(
|
| 815 |
+
item, column_names, ext_columns_dtypes, return_block=False)
|
| 816 |
+
for item in result
|
| 817 |
+
]
|
| 818 |
+
df = create_dataframe_from_blocks(blocks, index=index, columns=columns)
|
| 819 |
+
return df
|
| 820 |
+
else:
|
| 821 |
+
from pandas.core.internals import BlockManager
|
| 822 |
+
from pandas import DataFrame
|
| 823 |
+
|
| 824 |
+
blocks = [
|
| 825 |
+
_reconstruct_block(item, column_names, ext_columns_dtypes)
|
| 826 |
+
for item in result
|
| 827 |
+
]
|
| 828 |
+
axes = [columns, index]
|
| 829 |
+
mgr = BlockManager(blocks, axes)
|
| 830 |
+
if _pandas_api.is_ge_v21():
|
| 831 |
+
df = DataFrame._from_mgr(mgr, mgr.axes)
|
| 832 |
+
else:
|
| 833 |
+
df = DataFrame(mgr)
|
| 834 |
+
return df
|
| 835 |
+
|
| 836 |
+
|
| 837 |
+
# Set of the string repr of all numpy dtypes that can be stored in a pandas
|
| 838 |
+
# dataframe (complex not included since not supported by Arrow)
|
| 839 |
+
_pandas_supported_numpy_types = {
|
| 840 |
+
"int8", "int16", "int32", "int64",
|
| 841 |
+
"uint8", "uint16", "uint32", "uint64",
|
| 842 |
+
"float16", "float32", "float64",
|
| 843 |
+
"object", "bool"
|
| 844 |
+
}
|
| 845 |
+
|
| 846 |
+
|
| 847 |
+
def _get_extension_dtypes(table, columns_metadata, types_mapper, options, categories):
|
| 848 |
+
"""
|
| 849 |
+
Based on the stored column pandas metadata and the extension types
|
| 850 |
+
in the arrow schema, infer which columns should be converted to a
|
| 851 |
+
pandas extension dtype.
|
| 852 |
+
|
| 853 |
+
The 'numpy_type' field in the column metadata stores the string
|
| 854 |
+
representation of the original pandas dtype (and, despite its name,
|
| 855 |
+
not the 'pandas_type' field).
|
| 856 |
+
Based on this string representation, a pandas/numpy dtype is constructed
|
| 857 |
+
and then we can check if this dtype supports conversion from arrow.
|
| 858 |
+
|
| 859 |
+
"""
|
| 860 |
+
strings_to_categorical = options["strings_to_categorical"]
|
| 861 |
+
categories = categories or []
|
| 862 |
+
|
| 863 |
+
ext_columns = {}
|
| 864 |
+
|
| 865 |
+
# older pandas version that does not yet support extension dtypes
|
| 866 |
+
if _pandas_api.extension_dtype is None:
|
| 867 |
+
return ext_columns
|
| 868 |
+
|
| 869 |
+
# use the specified mapping of built-in arrow types to pandas dtypes
|
| 870 |
+
if types_mapper:
|
| 871 |
+
for field in table.schema:
|
| 872 |
+
typ = field.type
|
| 873 |
+
pandas_dtype = types_mapper(typ)
|
| 874 |
+
if pandas_dtype is not None:
|
| 875 |
+
ext_columns[field.name] = pandas_dtype
|
| 876 |
+
|
| 877 |
+
# infer from extension type in the schema
|
| 878 |
+
for field in table.schema:
|
| 879 |
+
typ = field.type
|
| 880 |
+
if field.name not in ext_columns and isinstance(typ, pa.BaseExtensionType):
|
| 881 |
+
try:
|
| 882 |
+
pandas_dtype = typ.to_pandas_dtype()
|
| 883 |
+
except NotImplementedError:
|
| 884 |
+
pass
|
| 885 |
+
else:
|
| 886 |
+
ext_columns[field.name] = pandas_dtype
|
| 887 |
+
|
| 888 |
+
# infer the extension columns from the pandas metadata
|
| 889 |
+
for col_meta in columns_metadata:
|
| 890 |
+
try:
|
| 891 |
+
name = col_meta['field_name']
|
| 892 |
+
except KeyError:
|
| 893 |
+
name = col_meta['name']
|
| 894 |
+
dtype = col_meta['numpy_type']
|
| 895 |
+
|
| 896 |
+
if name not in ext_columns and dtype not in _pandas_supported_numpy_types:
|
| 897 |
+
# pandas_dtype is expensive, so avoid doing this for types
|
| 898 |
+
# that are certainly numpy dtypes
|
| 899 |
+
pandas_dtype = _pandas_api.pandas_dtype(dtype)
|
| 900 |
+
if isinstance(pandas_dtype, _pandas_api.extension_dtype):
|
| 901 |
+
if isinstance(pandas_dtype, _pandas_api.pd.StringDtype):
|
| 902 |
+
# when the metadata indicate to use the string dtype,
|
| 903 |
+
# ignore this in case:
|
| 904 |
+
# - it is specified to convert strings / this column to categorical
|
| 905 |
+
# - the column itself is dictionary encoded and would otherwise be
|
| 906 |
+
# converted to categorical
|
| 907 |
+
if strings_to_categorical or name in categories:
|
| 908 |
+
continue
|
| 909 |
+
try:
|
| 910 |
+
if pa.types.is_dictionary(table.schema.field(name).type):
|
| 911 |
+
continue
|
| 912 |
+
except KeyError:
|
| 913 |
+
pass
|
| 914 |
+
if hasattr(pandas_dtype, "__from_arrow__"):
|
| 915 |
+
ext_columns[name] = pandas_dtype
|
| 916 |
+
|
| 917 |
+
# for pandas 3.0+, use pandas' new default string dtype
|
| 918 |
+
if _pandas_api.uses_string_dtype() and not strings_to_categorical:
|
| 919 |
+
for field in table.schema:
|
| 920 |
+
if field.name not in ext_columns and (
|
| 921 |
+
pa.types.is_string(field.type)
|
| 922 |
+
or pa.types.is_large_string(field.type)
|
| 923 |
+
or pa.types.is_string_view(field.type)
|
| 924 |
+
) and field.name not in categories:
|
| 925 |
+
ext_columns[field.name] = _pandas_api.pd.StringDtype(na_value=np.nan)
|
| 926 |
+
|
| 927 |
+
return ext_columns
|
| 928 |
+
|
| 929 |
+
|
| 930 |
+
def _check_data_column_metadata_consistency(all_columns):
|
| 931 |
+
# It can never be the case in a released version of pyarrow that
|
| 932 |
+
# c['name'] is None *and* 'field_name' is not a key in the column metadata,
|
| 933 |
+
# because the change to allow c['name'] to be None and the change to add
|
| 934 |
+
# 'field_name' are in the same release (0.8.0)
|
| 935 |
+
assert all(
|
| 936 |
+
(c['name'] is None and 'field_name' in c) or c['name'] is not None
|
| 937 |
+
for c in all_columns
|
| 938 |
+
)
|
| 939 |
+
|
| 940 |
+
|
| 941 |
+
def _deserialize_column_index(block_table, all_columns, column_indexes):
|
| 942 |
+
if all_columns:
|
| 943 |
+
columns_name_dict = {
|
| 944 |
+
c.get('field_name', _column_name_to_strings(c['name'])): c['name']
|
| 945 |
+
for c in all_columns
|
| 946 |
+
}
|
| 947 |
+
columns_values = [
|
| 948 |
+
columns_name_dict.get(name, name) for name in block_table.column_names
|
| 949 |
+
]
|
| 950 |
+
else:
|
| 951 |
+
columns_values = block_table.column_names
|
| 952 |
+
|
| 953 |
+
# Construct the base index
|
| 954 |
+
if len(column_indexes) > 1:
|
| 955 |
+
# If we're passed multiple column indexes then evaluate with
|
| 956 |
+
# ast.literal_eval, since the column index values show up as a list of
|
| 957 |
+
# tuples
|
| 958 |
+
columns = _pandas_api.pd.MultiIndex.from_tuples(
|
| 959 |
+
list(map(ast.literal_eval, columns_values)),
|
| 960 |
+
names=[col_index['name'] for col_index in column_indexes],
|
| 961 |
+
)
|
| 962 |
+
else:
|
| 963 |
+
columns = _pandas_api.pd.Index(
|
| 964 |
+
columns_values, name=column_indexes[0]["name"] if column_indexes else None
|
| 965 |
+
)
|
| 966 |
+
|
| 967 |
+
# if we're reconstructing the index
|
| 968 |
+
if len(column_indexes) > 0:
|
| 969 |
+
columns = _reconstruct_columns_from_metadata(columns, column_indexes)
|
| 970 |
+
|
| 971 |
+
return columns
|
| 972 |
+
|
| 973 |
+
|
| 974 |
+
def _reconstruct_index(table, index_descriptors, all_columns, types_mapper=None):
|
| 975 |
+
# 0. 'field_name' is the name of the column in the arrow Table
|
| 976 |
+
# 1. 'name' is the user-facing name of the column, that is, it came from
|
| 977 |
+
# pandas
|
| 978 |
+
# 2. 'field_name' and 'name' differ for index columns
|
| 979 |
+
# 3. We fall back on c['name'] for backwards compatibility
|
| 980 |
+
field_name_to_metadata = {
|
| 981 |
+
c.get('field_name', c['name']): c
|
| 982 |
+
for c in all_columns
|
| 983 |
+
}
|
| 984 |
+
|
| 985 |
+
# Build up a list of index columns and names while removing those columns
|
| 986 |
+
# from the original table
|
| 987 |
+
index_arrays = []
|
| 988 |
+
index_names = []
|
| 989 |
+
result_table = table
|
| 990 |
+
for descr in index_descriptors:
|
| 991 |
+
if isinstance(descr, str):
|
| 992 |
+
result_table, index_level, index_name = _extract_index_level(
|
| 993 |
+
table, result_table, descr, field_name_to_metadata, types_mapper)
|
| 994 |
+
if index_level is None:
|
| 995 |
+
# ARROW-1883: the serialized index column was not found
|
| 996 |
+
continue
|
| 997 |
+
elif descr['kind'] == 'range':
|
| 998 |
+
index_name = descr['name']
|
| 999 |
+
index_level = _pandas_api.pd.RangeIndex(descr['start'],
|
| 1000 |
+
descr['stop'],
|
| 1001 |
+
step=descr['step'],
|
| 1002 |
+
name=index_name)
|
| 1003 |
+
if len(index_level) != len(table):
|
| 1004 |
+
# Possibly the result of munged metadata
|
| 1005 |
+
continue
|
| 1006 |
+
else:
|
| 1007 |
+
raise ValueError("Unrecognized index kind: {}"
|
| 1008 |
+
.format(descr['kind']))
|
| 1009 |
+
index_arrays.append(index_level)
|
| 1010 |
+
index_names.append(index_name)
|
| 1011 |
+
|
| 1012 |
+
pd = _pandas_api.pd
|
| 1013 |
+
|
| 1014 |
+
# Reconstruct the row index
|
| 1015 |
+
if len(index_arrays) > 1:
|
| 1016 |
+
index = pd.MultiIndex.from_arrays(index_arrays, names=index_names)
|
| 1017 |
+
elif len(index_arrays) == 1:
|
| 1018 |
+
index = index_arrays[0]
|
| 1019 |
+
if not isinstance(index, pd.Index):
|
| 1020 |
+
# Box anything that wasn't boxed above
|
| 1021 |
+
index = pd.Index(index, name=index_names[0])
|
| 1022 |
+
else:
|
| 1023 |
+
index = pd.RangeIndex(table.num_rows)
|
| 1024 |
+
|
| 1025 |
+
return result_table, index
|
| 1026 |
+
|
| 1027 |
+
|
| 1028 |
+
def _extract_index_level(table, result_table, field_name,
|
| 1029 |
+
field_name_to_metadata, types_mapper=None):
|
| 1030 |
+
logical_name = field_name_to_metadata[field_name]['name']
|
| 1031 |
+
index_name = _backwards_compatible_index_name(field_name, logical_name)
|
| 1032 |
+
i = table.schema.get_field_index(field_name)
|
| 1033 |
+
|
| 1034 |
+
if i == -1:
|
| 1035 |
+
# The serialized index column was removed by the user
|
| 1036 |
+
return result_table, None, None
|
| 1037 |
+
|
| 1038 |
+
col = table.column(i)
|
| 1039 |
+
index_level = col.to_pandas(types_mapper=types_mapper)
|
| 1040 |
+
index_level.name = None
|
| 1041 |
+
result_table = result_table.remove_column(
|
| 1042 |
+
result_table.schema.get_field_index(field_name)
|
| 1043 |
+
)
|
| 1044 |
+
return result_table, index_level, index_name
|
| 1045 |
+
|
| 1046 |
+
|
| 1047 |
+
def _backwards_compatible_index_name(raw_name, logical_name):
|
| 1048 |
+
"""Compute the name of an index column that is compatible with older
|
| 1049 |
+
versions of :mod:`pyarrow`.
|
| 1050 |
+
|
| 1051 |
+
Parameters
|
| 1052 |
+
----------
|
| 1053 |
+
raw_name : str
|
| 1054 |
+
logical_name : str
|
| 1055 |
+
|
| 1056 |
+
Returns
|
| 1057 |
+
-------
|
| 1058 |
+
result : str
|
| 1059 |
+
|
| 1060 |
+
Notes
|
| 1061 |
+
-----
|
| 1062 |
+
* Part of :func:`~pyarrow.pandas_compat.table_to_blockmanager`
|
| 1063 |
+
"""
|
| 1064 |
+
# Part of table_to_blockmanager
|
| 1065 |
+
if raw_name == logical_name and _is_generated_index_name(raw_name):
|
| 1066 |
+
return None
|
| 1067 |
+
else:
|
| 1068 |
+
return logical_name
|
| 1069 |
+
|
| 1070 |
+
|
| 1071 |
+
def _is_generated_index_name(name):
|
| 1072 |
+
pattern = r'^__index_level_\d+__$'
|
| 1073 |
+
return re.match(pattern, name) is not None
|
| 1074 |
+
|
| 1075 |
+
|
| 1076 |
+
def get_pandas_logical_type_map():
|
| 1077 |
+
global _pandas_logical_type_map
|
| 1078 |
+
|
| 1079 |
+
if not _pandas_logical_type_map:
|
| 1080 |
+
_pandas_logical_type_map.update({
|
| 1081 |
+
'date': 'datetime64[D]',
|
| 1082 |
+
'datetime': 'datetime64[ns]',
|
| 1083 |
+
'datetimetz': 'datetime64[ns]',
|
| 1084 |
+
'unicode': 'str',
|
| 1085 |
+
'bytes': np.bytes_,
|
| 1086 |
+
'string': 'str',
|
| 1087 |
+
'integer': np.int64,
|
| 1088 |
+
'floating': np.float64,
|
| 1089 |
+
'decimal': np.object_,
|
| 1090 |
+
'empty': np.object_,
|
| 1091 |
+
})
|
| 1092 |
+
return _pandas_logical_type_map
|
| 1093 |
+
|
| 1094 |
+
|
| 1095 |
+
def _pandas_type_to_numpy_type(pandas_type):
|
| 1096 |
+
"""Get the numpy dtype that corresponds to a pandas type.
|
| 1097 |
+
|
| 1098 |
+
Parameters
|
| 1099 |
+
----------
|
| 1100 |
+
pandas_type : str
|
| 1101 |
+
The result of a call to pandas.lib.infer_dtype.
|
| 1102 |
+
|
| 1103 |
+
Returns
|
| 1104 |
+
-------
|
| 1105 |
+
dtype : np.dtype
|
| 1106 |
+
The dtype that corresponds to `pandas_type`.
|
| 1107 |
+
"""
|
| 1108 |
+
pandas_logical_type_map = get_pandas_logical_type_map()
|
| 1109 |
+
try:
|
| 1110 |
+
return pandas_logical_type_map[pandas_type]
|
| 1111 |
+
except KeyError:
|
| 1112 |
+
if 'mixed' in pandas_type:
|
| 1113 |
+
# catching 'mixed', 'mixed-integer' and 'mixed-integer-float'
|
| 1114 |
+
return np.object_
|
| 1115 |
+
return np.dtype(pandas_type)
|
| 1116 |
+
|
| 1117 |
+
|
| 1118 |
+
def _reconstruct_columns_from_metadata(columns, column_indexes):
|
| 1119 |
+
"""Construct a pandas MultiIndex from `columns` and column index metadata
|
| 1120 |
+
in `column_indexes`.
|
| 1121 |
+
|
| 1122 |
+
Parameters
|
| 1123 |
+
----------
|
| 1124 |
+
columns : List[pd.Index]
|
| 1125 |
+
The columns coming from a pyarrow.Table
|
| 1126 |
+
column_indexes : List[Dict[str, str]]
|
| 1127 |
+
The column index metadata deserialized from the JSON schema metadata
|
| 1128 |
+
in a :class:`~pyarrow.Table`.
|
| 1129 |
+
|
| 1130 |
+
Returns
|
| 1131 |
+
-------
|
| 1132 |
+
result : MultiIndex
|
| 1133 |
+
The index reconstructed using `column_indexes` metadata with levels of
|
| 1134 |
+
the correct type.
|
| 1135 |
+
|
| 1136 |
+
Notes
|
| 1137 |
+
-----
|
| 1138 |
+
* Part of :func:`~pyarrow.pandas_compat.table_to_blockmanager`
|
| 1139 |
+
"""
|
| 1140 |
+
pd = _pandas_api.pd
|
| 1141 |
+
# Get levels and labels, and provide sane defaults if the index has a
|
| 1142 |
+
# single level to avoid if/else spaghetti.
|
| 1143 |
+
levels = getattr(columns, 'levels', None) or [columns]
|
| 1144 |
+
labels = getattr(columns, 'codes', None) or [None]
|
| 1145 |
+
|
| 1146 |
+
# Convert each level to the dtype provided in the metadata
|
| 1147 |
+
levels_dtypes = [
|
| 1148 |
+
(level, col_index.get('pandas_type', str(level.dtype)),
|
| 1149 |
+
col_index.get('numpy_type', None))
|
| 1150 |
+
for level, col_index in zip_longest(
|
| 1151 |
+
levels, column_indexes, fillvalue={}
|
| 1152 |
+
)
|
| 1153 |
+
]
|
| 1154 |
+
|
| 1155 |
+
new_levels = []
|
| 1156 |
+
encoder = operator.methodcaller('encode', 'UTF-8')
|
| 1157 |
+
|
| 1158 |
+
for level, pandas_dtype, numpy_dtype in levels_dtypes:
|
| 1159 |
+
dtype = _pandas_type_to_numpy_type(pandas_dtype)
|
| 1160 |
+
# Since our metadata is UTF-8 encoded, Python turns things that were
|
| 1161 |
+
# bytes into unicode strings when json.loads-ing them. We need to
|
| 1162 |
+
# convert them back to bytes to preserve metadata.
|
| 1163 |
+
if dtype == np.bytes_:
|
| 1164 |
+
level = level.map(encoder)
|
| 1165 |
+
# ARROW-13756: if index is timezone aware DataTimeIndex
|
| 1166 |
+
if pandas_dtype == "datetimetz":
|
| 1167 |
+
tz = pa.lib.string_to_tzinfo(
|
| 1168 |
+
column_indexes[0]['metadata']['timezone'])
|
| 1169 |
+
level = pd.to_datetime(level, utc=True).tz_convert(tz)
|
| 1170 |
+
if _pandas_api.is_ge_v3():
|
| 1171 |
+
# with pandas 3+, to_datetime returns a unit depending on the string
|
| 1172 |
+
# data, so we restore it to the original unit from the metadata
|
| 1173 |
+
level = level.as_unit(np.datetime_data(dtype)[0])
|
| 1174 |
+
# GH-41503: if the column index was decimal, restore to decimal
|
| 1175 |
+
elif pandas_dtype == "decimal":
|
| 1176 |
+
level = _pandas_api.pd.Index([decimal.Decimal(i) for i in level])
|
| 1177 |
+
elif (
|
| 1178 |
+
level.dtype == "str" and numpy_dtype == "object"
|
| 1179 |
+
and ("mixed" in pandas_dtype or pandas_dtype in ["unicode", "string"])
|
| 1180 |
+
):
|
| 1181 |
+
# the metadata indicate that the original dataframe used object dtype,
|
| 1182 |
+
# but ignore this and keep string dtype if:
|
| 1183 |
+
# - the original columns used mixed types -> we don't attempt to faithfully
|
| 1184 |
+
# roundtrip in this case, but keep the column names as strings
|
| 1185 |
+
# - the original columns were inferred to be strings but stored in object
|
| 1186 |
+
# dtype -> we don't restore the object dtype because all metadata
|
| 1187 |
+
# generated using pandas < 3 will have this case by default, and
|
| 1188 |
+
# for pandas >= 3 we want to use the default string dtype for .columns
|
| 1189 |
+
new_levels.append(level)
|
| 1190 |
+
continue
|
| 1191 |
+
elif level.dtype != dtype:
|
| 1192 |
+
level = level.astype(dtype)
|
| 1193 |
+
# ARROW-9096: if original DataFrame was upcast we keep that
|
| 1194 |
+
if level.dtype != numpy_dtype and pandas_dtype != "datetimetz":
|
| 1195 |
+
level = level.astype(numpy_dtype)
|
| 1196 |
+
|
| 1197 |
+
new_levels.append(level)
|
| 1198 |
+
|
| 1199 |
+
if len(new_levels) > 1:
|
| 1200 |
+
return pd.MultiIndex(new_levels, labels, names=columns.names)
|
| 1201 |
+
else:
|
| 1202 |
+
return pd.Index(new_levels[0], dtype=new_levels[0].dtype, name=columns.name)
|
| 1203 |
+
|
| 1204 |
+
|
| 1205 |
+
def _add_any_metadata(table, pandas_metadata):
|
| 1206 |
+
modified_columns = {}
|
| 1207 |
+
modified_fields = {}
|
| 1208 |
+
|
| 1209 |
+
schema = table.schema
|
| 1210 |
+
|
| 1211 |
+
index_columns = pandas_metadata['index_columns']
|
| 1212 |
+
# only take index columns into account if they are an actual table column
|
| 1213 |
+
index_columns = [idx_col for idx_col in index_columns
|
| 1214 |
+
if isinstance(idx_col, str)]
|
| 1215 |
+
n_index_levels = len(index_columns)
|
| 1216 |
+
n_columns = len(pandas_metadata['columns']) - n_index_levels
|
| 1217 |
+
|
| 1218 |
+
# Add time zones
|
| 1219 |
+
for i, col_meta in enumerate(pandas_metadata['columns']):
|
| 1220 |
+
|
| 1221 |
+
raw_name = col_meta.get('field_name')
|
| 1222 |
+
if not raw_name:
|
| 1223 |
+
# deal with metadata written with arrow < 0.8 or fastparquet
|
| 1224 |
+
raw_name = col_meta['name']
|
| 1225 |
+
if i >= n_columns:
|
| 1226 |
+
# index columns
|
| 1227 |
+
raw_name = index_columns[i - n_columns]
|
| 1228 |
+
if raw_name is None:
|
| 1229 |
+
raw_name = 'None'
|
| 1230 |
+
|
| 1231 |
+
idx = schema.get_field_index(raw_name)
|
| 1232 |
+
if idx != -1:
|
| 1233 |
+
if col_meta['pandas_type'] == 'datetimetz':
|
| 1234 |
+
col = table[idx]
|
| 1235 |
+
if not isinstance(col.type, pa.lib.TimestampType):
|
| 1236 |
+
continue
|
| 1237 |
+
metadata = col_meta['metadata']
|
| 1238 |
+
if not metadata:
|
| 1239 |
+
continue
|
| 1240 |
+
metadata_tz = metadata.get('timezone')
|
| 1241 |
+
if metadata_tz and metadata_tz != col.type.tz:
|
| 1242 |
+
converted = col.to_pandas()
|
| 1243 |
+
tz_aware_type = pa.timestamp('ns', tz=metadata_tz)
|
| 1244 |
+
with_metadata = pa.Array.from_pandas(converted,
|
| 1245 |
+
type=tz_aware_type)
|
| 1246 |
+
|
| 1247 |
+
modified_fields[idx] = pa.field(schema[idx].name,
|
| 1248 |
+
tz_aware_type)
|
| 1249 |
+
modified_columns[idx] = with_metadata
|
| 1250 |
+
|
| 1251 |
+
if len(modified_columns) > 0:
|
| 1252 |
+
columns = []
|
| 1253 |
+
fields = []
|
| 1254 |
+
for i in range(len(table.schema)):
|
| 1255 |
+
if i in modified_columns:
|
| 1256 |
+
columns.append(modified_columns[i])
|
| 1257 |
+
fields.append(modified_fields[i])
|
| 1258 |
+
else:
|
| 1259 |
+
columns.append(table[i])
|
| 1260 |
+
fields.append(table.schema[i])
|
| 1261 |
+
return pa.Table.from_arrays(columns, schema=pa.schema(fields))
|
| 1262 |
+
else:
|
| 1263 |
+
return table
|
| 1264 |
+
|
| 1265 |
+
|
| 1266 |
+
# ----------------------------------------------------------------------
|
| 1267 |
+
# Helper functions used in lib
|
| 1268 |
+
|
| 1269 |
+
|
| 1270 |
+
def make_tz_aware(series, tz):
|
| 1271 |
+
"""
|
| 1272 |
+
Make a datetime64 Series timezone-aware for the given tz
|
| 1273 |
+
"""
|
| 1274 |
+
tz = pa.lib.string_to_tzinfo(tz)
|
| 1275 |
+
series = (series.dt.tz_localize('utc')
|
| 1276 |
+
.dt.tz_convert(tz))
|
| 1277 |
+
return series
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/transformers/configuration_utils.py
ADDED
|
@@ -0,0 +1,1380 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2018 The Google AI Language Team Authors and The HuggingFace Inc. team.
|
| 2 |
+
# Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
|
| 3 |
+
#
|
| 4 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 5 |
+
# you may not use this file except in compliance with the License.
|
| 6 |
+
# You may obtain a copy of the License at
|
| 7 |
+
#
|
| 8 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 9 |
+
#
|
| 10 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 11 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 12 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 13 |
+
# See the License for the specific language governing permissions and
|
| 14 |
+
# limitations under the License.
|
| 15 |
+
"""Configuration base class and utilities."""
|
| 16 |
+
|
| 17 |
+
import copy
|
| 18 |
+
import json
|
| 19 |
+
import os
|
| 20 |
+
import warnings
|
| 21 |
+
from typing import TYPE_CHECKING, Any, Optional, TypeVar, Union
|
| 22 |
+
|
| 23 |
+
from packaging import version
|
| 24 |
+
|
| 25 |
+
from . import __version__
|
| 26 |
+
from .dynamic_module_utils import custom_object_save
|
| 27 |
+
from .modeling_gguf_pytorch_utils import load_gguf_checkpoint
|
| 28 |
+
from .utils import (
|
| 29 |
+
CONFIG_NAME,
|
| 30 |
+
PushToHubMixin,
|
| 31 |
+
cached_file,
|
| 32 |
+
copy_func,
|
| 33 |
+
download_url,
|
| 34 |
+
extract_commit_hash,
|
| 35 |
+
is_remote_url,
|
| 36 |
+
is_torch_available,
|
| 37 |
+
logging,
|
| 38 |
+
)
|
| 39 |
+
from .utils.generic import is_timm_config_dict
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
if TYPE_CHECKING:
|
| 43 |
+
import torch
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
logger = logging.get_logger(__name__)
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
# type hinting: specifying the type of config class that inherits from PretrainedConfig
|
| 50 |
+
SpecificPretrainedConfigType = TypeVar("SpecificPretrainedConfigType", bound="PretrainedConfig")
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
class PretrainedConfig(PushToHubMixin):
|
| 54 |
+
# no-format
|
| 55 |
+
r"""
|
| 56 |
+
Base class for all configuration classes. Handles a few parameters common to all models' configurations as well as
|
| 57 |
+
methods for loading/downloading/saving configurations.
|
| 58 |
+
|
| 59 |
+
<Tip>
|
| 60 |
+
|
| 61 |
+
A configuration file can be loaded and saved to disk. Loading the configuration file and using this file to
|
| 62 |
+
initialize a model does **not** load the model weights. It only affects the model's configuration.
|
| 63 |
+
|
| 64 |
+
</Tip>
|
| 65 |
+
|
| 66 |
+
Class attributes (overridden by derived classes):
|
| 67 |
+
|
| 68 |
+
- **model_type** (`str`) -- An identifier for the model type, serialized into the JSON file, and used to recreate
|
| 69 |
+
the correct object in [`~transformers.AutoConfig`].
|
| 70 |
+
- **has_no_defaults_at_init** (`bool`) -- Whether the config class can be initialized without providing input arguments.
|
| 71 |
+
Some configurations requires inputs to be defined at init and have no default values, usually these are composite configs,
|
| 72 |
+
(but not necessarily) such as [`~transformers.EncoderDecoderConfig`] or [`~RagConfig`]. They have to be initialized from
|
| 73 |
+
two or more configs of type [`~transformers.PretrainedConfig`].
|
| 74 |
+
- **keys_to_ignore_at_inference** (`list[str]`) -- A list of keys to ignore by default when looking at dictionary
|
| 75 |
+
outputs of the model during inference.
|
| 76 |
+
- **attribute_map** (`dict[str, str]`) -- A dict that maps model specific attribute names to the standardized
|
| 77 |
+
naming of attributes.
|
| 78 |
+
- **base_model_tp_plan** (`dict[str, Any]`) -- A dict that maps sub-modules FQNs of a base model to a tensor
|
| 79 |
+
parallel plan applied to the sub-module when `model.tensor_parallel` is called.
|
| 80 |
+
- **base_model_pp_plan** (`dict[str, tuple[list[str]]]`) -- A dict that maps child-modules of a base model to a
|
| 81 |
+
pipeline parallel plan that enables users to place the child-module on the appropriate device.
|
| 82 |
+
|
| 83 |
+
Common attributes (present in all subclasses):
|
| 84 |
+
|
| 85 |
+
- **vocab_size** (`int`) -- The number of tokens in the vocabulary, which is also the first dimension of the
|
| 86 |
+
embeddings matrix (this attribute may be missing for models that don't have a text modality like ViT).
|
| 87 |
+
- **hidden_size** (`int`) -- The hidden size of the model.
|
| 88 |
+
- **num_attention_heads** (`int`) -- The number of attention heads used in the multi-head attention layers of the
|
| 89 |
+
model.
|
| 90 |
+
- **num_hidden_layers** (`int`) -- The number of blocks in the model.
|
| 91 |
+
|
| 92 |
+
<Tip warning={true}>
|
| 93 |
+
|
| 94 |
+
Setting parameters for sequence generation in the model config is deprecated. For backward compatibility, loading
|
| 95 |
+
some of them will still be possible, but attempting to overwrite them will throw an exception -- you should set
|
| 96 |
+
them in a [~transformers.GenerationConfig]. Check the documentation of [~transformers.GenerationConfig] for more
|
| 97 |
+
information about the individual parameters.
|
| 98 |
+
|
| 99 |
+
</Tip>
|
| 100 |
+
|
| 101 |
+
Arg:
|
| 102 |
+
name_or_path (`str`, *optional*, defaults to `""`):
|
| 103 |
+
Store the string that was passed to [`PreTrainedModel.from_pretrained`] or
|
| 104 |
+
[`TFPreTrainedModel.from_pretrained`] as `pretrained_model_name_or_path` if the configuration was created
|
| 105 |
+
with such a method.
|
| 106 |
+
output_hidden_states (`bool`, *optional*, defaults to `False`):
|
| 107 |
+
Whether or not the model should return all hidden-states.
|
| 108 |
+
output_attentions (`bool`, *optional*, defaults to `False`):
|
| 109 |
+
Whether or not the model should returns all attentions.
|
| 110 |
+
return_dict (`bool`, *optional*, defaults to `True`):
|
| 111 |
+
Whether or not the model should return a [`~transformers.utils.ModelOutput`] instead of a plain tuple.
|
| 112 |
+
is_encoder_decoder (`bool`, *optional*, defaults to `False`):
|
| 113 |
+
Whether the model is used as an encoder/decoder or not.
|
| 114 |
+
is_decoder (`bool`, *optional*, defaults to `False`):
|
| 115 |
+
Whether to only use the decoder in an encoder-decoder architecture, otherwise it has no effect on
|
| 116 |
+
decoder-only or encoder-only architectures.
|
| 117 |
+
cross_attention_hidden_size (`bool`, *optional*):
|
| 118 |
+
The hidden size of the cross-attention layer in case the model is used as a decoder in an encoder-decoder
|
| 119 |
+
setting and the cross-attention hidden dimension differs from `self.config.hidden_size`.
|
| 120 |
+
add_cross_attention (`bool`, *optional*, defaults to `False`):
|
| 121 |
+
Whether cross-attention layers should be added to the model. Note, this option is only relevant for models
|
| 122 |
+
that can be used as decoder models within the [`EncoderDecoderModel`] class, which consists of all models
|
| 123 |
+
in `AUTO_MODELS_FOR_CAUSAL_LM`.
|
| 124 |
+
tie_encoder_decoder (`bool`, *optional*, defaults to `False`):
|
| 125 |
+
Whether all encoder weights should be tied to their equivalent decoder weights. This requires the encoder
|
| 126 |
+
and decoder model to have the exact same parameter names.
|
| 127 |
+
prune_heads (`dict[int, list[int]]`, *optional*, defaults to `{}`):
|
| 128 |
+
Pruned heads of the model. The keys are the selected layer indices and the associated values, the list of
|
| 129 |
+
heads to prune in said layer.
|
| 130 |
+
|
| 131 |
+
For instance `{1: [0, 2], 2: [2, 3]}` will prune heads 0 and 2 on layer 1 and heads 2 and 3 on layer 2.
|
| 132 |
+
chunk_size_feed_forward (`int`, *optional*, defaults to `0`):
|
| 133 |
+
The chunk size of all feed forward layers in the residual attention blocks. A chunk size of `0` means that
|
| 134 |
+
the feed forward layer is not chunked. A chunk size of n means that the feed forward layer processes `n` <
|
| 135 |
+
sequence_length embeddings at a time. For more information on feed forward chunking, see [How does Feed
|
| 136 |
+
Forward Chunking work?](../glossary.html#feed-forward-chunking).
|
| 137 |
+
|
| 138 |
+
> Parameters for fine-tuning tasks
|
| 139 |
+
|
| 140 |
+
architectures (`list[str]`, *optional*):
|
| 141 |
+
Model architectures that can be used with the model pretrained weights.
|
| 142 |
+
finetuning_task (`str`, *optional*):
|
| 143 |
+
Name of the task used to fine-tune the model. This can be used when converting from an original (TensorFlow
|
| 144 |
+
or PyTorch) checkpoint.
|
| 145 |
+
id2label (`dict[int, str]`, *optional*):
|
| 146 |
+
A map from index (for instance prediction index, or target index) to label.
|
| 147 |
+
label2id (`dict[str, int]`, *optional*):
|
| 148 |
+
A map from label to index for the model.
|
| 149 |
+
num_labels (`int`, *optional*):
|
| 150 |
+
Number of labels to use in the last layer added to the model, typically for a classification task.
|
| 151 |
+
task_specific_params (`dict[str, Any]`, *optional*):
|
| 152 |
+
Additional keyword arguments to store for the current task.
|
| 153 |
+
problem_type (`str`, *optional*):
|
| 154 |
+
Problem type for `XxxForSequenceClassification` models. Can be one of `"regression"`,
|
| 155 |
+
`"single_label_classification"` or `"multi_label_classification"`.
|
| 156 |
+
|
| 157 |
+
> Parameters linked to the tokenizer
|
| 158 |
+
|
| 159 |
+
tokenizer_class (`str`, *optional*):
|
| 160 |
+
The name of the associated tokenizer class to use (if none is set, will use the tokenizer associated to the
|
| 161 |
+
model by default).
|
| 162 |
+
prefix (`str`, *optional*):
|
| 163 |
+
A specific prompt that should be added at the beginning of each text before calling the model.
|
| 164 |
+
bos_token_id (`int`, *optional*):
|
| 165 |
+
The id of the _beginning-of-stream_ token.
|
| 166 |
+
pad_token_id (`int`, *optional*):
|
| 167 |
+
The id of the _padding_ token.
|
| 168 |
+
eos_token_id (`int`, *optional*):
|
| 169 |
+
The id of the _end-of-stream_ token.
|
| 170 |
+
decoder_start_token_id (`int`, *optional*):
|
| 171 |
+
If an encoder-decoder model starts decoding with a different token than _bos_, the id of that token.
|
| 172 |
+
sep_token_id (`int`, *optional*):
|
| 173 |
+
The id of the _separation_ token.
|
| 174 |
+
|
| 175 |
+
> PyTorch specific parameters
|
| 176 |
+
|
| 177 |
+
torchscript (`bool`, *optional*, defaults to `False`):
|
| 178 |
+
Whether or not the model should be used with Torchscript.
|
| 179 |
+
tie_word_embeddings (`bool`, *optional*, defaults to `True`):
|
| 180 |
+
Whether the model's input and output word embeddings should be tied. Note that this is only relevant if the
|
| 181 |
+
model has a output word embedding layer.
|
| 182 |
+
dtype (`str`, *optional*):
|
| 183 |
+
The `dtype` of the weights. This attribute can be used to initialize the model to a non-default `dtype`
|
| 184 |
+
(which is normally `float32`) and thus allow for optimal storage allocation. For example, if the saved
|
| 185 |
+
model is `float16`, ideally we want to load it back using the minimal amount of memory needed to load
|
| 186 |
+
`float16` weights.
|
| 187 |
+
"""
|
| 188 |
+
|
| 189 |
+
model_type: str = ""
|
| 190 |
+
base_config_key: str = ""
|
| 191 |
+
sub_configs: dict[str, type["PretrainedConfig"]] = {}
|
| 192 |
+
has_no_defaults_at_init: bool = False
|
| 193 |
+
attribute_map: dict[str, str] = {}
|
| 194 |
+
base_model_tp_plan: Optional[dict[str, Any]] = None
|
| 195 |
+
base_model_pp_plan: Optional[dict[str, tuple[list[str]]]] = None
|
| 196 |
+
base_model_ep_plan: Optional[dict[str, tuple[list[str]]]] = None
|
| 197 |
+
_auto_class: Optional[str] = None
|
| 198 |
+
|
| 199 |
+
def __setattr__(self, key, value):
|
| 200 |
+
if key in super().__getattribute__("attribute_map"):
|
| 201 |
+
key = super().__getattribute__("attribute_map")[key]
|
| 202 |
+
super().__setattr__(key, value)
|
| 203 |
+
|
| 204 |
+
def __getattribute__(self, key):
|
| 205 |
+
if key != "attribute_map" and key in super().__getattribute__("attribute_map"):
|
| 206 |
+
key = super().__getattribute__("attribute_map")[key]
|
| 207 |
+
return super().__getattribute__(key)
|
| 208 |
+
|
| 209 |
+
def __init__(
|
| 210 |
+
self,
|
| 211 |
+
*,
|
| 212 |
+
# All models common arguments
|
| 213 |
+
output_hidden_states: bool = False,
|
| 214 |
+
output_attentions: bool = False,
|
| 215 |
+
return_dict: bool = True,
|
| 216 |
+
torchscript: bool = False,
|
| 217 |
+
dtype: Optional[Union[str, "torch.dtype"]] = None,
|
| 218 |
+
# Common arguments
|
| 219 |
+
pruned_heads: Optional[dict[int, list[int]]] = None,
|
| 220 |
+
tie_word_embeddings: bool = True,
|
| 221 |
+
chunk_size_feed_forward: int = 0,
|
| 222 |
+
is_encoder_decoder: bool = False,
|
| 223 |
+
is_decoder: bool = False,
|
| 224 |
+
cross_attention_hidden_size: Optional[int] = None,
|
| 225 |
+
add_cross_attention: bool = False,
|
| 226 |
+
tie_encoder_decoder: bool = False,
|
| 227 |
+
# Fine-tuning task arguments
|
| 228 |
+
architectures: Optional[list[str]] = None,
|
| 229 |
+
finetuning_task: Optional[str] = None,
|
| 230 |
+
id2label: Optional[dict[int, str]] = None,
|
| 231 |
+
label2id: Optional[dict[str, int]] = None,
|
| 232 |
+
num_labels: Optional[int] = None,
|
| 233 |
+
task_specific_params: Optional[dict[str, Any]] = None,
|
| 234 |
+
problem_type: Optional[str] = None,
|
| 235 |
+
# Tokenizer kwargs
|
| 236 |
+
tokenizer_class: Optional[str] = None,
|
| 237 |
+
prefix: Optional[str] = None,
|
| 238 |
+
bos_token_id: Optional[int] = None,
|
| 239 |
+
pad_token_id: Optional[int] = None,
|
| 240 |
+
eos_token_id: Optional[int] = None,
|
| 241 |
+
sep_token_id: Optional[int] = None,
|
| 242 |
+
decoder_start_token_id: Optional[int] = None,
|
| 243 |
+
**kwargs,
|
| 244 |
+
):
|
| 245 |
+
# Validation for some arguments
|
| 246 |
+
if label2id is not None and not isinstance(label2id, dict):
|
| 247 |
+
raise ValueError("Argument label2id should be a dictionary.")
|
| 248 |
+
if id2label is not None and not isinstance(id2label, dict):
|
| 249 |
+
raise ValueError("Argument id2label should be a dictionary.")
|
| 250 |
+
if num_labels is not None and id2label is not None and len(id2label) != num_labels:
|
| 251 |
+
logger.warning(
|
| 252 |
+
f"You passed `num_labels={num_labels}` which is incompatible to "
|
| 253 |
+
f"the `id2label` map of length `{len(id2label)}`."
|
| 254 |
+
)
|
| 255 |
+
if problem_type is not None and problem_type not in (
|
| 256 |
+
"regression",
|
| 257 |
+
"single_label_classification",
|
| 258 |
+
"multi_label_classification",
|
| 259 |
+
):
|
| 260 |
+
raise ValueError(
|
| 261 |
+
f"The config parameter `problem_type` was not understood: received {problem_type} "
|
| 262 |
+
"but only 'regression', 'single_label_classification' and 'multi_label_classification' are valid."
|
| 263 |
+
)
|
| 264 |
+
# BC for the `torch_dtype` argument instead of the simpler `dtype`
|
| 265 |
+
# Do not warn, as it would otherwise always be triggered since most configs on the hub have `torch_dtype`
|
| 266 |
+
if (torch_dtype := kwargs.pop("torch_dtype", None)) is not None:
|
| 267 |
+
# If both are provided, keep `dtype`
|
| 268 |
+
dtype = dtype if dtype is not None else torch_dtype
|
| 269 |
+
if dtype is not None and isinstance(dtype, str) and is_torch_available():
|
| 270 |
+
# we will start using self.dtype in v5, but to be consistent with
|
| 271 |
+
# from_pretrained's dtype arg convert it to an actual torch.dtype object
|
| 272 |
+
import torch
|
| 273 |
+
|
| 274 |
+
dtype = getattr(torch, dtype)
|
| 275 |
+
|
| 276 |
+
# Attributes common for all models
|
| 277 |
+
self.return_dict = return_dict
|
| 278 |
+
self.output_hidden_states = output_hidden_states
|
| 279 |
+
self.torchscript = torchscript
|
| 280 |
+
self.dtype = dtype
|
| 281 |
+
self._output_attentions = output_attentions # has public property
|
| 282 |
+
|
| 283 |
+
# Less common kwargs, only used by some models
|
| 284 |
+
self.pruned_heads = pruned_heads if pruned_heads is not None else {}
|
| 285 |
+
self.tie_word_embeddings = tie_word_embeddings
|
| 286 |
+
self.chunk_size_feed_forward = chunk_size_feed_forward
|
| 287 |
+
|
| 288 |
+
# Encoder-decoder models attributes
|
| 289 |
+
self.is_encoder_decoder = is_encoder_decoder
|
| 290 |
+
self.is_decoder = is_decoder # used in encoder-decoder models to differentiate encoder from decoder
|
| 291 |
+
self.cross_attention_hidden_size = cross_attention_hidden_size
|
| 292 |
+
self.add_cross_attention = add_cross_attention
|
| 293 |
+
self.tie_encoder_decoder = tie_encoder_decoder
|
| 294 |
+
|
| 295 |
+
# Fine-tuning task attributes
|
| 296 |
+
self.architectures = architectures
|
| 297 |
+
self.finetuning_task = finetuning_task
|
| 298 |
+
self.id2label = id2label
|
| 299 |
+
self.label2id = label2id
|
| 300 |
+
self.task_specific_params = task_specific_params
|
| 301 |
+
self.problem_type = problem_type
|
| 302 |
+
|
| 303 |
+
if self.id2label is None:
|
| 304 |
+
self._create_id_label_maps(num_labels if num_labels is not None else 2)
|
| 305 |
+
else:
|
| 306 |
+
# Keys are always strings in JSON so convert ids to int here.
|
| 307 |
+
self.id2label = {int(key): value for key, value in self.id2label.items()}
|
| 308 |
+
|
| 309 |
+
# Tokenizer attributes
|
| 310 |
+
self.tokenizer_class = tokenizer_class
|
| 311 |
+
self.prefix = prefix
|
| 312 |
+
self.bos_token_id = bos_token_id
|
| 313 |
+
self.pad_token_id = pad_token_id
|
| 314 |
+
self.eos_token_id = eos_token_id
|
| 315 |
+
self.sep_token_id = sep_token_id
|
| 316 |
+
self.decoder_start_token_id = decoder_start_token_id
|
| 317 |
+
|
| 318 |
+
# Retrocompatibility: Parameters for sequence generation. While we will keep the ability to load these
|
| 319 |
+
# parameters, saving them will be deprecated. In a distant future, we won't need to load them.
|
| 320 |
+
for parameter_name, default_value in self._get_global_generation_defaults().items():
|
| 321 |
+
setattr(self, parameter_name, kwargs.pop(parameter_name, default_value))
|
| 322 |
+
|
| 323 |
+
# Name or path to the pretrained checkpoint
|
| 324 |
+
self._name_or_path = str(kwargs.pop("name_or_path", ""))
|
| 325 |
+
self._commit_hash = kwargs.pop("_commit_hash", None)
|
| 326 |
+
|
| 327 |
+
# Attention implementation to use, if relevant (it sets it recursively on sub-configs)
|
| 328 |
+
self._attn_implementation = kwargs.pop("attn_implementation", None)
|
| 329 |
+
|
| 330 |
+
# Drop the transformers version info
|
| 331 |
+
self.transformers_version = kwargs.pop("transformers_version", None)
|
| 332 |
+
|
| 333 |
+
# Deal with gradient checkpointing
|
| 334 |
+
if kwargs.get("gradient_checkpointing", False):
|
| 335 |
+
warnings.warn(
|
| 336 |
+
"Passing `gradient_checkpointing` to a config initialization is deprecated and will be removed in v5 "
|
| 337 |
+
"Transformers. Using `model.gradient_checkpointing_enable()` instead, or if you are using the "
|
| 338 |
+
"`Trainer` API, pass `gradient_checkpointing=True` in your `TrainingArguments`."
|
| 339 |
+
)
|
| 340 |
+
|
| 341 |
+
# Additional attributes without default values
|
| 342 |
+
for key, value in kwargs.items():
|
| 343 |
+
try:
|
| 344 |
+
setattr(self, key, value)
|
| 345 |
+
except AttributeError as err:
|
| 346 |
+
logger.error(f"Can't set {key} with value {value} for {self}")
|
| 347 |
+
raise err
|
| 348 |
+
|
| 349 |
+
# TODO: remove later, deprecated arguments for TF models
|
| 350 |
+
self.tf_legacy_loss = kwargs.pop("tf_legacy_loss", False)
|
| 351 |
+
self.use_bfloat16 = kwargs.pop("use_bfloat16", False)
|
| 352 |
+
|
| 353 |
+
def _create_id_label_maps(self, num_labels: int):
|
| 354 |
+
self.id2label = {i: f"LABEL_{i}" for i in range(num_labels)}
|
| 355 |
+
self.label2id = dict(zip(self.id2label.values(), self.id2label.keys()))
|
| 356 |
+
|
| 357 |
+
@property
|
| 358 |
+
def name_or_path(self) -> Optional[str]:
|
| 359 |
+
return getattr(self, "_name_or_path", None)
|
| 360 |
+
|
| 361 |
+
@name_or_path.setter
|
| 362 |
+
def name_or_path(self, value):
|
| 363 |
+
self._name_or_path = str(value) # Make sure that name_or_path is a string (for JSON encoding)
|
| 364 |
+
|
| 365 |
+
@property
|
| 366 |
+
def output_attentions(self):
|
| 367 |
+
"""
|
| 368 |
+
`bool`: Whether or not the model should returns all attentions.
|
| 369 |
+
"""
|
| 370 |
+
return self._output_attentions
|
| 371 |
+
|
| 372 |
+
@output_attentions.setter
|
| 373 |
+
def output_attentions(self, value: bool):
|
| 374 |
+
# If we set `output_attentions` explicitly before the attn implementation, dispatch eager
|
| 375 |
+
if value and self._attn_implementation is None:
|
| 376 |
+
self._attn_implementation = "eager"
|
| 377 |
+
if value and self._attn_implementation != "eager":
|
| 378 |
+
raise ValueError(
|
| 379 |
+
"The `output_attentions` attribute is not supported when using the `attn_implementation` set to "
|
| 380 |
+
f"{self._attn_implementation}. Please set it to 'eager' instead."
|
| 381 |
+
)
|
| 382 |
+
self._output_attentions = value
|
| 383 |
+
|
| 384 |
+
@property
|
| 385 |
+
def use_return_dict(self) -> bool:
|
| 386 |
+
"""
|
| 387 |
+
`bool`: Whether or not return [`~utils.ModelOutput`] instead of tuples.
|
| 388 |
+
"""
|
| 389 |
+
# If torchscript is set, force `return_dict=False` to avoid jit errors
|
| 390 |
+
return self.return_dict and not self.torchscript
|
| 391 |
+
|
| 392 |
+
@property
|
| 393 |
+
def num_labels(self) -> int:
|
| 394 |
+
"""
|
| 395 |
+
`int`: The number of labels for classification models.
|
| 396 |
+
"""
|
| 397 |
+
return len(self.id2label)
|
| 398 |
+
|
| 399 |
+
@num_labels.setter
|
| 400 |
+
def num_labels(self, num_labels: int):
|
| 401 |
+
# we do not store `num_labels` attribute in config, but instead
|
| 402 |
+
# compute it based on the length of the `id2label` map
|
| 403 |
+
if self.id2label is None or self.num_labels != num_labels:
|
| 404 |
+
self._create_id_label_maps(num_labels)
|
| 405 |
+
|
| 406 |
+
@property
|
| 407 |
+
def _attn_implementation(self):
|
| 408 |
+
return self._attn_implementation_internal
|
| 409 |
+
|
| 410 |
+
@_attn_implementation.setter
|
| 411 |
+
def _attn_implementation(self, value: Optional[Union[str, dict]]):
|
| 412 |
+
"""We set it recursively on the sub-configs as well"""
|
| 413 |
+
# Set if for current config
|
| 414 |
+
current_attn = getattr(self, "_attn_implementation", None)
|
| 415 |
+
attn_implementation = value if not isinstance(value, dict) else value.get("", current_attn)
|
| 416 |
+
self._attn_implementation_internal = attn_implementation
|
| 417 |
+
|
| 418 |
+
# Set it recursively on the subconfigs
|
| 419 |
+
for subconfig_key in self.sub_configs:
|
| 420 |
+
subconfig = getattr(self, subconfig_key, None)
|
| 421 |
+
if subconfig is not None:
|
| 422 |
+
current_subconfig_attn = getattr(subconfig, "_attn_implementation", None)
|
| 423 |
+
sub_implementation = (
|
| 424 |
+
value if not isinstance(value, dict) else value.get(subconfig_key, current_subconfig_attn)
|
| 425 |
+
)
|
| 426 |
+
subconfig._attn_implementation = sub_implementation
|
| 427 |
+
|
| 428 |
+
@property
|
| 429 |
+
def torch_dtype(self):
|
| 430 |
+
logger.warning_once("`torch_dtype` is deprecated! Use `dtype` instead!")
|
| 431 |
+
return self.dtype
|
| 432 |
+
|
| 433 |
+
@torch_dtype.setter
|
| 434 |
+
def torch_dtype(self, value):
|
| 435 |
+
logger.warning_once("`torch_dtype` is deprecated! Use `dtype` instead!")
|
| 436 |
+
self.dtype = value
|
| 437 |
+
|
| 438 |
+
def save_pretrained(self, save_directory: Union[str, os.PathLike], push_to_hub: bool = False, **kwargs):
|
| 439 |
+
"""
|
| 440 |
+
Save a configuration object to the directory `save_directory`, so that it can be re-loaded using the
|
| 441 |
+
[`~PretrainedConfig.from_pretrained`] class method.
|
| 442 |
+
|
| 443 |
+
Args:
|
| 444 |
+
save_directory (`str` or `os.PathLike`):
|
| 445 |
+
Directory where the configuration JSON file will be saved (will be created if it does not exist).
|
| 446 |
+
push_to_hub (`bool`, *optional*, defaults to `False`):
|
| 447 |
+
Whether or not to push your model to the Hugging Face model hub after saving it. You can specify the
|
| 448 |
+
repository you want to push to with `repo_id` (will default to the name of `save_directory` in your
|
| 449 |
+
namespace).
|
| 450 |
+
kwargs (`dict[str, Any]`, *optional*):
|
| 451 |
+
Additional key word arguments passed along to the [`~utils.PushToHubMixin.push_to_hub`] method.
|
| 452 |
+
"""
|
| 453 |
+
self._set_token_in_kwargs(kwargs)
|
| 454 |
+
|
| 455 |
+
if os.path.isfile(save_directory):
|
| 456 |
+
raise AssertionError(f"Provided path ({save_directory}) should be a directory, not a file")
|
| 457 |
+
|
| 458 |
+
non_default_generation_parameters = self._get_non_default_generation_parameters()
|
| 459 |
+
if len(non_default_generation_parameters) > 0:
|
| 460 |
+
# TODO (joao): this should be an exception if the user has modified the loaded config. See #33886
|
| 461 |
+
warnings.warn(
|
| 462 |
+
"Some non-default generation parameters are set in the model config. These should go into either a) "
|
| 463 |
+
"`model.generation_config` (as opposed to `model.config`); OR b) a GenerationConfig file "
|
| 464 |
+
"(https://huggingface.co/docs/transformers/generation_strategies#save-a-custom-decoding-strategy-with-your-model)."
|
| 465 |
+
"This warning will become an exception in the future."
|
| 466 |
+
f"\nNon-default generation parameters: {str(non_default_generation_parameters)}",
|
| 467 |
+
UserWarning,
|
| 468 |
+
)
|
| 469 |
+
|
| 470 |
+
os.makedirs(save_directory, exist_ok=True)
|
| 471 |
+
|
| 472 |
+
if push_to_hub:
|
| 473 |
+
commit_message = kwargs.pop("commit_message", None)
|
| 474 |
+
repo_id = kwargs.pop("repo_id", save_directory.split(os.path.sep)[-1])
|
| 475 |
+
repo_id = self._create_repo(repo_id, **kwargs)
|
| 476 |
+
files_timestamps = self._get_files_timestamps(save_directory)
|
| 477 |
+
|
| 478 |
+
# This attribute is important to know on load, but should not be serialized on save.
|
| 479 |
+
if "transformers_weights" in self:
|
| 480 |
+
delattr(self, "transformers_weights")
|
| 481 |
+
|
| 482 |
+
# If we have a custom config, we copy the file defining it in the folder and set the attributes so it can be
|
| 483 |
+
# loaded from the Hub.
|
| 484 |
+
if self._auto_class is not None:
|
| 485 |
+
custom_object_save(self, save_directory, config=self)
|
| 486 |
+
|
| 487 |
+
# If we save using the predefined names, we can load using `from_pretrained`
|
| 488 |
+
output_config_file = os.path.join(save_directory, CONFIG_NAME)
|
| 489 |
+
|
| 490 |
+
self.to_json_file(output_config_file, use_diff=True)
|
| 491 |
+
logger.info(f"Configuration saved in {output_config_file}")
|
| 492 |
+
|
| 493 |
+
if push_to_hub:
|
| 494 |
+
self._upload_modified_files(
|
| 495 |
+
save_directory,
|
| 496 |
+
repo_id,
|
| 497 |
+
files_timestamps,
|
| 498 |
+
commit_message=commit_message,
|
| 499 |
+
token=kwargs.get("token"),
|
| 500 |
+
)
|
| 501 |
+
|
| 502 |
+
@staticmethod
|
| 503 |
+
def _set_token_in_kwargs(kwargs, token=None):
|
| 504 |
+
"""Temporary method to deal with `token` and `use_auth_token`.
|
| 505 |
+
|
| 506 |
+
This method is to avoid apply the same changes in all model config classes that overwrite `from_pretrained`.
|
| 507 |
+
|
| 508 |
+
Need to clean up `use_auth_token` in a follow PR.
|
| 509 |
+
"""
|
| 510 |
+
# Some model config classes like CLIP define their own `from_pretrained` without the new argument `token` yet.
|
| 511 |
+
if token is None:
|
| 512 |
+
token = kwargs.pop("token", None)
|
| 513 |
+
use_auth_token = kwargs.pop("use_auth_token", None)
|
| 514 |
+
|
| 515 |
+
if use_auth_token is not None:
|
| 516 |
+
warnings.warn(
|
| 517 |
+
"The `use_auth_token` argument is deprecated and will be removed in v5 of Transformers. Please use `token` instead.",
|
| 518 |
+
FutureWarning,
|
| 519 |
+
)
|
| 520 |
+
if token is not None:
|
| 521 |
+
raise ValueError(
|
| 522 |
+
"`token` and `use_auth_token` are both specified. Please set only the argument `token`."
|
| 523 |
+
)
|
| 524 |
+
token = use_auth_token
|
| 525 |
+
|
| 526 |
+
if token is not None:
|
| 527 |
+
kwargs["token"] = token
|
| 528 |
+
|
| 529 |
+
@classmethod
|
| 530 |
+
def from_pretrained(
|
| 531 |
+
cls: type[SpecificPretrainedConfigType],
|
| 532 |
+
pretrained_model_name_or_path: Union[str, os.PathLike],
|
| 533 |
+
cache_dir: Optional[Union[str, os.PathLike]] = None,
|
| 534 |
+
force_download: bool = False,
|
| 535 |
+
local_files_only: bool = False,
|
| 536 |
+
token: Optional[Union[str, bool]] = None,
|
| 537 |
+
revision: str = "main",
|
| 538 |
+
**kwargs,
|
| 539 |
+
) -> SpecificPretrainedConfigType:
|
| 540 |
+
r"""
|
| 541 |
+
Instantiate a [`PretrainedConfig`] (or a derived class) from a pretrained model configuration.
|
| 542 |
+
|
| 543 |
+
Args:
|
| 544 |
+
pretrained_model_name_or_path (`str` or `os.PathLike`):
|
| 545 |
+
This can be either:
|
| 546 |
+
|
| 547 |
+
- a string, the *model id* of a pretrained model configuration hosted inside a model repo on
|
| 548 |
+
huggingface.co.
|
| 549 |
+
- a path to a *directory* containing a configuration file saved using the
|
| 550 |
+
[`~PretrainedConfig.save_pretrained`] method, e.g., `./my_model_directory/`.
|
| 551 |
+
- a path or url to a saved configuration JSON *file*, e.g., `./my_model_directory/configuration.json`.
|
| 552 |
+
cache_dir (`str` or `os.PathLike`, *optional*):
|
| 553 |
+
Path to a directory in which a downloaded pretrained model configuration should be cached if the
|
| 554 |
+
standard cache should not be used.
|
| 555 |
+
force_download (`bool`, *optional*, defaults to `False`):
|
| 556 |
+
Whether or not to force to (re-)download the configuration files and override the cached versions if
|
| 557 |
+
they exist.
|
| 558 |
+
resume_download:
|
| 559 |
+
Deprecated and ignored. All downloads are now resumed by default when possible.
|
| 560 |
+
Will be removed in v5 of Transformers.
|
| 561 |
+
proxies (`dict[str, str]`, *optional*):
|
| 562 |
+
A dictionary of proxy servers to use by protocol or endpoint, e.g., `{'http': 'foo.bar:3128',
|
| 563 |
+
'http://hostname': 'foo.bar:4012'}.` The proxies are used on each request.
|
| 564 |
+
token (`str` or `bool`, *optional*):
|
| 565 |
+
The token to use as HTTP bearer authorization for remote files. If `True`, or not specified, will use
|
| 566 |
+
the token generated when running `hf auth login` (stored in `~/.huggingface`).
|
| 567 |
+
revision (`str`, *optional*, defaults to `"main"`):
|
| 568 |
+
The specific model version to use. It can be a branch name, a tag name, or a commit id, since we use a
|
| 569 |
+
git-based system for storing models and other artifacts on huggingface.co, so `revision` can be any
|
| 570 |
+
identifier allowed by git.
|
| 571 |
+
|
| 572 |
+
<Tip>
|
| 573 |
+
|
| 574 |
+
To test a pull request you made on the Hub, you can pass `revision="refs/pr/<pr_number>"`.
|
| 575 |
+
|
| 576 |
+
</Tip>
|
| 577 |
+
|
| 578 |
+
return_unused_kwargs (`bool`, *optional*, defaults to `False`):
|
| 579 |
+
If `False`, then this function returns just the final configuration object.
|
| 580 |
+
|
| 581 |
+
If `True`, then this functions returns a `Tuple(config, unused_kwargs)` where *unused_kwargs* is a
|
| 582 |
+
dictionary consisting of the key/value pairs whose keys are not configuration attributes: i.e., the
|
| 583 |
+
part of `kwargs` which has not been used to update `config` and is otherwise ignored.
|
| 584 |
+
subfolder (`str`, *optional*, defaults to `""`):
|
| 585 |
+
In case the relevant files are located inside a subfolder of the model repo on huggingface.co, you can
|
| 586 |
+
specify the folder name here.
|
| 587 |
+
kwargs (`dict[str, Any]`, *optional*):
|
| 588 |
+
The values in kwargs of any keys which are configuration attributes will be used to override the loaded
|
| 589 |
+
values. Behavior concerning key/value pairs whose keys are *not* configuration attributes is controlled
|
| 590 |
+
by the `return_unused_kwargs` keyword parameter.
|
| 591 |
+
|
| 592 |
+
Returns:
|
| 593 |
+
[`PretrainedConfig`]: The configuration object instantiated from this pretrained model.
|
| 594 |
+
|
| 595 |
+
Examples:
|
| 596 |
+
|
| 597 |
+
```python
|
| 598 |
+
# We can't instantiate directly the base class *PretrainedConfig* so let's show the examples on a
|
| 599 |
+
# derived class: BertConfig
|
| 600 |
+
config = BertConfig.from_pretrained(
|
| 601 |
+
"google-bert/bert-base-uncased"
|
| 602 |
+
) # Download configuration from huggingface.co and cache.
|
| 603 |
+
config = BertConfig.from_pretrained(
|
| 604 |
+
"./test/saved_model/"
|
| 605 |
+
) # E.g. config (or model) was saved using *save_pretrained('./test/saved_model/')*
|
| 606 |
+
config = BertConfig.from_pretrained("./test/saved_model/my_configuration.json")
|
| 607 |
+
config = BertConfig.from_pretrained("google-bert/bert-base-uncased", output_attentions=True, foo=False)
|
| 608 |
+
assert config.output_attentions == True
|
| 609 |
+
config, unused_kwargs = BertConfig.from_pretrained(
|
| 610 |
+
"google-bert/bert-base-uncased", output_attentions=True, foo=False, return_unused_kwargs=True
|
| 611 |
+
)
|
| 612 |
+
assert config.output_attentions == True
|
| 613 |
+
assert unused_kwargs == {"foo": False}
|
| 614 |
+
```"""
|
| 615 |
+
kwargs["cache_dir"] = cache_dir
|
| 616 |
+
kwargs["force_download"] = force_download
|
| 617 |
+
kwargs["local_files_only"] = local_files_only
|
| 618 |
+
kwargs["revision"] = revision
|
| 619 |
+
|
| 620 |
+
cls._set_token_in_kwargs(kwargs, token)
|
| 621 |
+
|
| 622 |
+
config_dict, kwargs = cls.get_config_dict(pretrained_model_name_or_path, **kwargs)
|
| 623 |
+
if cls.base_config_key and cls.base_config_key in config_dict:
|
| 624 |
+
config_dict = config_dict[cls.base_config_key]
|
| 625 |
+
|
| 626 |
+
if "model_type" in config_dict and hasattr(cls, "model_type") and config_dict["model_type"] != cls.model_type:
|
| 627 |
+
# sometimes the config has no `base_config_key` if the config is used in several composite models
|
| 628 |
+
# e.g. LlamaConfig. In that case we try to see if there is match in `model_type` before raising a warning
|
| 629 |
+
for v in config_dict.values():
|
| 630 |
+
if isinstance(v, dict) and v.get("model_type") == cls.model_type:
|
| 631 |
+
config_dict = v
|
| 632 |
+
|
| 633 |
+
# raise warning only if we still can't see a match in `model_type`
|
| 634 |
+
if config_dict["model_type"] != cls.model_type:
|
| 635 |
+
logger.warning(
|
| 636 |
+
f"You are using a model of type {config_dict['model_type']} to instantiate a model of type "
|
| 637 |
+
f"{cls.model_type}. This is not supported for all configurations of models and can yield errors."
|
| 638 |
+
)
|
| 639 |
+
|
| 640 |
+
return cls.from_dict(config_dict, **kwargs)
|
| 641 |
+
|
| 642 |
+
@classmethod
|
| 643 |
+
def get_config_dict(
|
| 644 |
+
cls, pretrained_model_name_or_path: Union[str, os.PathLike], **kwargs
|
| 645 |
+
) -> tuple[dict[str, Any], dict[str, Any]]:
|
| 646 |
+
"""
|
| 647 |
+
From a `pretrained_model_name_or_path`, resolve to a dictionary of parameters, to be used for instantiating a
|
| 648 |
+
[`PretrainedConfig`] using `from_dict`.
|
| 649 |
+
|
| 650 |
+
Parameters:
|
| 651 |
+
pretrained_model_name_or_path (`str` or `os.PathLike`):
|
| 652 |
+
The identifier of the pre-trained checkpoint from which we want the dictionary of parameters.
|
| 653 |
+
|
| 654 |
+
Returns:
|
| 655 |
+
`tuple[Dict, Dict]`: The dictionary(ies) that will be used to instantiate the configuration object.
|
| 656 |
+
|
| 657 |
+
"""
|
| 658 |
+
cls._set_token_in_kwargs(kwargs)
|
| 659 |
+
|
| 660 |
+
original_kwargs = copy.deepcopy(kwargs)
|
| 661 |
+
# Get config dict associated with the base config file
|
| 662 |
+
config_dict, kwargs = cls._get_config_dict(pretrained_model_name_or_path, **kwargs)
|
| 663 |
+
if config_dict is None:
|
| 664 |
+
return {}, kwargs
|
| 665 |
+
if "_commit_hash" in config_dict:
|
| 666 |
+
original_kwargs["_commit_hash"] = config_dict["_commit_hash"]
|
| 667 |
+
|
| 668 |
+
# That config file may point us toward another config file to use.
|
| 669 |
+
if "configuration_files" in config_dict:
|
| 670 |
+
configuration_file = get_configuration_file(config_dict["configuration_files"])
|
| 671 |
+
config_dict, kwargs = cls._get_config_dict(
|
| 672 |
+
pretrained_model_name_or_path, _configuration_file=configuration_file, **original_kwargs
|
| 673 |
+
)
|
| 674 |
+
|
| 675 |
+
return config_dict, kwargs
|
| 676 |
+
|
| 677 |
+
@classmethod
|
| 678 |
+
def _get_config_dict(
|
| 679 |
+
cls, pretrained_model_name_or_path: Union[str, os.PathLike], **kwargs
|
| 680 |
+
) -> tuple[dict[str, Any], dict[str, Any]]:
|
| 681 |
+
cache_dir = kwargs.pop("cache_dir", None)
|
| 682 |
+
force_download = kwargs.pop("force_download", False)
|
| 683 |
+
resume_download = kwargs.pop("resume_download", None)
|
| 684 |
+
proxies = kwargs.pop("proxies", None)
|
| 685 |
+
token = kwargs.pop("token", None)
|
| 686 |
+
local_files_only = kwargs.pop("local_files_only", False)
|
| 687 |
+
revision = kwargs.pop("revision", None)
|
| 688 |
+
trust_remote_code = kwargs.pop("trust_remote_code", None)
|
| 689 |
+
subfolder = kwargs.pop("subfolder", "")
|
| 690 |
+
from_pipeline = kwargs.pop("_from_pipeline", None)
|
| 691 |
+
from_auto_class = kwargs.pop("_from_auto", False)
|
| 692 |
+
commit_hash = kwargs.pop("_commit_hash", None)
|
| 693 |
+
|
| 694 |
+
gguf_file = kwargs.get("gguf_file")
|
| 695 |
+
|
| 696 |
+
if trust_remote_code is True:
|
| 697 |
+
logger.warning(
|
| 698 |
+
"The argument `trust_remote_code` is to be used with Auto classes. It has no effect here and is"
|
| 699 |
+
" ignored."
|
| 700 |
+
)
|
| 701 |
+
|
| 702 |
+
user_agent = {"file_type": "config", "from_auto_class": from_auto_class}
|
| 703 |
+
if from_pipeline is not None:
|
| 704 |
+
user_agent["using_pipeline"] = from_pipeline
|
| 705 |
+
|
| 706 |
+
pretrained_model_name_or_path = str(pretrained_model_name_or_path)
|
| 707 |
+
|
| 708 |
+
is_local = os.path.isdir(pretrained_model_name_or_path)
|
| 709 |
+
if os.path.isfile(os.path.join(subfolder, pretrained_model_name_or_path)):
|
| 710 |
+
# Special case when pretrained_model_name_or_path is a local file
|
| 711 |
+
resolved_config_file = pretrained_model_name_or_path
|
| 712 |
+
is_local = True
|
| 713 |
+
elif is_remote_url(pretrained_model_name_or_path):
|
| 714 |
+
configuration_file = pretrained_model_name_or_path if gguf_file is None else gguf_file
|
| 715 |
+
resolved_config_file = download_url(pretrained_model_name_or_path)
|
| 716 |
+
else:
|
| 717 |
+
configuration_file = kwargs.pop("_configuration_file", CONFIG_NAME) if gguf_file is None else gguf_file
|
| 718 |
+
|
| 719 |
+
try:
|
| 720 |
+
# Load from local folder or from cache or download from model Hub and cache
|
| 721 |
+
resolved_config_file = cached_file(
|
| 722 |
+
pretrained_model_name_or_path,
|
| 723 |
+
configuration_file,
|
| 724 |
+
cache_dir=cache_dir,
|
| 725 |
+
force_download=force_download,
|
| 726 |
+
proxies=proxies,
|
| 727 |
+
resume_download=resume_download,
|
| 728 |
+
local_files_only=local_files_only,
|
| 729 |
+
token=token,
|
| 730 |
+
user_agent=user_agent,
|
| 731 |
+
revision=revision,
|
| 732 |
+
subfolder=subfolder,
|
| 733 |
+
_commit_hash=commit_hash,
|
| 734 |
+
)
|
| 735 |
+
if resolved_config_file is None:
|
| 736 |
+
return None, kwargs
|
| 737 |
+
commit_hash = extract_commit_hash(resolved_config_file, commit_hash)
|
| 738 |
+
except OSError:
|
| 739 |
+
# Raise any environment error raise by `cached_file`. It will have a helpful error message adapted to
|
| 740 |
+
# the original exception.
|
| 741 |
+
raise
|
| 742 |
+
except Exception:
|
| 743 |
+
# For any other exception, we throw a generic error.
|
| 744 |
+
raise OSError(
|
| 745 |
+
f"Can't load the configuration of '{pretrained_model_name_or_path}'. If you were trying to load it"
|
| 746 |
+
" from 'https://huggingface.co/models', make sure you don't have a local directory with the same"
|
| 747 |
+
f" name. Otherwise, make sure '{pretrained_model_name_or_path}' is the correct path to a directory"
|
| 748 |
+
f" containing a {configuration_file} file"
|
| 749 |
+
)
|
| 750 |
+
|
| 751 |
+
try:
|
| 752 |
+
if gguf_file:
|
| 753 |
+
config_dict = load_gguf_checkpoint(resolved_config_file, return_tensors=False)["config"]
|
| 754 |
+
else:
|
| 755 |
+
# Load config dict
|
| 756 |
+
config_dict = cls._dict_from_json_file(resolved_config_file)
|
| 757 |
+
|
| 758 |
+
config_dict["_commit_hash"] = commit_hash
|
| 759 |
+
except (json.JSONDecodeError, UnicodeDecodeError):
|
| 760 |
+
raise OSError(f"It looks like the config file at '{resolved_config_file}' is not a valid JSON file.")
|
| 761 |
+
|
| 762 |
+
if is_local:
|
| 763 |
+
logger.info(f"loading configuration file {resolved_config_file}")
|
| 764 |
+
else:
|
| 765 |
+
logger.info(f"loading configuration file {configuration_file} from cache at {resolved_config_file}")
|
| 766 |
+
|
| 767 |
+
# timm models are not saved with the model_type in the config file
|
| 768 |
+
if "model_type" not in config_dict and is_timm_config_dict(config_dict):
|
| 769 |
+
config_dict["model_type"] = "timm_wrapper"
|
| 770 |
+
|
| 771 |
+
return config_dict, kwargs
|
| 772 |
+
|
| 773 |
+
@classmethod
|
| 774 |
+
def from_dict(
|
| 775 |
+
cls: type[SpecificPretrainedConfigType], config_dict: dict[str, Any], **kwargs
|
| 776 |
+
) -> SpecificPretrainedConfigType:
|
| 777 |
+
"""
|
| 778 |
+
Instantiates a [`PretrainedConfig`] from a Python dictionary of parameters.
|
| 779 |
+
|
| 780 |
+
Args:
|
| 781 |
+
config_dict (`dict[str, Any]`):
|
| 782 |
+
Dictionary that will be used to instantiate the configuration object. Such a dictionary can be
|
| 783 |
+
retrieved from a pretrained checkpoint by leveraging the [`~PretrainedConfig.get_config_dict`] method.
|
| 784 |
+
kwargs (`dict[str, Any]`):
|
| 785 |
+
Additional parameters from which to initialize the configuration object.
|
| 786 |
+
|
| 787 |
+
Returns:
|
| 788 |
+
[`PretrainedConfig`]: The configuration object instantiated from those parameters.
|
| 789 |
+
"""
|
| 790 |
+
return_unused_kwargs = kwargs.pop("return_unused_kwargs", False)
|
| 791 |
+
# Those arguments may be passed along for our internal telemetry.
|
| 792 |
+
# We remove them so they don't appear in `return_unused_kwargs`.
|
| 793 |
+
kwargs.pop("_from_auto", None)
|
| 794 |
+
kwargs.pop("_from_pipeline", None)
|
| 795 |
+
# The commit hash might have been updated in the `config_dict`, we don't want the kwargs to erase that update.
|
| 796 |
+
if "_commit_hash" in kwargs and "_commit_hash" in config_dict:
|
| 797 |
+
kwargs["_commit_hash"] = config_dict["_commit_hash"]
|
| 798 |
+
|
| 799 |
+
# For BC on the old `torch_dtype`
|
| 800 |
+
if (torch_dtype := kwargs.pop("torch_dtype", None)) is not None:
|
| 801 |
+
logger.warning_once("`torch_dtype` is deprecated! Use `dtype` instead!")
|
| 802 |
+
# If both are present, use `dtype`
|
| 803 |
+
kwargs["dtype"] = kwargs.get("dtype", torch_dtype)
|
| 804 |
+
|
| 805 |
+
# We remove it from kwargs so that it does not appear in `return_unused_kwargs`.
|
| 806 |
+
config_dict["attn_implementation"] = kwargs.pop("attn_implementation", None)
|
| 807 |
+
|
| 808 |
+
config = cls(**config_dict)
|
| 809 |
+
|
| 810 |
+
if hasattr(config, "pruned_heads"):
|
| 811 |
+
config.pruned_heads = {int(key): value for key, value in config.pruned_heads.items()}
|
| 812 |
+
|
| 813 |
+
# Update config with kwargs if needed
|
| 814 |
+
if "num_labels" in kwargs and "id2label" in kwargs:
|
| 815 |
+
num_labels = kwargs["num_labels"]
|
| 816 |
+
id2label = kwargs["id2label"] if kwargs["id2label"] is not None else []
|
| 817 |
+
if len(id2label) != num_labels:
|
| 818 |
+
raise ValueError(
|
| 819 |
+
f"You passed along `num_labels={num_labels}` with an incompatible id to label map: "
|
| 820 |
+
f"{kwargs['id2label']}. Since those arguments are inconsistent with each other, you should remove "
|
| 821 |
+
"one of them."
|
| 822 |
+
)
|
| 823 |
+
to_remove = []
|
| 824 |
+
for key, value in kwargs.items():
|
| 825 |
+
if hasattr(config, key):
|
| 826 |
+
current_attr = getattr(config, key)
|
| 827 |
+
# To authorize passing a custom subconfig as kwarg in models that have nested configs.
|
| 828 |
+
# We need to update only custom kwarg values instead and keep other attributes in subconfig.
|
| 829 |
+
if isinstance(current_attr, PretrainedConfig) and isinstance(value, dict):
|
| 830 |
+
current_attr_updated = current_attr.to_dict()
|
| 831 |
+
current_attr_updated.update(value)
|
| 832 |
+
value = current_attr.__class__(**current_attr_updated)
|
| 833 |
+
setattr(config, key, value)
|
| 834 |
+
if key != "dtype":
|
| 835 |
+
to_remove.append(key)
|
| 836 |
+
for key in to_remove:
|
| 837 |
+
kwargs.pop(key, None)
|
| 838 |
+
|
| 839 |
+
logger.info(f"Model config {config}")
|
| 840 |
+
if return_unused_kwargs:
|
| 841 |
+
return config, kwargs
|
| 842 |
+
else:
|
| 843 |
+
return config
|
| 844 |
+
|
| 845 |
+
@classmethod
|
| 846 |
+
def from_json_file(
|
| 847 |
+
cls: type[SpecificPretrainedConfigType], json_file: Union[str, os.PathLike]
|
| 848 |
+
) -> SpecificPretrainedConfigType:
|
| 849 |
+
"""
|
| 850 |
+
Instantiates a [`PretrainedConfig`] from the path to a JSON file of parameters.
|
| 851 |
+
|
| 852 |
+
Args:
|
| 853 |
+
json_file (`str` or `os.PathLike`):
|
| 854 |
+
Path to the JSON file containing the parameters.
|
| 855 |
+
|
| 856 |
+
Returns:
|
| 857 |
+
[`PretrainedConfig`]: The configuration object instantiated from that JSON file.
|
| 858 |
+
|
| 859 |
+
"""
|
| 860 |
+
config_dict = cls._dict_from_json_file(json_file)
|
| 861 |
+
return cls(**config_dict)
|
| 862 |
+
|
| 863 |
+
@classmethod
|
| 864 |
+
def _dict_from_json_file(cls, json_file: Union[str, os.PathLike]):
|
| 865 |
+
with open(json_file, encoding="utf-8") as reader:
|
| 866 |
+
text = reader.read()
|
| 867 |
+
return json.loads(text)
|
| 868 |
+
|
| 869 |
+
def __eq__(self, other):
|
| 870 |
+
return isinstance(other, PretrainedConfig) and (self.__dict__ == other.__dict__)
|
| 871 |
+
|
| 872 |
+
def __repr__(self):
|
| 873 |
+
return f"{self.__class__.__name__} {self.to_json_string()}"
|
| 874 |
+
|
| 875 |
+
def __iter__(self):
|
| 876 |
+
yield from self.__dict__
|
| 877 |
+
|
| 878 |
+
def to_diff_dict(self) -> dict[str, Any]:
|
| 879 |
+
"""
|
| 880 |
+
Removes all attributes from the configuration that correspond to the default config attributes for
|
| 881 |
+
better readability, while always retaining the `config` attribute from the class. Serializes to a
|
| 882 |
+
Python dictionary.
|
| 883 |
+
|
| 884 |
+
Returns:
|
| 885 |
+
dict[str, Any]: Dictionary of all the attributes that make up this configuration instance.
|
| 886 |
+
"""
|
| 887 |
+
config_dict = self.to_dict()
|
| 888 |
+
|
| 889 |
+
# Get the default config dict (from a fresh PreTrainedConfig instance)
|
| 890 |
+
default_config_dict = PretrainedConfig().to_dict()
|
| 891 |
+
|
| 892 |
+
# get class specific config dict
|
| 893 |
+
class_config_dict = self.__class__().to_dict() if not self.has_no_defaults_at_init else {}
|
| 894 |
+
|
| 895 |
+
serializable_config_dict = {}
|
| 896 |
+
|
| 897 |
+
# Only serialize values that differ from the default config,
|
| 898 |
+
# except always keep the 'config' attribute.
|
| 899 |
+
for key, value in config_dict.items():
|
| 900 |
+
if (
|
| 901 |
+
isinstance(getattr(self, key, None), PretrainedConfig)
|
| 902 |
+
and key in class_config_dict
|
| 903 |
+
and isinstance(class_config_dict[key], dict)
|
| 904 |
+
or key in self.sub_configs
|
| 905 |
+
):
|
| 906 |
+
# For nested configs we need to clean the diff recursively
|
| 907 |
+
diff = recursive_diff_dict(value, default_config_dict, config_obj=getattr(self, key, None))
|
| 908 |
+
if "model_type" in value:
|
| 909 |
+
# Needs to be set even if it's not in the diff
|
| 910 |
+
diff["model_type"] = value["model_type"]
|
| 911 |
+
|
| 912 |
+
serializable_config_dict[key] = diff
|
| 913 |
+
elif (
|
| 914 |
+
key not in default_config_dict
|
| 915 |
+
or key == "transformers_version"
|
| 916 |
+
or key == "vocab_file"
|
| 917 |
+
or value != default_config_dict[key]
|
| 918 |
+
or (key in default_config_dict and value != class_config_dict.get(key, value))
|
| 919 |
+
):
|
| 920 |
+
serializable_config_dict[key] = value
|
| 921 |
+
|
| 922 |
+
self._remove_keys_not_serialized(serializable_config_dict)
|
| 923 |
+
|
| 924 |
+
# Key removed only in diff dict
|
| 925 |
+
if "_name_or_path" in serializable_config_dict:
|
| 926 |
+
del serializable_config_dict["_name_or_path"]
|
| 927 |
+
|
| 928 |
+
if hasattr(self, "quantization_config"):
|
| 929 |
+
serializable_config_dict["quantization_config"] = (
|
| 930 |
+
self.quantization_config.to_dict()
|
| 931 |
+
if not isinstance(self.quantization_config, dict)
|
| 932 |
+
else self.quantization_config
|
| 933 |
+
)
|
| 934 |
+
self.dict_dtype_to_str(serializable_config_dict)
|
| 935 |
+
|
| 936 |
+
return serializable_config_dict
|
| 937 |
+
|
| 938 |
+
def to_dict(self) -> dict[str, Any]:
|
| 939 |
+
"""
|
| 940 |
+
Serializes this instance to a Python dictionary.
|
| 941 |
+
|
| 942 |
+
Returns:
|
| 943 |
+
`dict[str, Any]`: Dictionary of all the attributes that make up this configuration instance.
|
| 944 |
+
"""
|
| 945 |
+
output = copy.deepcopy(self.__dict__)
|
| 946 |
+
if hasattr(self.__class__, "model_type"):
|
| 947 |
+
output["model_type"] = self.__class__.model_type
|
| 948 |
+
|
| 949 |
+
# Transformers version when serializing the model
|
| 950 |
+
output["transformers_version"] = __version__
|
| 951 |
+
|
| 952 |
+
for key, value in output.items():
|
| 953 |
+
# Deal with nested configs like CLIP
|
| 954 |
+
if isinstance(value, PretrainedConfig):
|
| 955 |
+
value = value.to_dict()
|
| 956 |
+
del value["transformers_version"]
|
| 957 |
+
|
| 958 |
+
output[key] = value
|
| 959 |
+
|
| 960 |
+
self._remove_keys_not_serialized(output)
|
| 961 |
+
|
| 962 |
+
if hasattr(self, "quantization_config"):
|
| 963 |
+
output["quantization_config"] = (
|
| 964 |
+
self.quantization_config.to_dict()
|
| 965 |
+
if not isinstance(self.quantization_config, dict)
|
| 966 |
+
else self.quantization_config
|
| 967 |
+
)
|
| 968 |
+
self.dict_dtype_to_str(output)
|
| 969 |
+
|
| 970 |
+
return output
|
| 971 |
+
|
| 972 |
+
def to_json_string(self, use_diff: bool = True) -> str:
|
| 973 |
+
"""
|
| 974 |
+
Serializes this instance to a JSON string.
|
| 975 |
+
|
| 976 |
+
Args:
|
| 977 |
+
use_diff (`bool`, *optional*, defaults to `True`):
|
| 978 |
+
If set to `True`, only the difference between the config instance and the default `PretrainedConfig()`
|
| 979 |
+
is serialized to JSON string.
|
| 980 |
+
|
| 981 |
+
Returns:
|
| 982 |
+
`str`: String containing all the attributes that make up this configuration instance in JSON format.
|
| 983 |
+
"""
|
| 984 |
+
if use_diff is True:
|
| 985 |
+
config_dict = self.to_diff_dict()
|
| 986 |
+
else:
|
| 987 |
+
config_dict = self.to_dict()
|
| 988 |
+
return json.dumps(config_dict, indent=2, sort_keys=True) + "\n"
|
| 989 |
+
|
| 990 |
+
def to_json_file(self, json_file_path: Union[str, os.PathLike], use_diff: bool = True):
|
| 991 |
+
"""
|
| 992 |
+
Save this instance to a JSON file.
|
| 993 |
+
|
| 994 |
+
Args:
|
| 995 |
+
json_file_path (`str` or `os.PathLike`):
|
| 996 |
+
Path to the JSON file in which this configuration instance's parameters will be saved.
|
| 997 |
+
use_diff (`bool`, *optional*, defaults to `True`):
|
| 998 |
+
If set to `True`, only the difference between the config instance and the default `PretrainedConfig()`
|
| 999 |
+
is serialized to JSON file.
|
| 1000 |
+
"""
|
| 1001 |
+
with open(json_file_path, "w", encoding="utf-8") as writer:
|
| 1002 |
+
writer.write(self.to_json_string(use_diff=use_diff))
|
| 1003 |
+
|
| 1004 |
+
def update(self, config_dict: dict[str, Any]):
|
| 1005 |
+
"""
|
| 1006 |
+
Updates attributes of this class with attributes from `config_dict`.
|
| 1007 |
+
|
| 1008 |
+
Args:
|
| 1009 |
+
config_dict (`dict[str, Any]`): Dictionary of attributes that should be updated for this class.
|
| 1010 |
+
"""
|
| 1011 |
+
for key, value in config_dict.items():
|
| 1012 |
+
setattr(self, key, value)
|
| 1013 |
+
|
| 1014 |
+
def update_from_string(self, update_str: str):
|
| 1015 |
+
"""
|
| 1016 |
+
Updates attributes of this class with attributes from `update_str`.
|
| 1017 |
+
|
| 1018 |
+
The expected format is ints, floats and strings as is, and for booleans use `true` or `false`. For example:
|
| 1019 |
+
"n_embd=10,resid_pdrop=0.2,scale_attn_weights=false,summary_type=cls_index"
|
| 1020 |
+
|
| 1021 |
+
The keys to change have to already exist in the config object.
|
| 1022 |
+
|
| 1023 |
+
Args:
|
| 1024 |
+
update_str (`str`): String with attributes that should be updated for this class.
|
| 1025 |
+
|
| 1026 |
+
"""
|
| 1027 |
+
|
| 1028 |
+
d = dict(x.split("=") for x in update_str.split(","))
|
| 1029 |
+
for k, v in d.items():
|
| 1030 |
+
if not hasattr(self, k):
|
| 1031 |
+
raise ValueError(f"key {k} isn't in the original config dict")
|
| 1032 |
+
|
| 1033 |
+
old_v = getattr(self, k)
|
| 1034 |
+
if isinstance(old_v, bool):
|
| 1035 |
+
if v.lower() in ["true", "1", "y", "yes"]:
|
| 1036 |
+
v = True
|
| 1037 |
+
elif v.lower() in ["false", "0", "n", "no"]:
|
| 1038 |
+
v = False
|
| 1039 |
+
else:
|
| 1040 |
+
raise ValueError(f"can't derive true or false from {v} (key {k})")
|
| 1041 |
+
elif isinstance(old_v, int):
|
| 1042 |
+
v = int(v)
|
| 1043 |
+
elif isinstance(old_v, float):
|
| 1044 |
+
v = float(v)
|
| 1045 |
+
elif not isinstance(old_v, str):
|
| 1046 |
+
raise TypeError(
|
| 1047 |
+
f"You can only update int, float, bool or string values in the config, got {v} for key {k}"
|
| 1048 |
+
)
|
| 1049 |
+
|
| 1050 |
+
setattr(self, k, v)
|
| 1051 |
+
|
| 1052 |
+
def dict_dtype_to_str(self, d: dict[str, Any]) -> None:
|
| 1053 |
+
"""
|
| 1054 |
+
Checks whether the passed dictionary and its nested dicts have a *dtype* key and if it's not None,
|
| 1055 |
+
converts torch.dtype to a string of just the type. For example, `torch.float32` get converted into *"float32"*
|
| 1056 |
+
string, which can then be stored in the json format.
|
| 1057 |
+
"""
|
| 1058 |
+
if d.get("dtype") is not None:
|
| 1059 |
+
if isinstance(d["dtype"], dict):
|
| 1060 |
+
d["dtype"] = {k: str(v).split(".")[-1] for k, v in d["dtype"].items()}
|
| 1061 |
+
# models like Emu3 can have "dtype" as token in config's vocabulary map,
|
| 1062 |
+
# so we also exclude int type here to avoid error in this special case.
|
| 1063 |
+
elif not isinstance(d["dtype"], (str, int)):
|
| 1064 |
+
d["dtype"] = str(d["dtype"]).split(".")[1]
|
| 1065 |
+
for value in d.values():
|
| 1066 |
+
if isinstance(value, dict):
|
| 1067 |
+
self.dict_dtype_to_str(value)
|
| 1068 |
+
|
| 1069 |
+
def _remove_keys_not_serialized(self, d: dict[str, Any]) -> None:
|
| 1070 |
+
"""
|
| 1071 |
+
Checks and removes if there are any keys in the dict that should not be serialized when saving the config.
|
| 1072 |
+
Runs recursive check on the dict, to remove from all sub configs.
|
| 1073 |
+
"""
|
| 1074 |
+
if hasattr(self, "quantization_config"):
|
| 1075 |
+
# Pop the `_pre_quantization_dtype` as torch.dtypes are not serializable.
|
| 1076 |
+
_ = d.pop("_pre_quantization_dtype", None)
|
| 1077 |
+
|
| 1078 |
+
if "_auto_class" in d:
|
| 1079 |
+
del d["_auto_class"]
|
| 1080 |
+
if "_output_attentions" in d:
|
| 1081 |
+
d["output_attentions"] = d.pop("_output_attentions")
|
| 1082 |
+
if "_commit_hash" in d:
|
| 1083 |
+
del d["_commit_hash"]
|
| 1084 |
+
if "_attn_implementation_internal" in d:
|
| 1085 |
+
del d["_attn_implementation_internal"]
|
| 1086 |
+
# Do not serialize `base_model_tp_plan` for now
|
| 1087 |
+
if "base_model_tp_plan" in d:
|
| 1088 |
+
del d["base_model_tp_plan"]
|
| 1089 |
+
# Do not serialize `base_model_pp_plan` for now
|
| 1090 |
+
if "base_model_pp_plan" in d:
|
| 1091 |
+
del d["base_model_pp_plan"]
|
| 1092 |
+
for value in d.values():
|
| 1093 |
+
if isinstance(value, dict):
|
| 1094 |
+
self._remove_keys_not_serialized(value)
|
| 1095 |
+
|
| 1096 |
+
@classmethod
|
| 1097 |
+
def register_for_auto_class(cls, auto_class="AutoConfig"):
|
| 1098 |
+
"""
|
| 1099 |
+
Register this class with a given auto class. This should only be used for custom configurations as the ones in
|
| 1100 |
+
the library are already mapped with `AutoConfig`.
|
| 1101 |
+
|
| 1102 |
+
|
| 1103 |
+
|
| 1104 |
+
Args:
|
| 1105 |
+
auto_class (`str` or `type`, *optional*, defaults to `"AutoConfig"`):
|
| 1106 |
+
The auto class to register this new configuration with.
|
| 1107 |
+
"""
|
| 1108 |
+
if not isinstance(auto_class, str):
|
| 1109 |
+
auto_class = auto_class.__name__
|
| 1110 |
+
|
| 1111 |
+
import transformers.models.auto as auto_module
|
| 1112 |
+
|
| 1113 |
+
if not hasattr(auto_module, auto_class):
|
| 1114 |
+
raise ValueError(f"{auto_class} is not a valid auto class.")
|
| 1115 |
+
|
| 1116 |
+
cls._auto_class = auto_class
|
| 1117 |
+
|
| 1118 |
+
@staticmethod
|
| 1119 |
+
def _get_global_generation_defaults() -> dict[str, Any]:
|
| 1120 |
+
return {
|
| 1121 |
+
"max_length": 20,
|
| 1122 |
+
"min_length": 0,
|
| 1123 |
+
"do_sample": False,
|
| 1124 |
+
"early_stopping": False,
|
| 1125 |
+
"num_beams": 1,
|
| 1126 |
+
"temperature": 1.0,
|
| 1127 |
+
"top_k": 50,
|
| 1128 |
+
"top_p": 1.0,
|
| 1129 |
+
"typical_p": 1.0,
|
| 1130 |
+
"repetition_penalty": 1.0,
|
| 1131 |
+
"length_penalty": 1.0,
|
| 1132 |
+
"no_repeat_ngram_size": 0,
|
| 1133 |
+
"encoder_no_repeat_ngram_size": 0,
|
| 1134 |
+
"bad_words_ids": None,
|
| 1135 |
+
"num_return_sequences": 1,
|
| 1136 |
+
"output_scores": False,
|
| 1137 |
+
"return_dict_in_generate": False,
|
| 1138 |
+
"forced_bos_token_id": None,
|
| 1139 |
+
"forced_eos_token_id": None,
|
| 1140 |
+
"remove_invalid_values": False,
|
| 1141 |
+
"exponential_decay_length_penalty": None,
|
| 1142 |
+
"suppress_tokens": None,
|
| 1143 |
+
"begin_suppress_tokens": None,
|
| 1144 |
+
# Deprecated arguments (moved to the Hub). TODO joao, manuel: remove in v4.62.0
|
| 1145 |
+
"num_beam_groups": 1,
|
| 1146 |
+
"diversity_penalty": 0.0,
|
| 1147 |
+
}
|
| 1148 |
+
|
| 1149 |
+
def _get_non_default_generation_parameters(self) -> dict[str, Any]:
|
| 1150 |
+
"""
|
| 1151 |
+
Gets the non-default generation parameters on the PretrainedConfig instance
|
| 1152 |
+
"""
|
| 1153 |
+
non_default_generation_parameters = {}
|
| 1154 |
+
decoder_attribute_name = None
|
| 1155 |
+
|
| 1156 |
+
# Composite models don't have a default config, use their decoder config as a fallback for default values
|
| 1157 |
+
# If no known pattern is matched, then `default_config = None` -> check against the global generation defaults
|
| 1158 |
+
try:
|
| 1159 |
+
default_config = self.__class__()
|
| 1160 |
+
except ValueError:
|
| 1161 |
+
decoder_config = self.get_text_config(decoder=True)
|
| 1162 |
+
if decoder_config is not self:
|
| 1163 |
+
default_config = decoder_config.__class__()
|
| 1164 |
+
else:
|
| 1165 |
+
default_config = None
|
| 1166 |
+
|
| 1167 |
+
# If it is a composite model, we want to check the subconfig that will be used for generation
|
| 1168 |
+
self_decoder_config = self if decoder_attribute_name is None else getattr(self, decoder_attribute_name)
|
| 1169 |
+
|
| 1170 |
+
for parameter_name, default_global_value in self._get_global_generation_defaults().items():
|
| 1171 |
+
if hasattr(self_decoder_config, parameter_name):
|
| 1172 |
+
is_default_in_config = is_default_generation_value = None
|
| 1173 |
+
parameter_value = getattr(self_decoder_config, parameter_name)
|
| 1174 |
+
# Three cases in which is okay for the model config to hold generation config parameters:
|
| 1175 |
+
# 1. The parameter is set to `None`, effectively delegating its value to the generation config
|
| 1176 |
+
if parameter_value is None:
|
| 1177 |
+
continue
|
| 1178 |
+
# 2. If we have a default config, then the instance should hold the same generation defaults
|
| 1179 |
+
if default_config is not None:
|
| 1180 |
+
is_default_in_config = parameter_value == getattr(default_config, parameter_name)
|
| 1181 |
+
# 3. if we don't have a default config, then the instance should hold the global generation defaults
|
| 1182 |
+
else:
|
| 1183 |
+
is_default_generation_value = parameter_value == default_global_value
|
| 1184 |
+
|
| 1185 |
+
is_non_default = (is_default_in_config is False) or (
|
| 1186 |
+
is_default_in_config is None and is_default_generation_value is False
|
| 1187 |
+
)
|
| 1188 |
+
if is_non_default:
|
| 1189 |
+
non_default_generation_parameters[parameter_name] = getattr(self_decoder_config, parameter_name)
|
| 1190 |
+
|
| 1191 |
+
return non_default_generation_parameters
|
| 1192 |
+
|
| 1193 |
+
def get_text_config(self, decoder=None, encoder=None) -> "PretrainedConfig":
|
| 1194 |
+
"""
|
| 1195 |
+
Returns the text config related to the text input (encoder) or text output (decoder) of the model. The
|
| 1196 |
+
`decoder` and `encoder` input arguments can be used to specify which end of the model we are interested in,
|
| 1197 |
+
which is useful on models that have both text input and output modalities.
|
| 1198 |
+
|
| 1199 |
+
There are three possible outcomes of using this method:
|
| 1200 |
+
1. On most models, it returns the original config instance itself.
|
| 1201 |
+
2. On newer (2024+) composite models, it returns the text section of the config, which is nested under a set
|
| 1202 |
+
of valid names.
|
| 1203 |
+
3. On older (2023-) composite models, it discards decoder-only parameters when `encoder=True` and vice-versa.
|
| 1204 |
+
|
| 1205 |
+
Args:
|
| 1206 |
+
decoder (`Optional[bool]`, *optional*):
|
| 1207 |
+
If set to `True`, then only search for decoder config names.
|
| 1208 |
+
encoder (`Optional[bool]`, *optional*):
|
| 1209 |
+
If set to `True`, then only search for encoder config names.
|
| 1210 |
+
"""
|
| 1211 |
+
return_both = decoder == encoder # both unset or both set -> search all possible names
|
| 1212 |
+
|
| 1213 |
+
decoder_possible_text_config_names = ("decoder", "generator", "text_config")
|
| 1214 |
+
encoder_possible_text_config_names = ("text_encoder",)
|
| 1215 |
+
if return_both:
|
| 1216 |
+
possible_text_config_names = encoder_possible_text_config_names + decoder_possible_text_config_names
|
| 1217 |
+
elif decoder:
|
| 1218 |
+
possible_text_config_names = decoder_possible_text_config_names
|
| 1219 |
+
else:
|
| 1220 |
+
possible_text_config_names = encoder_possible_text_config_names
|
| 1221 |
+
|
| 1222 |
+
valid_text_config_names = []
|
| 1223 |
+
for text_config_name in possible_text_config_names:
|
| 1224 |
+
if hasattr(self, text_config_name):
|
| 1225 |
+
text_config = getattr(self, text_config_name, None)
|
| 1226 |
+
if text_config is not None:
|
| 1227 |
+
valid_text_config_names += [text_config_name]
|
| 1228 |
+
|
| 1229 |
+
if len(valid_text_config_names) > 1:
|
| 1230 |
+
raise ValueError(
|
| 1231 |
+
f"Multiple valid text configs were found in the model config: {valid_text_config_names}. In this "
|
| 1232 |
+
"case, using `get_text_config()` would be ambiguous. Please specify the desired text config directly, "
|
| 1233 |
+
"e.g. `text_config = config.sub_config_name`"
|
| 1234 |
+
)
|
| 1235 |
+
elif len(valid_text_config_names) == 1:
|
| 1236 |
+
config_to_return = getattr(self, valid_text_config_names[0])
|
| 1237 |
+
else:
|
| 1238 |
+
config_to_return = self
|
| 1239 |
+
|
| 1240 |
+
# handle legacy models with flat config structure, when we only want one of the configs
|
| 1241 |
+
if not return_both and len(valid_text_config_names) == 0 and config_to_return.is_encoder_decoder:
|
| 1242 |
+
config_to_return = copy.deepcopy(config_to_return)
|
| 1243 |
+
prefix_to_discard = "encoder" if decoder else "decoder"
|
| 1244 |
+
prefix_to_keep = "decoder" if decoder else "encoder"
|
| 1245 |
+
for key in config_to_return.to_dict():
|
| 1246 |
+
# NOTE: We don't want to discard the key if it is mapped from a different attribute name at read time
|
| 1247 |
+
if key.startswith(prefix_to_discard) and key not in config_to_return.attribute_map.values():
|
| 1248 |
+
delattr(config_to_return, key)
|
| 1249 |
+
if key.startswith(prefix_to_keep):
|
| 1250 |
+
# [encoder/decoder]_layers -> num_hidden_layers
|
| 1251 |
+
if key == prefix_to_keep + "_layers":
|
| 1252 |
+
new_key = "num_hidden_layers"
|
| 1253 |
+
# [encoder/decoder]_attention_heads -> num_attention_heads
|
| 1254 |
+
elif key == prefix_to_keep + "_attention_heads":
|
| 1255 |
+
new_key = "num_attention_heads"
|
| 1256 |
+
# e.g. encoder_hidden_act -> hidden_act
|
| 1257 |
+
else:
|
| 1258 |
+
new_key = key[len(prefix_to_keep) + 1 :]
|
| 1259 |
+
|
| 1260 |
+
# Does the class map the new key into a different attribute name at read time? if so, let's write
|
| 1261 |
+
# into that attribute instead
|
| 1262 |
+
if new_key in config_to_return.attribute_map:
|
| 1263 |
+
new_key = config_to_return.attribute_map[new_key]
|
| 1264 |
+
|
| 1265 |
+
value = getattr(config_to_return, key)
|
| 1266 |
+
delattr(config_to_return, key)
|
| 1267 |
+
setattr(config_to_return, new_key, value)
|
| 1268 |
+
|
| 1269 |
+
return config_to_return
|
| 1270 |
+
|
| 1271 |
+
@classmethod
|
| 1272 |
+
def from_text_vision_configs(cls, text_config, vision_config, **kwargs):
|
| 1273 |
+
r"""
|
| 1274 |
+
Instantiate a model config (or a derived class) from text model configuration and vision model
|
| 1275 |
+
configuration.
|
| 1276 |
+
|
| 1277 |
+
Returns:
|
| 1278 |
+
[`PreTrainedConfig`]: An instance of a configuration object
|
| 1279 |
+
"""
|
| 1280 |
+
|
| 1281 |
+
warnings.warn(
|
| 1282 |
+
"The `from_text_vision_configs` method is deprecated and will be removed in v4.60 of Transformers. Please instantiate "
|
| 1283 |
+
"the config class directly with `MyConfig(text_config=text_config, vision_config=vision_config, **kwargs)` instead.",
|
| 1284 |
+
FutureWarning,
|
| 1285 |
+
)
|
| 1286 |
+
|
| 1287 |
+
return cls(text_config=text_config.to_dict(), vision_config=vision_config.to_dict(), **kwargs)
|
| 1288 |
+
|
| 1289 |
+
@classmethod
|
| 1290 |
+
def from_text_audio_configs(cls, text_config, audio_config, **kwargs):
|
| 1291 |
+
r"""
|
| 1292 |
+
Instantiate a model config (or a derived class) from text model configuration and audio model
|
| 1293 |
+
configuration.
|
| 1294 |
+
|
| 1295 |
+
Returns:
|
| 1296 |
+
[`PreTrainedConfig`]: An instance of a configuration object
|
| 1297 |
+
"""
|
| 1298 |
+
|
| 1299 |
+
warnings.warn(
|
| 1300 |
+
"The `from_text_audio_configs` method is deprecated and will be removed in v4.60 of Transformers. Please instantiate "
|
| 1301 |
+
"the config class directly with `MyConfig(text_config=text_config, audio_config=audio_config, **kwargs)` instead.",
|
| 1302 |
+
FutureWarning,
|
| 1303 |
+
)
|
| 1304 |
+
|
| 1305 |
+
return cls(text_config=text_config.to_dict(), audio_config=audio_config.to_dict(), **kwargs)
|
| 1306 |
+
|
| 1307 |
+
|
| 1308 |
+
def get_configuration_file(configuration_files: list[str]) -> str:
|
| 1309 |
+
"""
|
| 1310 |
+
Get the configuration file to use for this version of transformers.
|
| 1311 |
+
|
| 1312 |
+
Args:
|
| 1313 |
+
configuration_files (`list[str]`): The list of available configuration files.
|
| 1314 |
+
|
| 1315 |
+
Returns:
|
| 1316 |
+
`str`: The configuration file to use.
|
| 1317 |
+
"""
|
| 1318 |
+
configuration_files_map = {}
|
| 1319 |
+
for file_name in configuration_files:
|
| 1320 |
+
if file_name.startswith("config.") and file_name.endswith(".json") and file_name != "config.json":
|
| 1321 |
+
v = file_name.removeprefix("config.").removesuffix(".json")
|
| 1322 |
+
configuration_files_map[v] = file_name
|
| 1323 |
+
available_versions = sorted(configuration_files_map.keys())
|
| 1324 |
+
|
| 1325 |
+
# Defaults to FULL_CONFIGURATION_FILE and then try to look at some newer versions.
|
| 1326 |
+
configuration_file = CONFIG_NAME
|
| 1327 |
+
transformers_version = version.parse(__version__)
|
| 1328 |
+
for v in available_versions:
|
| 1329 |
+
if version.parse(v) <= transformers_version:
|
| 1330 |
+
configuration_file = configuration_files_map[v]
|
| 1331 |
+
else:
|
| 1332 |
+
# No point going further since the versions are sorted.
|
| 1333 |
+
break
|
| 1334 |
+
|
| 1335 |
+
return configuration_file
|
| 1336 |
+
|
| 1337 |
+
|
| 1338 |
+
def recursive_diff_dict(dict_a, dict_b, config_obj=None):
|
| 1339 |
+
"""
|
| 1340 |
+
Helper function to recursively take the diff between two nested dictionaries. The resulting diff only contains the
|
| 1341 |
+
values from `dict_a` that are different from values in `dict_b`.
|
| 1342 |
+
|
| 1343 |
+
dict_b : the default config dictionary. We want to remove values that are in this one
|
| 1344 |
+
"""
|
| 1345 |
+
diff = {}
|
| 1346 |
+
default = config_obj.__class__().to_dict() if config_obj is not None else {}
|
| 1347 |
+
for key, value in dict_a.items():
|
| 1348 |
+
obj_value = getattr(config_obj, str(key), None)
|
| 1349 |
+
if isinstance(obj_value, PretrainedConfig) and key in dict_b and isinstance(dict_b[key], dict):
|
| 1350 |
+
diff_value = recursive_diff_dict(value, dict_b[key], config_obj=obj_value)
|
| 1351 |
+
diff[key] = diff_value
|
| 1352 |
+
elif key not in dict_b or (value != default[key]):
|
| 1353 |
+
diff[key] = value
|
| 1354 |
+
return diff
|
| 1355 |
+
|
| 1356 |
+
|
| 1357 |
+
PretrainedConfig.push_to_hub = copy_func(PretrainedConfig.push_to_hub)
|
| 1358 |
+
if PretrainedConfig.push_to_hub.__doc__ is not None:
|
| 1359 |
+
PretrainedConfig.push_to_hub.__doc__ = PretrainedConfig.push_to_hub.__doc__.format(
|
| 1360 |
+
object="config", object_class="AutoConfig", object_files="configuration file"
|
| 1361 |
+
)
|
| 1362 |
+
|
| 1363 |
+
|
| 1364 |
+
ALLOWED_LAYER_TYPES = (
|
| 1365 |
+
"full_attention",
|
| 1366 |
+
"sliding_attention",
|
| 1367 |
+
"chunked_attention",
|
| 1368 |
+
"linear_attention", # used in minimax
|
| 1369 |
+
)
|
| 1370 |
+
|
| 1371 |
+
|
| 1372 |
+
def layer_type_validation(layer_types: list[str], num_hidden_layers: Optional[int] = None):
|
| 1373 |
+
"""Check that `layer_types` is correctly defined."""
|
| 1374 |
+
if not all(layer_type in ALLOWED_LAYER_TYPES for layer_type in layer_types):
|
| 1375 |
+
raise ValueError(f"The `layer_types` entries must be in {ALLOWED_LAYER_TYPES}")
|
| 1376 |
+
if num_hidden_layers is not None and num_hidden_layers != len(layer_types):
|
| 1377 |
+
raise ValueError(
|
| 1378 |
+
f"`num_hidden_layers` ({num_hidden_layers}) must be equal to the number of layer types "
|
| 1379 |
+
f"({len(layer_types)})"
|
| 1380 |
+
)
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/transformers/convert_graph_to_onnx.py
ADDED
|
@@ -0,0 +1,551 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2020 The HuggingFace 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 |
+
|
| 15 |
+
import warnings
|
| 16 |
+
from argparse import ArgumentParser
|
| 17 |
+
from os import listdir, makedirs
|
| 18 |
+
from pathlib import Path
|
| 19 |
+
from typing import Optional
|
| 20 |
+
|
| 21 |
+
from packaging.version import Version, parse
|
| 22 |
+
|
| 23 |
+
from transformers.pipelines import Pipeline, pipeline
|
| 24 |
+
from transformers.tokenization_utils import BatchEncoding
|
| 25 |
+
from transformers.utils import ModelOutput, is_tf_available, is_torch_available
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
# This is the minimal required version to
|
| 29 |
+
# support some ONNX Runtime features
|
| 30 |
+
ORT_QUANTIZE_MINIMUM_VERSION = parse("1.4.0")
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
SUPPORTED_PIPELINES = [
|
| 34 |
+
"feature-extraction",
|
| 35 |
+
"ner",
|
| 36 |
+
"sentiment-analysis",
|
| 37 |
+
"fill-mask",
|
| 38 |
+
"question-answering",
|
| 39 |
+
"text-generation",
|
| 40 |
+
"translation_en_to_fr",
|
| 41 |
+
"translation_en_to_de",
|
| 42 |
+
"translation_en_to_ro",
|
| 43 |
+
]
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
class OnnxConverterArgumentParser(ArgumentParser):
|
| 47 |
+
"""
|
| 48 |
+
Wraps all the script arguments supported to export transformers models to ONNX IR
|
| 49 |
+
"""
|
| 50 |
+
|
| 51 |
+
def __init__(self):
|
| 52 |
+
super().__init__("ONNX Converter")
|
| 53 |
+
|
| 54 |
+
self.add_argument(
|
| 55 |
+
"--pipeline",
|
| 56 |
+
type=str,
|
| 57 |
+
choices=SUPPORTED_PIPELINES,
|
| 58 |
+
default="feature-extraction",
|
| 59 |
+
)
|
| 60 |
+
self.add_argument(
|
| 61 |
+
"--model",
|
| 62 |
+
type=str,
|
| 63 |
+
required=True,
|
| 64 |
+
help="Model's id or path (ex: google-bert/bert-base-cased)",
|
| 65 |
+
)
|
| 66 |
+
self.add_argument("--tokenizer", type=str, help="Tokenizer's id or path (ex: google-bert/bert-base-cased)")
|
| 67 |
+
self.add_argument(
|
| 68 |
+
"--framework",
|
| 69 |
+
type=str,
|
| 70 |
+
choices=["pt", "tf"],
|
| 71 |
+
help="Framework for loading the model",
|
| 72 |
+
)
|
| 73 |
+
self.add_argument("--opset", type=int, default=11, help="ONNX opset to use")
|
| 74 |
+
self.add_argument(
|
| 75 |
+
"--check-loading",
|
| 76 |
+
action="store_true",
|
| 77 |
+
help="Check ONNX is able to load the model",
|
| 78 |
+
)
|
| 79 |
+
self.add_argument(
|
| 80 |
+
"--use-external-format",
|
| 81 |
+
action="store_true",
|
| 82 |
+
help="Allow exporting model >= than 2Gb",
|
| 83 |
+
)
|
| 84 |
+
self.add_argument(
|
| 85 |
+
"--quantize",
|
| 86 |
+
action="store_true",
|
| 87 |
+
help="Quantize the neural network to be run with int8",
|
| 88 |
+
)
|
| 89 |
+
self.add_argument("output")
|
| 90 |
+
|
| 91 |
+
|
| 92 |
+
def generate_identified_filename(filename: Path, identifier: str) -> Path:
|
| 93 |
+
"""
|
| 94 |
+
Append a string-identifier at the end (before the extension, if any) to the provided filepath
|
| 95 |
+
|
| 96 |
+
Args:
|
| 97 |
+
filename: pathlib.Path The actual path object we would like to add an identifier suffix
|
| 98 |
+
identifier: The suffix to add
|
| 99 |
+
|
| 100 |
+
Returns: String with concatenated identifier at the end of the filename
|
| 101 |
+
"""
|
| 102 |
+
return filename.parent.joinpath(filename.stem + identifier).with_suffix(filename.suffix)
|
| 103 |
+
|
| 104 |
+
|
| 105 |
+
def check_onnxruntime_requirements(minimum_version: Version):
|
| 106 |
+
"""
|
| 107 |
+
Check onnxruntime is installed and if the installed version match is recent enough
|
| 108 |
+
|
| 109 |
+
Raises:
|
| 110 |
+
ImportError: If onnxruntime is not installed or too old version is found
|
| 111 |
+
"""
|
| 112 |
+
try:
|
| 113 |
+
import onnxruntime
|
| 114 |
+
|
| 115 |
+
# Parse the version of the installed onnxruntime
|
| 116 |
+
ort_version = parse(onnxruntime.__version__)
|
| 117 |
+
|
| 118 |
+
# We require 1.4.0 minimum
|
| 119 |
+
if ort_version < ORT_QUANTIZE_MINIMUM_VERSION:
|
| 120 |
+
raise ImportError(
|
| 121 |
+
f"We found an older version of onnxruntime ({onnxruntime.__version__}) "
|
| 122 |
+
f"but we require onnxruntime to be >= {minimum_version} to enable all the conversions options.\n"
|
| 123 |
+
"Please update onnxruntime by running `pip install --upgrade onnxruntime`"
|
| 124 |
+
)
|
| 125 |
+
|
| 126 |
+
except ImportError:
|
| 127 |
+
raise ImportError(
|
| 128 |
+
"onnxruntime doesn't seem to be currently installed. "
|
| 129 |
+
"Please install the onnxruntime by running `pip install onnxruntime`"
|
| 130 |
+
" and relaunch the conversion."
|
| 131 |
+
)
|
| 132 |
+
|
| 133 |
+
|
| 134 |
+
def ensure_valid_input(model, tokens, input_names):
|
| 135 |
+
"""
|
| 136 |
+
Ensure inputs are presented in the correct order, without any Non
|
| 137 |
+
|
| 138 |
+
Args:
|
| 139 |
+
model: The model used to forward the input data
|
| 140 |
+
tokens: BatchEncoding holding the input data
|
| 141 |
+
input_names: The name of the inputs
|
| 142 |
+
|
| 143 |
+
Returns: Tuple
|
| 144 |
+
|
| 145 |
+
"""
|
| 146 |
+
print("Ensuring inputs are in correct order")
|
| 147 |
+
|
| 148 |
+
model_args_name = model.forward.__code__.co_varnames
|
| 149 |
+
model_args, ordered_input_names = [], []
|
| 150 |
+
for arg_name in model_args_name[1:]: # start at index 1 to skip "self" argument
|
| 151 |
+
if arg_name in input_names:
|
| 152 |
+
ordered_input_names.append(arg_name)
|
| 153 |
+
model_args.append(tokens[arg_name])
|
| 154 |
+
else:
|
| 155 |
+
print(f"{arg_name} is not present in the generated input list.")
|
| 156 |
+
break
|
| 157 |
+
|
| 158 |
+
print(f"Generated inputs order: {ordered_input_names}")
|
| 159 |
+
return ordered_input_names, tuple(model_args)
|
| 160 |
+
|
| 161 |
+
|
| 162 |
+
def infer_shapes(nlp: Pipeline, framework: str) -> tuple[list[str], list[str], dict, BatchEncoding]:
|
| 163 |
+
"""
|
| 164 |
+
Attempt to infer the static vs dynamic axes for each input and output tensors for a specific model
|
| 165 |
+
|
| 166 |
+
Args:
|
| 167 |
+
nlp: The pipeline object holding the model to be exported
|
| 168 |
+
framework: The framework identifier to dispatch to the correct inference scheme (pt/tf)
|
| 169 |
+
|
| 170 |
+
Returns:
|
| 171 |
+
|
| 172 |
+
- List of the inferred input variable names
|
| 173 |
+
- List of the inferred output variable names
|
| 174 |
+
- Dictionary with input/output variables names as key and shape tensor as value
|
| 175 |
+
- a BatchEncoding reference which was used to infer all the above information
|
| 176 |
+
"""
|
| 177 |
+
|
| 178 |
+
def build_shape_dict(name: str, tensor, is_input: bool, seq_len: int):
|
| 179 |
+
if isinstance(tensor, (tuple, list)):
|
| 180 |
+
return [build_shape_dict(name, t, is_input, seq_len) for t in tensor]
|
| 181 |
+
|
| 182 |
+
else:
|
| 183 |
+
# Let's assume batch is the first axis with only 1 element (~~ might not be always true ...)
|
| 184 |
+
axes = {[axis for axis, numel in enumerate(tensor.shape) if numel == 1][0]: "batch"}
|
| 185 |
+
if is_input:
|
| 186 |
+
if len(tensor.shape) == 2:
|
| 187 |
+
axes[1] = "sequence"
|
| 188 |
+
else:
|
| 189 |
+
raise ValueError(f"Unable to infer tensor axes ({len(tensor.shape)})")
|
| 190 |
+
else:
|
| 191 |
+
seq_axes = [dim for dim, shape in enumerate(tensor.shape) if shape == seq_len]
|
| 192 |
+
axes.update(dict.fromkeys(seq_axes, "sequence"))
|
| 193 |
+
|
| 194 |
+
print(f"Found {'input' if is_input else 'output'} {name} with shape: {axes}")
|
| 195 |
+
return axes
|
| 196 |
+
|
| 197 |
+
tokens = nlp.tokenizer("This is a sample output", return_tensors=framework)
|
| 198 |
+
seq_len = tokens.input_ids.shape[-1]
|
| 199 |
+
outputs = nlp.model(**tokens) if framework == "pt" else nlp.model(tokens)
|
| 200 |
+
if isinstance(outputs, ModelOutput):
|
| 201 |
+
outputs = outputs.to_tuple()
|
| 202 |
+
if not isinstance(outputs, (list, tuple)):
|
| 203 |
+
outputs = (outputs,)
|
| 204 |
+
|
| 205 |
+
# Generate input names & axes
|
| 206 |
+
input_vars = list(tokens.keys())
|
| 207 |
+
input_dynamic_axes = {k: build_shape_dict(k, v, True, seq_len) for k, v in tokens.items()}
|
| 208 |
+
|
| 209 |
+
# flatten potentially grouped outputs (past for gpt2, attentions)
|
| 210 |
+
outputs_flat = []
|
| 211 |
+
for output in outputs:
|
| 212 |
+
if isinstance(output, (tuple, list)):
|
| 213 |
+
outputs_flat.extend(output)
|
| 214 |
+
else:
|
| 215 |
+
outputs_flat.append(output)
|
| 216 |
+
|
| 217 |
+
# Generate output names & axes
|
| 218 |
+
output_names = [f"output_{i}" for i in range(len(outputs_flat))]
|
| 219 |
+
output_dynamic_axes = {k: build_shape_dict(k, v, False, seq_len) for k, v in zip(output_names, outputs_flat)}
|
| 220 |
+
|
| 221 |
+
# Create the aggregated axes representation
|
| 222 |
+
dynamic_axes = dict(input_dynamic_axes, **output_dynamic_axes)
|
| 223 |
+
return input_vars, output_names, dynamic_axes, tokens
|
| 224 |
+
|
| 225 |
+
|
| 226 |
+
def load_graph_from_args(
|
| 227 |
+
pipeline_name: str, framework: str, model: str, tokenizer: Optional[str] = None, **models_kwargs
|
| 228 |
+
) -> Pipeline:
|
| 229 |
+
"""
|
| 230 |
+
Convert the set of arguments provided through the CLI to an actual pipeline reference (tokenizer + model
|
| 231 |
+
|
| 232 |
+
Args:
|
| 233 |
+
pipeline_name: The kind of pipeline to use (ner, question-answering, etc.)
|
| 234 |
+
framework: The actual model to convert the pipeline from ("pt" or "tf")
|
| 235 |
+
model: The model name which will be loaded by the pipeline
|
| 236 |
+
tokenizer: The tokenizer name which will be loaded by the pipeline, default to the model's value
|
| 237 |
+
|
| 238 |
+
Returns: Pipeline object
|
| 239 |
+
|
| 240 |
+
"""
|
| 241 |
+
# If no tokenizer provided
|
| 242 |
+
if tokenizer is None:
|
| 243 |
+
tokenizer = model
|
| 244 |
+
|
| 245 |
+
# Check the wanted framework is available
|
| 246 |
+
if framework == "pt" and not is_torch_available():
|
| 247 |
+
raise Exception("Cannot convert because PyTorch is not installed. Please install torch first.")
|
| 248 |
+
if framework == "tf" and not is_tf_available():
|
| 249 |
+
raise Exception("Cannot convert because TF is not installed. Please install tensorflow first.")
|
| 250 |
+
|
| 251 |
+
print(f"Loading pipeline (model: {model}, tokenizer: {tokenizer})")
|
| 252 |
+
|
| 253 |
+
# Allocate tokenizer and model
|
| 254 |
+
return pipeline(pipeline_name, model=model, tokenizer=tokenizer, framework=framework, model_kwargs=models_kwargs)
|
| 255 |
+
|
| 256 |
+
|
| 257 |
+
def convert_pytorch(nlp: Pipeline, opset: int, output: Path, use_external_format: bool):
|
| 258 |
+
"""
|
| 259 |
+
Export a PyTorch backed pipeline to ONNX Intermediate Representation (IR
|
| 260 |
+
|
| 261 |
+
Args:
|
| 262 |
+
nlp: The pipeline to be exported
|
| 263 |
+
opset: The actual version of the ONNX operator set to use
|
| 264 |
+
output: Path where will be stored the generated ONNX model
|
| 265 |
+
use_external_format: Split the model definition from its parameters to allow model bigger than 2GB
|
| 266 |
+
|
| 267 |
+
Returns:
|
| 268 |
+
|
| 269 |
+
"""
|
| 270 |
+
if not is_torch_available():
|
| 271 |
+
raise Exception("Cannot convert because PyTorch is not installed. Please install torch first.")
|
| 272 |
+
|
| 273 |
+
import torch
|
| 274 |
+
from torch.onnx import export
|
| 275 |
+
|
| 276 |
+
print(f"Using framework PyTorch: {torch.__version__}")
|
| 277 |
+
|
| 278 |
+
with torch.no_grad():
|
| 279 |
+
input_names, output_names, dynamic_axes, tokens = infer_shapes(nlp, "pt")
|
| 280 |
+
ordered_input_names, model_args = ensure_valid_input(nlp.model, tokens, input_names)
|
| 281 |
+
|
| 282 |
+
export(
|
| 283 |
+
nlp.model,
|
| 284 |
+
model_args,
|
| 285 |
+
f=output.as_posix(),
|
| 286 |
+
input_names=ordered_input_names,
|
| 287 |
+
output_names=output_names,
|
| 288 |
+
dynamic_axes=dynamic_axes,
|
| 289 |
+
do_constant_folding=True,
|
| 290 |
+
opset_version=opset,
|
| 291 |
+
)
|
| 292 |
+
|
| 293 |
+
|
| 294 |
+
def convert_tensorflow(nlp: Pipeline, opset: int, output: Path):
|
| 295 |
+
"""
|
| 296 |
+
Export a TensorFlow backed pipeline to ONNX Intermediate Representation (IR)
|
| 297 |
+
|
| 298 |
+
Args:
|
| 299 |
+
nlp: The pipeline to be exported
|
| 300 |
+
opset: The actual version of the ONNX operator set to use
|
| 301 |
+
output: Path where will be stored the generated ONNX model
|
| 302 |
+
|
| 303 |
+
Notes: TensorFlow cannot export model bigger than 2GB due to internal constraint from TensorFlow
|
| 304 |
+
|
| 305 |
+
"""
|
| 306 |
+
if not is_tf_available():
|
| 307 |
+
raise Exception("Cannot convert because TF is not installed. Please install tensorflow first.")
|
| 308 |
+
|
| 309 |
+
print("/!\\ Please note TensorFlow doesn't support exporting model > 2Gb /!\\")
|
| 310 |
+
|
| 311 |
+
try:
|
| 312 |
+
import tensorflow as tf
|
| 313 |
+
import tf2onnx
|
| 314 |
+
from tf2onnx import __version__ as t2ov
|
| 315 |
+
|
| 316 |
+
print(f"Using framework TensorFlow: {tf.version.VERSION}, tf2onnx: {t2ov}")
|
| 317 |
+
|
| 318 |
+
# Build
|
| 319 |
+
input_names, output_names, dynamic_axes, tokens = infer_shapes(nlp, "tf")
|
| 320 |
+
|
| 321 |
+
# Forward
|
| 322 |
+
nlp.model.predict(tokens.data)
|
| 323 |
+
input_signature = [tf.TensorSpec.from_tensor(tensor, name=key) for key, tensor in tokens.items()]
|
| 324 |
+
model_proto, _ = tf2onnx.convert.from_keras(
|
| 325 |
+
nlp.model, input_signature, opset=opset, output_path=output.as_posix()
|
| 326 |
+
)
|
| 327 |
+
|
| 328 |
+
except ImportError as e:
|
| 329 |
+
raise Exception(
|
| 330 |
+
f"Cannot import {e.name} required to convert TF model to ONNX. Please install {e.name} first. {e}"
|
| 331 |
+
)
|
| 332 |
+
|
| 333 |
+
|
| 334 |
+
def convert(
|
| 335 |
+
framework: str,
|
| 336 |
+
model: str,
|
| 337 |
+
output: Path,
|
| 338 |
+
opset: int,
|
| 339 |
+
tokenizer: Optional[str] = None,
|
| 340 |
+
use_external_format: bool = False,
|
| 341 |
+
pipeline_name: str = "feature-extraction",
|
| 342 |
+
**model_kwargs,
|
| 343 |
+
):
|
| 344 |
+
"""
|
| 345 |
+
Convert the pipeline object to the ONNX Intermediate Representation (IR) format
|
| 346 |
+
|
| 347 |
+
Args:
|
| 348 |
+
framework: The framework the pipeline is backed by ("pt" or "tf")
|
| 349 |
+
model: The name of the model to load for the pipeline
|
| 350 |
+
output: The path where the ONNX graph will be stored
|
| 351 |
+
opset: The actual version of the ONNX operator set to use
|
| 352 |
+
tokenizer: The name of the model to load for the pipeline, default to the model's name if not provided
|
| 353 |
+
use_external_format:
|
| 354 |
+
Split the model definition from its parameters to allow model bigger than 2GB (PyTorch only)
|
| 355 |
+
pipeline_name: The kind of pipeline to instantiate (ner, question-answering, etc.)
|
| 356 |
+
model_kwargs: Keyword arguments to be forwarded to the model constructor
|
| 357 |
+
|
| 358 |
+
Returns:
|
| 359 |
+
|
| 360 |
+
"""
|
| 361 |
+
warnings.warn(
|
| 362 |
+
"The `transformers.convert_graph_to_onnx` package is deprecated and will be removed in version 5 of"
|
| 363 |
+
" Transformers",
|
| 364 |
+
FutureWarning,
|
| 365 |
+
)
|
| 366 |
+
print(f"ONNX opset version set to: {opset}")
|
| 367 |
+
|
| 368 |
+
# Load the pipeline
|
| 369 |
+
nlp = load_graph_from_args(pipeline_name, framework, model, tokenizer, **model_kwargs)
|
| 370 |
+
|
| 371 |
+
if not output.parent.exists():
|
| 372 |
+
print(f"Creating folder {output.parent}")
|
| 373 |
+
makedirs(output.parent.as_posix())
|
| 374 |
+
elif len(listdir(output.parent.as_posix())) > 0:
|
| 375 |
+
raise Exception(f"Folder {output.parent.as_posix()} is not empty, aborting conversion")
|
| 376 |
+
|
| 377 |
+
# Export the graph
|
| 378 |
+
if framework == "pt":
|
| 379 |
+
convert_pytorch(nlp, opset, output, use_external_format)
|
| 380 |
+
else:
|
| 381 |
+
convert_tensorflow(nlp, opset, output)
|
| 382 |
+
|
| 383 |
+
|
| 384 |
+
def optimize(onnx_model_path: Path) -> Path:
|
| 385 |
+
"""
|
| 386 |
+
Load the model at the specified path and let onnxruntime look at transformations on the graph to enable all the
|
| 387 |
+
optimizations possible
|
| 388 |
+
|
| 389 |
+
Args:
|
| 390 |
+
onnx_model_path: filepath where the model binary description is stored
|
| 391 |
+
|
| 392 |
+
Returns: Path where the optimized model binary description has been saved
|
| 393 |
+
|
| 394 |
+
"""
|
| 395 |
+
from onnxruntime import InferenceSession, SessionOptions
|
| 396 |
+
|
| 397 |
+
# Generate model name with suffix "optimized"
|
| 398 |
+
opt_model_path = generate_identified_filename(onnx_model_path, "-optimized")
|
| 399 |
+
sess_option = SessionOptions()
|
| 400 |
+
sess_option.optimized_model_filepath = opt_model_path.as_posix()
|
| 401 |
+
_ = InferenceSession(onnx_model_path.as_posix(), sess_option)
|
| 402 |
+
|
| 403 |
+
print(f"Optimized model has been written at {opt_model_path}: \N{HEAVY CHECK MARK}")
|
| 404 |
+
print("/!\\ Optimized model contains hardware specific operators which might not be portable. /!\\")
|
| 405 |
+
|
| 406 |
+
return opt_model_path
|
| 407 |
+
|
| 408 |
+
|
| 409 |
+
def quantize(onnx_model_path: Path) -> Path:
|
| 410 |
+
"""
|
| 411 |
+
Quantize the weights of the model from float32 to in8 to allow very efficient inference on modern CPU
|
| 412 |
+
|
| 413 |
+
Args:
|
| 414 |
+
onnx_model_path: Path to location the exported ONNX model is stored
|
| 415 |
+
|
| 416 |
+
Returns: The Path generated for the quantized
|
| 417 |
+
"""
|
| 418 |
+
import onnx
|
| 419 |
+
import onnxruntime
|
| 420 |
+
from onnx.onnx_pb import ModelProto
|
| 421 |
+
from onnxruntime.quantization import QuantizationMode
|
| 422 |
+
from onnxruntime.quantization.onnx_quantizer import ONNXQuantizer
|
| 423 |
+
from onnxruntime.quantization.registry import IntegerOpsRegistry
|
| 424 |
+
|
| 425 |
+
# Load the ONNX model
|
| 426 |
+
onnx_model = onnx.load(onnx_model_path.as_posix())
|
| 427 |
+
|
| 428 |
+
if parse(onnx.__version__) < parse("1.5.0"):
|
| 429 |
+
print(
|
| 430 |
+
"Models larger than 2GB will fail to quantize due to protobuf constraint.\n"
|
| 431 |
+
"Please upgrade to onnxruntime >= 1.5.0."
|
| 432 |
+
)
|
| 433 |
+
|
| 434 |
+
# Copy it
|
| 435 |
+
copy_model = ModelProto()
|
| 436 |
+
copy_model.CopyFrom(onnx_model)
|
| 437 |
+
|
| 438 |
+
# Construct quantizer
|
| 439 |
+
# onnxruntime renamed input_qType to activation_qType in v1.13.1, so we
|
| 440 |
+
# check the onnxruntime version to ensure backward compatibility.
|
| 441 |
+
# See also: https://github.com/microsoft/onnxruntime/pull/12873
|
| 442 |
+
if parse(onnxruntime.__version__) < parse("1.13.1"):
|
| 443 |
+
quantizer = ONNXQuantizer(
|
| 444 |
+
model=copy_model,
|
| 445 |
+
per_channel=False,
|
| 446 |
+
reduce_range=False,
|
| 447 |
+
mode=QuantizationMode.IntegerOps,
|
| 448 |
+
static=False,
|
| 449 |
+
weight_qType=True,
|
| 450 |
+
input_qType=False,
|
| 451 |
+
tensors_range=None,
|
| 452 |
+
nodes_to_quantize=None,
|
| 453 |
+
nodes_to_exclude=None,
|
| 454 |
+
op_types_to_quantize=list(IntegerOpsRegistry),
|
| 455 |
+
)
|
| 456 |
+
else:
|
| 457 |
+
quantizer = ONNXQuantizer(
|
| 458 |
+
model=copy_model,
|
| 459 |
+
per_channel=False,
|
| 460 |
+
reduce_range=False,
|
| 461 |
+
mode=QuantizationMode.IntegerOps,
|
| 462 |
+
static=False,
|
| 463 |
+
weight_qType=True,
|
| 464 |
+
activation_qType=False,
|
| 465 |
+
tensors_range=None,
|
| 466 |
+
nodes_to_quantize=None,
|
| 467 |
+
nodes_to_exclude=None,
|
| 468 |
+
op_types_to_quantize=list(IntegerOpsRegistry),
|
| 469 |
+
)
|
| 470 |
+
|
| 471 |
+
# Quantize and export
|
| 472 |
+
quantizer.quantize_model()
|
| 473 |
+
|
| 474 |
+
# Append "-quantized" at the end of the model's name
|
| 475 |
+
quantized_model_path = generate_identified_filename(onnx_model_path, "-quantized")
|
| 476 |
+
|
| 477 |
+
# Save model
|
| 478 |
+
print(f"Quantized model has been written at {quantized_model_path}: \N{HEAVY CHECK MARK}")
|
| 479 |
+
onnx.save_model(quantizer.model.model, quantized_model_path.as_posix())
|
| 480 |
+
|
| 481 |
+
return quantized_model_path
|
| 482 |
+
|
| 483 |
+
|
| 484 |
+
def verify(path: Path):
|
| 485 |
+
from onnxruntime import InferenceSession, SessionOptions
|
| 486 |
+
from onnxruntime.capi.onnxruntime_pybind11_state import RuntimeException
|
| 487 |
+
|
| 488 |
+
print(f"Checking ONNX model loading from: {path} ...")
|
| 489 |
+
try:
|
| 490 |
+
onnx_options = SessionOptions()
|
| 491 |
+
_ = InferenceSession(path.as_posix(), onnx_options, providers=["CPUExecutionProvider"])
|
| 492 |
+
print(f"Model {path} correctly loaded: \N{HEAVY CHECK MARK}")
|
| 493 |
+
except RuntimeException as re:
|
| 494 |
+
print(f"Error while loading the model {re}: \N{HEAVY BALLOT X}")
|
| 495 |
+
|
| 496 |
+
|
| 497 |
+
if __name__ == "__main__":
|
| 498 |
+
parser = OnnxConverterArgumentParser()
|
| 499 |
+
args = parser.parse_args()
|
| 500 |
+
|
| 501 |
+
# Make sure output is absolute path
|
| 502 |
+
args.output = Path(args.output).absolute()
|
| 503 |
+
|
| 504 |
+
try:
|
| 505 |
+
print("\n====== Converting model to ONNX ======")
|
| 506 |
+
# Convert
|
| 507 |
+
convert(
|
| 508 |
+
args.framework,
|
| 509 |
+
args.model,
|
| 510 |
+
args.output,
|
| 511 |
+
args.opset,
|
| 512 |
+
args.tokenizer,
|
| 513 |
+
args.use_external_format,
|
| 514 |
+
args.pipeline,
|
| 515 |
+
)
|
| 516 |
+
|
| 517 |
+
if args.quantize:
|
| 518 |
+
# Ensure requirements for quantization on onnxruntime is met
|
| 519 |
+
check_onnxruntime_requirements(ORT_QUANTIZE_MINIMUM_VERSION)
|
| 520 |
+
|
| 521 |
+
# onnxruntime optimizations doesn't provide the same level of performances on TensorFlow than PyTorch
|
| 522 |
+
if args.framework == "tf":
|
| 523 |
+
print(
|
| 524 |
+
"\t Using TensorFlow might not provide the same optimization level compared to PyTorch.\n"
|
| 525 |
+
"\t For TensorFlow users you can try optimizing the model directly through onnxruntime_tools.\n"
|
| 526 |
+
"\t For more information, please refer to the onnxruntime documentation:\n"
|
| 527 |
+
"\t\thttps://github.com/microsoft/onnxruntime/tree/master/onnxruntime/python/tools/transformers\n"
|
| 528 |
+
)
|
| 529 |
+
|
| 530 |
+
print("\n====== Optimizing ONNX model ======")
|
| 531 |
+
|
| 532 |
+
# Quantization works best when using the optimized version of the model
|
| 533 |
+
args.optimized_output = optimize(args.output)
|
| 534 |
+
|
| 535 |
+
# Do the quantization on the right graph
|
| 536 |
+
args.quantized_output = quantize(args.optimized_output)
|
| 537 |
+
|
| 538 |
+
# And verify
|
| 539 |
+
if args.check_loading:
|
| 540 |
+
print("\n====== Check exported ONNX model(s) ======")
|
| 541 |
+
verify(args.output)
|
| 542 |
+
|
| 543 |
+
if hasattr(args, "optimized_output"):
|
| 544 |
+
verify(args.optimized_output)
|
| 545 |
+
|
| 546 |
+
if hasattr(args, "quantized_output"):
|
| 547 |
+
verify(args.quantized_output)
|
| 548 |
+
|
| 549 |
+
except Exception as e:
|
| 550 |
+
print(f"Error while converting the model: {e}")
|
| 551 |
+
exit(1)
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/transformers/convert_slow_tokenizer.py
ADDED
|
@@ -0,0 +1,1873 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2018 The HuggingFace Inc. team.
|
| 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 |
+
"""
|
| 15 |
+
Utilities to convert slow tokenizers in their fast tokenizers counterparts.
|
| 16 |
+
|
| 17 |
+
All the conversions are grouped here to gather SentencePiece dependencies outside of the fast tokenizers files and
|
| 18 |
+
allow to make our dependency on SentencePiece optional.
|
| 19 |
+
"""
|
| 20 |
+
|
| 21 |
+
import warnings
|
| 22 |
+
from functools import lru_cache
|
| 23 |
+
from typing import Optional
|
| 24 |
+
|
| 25 |
+
from packaging import version
|
| 26 |
+
from tokenizers import AddedToken, Regex, Tokenizer, decoders, normalizers, pre_tokenizers, processors
|
| 27 |
+
from tokenizers.models import BPE, Unigram, WordPiece
|
| 28 |
+
from tqdm import tqdm
|
| 29 |
+
|
| 30 |
+
from .utils import is_protobuf_available, is_sentencepiece_available, logging, requires_backends
|
| 31 |
+
from .utils.import_utils import PROTOBUF_IMPORT_ERROR
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
logger = logging.get_logger(__name__)
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
def import_protobuf(error_message=""):
|
| 38 |
+
if is_sentencepiece_available():
|
| 39 |
+
from sentencepiece import sentencepiece_model_pb2
|
| 40 |
+
|
| 41 |
+
return sentencepiece_model_pb2
|
| 42 |
+
if is_protobuf_available():
|
| 43 |
+
import google.protobuf
|
| 44 |
+
|
| 45 |
+
if version.parse(google.protobuf.__version__) < version.parse("4.0.0"):
|
| 46 |
+
from transformers.utils import sentencepiece_model_pb2
|
| 47 |
+
else:
|
| 48 |
+
from transformers.utils import sentencepiece_model_pb2_new as sentencepiece_model_pb2
|
| 49 |
+
return sentencepiece_model_pb2
|
| 50 |
+
else:
|
| 51 |
+
raise ImportError(PROTOBUF_IMPORT_ERROR.format(error_message))
|
| 52 |
+
|
| 53 |
+
|
| 54 |
+
def _get_prepend_scheme(add_prefix_space: bool, original_tokenizer) -> str:
|
| 55 |
+
if add_prefix_space:
|
| 56 |
+
prepend_scheme = "always"
|
| 57 |
+
if not getattr(original_tokenizer, "legacy", True):
|
| 58 |
+
prepend_scheme = "first"
|
| 59 |
+
else:
|
| 60 |
+
prepend_scheme = "never"
|
| 61 |
+
return prepend_scheme
|
| 62 |
+
|
| 63 |
+
|
| 64 |
+
def generate_merges(vocab, vocab_scores):
|
| 65 |
+
reverse = vocab_scores is not None
|
| 66 |
+
vocab_scores = dict(vocab_scores) if reverse else vocab
|
| 67 |
+
|
| 68 |
+
merges = []
|
| 69 |
+
for merge, piece_score in vocab_scores.items():
|
| 70 |
+
local = []
|
| 71 |
+
for index in range(1, len(merge)):
|
| 72 |
+
piece_l, piece_r = merge[:index], merge[index:]
|
| 73 |
+
if piece_l in vocab and piece_r in vocab:
|
| 74 |
+
local.append((piece_l, piece_r, piece_score))
|
| 75 |
+
local = sorted(local, key=lambda x: (vocab[x[0]], vocab[x[1]]))
|
| 76 |
+
merges.extend(local)
|
| 77 |
+
|
| 78 |
+
merges = sorted(merges, key=lambda val: (val[2], len(val[0]), len(val[1])), reverse=reverse)
|
| 79 |
+
merges = [(val[0], val[1]) for val in merges]
|
| 80 |
+
return merges
|
| 81 |
+
|
| 82 |
+
|
| 83 |
+
class SentencePieceExtractor:
|
| 84 |
+
"""
|
| 85 |
+
Extractor implementation for SentencePiece trained models. https://github.com/google/sentencepiece
|
| 86 |
+
"""
|
| 87 |
+
|
| 88 |
+
def __init__(self, model: str):
|
| 89 |
+
requires_backends(self, "sentencepiece")
|
| 90 |
+
from sentencepiece import SentencePieceProcessor
|
| 91 |
+
|
| 92 |
+
self.sp = SentencePieceProcessor()
|
| 93 |
+
self.sp.Load(model)
|
| 94 |
+
|
| 95 |
+
def extract(self, vocab_scores=None) -> tuple[dict[str, int], list[tuple]]:
|
| 96 |
+
"""
|
| 97 |
+
By default will return vocab and merges with respect to their order, by sending `vocab_scores` we're going to
|
| 98 |
+
order the merges with respect to the piece scores instead.
|
| 99 |
+
"""
|
| 100 |
+
sp = self.sp
|
| 101 |
+
vocab = {sp.id_to_piece(index): index for index in range(sp.GetPieceSize())}
|
| 102 |
+
|
| 103 |
+
merges = generate_merges(vocab, vocab_scores)
|
| 104 |
+
|
| 105 |
+
return vocab, merges
|
| 106 |
+
|
| 107 |
+
|
| 108 |
+
class GemmaSentencePieceExtractor(SentencePieceExtractor):
|
| 109 |
+
def extract(self, vocab_scores=None) -> tuple[dict[str, int], list[tuple]]:
|
| 110 |
+
"""
|
| 111 |
+
By default will return vocab and merges with respect to their order, by sending `vocab_scores` we're going to
|
| 112 |
+
order the merges with respect to the piece scores instead.
|
| 113 |
+
"""
|
| 114 |
+
sp = self.sp
|
| 115 |
+
vocab = {sp.id_to_piece(index): index for index in range(sp.GetPieceSize())}
|
| 116 |
+
|
| 117 |
+
# If "\t" is missing in the vocab, we have to do this to support merges
|
| 118 |
+
# "<0x09>" is the bytefallback for `\t`
|
| 119 |
+
if "\t" not in vocab:
|
| 120 |
+
vocab["\t"] = vocab.get("<0x09>")
|
| 121 |
+
merges = generate_merges(vocab, vocab_scores)
|
| 122 |
+
return vocab, merges
|
| 123 |
+
|
| 124 |
+
|
| 125 |
+
def check_number_comma(piece: str) -> bool:
|
| 126 |
+
return len(piece) < 2 or piece[-1] != "," or not piece[-2].isdigit()
|
| 127 |
+
|
| 128 |
+
|
| 129 |
+
class Converter:
|
| 130 |
+
def __init__(self, original_tokenizer):
|
| 131 |
+
self.original_tokenizer = original_tokenizer
|
| 132 |
+
|
| 133 |
+
def converted(self) -> Tokenizer:
|
| 134 |
+
raise NotImplementedError()
|
| 135 |
+
|
| 136 |
+
|
| 137 |
+
class BertConverter(Converter):
|
| 138 |
+
def converted(self) -> Tokenizer:
|
| 139 |
+
vocab = self.original_tokenizer.vocab
|
| 140 |
+
tokenizer = Tokenizer(WordPiece(vocab, unk_token=str(self.original_tokenizer.unk_token)))
|
| 141 |
+
|
| 142 |
+
tokenize_chinese_chars = False
|
| 143 |
+
strip_accents = False
|
| 144 |
+
do_lower_case = False
|
| 145 |
+
if hasattr(self.original_tokenizer, "basic_tokenizer"):
|
| 146 |
+
tokenize_chinese_chars = self.original_tokenizer.basic_tokenizer.tokenize_chinese_chars
|
| 147 |
+
strip_accents = self.original_tokenizer.basic_tokenizer.strip_accents
|
| 148 |
+
do_lower_case = self.original_tokenizer.basic_tokenizer.do_lower_case
|
| 149 |
+
|
| 150 |
+
tokenizer.normalizer = normalizers.BertNormalizer(
|
| 151 |
+
clean_text=True,
|
| 152 |
+
handle_chinese_chars=tokenize_chinese_chars,
|
| 153 |
+
strip_accents=strip_accents,
|
| 154 |
+
lowercase=do_lower_case,
|
| 155 |
+
)
|
| 156 |
+
tokenizer.pre_tokenizer = pre_tokenizers.BertPreTokenizer()
|
| 157 |
+
|
| 158 |
+
cls = str(self.original_tokenizer.cls_token)
|
| 159 |
+
sep = str(self.original_tokenizer.sep_token)
|
| 160 |
+
cls_token_id = self.original_tokenizer.cls_token_id
|
| 161 |
+
sep_token_id = self.original_tokenizer.sep_token_id
|
| 162 |
+
|
| 163 |
+
tokenizer.post_processor = processors.TemplateProcessing(
|
| 164 |
+
single=f"{cls}:0 $A:0 {sep}:0",
|
| 165 |
+
pair=f"{cls}:0 $A:0 {sep}:0 $B:1 {sep}:1",
|
| 166 |
+
special_tokens=[
|
| 167 |
+
(cls, cls_token_id),
|
| 168 |
+
(sep, sep_token_id),
|
| 169 |
+
],
|
| 170 |
+
)
|
| 171 |
+
tokenizer.decoder = decoders.WordPiece(prefix="##")
|
| 172 |
+
|
| 173 |
+
return tokenizer
|
| 174 |
+
|
| 175 |
+
|
| 176 |
+
class SplinterConverter(Converter):
|
| 177 |
+
def converted(self) -> Tokenizer:
|
| 178 |
+
vocab = self.original_tokenizer.vocab
|
| 179 |
+
tokenizer = Tokenizer(WordPiece(vocab, unk_token=str(self.original_tokenizer.unk_token)))
|
| 180 |
+
|
| 181 |
+
tokenize_chinese_chars = False
|
| 182 |
+
strip_accents = False
|
| 183 |
+
do_lower_case = False
|
| 184 |
+
if hasattr(self.original_tokenizer, "basic_tokenizer"):
|
| 185 |
+
tokenize_chinese_chars = self.original_tokenizer.basic_tokenizer.tokenize_chinese_chars
|
| 186 |
+
strip_accents = self.original_tokenizer.basic_tokenizer.strip_accents
|
| 187 |
+
do_lower_case = self.original_tokenizer.basic_tokenizer.do_lower_case
|
| 188 |
+
|
| 189 |
+
tokenizer.normalizer = normalizers.BertNormalizer(
|
| 190 |
+
clean_text=True,
|
| 191 |
+
handle_chinese_chars=tokenize_chinese_chars,
|
| 192 |
+
strip_accents=strip_accents,
|
| 193 |
+
lowercase=do_lower_case,
|
| 194 |
+
)
|
| 195 |
+
tokenizer.pre_tokenizer = pre_tokenizers.BertPreTokenizer()
|
| 196 |
+
|
| 197 |
+
cls = str(self.original_tokenizer.cls_token)
|
| 198 |
+
sep = str(self.original_tokenizer.sep_token)
|
| 199 |
+
question = str(self.original_tokenizer.question_token)
|
| 200 |
+
dot = "."
|
| 201 |
+
cls_token_id = self.original_tokenizer.cls_token_id
|
| 202 |
+
sep_token_id = self.original_tokenizer.sep_token_id
|
| 203 |
+
question_token_id = self.original_tokenizer.question_token_id
|
| 204 |
+
dot_token_id = self.original_tokenizer.convert_tokens_to_ids(".")
|
| 205 |
+
|
| 206 |
+
if self.original_tokenizer.padding_side == "right":
|
| 207 |
+
pair = f"{cls}:0 $A:0 {question} {dot} {sep}:0 $B:1 {sep}:1"
|
| 208 |
+
else:
|
| 209 |
+
pair = f"{cls}:0 $A:0 {sep}:0 $B:1 {question} {dot} {sep}:1"
|
| 210 |
+
|
| 211 |
+
tokenizer.post_processor = processors.TemplateProcessing(
|
| 212 |
+
single=f"{cls}:0 $A:0 {sep}:0",
|
| 213 |
+
pair=pair,
|
| 214 |
+
special_tokens=[
|
| 215 |
+
(cls, cls_token_id),
|
| 216 |
+
(sep, sep_token_id),
|
| 217 |
+
(question, question_token_id),
|
| 218 |
+
(dot, dot_token_id),
|
| 219 |
+
],
|
| 220 |
+
)
|
| 221 |
+
tokenizer.decoder = decoders.WordPiece(prefix="##")
|
| 222 |
+
|
| 223 |
+
return tokenizer
|
| 224 |
+
|
| 225 |
+
|
| 226 |
+
class FunnelConverter(Converter):
|
| 227 |
+
def converted(self) -> Tokenizer:
|
| 228 |
+
vocab = self.original_tokenizer.vocab
|
| 229 |
+
tokenizer = Tokenizer(WordPiece(vocab, unk_token=str(self.original_tokenizer.unk_token)))
|
| 230 |
+
|
| 231 |
+
tokenize_chinese_chars = False
|
| 232 |
+
strip_accents = False
|
| 233 |
+
do_lower_case = False
|
| 234 |
+
if hasattr(self.original_tokenizer, "basic_tokenizer"):
|
| 235 |
+
tokenize_chinese_chars = self.original_tokenizer.basic_tokenizer.tokenize_chinese_chars
|
| 236 |
+
strip_accents = self.original_tokenizer.basic_tokenizer.strip_accents
|
| 237 |
+
do_lower_case = self.original_tokenizer.basic_tokenizer.do_lower_case
|
| 238 |
+
|
| 239 |
+
tokenizer.normalizer = normalizers.BertNormalizer(
|
| 240 |
+
clean_text=True,
|
| 241 |
+
handle_chinese_chars=tokenize_chinese_chars,
|
| 242 |
+
strip_accents=strip_accents,
|
| 243 |
+
lowercase=do_lower_case,
|
| 244 |
+
)
|
| 245 |
+
tokenizer.pre_tokenizer = pre_tokenizers.BertPreTokenizer()
|
| 246 |
+
|
| 247 |
+
cls = str(self.original_tokenizer.cls_token)
|
| 248 |
+
sep = str(self.original_tokenizer.sep_token)
|
| 249 |
+
cls_token_id = self.original_tokenizer.cls_token_id
|
| 250 |
+
sep_token_id = self.original_tokenizer.sep_token_id
|
| 251 |
+
|
| 252 |
+
tokenizer.post_processor = processors.TemplateProcessing(
|
| 253 |
+
single=f"{cls}:2 $A:0 {sep}:0", # token_type_id is 2 for Funnel transformer
|
| 254 |
+
pair=f"{cls}:2 $A:0 {sep}:0 $B:1 {sep}:1",
|
| 255 |
+
special_tokens=[
|
| 256 |
+
(cls, cls_token_id),
|
| 257 |
+
(sep, sep_token_id),
|
| 258 |
+
],
|
| 259 |
+
)
|
| 260 |
+
tokenizer.decoder = decoders.WordPiece(prefix="##")
|
| 261 |
+
|
| 262 |
+
return tokenizer
|
| 263 |
+
|
| 264 |
+
|
| 265 |
+
class MPNetConverter(Converter):
|
| 266 |
+
def converted(self) -> Tokenizer:
|
| 267 |
+
vocab = self.original_tokenizer.vocab
|
| 268 |
+
tokenizer = Tokenizer(WordPiece(vocab, unk_token=str(self.original_tokenizer.unk_token)))
|
| 269 |
+
|
| 270 |
+
tokenize_chinese_chars = False
|
| 271 |
+
strip_accents = False
|
| 272 |
+
do_lower_case = False
|
| 273 |
+
if hasattr(self.original_tokenizer, "basic_tokenizer"):
|
| 274 |
+
tokenize_chinese_chars = self.original_tokenizer.basic_tokenizer.tokenize_chinese_chars
|
| 275 |
+
strip_accents = self.original_tokenizer.basic_tokenizer.strip_accents
|
| 276 |
+
do_lower_case = self.original_tokenizer.basic_tokenizer.do_lower_case
|
| 277 |
+
|
| 278 |
+
tokenizer.normalizer = normalizers.BertNormalizer(
|
| 279 |
+
clean_text=True,
|
| 280 |
+
handle_chinese_chars=tokenize_chinese_chars,
|
| 281 |
+
strip_accents=strip_accents,
|
| 282 |
+
lowercase=do_lower_case,
|
| 283 |
+
)
|
| 284 |
+
tokenizer.pre_tokenizer = pre_tokenizers.BertPreTokenizer()
|
| 285 |
+
|
| 286 |
+
cls = str(self.original_tokenizer.cls_token)
|
| 287 |
+
sep = str(self.original_tokenizer.sep_token)
|
| 288 |
+
cls_token_id = self.original_tokenizer.cls_token_id
|
| 289 |
+
sep_token_id = self.original_tokenizer.sep_token_id
|
| 290 |
+
|
| 291 |
+
tokenizer.post_processor = processors.TemplateProcessing(
|
| 292 |
+
single=f"{cls}:0 $A:0 {sep}:0",
|
| 293 |
+
pair=f"{cls}:0 $A:0 {sep}:0 {sep}:0 $B:1 {sep}:1", # MPNet uses two [SEP] tokens
|
| 294 |
+
special_tokens=[
|
| 295 |
+
(cls, cls_token_id),
|
| 296 |
+
(sep, sep_token_id),
|
| 297 |
+
],
|
| 298 |
+
)
|
| 299 |
+
tokenizer.decoder = decoders.WordPiece(prefix="##")
|
| 300 |
+
|
| 301 |
+
return tokenizer
|
| 302 |
+
|
| 303 |
+
|
| 304 |
+
class OpenAIGPTConverter(Converter):
|
| 305 |
+
def converted(self) -> Tokenizer:
|
| 306 |
+
vocab = self.original_tokenizer.encoder
|
| 307 |
+
merges = list(self.original_tokenizer.bpe_ranks.keys())
|
| 308 |
+
unk_token = self.original_tokenizer.unk_token
|
| 309 |
+
|
| 310 |
+
tokenizer = Tokenizer(
|
| 311 |
+
BPE(
|
| 312 |
+
vocab=vocab,
|
| 313 |
+
merges=merges,
|
| 314 |
+
dropout=None,
|
| 315 |
+
unk_token=str(unk_token),
|
| 316 |
+
end_of_word_suffix="</w>",
|
| 317 |
+
fuse_unk=False,
|
| 318 |
+
)
|
| 319 |
+
)
|
| 320 |
+
|
| 321 |
+
if tokenizer.token_to_id(str(unk_token)) is not None:
|
| 322 |
+
tokenizer.add_special_tokens([str(unk_token)])
|
| 323 |
+
|
| 324 |
+
tokenizer.normalizer = normalizers.BertNormalizer(lowercase=True)
|
| 325 |
+
tokenizer.pre_tokenizer = pre_tokenizers.BertPreTokenizer()
|
| 326 |
+
tokenizer.decoder = decoders.BPEDecoder(suffix="</w>")
|
| 327 |
+
|
| 328 |
+
return tokenizer
|
| 329 |
+
|
| 330 |
+
|
| 331 |
+
class GPT2Converter(Converter):
|
| 332 |
+
def converted(
|
| 333 |
+
self, vocab: Optional[dict[str, int]] = None, merges: Optional[list[tuple[str, str]]] = None
|
| 334 |
+
) -> Tokenizer:
|
| 335 |
+
if not vocab:
|
| 336 |
+
vocab = self.original_tokenizer.encoder
|
| 337 |
+
if not merges:
|
| 338 |
+
merges = list(self.original_tokenizer.bpe_ranks)
|
| 339 |
+
|
| 340 |
+
tokenizer = Tokenizer(
|
| 341 |
+
BPE(
|
| 342 |
+
vocab=vocab,
|
| 343 |
+
merges=merges,
|
| 344 |
+
dropout=None,
|
| 345 |
+
continuing_subword_prefix="",
|
| 346 |
+
end_of_word_suffix="",
|
| 347 |
+
fuse_unk=False,
|
| 348 |
+
)
|
| 349 |
+
)
|
| 350 |
+
|
| 351 |
+
add_prefix_space = getattr(self.original_tokenizer, "add_prefix_space", False)
|
| 352 |
+
tokenizer.pre_tokenizer = pre_tokenizers.ByteLevel(add_prefix_space=add_prefix_space)
|
| 353 |
+
tokenizer.decoder = decoders.ByteLevel()
|
| 354 |
+
if getattr(self.original_tokenizer, "add_bos_token", False):
|
| 355 |
+
bos = self.original_tokenizer.bos_token
|
| 356 |
+
bos_token_id = self.original_tokenizer.bos_token_id
|
| 357 |
+
tokenizer.post_processor = processors.TemplateProcessing(
|
| 358 |
+
single=f"{bos}:0 $A:0",
|
| 359 |
+
pair=f"{bos}:0 $A:0 $B:1",
|
| 360 |
+
special_tokens=[
|
| 361 |
+
(bos, bos_token_id),
|
| 362 |
+
],
|
| 363 |
+
)
|
| 364 |
+
else:
|
| 365 |
+
# XXX trim_offsets=False actually means this post_processor doesn't
|
| 366 |
+
# really do anything.
|
| 367 |
+
tokenizer.post_processor = processors.ByteLevel(trim_offsets=False)
|
| 368 |
+
return tokenizer
|
| 369 |
+
|
| 370 |
+
|
| 371 |
+
class HerbertConverter(Converter):
|
| 372 |
+
def converted(self) -> Tokenizer:
|
| 373 |
+
tokenizer_info_str = "#version:"
|
| 374 |
+
token_suffix = "</w>"
|
| 375 |
+
|
| 376 |
+
vocab = self.original_tokenizer.encoder
|
| 377 |
+
merges = list(self.original_tokenizer.bpe_ranks.keys())
|
| 378 |
+
if tokenizer_info_str in merges[0][0]:
|
| 379 |
+
merges = merges[1:]
|
| 380 |
+
|
| 381 |
+
tokenizer = Tokenizer(
|
| 382 |
+
BPE(
|
| 383 |
+
vocab,
|
| 384 |
+
merges,
|
| 385 |
+
dropout=None,
|
| 386 |
+
unk_token=self.original_tokenizer.unk_token,
|
| 387 |
+
end_of_word_suffix=token_suffix,
|
| 388 |
+
)
|
| 389 |
+
)
|
| 390 |
+
|
| 391 |
+
tokenizer.normalizer = normalizers.BertNormalizer(lowercase=False, strip_accents=False)
|
| 392 |
+
tokenizer.pre_tokenizer = pre_tokenizers.BertPreTokenizer()
|
| 393 |
+
tokenizer.decoder = decoders.BPEDecoder(suffix=token_suffix)
|
| 394 |
+
tokenizer.post_processor = processors.BertProcessing(
|
| 395 |
+
sep=(self.original_tokenizer.sep_token, self.original_tokenizer.sep_token_id),
|
| 396 |
+
cls=(self.original_tokenizer.cls_token, self.original_tokenizer.cls_token_id),
|
| 397 |
+
)
|
| 398 |
+
|
| 399 |
+
return tokenizer
|
| 400 |
+
|
| 401 |
+
|
| 402 |
+
class Qwen2Converter(Converter):
|
| 403 |
+
def converted(
|
| 404 |
+
self, vocab: Optional[dict[str, int]] = None, merges: Optional[list[tuple[str, str]]] = None
|
| 405 |
+
) -> Tokenizer:
|
| 406 |
+
if not vocab:
|
| 407 |
+
vocab = self.original_tokenizer.encoder
|
| 408 |
+
if not merges:
|
| 409 |
+
merges = list(self.original_tokenizer.bpe_ranks.keys())
|
| 410 |
+
|
| 411 |
+
tokenizer = Tokenizer(
|
| 412 |
+
BPE(
|
| 413 |
+
vocab=vocab,
|
| 414 |
+
merges=merges,
|
| 415 |
+
dropout=None,
|
| 416 |
+
unk_token=None,
|
| 417 |
+
continuing_subword_prefix="",
|
| 418 |
+
end_of_word_suffix="",
|
| 419 |
+
fuse_unk=False,
|
| 420 |
+
byte_fallback=False,
|
| 421 |
+
)
|
| 422 |
+
)
|
| 423 |
+
|
| 424 |
+
tokenizer.normalizer = normalizers.NFC()
|
| 425 |
+
|
| 426 |
+
tokenizer.pre_tokenizer = pre_tokenizers.Sequence(
|
| 427 |
+
[
|
| 428 |
+
pre_tokenizers.Split(
|
| 429 |
+
Regex(
|
| 430 |
+
r"""(?i:'s|'t|'re|'ve|'m|'ll|'d)|[^\r\n\p{L}\p{N}]?\p{L}+|\p{N}| ?[^\s\p{L}\p{N}]+[\r\n]*|\s*[\r\n]+|\s+(?!\S)|\s+"""
|
| 431 |
+
),
|
| 432 |
+
behavior="isolated",
|
| 433 |
+
invert=False,
|
| 434 |
+
),
|
| 435 |
+
pre_tokenizers.ByteLevel(
|
| 436 |
+
add_prefix_space=getattr(self.original_tokenizer, "add_prefix_space", False),
|
| 437 |
+
use_regex=False,
|
| 438 |
+
),
|
| 439 |
+
]
|
| 440 |
+
)
|
| 441 |
+
|
| 442 |
+
tokenizer.decoder = decoders.ByteLevel()
|
| 443 |
+
tokenizer.post_processor = processors.ByteLevel(trim_offsets=False)
|
| 444 |
+
|
| 445 |
+
return tokenizer
|
| 446 |
+
|
| 447 |
+
|
| 448 |
+
class RobertaConverter(Converter):
|
| 449 |
+
def converted(self) -> Tokenizer:
|
| 450 |
+
ot = self.original_tokenizer
|
| 451 |
+
vocab = ot.encoder
|
| 452 |
+
merges = list(ot.bpe_ranks.keys())
|
| 453 |
+
|
| 454 |
+
tokenizer = Tokenizer(
|
| 455 |
+
BPE(
|
| 456 |
+
vocab=vocab,
|
| 457 |
+
merges=merges,
|
| 458 |
+
dropout=None,
|
| 459 |
+
continuing_subword_prefix="",
|
| 460 |
+
end_of_word_suffix="",
|
| 461 |
+
fuse_unk=False,
|
| 462 |
+
)
|
| 463 |
+
)
|
| 464 |
+
|
| 465 |
+
tokenizer.pre_tokenizer = pre_tokenizers.ByteLevel(add_prefix_space=ot.add_prefix_space)
|
| 466 |
+
tokenizer.decoder = decoders.ByteLevel()
|
| 467 |
+
tokenizer.post_processor = processors.RobertaProcessing(
|
| 468 |
+
sep=(ot.sep_token, ot.sep_token_id),
|
| 469 |
+
cls=(ot.cls_token, ot.cls_token_id),
|
| 470 |
+
add_prefix_space=ot.add_prefix_space,
|
| 471 |
+
trim_offsets=True, # True by default on Roberta (historical)
|
| 472 |
+
)
|
| 473 |
+
|
| 474 |
+
return tokenizer
|
| 475 |
+
|
| 476 |
+
|
| 477 |
+
class RoFormerConverter(Converter):
|
| 478 |
+
def converted(self) -> Tokenizer:
|
| 479 |
+
from .models.roformer.tokenization_utils import JiebaPreTokenizer
|
| 480 |
+
|
| 481 |
+
vocab = self.original_tokenizer.vocab
|
| 482 |
+
tokenizer = Tokenizer(WordPiece(vocab, unk_token=str(self.original_tokenizer.unk_token)))
|
| 483 |
+
|
| 484 |
+
strip_accents = False
|
| 485 |
+
do_lower_case = False
|
| 486 |
+
if hasattr(self.original_tokenizer, "basic_tokenizer"):
|
| 487 |
+
strip_accents = self.original_tokenizer.basic_tokenizer.strip_accents
|
| 488 |
+
do_lower_case = self.original_tokenizer.basic_tokenizer.do_lower_case
|
| 489 |
+
|
| 490 |
+
tokenizer.normalizer = normalizers.BertNormalizer(
|
| 491 |
+
clean_text=True,
|
| 492 |
+
handle_chinese_chars=False,
|
| 493 |
+
strip_accents=strip_accents,
|
| 494 |
+
lowercase=do_lower_case,
|
| 495 |
+
)
|
| 496 |
+
tokenizer.pre_tokenizer = pre_tokenizers.PreTokenizer.custom(JiebaPreTokenizer(vocab))
|
| 497 |
+
|
| 498 |
+
cls = str(self.original_tokenizer.cls_token)
|
| 499 |
+
sep = str(self.original_tokenizer.sep_token)
|
| 500 |
+
cls_token_id = self.original_tokenizer.cls_token_id
|
| 501 |
+
sep_token_id = self.original_tokenizer.sep_token_id
|
| 502 |
+
|
| 503 |
+
tokenizer.post_processor = processors.TemplateProcessing(
|
| 504 |
+
single=f"{cls}:0 $A:0 {sep}:0",
|
| 505 |
+
pair=f"{cls}:0 $A:0 {sep}:0 $B:1 {sep}:1",
|
| 506 |
+
special_tokens=[
|
| 507 |
+
(cls, cls_token_id),
|
| 508 |
+
(sep, sep_token_id),
|
| 509 |
+
],
|
| 510 |
+
)
|
| 511 |
+
tokenizer.decoder = decoders.WordPiece(prefix="##")
|
| 512 |
+
|
| 513 |
+
return tokenizer
|
| 514 |
+
|
| 515 |
+
|
| 516 |
+
class DebertaConverter(Converter):
|
| 517 |
+
def converted(self) -> Tokenizer:
|
| 518 |
+
ot = self.original_tokenizer
|
| 519 |
+
vocab = ot.encoder
|
| 520 |
+
merges = list(ot.bpe_ranks.keys())
|
| 521 |
+
|
| 522 |
+
tokenizer = Tokenizer(
|
| 523 |
+
BPE(
|
| 524 |
+
vocab=vocab,
|
| 525 |
+
merges=merges,
|
| 526 |
+
dropout=None,
|
| 527 |
+
continuing_subword_prefix="",
|
| 528 |
+
end_of_word_suffix="",
|
| 529 |
+
fuse_unk=False,
|
| 530 |
+
)
|
| 531 |
+
)
|
| 532 |
+
|
| 533 |
+
tokenizer.pre_tokenizer = pre_tokenizers.ByteLevel(add_prefix_space=ot.add_prefix_space)
|
| 534 |
+
tokenizer.decoder = decoders.ByteLevel()
|
| 535 |
+
tokenizer.post_processor = processors.TemplateProcessing(
|
| 536 |
+
single="[CLS]:0 $A:0 [SEP]:0",
|
| 537 |
+
pair="[CLS]:0 $A:0 [SEP]:0 $B:1 [SEP]:1",
|
| 538 |
+
special_tokens=[
|
| 539 |
+
("[CLS]", self.original_tokenizer.convert_tokens_to_ids("[CLS]")),
|
| 540 |
+
("[SEP]", self.original_tokenizer.convert_tokens_to_ids("[SEP]")),
|
| 541 |
+
],
|
| 542 |
+
)
|
| 543 |
+
|
| 544 |
+
return tokenizer
|
| 545 |
+
|
| 546 |
+
|
| 547 |
+
class SpmConverter(Converter):
|
| 548 |
+
handle_byte_fallback = False
|
| 549 |
+
SpmExtractor = SentencePieceExtractor
|
| 550 |
+
special_tokens = {}
|
| 551 |
+
|
| 552 |
+
def __init__(self, *args):
|
| 553 |
+
requires_backends(self, "protobuf")
|
| 554 |
+
|
| 555 |
+
super().__init__(*args)
|
| 556 |
+
|
| 557 |
+
# from .utils import sentencepiece_model_pb2 as model_pb2
|
| 558 |
+
model_pb2 = import_protobuf()
|
| 559 |
+
|
| 560 |
+
m = model_pb2.ModelProto()
|
| 561 |
+
with open(self.original_tokenizer.vocab_file, "rb") as f:
|
| 562 |
+
m.ParseFromString(f.read())
|
| 563 |
+
self.proto = m
|
| 564 |
+
|
| 565 |
+
if self.proto.trainer_spec.byte_fallback and not self.handle_byte_fallback:
|
| 566 |
+
warnings.warn(
|
| 567 |
+
"The sentencepiece tokenizer that you are converting to a fast tokenizer uses the byte fallback option"
|
| 568 |
+
" which is not implemented in the fast tokenizers. In practice this means that the fast version of the"
|
| 569 |
+
" tokenizer can produce unknown tokens whereas the sentencepiece version would have converted these "
|
| 570 |
+
"unknown tokens into a sequence of byte tokens matching the original piece of text."
|
| 571 |
+
)
|
| 572 |
+
|
| 573 |
+
def vocab(self, proto):
|
| 574 |
+
return [(piece.piece, piece.score) for piece in proto.pieces]
|
| 575 |
+
|
| 576 |
+
def unk_id(self, proto):
|
| 577 |
+
return proto.trainer_spec.unk_id
|
| 578 |
+
|
| 579 |
+
def tokenizer(self, proto):
|
| 580 |
+
model_type = proto.trainer_spec.model_type
|
| 581 |
+
vocab_scores = self.vocab(proto)
|
| 582 |
+
|
| 583 |
+
if model_type == 1:
|
| 584 |
+
tokenizer = Tokenizer(
|
| 585 |
+
Unigram(
|
| 586 |
+
vocab_scores,
|
| 587 |
+
unk_id=self.unk_id(proto),
|
| 588 |
+
byte_fallback=self.handle_byte_fallback,
|
| 589 |
+
)
|
| 590 |
+
)
|
| 591 |
+
|
| 592 |
+
elif model_type == 2:
|
| 593 |
+
_, merges = self.SpmExtractor(self.original_tokenizer.vocab_file).extract(vocab_scores)
|
| 594 |
+
bpe_vocab = {word: i for i, (word, score) in enumerate(vocab_scores)}
|
| 595 |
+
tokenizer = Tokenizer(
|
| 596 |
+
BPE(
|
| 597 |
+
bpe_vocab,
|
| 598 |
+
merges,
|
| 599 |
+
unk_token=proto.trainer_spec.unk_piece,
|
| 600 |
+
fuse_unk=True,
|
| 601 |
+
byte_fallback=self.handle_byte_fallback,
|
| 602 |
+
dropout=None,
|
| 603 |
+
)
|
| 604 |
+
)
|
| 605 |
+
|
| 606 |
+
else:
|
| 607 |
+
raise Exception(
|
| 608 |
+
"You're trying to run a `Unigram` model but you're file was trained with a different algorithm"
|
| 609 |
+
)
|
| 610 |
+
|
| 611 |
+
# control tokens are special
|
| 612 |
+
# user defined symbols are not
|
| 613 |
+
# both user and control tokens are AddedTokens
|
| 614 |
+
# Add user defined symbols (type == 4) from sentencepiece (https://github.com/google/sentencepiece/blob/6225e08edb2577757163b3f5dbba4c0b670ef445/src/sentencepiece_model.proto#L299C29-L299C33)
|
| 615 |
+
spm_added_tokens = [
|
| 616 |
+
(id, p.piece, p.type == 3 or p.piece in self.special_tokens)
|
| 617 |
+
for id, p in enumerate(proto.pieces)
|
| 618 |
+
if p.type in [3, 4]
|
| 619 |
+
]
|
| 620 |
+
tokenizer.add_tokens(
|
| 621 |
+
[
|
| 622 |
+
AddedToken(token, normalized=False, special=special)
|
| 623 |
+
for id, token, special in sorted(spm_added_tokens, key=lambda x: x[0])
|
| 624 |
+
]
|
| 625 |
+
)
|
| 626 |
+
|
| 627 |
+
return tokenizer
|
| 628 |
+
|
| 629 |
+
def normalizer(self, proto):
|
| 630 |
+
precompiled_charsmap = proto.normalizer_spec.precompiled_charsmap
|
| 631 |
+
_normalizers = [
|
| 632 |
+
normalizers.Strip(left=False, right=True), # stripping is important
|
| 633 |
+
normalizers.Replace(Regex(" {2,}"), "▁"),
|
| 634 |
+
]
|
| 635 |
+
if not precompiled_charsmap:
|
| 636 |
+
return normalizers.Sequence(_normalizers)
|
| 637 |
+
else:
|
| 638 |
+
return normalizers.Sequence([normalizers.Precompiled(precompiled_charsmap)] + _normalizers)
|
| 639 |
+
|
| 640 |
+
def pre_tokenizer(self, replacement, add_prefix_space):
|
| 641 |
+
prepend_scheme = _get_prepend_scheme(add_prefix_space, self.original_tokenizer)
|
| 642 |
+
return pre_tokenizers.Metaspace(replacement=replacement, prepend_scheme=prepend_scheme)
|
| 643 |
+
|
| 644 |
+
def post_processor(self):
|
| 645 |
+
return None
|
| 646 |
+
|
| 647 |
+
def decoder(self, replacement, add_prefix_space):
|
| 648 |
+
prepend_scheme = _get_prepend_scheme(add_prefix_space, self.original_tokenizer)
|
| 649 |
+
return decoders.Metaspace(replacement=replacement, prepend_scheme=prepend_scheme)
|
| 650 |
+
|
| 651 |
+
def converted(self) -> Tokenizer:
|
| 652 |
+
tokenizer = self.tokenizer(self.proto)
|
| 653 |
+
|
| 654 |
+
# Tokenizer assemble
|
| 655 |
+
normalizer = self.normalizer(self.proto)
|
| 656 |
+
if normalizer is not None:
|
| 657 |
+
tokenizer.normalizer = normalizer
|
| 658 |
+
|
| 659 |
+
replacement = "▁"
|
| 660 |
+
add_prefix_space = True
|
| 661 |
+
if hasattr(self.original_tokenizer, "add_prefix_space"):
|
| 662 |
+
add_prefix_space = self.original_tokenizer.add_prefix_space
|
| 663 |
+
|
| 664 |
+
pre_tokenizer = self.pre_tokenizer(replacement, add_prefix_space)
|
| 665 |
+
if pre_tokenizer is not None:
|
| 666 |
+
tokenizer.pre_tokenizer = pre_tokenizer
|
| 667 |
+
|
| 668 |
+
tokenizer.decoder = self.decoder(replacement, add_prefix_space)
|
| 669 |
+
post_processor = self.post_processor()
|
| 670 |
+
if post_processor:
|
| 671 |
+
tokenizer.post_processor = post_processor
|
| 672 |
+
|
| 673 |
+
return tokenizer
|
| 674 |
+
|
| 675 |
+
|
| 676 |
+
class AlbertConverter(SpmConverter):
|
| 677 |
+
def vocab(self, proto):
|
| 678 |
+
return [
|
| 679 |
+
(piece.piece, piece.score) if check_number_comma(piece.piece) else (piece.piece, piece.score - 100)
|
| 680 |
+
for piece in proto.pieces
|
| 681 |
+
]
|
| 682 |
+
|
| 683 |
+
def normalizer(self, proto):
|
| 684 |
+
list_normalizers = [
|
| 685 |
+
normalizers.Replace("``", '"'),
|
| 686 |
+
normalizers.Replace("''", '"'),
|
| 687 |
+
]
|
| 688 |
+
if not self.original_tokenizer.keep_accents:
|
| 689 |
+
list_normalizers.append(normalizers.NFKD())
|
| 690 |
+
list_normalizers.append(normalizers.StripAccents())
|
| 691 |
+
if self.original_tokenizer.do_lower_case:
|
| 692 |
+
list_normalizers.append(normalizers.Lowercase())
|
| 693 |
+
|
| 694 |
+
precompiled_charsmap = proto.normalizer_spec.precompiled_charsmap
|
| 695 |
+
|
| 696 |
+
if precompiled_charsmap:
|
| 697 |
+
list_normalizers.append(normalizers.Precompiled(precompiled_charsmap))
|
| 698 |
+
|
| 699 |
+
list_normalizers.append(normalizers.Replace(Regex(" {2,}"), " "))
|
| 700 |
+
return normalizers.Sequence(list_normalizers)
|
| 701 |
+
|
| 702 |
+
def post_processor(self):
|
| 703 |
+
return processors.TemplateProcessing(
|
| 704 |
+
single="[CLS]:0 $A:0 [SEP]:0",
|
| 705 |
+
pair="[CLS]:0 $A:0 [SEP]:0 $B:1 [SEP]:1",
|
| 706 |
+
special_tokens=[
|
| 707 |
+
("[CLS]", self.original_tokenizer.convert_tokens_to_ids("[CLS]")),
|
| 708 |
+
("[SEP]", self.original_tokenizer.convert_tokens_to_ids("[SEP]")),
|
| 709 |
+
],
|
| 710 |
+
)
|
| 711 |
+
|
| 712 |
+
|
| 713 |
+
class BarthezConverter(SpmConverter):
|
| 714 |
+
def unk_id(self, proto):
|
| 715 |
+
unk_id = 3
|
| 716 |
+
return unk_id
|
| 717 |
+
|
| 718 |
+
def post_processor(self):
|
| 719 |
+
return processors.TemplateProcessing(
|
| 720 |
+
single="<s> $A </s>",
|
| 721 |
+
pair="<s> $A </s> </s> $B </s>",
|
| 722 |
+
special_tokens=[
|
| 723 |
+
("<s>", self.original_tokenizer.convert_tokens_to_ids("<s>")),
|
| 724 |
+
("</s>", self.original_tokenizer.convert_tokens_to_ids("</s>")),
|
| 725 |
+
],
|
| 726 |
+
)
|
| 727 |
+
|
| 728 |
+
|
| 729 |
+
class CamembertConverter(SpmConverter):
|
| 730 |
+
def vocab(self, proto):
|
| 731 |
+
vocab = [
|
| 732 |
+
("<s>NOTUSED", 0.0),
|
| 733 |
+
("<pad>", 0.0),
|
| 734 |
+
("</s>NOTUSED", 0.0),
|
| 735 |
+
("<unk>", 0.0),
|
| 736 |
+
("<unk>NOTUSED", -100),
|
| 737 |
+
]
|
| 738 |
+
# We down-grade the original SentencePiece by -100 to avoid using it and use our added token instead
|
| 739 |
+
vocab += [(piece.piece, piece.score) for piece in proto.pieces[1:]]
|
| 740 |
+
vocab += [("<mask>", 0.0)]
|
| 741 |
+
return vocab
|
| 742 |
+
|
| 743 |
+
def unk_id(self, proto):
|
| 744 |
+
# See vocab unk position
|
| 745 |
+
return 3
|
| 746 |
+
|
| 747 |
+
def post_processor(self):
|
| 748 |
+
return processors.TemplateProcessing(
|
| 749 |
+
single="<s> $A </s>",
|
| 750 |
+
pair="<s> $A </s> </s> $B </s>",
|
| 751 |
+
special_tokens=[
|
| 752 |
+
("<s>", self.original_tokenizer.convert_tokens_to_ids("<s>")),
|
| 753 |
+
("</s>", self.original_tokenizer.convert_tokens_to_ids("</s>")),
|
| 754 |
+
],
|
| 755 |
+
)
|
| 756 |
+
|
| 757 |
+
|
| 758 |
+
class DebertaV2Converter(SpmConverter):
|
| 759 |
+
def pre_tokenizer(self, replacement, add_prefix_space):
|
| 760 |
+
list_pretokenizers = []
|
| 761 |
+
if self.original_tokenizer.split_by_punct:
|
| 762 |
+
list_pretokenizers.append(pre_tokenizers.Punctuation(behavior="isolated"))
|
| 763 |
+
prepend_scheme = _get_prepend_scheme(add_prefix_space, self.original_tokenizer)
|
| 764 |
+
list_pretokenizers.append(pre_tokenizers.Metaspace(replacement=replacement, prepend_scheme=prepend_scheme))
|
| 765 |
+
return pre_tokenizers.Sequence(list_pretokenizers)
|
| 766 |
+
|
| 767 |
+
def normalizer(self, proto):
|
| 768 |
+
list_normalizers = []
|
| 769 |
+
if self.original_tokenizer.do_lower_case:
|
| 770 |
+
list_normalizers.append(normalizers.Lowercase())
|
| 771 |
+
list_normalizers.append(normalizers.Strip())
|
| 772 |
+
|
| 773 |
+
precompiled_charsmap = proto.normalizer_spec.precompiled_charsmap
|
| 774 |
+
if precompiled_charsmap:
|
| 775 |
+
list_normalizers.append(normalizers.Precompiled(precompiled_charsmap))
|
| 776 |
+
list_normalizers.append(normalizers.Replace(Regex(" {2,}"), " "))
|
| 777 |
+
|
| 778 |
+
return normalizers.Sequence(list_normalizers)
|
| 779 |
+
|
| 780 |
+
def post_processor(self):
|
| 781 |
+
return processors.TemplateProcessing(
|
| 782 |
+
single="[CLS]:0 $A:0 [SEP]:0",
|
| 783 |
+
pair="[CLS]:0 $A:0 [SEP]:0 $B:1 [SEP]:1",
|
| 784 |
+
special_tokens=[
|
| 785 |
+
("[CLS]", self.original_tokenizer.convert_tokens_to_ids("[CLS]")),
|
| 786 |
+
("[SEP]", self.original_tokenizer.convert_tokens_to_ids("[SEP]")),
|
| 787 |
+
],
|
| 788 |
+
)
|
| 789 |
+
|
| 790 |
+
|
| 791 |
+
class MBartConverter(SpmConverter):
|
| 792 |
+
def vocab(self, proto):
|
| 793 |
+
vocab = [
|
| 794 |
+
("<s>", 0.0),
|
| 795 |
+
("<pad>", 0.0),
|
| 796 |
+
("</s>", 0.0),
|
| 797 |
+
("<unk>", 0.0),
|
| 798 |
+
]
|
| 799 |
+
vocab += [(piece.piece, piece.score) for piece in proto.pieces[3:]]
|
| 800 |
+
vocab += [
|
| 801 |
+
("ar_AR", 0.0),
|
| 802 |
+
("cs_CZ", 0.0),
|
| 803 |
+
("de_DE", 0.0),
|
| 804 |
+
("en_XX", 0.0),
|
| 805 |
+
("es_XX", 0.0),
|
| 806 |
+
("et_EE", 0.0),
|
| 807 |
+
("fi_FI", 0.0),
|
| 808 |
+
("fr_XX", 0.0),
|
| 809 |
+
("gu_IN", 0.0),
|
| 810 |
+
("hi_IN", 0.0),
|
| 811 |
+
("it_IT", 0.0),
|
| 812 |
+
("ja_XX", 0.0),
|
| 813 |
+
("kk_KZ", 0.0),
|
| 814 |
+
("ko_KR", 0.0),
|
| 815 |
+
("lt_LT", 0.0),
|
| 816 |
+
("lv_LV", 0.0),
|
| 817 |
+
("my_MM", 0.0),
|
| 818 |
+
("ne_NP", 0.0),
|
| 819 |
+
("nl_XX", 0.0),
|
| 820 |
+
("ro_RO", 0.0),
|
| 821 |
+
("ru_RU", 0.0),
|
| 822 |
+
("si_LK", 0.0),
|
| 823 |
+
("tr_TR", 0.0),
|
| 824 |
+
("vi_VN", 0.0),
|
| 825 |
+
("zh_CN", 0.0),
|
| 826 |
+
]
|
| 827 |
+
vocab += [("<mask>", 0.0)]
|
| 828 |
+
return vocab
|
| 829 |
+
|
| 830 |
+
def unk_id(self, proto):
|
| 831 |
+
return 3
|
| 832 |
+
|
| 833 |
+
def post_processor(self):
|
| 834 |
+
return processors.TemplateProcessing(
|
| 835 |
+
single="$A </s> en_XX",
|
| 836 |
+
pair="$A $B </s> en_XX",
|
| 837 |
+
special_tokens=[
|
| 838 |
+
("en_XX", self.original_tokenizer.convert_tokens_to_ids("en_XX")),
|
| 839 |
+
("</s>", self.original_tokenizer.convert_tokens_to_ids("</s>")),
|
| 840 |
+
],
|
| 841 |
+
)
|
| 842 |
+
|
| 843 |
+
|
| 844 |
+
class MBart50Converter(SpmConverter):
|
| 845 |
+
def vocab(self, proto):
|
| 846 |
+
vocab = [
|
| 847 |
+
("<s>", 0.0),
|
| 848 |
+
("<pad>", 0.0),
|
| 849 |
+
("</s>", 0.0),
|
| 850 |
+
("<unk>", 0.0),
|
| 851 |
+
]
|
| 852 |
+
vocab += [(piece.piece, piece.score) for piece in proto.pieces[3:]]
|
| 853 |
+
vocab += [("ar_AR", 0.0), ("cs_CZ", 0.0), ("de_DE", 0.0), ("en_XX", 0.0), ("es_XX", 0.0), ("et_EE", 0.0), ("fi_FI", 0.0), ("fr_XX", 0.0), ("gu_IN", 0.0), ("hi_IN", 0.0), ("it_IT", 0.0), ("ja_XX", 0.0), ("kk_KZ", 0.0), ("ko_KR", 0.0), ("lt_LT", 0.0), ("lv_LV", 0.0), ("my_MM", 0.0), ("ne_NP", 0.0), ("nl_XX", 0.0), ("ro_RO", 0.0), ("ru_RU", 0.0), ("si_LK", 0.0), ("tr_TR", 0.0), ("vi_VN", 0.0), ("zh_CN", 0.0), ("af_ZA", 0.0), ("az_AZ", 0.0), ("bn_IN", 0.0), ("fa_IR", 0.0), ("he_IL", 0.0), ("hr_HR", 0.0), ("id_ID", 0.0), ("ka_GE", 0.0), ("km_KH", 0.0), ("mk_MK", 0.0), ("ml_IN", 0.0), ("mn_MN", 0.0), ("mr_IN", 0.0), ("pl_PL", 0.0), ("ps_AF", 0.0), ("pt_XX", 0.0), ("sv_SE", 0.0), ("sw_KE", 0.0), ("ta_IN", 0.0), ("te_IN", 0.0), ("th_TH", 0.0), ("tl_XX", 0.0), ("uk_UA", 0.0), ("ur_PK", 0.0), ("xh_ZA", 0.0), ("gl_ES", 0.0), ("sl_SI", 0.0)] # fmt: skip
|
| 854 |
+
vocab += [("<mask>", 0.0)]
|
| 855 |
+
return vocab
|
| 856 |
+
|
| 857 |
+
def unk_id(self, proto):
|
| 858 |
+
return 3
|
| 859 |
+
|
| 860 |
+
def post_processor(self):
|
| 861 |
+
return processors.TemplateProcessing(
|
| 862 |
+
single="en_XX $A </s>",
|
| 863 |
+
pair="en_XX $A $B </s>",
|
| 864 |
+
special_tokens=[
|
| 865 |
+
("en_XX", self.original_tokenizer.convert_tokens_to_ids("en_XX")),
|
| 866 |
+
("</s>", self.original_tokenizer.convert_tokens_to_ids("</s>")),
|
| 867 |
+
],
|
| 868 |
+
)
|
| 869 |
+
|
| 870 |
+
|
| 871 |
+
class NllbConverter(SpmConverter):
|
| 872 |
+
def vocab(self, proto):
|
| 873 |
+
vocab = [
|
| 874 |
+
("<s>", 0.0),
|
| 875 |
+
("<pad>", 0.0),
|
| 876 |
+
("</s>", 0.0),
|
| 877 |
+
("<unk>", 0.0),
|
| 878 |
+
]
|
| 879 |
+
vocab += [(piece.piece, piece.score) for piece in proto.pieces[3:]]
|
| 880 |
+
return vocab
|
| 881 |
+
|
| 882 |
+
def unk_id(self, proto):
|
| 883 |
+
return 3
|
| 884 |
+
|
| 885 |
+
def post_processor(self):
|
| 886 |
+
return processors.TemplateProcessing(
|
| 887 |
+
single="eng_Latn $A </s>",
|
| 888 |
+
pair="eng_Latn $A $B </s>",
|
| 889 |
+
special_tokens=[
|
| 890 |
+
("eng_Latn", self.original_tokenizer.convert_tokens_to_ids("eng_Latn")),
|
| 891 |
+
("</s>", self.original_tokenizer.convert_tokens_to_ids("</s>")),
|
| 892 |
+
],
|
| 893 |
+
)
|
| 894 |
+
|
| 895 |
+
|
| 896 |
+
class SeamlessM4TConverter(SpmConverter):
|
| 897 |
+
def vocab(self, proto):
|
| 898 |
+
vocab = [
|
| 899 |
+
("<pad>", 0.0),
|
| 900 |
+
("<unk>", 0.0),
|
| 901 |
+
("<s>", 0.0),
|
| 902 |
+
("</s>", 0.0),
|
| 903 |
+
]
|
| 904 |
+
vocab += [(piece.piece, piece.score) for piece in proto.pieces[3:]]
|
| 905 |
+
return vocab
|
| 906 |
+
|
| 907 |
+
def unk_id(self, proto):
|
| 908 |
+
return self.original_tokenizer.unk_token_id
|
| 909 |
+
|
| 910 |
+
def post_processor(self):
|
| 911 |
+
return processors.TemplateProcessing(
|
| 912 |
+
single="__eng__ $A </s>",
|
| 913 |
+
pair="__eng__ $A $B </s>",
|
| 914 |
+
special_tokens=[
|
| 915 |
+
("__eng__", self.original_tokenizer.convert_tokens_to_ids("__eng__")),
|
| 916 |
+
("</s>", self.original_tokenizer.convert_tokens_to_ids("</s>")),
|
| 917 |
+
],
|
| 918 |
+
)
|
| 919 |
+
|
| 920 |
+
|
| 921 |
+
class XLMRobertaConverter(SpmConverter):
|
| 922 |
+
def vocab(self, proto):
|
| 923 |
+
vocab = [
|
| 924 |
+
("<s>", 0.0),
|
| 925 |
+
("<pad>", 0.0),
|
| 926 |
+
("</s>", 0.0),
|
| 927 |
+
("<unk>", 0.0),
|
| 928 |
+
]
|
| 929 |
+
vocab += [(piece.piece, piece.score) for piece in proto.pieces[3:]]
|
| 930 |
+
vocab += [("<mask>", 0.0)]
|
| 931 |
+
return vocab
|
| 932 |
+
|
| 933 |
+
def unk_id(self, proto):
|
| 934 |
+
unk_id = 3
|
| 935 |
+
return unk_id
|
| 936 |
+
|
| 937 |
+
def post_processor(self):
|
| 938 |
+
return processors.TemplateProcessing(
|
| 939 |
+
single="<s> $A </s>",
|
| 940 |
+
pair="<s> $A </s> </s> $B </s>",
|
| 941 |
+
special_tokens=[
|
| 942 |
+
("<s>", self.original_tokenizer.convert_tokens_to_ids("<s>")),
|
| 943 |
+
("</s>", self.original_tokenizer.convert_tokens_to_ids("</s>")),
|
| 944 |
+
],
|
| 945 |
+
)
|
| 946 |
+
|
| 947 |
+
|
| 948 |
+
class XLNetConverter(SpmConverter):
|
| 949 |
+
def vocab(self, proto):
|
| 950 |
+
return [
|
| 951 |
+
(piece.piece, piece.score) if check_number_comma(piece.piece) else (piece.piece, piece.score - 100)
|
| 952 |
+
for piece in proto.pieces
|
| 953 |
+
]
|
| 954 |
+
|
| 955 |
+
def normalizer(self, proto):
|
| 956 |
+
list_normalizers = [
|
| 957 |
+
normalizers.Replace("``", '"'),
|
| 958 |
+
normalizers.Replace("''", '"'),
|
| 959 |
+
]
|
| 960 |
+
if not self.original_tokenizer.keep_accents:
|
| 961 |
+
list_normalizers.append(normalizers.NFKD())
|
| 962 |
+
list_normalizers.append(normalizers.StripAccents())
|
| 963 |
+
if self.original_tokenizer.do_lower_case:
|
| 964 |
+
list_normalizers.append(normalizers.Lowercase())
|
| 965 |
+
|
| 966 |
+
precompiled_charsmap = proto.normalizer_spec.precompiled_charsmap
|
| 967 |
+
|
| 968 |
+
if precompiled_charsmap:
|
| 969 |
+
list_normalizers.append(normalizers.Precompiled(precompiled_charsmap))
|
| 970 |
+
|
| 971 |
+
list_normalizers.append(normalizers.Replace(Regex(" {2,}"), " "))
|
| 972 |
+
return normalizers.Sequence(list_normalizers)
|
| 973 |
+
|
| 974 |
+
def post_processor(self):
|
| 975 |
+
return processors.TemplateProcessing(
|
| 976 |
+
single="$A:0 <sep>:0 <cls>:2",
|
| 977 |
+
pair="$A:0 <sep>:0 $B:1 <sep>:1 <cls>:2",
|
| 978 |
+
special_tokens=[
|
| 979 |
+
("<sep>", self.original_tokenizer.convert_tokens_to_ids("<sep>")),
|
| 980 |
+
("<cls>", self.original_tokenizer.convert_tokens_to_ids("<cls>")),
|
| 981 |
+
],
|
| 982 |
+
)
|
| 983 |
+
|
| 984 |
+
|
| 985 |
+
class ReformerConverter(SpmConverter):
|
| 986 |
+
pass
|
| 987 |
+
|
| 988 |
+
|
| 989 |
+
class RemBertConverter(SpmConverter):
|
| 990 |
+
# Inspired from AlbertConverter
|
| 991 |
+
def normalizer(self, proto):
|
| 992 |
+
list_normalizers = [
|
| 993 |
+
normalizers.Replace("``", '"'),
|
| 994 |
+
normalizers.Replace("''", '"'),
|
| 995 |
+
normalizers.Replace(Regex(" {2,}"), " "),
|
| 996 |
+
]
|
| 997 |
+
if not self.original_tokenizer.keep_accents:
|
| 998 |
+
list_normalizers.append(normalizers.NFKD())
|
| 999 |
+
list_normalizers.append(normalizers.StripAccents())
|
| 1000 |
+
if self.original_tokenizer.do_lower_case:
|
| 1001 |
+
list_normalizers.append(normalizers.Lowercase())
|
| 1002 |
+
|
| 1003 |
+
precompiled_charsmap = proto.normalizer_spec.precompiled_charsmap
|
| 1004 |
+
|
| 1005 |
+
if precompiled_charsmap:
|
| 1006 |
+
list_normalizers.append(normalizers.Precompiled(precompiled_charsmap))
|
| 1007 |
+
|
| 1008 |
+
return normalizers.Sequence(list_normalizers)
|
| 1009 |
+
|
| 1010 |
+
def post_processor(self):
|
| 1011 |
+
return processors.TemplateProcessing(
|
| 1012 |
+
single="[CLS]:0 $A:0 [SEP]:0",
|
| 1013 |
+
pair="[CLS]:0 $A:0 [SEP]:0 $B:1 [SEP]:1",
|
| 1014 |
+
special_tokens=[
|
| 1015 |
+
("[CLS]", self.original_tokenizer.convert_tokens_to_ids("[CLS]")),
|
| 1016 |
+
("[SEP]", self.original_tokenizer.convert_tokens_to_ids("[SEP]")),
|
| 1017 |
+
],
|
| 1018 |
+
)
|
| 1019 |
+
|
| 1020 |
+
|
| 1021 |
+
class BertGenerationConverter(SpmConverter):
|
| 1022 |
+
pass
|
| 1023 |
+
|
| 1024 |
+
|
| 1025 |
+
class PegasusConverter(SpmConverter):
|
| 1026 |
+
def vocab(self, proto):
|
| 1027 |
+
vocab = [
|
| 1028 |
+
(self.original_tokenizer.pad_token, 0.0),
|
| 1029 |
+
(self.original_tokenizer.eos_token, 0.0),
|
| 1030 |
+
]
|
| 1031 |
+
|
| 1032 |
+
if self.original_tokenizer.mask_token_sent is not None:
|
| 1033 |
+
vocab += [(self.original_tokenizer.mask_token_sent, 0.0)]
|
| 1034 |
+
|
| 1035 |
+
if (
|
| 1036 |
+
self.original_tokenizer.mask_token is not None
|
| 1037 |
+
and self.original_tokenizer.mask_token_id < self.original_tokenizer.offset
|
| 1038 |
+
):
|
| 1039 |
+
vocab += [(self.original_tokenizer.mask_token, 0.0)]
|
| 1040 |
+
|
| 1041 |
+
vocab += [(f"<unk_{i}>", -100.0) for i in range(2, self.original_tokenizer.offset)]
|
| 1042 |
+
vocab += [(piece.piece, piece.score) for piece in proto.pieces[2:]]
|
| 1043 |
+
return vocab
|
| 1044 |
+
|
| 1045 |
+
def unk_id(self, proto):
|
| 1046 |
+
return proto.trainer_spec.unk_id + self.original_tokenizer.offset
|
| 1047 |
+
|
| 1048 |
+
def pre_tokenizer(self, replacement, add_prefix_space):
|
| 1049 |
+
prepend_scheme = _get_prepend_scheme(add_prefix_space, self.original_tokenizer)
|
| 1050 |
+
return pre_tokenizers.Sequence(
|
| 1051 |
+
[
|
| 1052 |
+
pre_tokenizers.WhitespaceSplit(),
|
| 1053 |
+
pre_tokenizers.Metaspace(replacement=replacement, prepend_scheme=prepend_scheme),
|
| 1054 |
+
]
|
| 1055 |
+
)
|
| 1056 |
+
|
| 1057 |
+
def post_processor(self):
|
| 1058 |
+
eos = self.original_tokenizer.eos_token
|
| 1059 |
+
special_tokens = [
|
| 1060 |
+
(eos, self.original_tokenizer.eos_token_id),
|
| 1061 |
+
]
|
| 1062 |
+
return processors.TemplateProcessing(single=["$A", eos], pair=["$A", "$B", eos], special_tokens=special_tokens)
|
| 1063 |
+
|
| 1064 |
+
|
| 1065 |
+
class T5Converter(SpmConverter):
|
| 1066 |
+
def vocab(self, proto):
|
| 1067 |
+
num_extra_ids = self.original_tokenizer._extra_ids
|
| 1068 |
+
vocab = [(piece.piece, piece.score) for piece in proto.pieces]
|
| 1069 |
+
vocab += [(f"<extra_id_{i}>", 0.0) for i in range(num_extra_ids - 1, -1, -1)]
|
| 1070 |
+
return vocab
|
| 1071 |
+
|
| 1072 |
+
def post_processor(self):
|
| 1073 |
+
return processors.TemplateProcessing(
|
| 1074 |
+
single=["$A", "</s>"],
|
| 1075 |
+
pair=["$A", "</s>", "$B", "</s>"],
|
| 1076 |
+
special_tokens=[
|
| 1077 |
+
("</s>", self.original_tokenizer.convert_tokens_to_ids("</s>")),
|
| 1078 |
+
],
|
| 1079 |
+
)
|
| 1080 |
+
|
| 1081 |
+
|
| 1082 |
+
class UdopConverter(SpmConverter):
|
| 1083 |
+
def post_processor(self):
|
| 1084 |
+
return processors.TemplateProcessing(
|
| 1085 |
+
single=["$A", "</s>"],
|
| 1086 |
+
pair=["$A", "</s>", "$B", "</s>"],
|
| 1087 |
+
special_tokens=[
|
| 1088 |
+
("</s>", self.original_tokenizer.convert_tokens_to_ids("</s>")),
|
| 1089 |
+
],
|
| 1090 |
+
)
|
| 1091 |
+
|
| 1092 |
+
|
| 1093 |
+
class WhisperConverter(Converter):
|
| 1094 |
+
def converted(self) -> Tokenizer:
|
| 1095 |
+
vocab = self.original_tokenizer.encoder
|
| 1096 |
+
merges = list(self.original_tokenizer.bpe_ranks.keys())
|
| 1097 |
+
|
| 1098 |
+
tokenizer = Tokenizer(
|
| 1099 |
+
BPE(
|
| 1100 |
+
vocab=vocab,
|
| 1101 |
+
merges=merges,
|
| 1102 |
+
dropout=None,
|
| 1103 |
+
continuing_subword_prefix="",
|
| 1104 |
+
end_of_word_suffix="",
|
| 1105 |
+
fuse_unk=False,
|
| 1106 |
+
)
|
| 1107 |
+
)
|
| 1108 |
+
|
| 1109 |
+
tokenizer.pre_tokenizer = pre_tokenizers.ByteLevel(add_prefix_space=self.original_tokenizer.add_prefix_space)
|
| 1110 |
+
tokenizer.decoder = decoders.ByteLevel()
|
| 1111 |
+
|
| 1112 |
+
prefix_token_ids = self.original_tokenizer.prefix_tokens
|
| 1113 |
+
prefixes = self.original_tokenizer.convert_ids_to_tokens(prefix_token_ids)
|
| 1114 |
+
eos = self.original_tokenizer.eos_token
|
| 1115 |
+
eos_token_id = self.original_tokenizer.eos_token_id
|
| 1116 |
+
prefix_template = " ".join([f"{token}:0" for token in prefixes])
|
| 1117 |
+
tokenizer.post_processor = processors.TemplateProcessing(
|
| 1118 |
+
single=f"{prefix_template} $A:0 {eos}:0",
|
| 1119 |
+
pair=f"{prefix_template} $A:0 $B:1 {eos}:1",
|
| 1120 |
+
special_tokens=[
|
| 1121 |
+
(eos, eos_token_id),
|
| 1122 |
+
*zip(prefixes, prefix_token_ids),
|
| 1123 |
+
],
|
| 1124 |
+
)
|
| 1125 |
+
|
| 1126 |
+
return tokenizer
|
| 1127 |
+
|
| 1128 |
+
|
| 1129 |
+
class BigBirdConverter(SpmConverter):
|
| 1130 |
+
def post_processor(self):
|
| 1131 |
+
return processors.TemplateProcessing(
|
| 1132 |
+
single="[CLS]:0 $A:0 [SEP]:0",
|
| 1133 |
+
pair="[CLS]:0 $A:0 [SEP]:0 $B:1 [SEP]:1",
|
| 1134 |
+
special_tokens=[
|
| 1135 |
+
("[CLS]", self.original_tokenizer.convert_tokens_to_ids("[CLS]")),
|
| 1136 |
+
("[SEP]", self.original_tokenizer.convert_tokens_to_ids("[SEP]")),
|
| 1137 |
+
],
|
| 1138 |
+
)
|
| 1139 |
+
|
| 1140 |
+
|
| 1141 |
+
class CLIPConverter(Converter):
|
| 1142 |
+
def converted(self) -> Tokenizer:
|
| 1143 |
+
vocab = self.original_tokenizer.encoder
|
| 1144 |
+
merges = list(self.original_tokenizer.bpe_ranks.keys())
|
| 1145 |
+
unk_token = self.original_tokenizer.unk_token
|
| 1146 |
+
|
| 1147 |
+
tokenizer = Tokenizer(
|
| 1148 |
+
BPE(
|
| 1149 |
+
vocab=vocab,
|
| 1150 |
+
merges=merges,
|
| 1151 |
+
dropout=None,
|
| 1152 |
+
continuing_subword_prefix="",
|
| 1153 |
+
end_of_word_suffix="</w>",
|
| 1154 |
+
fuse_unk=False,
|
| 1155 |
+
unk_token=str(unk_token),
|
| 1156 |
+
)
|
| 1157 |
+
)
|
| 1158 |
+
|
| 1159 |
+
tokenizer.normalizer = normalizers.Sequence(
|
| 1160 |
+
[normalizers.NFC(), normalizers.Replace(Regex(r"\s+"), " "), normalizers.Lowercase()]
|
| 1161 |
+
)
|
| 1162 |
+
tokenizer.pre_tokenizer = pre_tokenizers.Sequence(
|
| 1163 |
+
[
|
| 1164 |
+
pre_tokenizers.Split(
|
| 1165 |
+
Regex(r"""'s|'t|'re|'ve|'m|'ll|'d|[\p{L}]+|[\p{N}]|[^\s\p{L}\p{N}]+"""),
|
| 1166 |
+
behavior="removed",
|
| 1167 |
+
invert=True,
|
| 1168 |
+
),
|
| 1169 |
+
pre_tokenizers.ByteLevel(add_prefix_space=False),
|
| 1170 |
+
]
|
| 1171 |
+
)
|
| 1172 |
+
tokenizer.decoder = decoders.ByteLevel()
|
| 1173 |
+
|
| 1174 |
+
# Hack to have a ByteLevel and TemplaceProcessor
|
| 1175 |
+
tokenizer.post_processor = processors.RobertaProcessing(
|
| 1176 |
+
sep=(self.original_tokenizer.eos_token, self.original_tokenizer.eos_token_id),
|
| 1177 |
+
cls=(self.original_tokenizer.bos_token, self.original_tokenizer.bos_token_id),
|
| 1178 |
+
add_prefix_space=False,
|
| 1179 |
+
trim_offsets=False,
|
| 1180 |
+
)
|
| 1181 |
+
return tokenizer
|
| 1182 |
+
|
| 1183 |
+
|
| 1184 |
+
class LayoutLMv2Converter(Converter):
|
| 1185 |
+
def converted(self) -> Tokenizer:
|
| 1186 |
+
vocab = self.original_tokenizer.vocab
|
| 1187 |
+
tokenizer = Tokenizer(WordPiece(vocab, unk_token=str(self.original_tokenizer.unk_token)))
|
| 1188 |
+
|
| 1189 |
+
tokenize_chinese_chars = False
|
| 1190 |
+
strip_accents = False
|
| 1191 |
+
do_lower_case = True
|
| 1192 |
+
if hasattr(self.original_tokenizer, "basic_tokenizer"):
|
| 1193 |
+
tokenize_chinese_chars = self.original_tokenizer.basic_tokenizer.tokenize_chinese_chars
|
| 1194 |
+
strip_accents = self.original_tokenizer.basic_tokenizer.strip_accents
|
| 1195 |
+
do_lower_case = self.original_tokenizer.basic_tokenizer.do_lower_case
|
| 1196 |
+
|
| 1197 |
+
tokenizer.normalizer = normalizers.BertNormalizer(
|
| 1198 |
+
clean_text=True,
|
| 1199 |
+
handle_chinese_chars=tokenize_chinese_chars,
|
| 1200 |
+
strip_accents=strip_accents,
|
| 1201 |
+
lowercase=do_lower_case,
|
| 1202 |
+
)
|
| 1203 |
+
tokenizer.pre_tokenizer = pre_tokenizers.BertPreTokenizer()
|
| 1204 |
+
|
| 1205 |
+
cls = str(self.original_tokenizer.cls_token)
|
| 1206 |
+
sep = str(self.original_tokenizer.sep_token)
|
| 1207 |
+
cls_token_id = self.original_tokenizer.cls_token_id
|
| 1208 |
+
sep_token_id = self.original_tokenizer.sep_token_id
|
| 1209 |
+
|
| 1210 |
+
tokenizer.post_processor = processors.TemplateProcessing(
|
| 1211 |
+
single=f"{cls}:0 $A:0 {sep}:0",
|
| 1212 |
+
pair=f"{cls}:0 $A:0 {sep}:0 $B:1 {sep}:1",
|
| 1213 |
+
special_tokens=[
|
| 1214 |
+
(cls, cls_token_id),
|
| 1215 |
+
(sep, sep_token_id),
|
| 1216 |
+
],
|
| 1217 |
+
)
|
| 1218 |
+
tokenizer.decoder = decoders.WordPiece(prefix="##")
|
| 1219 |
+
|
| 1220 |
+
return tokenizer
|
| 1221 |
+
|
| 1222 |
+
|
| 1223 |
+
class BlenderbotConverter(Converter):
|
| 1224 |
+
def converted(self) -> Tokenizer:
|
| 1225 |
+
ot = self.original_tokenizer
|
| 1226 |
+
vocab = ot.encoder
|
| 1227 |
+
merges = list(ot.bpe_ranks.keys())
|
| 1228 |
+
|
| 1229 |
+
tokenizer = Tokenizer(
|
| 1230 |
+
BPE(
|
| 1231 |
+
vocab=vocab,
|
| 1232 |
+
merges=merges,
|
| 1233 |
+
dropout=None,
|
| 1234 |
+
continuing_subword_prefix="",
|
| 1235 |
+
end_of_word_suffix="",
|
| 1236 |
+
fuse_unk=False,
|
| 1237 |
+
)
|
| 1238 |
+
)
|
| 1239 |
+
|
| 1240 |
+
tokenizer.pre_tokenizer = pre_tokenizers.ByteLevel(add_prefix_space=ot.add_prefix_space)
|
| 1241 |
+
tokenizer.decoder = decoders.ByteLevel()
|
| 1242 |
+
tokenizer.post_processor = processors.TemplateProcessing(
|
| 1243 |
+
single=f"$A:0 {ot.eos_token}:0",
|
| 1244 |
+
special_tokens=[
|
| 1245 |
+
(ot.eos_token, ot.eos_token_id),
|
| 1246 |
+
],
|
| 1247 |
+
)
|
| 1248 |
+
|
| 1249 |
+
return tokenizer
|
| 1250 |
+
|
| 1251 |
+
|
| 1252 |
+
class XGLMConverter(SpmConverter):
|
| 1253 |
+
def vocab(self, proto):
|
| 1254 |
+
vocab = [
|
| 1255 |
+
("<s>", 0.0),
|
| 1256 |
+
("<pad>", 0.0),
|
| 1257 |
+
("</s>", 0.0),
|
| 1258 |
+
("<unk>", 0.0),
|
| 1259 |
+
]
|
| 1260 |
+
vocab += [(piece.piece, piece.score) for piece in proto.pieces[3:]]
|
| 1261 |
+
vocab += [("<madeupword0>", 0.0), ("<madeupword1>", 0.0), ("<madeupword2>", 0.0), ("<madeupword3>", 0.0), ("<madeupword4>", 0.0), ("<madeupword5>", 0.0), ("<madeupword6>", 0.0)] # fmt: skip
|
| 1262 |
+
return vocab
|
| 1263 |
+
|
| 1264 |
+
def unk_id(self, proto):
|
| 1265 |
+
unk_id = 3
|
| 1266 |
+
return unk_id
|
| 1267 |
+
|
| 1268 |
+
def post_processor(self):
|
| 1269 |
+
return processors.TemplateProcessing(
|
| 1270 |
+
single="</s> $A",
|
| 1271 |
+
pair="</s> $A </s> </s> $B",
|
| 1272 |
+
special_tokens=[
|
| 1273 |
+
("<s>", self.original_tokenizer.convert_tokens_to_ids("<s>")),
|
| 1274 |
+
("</s>", self.original_tokenizer.convert_tokens_to_ids("</s>")),
|
| 1275 |
+
],
|
| 1276 |
+
)
|
| 1277 |
+
|
| 1278 |
+
|
| 1279 |
+
class GemmaConverter(SpmConverter):
|
| 1280 |
+
handle_byte_fallback = True
|
| 1281 |
+
SpmExtractor = GemmaSentencePieceExtractor
|
| 1282 |
+
# start and end of turn tokens must be marked as special
|
| 1283 |
+
special_tokens = {"<start_of_turn>", "<end_of_turn>"}
|
| 1284 |
+
|
| 1285 |
+
""""
|
| 1286 |
+
split_by_unicode_script: true
|
| 1287 |
+
split_by_number: true
|
| 1288 |
+
split_by_whitespace: true
|
| 1289 |
+
treat_whitespace_as_suffix: false
|
| 1290 |
+
allow_whitespace_only_pieces: true
|
| 1291 |
+
split_digits: true
|
| 1292 |
+
byte_fallback: true
|
| 1293 |
+
"""
|
| 1294 |
+
|
| 1295 |
+
def normalizer(self, proto):
|
| 1296 |
+
return normalizers.Replace(" ", "▁")
|
| 1297 |
+
|
| 1298 |
+
def vocab(self, proto):
|
| 1299 |
+
vocab = [
|
| 1300 |
+
(self.original_tokenizer.pad_token, 0.0),
|
| 1301 |
+
(self.original_tokenizer.eos_token, 0.0),
|
| 1302 |
+
(self.original_tokenizer.bos_token, 0.0),
|
| 1303 |
+
]
|
| 1304 |
+
vocab += [(piece.piece, piece.score) for piece in proto.pieces[3:]]
|
| 1305 |
+
|
| 1306 |
+
# Older gemma tokenizers had a missing tab token, so we fix that here
|
| 1307 |
+
if not any(x[0] == "\t" for x in vocab):
|
| 1308 |
+
override_index = next((i for i, x in enumerate(vocab) if x[0] == "<0x09>"), None)
|
| 1309 |
+
if override_index is not None:
|
| 1310 |
+
vocab[override_index] = ("\t", 0.0)
|
| 1311 |
+
|
| 1312 |
+
return vocab
|
| 1313 |
+
|
| 1314 |
+
def pre_tokenizer(self, replacement, add_prefix_space):
|
| 1315 |
+
return pre_tokenizers.Split(" ", "merged_with_previous")
|
| 1316 |
+
|
| 1317 |
+
def unk_id(self, proto):
|
| 1318 |
+
unk_id = 3
|
| 1319 |
+
return unk_id
|
| 1320 |
+
|
| 1321 |
+
def decoder(self, replacement, add_prefix_space):
|
| 1322 |
+
return decoders.Sequence(
|
| 1323 |
+
[
|
| 1324 |
+
decoders.Replace("▁", " "),
|
| 1325 |
+
decoders.ByteFallback(),
|
| 1326 |
+
decoders.Fuse(),
|
| 1327 |
+
]
|
| 1328 |
+
)
|
| 1329 |
+
|
| 1330 |
+
|
| 1331 |
+
class LlamaConverter(SpmConverter):
|
| 1332 |
+
handle_byte_fallback = True
|
| 1333 |
+
|
| 1334 |
+
def vocab(self, proto):
|
| 1335 |
+
vocab = [
|
| 1336 |
+
(self.original_tokenizer.convert_ids_to_tokens(0), 0.0),
|
| 1337 |
+
(self.original_tokenizer.convert_ids_to_tokens(1), 0.0),
|
| 1338 |
+
(self.original_tokenizer.convert_ids_to_tokens(2), 0.0),
|
| 1339 |
+
]
|
| 1340 |
+
vocab += [(piece.piece, piece.score) for piece in proto.pieces[3:]]
|
| 1341 |
+
return vocab
|
| 1342 |
+
|
| 1343 |
+
def unk_id(self, proto):
|
| 1344 |
+
unk_id = 0
|
| 1345 |
+
return unk_id
|
| 1346 |
+
|
| 1347 |
+
def decoder(self, replacement, add_prefix_space):
|
| 1348 |
+
sequence = [
|
| 1349 |
+
decoders.Replace("▁", " "),
|
| 1350 |
+
decoders.ByteFallback(),
|
| 1351 |
+
decoders.Fuse(),
|
| 1352 |
+
]
|
| 1353 |
+
if add_prefix_space:
|
| 1354 |
+
sequence += [decoders.Strip(content=" ", left=1)]
|
| 1355 |
+
return decoders.Sequence(sequence)
|
| 1356 |
+
|
| 1357 |
+
def normalizer(self, proto):
|
| 1358 |
+
if getattr(self.original_tokenizer, "legacy", True):
|
| 1359 |
+
sequence = []
|
| 1360 |
+
if getattr(self.original_tokenizer, "add_prefix_space", True):
|
| 1361 |
+
sequence += [normalizers.Prepend(prepend="▁")]
|
| 1362 |
+
sequence += [normalizers.Replace(pattern=" ", content="▁")]
|
| 1363 |
+
return normalizers.Sequence(sequence)
|
| 1364 |
+
return None # non-legacy, no normalizer
|
| 1365 |
+
|
| 1366 |
+
def pre_tokenizer(self, replacement, add_prefix_space):
|
| 1367 |
+
if not getattr(self.original_tokenizer, "legacy", True): # non-legacy, we need a replace
|
| 1368 |
+
prepend_scheme = _get_prepend_scheme(add_prefix_space, self.original_tokenizer)
|
| 1369 |
+
return pre_tokenizers.Metaspace(replacement=replacement, prepend_scheme=prepend_scheme, split=False)
|
| 1370 |
+
return None
|
| 1371 |
+
|
| 1372 |
+
def post_processor(self):
|
| 1373 |
+
# the processor is defined in the LlamaTokenizerFast class.
|
| 1374 |
+
return None
|
| 1375 |
+
|
| 1376 |
+
|
| 1377 |
+
class MarkupLMConverter(Converter):
|
| 1378 |
+
def converted(self) -> Tokenizer:
|
| 1379 |
+
ot = self.original_tokenizer
|
| 1380 |
+
vocab = ot.encoder
|
| 1381 |
+
merges = list(ot.bpe_ranks.keys())
|
| 1382 |
+
|
| 1383 |
+
tokenizer = Tokenizer(
|
| 1384 |
+
BPE(
|
| 1385 |
+
vocab=vocab,
|
| 1386 |
+
merges=merges,
|
| 1387 |
+
dropout=None,
|
| 1388 |
+
continuing_subword_prefix="",
|
| 1389 |
+
end_of_word_suffix="",
|
| 1390 |
+
fuse_unk=False,
|
| 1391 |
+
unk_token=self.original_tokenizer.unk_token,
|
| 1392 |
+
)
|
| 1393 |
+
)
|
| 1394 |
+
|
| 1395 |
+
tokenizer.pre_tokenizer = pre_tokenizers.ByteLevel(add_prefix_space=ot.add_prefix_space)
|
| 1396 |
+
tokenizer.decoder = decoders.ByteLevel()
|
| 1397 |
+
|
| 1398 |
+
cls = str(self.original_tokenizer.cls_token)
|
| 1399 |
+
sep = str(self.original_tokenizer.sep_token)
|
| 1400 |
+
cls_token_id = self.original_tokenizer.cls_token_id
|
| 1401 |
+
sep_token_id = self.original_tokenizer.sep_token_id
|
| 1402 |
+
|
| 1403 |
+
tokenizer.post_processor = processors.TemplateProcessing(
|
| 1404 |
+
single=f"{cls} $A {sep}",
|
| 1405 |
+
pair=f"{cls} $A {sep} $B {sep}",
|
| 1406 |
+
special_tokens=[
|
| 1407 |
+
(cls, cls_token_id),
|
| 1408 |
+
(sep, sep_token_id),
|
| 1409 |
+
],
|
| 1410 |
+
)
|
| 1411 |
+
|
| 1412 |
+
return tokenizer
|
| 1413 |
+
|
| 1414 |
+
|
| 1415 |
+
class MoshiConverter(SpmConverter):
|
| 1416 |
+
handle_byte_fallback = True
|
| 1417 |
+
|
| 1418 |
+
def __init__(self, vocab_file, model_max_length=None, **kwargs):
|
| 1419 |
+
requires_backends(self, "protobuf")
|
| 1420 |
+
|
| 1421 |
+
Converter.__init__(self, vocab_file)
|
| 1422 |
+
|
| 1423 |
+
# from .utils import sentencepiece_model_pb2 as model_pb2
|
| 1424 |
+
model_pb2 = import_protobuf()
|
| 1425 |
+
|
| 1426 |
+
m = model_pb2.ModelProto()
|
| 1427 |
+
with open(vocab_file, "rb") as f:
|
| 1428 |
+
m.ParseFromString(f.read())
|
| 1429 |
+
self.proto = m
|
| 1430 |
+
|
| 1431 |
+
def normalizer(self, proto):
|
| 1432 |
+
precompiled_charsmap = proto.normalizer_spec.precompiled_charsmap
|
| 1433 |
+
_normalizers = [
|
| 1434 |
+
normalizers.Replace(" ", "▁"),
|
| 1435 |
+
]
|
| 1436 |
+
if not precompiled_charsmap:
|
| 1437 |
+
return normalizers.Sequence(_normalizers)
|
| 1438 |
+
else:
|
| 1439 |
+
return normalizers.Sequence([normalizers.Precompiled(precompiled_charsmap)] + _normalizers)
|
| 1440 |
+
|
| 1441 |
+
def decoder(self, replacement, add_prefix_space):
|
| 1442 |
+
sequence = [
|
| 1443 |
+
decoders.Replace("▁", " "),
|
| 1444 |
+
decoders.ByteFallback(),
|
| 1445 |
+
decoders.Fuse(),
|
| 1446 |
+
]
|
| 1447 |
+
if add_prefix_space:
|
| 1448 |
+
sequence += [decoders.Strip(content=" ", left=1)]
|
| 1449 |
+
return decoders.Sequence(sequence)
|
| 1450 |
+
|
| 1451 |
+
def pre_tokenizer(self, replacement, add_prefix_space):
|
| 1452 |
+
prepend_scheme = "first"
|
| 1453 |
+
return pre_tokenizers.Metaspace(replacement=replacement, prepend_scheme=prepend_scheme, split=False)
|
| 1454 |
+
|
| 1455 |
+
|
| 1456 |
+
class HeliumConverter(SpmConverter):
|
| 1457 |
+
handle_byte_fallback = True
|
| 1458 |
+
|
| 1459 |
+
def __init__(self, vocab_file=None, **kwargs):
|
| 1460 |
+
requires_backends(self, "protobuf")
|
| 1461 |
+
|
| 1462 |
+
Converter.__init__(self, vocab_file)
|
| 1463 |
+
|
| 1464 |
+
model_pb2 = import_protobuf()
|
| 1465 |
+
|
| 1466 |
+
m = model_pb2.ModelProto()
|
| 1467 |
+
with open(vocab_file, "rb") as f:
|
| 1468 |
+
m.ParseFromString(f.read())
|
| 1469 |
+
self.proto = m
|
| 1470 |
+
|
| 1471 |
+
def tokenizer(self, proto):
|
| 1472 |
+
vocab_scores = self.vocab(proto)
|
| 1473 |
+
tokenizer = Tokenizer(
|
| 1474 |
+
Unigram(
|
| 1475 |
+
vocab_scores,
|
| 1476 |
+
unk_id=self.unk_id(proto),
|
| 1477 |
+
byte_fallback=self.handle_byte_fallback,
|
| 1478 |
+
)
|
| 1479 |
+
)
|
| 1480 |
+
# control tokens are special
|
| 1481 |
+
# user defined symbols are not
|
| 1482 |
+
# both user and control tokens are AddedTokens
|
| 1483 |
+
# Add user defined symbols (type == 4) from sentencepiece (https://github.com/google/sentencepiece/blob/6225e08edb2577757163b3f5dbba4c0b670ef445/src/sentencepiece_model.proto#L299C29-L299C33)
|
| 1484 |
+
spm_added_tokens = [
|
| 1485 |
+
(id, p.piece, p.type == 3 or p.piece in self.special_tokens)
|
| 1486 |
+
for id, p in enumerate(proto.pieces)
|
| 1487 |
+
if p.type in [3, 4]
|
| 1488 |
+
]
|
| 1489 |
+
tokenizer.add_tokens(
|
| 1490 |
+
[
|
| 1491 |
+
AddedToken(token, normalized=False, special=special, single_word=True)
|
| 1492 |
+
for id, token, special in sorted(spm_added_tokens, key=lambda x: x[0])
|
| 1493 |
+
]
|
| 1494 |
+
)
|
| 1495 |
+
tokenizer.add_tokens([AddedToken("\n", normalized=False, special=False)])
|
| 1496 |
+
tokenizer.enable_padding(pad_token="<pad>", pad_id=3)
|
| 1497 |
+
return tokenizer
|
| 1498 |
+
|
| 1499 |
+
def vocab(self, proto):
|
| 1500 |
+
vocab = []
|
| 1501 |
+
for piece in proto.pieces:
|
| 1502 |
+
if piece.piece == "<0x0A>":
|
| 1503 |
+
vocab += [("\n", piece.score)]
|
| 1504 |
+
else:
|
| 1505 |
+
vocab += [(piece.piece, piece.score)]
|
| 1506 |
+
return vocab
|
| 1507 |
+
|
| 1508 |
+
def unk_id(self, proto):
|
| 1509 |
+
unk_id = 0
|
| 1510 |
+
return unk_id
|
| 1511 |
+
|
| 1512 |
+
def decoder(self, replacement, add_prefix_space):
|
| 1513 |
+
sequence = [
|
| 1514 |
+
decoders.Replace("▁", " "),
|
| 1515 |
+
decoders.ByteFallback(),
|
| 1516 |
+
decoders.Fuse(),
|
| 1517 |
+
]
|
| 1518 |
+
sequence += [decoders.Strip(content=" ", left=1)]
|
| 1519 |
+
return decoders.Sequence(sequence)
|
| 1520 |
+
|
| 1521 |
+
def normalizer(self, proto):
|
| 1522 |
+
return normalizers.Sequence([normalizers.Prepend(" "), normalizers.Replace(r" ", "▁")])
|
| 1523 |
+
|
| 1524 |
+
def pre_tokenizer(self, replacement, add_prefix_space):
|
| 1525 |
+
return pre_tokenizers.Sequence([pre_tokenizers.Split("\n", "contiguous")])
|
| 1526 |
+
|
| 1527 |
+
def post_processor(self):
|
| 1528 |
+
return processors.TemplateProcessing(
|
| 1529 |
+
single=[
|
| 1530 |
+
"<s>",
|
| 1531 |
+
"$A",
|
| 1532 |
+
],
|
| 1533 |
+
pair=[
|
| 1534 |
+
"<s>",
|
| 1535 |
+
"$A",
|
| 1536 |
+
"<s>",
|
| 1537 |
+
"$B",
|
| 1538 |
+
],
|
| 1539 |
+
special_tokens=[
|
| 1540 |
+
("<s>", 1),
|
| 1541 |
+
],
|
| 1542 |
+
)
|
| 1543 |
+
|
| 1544 |
+
|
| 1545 |
+
class ParakeetConverter(SpmConverter):
|
| 1546 |
+
handle_byte_fallback = True
|
| 1547 |
+
|
| 1548 |
+
def __init__(self, vocab_file=None, *args):
|
| 1549 |
+
self.vocab_file = vocab_file
|
| 1550 |
+
|
| 1551 |
+
requires_backends(self, "protobuf")
|
| 1552 |
+
|
| 1553 |
+
Converter.__init__(self, vocab_file)
|
| 1554 |
+
|
| 1555 |
+
model_pb2 = import_protobuf()
|
| 1556 |
+
m = model_pb2.ModelProto()
|
| 1557 |
+
with open(vocab_file, "rb") as f:
|
| 1558 |
+
m.ParseFromString(f.read())
|
| 1559 |
+
self.proto = m
|
| 1560 |
+
|
| 1561 |
+
def tokenizer(self, proto):
|
| 1562 |
+
vocab_scores = self.vocab(proto)
|
| 1563 |
+
|
| 1564 |
+
_, merges = self.SpmExtractor(self.vocab_file).extract(vocab_scores)
|
| 1565 |
+
bpe_vocab = {word: i for i, (word, score) in enumerate(vocab_scores)}
|
| 1566 |
+
tokenizer = Tokenizer(
|
| 1567 |
+
BPE(
|
| 1568 |
+
bpe_vocab,
|
| 1569 |
+
merges,
|
| 1570 |
+
unk_token=proto.trainer_spec.unk_piece,
|
| 1571 |
+
fuse_unk=True,
|
| 1572 |
+
byte_fallback=self.handle_byte_fallback,
|
| 1573 |
+
dropout=None,
|
| 1574 |
+
)
|
| 1575 |
+
)
|
| 1576 |
+
|
| 1577 |
+
# Add user defined symbols and control tokens from sentencepiece model
|
| 1578 |
+
spm_added_tokens = [
|
| 1579 |
+
(id, p.piece, p.type == 3 or p.piece in self.special_tokens)
|
| 1580 |
+
for id, p in enumerate(proto.pieces)
|
| 1581 |
+
if p.type in [3, 4]
|
| 1582 |
+
]
|
| 1583 |
+
tokenizer.add_tokens(
|
| 1584 |
+
[
|
| 1585 |
+
AddedToken(token, normalized=False, special=special)
|
| 1586 |
+
for id, token, special in sorted(spm_added_tokens, key=lambda x: x[0])
|
| 1587 |
+
]
|
| 1588 |
+
)
|
| 1589 |
+
|
| 1590 |
+
return tokenizer
|
| 1591 |
+
|
| 1592 |
+
|
| 1593 |
+
# Copied from transformers.models.gpt2.tokenization_gpt2.bytes_to_unicode
|
| 1594 |
+
def bytes_to_unicode():
|
| 1595 |
+
"""
|
| 1596 |
+
Returns list of utf-8 byte and a mapping to unicode strings. We specifically avoids mapping to whitespace/control
|
| 1597 |
+
characters the bpe code barfs on.
|
| 1598 |
+
|
| 1599 |
+
The reversible bpe codes work on unicode strings. This means you need a large # of unicode characters in your vocab
|
| 1600 |
+
if you want to avoid UNKs. When you're at something like a 10B token dataset you end up needing around 5K for
|
| 1601 |
+
decent coverage. This is a significant percentage of your normal, say, 32K bpe vocab. To avoid that, we want lookup
|
| 1602 |
+
tables between utf-8 bytes and unicode strings.
|
| 1603 |
+
"""
|
| 1604 |
+
bs = (
|
| 1605 |
+
list(range(ord("!"), ord("~") + 1)) + list(range(ord("¡"), ord("¬") + 1)) + list(range(ord("®"), ord("ÿ") + 1))
|
| 1606 |
+
)
|
| 1607 |
+
cs = bs[:]
|
| 1608 |
+
n = 0
|
| 1609 |
+
for b in range(2**8):
|
| 1610 |
+
if b not in bs:
|
| 1611 |
+
bs.append(b)
|
| 1612 |
+
cs.append(2**8 + n)
|
| 1613 |
+
n += 1
|
| 1614 |
+
cs = [chr(n) for n in cs]
|
| 1615 |
+
return dict(zip(bs, cs))
|
| 1616 |
+
|
| 1617 |
+
|
| 1618 |
+
class TikTokenConverter:
|
| 1619 |
+
"""
|
| 1620 |
+
A general tiktoken converter.
|
| 1621 |
+
"""
|
| 1622 |
+
|
| 1623 |
+
def __init__(
|
| 1624 |
+
self,
|
| 1625 |
+
vocab_file=None,
|
| 1626 |
+
pattern=r"""(?i:'s|'t|'re|'ve|'m|'ll|'d)|[^\r\n\p{L}\p{N}]?\p{L}+|\p{N}{1,3}| ?[^\s\p{L}\p{N}]+[\r\n]*|\s*[\r\n]+|\s+(?!\S)|\s+""",
|
| 1627 |
+
add_prefix_space=False,
|
| 1628 |
+
additional_special_tokens=None,
|
| 1629 |
+
**kwargs,
|
| 1630 |
+
):
|
| 1631 |
+
self.vocab_file = vocab_file
|
| 1632 |
+
self.pattern = pattern
|
| 1633 |
+
self.add_prefix_space = add_prefix_space
|
| 1634 |
+
self.additional_special_tokens = (
|
| 1635 |
+
additional_special_tokens.keys()
|
| 1636 |
+
if isinstance(additional_special_tokens, dict)
|
| 1637 |
+
else additional_special_tokens
|
| 1638 |
+
)
|
| 1639 |
+
|
| 1640 |
+
def extract_vocab_merges_from_model(self, tiktoken_url: str):
|
| 1641 |
+
try:
|
| 1642 |
+
from tiktoken.load import load_tiktoken_bpe
|
| 1643 |
+
except Exception:
|
| 1644 |
+
raise ValueError(
|
| 1645 |
+
"`tiktoken` is required to read a `tiktoken` file. Install it with `pip install tiktoken`."
|
| 1646 |
+
)
|
| 1647 |
+
|
| 1648 |
+
bpe_ranks = load_tiktoken_bpe(tiktoken_url)
|
| 1649 |
+
byte_encoder = bytes_to_unicode()
|
| 1650 |
+
|
| 1651 |
+
def token_bytes_to_string(b):
|
| 1652 |
+
return "".join([byte_encoder[ord(char)] for char in b.decode("latin-1")])
|
| 1653 |
+
|
| 1654 |
+
merges = []
|
| 1655 |
+
vocab = {}
|
| 1656 |
+
for token, rank in bpe_ranks.items():
|
| 1657 |
+
vocab[token_bytes_to_string(token)] = rank
|
| 1658 |
+
if len(token) == 1:
|
| 1659 |
+
continue
|
| 1660 |
+
local = []
|
| 1661 |
+
for index in range(1, len(token)):
|
| 1662 |
+
piece_l, piece_r = token[:index], token[index:]
|
| 1663 |
+
if piece_l in bpe_ranks and piece_r in bpe_ranks and (piece_l + piece_r) in bpe_ranks:
|
| 1664 |
+
local.append((piece_l, piece_r, rank))
|
| 1665 |
+
local = sorted(local, key=lambda x: (bpe_ranks[x[0]], bpe_ranks[x[1]]), reverse=False)
|
| 1666 |
+
merges.extend(local)
|
| 1667 |
+
merges = sorted(merges, key=lambda val: val[2], reverse=False)
|
| 1668 |
+
merges = [(token_bytes_to_string(val[0]), token_bytes_to_string(val[1])) for val in merges]
|
| 1669 |
+
return vocab, merges
|
| 1670 |
+
|
| 1671 |
+
def tokenizer(self):
|
| 1672 |
+
vocab_scores, merges = self.extract_vocab_merges_from_model(self.vocab_file)
|
| 1673 |
+
tokenizer = Tokenizer(BPE(vocab_scores, merges, fuse_unk=False))
|
| 1674 |
+
if hasattr(tokenizer.model, "ignore_merges"):
|
| 1675 |
+
tokenizer.model.ignore_merges = True
|
| 1676 |
+
return tokenizer
|
| 1677 |
+
|
| 1678 |
+
def converted(self) -> Tokenizer:
|
| 1679 |
+
tokenizer = self.tokenizer()
|
| 1680 |
+
tokenizer.pre_tokenizer = pre_tokenizers.Sequence(
|
| 1681 |
+
[
|
| 1682 |
+
pre_tokenizers.Split(Regex(self.pattern), behavior="isolated", invert=False),
|
| 1683 |
+
pre_tokenizers.ByteLevel(add_prefix_space=self.add_prefix_space, use_regex=False),
|
| 1684 |
+
]
|
| 1685 |
+
)
|
| 1686 |
+
tokenizer.decoder = decoders.ByteLevel()
|
| 1687 |
+
|
| 1688 |
+
tokenizer.add_special_tokens(
|
| 1689 |
+
[AddedToken(token, normalized=False, special=True) for token in self.additional_special_tokens]
|
| 1690 |
+
)
|
| 1691 |
+
|
| 1692 |
+
tokenizer.post_processor = processors.ByteLevel(trim_offsets=False)
|
| 1693 |
+
|
| 1694 |
+
return tokenizer
|
| 1695 |
+
|
| 1696 |
+
|
| 1697 |
+
class MistralConverter:
|
| 1698 |
+
def __init__(
|
| 1699 |
+
self,
|
| 1700 |
+
vocab_file=None,
|
| 1701 |
+
pattern=r"""(?i:'s|'t|'re|'ve|'m|'ll|'d)|[^\r\n\p{L}\p{N}]?\p{L}+|\p{N}{1,3}| ?[^\s\p{L}\p{N}]+[\r\n]*|\s*[\r\n]+|\s+(?!\S)|\s+""",
|
| 1702 |
+
add_prefix_space=False,
|
| 1703 |
+
additional_special_tokens=None,
|
| 1704 |
+
**kwargs,
|
| 1705 |
+
):
|
| 1706 |
+
self.vocab_file = vocab_file
|
| 1707 |
+
self.pattern = pattern
|
| 1708 |
+
self.add_prefix_space = add_prefix_space
|
| 1709 |
+
self.additional_special_tokens = (
|
| 1710 |
+
additional_special_tokens.keys()
|
| 1711 |
+
if isinstance(additional_special_tokens, dict)
|
| 1712 |
+
else additional_special_tokens
|
| 1713 |
+
)
|
| 1714 |
+
|
| 1715 |
+
def extract_vocab_merges_from_model(self, tiktoken_url: str):
|
| 1716 |
+
import base64
|
| 1717 |
+
import json
|
| 1718 |
+
|
| 1719 |
+
with open(self.vocab_file, "r", encoding="utf-8") as f:
|
| 1720 |
+
untyped = json.load(f)
|
| 1721 |
+
self.pattern = untyped["config"]["pattern"]
|
| 1722 |
+
self.additional_special_tokens = [
|
| 1723 |
+
AddedToken(k["token_str"], special=k["is_control"]) for k in untyped["special_tokens"]
|
| 1724 |
+
]
|
| 1725 |
+
bpe_ranks = untyped["vocab"]
|
| 1726 |
+
byte_encoder = bytes_to_unicode()
|
| 1727 |
+
|
| 1728 |
+
@lru_cache
|
| 1729 |
+
def token_bytes_to_string(b):
|
| 1730 |
+
return "".join([byte_encoder[ord(char)] for char in b.decode("latin-1")])
|
| 1731 |
+
|
| 1732 |
+
merges = []
|
| 1733 |
+
vocab = {}
|
| 1734 |
+
for idx, token in enumerate(self.additional_special_tokens):
|
| 1735 |
+
vocab[token.content] = idx
|
| 1736 |
+
bpe_ranks = [base64.b64decode(k["token_bytes"]) for k in bpe_ranks]
|
| 1737 |
+
rank_set = set(bpe_ranks)
|
| 1738 |
+
for rank, token in enumerate(tqdm(bpe_ranks, desc="Converting tekken.json to tokenizer.json")):
|
| 1739 |
+
vocab[token_bytes_to_string(token)] = rank
|
| 1740 |
+
if len(token) == 1:
|
| 1741 |
+
continue
|
| 1742 |
+
local = []
|
| 1743 |
+
for index in range(1, len(token)):
|
| 1744 |
+
piece_l, piece_r = token[:index], token[index:]
|
| 1745 |
+
if piece_l in rank_set and piece_r in rank_set and (piece_l + piece_r) in rank_set:
|
| 1746 |
+
local.append((piece_l, piece_r, rank))
|
| 1747 |
+
local = sorted(local, key=lambda x: (bpe_ranks.index(x[0]), bpe_ranks.index(x[1])), reverse=False)
|
| 1748 |
+
merges.extend(local)
|
| 1749 |
+
merges = sorted(merges, key=lambda val: val[2], reverse=False)
|
| 1750 |
+
merges = [(token_bytes_to_string(val[0]), token_bytes_to_string(val[1])) for val in merges]
|
| 1751 |
+
return vocab, merges
|
| 1752 |
+
|
| 1753 |
+
def tokenizer(self):
|
| 1754 |
+
vocab_scores, merges = self.extract_vocab_merges_from_model(self.vocab_file)
|
| 1755 |
+
tokenizer = Tokenizer(BPE(vocab_scores, merges, fuse_unk=False))
|
| 1756 |
+
if hasattr(tokenizer.model, "ignore_merges"):
|
| 1757 |
+
tokenizer.model.ignore_merges = True
|
| 1758 |
+
return tokenizer
|
| 1759 |
+
|
| 1760 |
+
def converted(self) -> Tokenizer:
|
| 1761 |
+
tokenizer = self.tokenizer()
|
| 1762 |
+
tokenizer.pre_tokenizer = pre_tokenizers.Sequence(
|
| 1763 |
+
[
|
| 1764 |
+
pre_tokenizers.Split(Regex(self.pattern), behavior="isolated", invert=False),
|
| 1765 |
+
pre_tokenizers.ByteLevel(add_prefix_space=self.add_prefix_space, use_regex=False),
|
| 1766 |
+
]
|
| 1767 |
+
)
|
| 1768 |
+
tokenizer.decoder = decoders.ByteLevel()
|
| 1769 |
+
|
| 1770 |
+
tokenizer.add_tokens(self.additional_special_tokens)
|
| 1771 |
+
tokenizer.post_processor = processors.ByteLevel(trim_offsets=False)
|
| 1772 |
+
|
| 1773 |
+
return tokenizer
|
| 1774 |
+
|
| 1775 |
+
|
| 1776 |
+
SLOW_TO_FAST_CONVERTERS = {
|
| 1777 |
+
"AlbertTokenizer": AlbertConverter,
|
| 1778 |
+
"BartTokenizer": RobertaConverter,
|
| 1779 |
+
"BarthezTokenizer": BarthezConverter,
|
| 1780 |
+
"BertTokenizer": BertConverter,
|
| 1781 |
+
"BigBirdTokenizer": BigBirdConverter,
|
| 1782 |
+
"BlenderbotTokenizer": BlenderbotConverter,
|
| 1783 |
+
"CamembertTokenizer": CamembertConverter,
|
| 1784 |
+
"CLIPTokenizer": CLIPConverter,
|
| 1785 |
+
"CodeGenTokenizer": GPT2Converter,
|
| 1786 |
+
"ConvBertTokenizer": BertConverter,
|
| 1787 |
+
"DebertaTokenizer": DebertaConverter,
|
| 1788 |
+
"DebertaV2Tokenizer": DebertaV2Converter,
|
| 1789 |
+
"DistilBertTokenizer": BertConverter,
|
| 1790 |
+
"DPRReaderTokenizer": BertConverter,
|
| 1791 |
+
"DPRQuestionEncoderTokenizer": BertConverter,
|
| 1792 |
+
"DPRContextEncoderTokenizer": BertConverter,
|
| 1793 |
+
"ElectraTokenizer": BertConverter,
|
| 1794 |
+
"FNetTokenizer": AlbertConverter,
|
| 1795 |
+
"FunnelTokenizer": FunnelConverter,
|
| 1796 |
+
"GPT2Tokenizer": GPT2Converter,
|
| 1797 |
+
"HerbertTokenizer": HerbertConverter,
|
| 1798 |
+
"LayoutLMTokenizer": BertConverter,
|
| 1799 |
+
"LayoutLMv2Tokenizer": BertConverter,
|
| 1800 |
+
"LayoutLMv3Tokenizer": RobertaConverter,
|
| 1801 |
+
"LayoutXLMTokenizer": XLMRobertaConverter,
|
| 1802 |
+
"LongformerTokenizer": RobertaConverter,
|
| 1803 |
+
"LEDTokenizer": RobertaConverter,
|
| 1804 |
+
"LxmertTokenizer": BertConverter,
|
| 1805 |
+
"MarkupLMTokenizer": MarkupLMConverter,
|
| 1806 |
+
"MBartTokenizer": MBartConverter,
|
| 1807 |
+
"MBart50Tokenizer": MBart50Converter,
|
| 1808 |
+
"MPNetTokenizer": MPNetConverter,
|
| 1809 |
+
"MobileBertTokenizer": BertConverter,
|
| 1810 |
+
"MvpTokenizer": RobertaConverter,
|
| 1811 |
+
"NllbTokenizer": NllbConverter,
|
| 1812 |
+
"OpenAIGPTTokenizer": OpenAIGPTConverter,
|
| 1813 |
+
"PegasusTokenizer": PegasusConverter,
|
| 1814 |
+
"Qwen2Tokenizer": Qwen2Converter,
|
| 1815 |
+
"RealmTokenizer": BertConverter,
|
| 1816 |
+
"ReformerTokenizer": ReformerConverter,
|
| 1817 |
+
"RemBertTokenizer": RemBertConverter,
|
| 1818 |
+
"RetriBertTokenizer": BertConverter,
|
| 1819 |
+
"RobertaTokenizer": RobertaConverter,
|
| 1820 |
+
"RoFormerTokenizer": RoFormerConverter,
|
| 1821 |
+
"SeamlessM4TTokenizer": SeamlessM4TConverter,
|
| 1822 |
+
"SqueezeBertTokenizer": BertConverter,
|
| 1823 |
+
"T5Tokenizer": T5Converter,
|
| 1824 |
+
"UdopTokenizer": UdopConverter,
|
| 1825 |
+
"WhisperTokenizer": WhisperConverter,
|
| 1826 |
+
"XLMRobertaTokenizer": XLMRobertaConverter,
|
| 1827 |
+
"XLNetTokenizer": XLNetConverter,
|
| 1828 |
+
"SplinterTokenizer": SplinterConverter,
|
| 1829 |
+
"XGLMTokenizer": XGLMConverter,
|
| 1830 |
+
"LlamaTokenizer": LlamaConverter,
|
| 1831 |
+
"CodeLlamaTokenizer": LlamaConverter,
|
| 1832 |
+
"GemmaTokenizer": GemmaConverter,
|
| 1833 |
+
"Phi3Tokenizer": LlamaConverter,
|
| 1834 |
+
}
|
| 1835 |
+
|
| 1836 |
+
|
| 1837 |
+
def convert_slow_tokenizer(transformer_tokenizer, from_tiktoken=False) -> Tokenizer:
|
| 1838 |
+
"""
|
| 1839 |
+
Utilities to convert a slow tokenizer instance in a fast tokenizer instance.
|
| 1840 |
+
|
| 1841 |
+
Args:
|
| 1842 |
+
transformer_tokenizer ([`~tokenization_utils_base.PreTrainedTokenizer`]):
|
| 1843 |
+
Instance of a slow tokenizer to convert in the backend tokenizer for
|
| 1844 |
+
[`~tokenization_utils_base.PreTrainedTokenizerFast`].
|
| 1845 |
+
from_tiktoken (bool, optional): Whether to use the `tiktoken` library to convert the tokenizer instead of sentencepiece.
|
| 1846 |
+
Defaults to False.
|
| 1847 |
+
|
| 1848 |
+
Return:
|
| 1849 |
+
A instance of [`~tokenizers.Tokenizer`] to be used as the backend tokenizer of a
|
| 1850 |
+
[`~tokenization_utils_base.PreTrainedTokenizerFast`]
|
| 1851 |
+
"""
|
| 1852 |
+
|
| 1853 |
+
tokenizer_class_name = transformer_tokenizer.__class__.__name__
|
| 1854 |
+
if tokenizer_class_name in SLOW_TO_FAST_CONVERTERS and not from_tiktoken:
|
| 1855 |
+
converter_class = SLOW_TO_FAST_CONVERTERS[tokenizer_class_name]
|
| 1856 |
+
return converter_class(transformer_tokenizer).converted()
|
| 1857 |
+
elif transformer_tokenizer.vocab_file.endswith("tekken.json"):
|
| 1858 |
+
transformer_tokenizer.original_tokenizer = transformer_tokenizer
|
| 1859 |
+
logger.info("Converting from Mistral tekken.json")
|
| 1860 |
+
return MistralConverter(transformer_tokenizer.vocab_file).converted()
|
| 1861 |
+
else:
|
| 1862 |
+
try:
|
| 1863 |
+
logger.info("Converting from Tiktoken")
|
| 1864 |
+
return TikTokenConverter(
|
| 1865 |
+
vocab_file=transformer_tokenizer.vocab_file,
|
| 1866 |
+
additional_special_tokens=transformer_tokenizer.additional_special_tokens,
|
| 1867 |
+
).converted()
|
| 1868 |
+
except Exception:
|
| 1869 |
+
raise ValueError(
|
| 1870 |
+
f"Converting from SentencePiece and Tiktoken failed, if a converter for SentencePiece is available, provide a model path "
|
| 1871 |
+
f"with a SentencePiece tokenizer.model file."
|
| 1872 |
+
f"Currently available slow->fast converters: {list(SLOW_TO_FAST_CONVERTERS.keys())}"
|
| 1873 |
+
)
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/transformers/convert_slow_tokenizers_checkpoints_to_fast.py
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2018 The HuggingFace Inc. team.
|
| 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 |
+
"""Convert slow tokenizers checkpoints in fast (serialization format of the `tokenizers` library)"""
|
| 15 |
+
|
| 16 |
+
import argparse
|
| 17 |
+
import os
|
| 18 |
+
|
| 19 |
+
import transformers
|
| 20 |
+
|
| 21 |
+
from .convert_slow_tokenizer import SLOW_TO_FAST_CONVERTERS
|
| 22 |
+
from .utils import logging
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
logging.set_verbosity_info()
|
| 26 |
+
|
| 27 |
+
logger = logging.get_logger(__name__)
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
TOKENIZER_CLASSES = {
|
| 31 |
+
# Phi3 uses Llama tokenizer
|
| 32 |
+
name: getattr(transformers, "LlamaTokenizerFast" if name == "Phi3Tokenizer" else name + "Fast")
|
| 33 |
+
for name in SLOW_TO_FAST_CONVERTERS
|
| 34 |
+
}
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
def convert_slow_checkpoint_to_fast(tokenizer_name, checkpoint_name, dump_path, force_download):
|
| 38 |
+
if tokenizer_name is not None and tokenizer_name not in TOKENIZER_CLASSES:
|
| 39 |
+
raise ValueError(f"Unrecognized tokenizer name, should be one of {list(TOKENIZER_CLASSES.keys())}.")
|
| 40 |
+
|
| 41 |
+
if tokenizer_name is None:
|
| 42 |
+
tokenizer_names = TOKENIZER_CLASSES
|
| 43 |
+
else:
|
| 44 |
+
tokenizer_names = {tokenizer_name: getattr(transformers, tokenizer_name + "Fast")}
|
| 45 |
+
|
| 46 |
+
logger.info(f"Loading tokenizer classes: {tokenizer_names}")
|
| 47 |
+
|
| 48 |
+
for tokenizer_name in tokenizer_names:
|
| 49 |
+
tokenizer_class = TOKENIZER_CLASSES[tokenizer_name]
|
| 50 |
+
|
| 51 |
+
add_prefix = True
|
| 52 |
+
if checkpoint_name is None:
|
| 53 |
+
checkpoint_names = list(tokenizer_class.max_model_input_sizes.keys())
|
| 54 |
+
else:
|
| 55 |
+
checkpoint_names = [checkpoint_name]
|
| 56 |
+
|
| 57 |
+
logger.info(f"For tokenizer {tokenizer_class.__class__.__name__} loading checkpoints: {checkpoint_names}")
|
| 58 |
+
|
| 59 |
+
for checkpoint in checkpoint_names:
|
| 60 |
+
logger.info(f"Loading {tokenizer_class.__class__.__name__} {checkpoint}")
|
| 61 |
+
|
| 62 |
+
# Load tokenizer
|
| 63 |
+
tokenizer = tokenizer_class.from_pretrained(checkpoint, force_download=force_download)
|
| 64 |
+
|
| 65 |
+
# Save fast tokenizer
|
| 66 |
+
logger.info(f"Save fast tokenizer to {dump_path} with prefix {checkpoint} add_prefix {add_prefix}")
|
| 67 |
+
|
| 68 |
+
# For organization names we create sub-directories
|
| 69 |
+
if "/" in checkpoint:
|
| 70 |
+
checkpoint_directory, checkpoint_prefix_name = checkpoint.split("/")
|
| 71 |
+
dump_path_full = os.path.join(dump_path, checkpoint_directory)
|
| 72 |
+
elif add_prefix:
|
| 73 |
+
checkpoint_prefix_name = checkpoint
|
| 74 |
+
dump_path_full = dump_path
|
| 75 |
+
else:
|
| 76 |
+
checkpoint_prefix_name = None
|
| 77 |
+
dump_path_full = dump_path
|
| 78 |
+
|
| 79 |
+
logger.info(f"=> {dump_path_full} with prefix {checkpoint_prefix_name}, add_prefix {add_prefix}")
|
| 80 |
+
|
| 81 |
+
if checkpoint in list(tokenizer.pretrained_vocab_files_map.values())[0]:
|
| 82 |
+
file_path = list(tokenizer.pretrained_vocab_files_map.values())[0][checkpoint]
|
| 83 |
+
next_char = file_path.split(checkpoint)[-1][0]
|
| 84 |
+
if next_char == "/":
|
| 85 |
+
dump_path_full = os.path.join(dump_path_full, checkpoint_prefix_name)
|
| 86 |
+
checkpoint_prefix_name = None
|
| 87 |
+
|
| 88 |
+
logger.info(f"=> {dump_path_full} with prefix {checkpoint_prefix_name}, add_prefix {add_prefix}")
|
| 89 |
+
|
| 90 |
+
file_names = tokenizer.save_pretrained(
|
| 91 |
+
dump_path_full, legacy_format=False, filename_prefix=checkpoint_prefix_name
|
| 92 |
+
)
|
| 93 |
+
logger.info(f"=> File names {file_names}")
|
| 94 |
+
|
| 95 |
+
for file_name in file_names:
|
| 96 |
+
if not file_name.endswith("tokenizer.json"):
|
| 97 |
+
os.remove(file_name)
|
| 98 |
+
logger.info(f"=> removing {file_name}")
|
| 99 |
+
|
| 100 |
+
|
| 101 |
+
if __name__ == "__main__":
|
| 102 |
+
parser = argparse.ArgumentParser()
|
| 103 |
+
# Required parameters
|
| 104 |
+
parser.add_argument(
|
| 105 |
+
"--dump_path", default=None, type=str, required=True, help="Path to output generated fast tokenizer files."
|
| 106 |
+
)
|
| 107 |
+
parser.add_argument(
|
| 108 |
+
"--tokenizer_name",
|
| 109 |
+
default=None,
|
| 110 |
+
type=str,
|
| 111 |
+
help=(
|
| 112 |
+
f"Optional tokenizer type selected in the list of {list(TOKENIZER_CLASSES.keys())}. If not given, will "
|
| 113 |
+
"download and convert all the checkpoints from AWS."
|
| 114 |
+
),
|
| 115 |
+
)
|
| 116 |
+
parser.add_argument(
|
| 117 |
+
"--checkpoint_name",
|
| 118 |
+
default=None,
|
| 119 |
+
type=str,
|
| 120 |
+
help="Optional checkpoint name. If not given, will download and convert the canonical checkpoints from AWS.",
|
| 121 |
+
)
|
| 122 |
+
parser.add_argument(
|
| 123 |
+
"--force_download",
|
| 124 |
+
action="store_true",
|
| 125 |
+
help="Re-download checkpoints.",
|
| 126 |
+
)
|
| 127 |
+
args = parser.parse_args()
|
| 128 |
+
|
| 129 |
+
convert_slow_checkpoint_to_fast(args.tokenizer_name, args.checkpoint_name, args.dump_path, args.force_download)
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/transformers/dependency_versions_check.py
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2020 The HuggingFace 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 |
+
|
| 15 |
+
from .dependency_versions_table import deps
|
| 16 |
+
from .utils.versions import require_version, require_version_core
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
# define which module versions we always want to check at run time
|
| 20 |
+
# (usually the ones defined in `install_requires` in setup.py)
|
| 21 |
+
#
|
| 22 |
+
# order specific notes:
|
| 23 |
+
# - tqdm must be checked before tokenizers
|
| 24 |
+
|
| 25 |
+
pkgs_to_check_at_runtime = [
|
| 26 |
+
"python",
|
| 27 |
+
"tqdm",
|
| 28 |
+
"regex",
|
| 29 |
+
"requests",
|
| 30 |
+
"packaging",
|
| 31 |
+
"filelock",
|
| 32 |
+
"numpy",
|
| 33 |
+
"tokenizers",
|
| 34 |
+
"huggingface-hub",
|
| 35 |
+
"safetensors",
|
| 36 |
+
"accelerate",
|
| 37 |
+
"pyyaml",
|
| 38 |
+
]
|
| 39 |
+
|
| 40 |
+
for pkg in pkgs_to_check_at_runtime:
|
| 41 |
+
if pkg in deps:
|
| 42 |
+
if pkg == "tokenizers":
|
| 43 |
+
# must be loaded here, or else tqdm check may fail
|
| 44 |
+
from .utils import is_tokenizers_available
|
| 45 |
+
|
| 46 |
+
if not is_tokenizers_available():
|
| 47 |
+
continue # not required, check version only if installed
|
| 48 |
+
elif pkg == "accelerate":
|
| 49 |
+
# must be loaded here, or else tqdm check may fail
|
| 50 |
+
from .utils import is_accelerate_available
|
| 51 |
+
|
| 52 |
+
# Maybe switch to is_torch_available in the future here so that Accelerate is hard dep of
|
| 53 |
+
# Transformers with PyTorch
|
| 54 |
+
if not is_accelerate_available():
|
| 55 |
+
continue # not required, check version only if installed
|
| 56 |
+
|
| 57 |
+
require_version_core(deps[pkg])
|
| 58 |
+
else:
|
| 59 |
+
raise ValueError(f"can't find {pkg} in {deps.keys()}, check dependency_versions_table.py")
|
| 60 |
+
|
| 61 |
+
|
| 62 |
+
def dep_version_check(pkg, hint=None):
|
| 63 |
+
require_version(deps[pkg], hint)
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/transformers/hf_argparser.py
ADDED
|
@@ -0,0 +1,430 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2020 The HuggingFace 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 |
+
|
| 15 |
+
import dataclasses
|
| 16 |
+
import json
|
| 17 |
+
import os
|
| 18 |
+
import sys
|
| 19 |
+
import types
|
| 20 |
+
from argparse import ArgumentDefaultsHelpFormatter, ArgumentParser, ArgumentTypeError
|
| 21 |
+
from collections.abc import Iterable
|
| 22 |
+
from copy import copy
|
| 23 |
+
from enum import Enum
|
| 24 |
+
from inspect import isclass
|
| 25 |
+
from pathlib import Path
|
| 26 |
+
from typing import Any, Callable, Literal, NewType, Optional, Union, get_type_hints
|
| 27 |
+
|
| 28 |
+
import yaml
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
DataClass = NewType("DataClass", Any)
|
| 32 |
+
DataClassType = NewType("DataClassType", Any)
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
# From https://stackoverflow.com/questions/15008758/parsing-boolean-values-with-argparse
|
| 36 |
+
def string_to_bool(v):
|
| 37 |
+
if isinstance(v, bool):
|
| 38 |
+
return v
|
| 39 |
+
if v.lower() in ("yes", "true", "t", "y", "1"):
|
| 40 |
+
return True
|
| 41 |
+
elif v.lower() in ("no", "false", "f", "n", "0"):
|
| 42 |
+
return False
|
| 43 |
+
else:
|
| 44 |
+
raise ArgumentTypeError(
|
| 45 |
+
f"Truthy value expected: got {v} but expected one of yes/no, true/false, t/f, y/n, 1/0 (case insensitive)."
|
| 46 |
+
)
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
def make_choice_type_function(choices: list) -> Callable[[str], Any]:
|
| 50 |
+
"""
|
| 51 |
+
Creates a mapping function from each choices string representation to the actual value. Used to support multiple
|
| 52 |
+
value types for a single argument.
|
| 53 |
+
|
| 54 |
+
Args:
|
| 55 |
+
choices (list): List of choices.
|
| 56 |
+
|
| 57 |
+
Returns:
|
| 58 |
+
Callable[[str], Any]: Mapping function from string representation to actual value for each choice.
|
| 59 |
+
"""
|
| 60 |
+
str_to_choice = {str(choice): choice for choice in choices}
|
| 61 |
+
return lambda arg: str_to_choice.get(arg, arg)
|
| 62 |
+
|
| 63 |
+
|
| 64 |
+
def HfArg(
|
| 65 |
+
*,
|
| 66 |
+
aliases: Optional[Union[str, list[str]]] = None,
|
| 67 |
+
help: Optional[str] = None,
|
| 68 |
+
default: Any = dataclasses.MISSING,
|
| 69 |
+
default_factory: Callable[[], Any] = dataclasses.MISSING,
|
| 70 |
+
metadata: Optional[dict] = None,
|
| 71 |
+
**kwargs,
|
| 72 |
+
) -> dataclasses.Field:
|
| 73 |
+
"""Argument helper enabling a concise syntax to create dataclass fields for parsing with `HfArgumentParser`.
|
| 74 |
+
|
| 75 |
+
Example comparing the use of `HfArg` and `dataclasses.field`:
|
| 76 |
+
```
|
| 77 |
+
@dataclass
|
| 78 |
+
class Args:
|
| 79 |
+
regular_arg: str = dataclasses.field(default="Huggingface", metadata={"aliases": ["--example", "-e"], "help": "This syntax could be better!"})
|
| 80 |
+
hf_arg: str = HfArg(default="Huggingface", aliases=["--example", "-e"], help="What a nice syntax!")
|
| 81 |
+
```
|
| 82 |
+
|
| 83 |
+
Args:
|
| 84 |
+
aliases (Union[str, list[str]], optional):
|
| 85 |
+
Single string or list of strings of aliases to pass on to argparse, e.g. `aliases=["--example", "-e"]`.
|
| 86 |
+
Defaults to None.
|
| 87 |
+
help (str, optional): Help string to pass on to argparse that can be displayed with --help. Defaults to None.
|
| 88 |
+
default (Any, optional):
|
| 89 |
+
Default value for the argument. If not default or default_factory is specified, the argument is required.
|
| 90 |
+
Defaults to dataclasses.MISSING.
|
| 91 |
+
default_factory (Callable[[], Any], optional):
|
| 92 |
+
The default_factory is a 0-argument function called to initialize a field's value. It is useful to provide
|
| 93 |
+
default values for mutable types, e.g. lists: `default_factory=list`. Mutually exclusive with `default=`.
|
| 94 |
+
Defaults to dataclasses.MISSING.
|
| 95 |
+
metadata (dict, optional): Further metadata to pass on to `dataclasses.field`. Defaults to None.
|
| 96 |
+
|
| 97 |
+
Returns:
|
| 98 |
+
Field: A `dataclasses.Field` with the desired properties.
|
| 99 |
+
"""
|
| 100 |
+
if metadata is None:
|
| 101 |
+
# Important, don't use as default param in function signature because dict is mutable and shared across function calls
|
| 102 |
+
metadata = {}
|
| 103 |
+
if aliases is not None:
|
| 104 |
+
metadata["aliases"] = aliases
|
| 105 |
+
if help is not None:
|
| 106 |
+
metadata["help"] = help
|
| 107 |
+
|
| 108 |
+
return dataclasses.field(metadata=metadata, default=default, default_factory=default_factory, **kwargs)
|
| 109 |
+
|
| 110 |
+
|
| 111 |
+
class HfArgumentParser(ArgumentParser):
|
| 112 |
+
"""
|
| 113 |
+
This subclass of `argparse.ArgumentParser` uses type hints on dataclasses to generate arguments.
|
| 114 |
+
|
| 115 |
+
The class is designed to play well with the native argparse. In particular, you can add more (non-dataclass backed)
|
| 116 |
+
arguments to the parser after initialization and you'll get the output back after parsing as an additional
|
| 117 |
+
namespace. Optional: To create sub argument groups use the `_argument_group_name` attribute in the dataclass.
|
| 118 |
+
|
| 119 |
+
Args:
|
| 120 |
+
dataclass_types (`DataClassType` or `Iterable[DataClassType]`, *optional*):
|
| 121 |
+
Dataclass type, or list of dataclass types for which we will "fill" instances with the parsed args.
|
| 122 |
+
kwargs (`dict[str, Any]`, *optional*):
|
| 123 |
+
Passed to `argparse.ArgumentParser()` in the regular way.
|
| 124 |
+
"""
|
| 125 |
+
|
| 126 |
+
dataclass_types: Iterable[DataClassType]
|
| 127 |
+
|
| 128 |
+
def __init__(self, dataclass_types: Optional[Union[DataClassType, Iterable[DataClassType]]] = None, **kwargs):
|
| 129 |
+
# Make sure dataclass_types is an iterable
|
| 130 |
+
if dataclass_types is None:
|
| 131 |
+
dataclass_types = []
|
| 132 |
+
elif not isinstance(dataclass_types, Iterable):
|
| 133 |
+
dataclass_types = [dataclass_types]
|
| 134 |
+
|
| 135 |
+
# To make the default appear when using --help
|
| 136 |
+
if "formatter_class" not in kwargs:
|
| 137 |
+
kwargs["formatter_class"] = ArgumentDefaultsHelpFormatter
|
| 138 |
+
super().__init__(**kwargs)
|
| 139 |
+
if dataclasses.is_dataclass(dataclass_types):
|
| 140 |
+
dataclass_types = [dataclass_types]
|
| 141 |
+
self.dataclass_types = list(dataclass_types)
|
| 142 |
+
for dtype in self.dataclass_types:
|
| 143 |
+
self._add_dataclass_arguments(dtype)
|
| 144 |
+
|
| 145 |
+
@staticmethod
|
| 146 |
+
def _parse_dataclass_field(parser: ArgumentParser, field: dataclasses.Field):
|
| 147 |
+
# Long-option strings are conventionlly separated by hyphens rather
|
| 148 |
+
# than underscores, e.g., "--long-format" rather than "--long_format".
|
| 149 |
+
# Argparse converts hyphens to underscores so that the destination
|
| 150 |
+
# string is a valid attribute name. Hf_argparser should do the same.
|
| 151 |
+
long_options = [f"--{field.name}"]
|
| 152 |
+
if "_" in field.name:
|
| 153 |
+
long_options.append(f"--{field.name.replace('_', '-')}")
|
| 154 |
+
|
| 155 |
+
kwargs = field.metadata.copy()
|
| 156 |
+
# field.metadata is not used at all by Data Classes,
|
| 157 |
+
# it is provided as a third-party extension mechanism.
|
| 158 |
+
if isinstance(field.type, str):
|
| 159 |
+
raise RuntimeError(
|
| 160 |
+
"Unresolved type detected, which should have been done with the help of "
|
| 161 |
+
"`typing.get_type_hints` method by default"
|
| 162 |
+
)
|
| 163 |
+
|
| 164 |
+
aliases = kwargs.pop("aliases", [])
|
| 165 |
+
if isinstance(aliases, str):
|
| 166 |
+
aliases = [aliases]
|
| 167 |
+
|
| 168 |
+
origin_type = getattr(field.type, "__origin__", field.type)
|
| 169 |
+
if origin_type is Union or (hasattr(types, "UnionType") and isinstance(origin_type, types.UnionType)):
|
| 170 |
+
if str not in field.type.__args__ and (
|
| 171 |
+
len(field.type.__args__) != 2 or type(None) not in field.type.__args__
|
| 172 |
+
):
|
| 173 |
+
raise ValueError(
|
| 174 |
+
"Only `Union[X, NoneType]` (i.e., `Optional[X]`) is allowed for `Union` because"
|
| 175 |
+
" the argument parser only supports one type per argument."
|
| 176 |
+
f" Problem encountered in field '{field.name}'."
|
| 177 |
+
)
|
| 178 |
+
if type(None) not in field.type.__args__:
|
| 179 |
+
# filter `str` in Union
|
| 180 |
+
field.type = field.type.__args__[0] if field.type.__args__[1] is str else field.type.__args__[1]
|
| 181 |
+
origin_type = getattr(field.type, "__origin__", field.type)
|
| 182 |
+
elif bool not in field.type.__args__:
|
| 183 |
+
# filter `NoneType` in Union (except for `Union[bool, NoneType]`)
|
| 184 |
+
field.type = (
|
| 185 |
+
field.type.__args__[0] if isinstance(None, field.type.__args__[1]) else field.type.__args__[1]
|
| 186 |
+
)
|
| 187 |
+
origin_type = getattr(field.type, "__origin__", field.type)
|
| 188 |
+
|
| 189 |
+
# A variable to store kwargs for a boolean field, if needed
|
| 190 |
+
# so that we can init a `no_*` complement argument (see below)
|
| 191 |
+
bool_kwargs = {}
|
| 192 |
+
if origin_type is Literal or (isinstance(field.type, type) and issubclass(field.type, Enum)):
|
| 193 |
+
if origin_type is Literal:
|
| 194 |
+
kwargs["choices"] = field.type.__args__
|
| 195 |
+
else:
|
| 196 |
+
kwargs["choices"] = [x.value for x in field.type]
|
| 197 |
+
|
| 198 |
+
kwargs["type"] = make_choice_type_function(kwargs["choices"])
|
| 199 |
+
|
| 200 |
+
if field.default is not dataclasses.MISSING:
|
| 201 |
+
kwargs["default"] = field.default
|
| 202 |
+
else:
|
| 203 |
+
kwargs["required"] = True
|
| 204 |
+
elif field.type is bool or field.type == Optional[bool]:
|
| 205 |
+
# Copy the correct kwargs to use to instantiate a `no_*` complement argument below.
|
| 206 |
+
# We do not initialize it here because the `no_*` alternative must be instantiated after the real argument
|
| 207 |
+
bool_kwargs = copy(kwargs)
|
| 208 |
+
|
| 209 |
+
# Hack because type=bool in argparse does not behave as we want.
|
| 210 |
+
kwargs["type"] = string_to_bool
|
| 211 |
+
if field.type is bool or (field.default is not None and field.default is not dataclasses.MISSING):
|
| 212 |
+
# Default value is False if we have no default when of type bool.
|
| 213 |
+
default = False if field.default is dataclasses.MISSING else field.default
|
| 214 |
+
# This is the value that will get picked if we don't include --{field.name} in any way
|
| 215 |
+
kwargs["default"] = default
|
| 216 |
+
# This tells argparse we accept 0 or 1 value after --{field.name}
|
| 217 |
+
kwargs["nargs"] = "?"
|
| 218 |
+
# This is the value that will get picked if we do --{field.name} (without value)
|
| 219 |
+
kwargs["const"] = True
|
| 220 |
+
elif isclass(origin_type) and issubclass(origin_type, list):
|
| 221 |
+
kwargs["type"] = field.type.__args__[0]
|
| 222 |
+
kwargs["nargs"] = "+"
|
| 223 |
+
if field.default_factory is not dataclasses.MISSING:
|
| 224 |
+
kwargs["default"] = field.default_factory()
|
| 225 |
+
elif field.default is dataclasses.MISSING:
|
| 226 |
+
kwargs["required"] = True
|
| 227 |
+
else:
|
| 228 |
+
kwargs["type"] = field.type
|
| 229 |
+
if field.default is not dataclasses.MISSING:
|
| 230 |
+
kwargs["default"] = field.default
|
| 231 |
+
elif field.default_factory is not dataclasses.MISSING:
|
| 232 |
+
kwargs["default"] = field.default_factory()
|
| 233 |
+
else:
|
| 234 |
+
kwargs["required"] = True
|
| 235 |
+
parser.add_argument(*long_options, *aliases, **kwargs)
|
| 236 |
+
|
| 237 |
+
# Add a complement `no_*` argument for a boolean field AFTER the initial field has already been added.
|
| 238 |
+
# Order is important for arguments with the same destination!
|
| 239 |
+
# We use a copy of earlier kwargs because the original kwargs have changed a lot before reaching down
|
| 240 |
+
# here and we do not need those changes/additional keys.
|
| 241 |
+
if field.default is True and (field.type is bool or field.type == Optional[bool]):
|
| 242 |
+
bool_kwargs["default"] = False
|
| 243 |
+
parser.add_argument(
|
| 244 |
+
f"--no_{field.name}",
|
| 245 |
+
f"--no-{field.name.replace('_', '-')}",
|
| 246 |
+
action="store_false",
|
| 247 |
+
dest=field.name,
|
| 248 |
+
**bool_kwargs,
|
| 249 |
+
)
|
| 250 |
+
|
| 251 |
+
def _add_dataclass_arguments(self, dtype: DataClassType):
|
| 252 |
+
if hasattr(dtype, "_argument_group_name"):
|
| 253 |
+
parser = self.add_argument_group(dtype._argument_group_name)
|
| 254 |
+
else:
|
| 255 |
+
parser = self
|
| 256 |
+
|
| 257 |
+
try:
|
| 258 |
+
type_hints: dict[str, type] = get_type_hints(dtype)
|
| 259 |
+
except NameError:
|
| 260 |
+
raise RuntimeError(
|
| 261 |
+
f"Type resolution failed for {dtype}. Try declaring the class in global scope or "
|
| 262 |
+
"removing line of `from __future__ import annotations` which opts in Postponed "
|
| 263 |
+
"Evaluation of Annotations (PEP 563)"
|
| 264 |
+
)
|
| 265 |
+
|
| 266 |
+
for field in dataclasses.fields(dtype):
|
| 267 |
+
if not field.init:
|
| 268 |
+
continue
|
| 269 |
+
field.type = type_hints[field.name]
|
| 270 |
+
self._parse_dataclass_field(parser, field)
|
| 271 |
+
|
| 272 |
+
def parse_args_into_dataclasses(
|
| 273 |
+
self,
|
| 274 |
+
args=None,
|
| 275 |
+
return_remaining_strings=False,
|
| 276 |
+
look_for_args_file=True,
|
| 277 |
+
args_filename=None,
|
| 278 |
+
args_file_flag=None,
|
| 279 |
+
) -> tuple[DataClass, ...]:
|
| 280 |
+
"""
|
| 281 |
+
Parse command-line args into instances of the specified dataclass types.
|
| 282 |
+
|
| 283 |
+
This relies on argparse's `ArgumentParser.parse_known_args`. See the doc at:
|
| 284 |
+
docs.python.org/3/library/argparse.html#argparse.ArgumentParser.parse_args
|
| 285 |
+
|
| 286 |
+
Args:
|
| 287 |
+
args:
|
| 288 |
+
List of strings to parse. The default is taken from sys.argv. (same as argparse.ArgumentParser)
|
| 289 |
+
return_remaining_strings:
|
| 290 |
+
If true, also return a list of remaining argument strings.
|
| 291 |
+
look_for_args_file:
|
| 292 |
+
If true, will look for a ".args" file with the same base name as the entry point script for this
|
| 293 |
+
process, and will append its potential content to the command line args.
|
| 294 |
+
args_filename:
|
| 295 |
+
If not None, will uses this file instead of the ".args" file specified in the previous argument.
|
| 296 |
+
args_file_flag:
|
| 297 |
+
If not None, will look for a file in the command-line args specified with this flag. The flag can be
|
| 298 |
+
specified multiple times and precedence is determined by the order (last one wins).
|
| 299 |
+
|
| 300 |
+
Returns:
|
| 301 |
+
Tuple consisting of:
|
| 302 |
+
|
| 303 |
+
- the dataclass instances in the same order as they were passed to the initializer.abspath
|
| 304 |
+
- if applicable, an additional namespace for more (non-dataclass backed) arguments added to the parser
|
| 305 |
+
after initialization.
|
| 306 |
+
- The potential list of remaining argument strings. (same as argparse.ArgumentParser.parse_known_args)
|
| 307 |
+
"""
|
| 308 |
+
|
| 309 |
+
if args_file_flag or args_filename or (look_for_args_file and len(sys.argv)):
|
| 310 |
+
args_files = []
|
| 311 |
+
|
| 312 |
+
if args_filename:
|
| 313 |
+
args_files.append(Path(args_filename))
|
| 314 |
+
elif look_for_args_file and len(sys.argv):
|
| 315 |
+
args_files.append(Path(sys.argv[0]).with_suffix(".args"))
|
| 316 |
+
|
| 317 |
+
# args files specified via command line flag should overwrite default args files so we add them last
|
| 318 |
+
if args_file_flag:
|
| 319 |
+
# Create special parser just to extract the args_file_flag values
|
| 320 |
+
args_file_parser = ArgumentParser()
|
| 321 |
+
args_file_parser.add_argument(args_file_flag, type=str, action="append")
|
| 322 |
+
|
| 323 |
+
# Use only remaining args for further parsing (remove the args_file_flag)
|
| 324 |
+
cfg, args = args_file_parser.parse_known_args(args=args)
|
| 325 |
+
cmd_args_file_paths = vars(cfg).get(args_file_flag.lstrip("-"), None)
|
| 326 |
+
|
| 327 |
+
if cmd_args_file_paths:
|
| 328 |
+
args_files.extend([Path(p) for p in cmd_args_file_paths])
|
| 329 |
+
|
| 330 |
+
file_args = []
|
| 331 |
+
for args_file in args_files:
|
| 332 |
+
if args_file.exists():
|
| 333 |
+
file_args += args_file.read_text().split()
|
| 334 |
+
|
| 335 |
+
# in case of duplicate arguments the last one has precedence
|
| 336 |
+
# args specified via the command line should overwrite args from files, so we add them last
|
| 337 |
+
args = file_args + args if args is not None else file_args + sys.argv[1:]
|
| 338 |
+
namespace, remaining_args = self.parse_known_args(args=args)
|
| 339 |
+
outputs = []
|
| 340 |
+
for dtype in self.dataclass_types:
|
| 341 |
+
keys = {f.name for f in dataclasses.fields(dtype) if f.init}
|
| 342 |
+
inputs = {k: v for k, v in vars(namespace).items() if k in keys}
|
| 343 |
+
for k in keys:
|
| 344 |
+
delattr(namespace, k)
|
| 345 |
+
obj = dtype(**inputs)
|
| 346 |
+
outputs.append(obj)
|
| 347 |
+
if len(namespace.__dict__) > 0:
|
| 348 |
+
# additional namespace.
|
| 349 |
+
outputs.append(namespace)
|
| 350 |
+
if return_remaining_strings:
|
| 351 |
+
return (*outputs, remaining_args)
|
| 352 |
+
else:
|
| 353 |
+
if remaining_args:
|
| 354 |
+
raise ValueError(f"Some specified arguments are not used by the HfArgumentParser: {remaining_args}")
|
| 355 |
+
|
| 356 |
+
return (*outputs,)
|
| 357 |
+
|
| 358 |
+
def parse_dict(self, args: dict[str, Any], allow_extra_keys: bool = False) -> tuple[DataClass, ...]:
|
| 359 |
+
"""
|
| 360 |
+
Alternative helper method that does not use `argparse` at all, instead uses a dict and populating the dataclass
|
| 361 |
+
types.
|
| 362 |
+
|
| 363 |
+
Args:
|
| 364 |
+
args (`dict`):
|
| 365 |
+
dict containing config values
|
| 366 |
+
allow_extra_keys (`bool`, *optional*, defaults to `False`):
|
| 367 |
+
Defaults to False. If False, will raise an exception if the dict contains keys that are not parsed.
|
| 368 |
+
|
| 369 |
+
Returns:
|
| 370 |
+
Tuple consisting of:
|
| 371 |
+
|
| 372 |
+
- the dataclass instances in the same order as they were passed to the initializer.
|
| 373 |
+
"""
|
| 374 |
+
unused_keys = set(args.keys())
|
| 375 |
+
outputs = []
|
| 376 |
+
for dtype in self.dataclass_types:
|
| 377 |
+
keys = {f.name for f in dataclasses.fields(dtype) if f.init}
|
| 378 |
+
inputs = {k: v for k, v in args.items() if k in keys}
|
| 379 |
+
unused_keys.difference_update(inputs.keys())
|
| 380 |
+
obj = dtype(**inputs)
|
| 381 |
+
outputs.append(obj)
|
| 382 |
+
if not allow_extra_keys and unused_keys:
|
| 383 |
+
raise ValueError(f"Some keys are not used by the HfArgumentParser: {sorted(unused_keys)}")
|
| 384 |
+
return tuple(outputs)
|
| 385 |
+
|
| 386 |
+
def parse_json_file(
|
| 387 |
+
self, json_file: Union[str, os.PathLike], allow_extra_keys: bool = False
|
| 388 |
+
) -> tuple[DataClass, ...]:
|
| 389 |
+
"""
|
| 390 |
+
Alternative helper method that does not use `argparse` at all, instead loading a json file and populating the
|
| 391 |
+
dataclass types.
|
| 392 |
+
|
| 393 |
+
Args:
|
| 394 |
+
json_file (`str` or `os.PathLike`):
|
| 395 |
+
File name of the json file to parse
|
| 396 |
+
allow_extra_keys (`bool`, *optional*, defaults to `False`):
|
| 397 |
+
Defaults to False. If False, will raise an exception if the json file contains keys that are not
|
| 398 |
+
parsed.
|
| 399 |
+
|
| 400 |
+
Returns:
|
| 401 |
+
Tuple consisting of:
|
| 402 |
+
|
| 403 |
+
- the dataclass instances in the same order as they were passed to the initializer.
|
| 404 |
+
"""
|
| 405 |
+
with open(Path(json_file), encoding="utf-8") as open_json_file:
|
| 406 |
+
data = json.loads(open_json_file.read())
|
| 407 |
+
outputs = self.parse_dict(data, allow_extra_keys=allow_extra_keys)
|
| 408 |
+
return tuple(outputs)
|
| 409 |
+
|
| 410 |
+
def parse_yaml_file(
|
| 411 |
+
self, yaml_file: Union[str, os.PathLike], allow_extra_keys: bool = False
|
| 412 |
+
) -> tuple[DataClass, ...]:
|
| 413 |
+
"""
|
| 414 |
+
Alternative helper method that does not use `argparse` at all, instead loading a yaml file and populating the
|
| 415 |
+
dataclass types.
|
| 416 |
+
|
| 417 |
+
Args:
|
| 418 |
+
yaml_file (`str` or `os.PathLike`):
|
| 419 |
+
File name of the yaml file to parse
|
| 420 |
+
allow_extra_keys (`bool`, *optional*, defaults to `False`):
|
| 421 |
+
Defaults to False. If False, will raise an exception if the json file contains keys that are not
|
| 422 |
+
parsed.
|
| 423 |
+
|
| 424 |
+
Returns:
|
| 425 |
+
Tuple consisting of:
|
| 426 |
+
|
| 427 |
+
- the dataclass instances in the same order as they were passed to the initializer.
|
| 428 |
+
"""
|
| 429 |
+
outputs = self.parse_dict(yaml.safe_load(Path(yaml_file).read_text()), allow_extra_keys=allow_extra_keys)
|
| 430 |
+
return tuple(outputs)
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/transformers/image_processing_utils_fast.py
ADDED
|
@@ -0,0 +1,833 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 The HuggingFace Inc. team.
|
| 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 |
+
|
| 15 |
+
from collections.abc import Iterable
|
| 16 |
+
from copy import deepcopy
|
| 17 |
+
from functools import lru_cache, partial
|
| 18 |
+
from typing import Any, Optional, TypedDict, Union
|
| 19 |
+
|
| 20 |
+
import numpy as np
|
| 21 |
+
|
| 22 |
+
from .image_processing_utils import BaseImageProcessor, BatchFeature, get_size_dict
|
| 23 |
+
from .image_transforms import (
|
| 24 |
+
convert_to_rgb,
|
| 25 |
+
get_resize_output_image_size,
|
| 26 |
+
get_size_with_aspect_ratio,
|
| 27 |
+
group_images_by_shape,
|
| 28 |
+
reorder_images,
|
| 29 |
+
)
|
| 30 |
+
from .image_utils import (
|
| 31 |
+
ChannelDimension,
|
| 32 |
+
ImageInput,
|
| 33 |
+
ImageType,
|
| 34 |
+
SizeDict,
|
| 35 |
+
get_image_size,
|
| 36 |
+
get_image_size_for_max_height_width,
|
| 37 |
+
get_image_type,
|
| 38 |
+
infer_channel_dimension_format,
|
| 39 |
+
make_flat_list_of_images,
|
| 40 |
+
validate_kwargs,
|
| 41 |
+
validate_preprocess_arguments,
|
| 42 |
+
)
|
| 43 |
+
from .processing_utils import Unpack
|
| 44 |
+
from .utils import (
|
| 45 |
+
TensorType,
|
| 46 |
+
auto_docstring,
|
| 47 |
+
is_torch_available,
|
| 48 |
+
is_torchvision_available,
|
| 49 |
+
is_vision_available,
|
| 50 |
+
logging,
|
| 51 |
+
)
|
| 52 |
+
from .utils.import_utils import is_rocm_platform
|
| 53 |
+
|
| 54 |
+
|
| 55 |
+
if is_vision_available():
|
| 56 |
+
from .image_utils import PILImageResampling
|
| 57 |
+
|
| 58 |
+
if is_torch_available():
|
| 59 |
+
import torch
|
| 60 |
+
|
| 61 |
+
if is_torchvision_available():
|
| 62 |
+
from torchvision.transforms.v2 import functional as F
|
| 63 |
+
|
| 64 |
+
from .image_utils import pil_torch_interpolation_mapping
|
| 65 |
+
|
| 66 |
+
else:
|
| 67 |
+
pil_torch_interpolation_mapping = None
|
| 68 |
+
|
| 69 |
+
|
| 70 |
+
logger = logging.get_logger(__name__)
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
@lru_cache(maxsize=10)
|
| 74 |
+
def validate_fast_preprocess_arguments(
|
| 75 |
+
do_rescale: Optional[bool] = None,
|
| 76 |
+
rescale_factor: Optional[float] = None,
|
| 77 |
+
do_normalize: Optional[bool] = None,
|
| 78 |
+
image_mean: Optional[Union[float, list[float]]] = None,
|
| 79 |
+
image_std: Optional[Union[float, list[float]]] = None,
|
| 80 |
+
do_center_crop: Optional[bool] = None,
|
| 81 |
+
crop_size: Optional[SizeDict] = None,
|
| 82 |
+
do_resize: Optional[bool] = None,
|
| 83 |
+
size: Optional[SizeDict] = None,
|
| 84 |
+
interpolation: Optional["F.InterpolationMode"] = None,
|
| 85 |
+
return_tensors: Optional[Union[str, TensorType]] = None,
|
| 86 |
+
data_format: ChannelDimension = ChannelDimension.FIRST,
|
| 87 |
+
):
|
| 88 |
+
"""
|
| 89 |
+
Checks validity of typically used arguments in an `ImageProcessorFast` `preprocess` method.
|
| 90 |
+
Raises `ValueError` if arguments incompatibility is caught.
|
| 91 |
+
"""
|
| 92 |
+
validate_preprocess_arguments(
|
| 93 |
+
do_rescale=do_rescale,
|
| 94 |
+
rescale_factor=rescale_factor,
|
| 95 |
+
do_normalize=do_normalize,
|
| 96 |
+
image_mean=image_mean,
|
| 97 |
+
image_std=image_std,
|
| 98 |
+
do_center_crop=do_center_crop,
|
| 99 |
+
crop_size=crop_size,
|
| 100 |
+
do_resize=do_resize,
|
| 101 |
+
size=size,
|
| 102 |
+
interpolation=interpolation,
|
| 103 |
+
)
|
| 104 |
+
# Extra checks for ImageProcessorFast
|
| 105 |
+
if return_tensors is not None and return_tensors != "pt":
|
| 106 |
+
raise ValueError("Only returning PyTorch tensors is currently supported.")
|
| 107 |
+
|
| 108 |
+
if data_format != ChannelDimension.FIRST:
|
| 109 |
+
raise ValueError("Only channel first data format is currently supported.")
|
| 110 |
+
|
| 111 |
+
|
| 112 |
+
def safe_squeeze(tensor: "torch.Tensor", axis: Optional[int] = None) -> "torch.Tensor":
|
| 113 |
+
"""
|
| 114 |
+
Squeezes a tensor, but only if the axis specified has dim 1.
|
| 115 |
+
"""
|
| 116 |
+
if axis is None:
|
| 117 |
+
return tensor.squeeze()
|
| 118 |
+
|
| 119 |
+
try:
|
| 120 |
+
return tensor.squeeze(axis=axis)
|
| 121 |
+
except ValueError:
|
| 122 |
+
return tensor
|
| 123 |
+
|
| 124 |
+
|
| 125 |
+
def max_across_indices(values: Iterable[Any]) -> list[Any]:
|
| 126 |
+
"""
|
| 127 |
+
Return the maximum value across all indices of an iterable of values.
|
| 128 |
+
"""
|
| 129 |
+
return [max(values_i) for values_i in zip(*values)]
|
| 130 |
+
|
| 131 |
+
|
| 132 |
+
def get_max_height_width(images: list["torch.Tensor"]) -> tuple[int, ...]:
|
| 133 |
+
"""
|
| 134 |
+
Get the maximum height and width across all images in a batch.
|
| 135 |
+
"""
|
| 136 |
+
|
| 137 |
+
_, max_height, max_width = max_across_indices([img.shape for img in images])
|
| 138 |
+
|
| 139 |
+
return (max_height, max_width)
|
| 140 |
+
|
| 141 |
+
|
| 142 |
+
def divide_to_patches(
|
| 143 |
+
image: Union[np.ndarray, "torch.Tensor"], patch_size: int
|
| 144 |
+
) -> list[Union[np.ndarray, "torch.Tensor"]]:
|
| 145 |
+
"""
|
| 146 |
+
Divides an image into patches of a specified size.
|
| 147 |
+
|
| 148 |
+
Args:
|
| 149 |
+
image (`Union[np.array, "torch.Tensor"]`):
|
| 150 |
+
The input image.
|
| 151 |
+
patch_size (`int`):
|
| 152 |
+
The size of each patch.
|
| 153 |
+
Returns:
|
| 154 |
+
list: A list of Union[np.array, "torch.Tensor"] representing the patches.
|
| 155 |
+
"""
|
| 156 |
+
patches = []
|
| 157 |
+
height, width = get_image_size(image, channel_dim=ChannelDimension.FIRST)
|
| 158 |
+
for i in range(0, height, patch_size):
|
| 159 |
+
for j in range(0, width, patch_size):
|
| 160 |
+
patch = image[:, i : i + patch_size, j : j + patch_size]
|
| 161 |
+
patches.append(patch)
|
| 162 |
+
|
| 163 |
+
return patches
|
| 164 |
+
|
| 165 |
+
|
| 166 |
+
class DefaultFastImageProcessorKwargs(TypedDict, total=False):
|
| 167 |
+
do_resize: Optional[bool]
|
| 168 |
+
size: Optional[dict[str, int]]
|
| 169 |
+
default_to_square: Optional[bool]
|
| 170 |
+
resample: Optional[Union["PILImageResampling", "F.InterpolationMode"]]
|
| 171 |
+
do_center_crop: Optional[bool]
|
| 172 |
+
crop_size: Optional[dict[str, int]]
|
| 173 |
+
do_rescale: Optional[bool]
|
| 174 |
+
rescale_factor: Optional[Union[int, float]]
|
| 175 |
+
do_normalize: Optional[bool]
|
| 176 |
+
image_mean: Optional[Union[float, list[float]]]
|
| 177 |
+
image_std: Optional[Union[float, list[float]]]
|
| 178 |
+
do_pad: Optional[bool]
|
| 179 |
+
pad_size: Optional[dict[str, int]]
|
| 180 |
+
do_convert_rgb: Optional[bool]
|
| 181 |
+
return_tensors: Optional[Union[str, TensorType]]
|
| 182 |
+
data_format: Optional[ChannelDimension]
|
| 183 |
+
input_data_format: Optional[Union[str, ChannelDimension]]
|
| 184 |
+
device: Optional["torch.device"]
|
| 185 |
+
disable_grouping: Optional[bool]
|
| 186 |
+
|
| 187 |
+
|
| 188 |
+
@auto_docstring
|
| 189 |
+
class BaseImageProcessorFast(BaseImageProcessor):
|
| 190 |
+
resample = None
|
| 191 |
+
image_mean = None
|
| 192 |
+
image_std = None
|
| 193 |
+
size = None
|
| 194 |
+
default_to_square = True
|
| 195 |
+
crop_size = None
|
| 196 |
+
do_resize = None
|
| 197 |
+
do_center_crop = None
|
| 198 |
+
do_pad = None
|
| 199 |
+
pad_size = None
|
| 200 |
+
do_rescale = None
|
| 201 |
+
rescale_factor = 1 / 255
|
| 202 |
+
do_normalize = None
|
| 203 |
+
do_convert_rgb = None
|
| 204 |
+
return_tensors = None
|
| 205 |
+
data_format = ChannelDimension.FIRST
|
| 206 |
+
input_data_format = None
|
| 207 |
+
device = None
|
| 208 |
+
model_input_names = ["pixel_values"]
|
| 209 |
+
valid_kwargs = DefaultFastImageProcessorKwargs
|
| 210 |
+
unused_kwargs = None
|
| 211 |
+
|
| 212 |
+
def __init__(self, **kwargs: Unpack[DefaultFastImageProcessorKwargs]):
|
| 213 |
+
super().__init__(**kwargs)
|
| 214 |
+
kwargs = self.filter_out_unused_kwargs(kwargs)
|
| 215 |
+
size = kwargs.pop("size", self.size)
|
| 216 |
+
self.size = (
|
| 217 |
+
get_size_dict(size=size, default_to_square=kwargs.pop("default_to_square", self.default_to_square))
|
| 218 |
+
if size is not None
|
| 219 |
+
else None
|
| 220 |
+
)
|
| 221 |
+
crop_size = kwargs.pop("crop_size", self.crop_size)
|
| 222 |
+
self.crop_size = get_size_dict(crop_size, param_name="crop_size") if crop_size is not None else None
|
| 223 |
+
pad_size = kwargs.pop("pad_size", self.pad_size)
|
| 224 |
+
self.pad_size = get_size_dict(size=pad_size, param_name="pad_size") if pad_size is not None else None
|
| 225 |
+
|
| 226 |
+
for key in self.valid_kwargs.__annotations__:
|
| 227 |
+
kwarg = kwargs.pop(key, None)
|
| 228 |
+
if kwarg is not None:
|
| 229 |
+
setattr(self, key, kwarg)
|
| 230 |
+
else:
|
| 231 |
+
setattr(self, key, deepcopy(getattr(self, key, None)))
|
| 232 |
+
|
| 233 |
+
# get valid kwargs names
|
| 234 |
+
self._valid_kwargs_names = list(self.valid_kwargs.__annotations__.keys())
|
| 235 |
+
|
| 236 |
+
@property
|
| 237 |
+
def is_fast(self) -> bool:
|
| 238 |
+
"""
|
| 239 |
+
`bool`: Whether or not this image processor is a fast processor (backed by PyTorch and TorchVision).
|
| 240 |
+
"""
|
| 241 |
+
return True
|
| 242 |
+
|
| 243 |
+
def pad(
|
| 244 |
+
self,
|
| 245 |
+
images: "torch.Tensor",
|
| 246 |
+
pad_size: SizeDict = None,
|
| 247 |
+
fill_value: Optional[int] = 0,
|
| 248 |
+
padding_mode: Optional[str] = "constant",
|
| 249 |
+
return_mask: bool = False,
|
| 250 |
+
disable_grouping: Optional[bool] = False,
|
| 251 |
+
**kwargs,
|
| 252 |
+
) -> "torch.Tensor":
|
| 253 |
+
"""
|
| 254 |
+
Pads images to `(pad_size["height"], pad_size["width"])` or to the largest size in the batch.
|
| 255 |
+
|
| 256 |
+
Args:
|
| 257 |
+
images (`torch.Tensor`):
|
| 258 |
+
Images to pad.
|
| 259 |
+
pad_size (`SizeDict`, *optional*):
|
| 260 |
+
Dictionary in the format `{"height": int, "width": int}` specifying the size of the output image.
|
| 261 |
+
fill_value (`int`, *optional*, defaults to `0`):
|
| 262 |
+
The constant value used to fill the padded area.
|
| 263 |
+
padding_mode (`str`, *optional*, defaults to "constant"):
|
| 264 |
+
The padding mode to use. Can be any of the modes supported by
|
| 265 |
+
`torch.nn.functional.pad` (e.g. constant, reflection, replication).
|
| 266 |
+
return_mask (`bool`, *optional*, defaults to `False`):
|
| 267 |
+
Whether to return a pixel mask to denote padded regions.
|
| 268 |
+
disable_grouping (`bool`, *optional*, defaults to `False`):
|
| 269 |
+
Whether to disable grouping of images by size.
|
| 270 |
+
|
| 271 |
+
Returns:
|
| 272 |
+
`torch.Tensor`: The resized image.
|
| 273 |
+
"""
|
| 274 |
+
if pad_size is not None:
|
| 275 |
+
if not (pad_size.height and pad_size.width):
|
| 276 |
+
raise ValueError(f"Pad size must contain 'height' and 'width' keys only. Got pad_size={pad_size}.")
|
| 277 |
+
pad_size = (pad_size.height, pad_size.width)
|
| 278 |
+
else:
|
| 279 |
+
pad_size = get_max_height_width(images)
|
| 280 |
+
|
| 281 |
+
grouped_images, grouped_images_index = group_images_by_shape(images, disable_grouping=disable_grouping)
|
| 282 |
+
processed_images_grouped = {}
|
| 283 |
+
processed_masks_grouped = {}
|
| 284 |
+
for shape, stacked_images in grouped_images.items():
|
| 285 |
+
image_size = stacked_images.shape[-2:]
|
| 286 |
+
padding_height = pad_size[0] - image_size[0]
|
| 287 |
+
padding_width = pad_size[1] - image_size[1]
|
| 288 |
+
if padding_height < 0 or padding_width < 0:
|
| 289 |
+
raise ValueError(
|
| 290 |
+
f"Padding dimensions are negative. Please make sure that the `pad_size` is larger than the "
|
| 291 |
+
f"image size. Got pad_size={pad_size}, image_size={image_size}."
|
| 292 |
+
)
|
| 293 |
+
if image_size != pad_size:
|
| 294 |
+
padding = (0, 0, padding_width, padding_height)
|
| 295 |
+
stacked_images = F.pad(stacked_images, padding, fill=fill_value, padding_mode=padding_mode)
|
| 296 |
+
processed_images_grouped[shape] = stacked_images
|
| 297 |
+
|
| 298 |
+
if return_mask:
|
| 299 |
+
# keep only one from the channel dimension in pixel mask
|
| 300 |
+
stacked_masks = torch.zeros_like(stacked_images, dtype=torch.int64)[..., 0, :, :]
|
| 301 |
+
stacked_masks[..., : image_size[0], : image_size[1]] = 1
|
| 302 |
+
processed_masks_grouped[shape] = stacked_masks
|
| 303 |
+
|
| 304 |
+
processed_images = reorder_images(processed_images_grouped, grouped_images_index)
|
| 305 |
+
if return_mask:
|
| 306 |
+
processed_masks = reorder_images(processed_masks_grouped, grouped_images_index)
|
| 307 |
+
return processed_images, processed_masks
|
| 308 |
+
|
| 309 |
+
return processed_images
|
| 310 |
+
|
| 311 |
+
def resize(
|
| 312 |
+
self,
|
| 313 |
+
image: "torch.Tensor",
|
| 314 |
+
size: SizeDict,
|
| 315 |
+
interpolation: Optional["F.InterpolationMode"] = None,
|
| 316 |
+
antialias: bool = True,
|
| 317 |
+
**kwargs,
|
| 318 |
+
) -> "torch.Tensor":
|
| 319 |
+
"""
|
| 320 |
+
Resize an image to `(size["height"], size["width"])`.
|
| 321 |
+
|
| 322 |
+
Args:
|
| 323 |
+
image (`torch.Tensor`):
|
| 324 |
+
Image to resize.
|
| 325 |
+
size (`SizeDict`):
|
| 326 |
+
Dictionary in the format `{"height": int, "width": int}` specifying the size of the output image.
|
| 327 |
+
interpolation (`InterpolationMode`, *optional*, defaults to `InterpolationMode.BILINEAR`):
|
| 328 |
+
`InterpolationMode` filter to use when resizing the image e.g. `InterpolationMode.BICUBIC`.
|
| 329 |
+
|
| 330 |
+
Returns:
|
| 331 |
+
`torch.Tensor`: The resized image.
|
| 332 |
+
"""
|
| 333 |
+
interpolation = interpolation if interpolation is not None else F.InterpolationMode.BILINEAR
|
| 334 |
+
if size.shortest_edge and size.longest_edge:
|
| 335 |
+
# Resize the image so that the shortest edge or the longest edge is of the given size
|
| 336 |
+
# while maintaining the aspect ratio of the original image.
|
| 337 |
+
new_size = get_size_with_aspect_ratio(
|
| 338 |
+
image.size()[-2:],
|
| 339 |
+
size.shortest_edge,
|
| 340 |
+
size.longest_edge,
|
| 341 |
+
)
|
| 342 |
+
elif size.shortest_edge:
|
| 343 |
+
new_size = get_resize_output_image_size(
|
| 344 |
+
image,
|
| 345 |
+
size=size.shortest_edge,
|
| 346 |
+
default_to_square=False,
|
| 347 |
+
input_data_format=ChannelDimension.FIRST,
|
| 348 |
+
)
|
| 349 |
+
elif size.max_height and size.max_width:
|
| 350 |
+
new_size = get_image_size_for_max_height_width(image.size()[-2:], size.max_height, size.max_width)
|
| 351 |
+
elif size.height and size.width:
|
| 352 |
+
new_size = (size.height, size.width)
|
| 353 |
+
else:
|
| 354 |
+
raise ValueError(
|
| 355 |
+
"Size must contain 'height' and 'width' keys, or 'max_height' and 'max_width', or 'shortest_edge' key. Got"
|
| 356 |
+
f" {size}."
|
| 357 |
+
)
|
| 358 |
+
# This is a workaround to avoid a bug in torch.compile when dealing with uint8 on AMD MI3XX GPUs
|
| 359 |
+
# Tracked in PyTorch issue: https://github.com/pytorch/pytorch/issues/155209
|
| 360 |
+
# TODO: remove this once the bug is fixed (detected with torch==2.7.0+git1fee196, torchvision==0.22.0+9eb57cd)
|
| 361 |
+
if torch.compiler.is_compiling() and is_rocm_platform():
|
| 362 |
+
return self.compile_friendly_resize(image, new_size, interpolation, antialias)
|
| 363 |
+
return F.resize(image, new_size, interpolation=interpolation, antialias=antialias)
|
| 364 |
+
|
| 365 |
+
@staticmethod
|
| 366 |
+
def compile_friendly_resize(
|
| 367 |
+
image: "torch.Tensor",
|
| 368 |
+
new_size: tuple[int, int],
|
| 369 |
+
interpolation: Optional["F.InterpolationMode"] = None,
|
| 370 |
+
antialias: bool = True,
|
| 371 |
+
) -> "torch.Tensor":
|
| 372 |
+
"""
|
| 373 |
+
A wrapper around `F.resize` so that it is compatible with torch.compile when the image is a uint8 tensor.
|
| 374 |
+
"""
|
| 375 |
+
if image.dtype == torch.uint8:
|
| 376 |
+
# 256 is used on purpose instead of 255 to avoid numerical differences
|
| 377 |
+
# see https://github.com/huggingface/transformers/pull/38540#discussion_r2127165652
|
| 378 |
+
image = image.float() / 256
|
| 379 |
+
image = F.resize(image, new_size, interpolation=interpolation, antialias=antialias)
|
| 380 |
+
image = image * 256
|
| 381 |
+
# torch.where is used on purpose instead of torch.clamp to avoid bug in torch.compile
|
| 382 |
+
# see https://github.com/huggingface/transformers/pull/38540#discussion_r2126888471
|
| 383 |
+
image = torch.where(image > 255, 255, image)
|
| 384 |
+
image = torch.where(image < 0, 0, image)
|
| 385 |
+
image = image.round().to(torch.uint8)
|
| 386 |
+
else:
|
| 387 |
+
image = F.resize(image, new_size, interpolation=interpolation, antialias=antialias)
|
| 388 |
+
return image
|
| 389 |
+
|
| 390 |
+
def rescale(
|
| 391 |
+
self,
|
| 392 |
+
image: "torch.Tensor",
|
| 393 |
+
scale: float,
|
| 394 |
+
**kwargs,
|
| 395 |
+
) -> "torch.Tensor":
|
| 396 |
+
"""
|
| 397 |
+
Rescale an image by a scale factor. image = image * scale.
|
| 398 |
+
|
| 399 |
+
Args:
|
| 400 |
+
image (`torch.Tensor`):
|
| 401 |
+
Image to rescale.
|
| 402 |
+
scale (`float`):
|
| 403 |
+
The scaling factor to rescale pixel values by.
|
| 404 |
+
|
| 405 |
+
Returns:
|
| 406 |
+
`torch.Tensor`: The rescaled image.
|
| 407 |
+
"""
|
| 408 |
+
return image * scale
|
| 409 |
+
|
| 410 |
+
def normalize(
|
| 411 |
+
self,
|
| 412 |
+
image: "torch.Tensor",
|
| 413 |
+
mean: Union[float, Iterable[float]],
|
| 414 |
+
std: Union[float, Iterable[float]],
|
| 415 |
+
**kwargs,
|
| 416 |
+
) -> "torch.Tensor":
|
| 417 |
+
"""
|
| 418 |
+
Normalize an image. image = (image - image_mean) / image_std.
|
| 419 |
+
|
| 420 |
+
Args:
|
| 421 |
+
image (`torch.Tensor`):
|
| 422 |
+
Image to normalize.
|
| 423 |
+
mean (`torch.Tensor`, `float` or `Iterable[float]`):
|
| 424 |
+
Image mean to use for normalization.
|
| 425 |
+
std (`torch.Tensor`, `float` or `Iterable[float]`):
|
| 426 |
+
Image standard deviation to use for normalization.
|
| 427 |
+
|
| 428 |
+
Returns:
|
| 429 |
+
`torch.Tensor`: The normalized image.
|
| 430 |
+
"""
|
| 431 |
+
return F.normalize(image, mean, std)
|
| 432 |
+
|
| 433 |
+
@lru_cache(maxsize=10)
|
| 434 |
+
def _fuse_mean_std_and_rescale_factor(
|
| 435 |
+
self,
|
| 436 |
+
do_normalize: Optional[bool] = None,
|
| 437 |
+
image_mean: Optional[Union[float, list[float]]] = None,
|
| 438 |
+
image_std: Optional[Union[float, list[float]]] = None,
|
| 439 |
+
do_rescale: Optional[bool] = None,
|
| 440 |
+
rescale_factor: Optional[float] = None,
|
| 441 |
+
device: Optional["torch.device"] = None,
|
| 442 |
+
) -> tuple:
|
| 443 |
+
if do_rescale and do_normalize:
|
| 444 |
+
# Fused rescale and normalize
|
| 445 |
+
image_mean = torch.tensor(image_mean, device=device) * (1.0 / rescale_factor)
|
| 446 |
+
image_std = torch.tensor(image_std, device=device) * (1.0 / rescale_factor)
|
| 447 |
+
do_rescale = False
|
| 448 |
+
return image_mean, image_std, do_rescale
|
| 449 |
+
|
| 450 |
+
def rescale_and_normalize(
|
| 451 |
+
self,
|
| 452 |
+
images: "torch.Tensor",
|
| 453 |
+
do_rescale: bool,
|
| 454 |
+
rescale_factor: float,
|
| 455 |
+
do_normalize: bool,
|
| 456 |
+
image_mean: Union[float, list[float]],
|
| 457 |
+
image_std: Union[float, list[float]],
|
| 458 |
+
) -> "torch.Tensor":
|
| 459 |
+
"""
|
| 460 |
+
Rescale and normalize images.
|
| 461 |
+
"""
|
| 462 |
+
image_mean, image_std, do_rescale = self._fuse_mean_std_and_rescale_factor(
|
| 463 |
+
do_normalize=do_normalize,
|
| 464 |
+
image_mean=image_mean,
|
| 465 |
+
image_std=image_std,
|
| 466 |
+
do_rescale=do_rescale,
|
| 467 |
+
rescale_factor=rescale_factor,
|
| 468 |
+
device=images.device,
|
| 469 |
+
)
|
| 470 |
+
# if/elif as we use fused rescale and normalize if both are set to True
|
| 471 |
+
if do_normalize:
|
| 472 |
+
images = self.normalize(images.to(dtype=torch.float32), image_mean, image_std)
|
| 473 |
+
elif do_rescale:
|
| 474 |
+
images = self.rescale(images, rescale_factor)
|
| 475 |
+
|
| 476 |
+
return images
|
| 477 |
+
|
| 478 |
+
def center_crop(
|
| 479 |
+
self,
|
| 480 |
+
image: "torch.Tensor",
|
| 481 |
+
size: SizeDict,
|
| 482 |
+
**kwargs,
|
| 483 |
+
) -> "torch.Tensor":
|
| 484 |
+
"""
|
| 485 |
+
Note: override torchvision's center_crop to have the same behavior as the slow processor.
|
| 486 |
+
Center crop an image to `(size["height"], size["width"])`. If the input size is smaller than `crop_size` along
|
| 487 |
+
any edge, the image is padded with 0's and then center cropped.
|
| 488 |
+
|
| 489 |
+
Args:
|
| 490 |
+
image (`"torch.Tensor"`):
|
| 491 |
+
Image to center crop.
|
| 492 |
+
size (`dict[str, int]`):
|
| 493 |
+
Size of the output image.
|
| 494 |
+
|
| 495 |
+
Returns:
|
| 496 |
+
`torch.Tensor`: The center cropped image.
|
| 497 |
+
"""
|
| 498 |
+
if size.height is None or size.width is None:
|
| 499 |
+
raise ValueError(f"The size dictionary must have keys 'height' and 'width'. Got {size.keys()}")
|
| 500 |
+
image_height, image_width = image.shape[-2:]
|
| 501 |
+
crop_height, crop_width = size.height, size.width
|
| 502 |
+
|
| 503 |
+
if crop_width > image_width or crop_height > image_height:
|
| 504 |
+
padding_ltrb = [
|
| 505 |
+
(crop_width - image_width) // 2 if crop_width > image_width else 0,
|
| 506 |
+
(crop_height - image_height) // 2 if crop_height > image_height else 0,
|
| 507 |
+
(crop_width - image_width + 1) // 2 if crop_width > image_width else 0,
|
| 508 |
+
(crop_height - image_height + 1) // 2 if crop_height > image_height else 0,
|
| 509 |
+
]
|
| 510 |
+
image = F.pad(image, padding_ltrb, fill=0) # PIL uses fill value 0
|
| 511 |
+
image_height, image_width = image.shape[-2:]
|
| 512 |
+
if crop_width == image_width and crop_height == image_height:
|
| 513 |
+
return image
|
| 514 |
+
|
| 515 |
+
crop_top = int((image_height - crop_height) / 2.0)
|
| 516 |
+
crop_left = int((image_width - crop_width) / 2.0)
|
| 517 |
+
return F.crop(image, crop_top, crop_left, crop_height, crop_width)
|
| 518 |
+
|
| 519 |
+
def convert_to_rgb(
|
| 520 |
+
self,
|
| 521 |
+
image: ImageInput,
|
| 522 |
+
) -> ImageInput:
|
| 523 |
+
"""
|
| 524 |
+
Converts an image to RGB format. Only converts if the image is of type PIL.Image.Image, otherwise returns the image
|
| 525 |
+
as is.
|
| 526 |
+
Args:
|
| 527 |
+
image (ImageInput):
|
| 528 |
+
The image to convert.
|
| 529 |
+
|
| 530 |
+
Returns:
|
| 531 |
+
ImageInput: The converted image.
|
| 532 |
+
"""
|
| 533 |
+
return convert_to_rgb(image)
|
| 534 |
+
|
| 535 |
+
def filter_out_unused_kwargs(self, kwargs: dict):
|
| 536 |
+
"""
|
| 537 |
+
Filter out the unused kwargs from the kwargs dictionary.
|
| 538 |
+
"""
|
| 539 |
+
if self.unused_kwargs is None:
|
| 540 |
+
return kwargs
|
| 541 |
+
|
| 542 |
+
for kwarg_name in self.unused_kwargs:
|
| 543 |
+
if kwarg_name in kwargs:
|
| 544 |
+
logger.warning_once(f"This processor does not use the `{kwarg_name}` parameter. It will be ignored.")
|
| 545 |
+
kwargs.pop(kwarg_name)
|
| 546 |
+
return kwargs
|
| 547 |
+
|
| 548 |
+
def _prepare_images_structure(
|
| 549 |
+
self,
|
| 550 |
+
images: ImageInput,
|
| 551 |
+
expected_ndims: int = 3,
|
| 552 |
+
) -> ImageInput:
|
| 553 |
+
"""
|
| 554 |
+
Prepare the images structure for processing.
|
| 555 |
+
|
| 556 |
+
Args:
|
| 557 |
+
images (`ImageInput`):
|
| 558 |
+
The input images to process.
|
| 559 |
+
|
| 560 |
+
Returns:
|
| 561 |
+
`ImageInput`: The images with a valid nesting.
|
| 562 |
+
"""
|
| 563 |
+
# Checks for `str` in case of URL/local path and optionally loads images
|
| 564 |
+
images = self.fetch_images(images)
|
| 565 |
+
return make_flat_list_of_images(images, expected_ndims=expected_ndims)
|
| 566 |
+
|
| 567 |
+
def _process_image(
|
| 568 |
+
self,
|
| 569 |
+
image: ImageInput,
|
| 570 |
+
do_convert_rgb: Optional[bool] = None,
|
| 571 |
+
input_data_format: Optional[Union[str, ChannelDimension]] = None,
|
| 572 |
+
device: Optional["torch.device"] = None,
|
| 573 |
+
) -> "torch.Tensor":
|
| 574 |
+
image_type = get_image_type(image)
|
| 575 |
+
if image_type not in [ImageType.PIL, ImageType.TORCH, ImageType.NUMPY]:
|
| 576 |
+
raise ValueError(f"Unsupported input image type {image_type}")
|
| 577 |
+
|
| 578 |
+
if do_convert_rgb:
|
| 579 |
+
image = self.convert_to_rgb(image)
|
| 580 |
+
|
| 581 |
+
if image_type == ImageType.PIL:
|
| 582 |
+
image = F.pil_to_tensor(image)
|
| 583 |
+
elif image_type == ImageType.NUMPY:
|
| 584 |
+
# not using F.to_tensor as it doesn't handle (C, H, W) numpy arrays
|
| 585 |
+
image = torch.from_numpy(image).contiguous()
|
| 586 |
+
|
| 587 |
+
# If the image is 2D, we need to unsqueeze it to add a channel dimension for processing
|
| 588 |
+
if image.ndim == 2:
|
| 589 |
+
image = image.unsqueeze(0)
|
| 590 |
+
|
| 591 |
+
# Infer the channel dimension format if not provided
|
| 592 |
+
if input_data_format is None:
|
| 593 |
+
input_data_format = infer_channel_dimension_format(image)
|
| 594 |
+
|
| 595 |
+
if input_data_format == ChannelDimension.LAST:
|
| 596 |
+
# We force the channel dimension to be first for torch tensors as this is what torchvision expects.
|
| 597 |
+
image = image.permute(2, 0, 1).contiguous()
|
| 598 |
+
|
| 599 |
+
# Now that we have torch tensors, we can move them to the right device
|
| 600 |
+
if device is not None:
|
| 601 |
+
image = image.to(device)
|
| 602 |
+
|
| 603 |
+
return image
|
| 604 |
+
|
| 605 |
+
def _prepare_image_like_inputs(
|
| 606 |
+
self,
|
| 607 |
+
images: ImageInput,
|
| 608 |
+
do_convert_rgb: Optional[bool] = None,
|
| 609 |
+
input_data_format: Optional[Union[str, ChannelDimension]] = None,
|
| 610 |
+
device: Optional["torch.device"] = None,
|
| 611 |
+
expected_ndims: int = 3,
|
| 612 |
+
) -> list["torch.Tensor"]:
|
| 613 |
+
"""
|
| 614 |
+
Prepare image-like inputs for processing.
|
| 615 |
+
|
| 616 |
+
Args:
|
| 617 |
+
images (`ImageInput`):
|
| 618 |
+
The image-like inputs to process.
|
| 619 |
+
do_convert_rgb (`bool`, *optional*):
|
| 620 |
+
Whether to convert the images to RGB.
|
| 621 |
+
input_data_format (`str` or `ChannelDimension`, *optional*):
|
| 622 |
+
The input data format of the images.
|
| 623 |
+
device (`torch.device`, *optional*):
|
| 624 |
+
The device to put the processed images on.
|
| 625 |
+
expected_ndims (`int`, *optional*):
|
| 626 |
+
The expected number of dimensions for the images. (can be 2 for segmentation maps etc.)
|
| 627 |
+
|
| 628 |
+
Returns:
|
| 629 |
+
List[`torch.Tensor`]: The processed images.
|
| 630 |
+
"""
|
| 631 |
+
|
| 632 |
+
# Get structured images (potentially nested)
|
| 633 |
+
images = self._prepare_images_structure(images, expected_ndims=expected_ndims)
|
| 634 |
+
|
| 635 |
+
process_image_partial = partial(
|
| 636 |
+
self._process_image, do_convert_rgb=do_convert_rgb, input_data_format=input_data_format, device=device
|
| 637 |
+
)
|
| 638 |
+
|
| 639 |
+
# Check if we have nested structure, assuming the nesting is consistent
|
| 640 |
+
has_nested_structure = len(images) > 0 and isinstance(images[0], (list, tuple))
|
| 641 |
+
|
| 642 |
+
if has_nested_structure:
|
| 643 |
+
processed_images = [[process_image_partial(img) for img in nested_list] for nested_list in images]
|
| 644 |
+
else:
|
| 645 |
+
processed_images = [process_image_partial(img) for img in images]
|
| 646 |
+
|
| 647 |
+
return processed_images
|
| 648 |
+
|
| 649 |
+
def _further_process_kwargs(
|
| 650 |
+
self,
|
| 651 |
+
size: Optional[SizeDict] = None,
|
| 652 |
+
crop_size: Optional[SizeDict] = None,
|
| 653 |
+
pad_size: Optional[SizeDict] = None,
|
| 654 |
+
default_to_square: Optional[bool] = None,
|
| 655 |
+
image_mean: Optional[Union[float, list[float]]] = None,
|
| 656 |
+
image_std: Optional[Union[float, list[float]]] = None,
|
| 657 |
+
data_format: Optional[ChannelDimension] = None,
|
| 658 |
+
**kwargs,
|
| 659 |
+
) -> dict:
|
| 660 |
+
"""
|
| 661 |
+
Update kwargs that need further processing before being validated
|
| 662 |
+
Can be overridden by subclasses to customize the processing of kwargs.
|
| 663 |
+
"""
|
| 664 |
+
if kwargs is None:
|
| 665 |
+
kwargs = {}
|
| 666 |
+
if size is not None:
|
| 667 |
+
size = SizeDict(**get_size_dict(size=size, default_to_square=default_to_square))
|
| 668 |
+
if crop_size is not None:
|
| 669 |
+
crop_size = SizeDict(**get_size_dict(crop_size, param_name="crop_size"))
|
| 670 |
+
if pad_size is not None:
|
| 671 |
+
pad_size = SizeDict(**get_size_dict(size=pad_size, param_name="pad_size"))
|
| 672 |
+
if isinstance(image_mean, list):
|
| 673 |
+
image_mean = tuple(image_mean)
|
| 674 |
+
if isinstance(image_std, list):
|
| 675 |
+
image_std = tuple(image_std)
|
| 676 |
+
if data_format is None:
|
| 677 |
+
data_format = ChannelDimension.FIRST
|
| 678 |
+
|
| 679 |
+
kwargs["size"] = size
|
| 680 |
+
kwargs["crop_size"] = crop_size
|
| 681 |
+
kwargs["pad_size"] = pad_size
|
| 682 |
+
kwargs["image_mean"] = image_mean
|
| 683 |
+
kwargs["image_std"] = image_std
|
| 684 |
+
kwargs["data_format"] = data_format
|
| 685 |
+
|
| 686 |
+
# torch resize uses interpolation instead of resample
|
| 687 |
+
# Check if resample is an int before checking if it's an instance of PILImageResampling
|
| 688 |
+
# because if pillow < 9.1.0, resample is an int and PILImageResampling is a module.
|
| 689 |
+
# Checking PILImageResampling will fail with error `TypeError: isinstance() arg 2 must be a type or tuple of types`.
|
| 690 |
+
resample = kwargs.pop("resample")
|
| 691 |
+
kwargs["interpolation"] = (
|
| 692 |
+
pil_torch_interpolation_mapping[resample] if isinstance(resample, (PILImageResampling, int)) else resample
|
| 693 |
+
)
|
| 694 |
+
|
| 695 |
+
return kwargs
|
| 696 |
+
|
| 697 |
+
def _validate_preprocess_kwargs(
|
| 698 |
+
self,
|
| 699 |
+
do_rescale: Optional[bool] = None,
|
| 700 |
+
rescale_factor: Optional[float] = None,
|
| 701 |
+
do_normalize: Optional[bool] = None,
|
| 702 |
+
image_mean: Optional[Union[float, tuple[float]]] = None,
|
| 703 |
+
image_std: Optional[Union[float, tuple[float]]] = None,
|
| 704 |
+
do_resize: Optional[bool] = None,
|
| 705 |
+
size: Optional[SizeDict] = None,
|
| 706 |
+
do_center_crop: Optional[bool] = None,
|
| 707 |
+
crop_size: Optional[SizeDict] = None,
|
| 708 |
+
interpolation: Optional["F.InterpolationMode"] = None,
|
| 709 |
+
return_tensors: Optional[Union[str, TensorType]] = None,
|
| 710 |
+
data_format: Optional[ChannelDimension] = None,
|
| 711 |
+
**kwargs,
|
| 712 |
+
):
|
| 713 |
+
"""
|
| 714 |
+
validate the kwargs for the preprocess method.
|
| 715 |
+
"""
|
| 716 |
+
validate_fast_preprocess_arguments(
|
| 717 |
+
do_rescale=do_rescale,
|
| 718 |
+
rescale_factor=rescale_factor,
|
| 719 |
+
do_normalize=do_normalize,
|
| 720 |
+
image_mean=image_mean,
|
| 721 |
+
image_std=image_std,
|
| 722 |
+
do_resize=do_resize,
|
| 723 |
+
size=size,
|
| 724 |
+
do_center_crop=do_center_crop,
|
| 725 |
+
crop_size=crop_size,
|
| 726 |
+
interpolation=interpolation,
|
| 727 |
+
return_tensors=return_tensors,
|
| 728 |
+
data_format=data_format,
|
| 729 |
+
)
|
| 730 |
+
|
| 731 |
+
def __call__(self, images: ImageInput, *args, **kwargs: Unpack[DefaultFastImageProcessorKwargs]) -> BatchFeature:
|
| 732 |
+
return self.preprocess(images, *args, **kwargs)
|
| 733 |
+
|
| 734 |
+
@auto_docstring
|
| 735 |
+
def preprocess(self, images: ImageInput, *args, **kwargs: Unpack[DefaultFastImageProcessorKwargs]) -> BatchFeature:
|
| 736 |
+
# args are not validated, but their order in the `preprocess` and `_preprocess` signatures must be the same
|
| 737 |
+
validate_kwargs(captured_kwargs=kwargs.keys(), valid_processor_keys=self._valid_kwargs_names)
|
| 738 |
+
# Set default kwargs from self. This ensures that if a kwarg is not provided
|
| 739 |
+
# by the user, it gets its default value from the instance, or is set to None.
|
| 740 |
+
for kwarg_name in self._valid_kwargs_names:
|
| 741 |
+
kwargs.setdefault(kwarg_name, getattr(self, kwarg_name, None))
|
| 742 |
+
|
| 743 |
+
# Extract parameters that are only used for preparing the input images
|
| 744 |
+
do_convert_rgb = kwargs.pop("do_convert_rgb")
|
| 745 |
+
input_data_format = kwargs.pop("input_data_format")
|
| 746 |
+
device = kwargs.pop("device")
|
| 747 |
+
|
| 748 |
+
# Update kwargs that need further processing before being validated
|
| 749 |
+
kwargs = self._further_process_kwargs(**kwargs)
|
| 750 |
+
|
| 751 |
+
# Validate kwargs
|
| 752 |
+
self._validate_preprocess_kwargs(**kwargs)
|
| 753 |
+
|
| 754 |
+
# Pop kwargs that are not needed in _preprocess
|
| 755 |
+
kwargs.pop("data_format")
|
| 756 |
+
|
| 757 |
+
return self._preprocess_image_like_inputs(
|
| 758 |
+
images, *args, do_convert_rgb=do_convert_rgb, input_data_format=input_data_format, device=device, **kwargs
|
| 759 |
+
)
|
| 760 |
+
|
| 761 |
+
def _preprocess_image_like_inputs(
|
| 762 |
+
self,
|
| 763 |
+
images: ImageInput,
|
| 764 |
+
*args,
|
| 765 |
+
do_convert_rgb: bool,
|
| 766 |
+
input_data_format: ChannelDimension,
|
| 767 |
+
device: Optional[Union[str, "torch.device"]] = None,
|
| 768 |
+
**kwargs: Unpack[DefaultFastImageProcessorKwargs],
|
| 769 |
+
) -> BatchFeature:
|
| 770 |
+
"""
|
| 771 |
+
Preprocess image-like inputs.
|
| 772 |
+
To be overridden by subclasses when image-like inputs other than images should be processed.
|
| 773 |
+
It can be used for segmentation maps, depth maps, etc.
|
| 774 |
+
"""
|
| 775 |
+
# Prepare input images
|
| 776 |
+
images = self._prepare_image_like_inputs(
|
| 777 |
+
images=images, do_convert_rgb=do_convert_rgb, input_data_format=input_data_format, device=device
|
| 778 |
+
)
|
| 779 |
+
return self._preprocess(images, *args, **kwargs)
|
| 780 |
+
|
| 781 |
+
def _preprocess(
|
| 782 |
+
self,
|
| 783 |
+
images: list["torch.Tensor"],
|
| 784 |
+
do_resize: bool,
|
| 785 |
+
size: SizeDict,
|
| 786 |
+
interpolation: Optional["F.InterpolationMode"],
|
| 787 |
+
do_center_crop: bool,
|
| 788 |
+
crop_size: SizeDict,
|
| 789 |
+
do_rescale: bool,
|
| 790 |
+
rescale_factor: float,
|
| 791 |
+
do_normalize: bool,
|
| 792 |
+
image_mean: Optional[Union[float, list[float]]],
|
| 793 |
+
image_std: Optional[Union[float, list[float]]],
|
| 794 |
+
do_pad: Optional[bool],
|
| 795 |
+
pad_size: Optional[SizeDict],
|
| 796 |
+
disable_grouping: Optional[bool],
|
| 797 |
+
return_tensors: Optional[Union[str, TensorType]],
|
| 798 |
+
**kwargs,
|
| 799 |
+
) -> BatchFeature:
|
| 800 |
+
# Group images by size for batched resizing
|
| 801 |
+
grouped_images, grouped_images_index = group_images_by_shape(images, disable_grouping=disable_grouping)
|
| 802 |
+
resized_images_grouped = {}
|
| 803 |
+
for shape, stacked_images in grouped_images.items():
|
| 804 |
+
if do_resize:
|
| 805 |
+
stacked_images = self.resize(image=stacked_images, size=size, interpolation=interpolation)
|
| 806 |
+
resized_images_grouped[shape] = stacked_images
|
| 807 |
+
resized_images = reorder_images(resized_images_grouped, grouped_images_index)
|
| 808 |
+
|
| 809 |
+
# Group images by size for further processing
|
| 810 |
+
# Needed in case do_resize is False, or resize returns images with different sizes
|
| 811 |
+
grouped_images, grouped_images_index = group_images_by_shape(resized_images, disable_grouping=disable_grouping)
|
| 812 |
+
processed_images_grouped = {}
|
| 813 |
+
for shape, stacked_images in grouped_images.items():
|
| 814 |
+
if do_center_crop:
|
| 815 |
+
stacked_images = self.center_crop(stacked_images, crop_size)
|
| 816 |
+
# Fused rescale and normalize
|
| 817 |
+
stacked_images = self.rescale_and_normalize(
|
| 818 |
+
stacked_images, do_rescale, rescale_factor, do_normalize, image_mean, image_std
|
| 819 |
+
)
|
| 820 |
+
processed_images_grouped[shape] = stacked_images
|
| 821 |
+
processed_images = reorder_images(processed_images_grouped, grouped_images_index)
|
| 822 |
+
|
| 823 |
+
if do_pad:
|
| 824 |
+
processed_images = self.pad(processed_images, pad_size=pad_size, disable_grouping=disable_grouping)
|
| 825 |
+
|
| 826 |
+
processed_images = torch.stack(processed_images, dim=0) if return_tensors else processed_images
|
| 827 |
+
return BatchFeature(data={"pixel_values": processed_images}, tensor_type=return_tensors)
|
| 828 |
+
|
| 829 |
+
def to_dict(self):
|
| 830 |
+
encoder_dict = super().to_dict()
|
| 831 |
+
encoder_dict.pop("_valid_processor_keys", None)
|
| 832 |
+
encoder_dict.pop("_valid_kwargs_names", None)
|
| 833 |
+
return encoder_dict
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/transformers/image_transforms.py
ADDED
|
@@ -0,0 +1,977 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2022 The HuggingFace Inc. team.
|
| 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 |
+
|
| 15 |
+
from collections import defaultdict
|
| 16 |
+
from collections.abc import Collection, Iterable
|
| 17 |
+
from math import ceil
|
| 18 |
+
from typing import Optional, Union
|
| 19 |
+
|
| 20 |
+
import numpy as np
|
| 21 |
+
|
| 22 |
+
from .image_utils import (
|
| 23 |
+
ChannelDimension,
|
| 24 |
+
ImageInput,
|
| 25 |
+
get_channel_dimension_axis,
|
| 26 |
+
get_image_size,
|
| 27 |
+
infer_channel_dimension_format,
|
| 28 |
+
)
|
| 29 |
+
from .utils import ExplicitEnum, TensorType, is_jax_tensor, is_tf_tensor, is_torch_tensor
|
| 30 |
+
from .utils.import_utils import (
|
| 31 |
+
is_flax_available,
|
| 32 |
+
is_tf_available,
|
| 33 |
+
is_torch_available,
|
| 34 |
+
is_vision_available,
|
| 35 |
+
requires_backends,
|
| 36 |
+
)
|
| 37 |
+
|
| 38 |
+
|
| 39 |
+
if is_vision_available():
|
| 40 |
+
import PIL
|
| 41 |
+
|
| 42 |
+
from .image_utils import PILImageResampling
|
| 43 |
+
|
| 44 |
+
if is_torch_available():
|
| 45 |
+
import torch
|
| 46 |
+
|
| 47 |
+
if is_tf_available():
|
| 48 |
+
import tensorflow as tf
|
| 49 |
+
|
| 50 |
+
if is_flax_available():
|
| 51 |
+
import jax.numpy as jnp
|
| 52 |
+
|
| 53 |
+
|
| 54 |
+
def to_channel_dimension_format(
|
| 55 |
+
image: np.ndarray,
|
| 56 |
+
channel_dim: Union[ChannelDimension, str],
|
| 57 |
+
input_channel_dim: Optional[Union[ChannelDimension, str]] = None,
|
| 58 |
+
) -> np.ndarray:
|
| 59 |
+
"""
|
| 60 |
+
Converts `image` to the channel dimension format specified by `channel_dim`. The input
|
| 61 |
+
can have arbitrary number of leading dimensions. Only last three dimension will be permuted
|
| 62 |
+
to format the `image`.
|
| 63 |
+
|
| 64 |
+
Args:
|
| 65 |
+
image (`numpy.ndarray`):
|
| 66 |
+
The image to have its channel dimension set.
|
| 67 |
+
channel_dim (`ChannelDimension`):
|
| 68 |
+
The channel dimension format to use.
|
| 69 |
+
input_channel_dim (`ChannelDimension`, *optional*):
|
| 70 |
+
The channel dimension format of the input image. If not provided, it will be inferred from the input image.
|
| 71 |
+
|
| 72 |
+
Returns:
|
| 73 |
+
`np.ndarray`: The image with the channel dimension set to `channel_dim`.
|
| 74 |
+
"""
|
| 75 |
+
if not isinstance(image, np.ndarray):
|
| 76 |
+
raise TypeError(f"Input image must be of type np.ndarray, got {type(image)}")
|
| 77 |
+
|
| 78 |
+
if input_channel_dim is None:
|
| 79 |
+
input_channel_dim = infer_channel_dimension_format(image)
|
| 80 |
+
|
| 81 |
+
target_channel_dim = ChannelDimension(channel_dim)
|
| 82 |
+
if input_channel_dim == target_channel_dim:
|
| 83 |
+
return image
|
| 84 |
+
|
| 85 |
+
if target_channel_dim == ChannelDimension.FIRST:
|
| 86 |
+
axes = list(range(image.ndim - 3)) + [image.ndim - 1, image.ndim - 3, image.ndim - 2]
|
| 87 |
+
image = image.transpose(axes)
|
| 88 |
+
elif target_channel_dim == ChannelDimension.LAST:
|
| 89 |
+
axes = list(range(image.ndim - 3)) + [image.ndim - 2, image.ndim - 1, image.ndim - 3]
|
| 90 |
+
image = image.transpose(axes)
|
| 91 |
+
else:
|
| 92 |
+
raise ValueError(f"Unsupported channel dimension format: {channel_dim}")
|
| 93 |
+
|
| 94 |
+
return image
|
| 95 |
+
|
| 96 |
+
|
| 97 |
+
def rescale(
|
| 98 |
+
image: np.ndarray,
|
| 99 |
+
scale: float,
|
| 100 |
+
data_format: Optional[ChannelDimension] = None,
|
| 101 |
+
dtype: np.dtype = np.float32,
|
| 102 |
+
input_data_format: Optional[Union[str, ChannelDimension]] = None,
|
| 103 |
+
) -> np.ndarray:
|
| 104 |
+
"""
|
| 105 |
+
Rescales `image` by `scale`.
|
| 106 |
+
|
| 107 |
+
Args:
|
| 108 |
+
image (`np.ndarray`):
|
| 109 |
+
The image to rescale.
|
| 110 |
+
scale (`float`):
|
| 111 |
+
The scale to use for rescaling the image.
|
| 112 |
+
data_format (`ChannelDimension`, *optional*):
|
| 113 |
+
The channel dimension format of the image. If not provided, it will be the same as the input image.
|
| 114 |
+
dtype (`np.dtype`, *optional*, defaults to `np.float32`):
|
| 115 |
+
The dtype of the output image. Defaults to `np.float32`. Used for backwards compatibility with feature
|
| 116 |
+
extractors.
|
| 117 |
+
input_data_format (`ChannelDimension`, *optional*):
|
| 118 |
+
The channel dimension format of the input image. If not provided, it will be inferred from the input image.
|
| 119 |
+
|
| 120 |
+
Returns:
|
| 121 |
+
`np.ndarray`: The rescaled image.
|
| 122 |
+
"""
|
| 123 |
+
if not isinstance(image, np.ndarray):
|
| 124 |
+
raise TypeError(f"Input image must be of type np.ndarray, got {type(image)}")
|
| 125 |
+
|
| 126 |
+
rescaled_image = image.astype(np.float64) * scale # Numpy type promotion has changed, so always upcast first
|
| 127 |
+
if data_format is not None:
|
| 128 |
+
rescaled_image = to_channel_dimension_format(rescaled_image, data_format, input_data_format)
|
| 129 |
+
|
| 130 |
+
rescaled_image = rescaled_image.astype(dtype) # Finally downcast to the desired dtype at the end
|
| 131 |
+
|
| 132 |
+
return rescaled_image
|
| 133 |
+
|
| 134 |
+
|
| 135 |
+
def _rescale_for_pil_conversion(image):
|
| 136 |
+
"""
|
| 137 |
+
Detects whether or not the image needs to be rescaled before being converted to a PIL image.
|
| 138 |
+
|
| 139 |
+
The assumption is that if the image is of type `np.float` and all values are between 0 and 1, it needs to be
|
| 140 |
+
rescaled.
|
| 141 |
+
"""
|
| 142 |
+
if image.dtype == np.uint8:
|
| 143 |
+
do_rescale = False
|
| 144 |
+
elif np.allclose(image, image.astype(int)):
|
| 145 |
+
if np.all(0 <= image) and np.all(image <= 255):
|
| 146 |
+
do_rescale = False
|
| 147 |
+
else:
|
| 148 |
+
raise ValueError(
|
| 149 |
+
"The image to be converted to a PIL image contains values outside the range [0, 255], "
|
| 150 |
+
f"got [{image.min()}, {image.max()}] which cannot be converted to uint8."
|
| 151 |
+
)
|
| 152 |
+
elif np.all(0 <= image) and np.all(image <= 1):
|
| 153 |
+
do_rescale = True
|
| 154 |
+
else:
|
| 155 |
+
raise ValueError(
|
| 156 |
+
"The image to be converted to a PIL image contains values outside the range [0, 1], "
|
| 157 |
+
f"got [{image.min()}, {image.max()}] which cannot be converted to uint8."
|
| 158 |
+
)
|
| 159 |
+
return do_rescale
|
| 160 |
+
|
| 161 |
+
|
| 162 |
+
def to_pil_image(
|
| 163 |
+
image: Union[np.ndarray, "PIL.Image.Image", "torch.Tensor", "tf.Tensor", "jnp.ndarray"],
|
| 164 |
+
do_rescale: Optional[bool] = None,
|
| 165 |
+
image_mode: Optional[str] = None,
|
| 166 |
+
input_data_format: Optional[Union[str, ChannelDimension]] = None,
|
| 167 |
+
) -> "PIL.Image.Image":
|
| 168 |
+
"""
|
| 169 |
+
Converts `image` to a PIL Image. Optionally rescales it and puts the channel dimension back as the last axis if
|
| 170 |
+
needed.
|
| 171 |
+
|
| 172 |
+
Args:
|
| 173 |
+
image (`PIL.Image.Image` or `numpy.ndarray` or `torch.Tensor` or `tf.Tensor`):
|
| 174 |
+
The image to convert to the `PIL.Image` format.
|
| 175 |
+
do_rescale (`bool`, *optional*):
|
| 176 |
+
Whether or not to apply the scaling factor (to make pixel values integers between 0 and 255). Will default
|
| 177 |
+
to `True` if the image type is a floating type and casting to `int` would result in a loss of precision,
|
| 178 |
+
and `False` otherwise.
|
| 179 |
+
image_mode (`str`, *optional*):
|
| 180 |
+
The mode to use for the PIL image. If unset, will use the default mode for the input image type.
|
| 181 |
+
input_data_format (`ChannelDimension`, *optional*):
|
| 182 |
+
The channel dimension format of the input image. If unset, will use the inferred format from the input.
|
| 183 |
+
|
| 184 |
+
Returns:
|
| 185 |
+
`PIL.Image.Image`: The converted image.
|
| 186 |
+
"""
|
| 187 |
+
requires_backends(to_pil_image, ["vision"])
|
| 188 |
+
|
| 189 |
+
if isinstance(image, PIL.Image.Image):
|
| 190 |
+
return image
|
| 191 |
+
|
| 192 |
+
# Convert all tensors to numpy arrays before converting to PIL image
|
| 193 |
+
if is_torch_tensor(image) or is_tf_tensor(image):
|
| 194 |
+
image = image.numpy()
|
| 195 |
+
elif is_jax_tensor(image):
|
| 196 |
+
image = np.array(image)
|
| 197 |
+
elif not isinstance(image, np.ndarray):
|
| 198 |
+
raise ValueError(f"Input image type not supported: {type(image)}")
|
| 199 |
+
|
| 200 |
+
# If the channel has been moved to first dim, we put it back at the end.
|
| 201 |
+
image = to_channel_dimension_format(image, ChannelDimension.LAST, input_data_format)
|
| 202 |
+
|
| 203 |
+
# If there is a single channel, we squeeze it, as otherwise PIL can't handle it.
|
| 204 |
+
image = np.squeeze(image, axis=-1) if image.shape[-1] == 1 else image
|
| 205 |
+
|
| 206 |
+
# PIL.Image can only store uint8 values so we rescale the image to be between 0 and 255 if needed.
|
| 207 |
+
do_rescale = _rescale_for_pil_conversion(image) if do_rescale is None else do_rescale
|
| 208 |
+
|
| 209 |
+
if do_rescale:
|
| 210 |
+
image = rescale(image, 255)
|
| 211 |
+
|
| 212 |
+
image = image.astype(np.uint8)
|
| 213 |
+
return PIL.Image.fromarray(image, mode=image_mode)
|
| 214 |
+
|
| 215 |
+
|
| 216 |
+
def get_size_with_aspect_ratio(image_size, size, max_size=None) -> tuple[int, int]:
|
| 217 |
+
"""
|
| 218 |
+
Computes the output image size given the input image size and the desired output size.
|
| 219 |
+
|
| 220 |
+
Args:
|
| 221 |
+
image_size (`tuple[int, int]`):
|
| 222 |
+
The input image size.
|
| 223 |
+
size (`int`):
|
| 224 |
+
The desired output size.
|
| 225 |
+
max_size (`int`, *optional*):
|
| 226 |
+
The maximum allowed output size.
|
| 227 |
+
"""
|
| 228 |
+
height, width = image_size
|
| 229 |
+
raw_size = None
|
| 230 |
+
if max_size is not None:
|
| 231 |
+
min_original_size = float(min((height, width)))
|
| 232 |
+
max_original_size = float(max((height, width)))
|
| 233 |
+
if max_original_size / min_original_size * size > max_size:
|
| 234 |
+
raw_size = max_size * min_original_size / max_original_size
|
| 235 |
+
size = int(round(raw_size))
|
| 236 |
+
|
| 237 |
+
if (height <= width and height == size) or (width <= height and width == size):
|
| 238 |
+
oh, ow = height, width
|
| 239 |
+
elif width < height:
|
| 240 |
+
ow = size
|
| 241 |
+
if max_size is not None and raw_size is not None:
|
| 242 |
+
oh = int(raw_size * height / width)
|
| 243 |
+
else:
|
| 244 |
+
oh = int(size * height / width)
|
| 245 |
+
else:
|
| 246 |
+
oh = size
|
| 247 |
+
if max_size is not None and raw_size is not None:
|
| 248 |
+
ow = int(raw_size * width / height)
|
| 249 |
+
else:
|
| 250 |
+
ow = int(size * width / height)
|
| 251 |
+
|
| 252 |
+
return (oh, ow)
|
| 253 |
+
|
| 254 |
+
|
| 255 |
+
# Logic adapted from torchvision resizing logic: https://github.com/pytorch/vision/blob/511924c1ced4ce0461197e5caa64ce5b9e558aab/torchvision/transforms/functional.py#L366
|
| 256 |
+
def get_resize_output_image_size(
|
| 257 |
+
input_image: np.ndarray,
|
| 258 |
+
size: Union[int, tuple[int, int], list[int], tuple[int, ...]],
|
| 259 |
+
default_to_square: bool = True,
|
| 260 |
+
max_size: Optional[int] = None,
|
| 261 |
+
input_data_format: Optional[Union[str, ChannelDimension]] = None,
|
| 262 |
+
) -> tuple:
|
| 263 |
+
"""
|
| 264 |
+
Find the target (height, width) dimension of the output image after resizing given the input image and the desired
|
| 265 |
+
size.
|
| 266 |
+
|
| 267 |
+
Args:
|
| 268 |
+
input_image (`np.ndarray`):
|
| 269 |
+
The image to resize.
|
| 270 |
+
size (`int` or `tuple[int, int]` or list[int] or `tuple[int]`):
|
| 271 |
+
The size to use for resizing the image. If `size` is a sequence like (h, w), output size will be matched to
|
| 272 |
+
this.
|
| 273 |
+
|
| 274 |
+
If `size` is an int and `default_to_square` is `True`, then image will be resized to (size, size). If
|
| 275 |
+
`size` is an int and `default_to_square` is `False`, then smaller edge of the image will be matched to this
|
| 276 |
+
number. i.e, if height > width, then image will be rescaled to (size * height / width, size).
|
| 277 |
+
default_to_square (`bool`, *optional*, defaults to `True`):
|
| 278 |
+
How to convert `size` when it is a single int. If set to `True`, the `size` will be converted to a square
|
| 279 |
+
(`size`,`size`). If set to `False`, will replicate
|
| 280 |
+
[`torchvision.transforms.Resize`](https://pytorch.org/vision/stable/transforms.html#torchvision.transforms.Resize)
|
| 281 |
+
with support for resizing only the smallest edge and providing an optional `max_size`.
|
| 282 |
+
max_size (`int`, *optional*):
|
| 283 |
+
The maximum allowed for the longer edge of the resized image: if the longer edge of the image is greater
|
| 284 |
+
than `max_size` after being resized according to `size`, then the image is resized again so that the longer
|
| 285 |
+
edge is equal to `max_size`. As a result, `size` might be overruled, i.e the smaller edge may be shorter
|
| 286 |
+
than `size`. Only used if `default_to_square` is `False`.
|
| 287 |
+
input_data_format (`ChannelDimension`, *optional*):
|
| 288 |
+
The channel dimension format of the input image. If unset, will use the inferred format from the input.
|
| 289 |
+
|
| 290 |
+
Returns:
|
| 291 |
+
`tuple`: The target (height, width) dimension of the output image after resizing.
|
| 292 |
+
"""
|
| 293 |
+
if isinstance(size, (tuple, list)):
|
| 294 |
+
if len(size) == 2:
|
| 295 |
+
return tuple(size)
|
| 296 |
+
elif len(size) == 1:
|
| 297 |
+
# Perform same logic as if size was an int
|
| 298 |
+
size = size[0]
|
| 299 |
+
else:
|
| 300 |
+
raise ValueError("size must have 1 or 2 elements if it is a list or tuple")
|
| 301 |
+
|
| 302 |
+
if default_to_square:
|
| 303 |
+
return (size, size)
|
| 304 |
+
|
| 305 |
+
height, width = get_image_size(input_image, input_data_format)
|
| 306 |
+
short, long = (width, height) if width <= height else (height, width)
|
| 307 |
+
requested_new_short = size
|
| 308 |
+
|
| 309 |
+
new_short, new_long = requested_new_short, int(requested_new_short * long / short)
|
| 310 |
+
|
| 311 |
+
if max_size is not None:
|
| 312 |
+
if max_size <= requested_new_short:
|
| 313 |
+
raise ValueError(
|
| 314 |
+
f"max_size = {max_size} must be strictly greater than the requested "
|
| 315 |
+
f"size for the smaller edge size = {size}"
|
| 316 |
+
)
|
| 317 |
+
if new_long > max_size:
|
| 318 |
+
new_short, new_long = int(max_size * new_short / new_long), max_size
|
| 319 |
+
|
| 320 |
+
return (new_long, new_short) if width <= height else (new_short, new_long)
|
| 321 |
+
|
| 322 |
+
|
| 323 |
+
def resize(
|
| 324 |
+
image: np.ndarray,
|
| 325 |
+
size: tuple[int, int],
|
| 326 |
+
resample: Optional["PILImageResampling"] = None,
|
| 327 |
+
reducing_gap: Optional[int] = None,
|
| 328 |
+
data_format: Optional[ChannelDimension] = None,
|
| 329 |
+
return_numpy: bool = True,
|
| 330 |
+
input_data_format: Optional[Union[str, ChannelDimension]] = None,
|
| 331 |
+
) -> np.ndarray:
|
| 332 |
+
"""
|
| 333 |
+
Resizes `image` to `(height, width)` specified by `size` using the PIL library.
|
| 334 |
+
|
| 335 |
+
Args:
|
| 336 |
+
image (`np.ndarray`):
|
| 337 |
+
The image to resize.
|
| 338 |
+
size (`tuple[int, int]`):
|
| 339 |
+
The size to use for resizing the image.
|
| 340 |
+
resample (`int`, *optional*, defaults to `PILImageResampling.BILINEAR`):
|
| 341 |
+
The filter to user for resampling.
|
| 342 |
+
reducing_gap (`int`, *optional*):
|
| 343 |
+
Apply optimization by resizing the image in two steps. The bigger `reducing_gap`, the closer the result to
|
| 344 |
+
the fair resampling. See corresponding Pillow documentation for more details.
|
| 345 |
+
data_format (`ChannelDimension`, *optional*):
|
| 346 |
+
The channel dimension format of the output image. If unset, will use the inferred format from the input.
|
| 347 |
+
return_numpy (`bool`, *optional*, defaults to `True`):
|
| 348 |
+
Whether or not to return the resized image as a numpy array. If False a `PIL.Image.Image` object is
|
| 349 |
+
returned.
|
| 350 |
+
input_data_format (`ChannelDimension`, *optional*):
|
| 351 |
+
The channel dimension format of the input image. If unset, will use the inferred format from the input.
|
| 352 |
+
|
| 353 |
+
Returns:
|
| 354 |
+
`np.ndarray`: The resized image.
|
| 355 |
+
"""
|
| 356 |
+
requires_backends(resize, ["vision"])
|
| 357 |
+
|
| 358 |
+
resample = resample if resample is not None else PILImageResampling.BILINEAR
|
| 359 |
+
|
| 360 |
+
if not len(size) == 2:
|
| 361 |
+
raise ValueError("size must have 2 elements")
|
| 362 |
+
|
| 363 |
+
# For all transformations, we want to keep the same data format as the input image unless otherwise specified.
|
| 364 |
+
# The resized image from PIL will always have channels last, so find the input format first.
|
| 365 |
+
if input_data_format is None:
|
| 366 |
+
input_data_format = infer_channel_dimension_format(image)
|
| 367 |
+
data_format = input_data_format if data_format is None else data_format
|
| 368 |
+
|
| 369 |
+
# To maintain backwards compatibility with the resizing done in previous image feature extractors, we use
|
| 370 |
+
# the pillow library to resize the image and then convert back to numpy
|
| 371 |
+
do_rescale = False
|
| 372 |
+
if not isinstance(image, PIL.Image.Image):
|
| 373 |
+
do_rescale = _rescale_for_pil_conversion(image)
|
| 374 |
+
image = to_pil_image(image, do_rescale=do_rescale, input_data_format=input_data_format)
|
| 375 |
+
height, width = size
|
| 376 |
+
# PIL images are in the format (width, height)
|
| 377 |
+
resized_image = image.resize((width, height), resample=resample, reducing_gap=reducing_gap)
|
| 378 |
+
|
| 379 |
+
if return_numpy:
|
| 380 |
+
resized_image = np.array(resized_image)
|
| 381 |
+
# If the input image channel dimension was of size 1, then it is dropped when converting to a PIL image
|
| 382 |
+
# so we need to add it back if necessary.
|
| 383 |
+
resized_image = np.expand_dims(resized_image, axis=-1) if resized_image.ndim == 2 else resized_image
|
| 384 |
+
# The image is always in channels last format after converting from a PIL image
|
| 385 |
+
resized_image = to_channel_dimension_format(
|
| 386 |
+
resized_image, data_format, input_channel_dim=ChannelDimension.LAST
|
| 387 |
+
)
|
| 388 |
+
# If an image was rescaled to be in the range [0, 255] before converting to a PIL image, then we need to
|
| 389 |
+
# rescale it back to the original range.
|
| 390 |
+
resized_image = rescale(resized_image, 1 / 255) if do_rescale else resized_image
|
| 391 |
+
return resized_image
|
| 392 |
+
|
| 393 |
+
|
| 394 |
+
def normalize(
|
| 395 |
+
image: np.ndarray,
|
| 396 |
+
mean: Union[float, Collection[float]],
|
| 397 |
+
std: Union[float, Collection[float]],
|
| 398 |
+
data_format: Optional[ChannelDimension] = None,
|
| 399 |
+
input_data_format: Optional[Union[str, ChannelDimension]] = None,
|
| 400 |
+
) -> np.ndarray:
|
| 401 |
+
"""
|
| 402 |
+
Normalizes `image` using the mean and standard deviation specified by `mean` and `std`.
|
| 403 |
+
|
| 404 |
+
image = (image - mean) / std
|
| 405 |
+
|
| 406 |
+
Args:
|
| 407 |
+
image (`np.ndarray`):
|
| 408 |
+
The image to normalize.
|
| 409 |
+
mean (`float` or `Collection[float]`):
|
| 410 |
+
The mean to use for normalization.
|
| 411 |
+
std (`float` or `Collection[float]`):
|
| 412 |
+
The standard deviation to use for normalization.
|
| 413 |
+
data_format (`ChannelDimension`, *optional*):
|
| 414 |
+
The channel dimension format of the output image. If unset, will use the inferred format from the input.
|
| 415 |
+
input_data_format (`ChannelDimension`, *optional*):
|
| 416 |
+
The channel dimension format of the input image. If unset, will use the inferred format from the input.
|
| 417 |
+
"""
|
| 418 |
+
if not isinstance(image, np.ndarray):
|
| 419 |
+
raise TypeError("image must be a numpy array")
|
| 420 |
+
|
| 421 |
+
if input_data_format is None:
|
| 422 |
+
input_data_format = infer_channel_dimension_format(image)
|
| 423 |
+
|
| 424 |
+
channel_axis = get_channel_dimension_axis(image, input_data_format=input_data_format)
|
| 425 |
+
num_channels = image.shape[channel_axis]
|
| 426 |
+
|
| 427 |
+
# We cast to float32 to avoid errors that can occur when subtracting uint8 values.
|
| 428 |
+
# We preserve the original dtype if it is a float type to prevent upcasting float16.
|
| 429 |
+
if not np.issubdtype(image.dtype, np.floating):
|
| 430 |
+
image = image.astype(np.float32)
|
| 431 |
+
|
| 432 |
+
if isinstance(mean, Collection):
|
| 433 |
+
if len(mean) != num_channels:
|
| 434 |
+
raise ValueError(f"mean must have {num_channels} elements if it is an iterable, got {len(mean)}")
|
| 435 |
+
else:
|
| 436 |
+
mean = [mean] * num_channels
|
| 437 |
+
mean = np.array(mean, dtype=image.dtype)
|
| 438 |
+
|
| 439 |
+
if isinstance(std, Collection):
|
| 440 |
+
if len(std) != num_channels:
|
| 441 |
+
raise ValueError(f"std must have {num_channels} elements if it is an iterable, got {len(std)}")
|
| 442 |
+
else:
|
| 443 |
+
std = [std] * num_channels
|
| 444 |
+
std = np.array(std, dtype=image.dtype)
|
| 445 |
+
|
| 446 |
+
if input_data_format == ChannelDimension.LAST:
|
| 447 |
+
image = (image - mean) / std
|
| 448 |
+
else:
|
| 449 |
+
image = ((image.T - mean) / std).T
|
| 450 |
+
|
| 451 |
+
image = to_channel_dimension_format(image, data_format, input_data_format) if data_format is not None else image
|
| 452 |
+
return image
|
| 453 |
+
|
| 454 |
+
|
| 455 |
+
def center_crop(
|
| 456 |
+
image: np.ndarray,
|
| 457 |
+
size: tuple[int, int],
|
| 458 |
+
data_format: Optional[Union[str, ChannelDimension]] = None,
|
| 459 |
+
input_data_format: Optional[Union[str, ChannelDimension]] = None,
|
| 460 |
+
) -> np.ndarray:
|
| 461 |
+
"""
|
| 462 |
+
Crops the `image` to the specified `size` using a center crop. Note that if the image is too small to be cropped to
|
| 463 |
+
the size given, it will be padded (so the returned result will always be of size `size`).
|
| 464 |
+
|
| 465 |
+
Args:
|
| 466 |
+
image (`np.ndarray`):
|
| 467 |
+
The image to crop.
|
| 468 |
+
size (`tuple[int, int]`):
|
| 469 |
+
The target size for the cropped image.
|
| 470 |
+
data_format (`str` or `ChannelDimension`, *optional*):
|
| 471 |
+
The channel dimension format for the output image. Can be one of:
|
| 472 |
+
- `"channels_first"` or `ChannelDimension.FIRST`: image in (num_channels, height, width) format.
|
| 473 |
+
- `"channels_last"` or `ChannelDimension.LAST`: image in (height, width, num_channels) format.
|
| 474 |
+
If unset, will use the inferred format of the input image.
|
| 475 |
+
input_data_format (`str` or `ChannelDimension`, *optional*):
|
| 476 |
+
The channel dimension format for the input image. Can be one of:
|
| 477 |
+
- `"channels_first"` or `ChannelDimension.FIRST`: image in (num_channels, height, width) format.
|
| 478 |
+
- `"channels_last"` or `ChannelDimension.LAST`: image in (height, width, num_channels) format.
|
| 479 |
+
If unset, will use the inferred format of the input image.
|
| 480 |
+
Returns:
|
| 481 |
+
`np.ndarray`: The cropped image.
|
| 482 |
+
"""
|
| 483 |
+
requires_backends(center_crop, ["vision"])
|
| 484 |
+
|
| 485 |
+
if not isinstance(image, np.ndarray):
|
| 486 |
+
raise TypeError(f"Input image must be of type np.ndarray, got {type(image)}")
|
| 487 |
+
|
| 488 |
+
if not isinstance(size, Iterable) or len(size) != 2:
|
| 489 |
+
raise ValueError("size must have 2 elements representing the height and width of the output image")
|
| 490 |
+
|
| 491 |
+
if input_data_format is None:
|
| 492 |
+
input_data_format = infer_channel_dimension_format(image)
|
| 493 |
+
output_data_format = data_format if data_format is not None else input_data_format
|
| 494 |
+
|
| 495 |
+
# We perform the crop in (C, H, W) format and then convert to the output format
|
| 496 |
+
image = to_channel_dimension_format(image, ChannelDimension.FIRST, input_data_format)
|
| 497 |
+
|
| 498 |
+
orig_height, orig_width = get_image_size(image, ChannelDimension.FIRST)
|
| 499 |
+
crop_height, crop_width = size
|
| 500 |
+
crop_height, crop_width = int(crop_height), int(crop_width)
|
| 501 |
+
|
| 502 |
+
# In case size is odd, (image_shape[0] + size[0]) // 2 won't give the proper result.
|
| 503 |
+
top = (orig_height - crop_height) // 2
|
| 504 |
+
bottom = top + crop_height
|
| 505 |
+
# In case size is odd, (image_shape[1] + size[1]) // 2 won't give the proper result.
|
| 506 |
+
left = (orig_width - crop_width) // 2
|
| 507 |
+
right = left + crop_width
|
| 508 |
+
|
| 509 |
+
# Check if cropped area is within image boundaries
|
| 510 |
+
if top >= 0 and bottom <= orig_height and left >= 0 and right <= orig_width:
|
| 511 |
+
image = image[..., top:bottom, left:right]
|
| 512 |
+
image = to_channel_dimension_format(image, output_data_format, ChannelDimension.FIRST)
|
| 513 |
+
return image
|
| 514 |
+
|
| 515 |
+
# Otherwise, we may need to pad if the image is too small. Oh joy...
|
| 516 |
+
new_height = max(crop_height, orig_height)
|
| 517 |
+
new_width = max(crop_width, orig_width)
|
| 518 |
+
new_shape = image.shape[:-2] + (new_height, new_width)
|
| 519 |
+
new_image = np.zeros_like(image, shape=new_shape)
|
| 520 |
+
|
| 521 |
+
# If the image is too small, pad it with zeros
|
| 522 |
+
top_pad = ceil((new_height - orig_height) / 2)
|
| 523 |
+
bottom_pad = top_pad + orig_height
|
| 524 |
+
left_pad = ceil((new_width - orig_width) / 2)
|
| 525 |
+
right_pad = left_pad + orig_width
|
| 526 |
+
new_image[..., top_pad:bottom_pad, left_pad:right_pad] = image
|
| 527 |
+
|
| 528 |
+
top += top_pad
|
| 529 |
+
bottom += top_pad
|
| 530 |
+
left += left_pad
|
| 531 |
+
right += left_pad
|
| 532 |
+
|
| 533 |
+
new_image = new_image[..., max(0, top) : min(new_height, bottom), max(0, left) : min(new_width, right)]
|
| 534 |
+
new_image = to_channel_dimension_format(new_image, output_data_format, ChannelDimension.FIRST)
|
| 535 |
+
|
| 536 |
+
return new_image
|
| 537 |
+
|
| 538 |
+
|
| 539 |
+
def _center_to_corners_format_torch(bboxes_center: "torch.Tensor") -> "torch.Tensor":
|
| 540 |
+
center_x, center_y, width, height = bboxes_center.unbind(-1)
|
| 541 |
+
bbox_corners = torch.stack(
|
| 542 |
+
# top left x, top left y, bottom right x, bottom right y
|
| 543 |
+
[(center_x - 0.5 * width), (center_y - 0.5 * height), (center_x + 0.5 * width), (center_y + 0.5 * height)],
|
| 544 |
+
dim=-1,
|
| 545 |
+
)
|
| 546 |
+
return bbox_corners
|
| 547 |
+
|
| 548 |
+
|
| 549 |
+
def _center_to_corners_format_numpy(bboxes_center: np.ndarray) -> np.ndarray:
|
| 550 |
+
center_x, center_y, width, height = bboxes_center.T
|
| 551 |
+
bboxes_corners = np.stack(
|
| 552 |
+
# top left x, top left y, bottom right x, bottom right y
|
| 553 |
+
[center_x - 0.5 * width, center_y - 0.5 * height, center_x + 0.5 * width, center_y + 0.5 * height],
|
| 554 |
+
axis=-1,
|
| 555 |
+
)
|
| 556 |
+
return bboxes_corners
|
| 557 |
+
|
| 558 |
+
|
| 559 |
+
def _center_to_corners_format_tf(bboxes_center: "tf.Tensor") -> "tf.Tensor":
|
| 560 |
+
center_x, center_y, width, height = tf.unstack(bboxes_center, axis=-1)
|
| 561 |
+
bboxes_corners = tf.stack(
|
| 562 |
+
# top left x, top left y, bottom right x, bottom right y
|
| 563 |
+
[center_x - 0.5 * width, center_y - 0.5 * height, center_x + 0.5 * width, center_y + 0.5 * height],
|
| 564 |
+
axis=-1,
|
| 565 |
+
)
|
| 566 |
+
return bboxes_corners
|
| 567 |
+
|
| 568 |
+
|
| 569 |
+
# 2 functions below inspired by https://github.com/facebookresearch/detr/blob/master/util/box_ops.py
|
| 570 |
+
def center_to_corners_format(bboxes_center: TensorType) -> TensorType:
|
| 571 |
+
"""
|
| 572 |
+
Converts bounding boxes from center format to corners format.
|
| 573 |
+
|
| 574 |
+
center format: contains the coordinate for the center of the box and its width, height dimensions
|
| 575 |
+
(center_x, center_y, width, height)
|
| 576 |
+
corners format: contains the coordinates for the top-left and bottom-right corners of the box
|
| 577 |
+
(top_left_x, top_left_y, bottom_right_x, bottom_right_y)
|
| 578 |
+
"""
|
| 579 |
+
# Function is used during model forward pass, so we use the input framework if possible, without
|
| 580 |
+
# converting to numpy
|
| 581 |
+
if is_torch_tensor(bboxes_center):
|
| 582 |
+
return _center_to_corners_format_torch(bboxes_center)
|
| 583 |
+
elif isinstance(bboxes_center, np.ndarray):
|
| 584 |
+
return _center_to_corners_format_numpy(bboxes_center)
|
| 585 |
+
elif is_tf_tensor(bboxes_center):
|
| 586 |
+
return _center_to_corners_format_tf(bboxes_center)
|
| 587 |
+
|
| 588 |
+
raise ValueError(f"Unsupported input type {type(bboxes_center)}")
|
| 589 |
+
|
| 590 |
+
|
| 591 |
+
def _corners_to_center_format_torch(bboxes_corners: "torch.Tensor") -> "torch.Tensor":
|
| 592 |
+
top_left_x, top_left_y, bottom_right_x, bottom_right_y = bboxes_corners.unbind(-1)
|
| 593 |
+
b = [
|
| 594 |
+
(top_left_x + bottom_right_x) / 2, # center x
|
| 595 |
+
(top_left_y + bottom_right_y) / 2, # center y
|
| 596 |
+
(bottom_right_x - top_left_x), # width
|
| 597 |
+
(bottom_right_y - top_left_y), # height
|
| 598 |
+
]
|
| 599 |
+
return torch.stack(b, dim=-1)
|
| 600 |
+
|
| 601 |
+
|
| 602 |
+
def _corners_to_center_format_numpy(bboxes_corners: np.ndarray) -> np.ndarray:
|
| 603 |
+
top_left_x, top_left_y, bottom_right_x, bottom_right_y = bboxes_corners.T
|
| 604 |
+
bboxes_center = np.stack(
|
| 605 |
+
[
|
| 606 |
+
(top_left_x + bottom_right_x) / 2, # center x
|
| 607 |
+
(top_left_y + bottom_right_y) / 2, # center y
|
| 608 |
+
(bottom_right_x - top_left_x), # width
|
| 609 |
+
(bottom_right_y - top_left_y), # height
|
| 610 |
+
],
|
| 611 |
+
axis=-1,
|
| 612 |
+
)
|
| 613 |
+
return bboxes_center
|
| 614 |
+
|
| 615 |
+
|
| 616 |
+
def _corners_to_center_format_tf(bboxes_corners: "tf.Tensor") -> "tf.Tensor":
|
| 617 |
+
top_left_x, top_left_y, bottom_right_x, bottom_right_y = tf.unstack(bboxes_corners, axis=-1)
|
| 618 |
+
bboxes_center = tf.stack(
|
| 619 |
+
[
|
| 620 |
+
(top_left_x + bottom_right_x) / 2, # center x
|
| 621 |
+
(top_left_y + bottom_right_y) / 2, # center y
|
| 622 |
+
(bottom_right_x - top_left_x), # width
|
| 623 |
+
(bottom_right_y - top_left_y), # height
|
| 624 |
+
],
|
| 625 |
+
axis=-1,
|
| 626 |
+
)
|
| 627 |
+
return bboxes_center
|
| 628 |
+
|
| 629 |
+
|
| 630 |
+
def corners_to_center_format(bboxes_corners: TensorType) -> TensorType:
|
| 631 |
+
"""
|
| 632 |
+
Converts bounding boxes from corners format to center format.
|
| 633 |
+
|
| 634 |
+
corners format: contains the coordinates for the top-left and bottom-right corners of the box
|
| 635 |
+
(top_left_x, top_left_y, bottom_right_x, bottom_right_y)
|
| 636 |
+
center format: contains the coordinate for the center of the box and its the width, height dimensions
|
| 637 |
+
(center_x, center_y, width, height)
|
| 638 |
+
"""
|
| 639 |
+
# Inverse function accepts different input types so implemented here too
|
| 640 |
+
if is_torch_tensor(bboxes_corners):
|
| 641 |
+
return _corners_to_center_format_torch(bboxes_corners)
|
| 642 |
+
elif isinstance(bboxes_corners, np.ndarray):
|
| 643 |
+
return _corners_to_center_format_numpy(bboxes_corners)
|
| 644 |
+
elif is_tf_tensor(bboxes_corners):
|
| 645 |
+
return _corners_to_center_format_tf(bboxes_corners)
|
| 646 |
+
|
| 647 |
+
raise ValueError(f"Unsupported input type {type(bboxes_corners)}")
|
| 648 |
+
|
| 649 |
+
|
| 650 |
+
# 2 functions below copied from https://github.com/cocodataset/panopticapi/blob/master/panopticapi/utils.py
|
| 651 |
+
# Copyright (c) 2018, Alexander Kirillov
|
| 652 |
+
# All rights reserved.
|
| 653 |
+
def rgb_to_id(color):
|
| 654 |
+
"""
|
| 655 |
+
Converts RGB color to unique ID.
|
| 656 |
+
"""
|
| 657 |
+
if isinstance(color, np.ndarray) and len(color.shape) == 3:
|
| 658 |
+
if color.dtype == np.uint8:
|
| 659 |
+
color = color.astype(np.int32)
|
| 660 |
+
return color[:, :, 0] + 256 * color[:, :, 1] + 256 * 256 * color[:, :, 2]
|
| 661 |
+
return int(color[0] + 256 * color[1] + 256 * 256 * color[2])
|
| 662 |
+
|
| 663 |
+
|
| 664 |
+
def id_to_rgb(id_map):
|
| 665 |
+
"""
|
| 666 |
+
Converts unique ID to RGB color.
|
| 667 |
+
"""
|
| 668 |
+
if isinstance(id_map, np.ndarray):
|
| 669 |
+
id_map_copy = id_map.copy()
|
| 670 |
+
rgb_shape = tuple(list(id_map.shape) + [3])
|
| 671 |
+
rgb_map = np.zeros(rgb_shape, dtype=np.uint8)
|
| 672 |
+
for i in range(3):
|
| 673 |
+
rgb_map[..., i] = id_map_copy % 256
|
| 674 |
+
id_map_copy //= 256
|
| 675 |
+
return rgb_map
|
| 676 |
+
color = []
|
| 677 |
+
for _ in range(3):
|
| 678 |
+
color.append(id_map % 256)
|
| 679 |
+
id_map //= 256
|
| 680 |
+
return color
|
| 681 |
+
|
| 682 |
+
|
| 683 |
+
class PaddingMode(ExplicitEnum):
|
| 684 |
+
"""
|
| 685 |
+
Enum class for the different padding modes to use when padding images.
|
| 686 |
+
"""
|
| 687 |
+
|
| 688 |
+
CONSTANT = "constant"
|
| 689 |
+
REFLECT = "reflect"
|
| 690 |
+
REPLICATE = "replicate"
|
| 691 |
+
SYMMETRIC = "symmetric"
|
| 692 |
+
|
| 693 |
+
|
| 694 |
+
def pad(
|
| 695 |
+
image: np.ndarray,
|
| 696 |
+
padding: Union[int, tuple[int, int], Iterable[tuple[int, int]]],
|
| 697 |
+
mode: PaddingMode = PaddingMode.CONSTANT,
|
| 698 |
+
constant_values: Union[float, Iterable[float]] = 0.0,
|
| 699 |
+
data_format: Optional[Union[str, ChannelDimension]] = None,
|
| 700 |
+
input_data_format: Optional[Union[str, ChannelDimension]] = None,
|
| 701 |
+
) -> np.ndarray:
|
| 702 |
+
"""
|
| 703 |
+
Pads the `image` with the specified (height, width) `padding` and `mode`.
|
| 704 |
+
|
| 705 |
+
Args:
|
| 706 |
+
image (`np.ndarray`):
|
| 707 |
+
The image to pad.
|
| 708 |
+
padding (`int` or `tuple[int, int]` or `Iterable[tuple[int, int]]`):
|
| 709 |
+
Padding to apply to the edges of the height, width axes. Can be one of three formats:
|
| 710 |
+
- `((before_height, after_height), (before_width, after_width))` unique pad widths for each axis.
|
| 711 |
+
- `((before, after),)` yields same before and after pad for height and width.
|
| 712 |
+
- `(pad,)` or int is a shortcut for before = after = pad width for all axes.
|
| 713 |
+
mode (`PaddingMode`):
|
| 714 |
+
The padding mode to use. Can be one of:
|
| 715 |
+
- `"constant"`: pads with a constant value.
|
| 716 |
+
- `"reflect"`: pads with the reflection of the vector mirrored on the first and last values of the
|
| 717 |
+
vector along each axis.
|
| 718 |
+
- `"replicate"`: pads with the replication of the last value on the edge of the array along each axis.
|
| 719 |
+
- `"symmetric"`: pads with the reflection of the vector mirrored along the edge of the array.
|
| 720 |
+
constant_values (`float` or `Iterable[float]`, *optional*):
|
| 721 |
+
The value to use for the padding if `mode` is `"constant"`.
|
| 722 |
+
data_format (`str` or `ChannelDimension`, *optional*):
|
| 723 |
+
The channel dimension format for the output image. Can be one of:
|
| 724 |
+
- `"channels_first"` or `ChannelDimension.FIRST`: image in (num_channels, height, width) format.
|
| 725 |
+
- `"channels_last"` or `ChannelDimension.LAST`: image in (height, width, num_channels) format.
|
| 726 |
+
If unset, will use same as the input image.
|
| 727 |
+
input_data_format (`str` or `ChannelDimension`, *optional*):
|
| 728 |
+
The channel dimension format for the input image. Can be one of:
|
| 729 |
+
- `"channels_first"` or `ChannelDimension.FIRST`: image in (num_channels, height, width) format.
|
| 730 |
+
- `"channels_last"` or `ChannelDimension.LAST`: image in (height, width, num_channels) format.
|
| 731 |
+
If unset, will use the inferred format of the input image.
|
| 732 |
+
|
| 733 |
+
Returns:
|
| 734 |
+
`np.ndarray`: The padded image.
|
| 735 |
+
|
| 736 |
+
"""
|
| 737 |
+
if input_data_format is None:
|
| 738 |
+
input_data_format = infer_channel_dimension_format(image)
|
| 739 |
+
|
| 740 |
+
def _expand_for_data_format(values):
|
| 741 |
+
"""
|
| 742 |
+
Convert values to be in the format expected by np.pad based on the data format.
|
| 743 |
+
"""
|
| 744 |
+
if isinstance(values, (int, float)):
|
| 745 |
+
values = ((values, values), (values, values))
|
| 746 |
+
elif isinstance(values, tuple) and len(values) == 1:
|
| 747 |
+
values = ((values[0], values[0]), (values[0], values[0]))
|
| 748 |
+
elif isinstance(values, tuple) and len(values) == 2 and isinstance(values[0], int):
|
| 749 |
+
values = (values, values)
|
| 750 |
+
elif isinstance(values, tuple) and len(values) == 2 and isinstance(values[0], tuple):
|
| 751 |
+
pass
|
| 752 |
+
else:
|
| 753 |
+
raise ValueError(f"Unsupported format: {values}")
|
| 754 |
+
|
| 755 |
+
# add 0 for channel dimension
|
| 756 |
+
values = ((0, 0), *values) if input_data_format == ChannelDimension.FIRST else (*values, (0, 0))
|
| 757 |
+
|
| 758 |
+
# Add additional padding if there's a batch dimension
|
| 759 |
+
values = ((0, 0), *values) if image.ndim == 4 else values
|
| 760 |
+
return values
|
| 761 |
+
|
| 762 |
+
padding = _expand_for_data_format(padding)
|
| 763 |
+
|
| 764 |
+
if mode == PaddingMode.CONSTANT:
|
| 765 |
+
constant_values = _expand_for_data_format(constant_values)
|
| 766 |
+
image = np.pad(image, padding, mode="constant", constant_values=constant_values)
|
| 767 |
+
elif mode == PaddingMode.REFLECT:
|
| 768 |
+
image = np.pad(image, padding, mode="reflect")
|
| 769 |
+
elif mode == PaddingMode.REPLICATE:
|
| 770 |
+
image = np.pad(image, padding, mode="edge")
|
| 771 |
+
elif mode == PaddingMode.SYMMETRIC:
|
| 772 |
+
image = np.pad(image, padding, mode="symmetric")
|
| 773 |
+
else:
|
| 774 |
+
raise ValueError(f"Invalid padding mode: {mode}")
|
| 775 |
+
|
| 776 |
+
image = to_channel_dimension_format(image, data_format, input_data_format) if data_format is not None else image
|
| 777 |
+
return image
|
| 778 |
+
|
| 779 |
+
|
| 780 |
+
# TODO (Amy): Accept 1/3/4 channel numpy array as input and return np.array as default
|
| 781 |
+
def convert_to_rgb(image: ImageInput) -> ImageInput:
|
| 782 |
+
"""
|
| 783 |
+
Converts an image to RGB format. Only converts if the image is of type PIL.Image.Image, otherwise returns the image
|
| 784 |
+
as is.
|
| 785 |
+
Args:
|
| 786 |
+
image (Image):
|
| 787 |
+
The image to convert.
|
| 788 |
+
"""
|
| 789 |
+
requires_backends(convert_to_rgb, ["vision"])
|
| 790 |
+
|
| 791 |
+
if not isinstance(image, PIL.Image.Image):
|
| 792 |
+
return image
|
| 793 |
+
|
| 794 |
+
if image.mode == "RGB":
|
| 795 |
+
return image
|
| 796 |
+
|
| 797 |
+
image = image.convert("RGB")
|
| 798 |
+
return image
|
| 799 |
+
|
| 800 |
+
|
| 801 |
+
def flip_channel_order(
|
| 802 |
+
image: np.ndarray,
|
| 803 |
+
data_format: Optional[ChannelDimension] = None,
|
| 804 |
+
input_data_format: Optional[Union[str, ChannelDimension]] = None,
|
| 805 |
+
) -> np.ndarray:
|
| 806 |
+
"""
|
| 807 |
+
Flips the channel order of the image.
|
| 808 |
+
|
| 809 |
+
If the image is in RGB format, it will be converted to BGR and vice versa.
|
| 810 |
+
|
| 811 |
+
Args:
|
| 812 |
+
image (`np.ndarray`):
|
| 813 |
+
The image to flip.
|
| 814 |
+
data_format (`ChannelDimension`, *optional*):
|
| 815 |
+
The channel dimension format for the output image. Can be one of:
|
| 816 |
+
- `ChannelDimension.FIRST`: image in (num_channels, height, width) format.
|
| 817 |
+
- `ChannelDimension.LAST`: image in (height, width, num_channels) format.
|
| 818 |
+
If unset, will use same as the input image.
|
| 819 |
+
input_data_format (`ChannelDimension`, *optional*):
|
| 820 |
+
The channel dimension format for the input image. Can be one of:
|
| 821 |
+
- `ChannelDimension.FIRST`: image in (num_channels, height, width) format.
|
| 822 |
+
- `ChannelDimension.LAST`: image in (height, width, num_channels) format.
|
| 823 |
+
If unset, will use the inferred format of the input image.
|
| 824 |
+
"""
|
| 825 |
+
input_data_format = infer_channel_dimension_format(image) if input_data_format is None else input_data_format
|
| 826 |
+
|
| 827 |
+
if input_data_format == ChannelDimension.LAST:
|
| 828 |
+
image = image[..., ::-1]
|
| 829 |
+
elif input_data_format == ChannelDimension.FIRST:
|
| 830 |
+
image = image[::-1, ...]
|
| 831 |
+
else:
|
| 832 |
+
raise ValueError(f"Unsupported channel dimension: {input_data_format}")
|
| 833 |
+
|
| 834 |
+
if data_format is not None:
|
| 835 |
+
image = to_channel_dimension_format(image, data_format, input_channel_dim=input_data_format)
|
| 836 |
+
return image
|
| 837 |
+
|
| 838 |
+
|
| 839 |
+
def _cast_tensor_to_float(x):
|
| 840 |
+
if x.is_floating_point():
|
| 841 |
+
return x
|
| 842 |
+
return x.float()
|
| 843 |
+
|
| 844 |
+
|
| 845 |
+
def _group_images_by_shape(nested_images, is_nested: bool = False):
|
| 846 |
+
"""Helper function to flatten a single level of nested image structures and group by shape."""
|
| 847 |
+
grouped_images = defaultdict(list)
|
| 848 |
+
grouped_images_index = {}
|
| 849 |
+
nested_images = [nested_images] if not is_nested else nested_images
|
| 850 |
+
for i, sublist in enumerate(nested_images):
|
| 851 |
+
for j, image in enumerate(sublist):
|
| 852 |
+
key = (i, j) if is_nested else j
|
| 853 |
+
shape = image.shape[1:]
|
| 854 |
+
grouped_images[shape].append(image)
|
| 855 |
+
grouped_images_index[key] = (shape, len(grouped_images[shape]) - 1)
|
| 856 |
+
|
| 857 |
+
return grouped_images, grouped_images_index
|
| 858 |
+
|
| 859 |
+
|
| 860 |
+
def _reconstruct_nested_structure(indices, processed_images):
|
| 861 |
+
"""Helper function to reconstruct a single level nested structure."""
|
| 862 |
+
# Find the maximum outer index
|
| 863 |
+
max_outer_idx = max(idx[0] for idx in indices)
|
| 864 |
+
|
| 865 |
+
# Create the outer list
|
| 866 |
+
result = [None] * (max_outer_idx + 1)
|
| 867 |
+
|
| 868 |
+
# Group indices by outer index
|
| 869 |
+
nested_indices = defaultdict(list)
|
| 870 |
+
for i, j in indices:
|
| 871 |
+
nested_indices[i].append(j)
|
| 872 |
+
|
| 873 |
+
for i in range(max_outer_idx + 1):
|
| 874 |
+
if i in nested_indices:
|
| 875 |
+
inner_max_idx = max(nested_indices[i])
|
| 876 |
+
inner_list = [None] * (inner_max_idx + 1)
|
| 877 |
+
for j in range(inner_max_idx + 1):
|
| 878 |
+
if (i, j) in indices:
|
| 879 |
+
shape, idx = indices[(i, j)]
|
| 880 |
+
inner_list[j] = processed_images[shape][idx]
|
| 881 |
+
result[i] = inner_list
|
| 882 |
+
|
| 883 |
+
return result
|
| 884 |
+
|
| 885 |
+
|
| 886 |
+
def group_images_by_shape(
|
| 887 |
+
images: Union[list["torch.Tensor"], "torch.Tensor"],
|
| 888 |
+
disable_grouping: bool,
|
| 889 |
+
is_nested: bool = False,
|
| 890 |
+
) -> tuple[
|
| 891 |
+
dict[tuple[int, int], list["torch.Tensor"]], dict[Union[int, tuple[int, int]], tuple[tuple[int, int], int]]
|
| 892 |
+
]:
|
| 893 |
+
"""
|
| 894 |
+
Groups images by shape.
|
| 895 |
+
Returns a dictionary with the shape as key and a list of images with that shape as value,
|
| 896 |
+
and a dictionary with the index of the image in the original list as key and the shape and index in the grouped list as value.
|
| 897 |
+
|
| 898 |
+
The function supports both flat lists of tensors and nested structures.
|
| 899 |
+
The input must be either all flat or all nested, not a mix of both.
|
| 900 |
+
|
| 901 |
+
Args:
|
| 902 |
+
images (Union[list["torch.Tensor"], "torch.Tensor"]):
|
| 903 |
+
A list of images or a single tensor
|
| 904 |
+
disable_grouping (bool):
|
| 905 |
+
Whether to disable grouping. If None, will be set to True if the images are on CPU, and False otherwise.
|
| 906 |
+
This choice is based on empirical observations, as detailed here: https://github.com/huggingface/transformers/pull/38157
|
| 907 |
+
is_nested (bool, *optional*, defaults to False):
|
| 908 |
+
Whether the images are nested.
|
| 909 |
+
|
| 910 |
+
Returns:
|
| 911 |
+
tuple[dict[tuple[int, int], list["torch.Tensor"]], dict[Union[int, tuple[int, int]], tuple[tuple[int, int], int]]]:
|
| 912 |
+
- A dictionary with shape as key and list of images with that shape as value
|
| 913 |
+
- A dictionary mapping original indices to (shape, index) tuples
|
| 914 |
+
"""
|
| 915 |
+
# If disable grouping is not explicitly provided, we favor disabling it if the images are on CPU, and enabling it otherwise.
|
| 916 |
+
if disable_grouping is None:
|
| 917 |
+
device = images[0][0].device if is_nested else images[0].device
|
| 918 |
+
disable_grouping = device == "cpu"
|
| 919 |
+
|
| 920 |
+
if disable_grouping:
|
| 921 |
+
if is_nested:
|
| 922 |
+
return {(i, j): images[i][j].unsqueeze(0) for i in range(len(images)) for j in range(len(images[i]))}, {
|
| 923 |
+
(i, j): ((i, j), 0) for i in range(len(images)) for j in range(len(images[i]))
|
| 924 |
+
}
|
| 925 |
+
else:
|
| 926 |
+
return {i: images[i].unsqueeze(0) for i in range(len(images))}, {i: (i, 0) for i in range(len(images))}
|
| 927 |
+
|
| 928 |
+
# Handle single level nested structure
|
| 929 |
+
grouped_images, grouped_images_index = _group_images_by_shape(images, is_nested)
|
| 930 |
+
|
| 931 |
+
# Stack images with the same shape
|
| 932 |
+
grouped_images = {shape: torch.stack(images_list, dim=0) for shape, images_list in grouped_images.items()}
|
| 933 |
+
|
| 934 |
+
return grouped_images, grouped_images_index
|
| 935 |
+
|
| 936 |
+
|
| 937 |
+
def reorder_images(
|
| 938 |
+
processed_images: dict[tuple[int, int], "torch.Tensor"],
|
| 939 |
+
grouped_images_index: dict[Union[int, tuple[int, int]], tuple[tuple[int, int], int]],
|
| 940 |
+
is_nested: bool = False,
|
| 941 |
+
) -> Union[list["torch.Tensor"], "torch.Tensor"]:
|
| 942 |
+
"""
|
| 943 |
+
Reconstructs images in the original order, preserving the original structure (nested or not).
|
| 944 |
+
The input structure is either all flat or all nested.
|
| 945 |
+
|
| 946 |
+
Args:
|
| 947 |
+
processed_images (dict[tuple[int, int], "torch.Tensor"]):
|
| 948 |
+
Dictionary mapping shapes to batched processed images.
|
| 949 |
+
grouped_images_index (dict[Union[int, tuple[int, int]], tuple[tuple[int, int], int]]):
|
| 950 |
+
Dictionary mapping original indices to (shape, index) tuples.
|
| 951 |
+
is_nested (bool, *optional*, defaults to False):
|
| 952 |
+
Whether the images are nested. Cannot be inferred from the input, as some processing functions outputs nested images.
|
| 953 |
+
even with non nested images,e.g functions splitting images into patches. We thus can't deduce is_nested from the input.
|
| 954 |
+
|
| 955 |
+
|
| 956 |
+
Returns:
|
| 957 |
+
Union[list["torch.Tensor"], "torch.Tensor"]:
|
| 958 |
+
Images in the original structure.
|
| 959 |
+
"""
|
| 960 |
+
if not is_nested:
|
| 961 |
+
return [
|
| 962 |
+
processed_images[grouped_images_index[i][0]][grouped_images_index[i][1]]
|
| 963 |
+
for i in range(len(grouped_images_index))
|
| 964 |
+
]
|
| 965 |
+
|
| 966 |
+
return _reconstruct_nested_structure(grouped_images_index, processed_images)
|
| 967 |
+
|
| 968 |
+
|
| 969 |
+
class NumpyToTensor:
|
| 970 |
+
"""
|
| 971 |
+
Convert a numpy array to a PyTorch tensor.
|
| 972 |
+
"""
|
| 973 |
+
|
| 974 |
+
def __call__(self, image: np.ndarray):
|
| 975 |
+
# Same as in PyTorch, we assume incoming numpy images are in HWC format
|
| 976 |
+
# c.f. https://github.com/pytorch/vision/blob/61d97f41bc209e1407dcfbd685d2ee2da9c1cdad/torchvision/transforms/functional.py#L154
|
| 977 |
+
return torch.from_numpy(image.transpose(2, 0, 1)).contiguous()
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/transformers/masking_utils.py
ADDED
|
@@ -0,0 +1,1256 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# coding=utf-8
|
| 2 |
+
# Copyright 2025 HuggingFace Inc. team. All rights reserved.
|
| 3 |
+
#
|
| 4 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 5 |
+
# you may not use this file except in compliance with the License.
|
| 6 |
+
# You may obtain a copy of the License at
|
| 7 |
+
#
|
| 8 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 9 |
+
#
|
| 10 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 11 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 12 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 13 |
+
# See the License for the specific language governing permissions and
|
| 14 |
+
# limitations under the License.
|
| 15 |
+
import itertools
|
| 16 |
+
from typing import Callable, Optional, Union
|
| 17 |
+
|
| 18 |
+
import torch
|
| 19 |
+
import torch.nn.functional as F
|
| 20 |
+
|
| 21 |
+
from .cache_utils import Cache
|
| 22 |
+
from .configuration_utils import PretrainedConfig
|
| 23 |
+
from .utils import is_torch_xpu_available, logging
|
| 24 |
+
from .utils.generic import GeneralInterface
|
| 25 |
+
from .utils.import_utils import is_torch_flex_attn_available, is_torch_greater_or_equal, is_torchdynamo_compiling
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
if is_torch_flex_attn_available():
|
| 29 |
+
from torch.nn.attention.flex_attention import _DEFAULT_SPARSE_BLOCK_SIZE as flex_default_block_size
|
| 30 |
+
from torch.nn.attention.flex_attention import BlockMask, create_block_mask
|
| 31 |
+
else:
|
| 32 |
+
# Register a fake type to avoid crashing for annotations and `isinstance` checks
|
| 33 |
+
BlockMask = torch.Tensor
|
| 34 |
+
|
| 35 |
+
_is_torch_greater_or_equal_than_2_5 = is_torch_greater_or_equal("2.5", accept_dev=True)
|
| 36 |
+
_is_torch_greater_or_equal_than_2_6 = is_torch_greater_or_equal("2.6", accept_dev=True)
|
| 37 |
+
_is_torch_xpu_available = is_torch_xpu_available()
|
| 38 |
+
|
| 39 |
+
if _is_torch_greater_or_equal_than_2_6:
|
| 40 |
+
from torch._dynamo._trace_wrapped_higher_order_op import TransformGetItemToIndex
|
| 41 |
+
|
| 42 |
+
|
| 43 |
+
logger = logging.get_logger(__name__)
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
def and_masks(*mask_functions: Callable) -> Callable:
|
| 47 |
+
"""Returns a mask function that is the intersection of provided mask functions"""
|
| 48 |
+
if not all(callable(arg) for arg in mask_functions):
|
| 49 |
+
raise RuntimeError(f"All inputs should be callable mask_functions: {mask_functions}")
|
| 50 |
+
|
| 51 |
+
def and_mask(batch_idx, head_idx, q_idx, kv_idx):
|
| 52 |
+
result = q_idx.new_ones((), dtype=torch.bool)
|
| 53 |
+
for mask in mask_functions:
|
| 54 |
+
result = result & mask(batch_idx, head_idx, q_idx, kv_idx).to(result.device)
|
| 55 |
+
return result
|
| 56 |
+
|
| 57 |
+
return and_mask
|
| 58 |
+
|
| 59 |
+
|
| 60 |
+
def or_masks(*mask_functions: Callable) -> Callable:
|
| 61 |
+
"""Returns a mask function that is the union of provided mask functions"""
|
| 62 |
+
if not all(callable(arg) for arg in mask_functions):
|
| 63 |
+
raise RuntimeError(f"All inputs should be callable mask_functions: {mask_functions}")
|
| 64 |
+
|
| 65 |
+
def or_mask(batch_idx, head_idx, q_idx, kv_idx):
|
| 66 |
+
result = q_idx.new_zeros((), dtype=torch.bool)
|
| 67 |
+
for mask in mask_functions:
|
| 68 |
+
result = result | mask(batch_idx, head_idx, q_idx, kv_idx).to(result.device)
|
| 69 |
+
return result
|
| 70 |
+
|
| 71 |
+
return or_mask
|
| 72 |
+
|
| 73 |
+
|
| 74 |
+
def causal_mask_function(batch_idx: int, head_idx: int, q_idx: int, kv_idx: int) -> bool:
|
| 75 |
+
"""
|
| 76 |
+
This creates a basic lower-diagonal causal mask.
|
| 77 |
+
"""
|
| 78 |
+
return kv_idx <= q_idx
|
| 79 |
+
|
| 80 |
+
|
| 81 |
+
def sliding_window_overlay(sliding_window: int) -> Callable:
|
| 82 |
+
"""
|
| 83 |
+
This is an overlay depicting a sliding window pattern. Add it on top of a causal mask for a proper sliding
|
| 84 |
+
window mask.
|
| 85 |
+
"""
|
| 86 |
+
|
| 87 |
+
def inner_mask(batch_idx: int, head_idx: int, q_idx: int, kv_idx: int) -> bool:
|
| 88 |
+
return kv_idx > q_idx - sliding_window
|
| 89 |
+
|
| 90 |
+
return inner_mask
|
| 91 |
+
|
| 92 |
+
|
| 93 |
+
def chunked_overlay(chunk_size: int, left_padding: torch.Tensor) -> Callable:
|
| 94 |
+
"""
|
| 95 |
+
This is an overlay depicting a chunked attention pattern. Add it on top of a causal mask for a proper chunked
|
| 96 |
+
attention mask.
|
| 97 |
+
"""
|
| 98 |
+
|
| 99 |
+
def inner_mask(batch_idx: int, head_idx: int, q_idx: int, kv_idx: int) -> bool:
|
| 100 |
+
return (kv_idx - left_padding[batch_idx]) // chunk_size == (q_idx - left_padding[batch_idx]) // chunk_size
|
| 101 |
+
|
| 102 |
+
return inner_mask
|
| 103 |
+
|
| 104 |
+
|
| 105 |
+
def _legacy_chunked_overlay(chunk_size: int) -> Callable:
|
| 106 |
+
"""
|
| 107 |
+
Same as the above function, but do not correctly account for left padding tokens.
|
| 108 |
+
Only kept for compatibility with older torch versions (< 2.6).
|
| 109 |
+
"""
|
| 110 |
+
|
| 111 |
+
def inner_mask(batch_idx: int, head_idx: int, q_idx: int, kv_idx: int) -> bool:
|
| 112 |
+
return kv_idx // chunk_size == q_idx // chunk_size
|
| 113 |
+
|
| 114 |
+
return inner_mask
|
| 115 |
+
|
| 116 |
+
|
| 117 |
+
def sliding_window_causal_mask_function(sliding_window: int) -> Callable:
|
| 118 |
+
"""
|
| 119 |
+
This return the mask_function function to create a sliding window mask.
|
| 120 |
+
"""
|
| 121 |
+
return and_masks(sliding_window_overlay(sliding_window), causal_mask_function)
|
| 122 |
+
|
| 123 |
+
|
| 124 |
+
def chunked_causal_mask_function(chunk_size: int, left_padding: torch.Tensor) -> Callable:
|
| 125 |
+
"""
|
| 126 |
+
This return the mask_function function to create a chunked attention mask.
|
| 127 |
+
"""
|
| 128 |
+
if not _is_torch_greater_or_equal_than_2_6:
|
| 129 |
+
return and_masks(_legacy_chunked_overlay(chunk_size), causal_mask_function)
|
| 130 |
+
return and_masks(chunked_overlay(chunk_size, left_padding), causal_mask_function)
|
| 131 |
+
|
| 132 |
+
|
| 133 |
+
def padding_mask_function(padding_mask: torch.Tensor) -> Callable:
|
| 134 |
+
"""
|
| 135 |
+
This return the mask_function function corresponding to a 2D padding mask.
|
| 136 |
+
"""
|
| 137 |
+
|
| 138 |
+
def inner_mask(batch_idx: int, head_idx: int, q_idx: int, kv_idx: int) -> bool:
|
| 139 |
+
# Note that here the mask should ALWAYS be at least of the max `kv_index` size in the dimension 1. This is because
|
| 140 |
+
# we cannot pad it here in the mask_function as we don't know the final size, and we cannot try/except, as it is not
|
| 141 |
+
# vectorizable on accelerator devices
|
| 142 |
+
return padding_mask[batch_idx, kv_idx]
|
| 143 |
+
|
| 144 |
+
return inner_mask
|
| 145 |
+
|
| 146 |
+
|
| 147 |
+
def packed_sequence_mask_function(packed_sequence_mask: torch.Tensor) -> Callable:
|
| 148 |
+
"""
|
| 149 |
+
This return the mask_function function corresponding to a 2D packed sequence mask.
|
| 150 |
+
"""
|
| 151 |
+
|
| 152 |
+
def inner_mask(batch_idx: int, head_idx: int, q_idx: int, kv_idx: int) -> bool:
|
| 153 |
+
return packed_sequence_mask[batch_idx, q_idx] == packed_sequence_mask[batch_idx, kv_idx]
|
| 154 |
+
|
| 155 |
+
return inner_mask
|
| 156 |
+
|
| 157 |
+
|
| 158 |
+
def add_offsets_to_mask_function(mask_function: Callable, q_offset: int, kv_offset: int) -> Callable:
|
| 159 |
+
"""
|
| 160 |
+
This function adds the correct offsets to the `q_idx` and `kv_idx` as the torch API can only accept lengths,
|
| 161 |
+
not start and end indices.
|
| 162 |
+
"""
|
| 163 |
+
|
| 164 |
+
def inner_mask(batch_idx: int, head_idx: int, q_idx: int, kv_idx: int) -> bool:
|
| 165 |
+
return mask_function(batch_idx, head_idx, q_idx + q_offset, kv_idx + kv_offset)
|
| 166 |
+
|
| 167 |
+
return inner_mask
|
| 168 |
+
|
| 169 |
+
|
| 170 |
+
def _vmap_for_bhqkv(mask_function: Callable, bh_indices: bool = True) -> Callable:
|
| 171 |
+
"""
|
| 172 |
+
Used to vmap our mask_functions over the q_idx and kv_idx dimensions of the inputs. Optionally, vmap over
|
| 173 |
+
the batch and head indices as well if `bh_indices=True`.
|
| 174 |
+
Using vmap here allows us to keep the performance of vectorized ops, while having a single set of primitive
|
| 175 |
+
functions between attention interfaces (i.e. between flex and sdpa/eager, FA2 being a bit different).
|
| 176 |
+
|
| 177 |
+
Args:
|
| 178 |
+
mask_function (`Callable`):
|
| 179 |
+
The mask_function to vmap.
|
| 180 |
+
bh_indices (`bool`, optional):
|
| 181 |
+
Whether to vmap over the batch and head indices as well, or only q and kv indices.
|
| 182 |
+
|
| 183 |
+
Returns:
|
| 184 |
+
Callable: The vmapped function.
|
| 185 |
+
"""
|
| 186 |
+
# We vmap the function 2 times, broadcasting the [q_idx, kv_idx] dimensions
|
| 187 |
+
dimensions = [(None, None, None, 0), (None, None, 0, None)]
|
| 188 |
+
if bh_indices:
|
| 189 |
+
# We extend broadcasting over the [batch_idx, head_idx] dimensions
|
| 190 |
+
dimensions.extend([(None, 0, None, None), (0, None, None, None)])
|
| 191 |
+
|
| 192 |
+
for dims in dimensions:
|
| 193 |
+
mask_function = torch.vmap(mask_function, in_dims=dims, out_dims=0)
|
| 194 |
+
return mask_function
|
| 195 |
+
|
| 196 |
+
|
| 197 |
+
def prepare_padding_mask(
|
| 198 |
+
attention_mask: Optional[torch.Tensor], kv_length: int, kv_offset: int, _slice: bool = True
|
| 199 |
+
) -> Optional[torch.Tensor]:
|
| 200 |
+
"""
|
| 201 |
+
From the 2D attention mask, prepare the correct padding mask to use by potentially padding it, and slicing
|
| 202 |
+
according to the `kv_offset` if `_slice` is `True`.
|
| 203 |
+
"""
|
| 204 |
+
local_padding_mask = attention_mask
|
| 205 |
+
if attention_mask is not None:
|
| 206 |
+
# Pad it if necessary
|
| 207 |
+
if (padding_length := kv_length + kv_offset - attention_mask.shape[-1]) > 0:
|
| 208 |
+
local_padding_mask = torch.nn.functional.pad(attention_mask, (0, padding_length))
|
| 209 |
+
# For flex, we should not slice them, only use an offset
|
| 210 |
+
if _slice:
|
| 211 |
+
# Equivalent to: `local_padding_mask = attention_mask[:, kv_offset : kv_offset + kv_length]`,
|
| 212 |
+
# but without data-dependent slicing (i.e. torch.compile friendly)
|
| 213 |
+
mask_indices = torch.arange(kv_length, device=local_padding_mask.device)
|
| 214 |
+
mask_indices += kv_offset
|
| 215 |
+
local_padding_mask = local_padding_mask[:, mask_indices]
|
| 216 |
+
return local_padding_mask
|
| 217 |
+
|
| 218 |
+
|
| 219 |
+
def _ignore_causal_mask_sdpa(
|
| 220 |
+
padding_mask: Optional[torch.Tensor],
|
| 221 |
+
query_length: int,
|
| 222 |
+
kv_length: int,
|
| 223 |
+
kv_offset: int,
|
| 224 |
+
local_attention_size: Optional[int] = None,
|
| 225 |
+
) -> bool:
|
| 226 |
+
"""
|
| 227 |
+
Detects whether the causal mask can be ignored in case PyTorch's SDPA is used, rather relying on SDPA's `is_causal` argument.
|
| 228 |
+
|
| 229 |
+
In case no token is masked in the 2D `padding_mask` argument, if `query_length == 1` or
|
| 230 |
+
`key_value_length == query_length`, we rather rely on SDPA `is_causal` argument to use causal/non-causal masks,
|
| 231 |
+
allowing to dispatch to the flash attention kernel (that can otherwise not be used if a custom `attn_mask` is
|
| 232 |
+
passed).
|
| 233 |
+
"""
|
| 234 |
+
is_tracing = torch.jit.is_tracing() or isinstance(padding_mask, torch.fx.Proxy) or is_torchdynamo_compiling()
|
| 235 |
+
if padding_mask is not None and padding_mask.shape[-1] > kv_length:
|
| 236 |
+
mask_indices = torch.arange(kv_length, device=padding_mask.device)
|
| 237 |
+
mask_indices += kv_offset
|
| 238 |
+
padding_mask = padding_mask[:, mask_indices]
|
| 239 |
+
|
| 240 |
+
# When using `torch.export` or `torch.onnx.dynamo_export`, we must pass an example input, and `is_causal` behavior is
|
| 241 |
+
# hard-coded to the forward. If a user exports a model with query_length > 1, the exported model will hard-code `is_causal=True`
|
| 242 |
+
# which is in general wrong (see https://github.com/pytorch/pytorch/issues/108108). Thus, we only set
|
| 243 |
+
# `ignore_causal_mask = True` if we are not tracing
|
| 244 |
+
if (
|
| 245 |
+
not is_tracing
|
| 246 |
+
# only cases when lower and upper diags are the same, see https://github.com/pytorch/pytorch/issues/108108
|
| 247 |
+
and (query_length == 1 or (kv_length == query_length or _is_torch_xpu_available))
|
| 248 |
+
# in this case we need to add special patterns to the mask so cannot be skipped otherwise
|
| 249 |
+
and (local_attention_size is None or kv_length < local_attention_size)
|
| 250 |
+
# In this case, we need to add padding to the mask, so cannot be skipped otherwise
|
| 251 |
+
and (
|
| 252 |
+
padding_mask is None
|
| 253 |
+
or (
|
| 254 |
+
padding_mask.all()
|
| 255 |
+
if not _is_torch_xpu_available or query_length == 1
|
| 256 |
+
else padding_mask[:, :query_length].all()
|
| 257 |
+
)
|
| 258 |
+
)
|
| 259 |
+
):
|
| 260 |
+
return True
|
| 261 |
+
|
| 262 |
+
return False
|
| 263 |
+
|
| 264 |
+
|
| 265 |
+
def sdpa_mask_recent_torch(
|
| 266 |
+
batch_size: int,
|
| 267 |
+
cache_position: torch.Tensor,
|
| 268 |
+
kv_length: int,
|
| 269 |
+
kv_offset: int = 0,
|
| 270 |
+
mask_function: Callable = causal_mask_function,
|
| 271 |
+
attention_mask: Optional[torch.Tensor] = None,
|
| 272 |
+
local_size: Optional[int] = None,
|
| 273 |
+
allow_is_causal_skip: bool = True,
|
| 274 |
+
**kwargs,
|
| 275 |
+
) -> Optional[torch.Tensor]:
|
| 276 |
+
"""
|
| 277 |
+
Create a 4D boolean mask of shape `(batch_size, 1, query_length, kv_length)` where a value of True indicates that
|
| 278 |
+
the element should take part in the attention computation, and False that it should not.
|
| 279 |
+
This function can only be used with torch>=2.5, as the context manager is otherwise not available.
|
| 280 |
+
|
| 281 |
+
Args:
|
| 282 |
+
batch_size (`int`):
|
| 283 |
+
The batch size of the input sequence.
|
| 284 |
+
cache_position (`torch.Tensor`):
|
| 285 |
+
A tensor of shape (query_length,) indicating the current indices of the input sequence elements.
|
| 286 |
+
kv_length (`int`):
|
| 287 |
+
The size that the key and value states will have during the attention computation.
|
| 288 |
+
kv_offset (`int`, optional):
|
| 289 |
+
An optional offset to indicate at which first position the key and values states will refer to.
|
| 290 |
+
mask_function (`Callable`):
|
| 291 |
+
The mask factory function describing the mask pattern.
|
| 292 |
+
attention_mask (`torch.Tensor`, optional):
|
| 293 |
+
The 2D attention mask corresponding to padded tokens of shape (batch_size, number_of_seen_tokens+q_length)
|
| 294 |
+
local_size (`int`, optional):
|
| 295 |
+
The size of the local attention, if we do not use full attention. This is used only if `allow_is_causal_skip=True`
|
| 296 |
+
to try to skip mask creation if possible.
|
| 297 |
+
allow_is_causal_skip (`bool`, optional):
|
| 298 |
+
Whether to allow to return `None` for the mask under conditions where we can use the `is_causal` argument in
|
| 299 |
+
`torch.sdpa` instead. Default to `True`.
|
| 300 |
+
allow_torch_fix (`bool`, optional):
|
| 301 |
+
Whether to update the mask in case a query is not attending to any tokens, to solve a bug in torch's older
|
| 302 |
+
versions. We need an arg to skip it when using eager. By default `True`.
|
| 303 |
+
|
| 304 |
+
|
| 305 |
+
## Creating a simple causal mask:
|
| 306 |
+
|
| 307 |
+
To create the following causal mask:
|
| 308 |
+
|
| 309 |
+
0 ■ ⬚ ⬚ ⬚ ⬚
|
| 310 |
+
1 ■ ■ ⬚ ⬚ ⬚
|
| 311 |
+
2 ■ ■ ■ ⬚ ⬚
|
| 312 |
+
3 ■ ■ ■ ■ ⬚
|
| 313 |
+
4 ■ ■ ■ ■ ■
|
| 314 |
+
|
| 315 |
+
You can do
|
| 316 |
+
|
| 317 |
+
```python
|
| 318 |
+
>>> sdpa_mask(batch_size=1, cache_position=torch.arange(5), kv_length=5)
|
| 319 |
+
>>> tensor([[[[ True, False, False, False, False],
|
| 320 |
+
[ True, True, False, False, False],
|
| 321 |
+
[ True, True, True, False, False],
|
| 322 |
+
[ True, True, True, True, False],
|
| 323 |
+
[ True, True, True, True, True]]]])
|
| 324 |
+
```
|
| 325 |
+
|
| 326 |
+
## Creating a sliding window mask:
|
| 327 |
+
|
| 328 |
+
To create the following sliding window mask (`sliding_window=3`):
|
| 329 |
+
|
| 330 |
+
0 ■ ⬚ ⬚ ⬚ ⬚
|
| 331 |
+
1 ■ ■ ⬚ ⬚ ⬚
|
| 332 |
+
2 ■ ■ ■ ⬚ ⬚
|
| 333 |
+
3 ⬚ ■ ■ ■ ⬚
|
| 334 |
+
4 ⬚ ⬚ ■ ■ ■
|
| 335 |
+
|
| 336 |
+
You can do
|
| 337 |
+
|
| 338 |
+
```python
|
| 339 |
+
>>> sdpa_mask(batch_size=1, cache_position=torch.arange(5), kv_length=5, mask_function=sliding_window_causal_mask_function(3))
|
| 340 |
+
>>> tensor([[[[ True, False, False, False, False],
|
| 341 |
+
[ True, True, False, False, False],
|
| 342 |
+
[ True, True, True, False, False],
|
| 343 |
+
[False, True, True, True, False],
|
| 344 |
+
[False, False, True, True, True]]]])
|
| 345 |
+
```
|
| 346 |
+
|
| 347 |
+
## Creating a chunked attention mask
|
| 348 |
+
|
| 349 |
+
To create the following chunked attention mask (`chunk_size=3`):
|
| 350 |
+
|
| 351 |
+
0 ■ ⬚ ⬚ ⬚ ⬚
|
| 352 |
+
1 ■ ■ ⬚ ⬚ ⬚
|
| 353 |
+
2 ■ ■ ■ ⬚ ⬚
|
| 354 |
+
3 ⬚ ⬚ ⬚ ■ ⬚
|
| 355 |
+
4 ⬚ ⬚ ⬚ ■ ■
|
| 356 |
+
|
| 357 |
+
You can do
|
| 358 |
+
|
| 359 |
+
```python
|
| 360 |
+
>>> sdpa_mask(batch_size=1, cache_position=torch.arange(5), kv_length=5, mask_function=chunked_causal_mask_function(3, torch.zeros(1, dtype=int)))
|
| 361 |
+
>>> tensor([[[[ True, False, False, False, False],
|
| 362 |
+
[ True, True, False, False, False],
|
| 363 |
+
[ True, True, True, False, False],
|
| 364 |
+
[False, False, False, True, False],
|
| 365 |
+
[False, False, False, True, True]]]])
|
| 366 |
+
```
|
| 367 |
+
|
| 368 |
+
"""
|
| 369 |
+
q_length = cache_position.shape[0]
|
| 370 |
+
# Potentially pad the 2D mask, and slice it correctly
|
| 371 |
+
padding_mask = prepare_padding_mask(attention_mask, kv_length, kv_offset, _slice=False)
|
| 372 |
+
|
| 373 |
+
# Under specific conditions, we can avoid materializing the mask, instead relying on the `is_causal` argument
|
| 374 |
+
if allow_is_causal_skip and _ignore_causal_mask_sdpa(padding_mask, q_length, kv_length, kv_offset, local_size):
|
| 375 |
+
return None
|
| 376 |
+
|
| 377 |
+
# Similar to `kv_arange = torch.arange(start=kv_offset, end=kv_offset + kv_length, device=cache_position.device)`
|
| 378 |
+
# but without data-dependent slicing (i.e. torch.compile friendly)
|
| 379 |
+
kv_arange = torch.arange(kv_length, device=cache_position.device)
|
| 380 |
+
kv_arange += kv_offset
|
| 381 |
+
|
| 382 |
+
# Potentially add the padding 2D mask
|
| 383 |
+
if padding_mask is not None:
|
| 384 |
+
mask_function = and_masks(mask_function, padding_mask_function(padding_mask))
|
| 385 |
+
|
| 386 |
+
batch_arange = torch.arange(batch_size, device=cache_position.device)
|
| 387 |
+
head_arange = torch.arange(1, device=cache_position.device)
|
| 388 |
+
# This creates the 4D mask easily. Note that we need this context manager as vmap cannot handle slicing a tensor from
|
| 389 |
+
# scalar tensor (it internally calls `.item()` which vmap does not allow, but this context works around it
|
| 390 |
+
# We don't need to add an offset to the mask_function either, as we vmap directly the correct indices for k and kv indices
|
| 391 |
+
with TransformGetItemToIndex():
|
| 392 |
+
causal_mask = _vmap_for_bhqkv(mask_function)(batch_arange, head_arange, cache_position, kv_arange)
|
| 393 |
+
|
| 394 |
+
return causal_mask
|
| 395 |
+
|
| 396 |
+
|
| 397 |
+
def sdpa_mask_older_torch(
|
| 398 |
+
batch_size: int,
|
| 399 |
+
cache_position: torch.Tensor,
|
| 400 |
+
kv_length: int,
|
| 401 |
+
kv_offset: int = 0,
|
| 402 |
+
mask_function: Callable = causal_mask_function,
|
| 403 |
+
attention_mask: Optional[torch.Tensor] = None,
|
| 404 |
+
local_size: Optional[int] = None,
|
| 405 |
+
allow_is_causal_skip: bool = True,
|
| 406 |
+
allow_torch_fix: bool = True,
|
| 407 |
+
**kwargs,
|
| 408 |
+
) -> Optional[torch.Tensor]:
|
| 409 |
+
"""
|
| 410 |
+
NOTE: This function is only used when torch version is torch<2.5 - see `sdpa_mask_recent_torch` otherwise.
|
| 411 |
+
|
| 412 |
+
Create a 4D boolean mask of shape `(batch_size, 1, query_length, kv_length)` where a value of True indicates that
|
| 413 |
+
the element should take part in the attention computation, and False that it should not.
|
| 414 |
+
If `allow_torch_fix=True` (the default), rows corresponding to query tokens that do not attend
|
| 415 |
+
to any other tokens (due to padding) will be fully attended to instead, in order to avoid `nan` propagation (this does
|
| 416 |
+
not change the final result).
|
| 417 |
+
|
| 418 |
+
Args:
|
| 419 |
+
batch_size (`int`):
|
| 420 |
+
The batch size of the input sequence.
|
| 421 |
+
cache_position (`torch.Tensor`):
|
| 422 |
+
A tensor of shape (query_length,) indicating the current indices of the input sequence elements.
|
| 423 |
+
kv_length (`int`):
|
| 424 |
+
The size that the key and value states will have during the attention computation.
|
| 425 |
+
kv_offset (`int`, optional):
|
| 426 |
+
An optional offset to indicate at which first position the key and values states will refer to.
|
| 427 |
+
mask_function (`Callable`):
|
| 428 |
+
The mask factory function describing the mask pattern.
|
| 429 |
+
attention_mask (`torch.Tensor`, optional):
|
| 430 |
+
The 2D attention mask corresponding to padded tokens of shape (batch_size, number_of_seen_tokens+q_length)
|
| 431 |
+
local_size (`int`, optional):
|
| 432 |
+
The size of the local attention, if we do not use full attention. This is used only if `allow_is_causal_skip=True`
|
| 433 |
+
to try to skip mask creation if possible.
|
| 434 |
+
allow_is_causal_skip (`bool`, optional):
|
| 435 |
+
Whether to allow to return `None` for the mask under conditions where we can use the `is_causal` argument in
|
| 436 |
+
`torch.sdpa` instead. Default to `True`.
|
| 437 |
+
allow_torch_fix (`bool`, optional):
|
| 438 |
+
Whether to update the mask in case a query is not attending to any tokens, to solve a bug in torch's older
|
| 439 |
+
versions. We need an arg to skip it when using eager. By default `True`.
|
| 440 |
+
"""
|
| 441 |
+
q_length = cache_position.shape[0]
|
| 442 |
+
# Potentially pad the 2D mask, and slice it correctly
|
| 443 |
+
padding_mask = prepare_padding_mask(attention_mask, kv_length, kv_offset)
|
| 444 |
+
|
| 445 |
+
# Under specific conditions, we can avoid materializing the mask, instead relying on the `is_causal` argument
|
| 446 |
+
if allow_is_causal_skip and _ignore_causal_mask_sdpa(padding_mask, q_length, kv_length, kv_offset, local_size):
|
| 447 |
+
return None
|
| 448 |
+
|
| 449 |
+
# Similar to `kv_arange = torch.arange(start=kv_offset, end=kv_offset + kv_length, device=cache_position.device)`
|
| 450 |
+
# but without data-dependent slicing (i.e. torch.compile friendly)
|
| 451 |
+
kv_arange = torch.arange(kv_length, device=cache_position.device)
|
| 452 |
+
kv_arange += kv_offset
|
| 453 |
+
|
| 454 |
+
# This creates the 4D mask easily. Note that we do not include vmap over the batch_idx dimension as well,
|
| 455 |
+
# as vmap cannot handle slicing a tensor from scalar tensor (it internally calls `.item()` which vmap does not allow
|
| 456 |
+
# However, in more recent version of Pytorch, a trick was introduced to handle it - which is the reason we have
|
| 457 |
+
# `sdpa_mask_recent_torch`, as it allows more general `mask_function`
|
| 458 |
+
causal_mask = _vmap_for_bhqkv(mask_function, bh_indices=False)(None, None, cache_position, kv_arange)
|
| 459 |
+
causal_mask = causal_mask[None, None, :, :].expand(batch_size, -1, -1, -1)
|
| 460 |
+
if padding_mask is not None:
|
| 461 |
+
causal_mask = causal_mask * padding_mask[:, None, None, :]
|
| 462 |
+
|
| 463 |
+
# Due to a bug in versions of torch<2.5, we need to update the mask in case a query is not attending to any
|
| 464 |
+
# tokens (due to padding). See details in https://github.com/pytorch/pytorch/issues/110213
|
| 465 |
+
if not _is_torch_greater_or_equal_than_2_5 and allow_torch_fix:
|
| 466 |
+
causal_mask |= torch.all(~causal_mask, dim=-1, keepdim=True)
|
| 467 |
+
return causal_mask
|
| 468 |
+
|
| 469 |
+
|
| 470 |
+
# We use the version with newer torch whenever possible, as it is more general and can handle arbitrary mask functions
|
| 471 |
+
# (especially mask_function indexing a tensor, such as the padding mask function)
|
| 472 |
+
sdpa_mask = sdpa_mask_recent_torch if _is_torch_greater_or_equal_than_2_6 else sdpa_mask_older_torch
|
| 473 |
+
|
| 474 |
+
|
| 475 |
+
def eager_mask(
|
| 476 |
+
batch_size: int,
|
| 477 |
+
cache_position: torch.Tensor,
|
| 478 |
+
kv_length: int,
|
| 479 |
+
kv_offset: int = 0,
|
| 480 |
+
mask_function: Callable = causal_mask_function,
|
| 481 |
+
attention_mask: Optional[torch.Tensor] = None,
|
| 482 |
+
dtype: torch.dtype = torch.float32,
|
| 483 |
+
**kwargs,
|
| 484 |
+
) -> torch.Tensor:
|
| 485 |
+
"""
|
| 486 |
+
Create a 4D float mask of shape `(batch_size, 1, query_length, kv_length)` where a value of 0 indicates that
|
| 487 |
+
the element should take part in the attention computation, and -inf (minimum value for the given `dtype`) that
|
| 488 |
+
it should not.
|
| 489 |
+
|
| 490 |
+
Args:
|
| 491 |
+
batch_size (`int`):
|
| 492 |
+
The batch size of the input sequence.
|
| 493 |
+
cache_position (`torch.Tensor`):
|
| 494 |
+
A tensor of shape (query_length,) indicating the current indices of the input sequence elements.
|
| 495 |
+
kv_length (`int`):
|
| 496 |
+
The size that the key and value states will have during the attention computation.
|
| 497 |
+
kv_offset (`int`, optional):
|
| 498 |
+
An optional offset to indicate at which first position the key and values states will refer to.
|
| 499 |
+
mask_function (`Callable`):
|
| 500 |
+
The mask factory function describing the mask pattern.
|
| 501 |
+
attention_mask (`torch.Tensor`, optional):
|
| 502 |
+
The 2D attention mask corresponding to padded tokens of shape (batch_size, number_of_seen_tokens+q_length)
|
| 503 |
+
dtype (`torch.dtype`, optional):
|
| 504 |
+
The dtype to use for the mask. By default, `torch.float32`.
|
| 505 |
+
"""
|
| 506 |
+
# The masks for eager attention are simply boolean mask from sdpa, casted to 0 and -inf
|
| 507 |
+
_ = kwargs.pop("allow_is_causal_skip", None)
|
| 508 |
+
mask = sdpa_mask(
|
| 509 |
+
batch_size=batch_size,
|
| 510 |
+
cache_position=cache_position,
|
| 511 |
+
kv_length=kv_length,
|
| 512 |
+
kv_offset=kv_offset,
|
| 513 |
+
mask_function=mask_function,
|
| 514 |
+
attention_mask=attention_mask,
|
| 515 |
+
allow_is_causal_skip=False,
|
| 516 |
+
allow_torch_fix=False,
|
| 517 |
+
**kwargs,
|
| 518 |
+
)
|
| 519 |
+
min_dtype = torch.finfo(dtype).min
|
| 520 |
+
# we need 0s where the tokens should be taken into account, and -inf otherwise (mask is already of boolean type)
|
| 521 |
+
mask = torch.where(mask, torch.tensor(0.0, device=mask.device, dtype=dtype), min_dtype)
|
| 522 |
+
return mask
|
| 523 |
+
|
| 524 |
+
|
| 525 |
+
def flash_attention_mask(
|
| 526 |
+
batch_size: int,
|
| 527 |
+
cache_position: torch.Tensor,
|
| 528 |
+
kv_length: int,
|
| 529 |
+
kv_offset: int = 0,
|
| 530 |
+
mask_function: Callable = causal_mask_function,
|
| 531 |
+
attention_mask: Optional[torch.Tensor] = None,
|
| 532 |
+
**kwargs,
|
| 533 |
+
):
|
| 534 |
+
"""
|
| 535 |
+
Create the attention mask necessary to use FA2. Since FA2 is un-padded by definition, here we simply return
|
| 536 |
+
`None` if the mask is fully causal, or we return the 2D mask which will then be used to extract the seq_lens.
|
| 537 |
+
We just slice it in case of sliding window.
|
| 538 |
+
|
| 539 |
+
Args:
|
| 540 |
+
batch_size (`int`):
|
| 541 |
+
The batch size of the input sequence.
|
| 542 |
+
cache_position (`torch.Tensor`):
|
| 543 |
+
A tensor of shape (query_length,) indicating the current indices of the input sequence elements.
|
| 544 |
+
kv_length (`int`):
|
| 545 |
+
The size that the key and value states will have during the attention computation.
|
| 546 |
+
kv_offset (`int`, optional):
|
| 547 |
+
An optional offset to indicate at which first position the key and values states will refer to.
|
| 548 |
+
mask_function (`Callable`):
|
| 549 |
+
The mask factory function describing the mask pattern.
|
| 550 |
+
attention_mask (`torch.Tensor`, optional):
|
| 551 |
+
The 2D attention mask corresponding to padded tokens of shape (batch_size, number_of_seen_tokens+q_length)
|
| 552 |
+
"""
|
| 553 |
+
if attention_mask is not None:
|
| 554 |
+
# Here we need to slice from the right if using sliding or chunked (for full attention, this is equivalent to doing nothing)
|
| 555 |
+
attention_mask = attention_mask[:, -kv_length:]
|
| 556 |
+
# We only return an actual mask if there is at least 1 padding token, otherwise we return `None` and use `is_causal` in FA2
|
| 557 |
+
# (note that the attention_mask is a boolean dtype here)
|
| 558 |
+
if attention_mask.all():
|
| 559 |
+
attention_mask = None
|
| 560 |
+
|
| 561 |
+
return attention_mask
|
| 562 |
+
|
| 563 |
+
|
| 564 |
+
def flex_attention_mask(
|
| 565 |
+
batch_size: int,
|
| 566 |
+
cache_position: torch.Tensor,
|
| 567 |
+
kv_length: int,
|
| 568 |
+
kv_offset: int = 0,
|
| 569 |
+
mask_function: Callable = causal_mask_function,
|
| 570 |
+
attention_mask: Optional[torch.Tensor] = None,
|
| 571 |
+
**kwargs,
|
| 572 |
+
) -> BlockMask:
|
| 573 |
+
"""
|
| 574 |
+
Create a 4D block mask which is a compressed representation of the full 4D block causal mask. BlockMask is essential
|
| 575 |
+
for performant computation of flex attention. See: https://pytorch.org/blog/flexattention/
|
| 576 |
+
|
| 577 |
+
Args:
|
| 578 |
+
batch_size (`int`):
|
| 579 |
+
The batch size of the input sequence.
|
| 580 |
+
cache_position (`torch.Tensor`):
|
| 581 |
+
A tensor of shape (query_length,) indicating the current indices of the input sequence elements.
|
| 582 |
+
kv_length (`int`):
|
| 583 |
+
The size that the key and value states will have during the attention computation.
|
| 584 |
+
kv_offset (`int`, optional):
|
| 585 |
+
An optional offset to indicate at which first position the key and values states will refer to.
|
| 586 |
+
mask_function (`Callable`):
|
| 587 |
+
The mask factory function describing the mask pattern.
|
| 588 |
+
attention_mask (`torch.Tensor`, optional):
|
| 589 |
+
The 2D attention mask corresponding to padded tokens of shape (batch_size, number_of_seen_tokens+q_length)
|
| 590 |
+
"""
|
| 591 |
+
q_length, q_offset = cache_position.shape[0], cache_position[0]
|
| 592 |
+
|
| 593 |
+
# Potentially add the padding 2D mask
|
| 594 |
+
if attention_mask is not None:
|
| 595 |
+
# Older torch (2.5.x) cannot handle sequences not in multiples of 128 (default block size)
|
| 596 |
+
# Hence we pad to multiples of this as a minimum to ensure this
|
| 597 |
+
pad_len = ((attention_mask.shape[1] // flex_default_block_size) + 1) * flex_default_block_size
|
| 598 |
+
pad_len = pad_len - attention_mask.shape[1]
|
| 599 |
+
if not _is_torch_greater_or_equal_than_2_6 and pad_len > 0:
|
| 600 |
+
attention_mask = torch.nn.functional.pad(attention_mask, value=0, pad=(0, pad_len))
|
| 601 |
+
|
| 602 |
+
padding_mask = prepare_padding_mask(attention_mask, kv_length, kv_offset, _slice=False)
|
| 603 |
+
mask_function = and_masks(mask_function, padding_mask_function(padding_mask))
|
| 604 |
+
|
| 605 |
+
# Add the offsets on top (because flex interface only allows length, not start and end indices)
|
| 606 |
+
mask_function = add_offsets_to_mask_function(mask_function, q_offset, kv_offset)
|
| 607 |
+
|
| 608 |
+
# Finally create the block mask
|
| 609 |
+
block_mask = create_block_mask(
|
| 610 |
+
mask_mod=mask_function,
|
| 611 |
+
B=batch_size,
|
| 612 |
+
H=None,
|
| 613 |
+
Q_LEN=q_length,
|
| 614 |
+
KV_LEN=kv_length,
|
| 615 |
+
device=cache_position.device,
|
| 616 |
+
_compile=_is_torch_greater_or_equal_than_2_6,
|
| 617 |
+
)
|
| 618 |
+
return block_mask
|
| 619 |
+
|
| 620 |
+
|
| 621 |
+
class AttentionMaskInterface(GeneralInterface):
|
| 622 |
+
# Class instance object, so that a call to `register` can be reflected into all other files correctly, even if
|
| 623 |
+
# a new instance is created (in order to locally override a given function)
|
| 624 |
+
_global_mapping = {
|
| 625 |
+
"sdpa": sdpa_mask,
|
| 626 |
+
"eager": eager_mask,
|
| 627 |
+
"flash_attention_2": flash_attention_mask,
|
| 628 |
+
"flash_attention_3": flash_attention_mask,
|
| 629 |
+
"flex_attention": flex_attention_mask,
|
| 630 |
+
}
|
| 631 |
+
|
| 632 |
+
|
| 633 |
+
# Global AttentionMaskInterface shared by all models which do not need to overwrite any of the existing ones
|
| 634 |
+
ALL_MASK_ATTENTION_FUNCTIONS: AttentionMaskInterface = AttentionMaskInterface()
|
| 635 |
+
|
| 636 |
+
|
| 637 |
+
def find_packed_sequence_indices(position_ids: torch.Tensor) -> torch.Tensor:
|
| 638 |
+
"""
|
| 639 |
+
Find the indices of the sequence to which each new query token in the sequence belongs when using packed
|
| 640 |
+
tensor format (i.e. several sequences packed in the same batch dimension).
|
| 641 |
+
|
| 642 |
+
Args:
|
| 643 |
+
position_ids (`torch.Tensor`)
|
| 644 |
+
A 2D tensor of shape (batch_size, query_length) indicating the positions of each token in the sequences.
|
| 645 |
+
|
| 646 |
+
Returns:
|
| 647 |
+
A 2D tensor where each similar integer indicates that the tokens belong to the same sequence. For example, if we
|
| 648 |
+
pack 3 sequences of 2, 3 and 1 tokens respectively along a single batch dim, this will return [[0, 0, 1, 1, 1, 2]].
|
| 649 |
+
"""
|
| 650 |
+
# What separate different sequences is when 2 consecutive positions_ids are separated by more than 1. So
|
| 651 |
+
# taking the diff (by prepending the first value - 1 to keep correct indexing) and applying cumsum to the result
|
| 652 |
+
# gives exactly the sequence indices
|
| 653 |
+
# Note that we assume that a single sequence cannot span several batch dimensions, i.e. 1 single sequence
|
| 654 |
+
# cannot be part of the end of the first batch dim and the start of the 2nd one for example
|
| 655 |
+
first_dummy_value = position_ids[:, :1] - 1 # We just need the diff on this first value to be 1
|
| 656 |
+
position_diff = torch.diff(position_ids, prepend=first_dummy_value, dim=-1)
|
| 657 |
+
packed_sequence_mask = (position_diff != 1).cumsum(-1)
|
| 658 |
+
|
| 659 |
+
# Here it would be nice to return None if we did not detect packed sequence format, i.e. if `packed_sequence_mask[:, -1] == 0`
|
| 660 |
+
# but it causes issues with export
|
| 661 |
+
return packed_sequence_mask
|
| 662 |
+
|
| 663 |
+
|
| 664 |
+
def _preprocess_mask_arguments(
|
| 665 |
+
config: PretrainedConfig,
|
| 666 |
+
input_embeds: torch.Tensor,
|
| 667 |
+
attention_mask: Optional[Union[torch.Tensor, BlockMask]],
|
| 668 |
+
cache_position: torch.Tensor,
|
| 669 |
+
past_key_values: Optional[Cache],
|
| 670 |
+
position_ids: Optional[torch.Tensor],
|
| 671 |
+
layer_idx: Optional[int],
|
| 672 |
+
) -> tuple[bool, Optional[Union[torch.Tensor, BlockMask]], int, int]:
|
| 673 |
+
"""
|
| 674 |
+
Perform some common pre-processing of the mask arguments we get from the modeling code. Mostly determine the
|
| 675 |
+
key-value length and offsets, and if we should early exit or not.
|
| 676 |
+
|
| 677 |
+
Args:
|
| 678 |
+
config (`PretrainedConfig`):
|
| 679 |
+
The model config.
|
| 680 |
+
input_embeds (`torch.Tensor`):
|
| 681 |
+
The input embeddings of shape (batch_size, query_length, hidden_dim). This is used only to infer the
|
| 682 |
+
batch size, query length and dtype.
|
| 683 |
+
attention_mask (`torch.Tensor`, optional):
|
| 684 |
+
The 2D attention mask corresponding to padded tokens of shape (batch_size, number_of_seen_tokens+q_length).
|
| 685 |
+
It can also be an already prepared 4D mask, in which case it is returned as-is.
|
| 686 |
+
cache_position (`torch.Tensor`):
|
| 687 |
+
A tensor of shape (query_length,) indicating the current indices of the input sequence elements.
|
| 688 |
+
past_key_values (`Cache`, optional):
|
| 689 |
+
The past key values, if we use a cache.
|
| 690 |
+
position_ids (`torch.Tensor`, optional)
|
| 691 |
+
A 2D tensor of shape (batch_size, query_length) indicating the positions of each token in the sequences.
|
| 692 |
+
layer_idx (`int`, optional):
|
| 693 |
+
If `past_key_values` is not None, this is the layer index of the cache from which to get the key-value
|
| 694 |
+
length and offset. Indeed, for hybrid caches, different layers may return different lengths.
|
| 695 |
+
|
| 696 |
+
Returns:
|
| 697 |
+
early_exit (`bool`):
|
| 698 |
+
Whether we should early exit mask creation, and return the mask as-is.
|
| 699 |
+
attention_mask (`torch.Tensor` or `BlockMask` or `None`):
|
| 700 |
+
The attention mask to either return immediately, or to use in downstream mask creation.
|
| 701 |
+
packed_sequence_mask (`torch.Tensor`, optional):
|
| 702 |
+
In case we detected packed sequence format, this is a tensor where each similar integer indicates that
|
| 703 |
+
the tokens belong to the same sequence.
|
| 704 |
+
kv_length (`int`):
|
| 705 |
+
The size that the key and value states will have during the attention computation.
|
| 706 |
+
kv_offset (`int`):
|
| 707 |
+
An offset to indicate at which first position the key and values states will refer to.
|
| 708 |
+
"""
|
| 709 |
+
# If the mask is already 4D, simply return as-is (it was already prepared, or it is custom)
|
| 710 |
+
if isinstance(attention_mask, (torch.Tensor, BlockMask)) and len(attention_mask.shape) == 4:
|
| 711 |
+
return True, attention_mask, None, None, None
|
| 712 |
+
|
| 713 |
+
# For TGI/vLLM backends, or other custom attention without equivalent mask creation: we don't need a mask!
|
| 714 |
+
# Note: it's not ideal to check the `_global_mapping` attribute instead of the object itself, however otherwise
|
| 715 |
+
# full graph dynamo tracing (i.e. torch.export or compile with `fullgraph=True`) will fail on Python<3.11
|
| 716 |
+
# with `torch._dynamo.exc.Unsupported: 'inline in skipfiles:Mapping.__contains__ | __contains__, skipped
|
| 717 |
+
# according trace_rules.lookup SKIP_DIRS'` -- can be removed when we require Python>=3.11
|
| 718 |
+
if config._attn_implementation not in ALL_MASK_ATTENTION_FUNCTIONS._global_mapping:
|
| 719 |
+
return True, None, None, None, None
|
| 720 |
+
|
| 721 |
+
# Move the mask to correct device, and potentially switch dtype for efficiency
|
| 722 |
+
if attention_mask is not None and attention_mask.ndim == 2:
|
| 723 |
+
attention_mask = attention_mask.to(device=cache_position.device, dtype=torch.bool)
|
| 724 |
+
|
| 725 |
+
# If using a cache, it can give all information about mask sizes based on seen tokens
|
| 726 |
+
if past_key_values is not None:
|
| 727 |
+
kv_length, kv_offset = past_key_values.get_mask_sizes(cache_position, layer_idx)
|
| 728 |
+
# Otherwise, the sizes are simply the input sizes
|
| 729 |
+
else:
|
| 730 |
+
kv_length, kv_offset = input_embeds.shape[1], 0
|
| 731 |
+
|
| 732 |
+
# We check the position_ids for potential packed sequence format (only if the 2D attention mask is explicitly None,
|
| 733 |
+
# and we don't have past_key_values, i.e. generally a training setup)
|
| 734 |
+
packed_sequence_mask = None
|
| 735 |
+
if position_ids is not None and attention_mask is None and past_key_values is None:
|
| 736 |
+
batch_size = input_embeds.shape[0]
|
| 737 |
+
# The position ids are sometimes just unsqueezed, without being expanded
|
| 738 |
+
if batch_size != position_ids.shape[0]:
|
| 739 |
+
position_ids = position_ids.expand(batch_size, -1)
|
| 740 |
+
packed_sequence_mask = find_packed_sequence_indices(position_ids)
|
| 741 |
+
|
| 742 |
+
return False, attention_mask, packed_sequence_mask, kv_length, kv_offset
|
| 743 |
+
|
| 744 |
+
|
| 745 |
+
def create_causal_mask(
|
| 746 |
+
config: PretrainedConfig,
|
| 747 |
+
input_embeds: torch.Tensor,
|
| 748 |
+
attention_mask: Optional[torch.Tensor],
|
| 749 |
+
cache_position: torch.Tensor,
|
| 750 |
+
past_key_values: Optional[Cache],
|
| 751 |
+
position_ids: Optional[torch.Tensor] = None,
|
| 752 |
+
or_mask_function: Optional[Callable] = None,
|
| 753 |
+
and_mask_function: Optional[Callable] = None,
|
| 754 |
+
) -> Optional[Union[torch.Tensor, BlockMask]]:
|
| 755 |
+
"""
|
| 756 |
+
Create a standard causal mask based on the attention implementation used (stored in the config). If `past_key_values`
|
| 757 |
+
has an hybrid cache structure, this function will return the mask corresponding to one of the "full_attention" layers (to align
|
| 758 |
+
to what is needed in the `modeling_xxx.py` files).
|
| 759 |
+
|
| 760 |
+
Args:
|
| 761 |
+
config (`PretrainedConfig`):
|
| 762 |
+
The model config.
|
| 763 |
+
input_embeds (`torch.Tensor`):
|
| 764 |
+
The input embeddings of shape (batch_size, query_length, hidden_dim). This is used only to infer the
|
| 765 |
+
batch size, query length and dtype.
|
| 766 |
+
attention_mask (`torch.Tensor`, optional):
|
| 767 |
+
The 2D attention mask corresponding to padded tokens of shape (batch_size, number_of_seen_tokens+q_length).
|
| 768 |
+
It can also be an already prepared 4D mask, in which case it is returned as-is.
|
| 769 |
+
cache_position (`torch.Tensor`):
|
| 770 |
+
A tensor of shape (query_length,) indicating the current indices of the input sequence elements.
|
| 771 |
+
past_key_values (`Cache`, optional):
|
| 772 |
+
The past key values, if we use a cache.
|
| 773 |
+
position_ids (`torch.Tensor`, optional)
|
| 774 |
+
A 2D tensor of shape (batch_size, query_length) indicating the positions of each token in the sequences.
|
| 775 |
+
or_mask_function (`Callable`, optional):
|
| 776 |
+
An optional mask function to combine with the causal mask function (by doing the union of both). This is
|
| 777 |
+
useful to easily overlay another mask on top of the causal one, for example for image tokens handling.
|
| 778 |
+
and_mask_function (`Callable`, optional):
|
| 779 |
+
An optional mask function to combine with the causal mask function (by doing the intersection of both). This is
|
| 780 |
+
useful to easily overlay another mask on top of the causal one, for example for image tokens handling.
|
| 781 |
+
"""
|
| 782 |
+
# If we have an hybrid cache structure, here we want to create the mask for the full layers
|
| 783 |
+
if hasattr(past_key_values, "is_sliding") and False in past_key_values.is_sliding:
|
| 784 |
+
layer_idx = past_key_values.is_sliding.index(False)
|
| 785 |
+
else:
|
| 786 |
+
layer_idx = 0
|
| 787 |
+
|
| 788 |
+
early_exit, attention_mask, packed_sequence_mask, kv_length, kv_offset = _preprocess_mask_arguments(
|
| 789 |
+
config, input_embeds, attention_mask, cache_position, past_key_values, position_ids, layer_idx
|
| 790 |
+
)
|
| 791 |
+
if early_exit:
|
| 792 |
+
return attention_mask
|
| 793 |
+
|
| 794 |
+
batch_size, dtype = input_embeds.shape[0], input_embeds.dtype
|
| 795 |
+
mask_factory_function = causal_mask_function
|
| 796 |
+
mask_interface = ALL_MASK_ATTENTION_FUNCTIONS[config._attn_implementation]
|
| 797 |
+
|
| 798 |
+
# Do not allow skip if we are compiling (this is to match BC)
|
| 799 |
+
# TODO: cyril -> probably revisit and remove this, but a lot of tests rely on it
|
| 800 |
+
if _is_torch_xpu_available:
|
| 801 |
+
allow_is_causal_skip = True
|
| 802 |
+
else:
|
| 803 |
+
allow_is_causal_skip = not getattr(past_key_values, "is_compileable", False)
|
| 804 |
+
|
| 805 |
+
# Allow slight deviations from causal mask
|
| 806 |
+
# Note that it is very important to apply this before any other deviations of the mask (such as packed sequence mask,
|
| 807 |
+
# padding mask, etc) as the resulting mask may otherwise not be correct!
|
| 808 |
+
if or_mask_function is not None:
|
| 809 |
+
if not _is_torch_greater_or_equal_than_2_6:
|
| 810 |
+
raise ValueError("Using `or_mask_function` or `and_mask_function` arguments require torch>=2.6")
|
| 811 |
+
mask_factory_function = or_masks(mask_factory_function, or_mask_function)
|
| 812 |
+
allow_is_causal_skip = False
|
| 813 |
+
if and_mask_function is not None:
|
| 814 |
+
if not _is_torch_greater_or_equal_than_2_6:
|
| 815 |
+
raise ValueError("Using `or_mask_function` or `and_mask_function` arguments require torch>=2.6")
|
| 816 |
+
mask_factory_function = and_masks(mask_factory_function, and_mask_function)
|
| 817 |
+
allow_is_causal_skip = False
|
| 818 |
+
|
| 819 |
+
# If we detected packing format
|
| 820 |
+
if packed_sequence_mask is not None and _is_torch_greater_or_equal_than_2_6:
|
| 821 |
+
mask_factory_function = and_masks(mask_factory_function, packed_sequence_mask_function(packed_sequence_mask))
|
| 822 |
+
allow_is_causal_skip = False
|
| 823 |
+
|
| 824 |
+
# We now create the mask
|
| 825 |
+
causal_mask = mask_interface(
|
| 826 |
+
batch_size=batch_size,
|
| 827 |
+
cache_position=cache_position,
|
| 828 |
+
kv_length=kv_length,
|
| 829 |
+
kv_offset=kv_offset,
|
| 830 |
+
mask_function=mask_factory_function,
|
| 831 |
+
attention_mask=attention_mask,
|
| 832 |
+
allow_is_causal_skip=allow_is_causal_skip, # additional kwarg for sdpa
|
| 833 |
+
dtype=dtype, # Additional kwarg for eager
|
| 834 |
+
config=config, # Pass the config as well, in case someone wants to easily have their own mask_interface
|
| 835 |
+
)
|
| 836 |
+
return causal_mask
|
| 837 |
+
|
| 838 |
+
|
| 839 |
+
def create_sliding_window_causal_mask(
|
| 840 |
+
config: PretrainedConfig,
|
| 841 |
+
input_embeds: torch.Tensor,
|
| 842 |
+
attention_mask: Optional[torch.Tensor],
|
| 843 |
+
cache_position: torch.Tensor,
|
| 844 |
+
past_key_values: Optional[Cache],
|
| 845 |
+
position_ids: Optional[torch.Tensor] = None,
|
| 846 |
+
or_mask_function: Optional[Callable] = None,
|
| 847 |
+
and_mask_function: Optional[Callable] = None,
|
| 848 |
+
) -> Optional[Union[torch.Tensor, BlockMask]]:
|
| 849 |
+
"""
|
| 850 |
+
Create a sliding window causal mask based on the attention implementation used (stored in the config). This type
|
| 851 |
+
of attention pattern was mostly democratized by Mistral. If `past_key_values` has an hybrid cache structure, this
|
| 852 |
+
function will return the mask corresponding to one of the "sliding_attention" layers (to align to what is needed in the
|
| 853 |
+
`modeling_xxx.py` files).
|
| 854 |
+
|
| 855 |
+
Args:
|
| 856 |
+
config (`PretrainedConfig`):
|
| 857 |
+
The model config.
|
| 858 |
+
input_embeds (`torch.Tensor`):
|
| 859 |
+
The input embeddings of shape (batch_size, query_length, hidden_dim). This is used only to infer the
|
| 860 |
+
batch size, query length and dtype.
|
| 861 |
+
attention_mask (`torch.Tensor`, optional):
|
| 862 |
+
The 2D attention mask corresponding to padded tokens of shape (batch_size, number_of_seen_tokens+q_length).
|
| 863 |
+
It can also be an already prepared 4D mask, in which case it is returned as-is.
|
| 864 |
+
cache_position (`torch.Tensor`):
|
| 865 |
+
A tensor of shape (query_length,) indicating the current indices of the input sequence elements.
|
| 866 |
+
past_key_values (`Cache`, optional):
|
| 867 |
+
The past key values, if we use a cache.
|
| 868 |
+
position_ids (`torch.Tensor`, optional)
|
| 869 |
+
A 2D tensor of shape (batch_size, query_length) indicating the positions of each token in the sequences.
|
| 870 |
+
or_mask_function (`Callable`, optional):
|
| 871 |
+
An optional mask function to combine with the sliding causal mask function (by doing the union of both). This is
|
| 872 |
+
useful to easily overlay another mask on top of the sliding causal one, for example for image tokens handling.
|
| 873 |
+
and_mask_function (`Callable`, optional):
|
| 874 |
+
An optional mask function to combine with the sliding causal mask function (by doing the intersection of both). This is
|
| 875 |
+
useful to easily overlay another mask on top of the sliding causal one, for example for image tokens handling.
|
| 876 |
+
"""
|
| 877 |
+
# If we have an hybrid cache structure, here we want to create the mask for the sliding layers
|
| 878 |
+
if hasattr(past_key_values, "is_sliding") and True in past_key_values.is_sliding:
|
| 879 |
+
layer_idx = past_key_values.is_sliding.index(True)
|
| 880 |
+
else:
|
| 881 |
+
layer_idx = 0
|
| 882 |
+
|
| 883 |
+
early_exit, attention_mask, packed_sequence_mask, kv_length, kv_offset = _preprocess_mask_arguments(
|
| 884 |
+
config, input_embeds, attention_mask, cache_position, past_key_values, position_ids, layer_idx
|
| 885 |
+
)
|
| 886 |
+
if early_exit:
|
| 887 |
+
return attention_mask
|
| 888 |
+
|
| 889 |
+
sliding_window = getattr(config, "sliding_window", None)
|
| 890 |
+
if sliding_window is None:
|
| 891 |
+
raise ValueError("Could not find a `sliding_window` argument in the config, or it is not set")
|
| 892 |
+
|
| 893 |
+
batch_size, dtype = input_embeds.shape[0], input_embeds.dtype
|
| 894 |
+
mask_factory_function = sliding_window_causal_mask_function(sliding_window)
|
| 895 |
+
mask_interface = ALL_MASK_ATTENTION_FUNCTIONS[config._attn_implementation]
|
| 896 |
+
|
| 897 |
+
# Do not allow skip if we are compiling (this is to match BC)
|
| 898 |
+
# TODO: cyril -> probably revisit and remove this, but a lot of tests rely on it
|
| 899 |
+
allow_is_causal_skip = not getattr(past_key_values, "is_compileable", False)
|
| 900 |
+
|
| 901 |
+
# Allow slight deviations from causal mask
|
| 902 |
+
# Note that it is very important to apply this before any other deviations of the mask (such as packed sequence mask,
|
| 903 |
+
# padding mask, etc) as the resulting mask may otherwise not be correct!
|
| 904 |
+
if or_mask_function is not None:
|
| 905 |
+
if not _is_torch_greater_or_equal_than_2_6:
|
| 906 |
+
raise ValueError("Using `or_mask_function` or `and_mask_function` arguments require torch>=2.6")
|
| 907 |
+
mask_factory_function = or_masks(mask_factory_function, or_mask_function)
|
| 908 |
+
allow_is_causal_skip = False
|
| 909 |
+
if and_mask_function is not None:
|
| 910 |
+
if not _is_torch_greater_or_equal_than_2_6:
|
| 911 |
+
raise ValueError("Using `or_mask_function` or `and_mask_function` arguments require torch>=2.6")
|
| 912 |
+
mask_factory_function = and_masks(mask_factory_function, and_mask_function)
|
| 913 |
+
allow_is_causal_skip = False
|
| 914 |
+
|
| 915 |
+
# If we detected packing format
|
| 916 |
+
if packed_sequence_mask is not None and _is_torch_greater_or_equal_than_2_6:
|
| 917 |
+
mask_factory_function = and_masks(mask_factory_function, packed_sequence_mask_function(packed_sequence_mask))
|
| 918 |
+
allow_is_causal_skip = False
|
| 919 |
+
|
| 920 |
+
# We now create the mask
|
| 921 |
+
causal_mask = mask_interface(
|
| 922 |
+
batch_size=batch_size,
|
| 923 |
+
cache_position=cache_position,
|
| 924 |
+
kv_length=kv_length,
|
| 925 |
+
kv_offset=kv_offset,
|
| 926 |
+
mask_function=mask_factory_function,
|
| 927 |
+
attention_mask=attention_mask,
|
| 928 |
+
allow_is_causal_skip=allow_is_causal_skip, # additional kwarg for sdpa
|
| 929 |
+
local_size=sliding_window, # Additional kwarg for sdpa
|
| 930 |
+
dtype=dtype, # Additional kwarg for eager
|
| 931 |
+
config=config, # Pass the config as well, in case someone wants to easily have their own mask_interface
|
| 932 |
+
)
|
| 933 |
+
return causal_mask
|
| 934 |
+
|
| 935 |
+
|
| 936 |
+
def create_chunked_causal_mask(
|
| 937 |
+
config: PretrainedConfig,
|
| 938 |
+
input_embeds: torch.Tensor,
|
| 939 |
+
attention_mask: Optional[torch.Tensor],
|
| 940 |
+
cache_position: torch.Tensor,
|
| 941 |
+
past_key_values: Optional[Cache],
|
| 942 |
+
position_ids: Optional[torch.Tensor] = None,
|
| 943 |
+
or_mask_function: Optional[Callable] = None,
|
| 944 |
+
and_mask_function: Optional[Callable] = None,
|
| 945 |
+
) -> Optional[Union[torch.Tensor, BlockMask]]:
|
| 946 |
+
"""
|
| 947 |
+
Create a chunked attention causal mask based on the attention implementation used (stored in the config). This type
|
| 948 |
+
of attention pattern was mostly democratized by Llama4. If `past_key_values` has an hybrid cache structure, this
|
| 949 |
+
function will return the mask corresponding to one of the "chunked_attention" layers (to align to what is needed in the
|
| 950 |
+
`modeling_xxx.py` files).
|
| 951 |
+
|
| 952 |
+
Args:
|
| 953 |
+
config (`PretrainedConfig`):
|
| 954 |
+
The model config.
|
| 955 |
+
input_embeds (`torch.Tensor`):
|
| 956 |
+
The input embeddings of shape (batch_size, query_length, hidden_dim). This is used only to infer the
|
| 957 |
+
batch size, query length and dtype.
|
| 958 |
+
attention_mask (`torch.Tensor`, optional):
|
| 959 |
+
The 2D attention mask corresponding to padded tokens of shape (batch_size, number_of_seen_tokens+q_length).
|
| 960 |
+
It can also be an already prepared 4D mask, in which case it is returned as-is.
|
| 961 |
+
cache_position (`torch.Tensor`):
|
| 962 |
+
A tensor of shape (query_length,) indicating the current indices of the input sequence elements.
|
| 963 |
+
past_key_values (`Cache`, optional):
|
| 964 |
+
The past key values, if we use a cache.
|
| 965 |
+
position_ids (`torch.Tensor`, optional)
|
| 966 |
+
A 2D tensor of shape (batch_size, query_length) indicating the positions of each token in the sequences.
|
| 967 |
+
or_mask_function (`Callable`, optional):
|
| 968 |
+
An optional mask function to combine with the chunked causal mask function (by doing the union of both). This is
|
| 969 |
+
useful to easily overlay another mask on top of the chunked causal one, for example for image tokens handling.
|
| 970 |
+
and_mask_function (`Callable`, optional):
|
| 971 |
+
An optional mask function to combine with the chunked causal mask function (by doing the intersection of both). This is
|
| 972 |
+
useful to easily overlay another mask on top of the chunked causal one, for example for image tokens handling.
|
| 973 |
+
"""
|
| 974 |
+
# If we have an hybrid cache structure, here we want to create the mask for the sliding layers
|
| 975 |
+
if hasattr(past_key_values, "is_sliding") and True in past_key_values.is_sliding:
|
| 976 |
+
layer_idx = past_key_values.is_sliding.index(True)
|
| 977 |
+
else:
|
| 978 |
+
layer_idx = 0
|
| 979 |
+
|
| 980 |
+
early_exit, attention_mask, packed_sequence_mask, kv_length, kv_offset = _preprocess_mask_arguments(
|
| 981 |
+
config, input_embeds, attention_mask, cache_position, past_key_values, position_ids, layer_idx
|
| 982 |
+
)
|
| 983 |
+
if early_exit:
|
| 984 |
+
return attention_mask
|
| 985 |
+
|
| 986 |
+
chunk_size = getattr(config, "attention_chunk_size", None)
|
| 987 |
+
if chunk_size is None:
|
| 988 |
+
raise ValueError("Could not find an `attention_chunk_size` argument in the config, or it is not set")
|
| 989 |
+
|
| 990 |
+
# Raise if using chunked attention on context too large with FA2
|
| 991 |
+
if config._attn_implementation == "flash_attention_2" and kv_length + kv_offset > chunk_size:
|
| 992 |
+
raise ValueError(
|
| 993 |
+
"Flash attention 2 cannot handle chunked attention, and the key-value length is larger than the chunk size so the "
|
| 994 |
+
"chunked pattern cannot be respected. You should use another `attn_implementation` when instantiating the model"
|
| 995 |
+
)
|
| 996 |
+
|
| 997 |
+
batch_size, dtype = input_embeds.shape[0], input_embeds.dtype
|
| 998 |
+
# For chunked attention and batched inputs, we need to take the number of left padding tokens into account
|
| 999 |
+
# to start the chunk from the actual start of the sequence for the padded sequence
|
| 1000 |
+
if attention_mask is not None:
|
| 1001 |
+
# Only count the left padding tokens, not all of them
|
| 1002 |
+
left_padding_tokens = (attention_mask.cumsum(dim=-1) == torch.zeros_like(attention_mask)).sum(dim=-1)
|
| 1003 |
+
else:
|
| 1004 |
+
left_padding_tokens = torch.zeros(batch_size, device=cache_position.device, dtype=int)
|
| 1005 |
+
# Raise a warning for older versions if the problematic left-padding situation arises
|
| 1006 |
+
if (
|
| 1007 |
+
not _is_torch_greater_or_equal_than_2_6
|
| 1008 |
+
and kv_length + kv_offset > chunk_size
|
| 1009 |
+
and (left_padding_tokens > 0).any()
|
| 1010 |
+
):
|
| 1011 |
+
logger.warning_once(
|
| 1012 |
+
"Due to limitations of your current torch version, we cannot correctly account for the left-padding "
|
| 1013 |
+
"when computing the chunked attention pattern. This will lead to a wrong attention mask for the padded "
|
| 1014 |
+
"sequences. Behavior will be undefined. Please upgrade to `torch>=2.6` to solve this issue."
|
| 1015 |
+
)
|
| 1016 |
+
mask_factory_function = chunked_causal_mask_function(chunk_size, left_padding_tokens)
|
| 1017 |
+
mask_interface = ALL_MASK_ATTENTION_FUNCTIONS[config._attn_implementation]
|
| 1018 |
+
|
| 1019 |
+
# Do not allow skip if we are compiling (this is to match BC)
|
| 1020 |
+
# TODO: cyril -> probably revisit and remove this, but a lot of tests rely on it
|
| 1021 |
+
allow_is_causal_skip = not getattr(past_key_values, "is_compileable", False)
|
| 1022 |
+
|
| 1023 |
+
# Allow slight deviations from causal mask
|
| 1024 |
+
# Note that it is very important to apply this before any other deviations of the mask (such as packed sequence mask,
|
| 1025 |
+
# padding mask, etc) as the resulting mask may otherwise not be correct!
|
| 1026 |
+
if or_mask_function is not None:
|
| 1027 |
+
if not _is_torch_greater_or_equal_than_2_6:
|
| 1028 |
+
raise ValueError("Using `or_mask_function` or `and_mask_function` arguments require torch>=2.6")
|
| 1029 |
+
mask_factory_function = or_masks(mask_factory_function, or_mask_function)
|
| 1030 |
+
allow_is_causal_skip = False
|
| 1031 |
+
if and_mask_function is not None:
|
| 1032 |
+
if not _is_torch_greater_or_equal_than_2_6:
|
| 1033 |
+
raise ValueError("Using `or_mask_function` or `and_mask_function` arguments require torch>=2.6")
|
| 1034 |
+
mask_factory_function = and_masks(mask_factory_function, and_mask_function)
|
| 1035 |
+
allow_is_causal_skip = False
|
| 1036 |
+
|
| 1037 |
+
# If we detected packing format
|
| 1038 |
+
if packed_sequence_mask is not None and _is_torch_greater_or_equal_than_2_6:
|
| 1039 |
+
mask_factory_function = and_masks(mask_factory_function, packed_sequence_mask_function(packed_sequence_mask))
|
| 1040 |
+
allow_is_causal_skip = False
|
| 1041 |
+
|
| 1042 |
+
# We now create the mask
|
| 1043 |
+
causal_mask = mask_interface(
|
| 1044 |
+
batch_size=batch_size,
|
| 1045 |
+
cache_position=cache_position,
|
| 1046 |
+
kv_length=kv_length,
|
| 1047 |
+
kv_offset=kv_offset,
|
| 1048 |
+
mask_function=mask_factory_function,
|
| 1049 |
+
attention_mask=attention_mask,
|
| 1050 |
+
allow_is_causal_skip=allow_is_causal_skip, # additional kwarg for sdpa
|
| 1051 |
+
local_size=chunk_size, # Additional kwarg for sdpa
|
| 1052 |
+
dtype=dtype, # Additional kwarg for eager
|
| 1053 |
+
config=config, # Pass the config as well, in case someone wants to easily have their own mask_interface
|
| 1054 |
+
)
|
| 1055 |
+
return causal_mask
|
| 1056 |
+
|
| 1057 |
+
|
| 1058 |
+
LAYER_PATTERN_TO_MASK_FUNCTION_MAPPING = {
|
| 1059 |
+
"full_attention": create_causal_mask,
|
| 1060 |
+
"sliding_attention": create_sliding_window_causal_mask,
|
| 1061 |
+
"chunked_attention": create_chunked_causal_mask,
|
| 1062 |
+
}
|
| 1063 |
+
|
| 1064 |
+
|
| 1065 |
+
def create_masks_for_generate(
|
| 1066 |
+
config: PretrainedConfig,
|
| 1067 |
+
input_embeds: torch.Tensor,
|
| 1068 |
+
attention_mask: Optional[torch.Tensor],
|
| 1069 |
+
cache_position: torch.Tensor,
|
| 1070 |
+
past_key_values: Optional[Cache],
|
| 1071 |
+
position_ids: Optional[torch.Tensor] = None,
|
| 1072 |
+
or_mask_function: Optional[Callable] = None,
|
| 1073 |
+
and_mask_function: Optional[Callable] = None,
|
| 1074 |
+
**kwargs,
|
| 1075 |
+
):
|
| 1076 |
+
"""
|
| 1077 |
+
This function mimics how we create the masks in the `modeling_xxx.py` files, and is used in `generate` in order
|
| 1078 |
+
to easily create the masks in advance, when we compile the forwards with Static caches.
|
| 1079 |
+
|
| 1080 |
+
Args:
|
| 1081 |
+
config (`PretrainedConfig`):
|
| 1082 |
+
The model config.
|
| 1083 |
+
input_embeds (`torch.Tensor`):
|
| 1084 |
+
The input embeddings of shape (batch_size, query_length, hidden_dim). This is used only to infer the
|
| 1085 |
+
batch size, query length and dtype.
|
| 1086 |
+
attention_mask (`torch.Tensor`, optional):
|
| 1087 |
+
The 2D attention mask corresponding to padded tokens of shape (batch_size, number_of_seen_tokens+q_length).
|
| 1088 |
+
It can also be an already prepared 4D mask, in which case it is returned as-is.
|
| 1089 |
+
cache_position (`torch.Tensor`):
|
| 1090 |
+
A tensor of shape (query_length,) indicating the current indices of the input sequence elements.
|
| 1091 |
+
past_key_values (`Cache`, optional):
|
| 1092 |
+
The past key values, if we use a cache.
|
| 1093 |
+
position_ids (`torch.Tensor`, optional)
|
| 1094 |
+
A 2D tensor of shape (batch_size, query_length) indicating the positions of each token in the sequences.
|
| 1095 |
+
or_mask_function (`Callable`, optional):
|
| 1096 |
+
An optional mask function to combine with the other mask function (by doing the union of both). This is
|
| 1097 |
+
useful to easily overlay another mask on top of the causal one, for example for image tokens handling.
|
| 1098 |
+
and_mask_function (`Callable`, optional):
|
| 1099 |
+
An optional mask function to combine with the other mask function (by doing the intersection of both). This is
|
| 1100 |
+
useful to easily overlay another mask on top of the causal one, for example for image tokens handling.
|
| 1101 |
+
"""
|
| 1102 |
+
# The attribute reside in the text config for composite models
|
| 1103 |
+
effective_config = config.get_text_config()
|
| 1104 |
+
# Prepare the mask args
|
| 1105 |
+
mask_kwargs = {
|
| 1106 |
+
"config": effective_config,
|
| 1107 |
+
"input_embeds": input_embeds,
|
| 1108 |
+
"attention_mask": attention_mask,
|
| 1109 |
+
"cache_position": cache_position,
|
| 1110 |
+
"past_key_values": past_key_values,
|
| 1111 |
+
"position_ids": position_ids,
|
| 1112 |
+
"or_mask_function": or_mask_function,
|
| 1113 |
+
"and_mask_function": and_mask_function,
|
| 1114 |
+
}
|
| 1115 |
+
|
| 1116 |
+
# If the attribute exist, we need several masks
|
| 1117 |
+
if hasattr(effective_config, "layer_types"):
|
| 1118 |
+
causal_masks = {}
|
| 1119 |
+
for layer_pattern in set(effective_config.layer_types):
|
| 1120 |
+
causal_masks[layer_pattern] = LAYER_PATTERN_TO_MASK_FUNCTION_MAPPING[layer_pattern](**mask_kwargs)
|
| 1121 |
+
return causal_masks
|
| 1122 |
+
# In this case, all layers are sliding
|
| 1123 |
+
elif getattr(effective_config, "sliding_window", None) is not None:
|
| 1124 |
+
return create_sliding_window_causal_mask(**mask_kwargs)
|
| 1125 |
+
# In this case, all layers are chunked
|
| 1126 |
+
elif getattr(effective_config, "attention_chunk_size", None) is not None:
|
| 1127 |
+
return create_chunked_causal_mask(**mask_kwargs)
|
| 1128 |
+
# All layers use standard causal attention
|
| 1129 |
+
return create_causal_mask(**mask_kwargs)
|
| 1130 |
+
|
| 1131 |
+
|
| 1132 |
+
# Below are utilities to pretty-print the different masks
|
| 1133 |
+
# Print the matrix with words as row labels
|
| 1134 |
+
GREEN = "\033[92m"
|
| 1135 |
+
YELLOW = "\033[93m"
|
| 1136 |
+
RESET = "\033[0m"
|
| 1137 |
+
BLACK_SQUARE = "■"
|
| 1138 |
+
WHITE_SQUARE = "⬚"
|
| 1139 |
+
GREY_SQUARE = "∙"
|
| 1140 |
+
LOW_TRIANGLE = "⬕"
|
| 1141 |
+
UPPER_TRIANGLE = "⬔"
|
| 1142 |
+
|
| 1143 |
+
|
| 1144 |
+
def get_style(style):
|
| 1145 |
+
if style == "majong":
|
| 1146 |
+
BLACK_SQUARE = "🀞" # Full block (represents "on" or active)
|
| 1147 |
+
BLACK_SQUARE = "🀙" # Full block (represents "on" or active)
|
| 1148 |
+
WHITE_SQUARE = "🀆" # "▒" # Light shade (represents "off" or inactive)
|
| 1149 |
+
LOW_TRIANGLE = "🀛" # Lower left triangle (stylized indication)
|
| 1150 |
+
UPPER_TRIANGLE = "🀛" # Upper left triangle (stylized indication)
|
| 1151 |
+
else:
|
| 1152 |
+
BLACK_SQUARE = "█" # Full block (represents "on" or active)
|
| 1153 |
+
WHITE_SQUARE = "░" # "▒" # Light shade (represents "off" or inactive)
|
| 1154 |
+
LOW_TRIANGLE = "▙" # Lower left triangle (stylized indication))
|
| 1155 |
+
UPPER_TRIANGLE = "▜" # Upper left triangle (stylized indication)
|
| 1156 |
+
|
| 1157 |
+
return BLACK_SQUARE, WHITE_SQUARE, LOW_TRIANGLE, UPPER_TRIANGLE
|
| 1158 |
+
|
| 1159 |
+
|
| 1160 |
+
# LOW_TRIANGLE = UPPER_TRIANGLE = "⟍" # Upper right triangle (stylized indication)
|
| 1161 |
+
|
| 1162 |
+
YELLOW_SQUARE = f"{YELLOW}{BLACK_SQUARE}{RESET}"
|
| 1163 |
+
GREEN_SQUARE = f"{GREEN}{BLACK_SQUARE}{RESET}"
|
| 1164 |
+
|
| 1165 |
+
|
| 1166 |
+
def tensor_to_mask_visual(original_tensor: torch.Tensor, grid_size=(20, 40), style="majong") -> str:
|
| 1167 |
+
BLACK_SQUARE, WHITE_SQUARE, LOW_TRIANGLE, UPPER_TRIANGLE = get_style(style)
|
| 1168 |
+
h, w = original_tensor.shape
|
| 1169 |
+
max_h, max_w = grid_size
|
| 1170 |
+
if not (h < max_h and w < max_w):
|
| 1171 |
+
# Preserve aspect ratio within max grid size
|
| 1172 |
+
aspect_ratio = 2 * w / h
|
| 1173 |
+
if aspect_ratio > 1:
|
| 1174 |
+
w = max_w
|
| 1175 |
+
h = min(max_h, max(1, round(max_w / aspect_ratio)))
|
| 1176 |
+
else:
|
| 1177 |
+
h = max_h
|
| 1178 |
+
w = max(1, round(max_h * aspect_ratio))
|
| 1179 |
+
|
| 1180 |
+
# Step 1: Rescale tensor by average pooling
|
| 1181 |
+
tensor = original_tensor.unsqueeze(0).unsqueeze(0) # Add batch and channel dimensions
|
| 1182 |
+
tensor = F.adaptive_avg_pool2d(tensor, output_size=(h, w))[0, 0] # Remove extra dims
|
| 1183 |
+
else:
|
| 1184 |
+
tensor = original_tensor
|
| 1185 |
+
|
| 1186 |
+
# Step 3: Build the string representation
|
| 1187 |
+
result = []
|
| 1188 |
+
for i in range(h):
|
| 1189 |
+
row = ""
|
| 1190 |
+
for j in range(w):
|
| 1191 |
+
if tensor[i, j] == 1:
|
| 1192 |
+
row += BLACK_SQUARE
|
| 1193 |
+
elif tensor[i, j] == 0:
|
| 1194 |
+
row += WHITE_SQUARE
|
| 1195 |
+
else:
|
| 1196 |
+
if j > 0:
|
| 1197 |
+
if tensor[i, j - 1] == 1:
|
| 1198 |
+
row += LOW_TRIANGLE
|
| 1199 |
+
elif tensor[i, j - 1] == 0:
|
| 1200 |
+
row += UPPER_TRIANGLE
|
| 1201 |
+
else:
|
| 1202 |
+
row += BLACK_SQUARE if tensor[i, j] == 1 else WHITE_SQUARE
|
| 1203 |
+
else:
|
| 1204 |
+
row += (
|
| 1205 |
+
BLACK_SQUARE
|
| 1206 |
+
if tensor[i, j] == 1
|
| 1207 |
+
else (
|
| 1208 |
+
WHITE_SQUARE
|
| 1209 |
+
if tensor[i, j] == 0
|
| 1210 |
+
else (UPPER_TRIANGLE if tensor[i, j + 1] == 1 else LOW_TRIANGLE)
|
| 1211 |
+
)
|
| 1212 |
+
)
|
| 1213 |
+
result.append(row)
|
| 1214 |
+
|
| 1215 |
+
return "\n".join(result)
|
| 1216 |
+
|
| 1217 |
+
|
| 1218 |
+
class AttentionMask(torch.Tensor):
|
| 1219 |
+
def __new__(cls, data, style=None):
|
| 1220 |
+
# Create a new instance of AttentionMask as a Tensor
|
| 1221 |
+
cls.style = style
|
| 1222 |
+
return torch.Tensor._make_subclass(cls, data, require_grad=False)
|
| 1223 |
+
|
| 1224 |
+
def __init__(self, data):
|
| 1225 |
+
# You can initialize any additional metadata here if needed
|
| 1226 |
+
pass
|
| 1227 |
+
|
| 1228 |
+
def to_string(self, grid_size=(20, 40), limit=4):
|
| 1229 |
+
"""Returns a string representation of the block mask."""
|
| 1230 |
+
dense_mask = self
|
| 1231 |
+
*batch_dims, num_rows, num_cols = dense_mask.shape
|
| 1232 |
+
total_vis = []
|
| 1233 |
+
|
| 1234 |
+
for idx, batch_idx in enumerate(itertools.product(*[range(i) for i in batch_dims])):
|
| 1235 |
+
if idx == limit:
|
| 1236 |
+
total_vis.append("...")
|
| 1237 |
+
total_vis.append("To print out more, set AttentionMask.to_string(limit=N)")
|
| 1238 |
+
total_vis.append("You can also index (AttentionMask[batch, head]) to choose a specific batch or head")
|
| 1239 |
+
break
|
| 1240 |
+
block_vis = tensor_to_mask_visual(dense_mask[batch_idx], grid_size=grid_size, style=self.style)
|
| 1241 |
+
total_vis.append(block_vis)
|
| 1242 |
+
|
| 1243 |
+
total_vis.append(f"torch.Tensor(shape={tuple(self.shape)}, dtype={self.dtype})")
|
| 1244 |
+
return "\n".join(total_vis)
|
| 1245 |
+
|
| 1246 |
+
def __repr__(self):
|
| 1247 |
+
return self.to_string()
|
| 1248 |
+
|
| 1249 |
+
def __str__(self):
|
| 1250 |
+
return self.to_string()
|
| 1251 |
+
|
| 1252 |
+
@classmethod
|
| 1253 |
+
def from_tensor(cls, tensor: torch.Tensor, style: Optional[str] = None) -> "AttentionMask":
|
| 1254 |
+
res = cls(tensor)
|
| 1255 |
+
res.style = style
|
| 1256 |
+
return res
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/transformers/modeling_flax_pytorch_utils.py
ADDED
|
@@ -0,0 +1,491 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# coding=utf-8
|
| 2 |
+
# Copyright 2021 The HuggingFace Inc. team.
|
| 3 |
+
#
|
| 4 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 5 |
+
# you may not use this file except in compliance with the License.
|
| 6 |
+
# You may obtain a copy of the License at
|
| 7 |
+
#
|
| 8 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 9 |
+
#
|
| 10 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 11 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 12 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 13 |
+
# See the License for the specific language governing permissions and
|
| 14 |
+
# limitations under the License.
|
| 15 |
+
"""PyTorch - Flax general utilities."""
|
| 16 |
+
|
| 17 |
+
import os
|
| 18 |
+
from pickle import UnpicklingError
|
| 19 |
+
|
| 20 |
+
import jax
|
| 21 |
+
import jax.numpy as jnp
|
| 22 |
+
import numpy as np
|
| 23 |
+
from flax.serialization import from_bytes
|
| 24 |
+
from flax.traverse_util import flatten_dict, unflatten_dict
|
| 25 |
+
|
| 26 |
+
import transformers
|
| 27 |
+
|
| 28 |
+
from . import is_safetensors_available, is_torch_available
|
| 29 |
+
from .utils import check_torch_load_is_safe, logging
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
if is_torch_available():
|
| 33 |
+
import torch
|
| 34 |
+
|
| 35 |
+
if is_safetensors_available():
|
| 36 |
+
from safetensors import safe_open
|
| 37 |
+
from safetensors.flax import load_file as safe_load_file
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
logger = logging.get_logger(__name__)
|
| 41 |
+
|
| 42 |
+
|
| 43 |
+
#####################
|
| 44 |
+
# PyTorch => Flax #
|
| 45 |
+
#####################
|
| 46 |
+
|
| 47 |
+
|
| 48 |
+
def load_pytorch_checkpoint_in_flax_state_dict(
|
| 49 |
+
flax_model, pytorch_checkpoint_path, is_sharded, allow_missing_keys=False
|
| 50 |
+
):
|
| 51 |
+
"""Load pytorch checkpoints in a flax model"""
|
| 52 |
+
|
| 53 |
+
if not is_sharded:
|
| 54 |
+
pt_path = os.path.abspath(pytorch_checkpoint_path)
|
| 55 |
+
logger.info(f"Loading PyTorch weights from {pt_path}")
|
| 56 |
+
|
| 57 |
+
if pt_path.endswith(".safetensors"):
|
| 58 |
+
pt_state_dict = {}
|
| 59 |
+
with safe_open(pt_path, framework="flax") as f:
|
| 60 |
+
for k in f.keys():
|
| 61 |
+
pt_state_dict[k] = f.get_tensor(k)
|
| 62 |
+
else:
|
| 63 |
+
try:
|
| 64 |
+
import torch # noqa: F401
|
| 65 |
+
except (ImportError, ModuleNotFoundError):
|
| 66 |
+
logger.error(
|
| 67 |
+
"Loading a PyTorch model in Flax, requires both PyTorch and Flax to be installed. Please see"
|
| 68 |
+
" https://pytorch.org/ and https://flax.readthedocs.io/en/latest/index.html#installation for installation"
|
| 69 |
+
" instructions."
|
| 70 |
+
)
|
| 71 |
+
raise
|
| 72 |
+
|
| 73 |
+
check_torch_load_is_safe()
|
| 74 |
+
pt_state_dict = torch.load(pt_path, map_location="cpu", weights_only=True)
|
| 75 |
+
logger.info(f"PyTorch checkpoint contains {sum(t.numel() for t in pt_state_dict.values()):,} parameters.")
|
| 76 |
+
|
| 77 |
+
flax_state_dict = convert_pytorch_state_dict_to_flax(pt_state_dict, flax_model)
|
| 78 |
+
else:
|
| 79 |
+
# model is sharded and pytorch_checkpoint_path already contains the list of .pt shard files
|
| 80 |
+
flax_state_dict = convert_pytorch_sharded_state_dict_to_flax(pytorch_checkpoint_path, flax_model)
|
| 81 |
+
return flax_state_dict
|
| 82 |
+
|
| 83 |
+
|
| 84 |
+
def rename_key_and_reshape_tensor(
|
| 85 |
+
pt_tuple_key: tuple[str],
|
| 86 |
+
pt_tensor: np.ndarray,
|
| 87 |
+
random_flax_state_dict: dict[str, jnp.ndarray],
|
| 88 |
+
model_prefix: str,
|
| 89 |
+
) -> tuple[tuple[str], np.ndarray]:
|
| 90 |
+
"""Rename PT weight names to corresponding Flax weight names and reshape tensor if necessary"""
|
| 91 |
+
|
| 92 |
+
def is_key_or_prefix_key_in_dict(key: tuple[str]) -> bool:
|
| 93 |
+
"""Checks if `key` of `(prefix,) + key` is in random_flax_state_dict"""
|
| 94 |
+
return len(set(random_flax_state_dict) & {key, (model_prefix,) + key}) > 0
|
| 95 |
+
|
| 96 |
+
# layer norm
|
| 97 |
+
renamed_pt_tuple_key = pt_tuple_key[:-1] + ("scale",)
|
| 98 |
+
if pt_tuple_key[-1] in ["weight", "gamma"] and is_key_or_prefix_key_in_dict(renamed_pt_tuple_key):
|
| 99 |
+
return renamed_pt_tuple_key, pt_tensor
|
| 100 |
+
|
| 101 |
+
# batch norm layer mean
|
| 102 |
+
renamed_pt_tuple_key = pt_tuple_key[:-1] + ("mean",)
|
| 103 |
+
if pt_tuple_key[-1] == "running_mean" and not is_key_or_prefix_key_in_dict(pt_tuple_key):
|
| 104 |
+
return renamed_pt_tuple_key, pt_tensor
|
| 105 |
+
|
| 106 |
+
# batch norm layer var
|
| 107 |
+
renamed_pt_tuple_key = pt_tuple_key[:-1] + ("var",)
|
| 108 |
+
if pt_tuple_key[-1] == "running_var" and not is_key_or_prefix_key_in_dict(pt_tuple_key):
|
| 109 |
+
return renamed_pt_tuple_key, pt_tensor
|
| 110 |
+
|
| 111 |
+
# embedding
|
| 112 |
+
renamed_pt_tuple_key = pt_tuple_key[:-1] + ("embedding",)
|
| 113 |
+
if pt_tuple_key[-1] == "weight" and is_key_or_prefix_key_in_dict(renamed_pt_tuple_key):
|
| 114 |
+
return renamed_pt_tuple_key, pt_tensor
|
| 115 |
+
|
| 116 |
+
# conv layer
|
| 117 |
+
renamed_pt_tuple_key = pt_tuple_key[:-1] + ("kernel",)
|
| 118 |
+
if pt_tuple_key[-1] == "weight" and pt_tensor.ndim == 4 and not is_key_or_prefix_key_in_dict(pt_tuple_key):
|
| 119 |
+
pt_tensor = pt_tensor.transpose(2, 3, 1, 0)
|
| 120 |
+
return renamed_pt_tuple_key, pt_tensor
|
| 121 |
+
|
| 122 |
+
# linear layer
|
| 123 |
+
renamed_pt_tuple_key = pt_tuple_key[:-1] + ("kernel",)
|
| 124 |
+
if pt_tuple_key[-1] == "weight" and not is_key_or_prefix_key_in_dict(pt_tuple_key):
|
| 125 |
+
pt_tensor = pt_tensor.T
|
| 126 |
+
return renamed_pt_tuple_key, pt_tensor
|
| 127 |
+
|
| 128 |
+
# old PyTorch layer norm weight
|
| 129 |
+
renamed_pt_tuple_key = pt_tuple_key[:-1] + ("weight",)
|
| 130 |
+
if pt_tuple_key[-1] == "gamma":
|
| 131 |
+
return renamed_pt_tuple_key, pt_tensor
|
| 132 |
+
|
| 133 |
+
# old PyTorch layer norm bias
|
| 134 |
+
renamed_pt_tuple_key = pt_tuple_key[:-1] + ("bias",)
|
| 135 |
+
if pt_tuple_key[-1] == "beta":
|
| 136 |
+
return renamed_pt_tuple_key, pt_tensor
|
| 137 |
+
|
| 138 |
+
# New `weight_norm` from https://github.com/huggingface/transformers/pull/24030
|
| 139 |
+
name = None
|
| 140 |
+
if pt_tuple_key[-3::2] == ("parametrizations", "original0"):
|
| 141 |
+
name = pt_tuple_key[-2] + "_g"
|
| 142 |
+
elif pt_tuple_key[-3::2] == ("parametrizations", "original1"):
|
| 143 |
+
name = pt_tuple_key[-2] + "_v"
|
| 144 |
+
if name is not None:
|
| 145 |
+
renamed_pt_tuple_key = pt_tuple_key[:-3] + (name,)
|
| 146 |
+
return renamed_pt_tuple_key, pt_tensor
|
| 147 |
+
|
| 148 |
+
return pt_tuple_key, pt_tensor
|
| 149 |
+
|
| 150 |
+
|
| 151 |
+
def convert_pytorch_state_dict_to_flax(pt_state_dict, flax_model):
|
| 152 |
+
# convert pytorch tensor to numpy
|
| 153 |
+
from_bin = is_torch_available() and isinstance(next(iter(pt_state_dict.values())), torch.Tensor)
|
| 154 |
+
bfloat16 = torch.bfloat16 if from_bin else "bfloat16"
|
| 155 |
+
|
| 156 |
+
weight_dtypes = {k: v.dtype for k, v in pt_state_dict.items()}
|
| 157 |
+
|
| 158 |
+
if from_bin:
|
| 159 |
+
for k, v in pt_state_dict.items():
|
| 160 |
+
# numpy currently does not support bfloat16, need to go over float32 in this case to not lose precision
|
| 161 |
+
if v.dtype == bfloat16:
|
| 162 |
+
v = v.float()
|
| 163 |
+
pt_state_dict[k] = v.cpu().numpy()
|
| 164 |
+
|
| 165 |
+
model_prefix = flax_model.base_model_prefix
|
| 166 |
+
|
| 167 |
+
# use params dict if the model contains batch norm layers
|
| 168 |
+
if "params" in flax_model.params:
|
| 169 |
+
flax_model_params = flax_model.params["params"]
|
| 170 |
+
else:
|
| 171 |
+
flax_model_params = flax_model.params
|
| 172 |
+
random_flax_state_dict = flatten_dict(flax_model_params)
|
| 173 |
+
|
| 174 |
+
# add batch_stats keys,values to dict
|
| 175 |
+
if "batch_stats" in flax_model.params:
|
| 176 |
+
flax_batch_stats = flatten_dict(flax_model.params["batch_stats"])
|
| 177 |
+
random_flax_state_dict.update(flax_batch_stats)
|
| 178 |
+
|
| 179 |
+
flax_state_dict = {}
|
| 180 |
+
|
| 181 |
+
load_model_with_head_into_base_model = (model_prefix not in flax_model_params) and (
|
| 182 |
+
model_prefix in {k.split(".")[0] for k in pt_state_dict}
|
| 183 |
+
)
|
| 184 |
+
load_base_model_into_model_with_head = (model_prefix in flax_model_params) and (
|
| 185 |
+
model_prefix not in {k.split(".")[0] for k in pt_state_dict}
|
| 186 |
+
)
|
| 187 |
+
|
| 188 |
+
# Need to change some parameters name to match Flax names
|
| 189 |
+
for pt_key, pt_tensor in pt_state_dict.items():
|
| 190 |
+
pt_tuple_key = tuple(pt_key.split("."))
|
| 191 |
+
is_bfloat_16 = weight_dtypes[pt_key] == bfloat16
|
| 192 |
+
|
| 193 |
+
# remove base model prefix if necessary
|
| 194 |
+
has_base_model_prefix = pt_tuple_key[0] == model_prefix
|
| 195 |
+
if load_model_with_head_into_base_model and has_base_model_prefix:
|
| 196 |
+
pt_tuple_key = pt_tuple_key[1:]
|
| 197 |
+
|
| 198 |
+
# Correctly rename weight parameters
|
| 199 |
+
flax_key, flax_tensor = rename_key_and_reshape_tensor(
|
| 200 |
+
pt_tuple_key, pt_tensor, random_flax_state_dict, model_prefix
|
| 201 |
+
)
|
| 202 |
+
|
| 203 |
+
# add model prefix if necessary
|
| 204 |
+
require_base_model_prefix = (model_prefix,) + flax_key in random_flax_state_dict
|
| 205 |
+
if load_base_model_into_model_with_head and require_base_model_prefix:
|
| 206 |
+
flax_key = (model_prefix,) + flax_key
|
| 207 |
+
|
| 208 |
+
if flax_key in random_flax_state_dict:
|
| 209 |
+
if flax_tensor.shape != random_flax_state_dict[flax_key].shape:
|
| 210 |
+
raise ValueError(
|
| 211 |
+
f"PyTorch checkpoint seems to be incorrect. Weight {pt_key} was expected to be of shape "
|
| 212 |
+
f"{random_flax_state_dict[flax_key].shape}, but is {flax_tensor.shape}."
|
| 213 |
+
)
|
| 214 |
+
|
| 215 |
+
# add batch stats if the model contains batchnorm layers
|
| 216 |
+
if "batch_stats" in flax_model.params:
|
| 217 |
+
if "mean" in flax_key[-1] or "var" in flax_key[-1]:
|
| 218 |
+
flax_state_dict[("batch_stats",) + flax_key] = jnp.asarray(flax_tensor)
|
| 219 |
+
continue
|
| 220 |
+
# remove num_batches_tracked key
|
| 221 |
+
if "num_batches_tracked" in flax_key[-1]:
|
| 222 |
+
flax_state_dict.pop(flax_key, None)
|
| 223 |
+
continue
|
| 224 |
+
|
| 225 |
+
# also add unexpected weight so that warning is thrown
|
| 226 |
+
flax_state_dict[("params",) + flax_key] = (
|
| 227 |
+
jnp.asarray(flax_tensor) if not is_bfloat_16 else jnp.asarray(flax_tensor, dtype=jnp.bfloat16)
|
| 228 |
+
)
|
| 229 |
+
else:
|
| 230 |
+
# also add unexpected weight so that warning is thrown
|
| 231 |
+
flax_state_dict[flax_key] = (
|
| 232 |
+
jnp.asarray(flax_tensor) if not is_bfloat_16 else jnp.asarray(flax_tensor, dtype=jnp.bfloat16)
|
| 233 |
+
)
|
| 234 |
+
|
| 235 |
+
return unflatten_dict(flax_state_dict)
|
| 236 |
+
|
| 237 |
+
|
| 238 |
+
############################
|
| 239 |
+
# Sharded Pytorch => Flax #
|
| 240 |
+
############################
|
| 241 |
+
|
| 242 |
+
|
| 243 |
+
def convert_pytorch_sharded_state_dict_to_flax(shard_filenames, flax_model):
|
| 244 |
+
import torch
|
| 245 |
+
|
| 246 |
+
# Load the index
|
| 247 |
+
flax_state_dict = {}
|
| 248 |
+
for shard_file in shard_filenames:
|
| 249 |
+
# load using msgpack utils
|
| 250 |
+
check_torch_load_is_safe()
|
| 251 |
+
pt_state_dict = torch.load(shard_file, weights_only=True)
|
| 252 |
+
weight_dtypes = {k: v.dtype for k, v in pt_state_dict.items()}
|
| 253 |
+
pt_state_dict = {
|
| 254 |
+
k: v.numpy() if v.dtype != torch.bfloat16 else v.float().numpy() for k, v in pt_state_dict.items()
|
| 255 |
+
}
|
| 256 |
+
|
| 257 |
+
model_prefix = flax_model.base_model_prefix
|
| 258 |
+
|
| 259 |
+
# use params dict if the model contains batch norm layers and then add batch_stats keys,values to dict
|
| 260 |
+
if "batch_stats" in flax_model.params:
|
| 261 |
+
flax_model_params = flax_model.params["params"]
|
| 262 |
+
|
| 263 |
+
random_flax_state_dict = flatten_dict(flax_model_params)
|
| 264 |
+
random_flax_state_dict.update(flatten_dict(flax_model.params["batch_stats"]))
|
| 265 |
+
else:
|
| 266 |
+
flax_model_params = flax_model.params
|
| 267 |
+
random_flax_state_dict = flatten_dict(flax_model_params)
|
| 268 |
+
|
| 269 |
+
load_model_with_head_into_base_model = (model_prefix not in flax_model_params) and (
|
| 270 |
+
model_prefix in {k.split(".")[0] for k in pt_state_dict}
|
| 271 |
+
)
|
| 272 |
+
load_base_model_into_model_with_head = (model_prefix in flax_model_params) and (
|
| 273 |
+
model_prefix not in {k.split(".")[0] for k in pt_state_dict}
|
| 274 |
+
)
|
| 275 |
+
# Need to change some parameters name to match Flax names
|
| 276 |
+
for pt_key, pt_tensor in pt_state_dict.items():
|
| 277 |
+
pt_tuple_key = tuple(pt_key.split("."))
|
| 278 |
+
is_bfloat_16 = weight_dtypes[pt_key] == torch.bfloat16
|
| 279 |
+
|
| 280 |
+
# remove base model prefix if necessary
|
| 281 |
+
has_base_model_prefix = pt_tuple_key[0] == model_prefix
|
| 282 |
+
if load_model_with_head_into_base_model and has_base_model_prefix:
|
| 283 |
+
pt_tuple_key = pt_tuple_key[1:]
|
| 284 |
+
|
| 285 |
+
# Correctly rename weight parameters
|
| 286 |
+
flax_key, flax_tensor = rename_key_and_reshape_tensor(
|
| 287 |
+
pt_tuple_key, pt_tensor, random_flax_state_dict, model_prefix
|
| 288 |
+
)
|
| 289 |
+
# add model prefix if necessary
|
| 290 |
+
require_base_model_prefix = (model_prefix,) + flax_key in random_flax_state_dict
|
| 291 |
+
if load_base_model_into_model_with_head and require_base_model_prefix:
|
| 292 |
+
flax_key = (model_prefix,) + flax_key
|
| 293 |
+
|
| 294 |
+
if flax_key in random_flax_state_dict:
|
| 295 |
+
if flax_tensor.shape != random_flax_state_dict[flax_key].shape:
|
| 296 |
+
raise ValueError(
|
| 297 |
+
f"PyTorch checkpoint seems to be incorrect. Weight {pt_key} was expected to be of shape "
|
| 298 |
+
f"{random_flax_state_dict[flax_key].shape}, but is {flax_tensor.shape}."
|
| 299 |
+
)
|
| 300 |
+
|
| 301 |
+
# add batch stats if the model contains batchnorm layers
|
| 302 |
+
if "batch_stats" in flax_model.params:
|
| 303 |
+
if "mean" in flax_key[-1]:
|
| 304 |
+
flax_state_dict[("batch_stats",) + flax_key] = jnp.asarray(flax_tensor)
|
| 305 |
+
continue
|
| 306 |
+
if "var" in flax_key[-1]:
|
| 307 |
+
flax_state_dict[("batch_stats",) + flax_key] = jnp.asarray(flax_tensor)
|
| 308 |
+
continue
|
| 309 |
+
# remove num_batches_tracked key
|
| 310 |
+
if "num_batches_tracked" in flax_key[-1]:
|
| 311 |
+
flax_state_dict.pop(flax_key, None)
|
| 312 |
+
continue
|
| 313 |
+
|
| 314 |
+
# also add unexpected weight so that warning is thrown
|
| 315 |
+
flax_state_dict[("params",) + flax_key] = (
|
| 316 |
+
jnp.asarray(flax_tensor) if not is_bfloat_16 else jnp.asarray(flax_tensor, dtype=jnp.bfloat16)
|
| 317 |
+
)
|
| 318 |
+
|
| 319 |
+
else:
|
| 320 |
+
# also add unexpected weight so that warning is thrown
|
| 321 |
+
flax_state_dict[flax_key] = (
|
| 322 |
+
jnp.asarray(flax_tensor) if not is_bfloat_16 else jnp.asarray(flax_tensor, dtype=jnp.bfloat16)
|
| 323 |
+
)
|
| 324 |
+
return unflatten_dict(flax_state_dict)
|
| 325 |
+
|
| 326 |
+
|
| 327 |
+
#####################
|
| 328 |
+
# Flax => PyTorch #
|
| 329 |
+
#####################
|
| 330 |
+
|
| 331 |
+
|
| 332 |
+
def load_flax_checkpoint_in_pytorch_model(model, flax_checkpoint_path):
|
| 333 |
+
"""Load flax checkpoints in a PyTorch model"""
|
| 334 |
+
flax_checkpoint_path = os.path.abspath(flax_checkpoint_path)
|
| 335 |
+
logger.info(f"Loading Flax weights from {flax_checkpoint_path}")
|
| 336 |
+
|
| 337 |
+
# import correct flax class
|
| 338 |
+
flax_cls = getattr(transformers, "Flax" + model.__class__.__name__)
|
| 339 |
+
|
| 340 |
+
# load flax weight dict
|
| 341 |
+
if flax_checkpoint_path.endswith(".safetensors"):
|
| 342 |
+
flax_state_dict = safe_load_file(flax_checkpoint_path)
|
| 343 |
+
flax_state_dict = unflatten_dict(flax_state_dict, sep=".")
|
| 344 |
+
else:
|
| 345 |
+
with open(flax_checkpoint_path, "rb") as state_f:
|
| 346 |
+
try:
|
| 347 |
+
flax_state_dict = from_bytes(flax_cls, state_f.read())
|
| 348 |
+
except UnpicklingError:
|
| 349 |
+
raise OSError(f"Unable to convert {flax_checkpoint_path} to Flax deserializable object. ")
|
| 350 |
+
|
| 351 |
+
return load_flax_weights_in_pytorch_model(model, flax_state_dict)
|
| 352 |
+
|
| 353 |
+
|
| 354 |
+
def load_flax_weights_in_pytorch_model(pt_model, flax_state):
|
| 355 |
+
"""Load flax checkpoints in a PyTorch model"""
|
| 356 |
+
|
| 357 |
+
try:
|
| 358 |
+
import torch # noqa: F401
|
| 359 |
+
except (ImportError, ModuleNotFoundError):
|
| 360 |
+
logger.error(
|
| 361 |
+
"Loading a Flax weights in PyTorch, requires both PyTorch and Flax to be installed. Please see"
|
| 362 |
+
" https://pytorch.org/ and https://flax.readthedocs.io/en/latest/index.html#installation for installation"
|
| 363 |
+
" instructions."
|
| 364 |
+
)
|
| 365 |
+
raise
|
| 366 |
+
|
| 367 |
+
# check if we have bf16 weights
|
| 368 |
+
is_type_bf16 = flatten_dict(jax.tree_util.tree_map(lambda x: x.dtype == jnp.bfloat16, flax_state)).values()
|
| 369 |
+
if any(is_type_bf16):
|
| 370 |
+
# convert all weights to fp32 if the are bf16 since torch.from_numpy can-not handle bf16
|
| 371 |
+
# and bf16 is not fully supported in PT yet.
|
| 372 |
+
logger.warning(
|
| 373 |
+
"Found ``bfloat16`` weights in Flax model. Casting all ``bfloat16`` weights to ``float32`` "
|
| 374 |
+
"before loading those in PyTorch model."
|
| 375 |
+
)
|
| 376 |
+
flax_state = jax.tree_util.tree_map(
|
| 377 |
+
lambda params: params.astype(np.float32) if params.dtype == jnp.bfloat16 else params, flax_state
|
| 378 |
+
)
|
| 379 |
+
|
| 380 |
+
flax_state_dict = flatten_dict(flax_state)
|
| 381 |
+
pt_model_dict = pt_model.state_dict()
|
| 382 |
+
|
| 383 |
+
load_model_with_head_into_base_model = (pt_model.base_model_prefix in flax_state) and (
|
| 384 |
+
pt_model.base_model_prefix not in {k.split(".")[0] for k in pt_model_dict}
|
| 385 |
+
)
|
| 386 |
+
load_base_model_into_model_with_head = (pt_model.base_model_prefix not in flax_state) and (
|
| 387 |
+
pt_model.base_model_prefix in {k.split(".")[0] for k in pt_model_dict}
|
| 388 |
+
)
|
| 389 |
+
|
| 390 |
+
# keep track of unexpected & missing keys
|
| 391 |
+
unexpected_keys = []
|
| 392 |
+
missing_keys = set(pt_model_dict.keys())
|
| 393 |
+
|
| 394 |
+
for flax_key_tuple, flax_tensor in flax_state_dict.items():
|
| 395 |
+
has_base_model_prefix = flax_key_tuple[0] == pt_model.base_model_prefix
|
| 396 |
+
require_base_model_prefix = ".".join((pt_model.base_model_prefix,) + flax_key_tuple) in pt_model_dict
|
| 397 |
+
|
| 398 |
+
# adapt flax_key to prepare for loading from/to base model only
|
| 399 |
+
if load_model_with_head_into_base_model and has_base_model_prefix:
|
| 400 |
+
flax_key_tuple = flax_key_tuple[1:]
|
| 401 |
+
elif load_base_model_into_model_with_head and require_base_model_prefix:
|
| 402 |
+
flax_key_tuple = (pt_model.base_model_prefix,) + flax_key_tuple
|
| 403 |
+
|
| 404 |
+
# rename flax weights to PyTorch format
|
| 405 |
+
if flax_key_tuple[-1] == "kernel" and flax_tensor.ndim == 4 and ".".join(flax_key_tuple) not in pt_model_dict:
|
| 406 |
+
# conv layer
|
| 407 |
+
flax_key_tuple = flax_key_tuple[:-1] + ("weight",)
|
| 408 |
+
flax_tensor = jnp.transpose(flax_tensor, (3, 2, 0, 1))
|
| 409 |
+
elif flax_key_tuple[-1] == "kernel" and ".".join(flax_key_tuple) not in pt_model_dict:
|
| 410 |
+
# linear layer
|
| 411 |
+
flax_key_tuple = flax_key_tuple[:-1] + ("weight",)
|
| 412 |
+
flax_tensor = flax_tensor.T
|
| 413 |
+
elif flax_key_tuple[-1] in ["scale", "embedding"]:
|
| 414 |
+
flax_key_tuple = flax_key_tuple[:-1] + ("weight",)
|
| 415 |
+
|
| 416 |
+
# adding batch stats from flax batch norm to pt
|
| 417 |
+
elif "mean" in flax_key_tuple[-1]:
|
| 418 |
+
flax_key_tuple = flax_key_tuple[:-1] + ("running_mean",)
|
| 419 |
+
elif "var" in flax_key_tuple[-1]:
|
| 420 |
+
flax_key_tuple = flax_key_tuple[:-1] + ("running_var",)
|
| 421 |
+
|
| 422 |
+
if "batch_stats" in flax_state:
|
| 423 |
+
flax_key = ".".join(flax_key_tuple[1:]) # Remove the params/batch_stats header
|
| 424 |
+
else:
|
| 425 |
+
flax_key = ".".join(flax_key_tuple)
|
| 426 |
+
|
| 427 |
+
# We also need to look at `pt_model_dict` and see if there are keys requiring further transformation.
|
| 428 |
+
special_pt_names = {}
|
| 429 |
+
# New `weight_norm` from https://github.com/huggingface/transformers/pull/24030
|
| 430 |
+
for key in pt_model_dict:
|
| 431 |
+
key_components = key.split(".")
|
| 432 |
+
name = None
|
| 433 |
+
if key_components[-3::2] == ["parametrizations", "original0"]:
|
| 434 |
+
name = key_components[-2] + "_g"
|
| 435 |
+
elif key_components[-3::2] == ["parametrizations", "original1"]:
|
| 436 |
+
name = key_components[-2] + "_v"
|
| 437 |
+
if name is not None:
|
| 438 |
+
key_components = key_components[:-3] + [name]
|
| 439 |
+
key_to_check = ".".join(key_components)
|
| 440 |
+
special_pt_names[key_to_check] = key
|
| 441 |
+
|
| 442 |
+
if flax_key in special_pt_names:
|
| 443 |
+
flax_key = special_pt_names[flax_key]
|
| 444 |
+
|
| 445 |
+
if flax_key in pt_model_dict:
|
| 446 |
+
if flax_tensor.shape != pt_model_dict[flax_key].shape:
|
| 447 |
+
raise ValueError(
|
| 448 |
+
f"Flax checkpoint seems to be incorrect. Weight {flax_key_tuple} was expected "
|
| 449 |
+
f"to be of shape {pt_model_dict[flax_key].shape}, but is {flax_tensor.shape}."
|
| 450 |
+
)
|
| 451 |
+
else:
|
| 452 |
+
# add weight to pytorch dict
|
| 453 |
+
flax_tensor = np.asarray(flax_tensor) if not isinstance(flax_tensor, np.ndarray) else flax_tensor
|
| 454 |
+
pt_model_dict[flax_key] = torch.from_numpy(flax_tensor)
|
| 455 |
+
# remove from missing keys
|
| 456 |
+
missing_keys.remove(flax_key)
|
| 457 |
+
else:
|
| 458 |
+
# weight is not expected by PyTorch model
|
| 459 |
+
unexpected_keys.append(flax_key)
|
| 460 |
+
|
| 461 |
+
pt_model.load_state_dict(pt_model_dict)
|
| 462 |
+
|
| 463 |
+
# re-transform missing_keys to list
|
| 464 |
+
missing_keys = list(missing_keys)
|
| 465 |
+
|
| 466 |
+
if len(unexpected_keys) > 0:
|
| 467 |
+
logger.warning(
|
| 468 |
+
"Some weights of the Flax model were not used when initializing the PyTorch model"
|
| 469 |
+
f" {pt_model.__class__.__name__}: {unexpected_keys}\n- This IS expected if you are initializing"
|
| 470 |
+
f" {pt_model.__class__.__name__} from a Flax model trained on another task or with another architecture"
|
| 471 |
+
" (e.g. initializing a BertForSequenceClassification model from a FlaxBertForPreTraining model).\n- This"
|
| 472 |
+
f" IS NOT expected if you are initializing {pt_model.__class__.__name__} from a Flax model that you expect"
|
| 473 |
+
" to be exactly identical (e.g. initializing a BertForSequenceClassification model from a"
|
| 474 |
+
" FlaxBertForSequenceClassification model)."
|
| 475 |
+
)
|
| 476 |
+
else:
|
| 477 |
+
logger.warning(f"All Flax model weights were used when initializing {pt_model.__class__.__name__}.\n")
|
| 478 |
+
if len(missing_keys) > 0:
|
| 479 |
+
logger.warning(
|
| 480 |
+
f"Some weights of {pt_model.__class__.__name__} were not initialized from the Flax model and are newly"
|
| 481 |
+
f" initialized: {missing_keys}\nYou should probably TRAIN this model on a down-stream task to be able to"
|
| 482 |
+
" use it for predictions and inference."
|
| 483 |
+
)
|
| 484 |
+
else:
|
| 485 |
+
logger.warning(
|
| 486 |
+
f"All the weights of {pt_model.__class__.__name__} were initialized from the Flax model.\n"
|
| 487 |
+
"If your task is similar to the task the model of the checkpoint was trained on, "
|
| 488 |
+
f"you can already use {pt_model.__class__.__name__} for predictions without further training."
|
| 489 |
+
)
|
| 490 |
+
|
| 491 |
+
return pt_model
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/transformers/modeling_layers.py
ADDED
|
@@ -0,0 +1,289 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2025 The HuggingFace 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 |
+
from functools import partial
|
| 15 |
+
from typing import Optional
|
| 16 |
+
|
| 17 |
+
import torch
|
| 18 |
+
import torch.nn as nn
|
| 19 |
+
|
| 20 |
+
from .cache_utils import Cache
|
| 21 |
+
from .modeling_outputs import (
|
| 22 |
+
BaseModelOutputWithPast,
|
| 23 |
+
QuestionAnsweringModelOutput,
|
| 24 |
+
SequenceClassifierOutputWithPast,
|
| 25 |
+
TokenClassifierOutput,
|
| 26 |
+
)
|
| 27 |
+
from .models.auto import AutoModel
|
| 28 |
+
from .processing_utils import Unpack
|
| 29 |
+
from .utils import TransformersKwargs, auto_docstring, can_return_tuple, logging
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
logger = logging.get_logger(__name__)
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
class GradientCheckpointingLayer(nn.Module):
|
| 36 |
+
"""Base class for layers with gradient checkpointing.
|
| 37 |
+
|
| 38 |
+
This class enables gradient checkpointing functionality for a layer. By default, gradient checkpointing is disabled
|
| 39 |
+
(`gradient_checkpointing = False`). When `model.set_gradient_checkpointing()` is called, gradient checkpointing is
|
| 40 |
+
enabled by setting `gradient_checkpointing = True` and assigning a checkpointing function to `_gradient_checkpointing_func`.
|
| 41 |
+
|
| 42 |
+
Important:
|
| 43 |
+
|
| 44 |
+
When using gradient checkpointing with `use_reentrant=True`, inputs that require gradients (e.g. hidden states)
|
| 45 |
+
must be passed as positional arguments (`*args`) rather than keyword arguments to properly propagate gradients.
|
| 46 |
+
|
| 47 |
+
Example:
|
| 48 |
+
|
| 49 |
+
```python
|
| 50 |
+
>>> # Correct - hidden_states passed as positional arg
|
| 51 |
+
>>> out = self.layer(hidden_states, attention_mask=attention_mask)
|
| 52 |
+
|
| 53 |
+
>>> # Incorrect - hidden_states passed as keyword arg
|
| 54 |
+
>>> out = self.layer(hidden_states=hidden_states, attention_mask=attention_mask)
|
| 55 |
+
```
|
| 56 |
+
"""
|
| 57 |
+
|
| 58 |
+
gradient_checkpointing = False
|
| 59 |
+
|
| 60 |
+
def __call__(self, *args, **kwargs):
|
| 61 |
+
if self.gradient_checkpointing and self.training:
|
| 62 |
+
do_warn = False
|
| 63 |
+
layer_name = self.__class__.__name__
|
| 64 |
+
message = f"Caching is incompatible with gradient checkpointing in {layer_name}. Setting"
|
| 65 |
+
|
| 66 |
+
if "use_cache" in kwargs and kwargs["use_cache"]:
|
| 67 |
+
kwargs["use_cache"] = False
|
| 68 |
+
message += " `use_cache=False`,"
|
| 69 |
+
do_warn = True
|
| 70 |
+
|
| 71 |
+
# different names for the same thing in different layers
|
| 72 |
+
# TODO cyril: this one without `S` can be removed after deprection cycle
|
| 73 |
+
if "past_key_value" in kwargs and kwargs["past_key_value"] is not None:
|
| 74 |
+
kwargs["past_key_value"] = None
|
| 75 |
+
message += " `past_key_value=None`,"
|
| 76 |
+
do_warn = True
|
| 77 |
+
|
| 78 |
+
if "past_key_values" in kwargs and kwargs["past_key_values"] is not None:
|
| 79 |
+
kwargs["past_key_values"] = None
|
| 80 |
+
message += " `past_key_values=None`,"
|
| 81 |
+
do_warn = True
|
| 82 |
+
|
| 83 |
+
if "layer_past" in kwargs and kwargs["layer_past"] is not None:
|
| 84 |
+
kwargs["layer_past"] = None
|
| 85 |
+
message += " `layer_past=None`,"
|
| 86 |
+
do_warn = True
|
| 87 |
+
|
| 88 |
+
# warn if anything was changed
|
| 89 |
+
if do_warn:
|
| 90 |
+
message = message.rstrip(",") + "."
|
| 91 |
+
logger.warning_once(message)
|
| 92 |
+
|
| 93 |
+
return self._gradient_checkpointing_func(partial(super().__call__, **kwargs), *args)
|
| 94 |
+
return super().__call__(*args, **kwargs)
|
| 95 |
+
|
| 96 |
+
|
| 97 |
+
@auto_docstring
|
| 98 |
+
class GenericForSequenceClassification:
|
| 99 |
+
base_model_prefix = "model"
|
| 100 |
+
|
| 101 |
+
def __init__(self, config):
|
| 102 |
+
super().__init__(config)
|
| 103 |
+
self.num_labels = config.num_labels
|
| 104 |
+
# Similar to `self.model = AutoModel.from_config(config)` but allows to change the base model name if needed in the child class
|
| 105 |
+
setattr(self, self.base_model_prefix, AutoModel.from_config(config))
|
| 106 |
+
self.score = nn.Linear(config.hidden_size, self.num_labels, bias=False)
|
| 107 |
+
|
| 108 |
+
# Initialize weights and apply final processing
|
| 109 |
+
self.post_init()
|
| 110 |
+
|
| 111 |
+
@can_return_tuple
|
| 112 |
+
@auto_docstring
|
| 113 |
+
def forward(
|
| 114 |
+
self,
|
| 115 |
+
input_ids: Optional[torch.LongTensor] = None,
|
| 116 |
+
attention_mask: Optional[torch.Tensor] = None,
|
| 117 |
+
position_ids: Optional[torch.LongTensor] = None,
|
| 118 |
+
past_key_values: Optional[Cache] = None,
|
| 119 |
+
inputs_embeds: Optional[torch.FloatTensor] = None,
|
| 120 |
+
labels: Optional[torch.LongTensor] = None,
|
| 121 |
+
use_cache: Optional[bool] = None,
|
| 122 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 123 |
+
) -> SequenceClassifierOutputWithPast:
|
| 124 |
+
transformer_outputs: BaseModelOutputWithPast = getattr(self, self.base_model_prefix)(
|
| 125 |
+
input_ids,
|
| 126 |
+
attention_mask=attention_mask,
|
| 127 |
+
position_ids=position_ids,
|
| 128 |
+
past_key_values=past_key_values,
|
| 129 |
+
inputs_embeds=inputs_embeds,
|
| 130 |
+
use_cache=use_cache,
|
| 131 |
+
**kwargs,
|
| 132 |
+
)
|
| 133 |
+
hidden_states = transformer_outputs.last_hidden_state
|
| 134 |
+
logits = self.score(hidden_states)
|
| 135 |
+
|
| 136 |
+
if input_ids is not None:
|
| 137 |
+
batch_size = input_ids.shape[0]
|
| 138 |
+
else:
|
| 139 |
+
batch_size = inputs_embeds.shape[0]
|
| 140 |
+
|
| 141 |
+
if self.config.pad_token_id is None and batch_size != 1:
|
| 142 |
+
raise ValueError("Cannot handle batch sizes > 1 if no padding token is defined.")
|
| 143 |
+
if self.config.pad_token_id is None:
|
| 144 |
+
last_non_pad_token = -1
|
| 145 |
+
elif input_ids is not None:
|
| 146 |
+
# To handle both left- and right- padding, we take the rightmost token that is not equal to pad_token_id
|
| 147 |
+
non_pad_mask = (input_ids != self.config.pad_token_id).to(logits.device, torch.int32)
|
| 148 |
+
token_indices = torch.arange(input_ids.shape[-1], device=logits.device, dtype=torch.int32)
|
| 149 |
+
last_non_pad_token = (token_indices * non_pad_mask).argmax(-1)
|
| 150 |
+
else:
|
| 151 |
+
last_non_pad_token = -1
|
| 152 |
+
logger.warning_once(
|
| 153 |
+
f"{self.__class__.__name__} will not detect padding tokens in `inputs_embeds`. Results may be "
|
| 154 |
+
"unexpected if using padding tokens in conjunction with `inputs_embeds.`"
|
| 155 |
+
)
|
| 156 |
+
|
| 157 |
+
pooled_logits = logits[torch.arange(batch_size, device=logits.device), last_non_pad_token]
|
| 158 |
+
|
| 159 |
+
loss = None
|
| 160 |
+
if labels is not None:
|
| 161 |
+
loss = self.loss_function(logits=logits, labels=labels, pooled_logits=pooled_logits, config=self.config)
|
| 162 |
+
|
| 163 |
+
return SequenceClassifierOutputWithPast(
|
| 164 |
+
loss=loss,
|
| 165 |
+
logits=pooled_logits,
|
| 166 |
+
past_key_values=transformer_outputs.past_key_values,
|
| 167 |
+
hidden_states=transformer_outputs.hidden_states,
|
| 168 |
+
attentions=transformer_outputs.attentions,
|
| 169 |
+
)
|
| 170 |
+
|
| 171 |
+
|
| 172 |
+
@auto_docstring
|
| 173 |
+
class GenericForQuestionAnswering:
|
| 174 |
+
base_model_prefix = "model"
|
| 175 |
+
|
| 176 |
+
def __init__(self, config):
|
| 177 |
+
super().__init__(config)
|
| 178 |
+
# Similar to `self.model = AutoModel.from_config(config)` but allows to change the base model name if needed in the child class
|
| 179 |
+
setattr(self, self.base_model_prefix, AutoModel.from_config(config))
|
| 180 |
+
self.qa_outputs = nn.Linear(config.hidden_size, 2)
|
| 181 |
+
|
| 182 |
+
# Initialize weights and apply final processing
|
| 183 |
+
self.post_init()
|
| 184 |
+
|
| 185 |
+
def get_input_embeddings(self):
|
| 186 |
+
return getattr(self, self.base_model_prefix).embed_tokens
|
| 187 |
+
|
| 188 |
+
def set_input_embeddings(self, value):
|
| 189 |
+
getattr(self, self.base_model_prefix).embed_tokens = value
|
| 190 |
+
|
| 191 |
+
@can_return_tuple
|
| 192 |
+
@auto_docstring
|
| 193 |
+
def forward(
|
| 194 |
+
self,
|
| 195 |
+
input_ids: Optional[torch.LongTensor] = None,
|
| 196 |
+
attention_mask: Optional[torch.Tensor] = None,
|
| 197 |
+
position_ids: Optional[torch.LongTensor] = None,
|
| 198 |
+
past_key_values: Optional[Cache] = None,
|
| 199 |
+
inputs_embeds: Optional[torch.FloatTensor] = None,
|
| 200 |
+
start_positions: Optional[torch.LongTensor] = None,
|
| 201 |
+
end_positions: Optional[torch.LongTensor] = None,
|
| 202 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 203 |
+
) -> QuestionAnsweringModelOutput:
|
| 204 |
+
outputs: BaseModelOutputWithPast = getattr(self, self.base_model_prefix)(
|
| 205 |
+
input_ids,
|
| 206 |
+
attention_mask=attention_mask,
|
| 207 |
+
position_ids=position_ids,
|
| 208 |
+
past_key_values=past_key_values,
|
| 209 |
+
inputs_embeds=inputs_embeds,
|
| 210 |
+
**kwargs,
|
| 211 |
+
)
|
| 212 |
+
|
| 213 |
+
sequence_output = outputs.last_hidden_state
|
| 214 |
+
|
| 215 |
+
logits = self.qa_outputs(sequence_output)
|
| 216 |
+
start_logits, end_logits = logits.split(1, dim=-1)
|
| 217 |
+
start_logits = start_logits.squeeze(-1).contiguous()
|
| 218 |
+
end_logits = end_logits.squeeze(-1).contiguous()
|
| 219 |
+
|
| 220 |
+
loss = None
|
| 221 |
+
if start_positions is not None and end_positions is not None:
|
| 222 |
+
loss = self.loss_function(start_logits, end_logits, start_positions, end_positions, **kwargs)
|
| 223 |
+
|
| 224 |
+
return QuestionAnsweringModelOutput(
|
| 225 |
+
loss=loss,
|
| 226 |
+
start_logits=start_logits,
|
| 227 |
+
end_logits=end_logits,
|
| 228 |
+
hidden_states=outputs.hidden_states,
|
| 229 |
+
attentions=outputs.attentions,
|
| 230 |
+
)
|
| 231 |
+
|
| 232 |
+
|
| 233 |
+
@auto_docstring
|
| 234 |
+
class GenericForTokenClassification:
|
| 235 |
+
base_model_prefix = "model"
|
| 236 |
+
|
| 237 |
+
def __init__(self, config):
|
| 238 |
+
super().__init__(config)
|
| 239 |
+
self.num_labels = config.num_labels
|
| 240 |
+
# Similar to `self.model = AutoModel.from_config(config)` but allows to change the base model name if needed in the child class
|
| 241 |
+
setattr(self, self.base_model_prefix, AutoModel.from_config(config))
|
| 242 |
+
if getattr(config, "classifier_dropout", None) is not None:
|
| 243 |
+
classifier_dropout = config.classifier_dropout
|
| 244 |
+
elif getattr(config, "hidden_dropout", None) is not None:
|
| 245 |
+
classifier_dropout = config.hidden_dropout
|
| 246 |
+
else:
|
| 247 |
+
classifier_dropout = 0.1
|
| 248 |
+
self.dropout = nn.Dropout(classifier_dropout)
|
| 249 |
+
self.score = nn.Linear(config.hidden_size, config.num_labels)
|
| 250 |
+
|
| 251 |
+
# Initialize weights and apply final processing
|
| 252 |
+
self.post_init()
|
| 253 |
+
|
| 254 |
+
@can_return_tuple
|
| 255 |
+
@auto_docstring
|
| 256 |
+
def forward(
|
| 257 |
+
self,
|
| 258 |
+
input_ids: Optional[torch.LongTensor] = None,
|
| 259 |
+
attention_mask: Optional[torch.Tensor] = None,
|
| 260 |
+
position_ids: Optional[torch.LongTensor] = None,
|
| 261 |
+
past_key_values: Optional[Cache] = None,
|
| 262 |
+
inputs_embeds: Optional[torch.FloatTensor] = None,
|
| 263 |
+
labels: Optional[torch.LongTensor] = None,
|
| 264 |
+
use_cache: Optional[bool] = None,
|
| 265 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 266 |
+
) -> TokenClassifierOutput:
|
| 267 |
+
outputs: BaseModelOutputWithPast = getattr(self, self.base_model_prefix)(
|
| 268 |
+
input_ids,
|
| 269 |
+
attention_mask=attention_mask,
|
| 270 |
+
position_ids=position_ids,
|
| 271 |
+
past_key_values=past_key_values,
|
| 272 |
+
inputs_embeds=inputs_embeds,
|
| 273 |
+
use_cache=use_cache,
|
| 274 |
+
**kwargs,
|
| 275 |
+
)
|
| 276 |
+
sequence_output = outputs.last_hidden_state
|
| 277 |
+
sequence_output = self.dropout(sequence_output)
|
| 278 |
+
logits = self.score(sequence_output)
|
| 279 |
+
|
| 280 |
+
loss = None
|
| 281 |
+
if labels is not None:
|
| 282 |
+
loss = self.loss_function(logits, labels, self.config)
|
| 283 |
+
|
| 284 |
+
return TokenClassifierOutput(
|
| 285 |
+
loss=loss,
|
| 286 |
+
logits=logits,
|
| 287 |
+
hidden_states=outputs.hidden_states,
|
| 288 |
+
attentions=outputs.attentions,
|
| 289 |
+
)
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/transformers/modeling_utils.py
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/transformers/tokenization_mistral_common.py
ADDED
|
@@ -0,0 +1,1883 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2025 Mistral AI and 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 |
+
|
| 15 |
+
import os
|
| 16 |
+
import shutil
|
| 17 |
+
import warnings
|
| 18 |
+
from collections.abc import Mapping, Sized
|
| 19 |
+
from enum import Enum
|
| 20 |
+
from pathlib import Path
|
| 21 |
+
from typing import Any, Callable, Optional, Union, overload
|
| 22 |
+
|
| 23 |
+
import numpy as np
|
| 24 |
+
|
| 25 |
+
from transformers.audio_utils import load_audio_as
|
| 26 |
+
from transformers.tokenization_utils_base import (
|
| 27 |
+
LARGE_INTEGER,
|
| 28 |
+
VERY_LARGE_INTEGER,
|
| 29 |
+
BatchEncoding,
|
| 30 |
+
EncodedInput,
|
| 31 |
+
PreTokenizedInput,
|
| 32 |
+
PreTrainedTokenizerBase,
|
| 33 |
+
TextInput,
|
| 34 |
+
TruncationStrategy,
|
| 35 |
+
)
|
| 36 |
+
from transformers.utils import PaddingStrategy, TensorType, add_end_docstrings, logging, to_py_obj
|
| 37 |
+
from transformers.utils.generic import is_torch_tensor
|
| 38 |
+
from transformers.utils.hub import PushToHubMixin
|
| 39 |
+
from transformers.utils.import_utils import is_mistral_common_available, is_torch_available, requires
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
if is_mistral_common_available():
|
| 43 |
+
from mistral_common.protocol.instruct.request import ChatCompletionRequest
|
| 44 |
+
from mistral_common.protocol.instruct.validator import ValidationMode
|
| 45 |
+
from mistral_common.tokens.tokenizers.base import SpecialTokenPolicy, TokenizerVersion
|
| 46 |
+
from mistral_common.tokens.tokenizers.image import MultiModalVersion
|
| 47 |
+
from mistral_common.tokens.tokenizers.mistral import MistralTokenizer
|
| 48 |
+
from mistral_common.tokens.tokenizers.tekken import Tekkenizer
|
| 49 |
+
from mistral_common.tokens.tokenizers.utils import download_tokenizer_from_hf_hub
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
if is_torch_available():
|
| 53 |
+
import torch
|
| 54 |
+
|
| 55 |
+
|
| 56 |
+
logger = logging.get_logger(__name__)
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
ENCODE_KWARGS_DOCSTRING = r"""
|
| 60 |
+
add_special_tokens (`bool`, *optional*, defaults to `True`):
|
| 61 |
+
Whether or not to add special tokens when encoding the sequences. This will use the underlying
|
| 62 |
+
`PretrainedTokenizerBase.build_inputs_with_special_tokens` function, which defines which tokens are
|
| 63 |
+
automatically added to the input ids. This is useful if you want to add `bos` or `eos` tokens
|
| 64 |
+
automatically.
|
| 65 |
+
padding (`bool`, `str` or [`~utils.PaddingStrategy`], *optional*, defaults to `False`):
|
| 66 |
+
Activates and controls padding. Accepts the following values:
|
| 67 |
+
|
| 68 |
+
- `True` or `'longest'`: Pad to the longest sequence in the batch (or no padding if only a single
|
| 69 |
+
sequence is provided).
|
| 70 |
+
- `'max_length'`: Pad to a maximum length specified with the argument `max_length` or to the maximum
|
| 71 |
+
acceptable input length for the model if that argument is not provided.
|
| 72 |
+
- `False` or `'do_not_pad'` (default): No padding (i.e., can output a batch with sequences of different
|
| 73 |
+
lengths).
|
| 74 |
+
truncation (`bool`, `str` or [`~tokenization_utils_base.TruncationStrategy`], *optional*, defaults to `False`):
|
| 75 |
+
Activates and controls truncation. Accepts the following values:
|
| 76 |
+
|
| 77 |
+
- `True` or `'longest_first'`: Truncate to a maximum length specified with the argument `max_length` or
|
| 78 |
+
to the maximum acceptable input length for the model if that argument is not provided.
|
| 79 |
+
- `False` or `'do_not_truncate'` (default): No truncation (i.e., can output batch with sequence lengths
|
| 80 |
+
greater than the model maximum admissible input size).
|
| 81 |
+
max_length (`int`, *optional*):
|
| 82 |
+
Controls the maximum length to use by one of the truncation/padding parameters.
|
| 83 |
+
|
| 84 |
+
If left unset or set to `None`, this will use the predefined model maximum length if a maximum length
|
| 85 |
+
is required by one of the truncation/padding parameters. If the model has no specific maximum input
|
| 86 |
+
length (like XLNet) truncation/padding to a maximum length will be deactivated.
|
| 87 |
+
stride (`int`, *optional*, defaults to 0):
|
| 88 |
+
If set to a number along with `max_length`, the overflowing tokens returned when
|
| 89 |
+
`return_overflowing_tokens=True` will contain some tokens from the end of the truncated sequence
|
| 90 |
+
returned to provide some overlap between truncated and overflowing sequences. The value of this
|
| 91 |
+
argument defines the number of overlapping tokens.
|
| 92 |
+
pad_to_multiple_of (`int`, *optional*):
|
| 93 |
+
If set will pad the sequence to a multiple of the provided value. Requires `padding` to be activated.
|
| 94 |
+
This is especially useful to enable the use of Tensor Cores on NVIDIA hardware with compute capability
|
| 95 |
+
`>= 7.5` (Volta).
|
| 96 |
+
padding_side (`str`, *optional*):
|
| 97 |
+
The side on which the model should have padding applied. Should be selected between ['right', 'left'].
|
| 98 |
+
Default value is picked from the class attribute of the same name.
|
| 99 |
+
return_tensors (`str` or [`~utils.TensorType`], *optional*):
|
| 100 |
+
If set, will return tensors instead of list of python integers. Acceptable values are:
|
| 101 |
+
|
| 102 |
+
- `'pt'`: Return PyTorch `torch.Tensor` objects.
|
| 103 |
+
"""
|
| 104 |
+
|
| 105 |
+
ENCODE_PLUS_ADDITIONAL_KWARGS_DOCSTRING = r"""
|
| 106 |
+
return_attention_mask (`bool`, *optional*):
|
| 107 |
+
Whether to return the attention mask. If left to the default, will return the attention mask according
|
| 108 |
+
to the specific tokenizer's default, defined by the `return_outputs` attribute.
|
| 109 |
+
|
| 110 |
+
[What are attention masks?](../glossary#attention-mask)
|
| 111 |
+
return_overflowing_tokens (`bool`, *optional*, defaults to `False`):
|
| 112 |
+
Whether or not to return overflowing token sequences. If a pair of sequences of input ids (or a batch
|
| 113 |
+
of pairs) is provided with `truncation_strategy = longest_first` or `True`, an error is raised instead
|
| 114 |
+
of returning overflowing tokens.
|
| 115 |
+
return_special_tokens_mask (`bool`, *optional*, defaults to `False`):
|
| 116 |
+
Whether or not to return special tokens mask information.
|
| 117 |
+
return_offsets_mapping (`bool`, *optional*, defaults to `False`):
|
| 118 |
+
Whether or not to return `(char_start, char_end)` for each token.
|
| 119 |
+
|
| 120 |
+
This is only available on fast tokenizers inheriting from [`PreTrainedTokenizerFast`], if using
|
| 121 |
+
Python's tokenizer, this method will raise `NotImplementedError`.
|
| 122 |
+
return_length (`bool`, *optional*, defaults to `False`):
|
| 123 |
+
Whether or not to return the lengths of the encoded inputs.
|
| 124 |
+
verbose (`bool`, *optional*, defaults to `True`):
|
| 125 |
+
Whether or not to print more information and warnings.
|
| 126 |
+
**kwargs: passed to the `self.tokenize()` method
|
| 127 |
+
|
| 128 |
+
Return:
|
| 129 |
+
[`BatchEncoding`]: A [`BatchEncoding`] with the following fields:
|
| 130 |
+
|
| 131 |
+
- **input_ids** -- List of token ids to be fed to a model.
|
| 132 |
+
|
| 133 |
+
[What are input IDs?](../glossary#input-ids)
|
| 134 |
+
|
| 135 |
+
- **attention_mask** -- List of indices specifying which tokens should be attended to by the model (when
|
| 136 |
+
`return_attention_mask=True` or if *"attention_mask"* is in `self.model_input_names`).
|
| 137 |
+
|
| 138 |
+
[What are attention masks?](../glossary#attention-mask)
|
| 139 |
+
|
| 140 |
+
- **overflowing_tokens** -- List of overflowing tokens sequences (when a `max_length` is specified and
|
| 141 |
+
`return_overflowing_tokens=True`).
|
| 142 |
+
- **num_truncated_tokens** -- Number of tokens truncated (when a `max_length` is specified and
|
| 143 |
+
`return_overflowing_tokens=True`).
|
| 144 |
+
- **special_tokens_mask** -- List of 0s and 1s, with 1 specifying added special tokens and 0 specifying
|
| 145 |
+
regular sequence tokens (when `add_special_tokens=True` and `return_special_tokens_mask=True`).
|
| 146 |
+
- **length** -- The length of the inputs (when `return_length=True`)
|
| 147 |
+
"""
|
| 148 |
+
|
| 149 |
+
|
| 150 |
+
class MistralTokenizerType(str, Enum):
|
| 151 |
+
"""Enum for the different type of tokenizer."""
|
| 152 |
+
|
| 153 |
+
spm = "spm"
|
| 154 |
+
tekken = "tekken"
|
| 155 |
+
|
| 156 |
+
|
| 157 |
+
@requires(backends=("mistral-common",))
|
| 158 |
+
class MistralCommonTokenizer(PushToHubMixin):
|
| 159 |
+
"""
|
| 160 |
+
Class to wrap `mistral-common` tokenizers.
|
| 161 |
+
|
| 162 |
+
`mistral-common` is the official tokenizer library for Mistral AI models. To use it, you need to install it with:
|
| 163 |
+
|
| 164 |
+
```bash
|
| 165 |
+
pip install transformers[mistral-common]
|
| 166 |
+
```
|
| 167 |
+
|
| 168 |
+
Otherwise the tokenizer falls back to the Transformers implementation of the tokenizer.
|
| 169 |
+
|
| 170 |
+
For more info on `mistral-common`, see [mistral-common](https://github.com/mistralai/mistral-common).
|
| 171 |
+
|
| 172 |
+
This class is a wrapper around a `mistral_common.tokens.tokenizers.mistral.MistralTokenizer`.
|
| 173 |
+
It provides a Hugging Face compatible interface to tokenize using the official mistral-common tokenizer.
|
| 174 |
+
|
| 175 |
+
Supports the following methods from the `PreTrainedTokenizerBase` class:
|
| 176 |
+
|
| 177 |
+
- [`~MistralCommonTokenizer.get_vocab`]: Returns the vocabulary as a dictionary of token to index.
|
| 178 |
+
- [`~MistralCommonTokenizer.encode`]: Encode a string to a list of integers.
|
| 179 |
+
- [`~MistralCommonTokenizer.decode`]: Decode a list of integers to a string.
|
| 180 |
+
- [`~MistralCommonTokenizer.batch_decode`]: Decode a batch of list of integers to a list of strings.
|
| 181 |
+
- [`~MistralCommonTokenizer.convert_tokens_to_ids`]: Convert a list of tokens to a list of integers.
|
| 182 |
+
- [`~MistralCommonTokenizer.convert_ids_to_tokens`]: Convert a list of integers to a list of tokens.
|
| 183 |
+
- [`~MistralCommonTokenizer.tokenize`]: Tokenize a string.
|
| 184 |
+
- [`~MistralCommonTokenizer.get_special_tokens_mask`]: Get the special tokens mask for a list of tokens.
|
| 185 |
+
- [`~MistralCommonTokenizer.prepare_for_model`]: Prepare a list of inputs for the model.
|
| 186 |
+
- [`~MistralCommonTokenizer.pad`]: Pad a list of inputs to the same length.
|
| 187 |
+
- [`~MistralCommonTokenizer.truncate_sequences`]: Truncate a list of sequences to the same length.
|
| 188 |
+
- [`~MistralCommonTokenizer.apply_chat_template`]: Apply a chat template to a list of messages.
|
| 189 |
+
- [`~MistralCommonTokenizer.__call__`]: Tokenize a string or a list of strings.
|
| 190 |
+
- [`~MistralCommonTokenizer.from_pretrained`]: Download and cache a pretrained tokenizer from the Hugging Face model hub or local directory.
|
| 191 |
+
- [`~MistralCommonTokenizer.save_pretrained`]: Save a tokenizer to a directory, so it can be reloaded using the `from_pretrained` class method.
|
| 192 |
+
- [`~MistralCommonTokenizer.push_to_hub`]: Upload tokenizer to the Hugging Face model hub.
|
| 193 |
+
|
| 194 |
+
Here are the key differences with the `PreTrainedTokenizerBase` class:
|
| 195 |
+
|
| 196 |
+
- Pair of sequences are not supported. The signature have been kept for compatibility but all arguments related to pair of sequences are ignored. The return values of pairs are returned as `None`.
|
| 197 |
+
- The `is_split_into_words` argument is not supported.
|
| 198 |
+
- The `return_token_type_ids` argument is not supported.
|
| 199 |
+
- It is not possible to add new tokens to the tokenizer. Also the special tokens are handled differently from Transformers. In `mistral-common`, special tokens are never encoded directly. This means that: `tokenizer.encode("<s>")` will not return the ID of the `<s>` token. Instead, it will return a list of IDs corresponding to the tokenization of the string `"<s>"`. For more information, see the [mistral-common documentation](https://mistralai.github.io/mistral-common/usage/tokenizers/#special-tokens).
|
| 200 |
+
|
| 201 |
+
If you have suggestions to improve this class, please open an issue on the [mistral-common GitHub repository](https://github.com/mistralai/mistral-common/issues) if it is related to the tokenizer or on the [Transformers GitHub repository](https://github.com/huggingface/transformers/issues) if it is related to the Hugging Face interface.
|
| 202 |
+
"""
|
| 203 |
+
|
| 204 |
+
model_input_names: list[str] = ["input_ids", "attention_mask"]
|
| 205 |
+
padding_side: str = "left"
|
| 206 |
+
truncation_side: str = "right"
|
| 207 |
+
|
| 208 |
+
def __init__(
|
| 209 |
+
self,
|
| 210 |
+
tokenizer_path: Union[str, os.PathLike, Path],
|
| 211 |
+
mode: ValidationMode = ValidationMode.test,
|
| 212 |
+
model_max_length: int = VERY_LARGE_INTEGER,
|
| 213 |
+
padding_side: str = "left",
|
| 214 |
+
truncation_side: str = "right",
|
| 215 |
+
model_input_names: Optional[list[str]] = None,
|
| 216 |
+
clean_up_tokenization_spaces: bool = False,
|
| 217 |
+
**kwargs,
|
| 218 |
+
):
|
| 219 |
+
"""
|
| 220 |
+
Constructs a `MistralCommonTokenizer`.
|
| 221 |
+
|
| 222 |
+
- **model_input_names** (`List[str]`) -- A list of inputs expected in the forward pass of the model.
|
| 223 |
+
- **padding_side** (`str`) -- The default value for the side on which the model should have padding applied.
|
| 224 |
+
Should be `'right'` or `'left'`.
|
| 225 |
+
- **truncation_side** (`str`) -- The default value for the side on which the model should have truncation
|
| 226 |
+
applied. Should be `'right'` or `'left'`.
|
| 227 |
+
|
| 228 |
+
Args:
|
| 229 |
+
tokenizer_path (`str` or `os.PathLike` or `Path`):
|
| 230 |
+
Path to the tokenizer file to load the `MistralTokenizer`.
|
| 231 |
+
mode (`ValidationMode`, *optional*, defaults to `ValidationMode.test`):
|
| 232 |
+
The mode to use for the tokenizer. This will be passed to the `MistralTokenizer` constructor.
|
| 233 |
+
model_max_length (`int`, *optional*):
|
| 234 |
+
The maximum length (in number of tokens) for the inputs to the transformer model. When the tokenizer is
|
| 235 |
+
loaded with [`~tokenization_utils_base.PreTrainedTokenizerBase.from_pretrained`], this will be set to the
|
| 236 |
+
value stored for the associated model in `max_model_input_sizes` (see above). If no value is provided, will
|
| 237 |
+
default to VERY_LARGE_INTEGER (`int(1e30)`).
|
| 238 |
+
padding_side (`str`, *optional*):
|
| 239 |
+
The side on which the model should have padding applied. Should be selected between ['right', 'left'].
|
| 240 |
+
Default value is picked from the class attribute of the same name.
|
| 241 |
+
truncation_side (`str`, *optional*):
|
| 242 |
+
The side on which the model should have truncation applied. Should be selected between ['right', 'left'].
|
| 243 |
+
Default value is picked from the class attribute of the same name.
|
| 244 |
+
model_input_names (`List[string]`, *optional*):
|
| 245 |
+
The list of inputs accepted by the forward pass of the model (like `"token_type_ids"` or
|
| 246 |
+
`"attention_mask"`). Default value is picked from the class attribute of the same name.
|
| 247 |
+
clean_up_tokenization_spaces (`bool`, *optional*, defaults to `False`):
|
| 248 |
+
Whether or not the model should cleanup the spaces that were added when splitting the input text during the
|
| 249 |
+
tokenization process.
|
| 250 |
+
"""
|
| 251 |
+
if kwargs:
|
| 252 |
+
raise ValueError(f"Kwargs {list(kwargs.keys())} are not supported to init `MistralCommonTokenizer`.")
|
| 253 |
+
|
| 254 |
+
self._tokenizer_path = Path(tokenizer_path)
|
| 255 |
+
self.tokenizer: MistralTokenizer = MistralTokenizer.from_file(str(self._tokenizer_path), mode=mode)
|
| 256 |
+
self._tokenizer_type = (
|
| 257 |
+
MistralTokenizerType.tekken
|
| 258 |
+
if isinstance(self.tokenizer.instruct_tokenizer.tokenizer, Tekkenizer)
|
| 259 |
+
else MistralTokenizerType.spm
|
| 260 |
+
)
|
| 261 |
+
self.truncation_side = truncation_side
|
| 262 |
+
self.padding_side = padding_side
|
| 263 |
+
self.model_max_length = model_max_length
|
| 264 |
+
self.cleanup_tokenization_spaces = clean_up_tokenization_spaces
|
| 265 |
+
self.deprecation_warnings = {} # Use to store when we have already noticed a deprecation warning (avoid overlogging).
|
| 266 |
+
|
| 267 |
+
if model_input_names is not None:
|
| 268 |
+
if (
|
| 269 |
+
not isinstance(model_input_names, (list, tuple))
|
| 270 |
+
and len(model_input_names) == 0
|
| 271 |
+
and not all(isinstance(i, str) for i in model_input_names)
|
| 272 |
+
):
|
| 273 |
+
raise ValueError(
|
| 274 |
+
"`model_input_names` should be a non-empty list or tuple of str but got an empty value."
|
| 275 |
+
)
|
| 276 |
+
self.model_input_names = model_input_names
|
| 277 |
+
|
| 278 |
+
self._cache_get_vocab: Optional[dict[str, int]] = None
|
| 279 |
+
|
| 280 |
+
@property
|
| 281 |
+
def bos_token_id(self) -> int:
|
| 282 |
+
"""
|
| 283 |
+
Id of the beginning of sentence token in the vocabulary.
|
| 284 |
+
"""
|
| 285 |
+
return self.tokenizer.instruct_tokenizer.tokenizer.bos_id
|
| 286 |
+
|
| 287 |
+
@property
|
| 288 |
+
def eos_token_id(self) -> int:
|
| 289 |
+
"""
|
| 290 |
+
Id of the end of sentence token in the vocabulary.
|
| 291 |
+
"""
|
| 292 |
+
return self.tokenizer.instruct_tokenizer.tokenizer.eos_id
|
| 293 |
+
|
| 294 |
+
@property
|
| 295 |
+
def unk_token_id(self) -> int:
|
| 296 |
+
"""
|
| 297 |
+
Id of the unknown token in the vocabulary.
|
| 298 |
+
"""
|
| 299 |
+
return self.tokenizer.instruct_tokenizer.tokenizer.unk_id
|
| 300 |
+
|
| 301 |
+
@property
|
| 302 |
+
def pad_token_id(self) -> int:
|
| 303 |
+
"""
|
| 304 |
+
Id of the padding token in the vocabulary.
|
| 305 |
+
"""
|
| 306 |
+
return self.tokenizer.instruct_tokenizer.tokenizer.pad_id
|
| 307 |
+
|
| 308 |
+
@property
|
| 309 |
+
def bos_token(self) -> str:
|
| 310 |
+
"""
|
| 311 |
+
String associated to the beginning of sentence token in the vocabulary.
|
| 312 |
+
"""
|
| 313 |
+
return self.convert_ids_to_tokens(self.bos_token_id)
|
| 314 |
+
|
| 315 |
+
@property
|
| 316 |
+
def eos_token(self) -> str:
|
| 317 |
+
"""
|
| 318 |
+
String associated to the end of sentence token in the vocabulary.
|
| 319 |
+
"""
|
| 320 |
+
return self.convert_ids_to_tokens(self.eos_token_id)
|
| 321 |
+
|
| 322 |
+
@property
|
| 323 |
+
def unk_token(self) -> str:
|
| 324 |
+
"""
|
| 325 |
+
String associated to the unknown token in the vocabulary.
|
| 326 |
+
"""
|
| 327 |
+
return self.convert_ids_to_tokens(self.unk_token_id)
|
| 328 |
+
|
| 329 |
+
@property
|
| 330 |
+
def pad_token(self) -> str:
|
| 331 |
+
"""
|
| 332 |
+
String associated to the padding token in the vocabulary.
|
| 333 |
+
"""
|
| 334 |
+
return self.convert_ids_to_tokens(self.pad_token_id)
|
| 335 |
+
|
| 336 |
+
@property
|
| 337 |
+
def vocab_size(self) -> int:
|
| 338 |
+
"""
|
| 339 |
+
Returns the size of the vocabulary.
|
| 340 |
+
|
| 341 |
+
`int`: Size of the vocabulary.
|
| 342 |
+
"""
|
| 343 |
+
return self.tokenizer.instruct_tokenizer.tokenizer.n_words
|
| 344 |
+
|
| 345 |
+
def get_vocab(self) -> dict[str, int]:
|
| 346 |
+
"""
|
| 347 |
+
Returns the vocabulary as a dictionary of token to index.
|
| 348 |
+
|
| 349 |
+
This is a lossy conversion. There may be multiple token ids that decode to the same
|
| 350 |
+
string due to partial UTF-8 byte sequences being converted to �.
|
| 351 |
+
|
| 352 |
+
Returns:
|
| 353 |
+
`Dict[str, int]`: The vocabulary.
|
| 354 |
+
"""
|
| 355 |
+
if self._cache_get_vocab is None:
|
| 356 |
+
self._cache_get_vocab = {
|
| 357 |
+
token: idx for idx, token in enumerate(self.tokenizer.instruct_tokenizer.tokenizer.vocab())
|
| 358 |
+
}
|
| 359 |
+
return self._cache_get_vocab
|
| 360 |
+
|
| 361 |
+
def __len__(self):
|
| 362 |
+
"""
|
| 363 |
+
Size of the full vocabulary with the added tokens.
|
| 364 |
+
"""
|
| 365 |
+
return self.vocab_size
|
| 366 |
+
|
| 367 |
+
@add_end_docstrings(
|
| 368 |
+
ENCODE_KWARGS_DOCSTRING,
|
| 369 |
+
"""
|
| 370 |
+
**kwargs: Not supported by `MistralCommonTokenizer.encode`.
|
| 371 |
+
Will raise an error if used.
|
| 372 |
+
""",
|
| 373 |
+
"""
|
| 374 |
+
Returns:
|
| 375 |
+
`List[int]`, `torch.Tensor`: The tokenized ids of the text.
|
| 376 |
+
""",
|
| 377 |
+
)
|
| 378 |
+
def encode(
|
| 379 |
+
self,
|
| 380 |
+
text: Union[TextInput, EncodedInput],
|
| 381 |
+
text_pair: None = None,
|
| 382 |
+
add_special_tokens: bool = True,
|
| 383 |
+
padding: Union[bool, str, PaddingStrategy] = False,
|
| 384 |
+
truncation: Union[bool, str, TruncationStrategy, None] = None,
|
| 385 |
+
max_length: Optional[int] = None,
|
| 386 |
+
stride: int = 0,
|
| 387 |
+
pad_to_multiple_of: Optional[int] = None,
|
| 388 |
+
padding_side: Optional[str] = None,
|
| 389 |
+
return_tensors: Optional[Union[str, TensorType]] = None,
|
| 390 |
+
verbose: bool = True,
|
| 391 |
+
**kwargs,
|
| 392 |
+
) -> list[int]:
|
| 393 |
+
"""
|
| 394 |
+
Converts a string to a sequence of ids (integer), using the tokenizer and vocabulary.
|
| 395 |
+
|
| 396 |
+
Args:
|
| 397 |
+
text (`str` or `List[int]`):
|
| 398 |
+
The first sequence to be encoded. This can be a string or a list of integers (tokenized string ids).
|
| 399 |
+
text_pair (`None`, *optional*):
|
| 400 |
+
Not supported by `MistralCommonTokenizer.encode`. Kept to match `PreTrainedTokenizerBase.encode` signature.
|
| 401 |
+
"""
|
| 402 |
+
if kwargs:
|
| 403 |
+
raise ValueError(f"Kwargs {list(kwargs.keys())} are not supported by `MistralCommonTokenizer.encode`.")
|
| 404 |
+
if text_pair:
|
| 405 |
+
raise ValueError("`MistralCommonTokenizer.encode` does not support `text_pair`.")
|
| 406 |
+
|
| 407 |
+
padding_strategy, truncation_strategy, max_length, _ = self._get_padding_truncation_strategies(
|
| 408 |
+
padding=padding,
|
| 409 |
+
truncation=truncation,
|
| 410 |
+
max_length=max_length,
|
| 411 |
+
pad_to_multiple_of=pad_to_multiple_of,
|
| 412 |
+
verbose=verbose,
|
| 413 |
+
)
|
| 414 |
+
|
| 415 |
+
encoded_inputs = self._encode_plus(
|
| 416 |
+
text,
|
| 417 |
+
add_special_tokens=add_special_tokens,
|
| 418 |
+
padding_strategy=padding_strategy,
|
| 419 |
+
truncation_strategy=truncation_strategy,
|
| 420 |
+
max_length=max_length,
|
| 421 |
+
stride=stride,
|
| 422 |
+
pad_to_multiple_of=pad_to_multiple_of,
|
| 423 |
+
padding_side=padding_side,
|
| 424 |
+
return_tensors=return_tensors,
|
| 425 |
+
return_attention_mask=False,
|
| 426 |
+
return_overflowing_tokens=False,
|
| 427 |
+
return_special_tokens_mask=False,
|
| 428 |
+
return_length=False,
|
| 429 |
+
verbose=verbose,
|
| 430 |
+
)
|
| 431 |
+
|
| 432 |
+
return encoded_inputs["input_ids"]
|
| 433 |
+
|
| 434 |
+
def decode(
|
| 435 |
+
self,
|
| 436 |
+
token_ids: Union[int, list[int], np.ndarray, "torch.Tensor"],
|
| 437 |
+
skip_special_tokens: bool = False,
|
| 438 |
+
clean_up_tokenization_spaces: Optional[bool] = None,
|
| 439 |
+
**kwargs,
|
| 440 |
+
) -> str:
|
| 441 |
+
"""
|
| 442 |
+
Converts a sequence of ids in a string, using the tokenizer and vocabulary with options to remove special
|
| 443 |
+
tokens and clean up tokenization spaces.
|
| 444 |
+
|
| 445 |
+
Args:
|
| 446 |
+
token_ids (`Union[int, List[int], np.ndarray, torch.Tensor]`):
|
| 447 |
+
List of tokenized input ids. Can be obtained using the `__call__` method.
|
| 448 |
+
skip_special_tokens (`bool`, *optional*, defaults to `False`):
|
| 449 |
+
Whether or not to remove special tokens in the decoding.
|
| 450 |
+
clean_up_tokenization_spaces (`bool`, *optional*):
|
| 451 |
+
Whether or not to clean up the tokenization spaces. If `None`, will default to
|
| 452 |
+
`self.clean_up_tokenization_spaces`.
|
| 453 |
+
kwargs (additional keyword arguments, *optional*):
|
| 454 |
+
Not supported by `MistralCommonTokenizer.decode`.
|
| 455 |
+
Will raise an error if used.
|
| 456 |
+
|
| 457 |
+
Returns:
|
| 458 |
+
`str`: The decoded sentence.
|
| 459 |
+
"""
|
| 460 |
+
if kwargs:
|
| 461 |
+
raise ValueError(f"Kwargs {list(kwargs.keys())} are not supported by `MistralCommonTokenizer.decode`.")
|
| 462 |
+
|
| 463 |
+
clean_up_tokenization_spaces = clean_up_tokenization_spaces or self.cleanup_tokenization_spaces
|
| 464 |
+
|
| 465 |
+
# Convert inputs to python lists
|
| 466 |
+
token_ids = to_py_obj(token_ids)
|
| 467 |
+
|
| 468 |
+
special_token_policy = SpecialTokenPolicy.IGNORE if skip_special_tokens else SpecialTokenPolicy.KEEP
|
| 469 |
+
|
| 470 |
+
decoded_string = self.tokenizer.decode(token_ids, special_token_policy=special_token_policy)
|
| 471 |
+
if clean_up_tokenization_spaces:
|
| 472 |
+
decoded_string = PreTrainedTokenizerBase.clean_up_tokenization(decoded_string)
|
| 473 |
+
|
| 474 |
+
return decoded_string
|
| 475 |
+
|
| 476 |
+
def batch_decode(
|
| 477 |
+
self,
|
| 478 |
+
sequences: Union[list[int], list[list[int]], np.ndarray, "torch.Tensor"],
|
| 479 |
+
skip_special_tokens: bool = False,
|
| 480 |
+
clean_up_tokenization_spaces: Optional[bool] = None,
|
| 481 |
+
**kwargs,
|
| 482 |
+
) -> list[str]:
|
| 483 |
+
"""
|
| 484 |
+
Convert a list of lists of token ids into a list of strings by calling decode.
|
| 485 |
+
|
| 486 |
+
Args:
|
| 487 |
+
sequences (`Union[List[int], List[List[int]], np.ndarray, torch.Tensor]`):
|
| 488 |
+
List of tokenized input ids. Can be obtained using the `__call__` method.
|
| 489 |
+
skip_special_tokens (`bool`, *optional*, defaults to `False`):
|
| 490 |
+
Whether or not to remove special tokens in the decoding.
|
| 491 |
+
clean_up_tokenization_spaces (`bool`, *optional*):
|
| 492 |
+
Whether or not to clean up the tokenization spaces. If `None`, will default to
|
| 493 |
+
`self.clean_up_tokenization_spaces`.
|
| 494 |
+
kwargs (additional keyword arguments, *optional*):
|
| 495 |
+
Not supported by `MistralCommonTokenizer.batch_decode`.
|
| 496 |
+
Will raise an error if used.
|
| 497 |
+
|
| 498 |
+
Returns:
|
| 499 |
+
`List[str]`: The list of decoded sentences.
|
| 500 |
+
"""
|
| 501 |
+
return [
|
| 502 |
+
self.decode(
|
| 503 |
+
seq,
|
| 504 |
+
skip_special_tokens=skip_special_tokens,
|
| 505 |
+
clean_up_tokenization_spaces=clean_up_tokenization_spaces,
|
| 506 |
+
**kwargs,
|
| 507 |
+
)
|
| 508 |
+
for seq in sequences
|
| 509 |
+
]
|
| 510 |
+
|
| 511 |
+
def _is_control_token(self, token_id: int) -> bool:
|
| 512 |
+
if self._tokenizer_type == MistralTokenizerType.spm:
|
| 513 |
+
return token_id in self.tokenizer.instruct_tokenizer.tokenizer._control_tokens()
|
| 514 |
+
elif self._tokenizer_type == MistralTokenizerType.tekken:
|
| 515 |
+
return token_id < self.tokenizer.instruct_tokenizer.tokenizer.num_special_tokens
|
| 516 |
+
else:
|
| 517 |
+
raise ValueError(f"Unknown tokenizer type: {self._tokenizer_type}")
|
| 518 |
+
|
| 519 |
+
@overload
|
| 520 |
+
def convert_ids_to_tokens(self, ids: int, skip_special_tokens: bool = False) -> str: ...
|
| 521 |
+
@overload
|
| 522 |
+
def convert_ids_to_tokens(self, ids: list[int], skip_special_tokens: bool = False) -> list[str]: ...
|
| 523 |
+
def convert_ids_to_tokens(
|
| 524 |
+
self, ids: Union[int, list[int]], skip_special_tokens: bool = False
|
| 525 |
+
) -> Union[str, list[str]]:
|
| 526 |
+
"""
|
| 527 |
+
Converts a single index or a sequence of indices in a token or a sequence of tokens, using the vocabulary and
|
| 528 |
+
added tokens.
|
| 529 |
+
|
| 530 |
+
Args:
|
| 531 |
+
ids (`int` or `List[int]`):
|
| 532 |
+
The token id (or token ids) to convert to tokens.
|
| 533 |
+
skip_special_tokens (`bool`, *optional*, defaults to `False`):
|
| 534 |
+
Whether or not to remove special tokens in the decoding.
|
| 535 |
+
|
| 536 |
+
Returns:
|
| 537 |
+
`str` or `List[str]`: The decoded token(s).
|
| 538 |
+
"""
|
| 539 |
+
|
| 540 |
+
if isinstance(ids, int):
|
| 541 |
+
one_token = True
|
| 542 |
+
ids = [ids]
|
| 543 |
+
else:
|
| 544 |
+
one_token = False
|
| 545 |
+
|
| 546 |
+
tokens: list[str] = []
|
| 547 |
+
for token_id in ids:
|
| 548 |
+
if self._is_control_token(token_id) and skip_special_tokens:
|
| 549 |
+
continue
|
| 550 |
+
tokens.append(self.tokenizer.instruct_tokenizer.tokenizer.id_to_piece(token_id))
|
| 551 |
+
|
| 552 |
+
if one_token:
|
| 553 |
+
if tokens == []:
|
| 554 |
+
raise ValueError(f"Invalid token id {ids}.")
|
| 555 |
+
|
| 556 |
+
return tokens[0]
|
| 557 |
+
return tokens
|
| 558 |
+
|
| 559 |
+
def _piece_to_id(self, piece: str) -> int:
|
| 560 |
+
if self._tokenizer_type == MistralTokenizerType.spm:
|
| 561 |
+
return self.tokenizer.instruct_tokenizer.tokenizer._model.piece_to_id(piece)
|
| 562 |
+
elif self._tokenizer_type == MistralTokenizerType.tekken:
|
| 563 |
+
pieces = self.tokenizer.instruct_tokenizer.tokenizer._model.encode(
|
| 564 |
+
piece, allowed_special="all", disallowed_special=set()
|
| 565 |
+
)
|
| 566 |
+
assert len(pieces) == 1, f"Expected to decode 1 token, got {len(pieces)}"
|
| 567 |
+
return pieces[0]
|
| 568 |
+
else:
|
| 569 |
+
raise ValueError(f"Unknown tokenizer type: {self._tokenizer_type}")
|
| 570 |
+
|
| 571 |
+
def convert_tokens_to_ids(self, tokens: Union[str, list[str]]) -> Union[int, list[int]]:
|
| 572 |
+
"""
|
| 573 |
+
Converts a token string (or a sequence of tokens) in a single integer id (or a sequence of ids), using the
|
| 574 |
+
vocabulary.
|
| 575 |
+
|
| 576 |
+
Args:
|
| 577 |
+
tokens (`str` or `List[str]`): One or several token(s) to convert to token id(s).
|
| 578 |
+
|
| 579 |
+
Returns:
|
| 580 |
+
`int` or `List[int]`: The token id or list of token ids.
|
| 581 |
+
"""
|
| 582 |
+
|
| 583 |
+
if isinstance(tokens, str):
|
| 584 |
+
one_token = True
|
| 585 |
+
tokens = [tokens]
|
| 586 |
+
else:
|
| 587 |
+
one_token = False
|
| 588 |
+
|
| 589 |
+
ids: list[int] = []
|
| 590 |
+
for token in tokens:
|
| 591 |
+
ids.append(self._piece_to_id(token))
|
| 592 |
+
|
| 593 |
+
if one_token:
|
| 594 |
+
return ids[0]
|
| 595 |
+
return ids
|
| 596 |
+
|
| 597 |
+
def _text_to_ids(self, text: TextInput, add_special_tokens: bool) -> list[int]:
|
| 598 |
+
"""
|
| 599 |
+
Converts a string into a sequence of tokens ids, using the tokenizer.
|
| 600 |
+
"""
|
| 601 |
+
tokens_ids = self.tokenizer.instruct_tokenizer.tokenizer.encode(
|
| 602 |
+
text, bos=add_special_tokens, eos=add_special_tokens
|
| 603 |
+
)
|
| 604 |
+
return tokens_ids
|
| 605 |
+
|
| 606 |
+
def tokenize(self, text: TextInput, **kwargs) -> list[str]:
|
| 607 |
+
"""
|
| 608 |
+
Converts a string into a sequence of tokens, using the tokenizer.
|
| 609 |
+
|
| 610 |
+
Split in words for word-based vocabulary or sub-words for sub-word-based vocabularies.
|
| 611 |
+
|
| 612 |
+
Args:
|
| 613 |
+
text (`str`):
|
| 614 |
+
The sequence to be encoded.
|
| 615 |
+
**kwargs (additional keyword arguments):
|
| 616 |
+
Not supported by `MistralCommonTokenizer.tokenize`.
|
| 617 |
+
Will raise an error if used.
|
| 618 |
+
|
| 619 |
+
Returns:
|
| 620 |
+
`List[str]`: The list of tokens.
|
| 621 |
+
"""
|
| 622 |
+
if kwargs:
|
| 623 |
+
raise ValueError(f"Kwargs {list(kwargs.keys())} are not supported by `MistralCommonTokenizer.tokenize`.")
|
| 624 |
+
|
| 625 |
+
return self.convert_ids_to_tokens(self._text_to_ids(text, add_special_tokens=False), skip_special_tokens=False)
|
| 626 |
+
|
| 627 |
+
def _encode_plus(
|
| 628 |
+
self,
|
| 629 |
+
text: Union[TextInput, EncodedInput],
|
| 630 |
+
add_special_tokens: bool = True,
|
| 631 |
+
padding_strategy: PaddingStrategy = PaddingStrategy.DO_NOT_PAD,
|
| 632 |
+
truncation_strategy: TruncationStrategy = TruncationStrategy.DO_NOT_TRUNCATE,
|
| 633 |
+
max_length: Optional[int] = None,
|
| 634 |
+
stride: int = 0,
|
| 635 |
+
pad_to_multiple_of: Optional[int] = None,
|
| 636 |
+
padding_side: Optional[str] = None,
|
| 637 |
+
return_tensors: Optional[Union[str, TensorType]] = None,
|
| 638 |
+
return_attention_mask: Optional[bool] = None,
|
| 639 |
+
return_overflowing_tokens: bool = False,
|
| 640 |
+
return_special_tokens_mask: bool = False,
|
| 641 |
+
return_length: bool = False,
|
| 642 |
+
verbose: bool = True,
|
| 643 |
+
**kwargs,
|
| 644 |
+
) -> BatchEncoding:
|
| 645 |
+
if kwargs:
|
| 646 |
+
raise ValueError(
|
| 647 |
+
f"Kwargs {list(kwargs.keys())} are not supported by `MistralCommonTokenizer._encode_plus`."
|
| 648 |
+
)
|
| 649 |
+
|
| 650 |
+
def get_input_ids(text):
|
| 651 |
+
if isinstance(text, str):
|
| 652 |
+
return self._text_to_ids(text, add_special_tokens)
|
| 653 |
+
elif isinstance(text, (list, tuple)) and len(text) > 0 and isinstance(text[0], int):
|
| 654 |
+
return text
|
| 655 |
+
else:
|
| 656 |
+
raise ValueError(f"Input {text} is not valid. Should be a string, or a list/tuple of integers.")
|
| 657 |
+
|
| 658 |
+
ids = get_input_ids(text)
|
| 659 |
+
|
| 660 |
+
return self.prepare_for_model(
|
| 661 |
+
ids,
|
| 662 |
+
add_special_tokens=add_special_tokens,
|
| 663 |
+
padding=padding_strategy.value,
|
| 664 |
+
truncation=truncation_strategy.value,
|
| 665 |
+
max_length=max_length,
|
| 666 |
+
stride=stride,
|
| 667 |
+
pad_to_multiple_of=pad_to_multiple_of,
|
| 668 |
+
padding_side=padding_side,
|
| 669 |
+
return_tensors=return_tensors,
|
| 670 |
+
prepend_batch_axis=True,
|
| 671 |
+
return_attention_mask=return_attention_mask,
|
| 672 |
+
return_overflowing_tokens=return_overflowing_tokens,
|
| 673 |
+
return_special_tokens_mask=return_special_tokens_mask,
|
| 674 |
+
return_length=return_length,
|
| 675 |
+
verbose=verbose,
|
| 676 |
+
)
|
| 677 |
+
|
| 678 |
+
def _batch_encode_plus(
|
| 679 |
+
self,
|
| 680 |
+
batch_text: Union[
|
| 681 |
+
list[TextInput],
|
| 682 |
+
list[EncodedInput],
|
| 683 |
+
],
|
| 684 |
+
add_special_tokens: bool = True,
|
| 685 |
+
padding_strategy: PaddingStrategy = PaddingStrategy.DO_NOT_PAD,
|
| 686 |
+
truncation_strategy: TruncationStrategy = TruncationStrategy.DO_NOT_TRUNCATE,
|
| 687 |
+
max_length: Optional[int] = None,
|
| 688 |
+
stride: int = 0,
|
| 689 |
+
pad_to_multiple_of: Optional[int] = None,
|
| 690 |
+
padding_side: Optional[str] = None,
|
| 691 |
+
return_tensors: Optional[Union[str, TensorType]] = None,
|
| 692 |
+
return_attention_mask: Optional[bool] = None,
|
| 693 |
+
return_overflowing_tokens: bool = False,
|
| 694 |
+
return_special_tokens_mask: bool = False,
|
| 695 |
+
return_offsets_mapping: bool = False,
|
| 696 |
+
return_length: bool = False,
|
| 697 |
+
verbose: bool = True,
|
| 698 |
+
**kwargs,
|
| 699 |
+
) -> BatchEncoding:
|
| 700 |
+
def get_input_ids(text):
|
| 701 |
+
if isinstance(text, str):
|
| 702 |
+
return self._text_to_ids(text, add_special_tokens)
|
| 703 |
+
elif isinstance(text, (list, tuple)) and len(text) > 0 and isinstance(text[0], int):
|
| 704 |
+
return text
|
| 705 |
+
else:
|
| 706 |
+
raise ValueError("Input is not valid. Should be a string or a list/tuple of integers.")
|
| 707 |
+
|
| 708 |
+
if return_offsets_mapping:
|
| 709 |
+
raise NotImplementedError(
|
| 710 |
+
"return_offset_mapping is not available when using Python tokenizers. "
|
| 711 |
+
"To use this feature, change your tokenizer to one deriving from "
|
| 712 |
+
"transformers.PreTrainedTokenizerFast."
|
| 713 |
+
)
|
| 714 |
+
|
| 715 |
+
input_ids = []
|
| 716 |
+
for ids in batch_text:
|
| 717 |
+
input_ids.append(get_input_ids(ids))
|
| 718 |
+
|
| 719 |
+
batch_outputs = self._batch_prepare_for_model(
|
| 720 |
+
input_ids,
|
| 721 |
+
add_special_tokens=add_special_tokens,
|
| 722 |
+
padding_strategy=padding_strategy,
|
| 723 |
+
truncation_strategy=truncation_strategy,
|
| 724 |
+
max_length=max_length,
|
| 725 |
+
stride=stride,
|
| 726 |
+
pad_to_multiple_of=pad_to_multiple_of,
|
| 727 |
+
padding_side=padding_side,
|
| 728 |
+
return_attention_mask=return_attention_mask,
|
| 729 |
+
return_overflowing_tokens=return_overflowing_tokens,
|
| 730 |
+
return_special_tokens_mask=return_special_tokens_mask,
|
| 731 |
+
return_length=return_length,
|
| 732 |
+
return_tensors=return_tensors,
|
| 733 |
+
verbose=verbose,
|
| 734 |
+
)
|
| 735 |
+
|
| 736 |
+
return BatchEncoding(batch_outputs)
|
| 737 |
+
|
| 738 |
+
def _all_special_ids(self) -> set[int]:
|
| 739 |
+
if self._tokenizer_type == MistralTokenizerType.tekken:
|
| 740 |
+
return {t["rank"] for t in self.tokenizer.instruct_tokenizer.tokenizer._all_special_tokens}
|
| 741 |
+
elif self._tokenizer_type == MistralTokenizerType.spm:
|
| 742 |
+
return self.tokenizer.instruct_tokenizer.tokenizer._control_tokens()
|
| 743 |
+
else:
|
| 744 |
+
raise ValueError(f"Unknown tokenizer type: {self._tokenizer_type}")
|
| 745 |
+
|
| 746 |
+
def get_special_tokens_mask(
|
| 747 |
+
self, token_ids_0: list, token_ids_1: None = None, already_has_special_tokens: bool = False
|
| 748 |
+
) -> list[int]:
|
| 749 |
+
"""
|
| 750 |
+
Retrieves sequence ids from a token list that has no special tokens added. This method is called when adding
|
| 751 |
+
special tokens using the tokenizer `prepare_for_model` or `encode_plus` methods.
|
| 752 |
+
|
| 753 |
+
Args:
|
| 754 |
+
token_ids_0 (`List[int]`):
|
| 755 |
+
List of ids of the sequence.
|
| 756 |
+
token_ids_1 (`List[int]`, *optional*):
|
| 757 |
+
Not supported by `MistralCommonTokenizer`. Kept to match the interface of `PreTrainedTokenizerBase`.
|
| 758 |
+
already_has_special_tokens (`bool`, *optional*, defaults to `False`):
|
| 759 |
+
Whether or not the token list is already formatted with special tokens for the model.
|
| 760 |
+
|
| 761 |
+
Returns:
|
| 762 |
+
A list of integers in the range [0, 1]: 1 for a special token, 0 for a sequence token.
|
| 763 |
+
"""
|
| 764 |
+
if token_ids_1 is not None:
|
| 765 |
+
raise ValueError(
|
| 766 |
+
"`token_ids_1` is not supported by `MistralCommonTokenizer` and should be `None`, kept for compatibility."
|
| 767 |
+
)
|
| 768 |
+
if already_has_special_tokens:
|
| 769 |
+
raise ValueError(
|
| 770 |
+
"`already_has_special_tokens` is not supported by `MistralCommonTokenizer` and should be `False`."
|
| 771 |
+
)
|
| 772 |
+
|
| 773 |
+
all_special_ids = self._all_special_ids() # cache the ids
|
| 774 |
+
|
| 775 |
+
special_tokens_mask = [1 if token in all_special_ids else 0 for token in token_ids_0]
|
| 776 |
+
return special_tokens_mask
|
| 777 |
+
|
| 778 |
+
def _batch_prepare_for_model(
|
| 779 |
+
self,
|
| 780 |
+
batch_ids: list[Union[PreTokenizedInput, list[int]]],
|
| 781 |
+
add_special_tokens: bool = True,
|
| 782 |
+
padding_strategy: PaddingStrategy = PaddingStrategy.DO_NOT_PAD,
|
| 783 |
+
truncation_strategy: TruncationStrategy = TruncationStrategy.DO_NOT_TRUNCATE,
|
| 784 |
+
max_length: Optional[int] = None,
|
| 785 |
+
stride: int = 0,
|
| 786 |
+
pad_to_multiple_of: Optional[int] = None,
|
| 787 |
+
padding_side: Optional[str] = None,
|
| 788 |
+
return_tensors: Optional[str] = None,
|
| 789 |
+
return_attention_mask: Optional[bool] = None,
|
| 790 |
+
return_overflowing_tokens: bool = False,
|
| 791 |
+
return_special_tokens_mask: bool = False,
|
| 792 |
+
return_length: bool = False,
|
| 793 |
+
verbose: bool = True,
|
| 794 |
+
) -> BatchEncoding:
|
| 795 |
+
"""
|
| 796 |
+
Prepares a sequence of input id so that it can be used by the model. It
|
| 797 |
+
adds special tokens, truncates sequences if overflowing while taking into account the special tokens and
|
| 798 |
+
manages a moving window (with user defined stride) for overflowing tokens.
|
| 799 |
+
|
| 800 |
+
Args:
|
| 801 |
+
batch_ids: list of tokenized input ids
|
| 802 |
+
"""
|
| 803 |
+
|
| 804 |
+
batch_outputs = {}
|
| 805 |
+
for ids in batch_ids:
|
| 806 |
+
outputs = self.prepare_for_model(
|
| 807 |
+
ids,
|
| 808 |
+
add_special_tokens=add_special_tokens,
|
| 809 |
+
padding=PaddingStrategy.DO_NOT_PAD.value, # we pad in batch afterward
|
| 810 |
+
truncation=truncation_strategy.value,
|
| 811 |
+
max_length=max_length,
|
| 812 |
+
stride=stride,
|
| 813 |
+
pad_to_multiple_of=None, # we pad in batch afterward
|
| 814 |
+
padding_side=None, # we pad in batch afterward
|
| 815 |
+
return_attention_mask=False, # we pad in batch afterward
|
| 816 |
+
return_overflowing_tokens=return_overflowing_tokens,
|
| 817 |
+
return_special_tokens_mask=return_special_tokens_mask,
|
| 818 |
+
return_length=return_length,
|
| 819 |
+
return_tensors=None, # We convert the whole batch to tensors at the end
|
| 820 |
+
prepend_batch_axis=False,
|
| 821 |
+
verbose=verbose,
|
| 822 |
+
)
|
| 823 |
+
|
| 824 |
+
for key, value in outputs.items():
|
| 825 |
+
if key not in batch_outputs:
|
| 826 |
+
batch_outputs[key] = []
|
| 827 |
+
batch_outputs[key].append(value)
|
| 828 |
+
|
| 829 |
+
batch_outputs = self.pad(
|
| 830 |
+
batch_outputs,
|
| 831 |
+
padding=padding_strategy.value,
|
| 832 |
+
max_length=max_length,
|
| 833 |
+
pad_to_multiple_of=pad_to_multiple_of,
|
| 834 |
+
padding_side=padding_side,
|
| 835 |
+
return_attention_mask=return_attention_mask,
|
| 836 |
+
)
|
| 837 |
+
|
| 838 |
+
batch_outputs = BatchEncoding(batch_outputs, tensor_type=return_tensors)
|
| 839 |
+
|
| 840 |
+
return batch_outputs
|
| 841 |
+
|
| 842 |
+
@add_end_docstrings(ENCODE_KWARGS_DOCSTRING, ENCODE_PLUS_ADDITIONAL_KWARGS_DOCSTRING)
|
| 843 |
+
def prepare_for_model(
|
| 844 |
+
self,
|
| 845 |
+
ids: list[int],
|
| 846 |
+
pair_ids: None = None,
|
| 847 |
+
add_special_tokens: bool = True,
|
| 848 |
+
padding: Union[bool, str, PaddingStrategy] = False,
|
| 849 |
+
truncation: Union[bool, str, TruncationStrategy, None] = None,
|
| 850 |
+
max_length: Optional[int] = None,
|
| 851 |
+
stride: int = 0,
|
| 852 |
+
pad_to_multiple_of: Optional[int] = None,
|
| 853 |
+
padding_side: Optional[str] = None,
|
| 854 |
+
return_tensors: Optional[Union[str, TensorType]] = None,
|
| 855 |
+
return_attention_mask: Optional[bool] = None,
|
| 856 |
+
return_overflowing_tokens: bool = False,
|
| 857 |
+
return_special_tokens_mask: bool = False,
|
| 858 |
+
return_length: bool = False,
|
| 859 |
+
verbose: bool = True,
|
| 860 |
+
prepend_batch_axis: bool = False,
|
| 861 |
+
**kwargs,
|
| 862 |
+
) -> BatchEncoding:
|
| 863 |
+
"""
|
| 864 |
+
Prepares a sequence of input id so that it can be used by the model. It
|
| 865 |
+
adds special tokens, truncates sequences if overflowing while taking into account the special tokens and
|
| 866 |
+
manages a moving window (with user defined stride) for overflowing tokens.
|
| 867 |
+
|
| 868 |
+
Args:
|
| 869 |
+
ids (`List[int]`):
|
| 870 |
+
Tokenized input ids of the first sequence.
|
| 871 |
+
pair_ids (`None`, *optional*):
|
| 872 |
+
Not supported by `MistralCommonTokenizer`. Kept to match the interface of `PreTrainedTokenizerBase`.
|
| 873 |
+
"""
|
| 874 |
+
if pair_ids is not None:
|
| 875 |
+
raise ValueError(
|
| 876 |
+
"`pair_ids` is not supported by `MistralCommonTokenizer` and should be `None`, kept for compatibility."
|
| 877 |
+
)
|
| 878 |
+
if kwargs:
|
| 879 |
+
raise ValueError(
|
| 880 |
+
f"Kwargs {list(kwargs.keys())} are not supported by `MistralCommonTokenizer.prepare_for_model`."
|
| 881 |
+
)
|
| 882 |
+
|
| 883 |
+
padding_strategy, truncation_strategy, max_length, _ = self._get_padding_truncation_strategies(
|
| 884 |
+
padding=padding,
|
| 885 |
+
truncation=truncation,
|
| 886 |
+
max_length=max_length,
|
| 887 |
+
pad_to_multiple_of=pad_to_multiple_of,
|
| 888 |
+
verbose=verbose,
|
| 889 |
+
)
|
| 890 |
+
|
| 891 |
+
len_ids = len(ids)
|
| 892 |
+
|
| 893 |
+
# Load from model defaults
|
| 894 |
+
if return_attention_mask is None:
|
| 895 |
+
return_attention_mask = "attention_mask" in self.model_input_names
|
| 896 |
+
|
| 897 |
+
encoded_inputs = {}
|
| 898 |
+
|
| 899 |
+
# Truncation: Handle max sequence length
|
| 900 |
+
overflowing_tokens = []
|
| 901 |
+
if truncation_strategy != TruncationStrategy.DO_NOT_TRUNCATE and max_length and len_ids > max_length:
|
| 902 |
+
ids, _, overflowing_tokens = self.truncate_sequences(
|
| 903 |
+
ids,
|
| 904 |
+
num_tokens_to_remove=len_ids - max_length,
|
| 905 |
+
truncation_strategy=truncation_strategy,
|
| 906 |
+
stride=stride,
|
| 907 |
+
)
|
| 908 |
+
|
| 909 |
+
if return_overflowing_tokens:
|
| 910 |
+
encoded_inputs["overflowing_tokens"] = overflowing_tokens
|
| 911 |
+
encoded_inputs["num_truncated_tokens"] = len_ids - max_length
|
| 912 |
+
|
| 913 |
+
# Build output dictionary
|
| 914 |
+
encoded_inputs[self.model_input_names[0]] = ids
|
| 915 |
+
if return_special_tokens_mask:
|
| 916 |
+
if add_special_tokens:
|
| 917 |
+
encoded_inputs["special_tokens_mask"] = self.get_special_tokens_mask(ids, None)
|
| 918 |
+
else:
|
| 919 |
+
encoded_inputs["special_tokens_mask"] = [0] * len(ids)
|
| 920 |
+
|
| 921 |
+
# Padding
|
| 922 |
+
if padding_strategy != PaddingStrategy.DO_NOT_PAD or return_attention_mask:
|
| 923 |
+
encoded_inputs = self.pad(
|
| 924 |
+
encoded_inputs,
|
| 925 |
+
max_length=max_length,
|
| 926 |
+
padding=padding_strategy.value,
|
| 927 |
+
pad_to_multiple_of=pad_to_multiple_of,
|
| 928 |
+
padding_side=padding_side,
|
| 929 |
+
return_attention_mask=return_attention_mask,
|
| 930 |
+
)
|
| 931 |
+
|
| 932 |
+
if return_length:
|
| 933 |
+
encoded_inputs["length"] = len(encoded_inputs["input_ids"])
|
| 934 |
+
|
| 935 |
+
batch_outputs = BatchEncoding(
|
| 936 |
+
encoded_inputs, tensor_type=return_tensors, prepend_batch_axis=prepend_batch_axis
|
| 937 |
+
)
|
| 938 |
+
|
| 939 |
+
return batch_outputs
|
| 940 |
+
|
| 941 |
+
def _get_padding_truncation_strategies(
|
| 942 |
+
self,
|
| 943 |
+
padding: Union[str, PaddingStrategy, bool] = False,
|
| 944 |
+
truncation: Optional[Union[str, TruncationStrategy, bool]] = None,
|
| 945 |
+
max_length: Optional[int] = None,
|
| 946 |
+
pad_to_multiple_of: Optional[int] = None,
|
| 947 |
+
verbose: bool = True,
|
| 948 |
+
**kwargs,
|
| 949 |
+
):
|
| 950 |
+
"""
|
| 951 |
+
Find the correct padding/truncation strategy.
|
| 952 |
+
"""
|
| 953 |
+
|
| 954 |
+
# Backward compatibility for previous behavior, maybe we should deprecate it:
|
| 955 |
+
# If you only set max_length, it activates truncation for max_length
|
| 956 |
+
if max_length is not None and padding is False and truncation is None:
|
| 957 |
+
if verbose:
|
| 958 |
+
if not self.deprecation_warnings.get("Truncation-not-explicitly-activated", False):
|
| 959 |
+
logger.warning(
|
| 960 |
+
"Truncation was not explicitly activated but `max_length` is provided a specific value, please"
|
| 961 |
+
" use `truncation=True` to explicitly truncate examples to max length. Defaulting to"
|
| 962 |
+
" 'longest_first' truncation strategy. If you encode pairs of sequences (GLUE-style) with the"
|
| 963 |
+
" tokenizer you can select this strategy more precisely by providing a specific strategy to"
|
| 964 |
+
" `truncation`."
|
| 965 |
+
)
|
| 966 |
+
self.deprecation_warnings["Truncation-not-explicitly-activated"] = True
|
| 967 |
+
truncation = "longest_first"
|
| 968 |
+
|
| 969 |
+
# Get padding strategy
|
| 970 |
+
if padding is not False:
|
| 971 |
+
if padding is True:
|
| 972 |
+
if verbose:
|
| 973 |
+
if max_length is not None and (
|
| 974 |
+
truncation is None or truncation is False or truncation == "do_not_truncate"
|
| 975 |
+
):
|
| 976 |
+
warnings.warn(
|
| 977 |
+
"`max_length` is ignored when `padding`=`True` and there is no truncation strategy. "
|
| 978 |
+
"To pad to max length, use `padding='max_length'`."
|
| 979 |
+
)
|
| 980 |
+
padding_strategy = PaddingStrategy.LONGEST # Default to pad to the longest sequence in the batch
|
| 981 |
+
elif not isinstance(padding, PaddingStrategy):
|
| 982 |
+
padding_strategy = PaddingStrategy(padding)
|
| 983 |
+
elif isinstance(padding, PaddingStrategy):
|
| 984 |
+
padding_strategy = padding
|
| 985 |
+
else:
|
| 986 |
+
padding_strategy = PaddingStrategy.DO_NOT_PAD
|
| 987 |
+
|
| 988 |
+
# Get truncation strategy
|
| 989 |
+
if truncation is not False and truncation is not None:
|
| 990 |
+
if truncation is True:
|
| 991 |
+
truncation_strategy = (
|
| 992 |
+
TruncationStrategy.LONGEST_FIRST
|
| 993 |
+
) # Default to truncate the longest sequences in pairs of inputs
|
| 994 |
+
elif not isinstance(truncation, TruncationStrategy):
|
| 995 |
+
truncation_strategy = TruncationStrategy(truncation)
|
| 996 |
+
elif isinstance(truncation, TruncationStrategy):
|
| 997 |
+
truncation_strategy = truncation
|
| 998 |
+
if truncation in [TruncationStrategy.ONLY_FIRST, TruncationStrategy.ONLY_SECOND]:
|
| 999 |
+
raise ValueError(
|
| 1000 |
+
"Truncation strategy `only_first` and `only_second` are not supported by `MistralCommonTokenizer`."
|
| 1001 |
+
)
|
| 1002 |
+
else:
|
| 1003 |
+
truncation_strategy = TruncationStrategy.DO_NOT_TRUNCATE
|
| 1004 |
+
|
| 1005 |
+
# Set max length if needed
|
| 1006 |
+
if max_length is None:
|
| 1007 |
+
if padding_strategy == PaddingStrategy.MAX_LENGTH:
|
| 1008 |
+
if self.model_max_length > LARGE_INTEGER:
|
| 1009 |
+
if verbose:
|
| 1010 |
+
if not self.deprecation_warnings.get("Asking-to-pad-to-max_length", False):
|
| 1011 |
+
logger.warning(
|
| 1012 |
+
"Asking to pad to max_length but no maximum length is provided and the model has no"
|
| 1013 |
+
" predefined maximum length. Default to no padding."
|
| 1014 |
+
)
|
| 1015 |
+
self.deprecation_warnings["Asking-to-pad-to-max_length"] = True
|
| 1016 |
+
padding_strategy = PaddingStrategy.DO_NOT_PAD
|
| 1017 |
+
else:
|
| 1018 |
+
max_length = self.model_max_length
|
| 1019 |
+
|
| 1020 |
+
if truncation_strategy != TruncationStrategy.DO_NOT_TRUNCATE:
|
| 1021 |
+
if self.model_max_length > LARGE_INTEGER:
|
| 1022 |
+
if verbose:
|
| 1023 |
+
if not self.deprecation_warnings.get("Asking-to-truncate-to-max_length", False):
|
| 1024 |
+
logger.warning(
|
| 1025 |
+
"Asking to truncate to max_length but no maximum length is provided and the model has"
|
| 1026 |
+
" no predefined maximum length. Default to no truncation."
|
| 1027 |
+
)
|
| 1028 |
+
self.deprecation_warnings["Asking-to-truncate-to-max_length"] = True
|
| 1029 |
+
truncation_strategy = TruncationStrategy.DO_NOT_TRUNCATE
|
| 1030 |
+
else:
|
| 1031 |
+
max_length = self.model_max_length
|
| 1032 |
+
|
| 1033 |
+
# Test if we have a padding token
|
| 1034 |
+
if padding_strategy != PaddingStrategy.DO_NOT_PAD and (self.pad_token is None or self.pad_token_id < 0):
|
| 1035 |
+
raise ValueError(
|
| 1036 |
+
"Asking to pad but the tokenizer does not have a padding token. "
|
| 1037 |
+
"Please select a token to use as `pad_token` `(tokenizer.pad_token = tokenizer.eos_token e.g.)` "
|
| 1038 |
+
"or add a new pad token via `tokenizer.add_special_tokens({'pad_token': '[PAD]'})`."
|
| 1039 |
+
)
|
| 1040 |
+
|
| 1041 |
+
# Check that we will truncate to a multiple of pad_to_multiple_of if both are provided
|
| 1042 |
+
if (
|
| 1043 |
+
truncation_strategy != TruncationStrategy.DO_NOT_TRUNCATE
|
| 1044 |
+
and padding_strategy != PaddingStrategy.DO_NOT_PAD
|
| 1045 |
+
and pad_to_multiple_of is not None
|
| 1046 |
+
and max_length is not None
|
| 1047 |
+
and (max_length % pad_to_multiple_of != 0)
|
| 1048 |
+
):
|
| 1049 |
+
raise ValueError(
|
| 1050 |
+
"Truncation and padding are both activated but "
|
| 1051 |
+
f"truncation length ({max_length}) is not a multiple of pad_to_multiple_of ({pad_to_multiple_of})."
|
| 1052 |
+
)
|
| 1053 |
+
|
| 1054 |
+
return padding_strategy, truncation_strategy, max_length, kwargs
|
| 1055 |
+
|
| 1056 |
+
def _pad(
|
| 1057 |
+
self,
|
| 1058 |
+
encoded_inputs: Union[dict[str, EncodedInput], BatchEncoding],
|
| 1059 |
+
max_length: Optional[int] = None,
|
| 1060 |
+
padding_strategy: PaddingStrategy = PaddingStrategy.DO_NOT_PAD,
|
| 1061 |
+
pad_to_multiple_of: Optional[int] = None,
|
| 1062 |
+
padding_side: Optional[str] = None,
|
| 1063 |
+
return_attention_mask: Optional[bool] = None,
|
| 1064 |
+
) -> dict:
|
| 1065 |
+
"""
|
| 1066 |
+
Pad encoded inputs (on left/right and up to predefined length or max length in the batch)
|
| 1067 |
+
|
| 1068 |
+
Args:
|
| 1069 |
+
encoded_inputs:
|
| 1070 |
+
Dictionary of tokenized inputs (`List[int]`) or batch of tokenized inputs (`List[List[int]]`).
|
| 1071 |
+
max_length: maximum length of the returned list and optionally padding length (see below).
|
| 1072 |
+
Will truncate by taking into account the special tokens.
|
| 1073 |
+
padding_strategy: PaddingStrategy to use for padding.
|
| 1074 |
+
|
| 1075 |
+
- PaddingStrategy.LONGEST Pad to the longest sequence in the batch
|
| 1076 |
+
- PaddingStrategy.MAX_LENGTH: Pad to the max length (default)
|
| 1077 |
+
- PaddingStrategy.DO_NOT_PAD: Do not pad
|
| 1078 |
+
The tokenizer padding sides are defined in `padding_side` argument:
|
| 1079 |
+
|
| 1080 |
+
- 'left': pads on the left of the sequences
|
| 1081 |
+
- 'right': pads on the right of the sequences
|
| 1082 |
+
pad_to_multiple_of: (optional) Integer if set will pad the sequence to a multiple of the provided value.
|
| 1083 |
+
This is especially useful to enable the use of Tensor Core on NVIDIA hardware with compute capability
|
| 1084 |
+
`>= 7.5` (Volta).
|
| 1085 |
+
padding_side:
|
| 1086 |
+
The side on which the model should have padding applied. Should be selected between ['right', 'left'].
|
| 1087 |
+
Default value is picked from the class attribute of the same name.
|
| 1088 |
+
return_attention_mask:
|
| 1089 |
+
(optional) Set to False to avoid returning attention mask (default: set to model specifics)
|
| 1090 |
+
"""
|
| 1091 |
+
# Load from model defaults
|
| 1092 |
+
if return_attention_mask is None:
|
| 1093 |
+
return_attention_mask = "attention_mask" in self.model_input_names
|
| 1094 |
+
|
| 1095 |
+
required_input = encoded_inputs[self.model_input_names[0]]
|
| 1096 |
+
|
| 1097 |
+
if padding_strategy == PaddingStrategy.LONGEST:
|
| 1098 |
+
max_length = len(required_input)
|
| 1099 |
+
|
| 1100 |
+
if max_length is not None and pad_to_multiple_of is not None and (max_length % pad_to_multiple_of != 0):
|
| 1101 |
+
max_length = ((max_length // pad_to_multiple_of) + 1) * pad_to_multiple_of
|
| 1102 |
+
|
| 1103 |
+
needs_to_be_padded = padding_strategy != PaddingStrategy.DO_NOT_PAD and len(required_input) != max_length
|
| 1104 |
+
|
| 1105 |
+
# Initialize attention mask if not present.
|
| 1106 |
+
if return_attention_mask and "attention_mask" not in encoded_inputs:
|
| 1107 |
+
encoded_inputs["attention_mask"] = [1] * len(required_input)
|
| 1108 |
+
|
| 1109 |
+
if needs_to_be_padded:
|
| 1110 |
+
difference = max_length - len(required_input)
|
| 1111 |
+
padding_side = padding_side if padding_side is not None else self.padding_side
|
| 1112 |
+
|
| 1113 |
+
if padding_side == "right":
|
| 1114 |
+
if return_attention_mask:
|
| 1115 |
+
encoded_inputs["attention_mask"] = encoded_inputs["attention_mask"] + [0] * difference
|
| 1116 |
+
if "special_tokens_mask" in encoded_inputs:
|
| 1117 |
+
encoded_inputs["special_tokens_mask"] = encoded_inputs["special_tokens_mask"] + [1] * difference
|
| 1118 |
+
encoded_inputs[self.model_input_names[0]] = required_input + [self.pad_token_id] * difference
|
| 1119 |
+
elif padding_side == "left":
|
| 1120 |
+
if return_attention_mask:
|
| 1121 |
+
encoded_inputs["attention_mask"] = [0] * difference + encoded_inputs["attention_mask"]
|
| 1122 |
+
if "special_tokens_mask" in encoded_inputs:
|
| 1123 |
+
encoded_inputs["special_tokens_mask"] = [1] * difference + encoded_inputs["special_tokens_mask"]
|
| 1124 |
+
encoded_inputs[self.model_input_names[0]] = [self.pad_token_id] * difference + required_input
|
| 1125 |
+
else:
|
| 1126 |
+
raise ValueError(f"Invalid padding strategy:{padding_side}")
|
| 1127 |
+
|
| 1128 |
+
return encoded_inputs
|
| 1129 |
+
|
| 1130 |
+
def pad(
|
| 1131 |
+
self,
|
| 1132 |
+
encoded_inputs: Union[
|
| 1133 |
+
BatchEncoding,
|
| 1134 |
+
list[BatchEncoding],
|
| 1135 |
+
dict[str, EncodedInput],
|
| 1136 |
+
dict[str, list[EncodedInput]],
|
| 1137 |
+
list[dict[str, EncodedInput]],
|
| 1138 |
+
],
|
| 1139 |
+
padding: Union[bool, str, PaddingStrategy] = True,
|
| 1140 |
+
max_length: Optional[int] = None,
|
| 1141 |
+
pad_to_multiple_of: Optional[int] = None,
|
| 1142 |
+
padding_side: Optional[str] = None,
|
| 1143 |
+
return_attention_mask: Optional[bool] = None,
|
| 1144 |
+
return_tensors: Optional[Union[str, TensorType]] = None,
|
| 1145 |
+
verbose: bool = True,
|
| 1146 |
+
) -> BatchEncoding:
|
| 1147 |
+
"""
|
| 1148 |
+
Pad a single encoded input or a batch of encoded inputs up to predefined length or to the max sequence length
|
| 1149 |
+
in the batch.
|
| 1150 |
+
|
| 1151 |
+
Padding side (left/right) padding token ids are defined at the tokenizer level (with `self.padding_side`,
|
| 1152 |
+
`self.pad_token_id`).
|
| 1153 |
+
<Tip>
|
| 1154 |
+
|
| 1155 |
+
If the `encoded_inputs` passed are dictionary of numpy arrays, PyTorch tensors, the
|
| 1156 |
+
result will use the same type unless you provide a different tensor type with `return_tensors`. In the case of
|
| 1157 |
+
PyTorch tensors, you will lose the specific device of your tensors however.
|
| 1158 |
+
|
| 1159 |
+
</Tip>
|
| 1160 |
+
|
| 1161 |
+
Args:
|
| 1162 |
+
encoded_inputs ([`BatchEncoding`], list of [`BatchEncoding`], `Dict[str, List[int]]`, `Dict[str, List[List[int]]` or `List[Dict[str, List[int]]]`):
|
| 1163 |
+
Tokenized inputs. Can represent one input ([`BatchEncoding`] or `Dict[str, List[int]]`) or a batch of
|
| 1164 |
+
tokenized inputs (list of [`BatchEncoding`], *Dict[str, List[List[int]]]* or *List[Dict[str,
|
| 1165 |
+
List[int]]]*) so you can use this method during preprocessing as well as in a PyTorch Dataloader
|
| 1166 |
+
collate function.
|
| 1167 |
+
|
| 1168 |
+
Instead of `List[int]` you can have tensors (numpy arrays, PyTorch tensors), see
|
| 1169 |
+
the note above for the return type.
|
| 1170 |
+
padding (`bool`, `str` or [`~utils.PaddingStrategy`], *optional*, defaults to `True`):
|
| 1171 |
+
Select a strategy to pad the returned sequences (according to the model's padding side and padding
|
| 1172 |
+
index) among:
|
| 1173 |
+
|
| 1174 |
+
- `True` or `'longest'` (default): Pad to the longest sequence in the batch (or no padding if only a single
|
| 1175 |
+
sequence if provided).
|
| 1176 |
+
- `'max_length'`: Pad to a maximum length specified with the argument `max_length` or to the maximum
|
| 1177 |
+
acceptable input length for the model if that argument is not provided.
|
| 1178 |
+
- `False` or `'do_not_pad'`: No padding (i.e., can output a batch with sequences of different
|
| 1179 |
+
lengths).
|
| 1180 |
+
max_length (`int`, *optional*):
|
| 1181 |
+
Maximum length of the returned list and optionally padding length (see above).
|
| 1182 |
+
pad_to_multiple_of (`int`, *optional*):
|
| 1183 |
+
If set will pad the sequence to a multiple of the provided value.
|
| 1184 |
+
|
| 1185 |
+
This is especially useful to enable the use of Tensor Cores on NVIDIA hardware with compute capability
|
| 1186 |
+
`>= 7.5` (Volta).
|
| 1187 |
+
padding_side (`str`, *optional*):
|
| 1188 |
+
The side on which the model should have padding applied. Should be selected between ['right', 'left'].
|
| 1189 |
+
Default value is picked from the class attribute of the same name.
|
| 1190 |
+
return_attention_mask (`bool`, *optional*):
|
| 1191 |
+
Whether to return the attention mask. If left to the default, will return the attention mask according
|
| 1192 |
+
to the specific tokenizer's default, defined by the `return_outputs` attribute.
|
| 1193 |
+
|
| 1194 |
+
[What are attention masks?](../glossary#attention-mask)
|
| 1195 |
+
return_tensors (`str` or [`~utils.TensorType`], *optional*):
|
| 1196 |
+
If set, will return tensors instead of list of python integers. Acceptable values are:
|
| 1197 |
+
|
| 1198 |
+
- `'pt'`: Return PyTorch `torch.Tensor` objects.
|
| 1199 |
+
- `'np'`: Return Numpy `np.ndarray` objects.
|
| 1200 |
+
verbose (`bool`, *optional*, defaults to `True`):
|
| 1201 |
+
Whether or not to print more information and warnings.
|
| 1202 |
+
"""
|
| 1203 |
+
# If we have a list of dicts, let's convert it in a dict of lists
|
| 1204 |
+
# We do this to allow using this method as a collate_fn function in PyTorch Dataloader
|
| 1205 |
+
if isinstance(encoded_inputs, (list, tuple)) and isinstance(encoded_inputs[0], Mapping):
|
| 1206 |
+
encoded_inputs = {key: [example[key] for example in encoded_inputs] for key in encoded_inputs[0]}
|
| 1207 |
+
|
| 1208 |
+
# The model's main input name, usually `input_ids`, has been passed for padding
|
| 1209 |
+
if self.model_input_names[0] not in encoded_inputs:
|
| 1210 |
+
raise ValueError(
|
| 1211 |
+
"You should supply an encoding or a list of encodings to this method "
|
| 1212 |
+
f"that includes {self.model_input_names[0]}, but you provided {list(encoded_inputs.keys())}"
|
| 1213 |
+
)
|
| 1214 |
+
|
| 1215 |
+
required_input = encoded_inputs[self.model_input_names[0]]
|
| 1216 |
+
|
| 1217 |
+
if required_input is None or (isinstance(required_input, Sized) and len(required_input) == 0):
|
| 1218 |
+
if return_attention_mask:
|
| 1219 |
+
encoded_inputs["attention_mask"] = []
|
| 1220 |
+
return encoded_inputs
|
| 1221 |
+
|
| 1222 |
+
# If we have PyTorch/TF/NumPy tensors/arrays as inputs, we cast them as python objects
|
| 1223 |
+
# and rebuild them afterwards if no return_tensors is specified
|
| 1224 |
+
# Note that we lose the specific device the tensor may be on for PyTorch
|
| 1225 |
+
|
| 1226 |
+
first_element = required_input[0]
|
| 1227 |
+
if isinstance(first_element, (list, tuple)):
|
| 1228 |
+
# first_element might be an empty list/tuple in some edge cases so we grab the first non empty element.
|
| 1229 |
+
for item in required_input:
|
| 1230 |
+
if len(item) != 0:
|
| 1231 |
+
first_element = item[0]
|
| 1232 |
+
break
|
| 1233 |
+
# At this state, if `first_element` is still a list/tuple, it's an empty one so there is nothing to do.
|
| 1234 |
+
if not isinstance(first_element, (int, list, tuple)):
|
| 1235 |
+
if is_torch_tensor(first_element):
|
| 1236 |
+
return_tensors = "pt" if return_tensors is None else return_tensors
|
| 1237 |
+
elif isinstance(first_element, np.ndarray):
|
| 1238 |
+
return_tensors = "np" if return_tensors is None else return_tensors
|
| 1239 |
+
else:
|
| 1240 |
+
raise ValueError(
|
| 1241 |
+
f"type of {first_element} unknown: {type(first_element)}. "
|
| 1242 |
+
"Should be one of a python, numpy, pytorch or tensorflow object."
|
| 1243 |
+
)
|
| 1244 |
+
|
| 1245 |
+
for key, value in encoded_inputs.items():
|
| 1246 |
+
encoded_inputs[key] = to_py_obj(value)
|
| 1247 |
+
|
| 1248 |
+
# Convert padding_strategy in PaddingStrategy
|
| 1249 |
+
padding_strategy, _, max_length, _ = self._get_padding_truncation_strategies(
|
| 1250 |
+
padding=padding, max_length=max_length, verbose=verbose
|
| 1251 |
+
)
|
| 1252 |
+
|
| 1253 |
+
required_input = encoded_inputs[self.model_input_names[0]]
|
| 1254 |
+
if required_input and not isinstance(required_input[0], (list, tuple)):
|
| 1255 |
+
encoded_inputs = self._pad(
|
| 1256 |
+
encoded_inputs,
|
| 1257 |
+
max_length=max_length,
|
| 1258 |
+
padding_strategy=padding_strategy,
|
| 1259 |
+
pad_to_multiple_of=pad_to_multiple_of,
|
| 1260 |
+
padding_side=padding_side,
|
| 1261 |
+
return_attention_mask=return_attention_mask,
|
| 1262 |
+
)
|
| 1263 |
+
return BatchEncoding(encoded_inputs, tensor_type=return_tensors)
|
| 1264 |
+
|
| 1265 |
+
batch_size = len(required_input)
|
| 1266 |
+
assert all(len(v) == batch_size for v in encoded_inputs.values()), (
|
| 1267 |
+
"Some items in the output dictionary have a different batch size than others."
|
| 1268 |
+
)
|
| 1269 |
+
|
| 1270 |
+
if padding_strategy == PaddingStrategy.LONGEST:
|
| 1271 |
+
max_length = max(len(inputs) for inputs in required_input)
|
| 1272 |
+
padding_strategy = PaddingStrategy.MAX_LENGTH
|
| 1273 |
+
|
| 1274 |
+
batch_outputs = {}
|
| 1275 |
+
for i in range(batch_size):
|
| 1276 |
+
inputs = {k: v[i] for k, v in encoded_inputs.items()}
|
| 1277 |
+
outputs = self._pad(
|
| 1278 |
+
inputs,
|
| 1279 |
+
max_length=max_length,
|
| 1280 |
+
padding_strategy=padding_strategy,
|
| 1281 |
+
pad_to_multiple_of=pad_to_multiple_of,
|
| 1282 |
+
padding_side=padding_side,
|
| 1283 |
+
return_attention_mask=return_attention_mask,
|
| 1284 |
+
)
|
| 1285 |
+
|
| 1286 |
+
for key, value in outputs.items():
|
| 1287 |
+
if key not in batch_outputs:
|
| 1288 |
+
batch_outputs[key] = []
|
| 1289 |
+
batch_outputs[key].append(value)
|
| 1290 |
+
|
| 1291 |
+
return BatchEncoding(batch_outputs, tensor_type=return_tensors)
|
| 1292 |
+
|
| 1293 |
+
def truncate_sequences(
|
| 1294 |
+
self,
|
| 1295 |
+
ids: list[int],
|
| 1296 |
+
pair_ids: None = None,
|
| 1297 |
+
num_tokens_to_remove: int = 0,
|
| 1298 |
+
truncation_strategy: Union[str, TruncationStrategy] = "longest_first",
|
| 1299 |
+
stride: int = 0,
|
| 1300 |
+
**kwargs,
|
| 1301 |
+
) -> tuple[list[int], None, list[int]]:
|
| 1302 |
+
"""
|
| 1303 |
+
Truncates a sequence pair in-place following the strategy.
|
| 1304 |
+
|
| 1305 |
+
Args:
|
| 1306 |
+
ids (`List[int]`):
|
| 1307 |
+
Tokenized input ids. Can be obtained from a string by chaining the `tokenize` and
|
| 1308 |
+
`convert_tokens_to_ids` methods.
|
| 1309 |
+
pair_ids (`None`, *optional*):
|
| 1310 |
+
Not supported by `MistralCommonTokenizer`. Kept to match the signature of `PreTrainedTokenizerBase.truncate_sequences`.
|
| 1311 |
+
num_tokens_to_remove (`int`, *optional*, defaults to 0):
|
| 1312 |
+
Number of tokens to remove using the truncation strategy.
|
| 1313 |
+
truncation_strategy (`str` or [`~tokenization_utils_base.TruncationStrategy`], *optional*, defaults to `'longest_first'`):
|
| 1314 |
+
The strategy to follow for truncation. Can be:
|
| 1315 |
+
|
| 1316 |
+
- `'longest_first'`: Truncate to a maximum length specified with the argument `max_length` or to the
|
| 1317 |
+
maximum acceptable input length for the model if that argument is not provided.
|
| 1318 |
+
- `'do_not_truncate'` (default): No truncation (i.e., can output batch with sequence lengths greater
|
| 1319 |
+
than the model maximum admissible input size).
|
| 1320 |
+
stride (`int`, *optional*, defaults to 0):
|
| 1321 |
+
If set to a positive number, the overflowing tokens returned will contain some tokens from the main
|
| 1322 |
+
sequence returned. The value of this argument defines the number of additional tokens.
|
| 1323 |
+
|
| 1324 |
+
Returns:
|
| 1325 |
+
`Tuple[List[int], None, List[int]]`: The truncated `ids` and the list of
|
| 1326 |
+
overflowing tokens. `None` is returned to match Transformers signature.
|
| 1327 |
+
"""
|
| 1328 |
+
if kwargs:
|
| 1329 |
+
raise ValueError(
|
| 1330 |
+
f"Kwargs {list(kwargs.keys())} are not supported by `MistralCommonTokenizer.truncate_sequences`."
|
| 1331 |
+
)
|
| 1332 |
+
if pair_ids:
|
| 1333 |
+
raise ValueError("`pair_ids` is not supported by `MistralCommonTokenizer.truncate_sequences`.")
|
| 1334 |
+
|
| 1335 |
+
if num_tokens_to_remove <= 0:
|
| 1336 |
+
return (ids, None, [])
|
| 1337 |
+
|
| 1338 |
+
if not isinstance(truncation_strategy, TruncationStrategy):
|
| 1339 |
+
truncation_strategy = TruncationStrategy(truncation_strategy)
|
| 1340 |
+
|
| 1341 |
+
if truncation_strategy in [TruncationStrategy.ONLY_FIRST, TruncationStrategy.ONLY_SECOND]:
|
| 1342 |
+
raise ValueError(
|
| 1343 |
+
f"Only {TruncationStrategy.LONGEST_FIRST} and {TruncationStrategy.DO_NOT_TRUNCATE} are supported."
|
| 1344 |
+
)
|
| 1345 |
+
|
| 1346 |
+
overflowing_tokens = []
|
| 1347 |
+
if truncation_strategy == TruncationStrategy.LONGEST_FIRST:
|
| 1348 |
+
if len(ids) > num_tokens_to_remove:
|
| 1349 |
+
window_len = min(len(ids), stride + num_tokens_to_remove)
|
| 1350 |
+
if self.truncation_side == "left":
|
| 1351 |
+
overflowing_tokens = ids[:window_len]
|
| 1352 |
+
ids = ids[num_tokens_to_remove:]
|
| 1353 |
+
elif self.truncation_side == "right":
|
| 1354 |
+
overflowing_tokens = ids[-window_len:]
|
| 1355 |
+
ids = ids[:-num_tokens_to_remove]
|
| 1356 |
+
else:
|
| 1357 |
+
raise ValueError(f"invalid truncation strategy: {self.truncation_side}, use 'left' or 'right'.")
|
| 1358 |
+
|
| 1359 |
+
else:
|
| 1360 |
+
error_msg = (
|
| 1361 |
+
f"We need to remove {num_tokens_to_remove} to truncate the input "
|
| 1362 |
+
f"but the first sequence has a length {len(ids)}. "
|
| 1363 |
+
)
|
| 1364 |
+
logger.error(error_msg)
|
| 1365 |
+
|
| 1366 |
+
return (ids, None, overflowing_tokens)
|
| 1367 |
+
|
| 1368 |
+
def apply_chat_template(
|
| 1369 |
+
self,
|
| 1370 |
+
conversation: Union[list[dict[str, str]], list[list[dict[str, str]]]],
|
| 1371 |
+
tools: Optional[list[Union[dict, Callable]]] = None,
|
| 1372 |
+
continue_final_message: bool = False,
|
| 1373 |
+
tokenize: bool = True,
|
| 1374 |
+
padding: Union[bool, str, PaddingStrategy] = False,
|
| 1375 |
+
truncation: bool = False,
|
| 1376 |
+
max_length: Optional[int] = None,
|
| 1377 |
+
return_tensors: Optional[Union[str, TensorType]] = None,
|
| 1378 |
+
return_dict: bool = False,
|
| 1379 |
+
**kwargs,
|
| 1380 |
+
) -> Union[str, list[int], list[str], list[list[int]], BatchEncoding]:
|
| 1381 |
+
"""
|
| 1382 |
+
Converts a list of dictionaries with `"role"` and `"content"` keys to a list of token
|
| 1383 |
+
ids.
|
| 1384 |
+
|
| 1385 |
+
Args:
|
| 1386 |
+
conversation (Union[List[Dict[str, str]], List[List[Dict[str, str]]]]): A list of dicts
|
| 1387 |
+
with "role" and "content" keys, representing the chat history so far.
|
| 1388 |
+
tools (`List[Union[Dict, Callable]]`, *optional*):
|
| 1389 |
+
A list of tools (callable functions) that will be accessible to the model. If the template does not
|
| 1390 |
+
support function calling, this argument will have no effect. Each tool should be passed as a JSON Schema,
|
| 1391 |
+
giving the name, description and argument types for the tool. See our
|
| 1392 |
+
[chat templating guide](https://huggingface.co/docs/transformers/main/en/chat_templating#automated-function-conversion-for-tool-use)
|
| 1393 |
+
for more information.
|
| 1394 |
+
continue_final_message (bool, *optional*):
|
| 1395 |
+
If this is set, the chat will be formatted so that the final
|
| 1396 |
+
message in the chat is open-ended, without any EOS tokens. The model will continue this message
|
| 1397 |
+
rather than starting a new one. This allows you to "prefill" part of
|
| 1398 |
+
the model's response for it. Cannot be used at the same time as `add_generation_prompt`.
|
| 1399 |
+
tokenize (`bool`, defaults to `True`):
|
| 1400 |
+
Whether to tokenize the output. If `False`, the output will be a string.
|
| 1401 |
+
padding (`bool`, `str` or [`~utils.PaddingStrategy`], *optional*, defaults to `False`):
|
| 1402 |
+
Select a strategy to pad the returned sequences (according to the model's padding side and padding
|
| 1403 |
+
index) among:
|
| 1404 |
+
|
| 1405 |
+
- `True` or `'longest'`: Pad to the longest sequence in the batch (or no padding if only a single
|
| 1406 |
+
sequence if provided).
|
| 1407 |
+
- `'max_length'`: Pad to a maximum length specified with the argument `max_length` or to the maximum
|
| 1408 |
+
acceptable input length for the model if that argument is not provided.
|
| 1409 |
+
- `False` or `'do_not_pad'` (default): No padding (i.e., can output a batch with sequences of different
|
| 1410 |
+
lengths).
|
| 1411 |
+
truncation (`bool`, defaults to `False`):
|
| 1412 |
+
Whether to truncate sequences at the maximum length. Has no effect if tokenize is `False`.
|
| 1413 |
+
max_length (`int`, *optional*):
|
| 1414 |
+
Maximum length (in tokens) to use for padding or truncation. Has no effect if tokenize is `False`. If
|
| 1415 |
+
not specified, the tokenizer's `max_length` attribute will be used as a default.
|
| 1416 |
+
return_tensors (`str` or [`~utils.TensorType`], *optional*):
|
| 1417 |
+
If set, will return tensors of a particular framework. Has no effect if tokenize is `False`. Acceptable
|
| 1418 |
+
values are:
|
| 1419 |
+
- `'pt'`: Return PyTorch `torch.Tensor` objects.
|
| 1420 |
+
return_dict (`bool`, defaults to `False`):
|
| 1421 |
+
Whether to return a dictionary with named outputs. Has no effect if tokenize is `False`.
|
| 1422 |
+
If at least one conversation contains an image, its pixel values will be returned in the `pixel_values` key.
|
| 1423 |
+
kwargs (additional keyword arguments, *optional*):
|
| 1424 |
+
Not supported by `MistralCommonTokenizer.apply_chat_template`.
|
| 1425 |
+
Will raise an error if used.
|
| 1426 |
+
|
| 1427 |
+
Returns:
|
| 1428 |
+
`Union[str, List[int], List[str], List[List[int]], BatchEncoding]`: A list of token ids representing the tokenized chat so far, including control
|
| 1429 |
+
tokens. This output is ready to pass to the model, either directly or via methods like `generate()`.
|
| 1430 |
+
"""
|
| 1431 |
+
if kwargs:
|
| 1432 |
+
raise ValueError(
|
| 1433 |
+
f"Kwargs {list(kwargs.keys())} are not supported by `MistralCommonTokenizer.apply_chat_template`."
|
| 1434 |
+
)
|
| 1435 |
+
if not isinstance(truncation, bool):
|
| 1436 |
+
raise ValueError("`truncation` must be a boolean for `apply_chat_template` method.")
|
| 1437 |
+
|
| 1438 |
+
if isinstance(conversation, (list, tuple)) and (
|
| 1439 |
+
isinstance(conversation[0], (list, tuple)) or hasattr(conversation[0], "messages")
|
| 1440 |
+
):
|
| 1441 |
+
conversations = conversation
|
| 1442 |
+
is_batched = True
|
| 1443 |
+
else:
|
| 1444 |
+
conversations = [conversation]
|
| 1445 |
+
is_batched = False
|
| 1446 |
+
|
| 1447 |
+
def _maybe_adapt_message(message: dict[str, Any]) -> None:
|
| 1448 |
+
"""Adapt message to `mistral-common` format and leave validation to `mistral-common`."""
|
| 1449 |
+
if not isinstance(message, dict):
|
| 1450 |
+
return
|
| 1451 |
+
maybe_list_content: Optional[Union[str, list[dict[str, Union[str, dict[str, Any]]]]]] = message.get(
|
| 1452 |
+
"content"
|
| 1453 |
+
)
|
| 1454 |
+
if not maybe_list_content or isinstance(maybe_list_content, str):
|
| 1455 |
+
return
|
| 1456 |
+
|
| 1457 |
+
normalized_content: list[dict[str, Union[str, dict[str, Any]]]] = []
|
| 1458 |
+
for content in maybe_list_content:
|
| 1459 |
+
content_type = content.get("type", None)
|
| 1460 |
+
if not content_type:
|
| 1461 |
+
continue
|
| 1462 |
+
elif content_type == "image":
|
| 1463 |
+
maybe_url: Optional[str] = content.get("url")
|
| 1464 |
+
maybe_path: Optional[str] = content.get("path")
|
| 1465 |
+
maybe_base64: Optional[str] = content.get("base64")
|
| 1466 |
+
if maybe_url:
|
| 1467 |
+
image_content = maybe_url
|
| 1468 |
+
elif maybe_path:
|
| 1469 |
+
if not maybe_path.startswith("file://"):
|
| 1470 |
+
maybe_path = Path(maybe_path).resolve().as_uri()
|
| 1471 |
+
image_content = maybe_path
|
| 1472 |
+
elif maybe_base64:
|
| 1473 |
+
if not maybe_base64.startswith("data:image"):
|
| 1474 |
+
maybe_base64 = "data:image/unk;base64," + maybe_base64
|
| 1475 |
+
image_content = maybe_base64
|
| 1476 |
+
else:
|
| 1477 |
+
raise ValueError("Image content must be specified.")
|
| 1478 |
+
normalized_content.append({"type": "image_url", "image_url": {"url": image_content}})
|
| 1479 |
+
elif content_type == "audio":
|
| 1480 |
+
maybe_url: Optional[str] = content.get("url")
|
| 1481 |
+
maybe_path: Optional[str] = content.get("path")
|
| 1482 |
+
maybe_base64: Optional[str] = content.get("base64")
|
| 1483 |
+
if maybe_url or maybe_path:
|
| 1484 |
+
audio_data = load_audio_as(maybe_url or maybe_path, return_format="dict", force_mono=True)
|
| 1485 |
+
normalized_content.append({"type": "input_audio", "input_audio": audio_data})
|
| 1486 |
+
continue
|
| 1487 |
+
if not maybe_base64:
|
| 1488 |
+
raise ValueError("Audio content must be specified.")
|
| 1489 |
+
normalized_content.append({"type": "audio_url", "audio_url": {"url": maybe_base64}})
|
| 1490 |
+
else:
|
| 1491 |
+
normalized_content.append(content)
|
| 1492 |
+
message["content"] = normalized_content
|
| 1493 |
+
|
| 1494 |
+
outputs = []
|
| 1495 |
+
images: list[np.ndarray] = []
|
| 1496 |
+
audios: list[np.ndarray] = []
|
| 1497 |
+
|
| 1498 |
+
for conversation in conversations:
|
| 1499 |
+
messages: list[dict[str, Union[str, list[dict[str, Union[str, dict[str, Any]]]]]]] = []
|
| 1500 |
+
for message in conversation:
|
| 1501 |
+
_maybe_adapt_message(message)
|
| 1502 |
+
messages.append(message)
|
| 1503 |
+
|
| 1504 |
+
chat_request = ChatCompletionRequest.from_openai(
|
| 1505 |
+
messages=messages,
|
| 1506 |
+
tools=tools,
|
| 1507 |
+
continue_final_message=continue_final_message,
|
| 1508 |
+
)
|
| 1509 |
+
|
| 1510 |
+
tokenized_request = self.tokenizer.encode_chat_completion(chat_request)
|
| 1511 |
+
if tokenize:
|
| 1512 |
+
outputs.append(tokenized_request.tokens)
|
| 1513 |
+
else:
|
| 1514 |
+
outputs.append(tokenized_request.text)
|
| 1515 |
+
images.extend(tokenized_request.images)
|
| 1516 |
+
audios.extend([el.audio_array for el in tokenized_request.audios])
|
| 1517 |
+
|
| 1518 |
+
if not is_batched:
|
| 1519 |
+
outputs = outputs[0]
|
| 1520 |
+
|
| 1521 |
+
if tokenize:
|
| 1522 |
+
out = self(
|
| 1523 |
+
outputs,
|
| 1524 |
+
padding=padding,
|
| 1525 |
+
truncation=truncation,
|
| 1526 |
+
max_length=max_length,
|
| 1527 |
+
add_special_tokens=False,
|
| 1528 |
+
return_tensors=return_tensors,
|
| 1529 |
+
)
|
| 1530 |
+
if return_dict:
|
| 1531 |
+
if images:
|
| 1532 |
+
pixel_values: Union[list[np.ndarray], np.ndarray, torch.Tensor]
|
| 1533 |
+
if return_tensors == "pt":
|
| 1534 |
+
if not is_torch_available():
|
| 1535 |
+
raise ImportError(
|
| 1536 |
+
"Unable to convert output to PyTorch tensors format, PyTorch is not installed."
|
| 1537 |
+
)
|
| 1538 |
+
|
| 1539 |
+
pixel_values = torch.tensor(images)
|
| 1540 |
+
elif return_tensors == "np":
|
| 1541 |
+
pixel_values = np.array(images)
|
| 1542 |
+
elif return_tensors is None:
|
| 1543 |
+
pixel_values = images
|
| 1544 |
+
else:
|
| 1545 |
+
raise ValueError(f"Unsupported return_tensors type: {return_tensors}")
|
| 1546 |
+
out.data["pixel_values"] = pixel_values
|
| 1547 |
+
if audios:
|
| 1548 |
+
if return_tensors is not None:
|
| 1549 |
+
raise NotImplementedError(
|
| 1550 |
+
"When passing audio content in apply_chat_template, `return_tensors` must be None since we cannot batch the audio inputs. The returned audio will be a list of numpy arrays."
|
| 1551 |
+
)
|
| 1552 |
+
# Transformers convention is audio for plural audio (audio does not take a "s")
|
| 1553 |
+
out.data["audio"] = audios
|
| 1554 |
+
return out
|
| 1555 |
+
else:
|
| 1556 |
+
return out["input_ids"]
|
| 1557 |
+
|
| 1558 |
+
else:
|
| 1559 |
+
logger.warning(
|
| 1560 |
+
"`MistralCommonTokenizer.apply_chat_template(..., tokenize=False)` is unsafe and may lead to unexpected behavior."
|
| 1561 |
+
" Please consider using `tokenize=True` instead and don't encode the output manually."
|
| 1562 |
+
)
|
| 1563 |
+
return outputs
|
| 1564 |
+
|
| 1565 |
+
@add_end_docstrings(ENCODE_KWARGS_DOCSTRING, ENCODE_PLUS_ADDITIONAL_KWARGS_DOCSTRING)
|
| 1566 |
+
def __call__(
|
| 1567 |
+
self,
|
| 1568 |
+
text: Union[TextInput, EncodedInput, list[TextInput], list[EncodedInput], None] = None,
|
| 1569 |
+
text_pair: None = None,
|
| 1570 |
+
text_target: None = None,
|
| 1571 |
+
text_pair_target: None = None,
|
| 1572 |
+
add_special_tokens: bool = True,
|
| 1573 |
+
padding: Union[bool, str, PaddingStrategy] = False,
|
| 1574 |
+
truncation: Union[bool, str, TruncationStrategy, None] = None,
|
| 1575 |
+
max_length: Optional[int] = None,
|
| 1576 |
+
stride: int = 0,
|
| 1577 |
+
pad_to_multiple_of: Optional[int] = None,
|
| 1578 |
+
padding_side: Optional[str] = None,
|
| 1579 |
+
return_tensors: Optional[Union[str, TensorType]] = None,
|
| 1580 |
+
return_attention_mask: Optional[bool] = None,
|
| 1581 |
+
return_overflowing_tokens: bool = False,
|
| 1582 |
+
return_special_tokens_mask: bool = False,
|
| 1583 |
+
return_length: bool = False,
|
| 1584 |
+
verbose: bool = True,
|
| 1585 |
+
**kwargs,
|
| 1586 |
+
) -> BatchEncoding:
|
| 1587 |
+
"""
|
| 1588 |
+
Main method to tokenize and prepare for the model one or several sequence(s) or one or several pair(s) of
|
| 1589 |
+
sequences.
|
| 1590 |
+
|
| 1591 |
+
Args:
|
| 1592 |
+
text (`str`, `List[str]`, `List[List[str]]`, *optional*):
|
| 1593 |
+
The sequence or batch of sequences to be encoded. Each sequence can be a string or a list of int
|
| 1594 |
+
(encoded strings).
|
| 1595 |
+
text_pair (`None`, *optional*):
|
| 1596 |
+
Not supported by `MistralCommonTokenizer`. Kept to match the signature of `PreTrainedTokenizerBase.__call__`.
|
| 1597 |
+
text_target (`None`, *optional*):
|
| 1598 |
+
Not supported by `MistralCommonTokenizer`. Kept to match the signature of `PreTrainedTokenizerBase.__call__`.
|
| 1599 |
+
text_pair_target (`None`, *optional*):
|
| 1600 |
+
Not supported by `MistralCommonTokenizer`. Kept to match the signature of `PreTrainedTokenizerBase.__call__`.
|
| 1601 |
+
"""
|
| 1602 |
+
if kwargs:
|
| 1603 |
+
raise ValueError(f"Kwargs {list(kwargs.keys())} are not supported by `MistralCommonTokenizer.__call__`.")
|
| 1604 |
+
|
| 1605 |
+
if text_pair or text_target or text_pair_target:
|
| 1606 |
+
raise ValueError(
|
| 1607 |
+
"`text_pair`, `text_target` and `text_pair_target` are not supported by `MistralCommonTokenizer`."
|
| 1608 |
+
)
|
| 1609 |
+
|
| 1610 |
+
if return_tensors in ("tf", "jax"):
|
| 1611 |
+
raise ValueError(
|
| 1612 |
+
"`MistralCommonTokenizer` does not support `return_tensors='tf'` or `return_tensors='jax'`."
|
| 1613 |
+
)
|
| 1614 |
+
|
| 1615 |
+
def _is_valid_text_input(t):
|
| 1616 |
+
if isinstance(t, str):
|
| 1617 |
+
# Strings are fine
|
| 1618 |
+
return True
|
| 1619 |
+
elif isinstance(t, (list, tuple)):
|
| 1620 |
+
# List are fine as long as they are...
|
| 1621 |
+
if len(t) == 0:
|
| 1622 |
+
# ... empty
|
| 1623 |
+
return True
|
| 1624 |
+
elif isinstance(t[0], (str, int)):
|
| 1625 |
+
# ... list of strings or int
|
| 1626 |
+
return True
|
| 1627 |
+
elif isinstance(t[0], (list, tuple)):
|
| 1628 |
+
# ... list with an empty list or with a list of strings or with a list of ints
|
| 1629 |
+
return len(t[0]) == 0 or isinstance(t[0][0], (str, int))
|
| 1630 |
+
else:
|
| 1631 |
+
return False
|
| 1632 |
+
else:
|
| 1633 |
+
return False
|
| 1634 |
+
|
| 1635 |
+
if not _is_valid_text_input(text):
|
| 1636 |
+
raise ValueError(
|
| 1637 |
+
"text input must be of type `str` (single example), `List[str]` (batch or single encoded example) "
|
| 1638 |
+
"or `List[List[int]]` (batch of encoded examples)."
|
| 1639 |
+
)
|
| 1640 |
+
|
| 1641 |
+
is_batched = isinstance(text, (list, tuple)) and isinstance(text[0], (str, list, tuple))
|
| 1642 |
+
|
| 1643 |
+
padding_strategy, truncation_strategy, max_length, kwargs = self._get_padding_truncation_strategies(
|
| 1644 |
+
padding=padding,
|
| 1645 |
+
truncation=truncation,
|
| 1646 |
+
max_length=max_length,
|
| 1647 |
+
pad_to_multiple_of=pad_to_multiple_of,
|
| 1648 |
+
verbose=verbose,
|
| 1649 |
+
**kwargs,
|
| 1650 |
+
)
|
| 1651 |
+
|
| 1652 |
+
if is_batched:
|
| 1653 |
+
return self._batch_encode_plus(
|
| 1654 |
+
batch_text=text,
|
| 1655 |
+
add_special_tokens=add_special_tokens,
|
| 1656 |
+
padding_strategy=padding_strategy,
|
| 1657 |
+
truncation_strategy=truncation_strategy,
|
| 1658 |
+
max_length=max_length,
|
| 1659 |
+
stride=stride,
|
| 1660 |
+
pad_to_multiple_of=pad_to_multiple_of,
|
| 1661 |
+
padding_side=padding_side,
|
| 1662 |
+
return_tensors=return_tensors,
|
| 1663 |
+
return_attention_mask=return_attention_mask,
|
| 1664 |
+
return_overflowing_tokens=return_overflowing_tokens,
|
| 1665 |
+
return_special_tokens_mask=return_special_tokens_mask,
|
| 1666 |
+
return_length=return_length,
|
| 1667 |
+
verbose=verbose,
|
| 1668 |
+
**kwargs,
|
| 1669 |
+
)
|
| 1670 |
+
else:
|
| 1671 |
+
return self._encode_plus(
|
| 1672 |
+
text=text,
|
| 1673 |
+
add_special_tokens=add_special_tokens,
|
| 1674 |
+
padding_strategy=padding_strategy,
|
| 1675 |
+
truncation_strategy=truncation_strategy,
|
| 1676 |
+
max_length=max_length,
|
| 1677 |
+
stride=stride,
|
| 1678 |
+
pad_to_multiple_of=pad_to_multiple_of,
|
| 1679 |
+
padding_side=padding_side,
|
| 1680 |
+
return_tensors=return_tensors,
|
| 1681 |
+
return_attention_mask=return_attention_mask,
|
| 1682 |
+
return_overflowing_tokens=return_overflowing_tokens,
|
| 1683 |
+
return_special_tokens_mask=return_special_tokens_mask,
|
| 1684 |
+
return_length=return_length,
|
| 1685 |
+
verbose=verbose,
|
| 1686 |
+
**kwargs,
|
| 1687 |
+
)
|
| 1688 |
+
|
| 1689 |
+
@classmethod
|
| 1690 |
+
def from_pretrained(
|
| 1691 |
+
cls,
|
| 1692 |
+
pretrained_model_name_or_path: Union[str, os.PathLike],
|
| 1693 |
+
*init_inputs,
|
| 1694 |
+
mode: ValidationMode = ValidationMode.test,
|
| 1695 |
+
cache_dir: Optional[Union[str, os.PathLike]] = None,
|
| 1696 |
+
force_download: bool = False,
|
| 1697 |
+
local_files_only: bool = False,
|
| 1698 |
+
token: Optional[Union[str, bool]] = None,
|
| 1699 |
+
revision: str = "main",
|
| 1700 |
+
model_max_length: int = VERY_LARGE_INTEGER,
|
| 1701 |
+
padding_side: str = "left",
|
| 1702 |
+
truncation_side: str = "right",
|
| 1703 |
+
model_input_names: Optional[list[str]] = None,
|
| 1704 |
+
clean_up_tokenization_spaces: bool = False,
|
| 1705 |
+
**kwargs,
|
| 1706 |
+
):
|
| 1707 |
+
r"""
|
| 1708 |
+
Instantiate a `MistralCommonTokenizer` from a predefined
|
| 1709 |
+
tokenizer.
|
| 1710 |
+
|
| 1711 |
+
Args:
|
| 1712 |
+
pretrained_model_name_or_path (`str` or `os.PathLike`):
|
| 1713 |
+
Can be either:
|
| 1714 |
+
|
| 1715 |
+
- A string, the *model id* of a predefined tokenizer hosted inside a model repo on huggingface.co.
|
| 1716 |
+
- A path to a *directory* containing the tokenizer config, for instance saved
|
| 1717 |
+
using the [`MistralCommonTokenizer.tokenization_mistral_common.save_pretrained`] method, e.g.,
|
| 1718 |
+
`./my_model_directory/`.
|
| 1719 |
+
mode (`ValidationMode`, *optional*, defaults to `ValidationMode.test`):
|
| 1720 |
+
Validation mode for the `MistralTokenizer` tokenizer.
|
| 1721 |
+
cache_dir (`str` or `os.PathLike`, *optional*):
|
| 1722 |
+
Path to a directory in which a downloaded predefined tokenizer vocabulary files should be cached if the
|
| 1723 |
+
standard cache should not be used.
|
| 1724 |
+
force_download (`bool`, *optional*, defaults to `False`):
|
| 1725 |
+
Whether or not to force the (re-)download the vocabulary files and override the cached versions if they
|
| 1726 |
+
exist.
|
| 1727 |
+
token (`str` or *bool*, *optional*):
|
| 1728 |
+
The token to use as HTTP bearer authorization for remote files. If `True`, will use the token generated
|
| 1729 |
+
when running `hf auth login` (stored in `~/.huggingface`).
|
| 1730 |
+
local_files_only (`bool`, *optional*, defaults to `False`):
|
| 1731 |
+
Whether or not to only rely on local files and not to attempt to download any files.
|
| 1732 |
+
revision (`str`, *optional*, defaults to `"main"`):
|
| 1733 |
+
The specific model version to use. It can be a branch name, a tag name, or a commit id, since we use a
|
| 1734 |
+
git-based system for storing models and other artifacts on huggingface.co, so `revision` can be any
|
| 1735 |
+
identifier allowed by git.
|
| 1736 |
+
max_length (`int`, *optional*):
|
| 1737 |
+
Controls the maximum length to use by one of the truncation/padding parameters.
|
| 1738 |
+
|
| 1739 |
+
If left unset or set to `None`, this will use the predefined model maximum length if a maximum length
|
| 1740 |
+
is required by one of the truncation/padding parameters. If the model has no specific maximum input
|
| 1741 |
+
length (like XLNet) truncation/padding to a maximum length will be deactivated.
|
| 1742 |
+
padding_side (`str`, *optional*, defaults to `"left"`):
|
| 1743 |
+
The side on which the model should have padding applied. Should be selected between ['right', 'left'].
|
| 1744 |
+
Default value is picked from the class attribute of the same name.
|
| 1745 |
+
truncation_side (`str`, *optional*, defaults to `"right"`):
|
| 1746 |
+
The side on which the model should have truncation applied. Should be selected between ['right', 'left'].
|
| 1747 |
+
model_input_names (`List[string]`, *optional*):
|
| 1748 |
+
The list of inputs accepted by the forward pass of the model (like `"token_type_ids"` or
|
| 1749 |
+
`"attention_mask"`). Default value is picked from the class attribute of the same name.
|
| 1750 |
+
clean_up_tokenization_spaces (`bool`, *optional*, defaults to `False`):
|
| 1751 |
+
Whether or not the model should cleanup the spaces that were added when splitting the input text during the
|
| 1752 |
+
tokenization process.
|
| 1753 |
+
kwargs (additional keyword arguments, *optional*):
|
| 1754 |
+
Not supported by `MistralCommonTokenizer.from_pretrained`.
|
| 1755 |
+
Will raise an error if used.
|
| 1756 |
+
"""
|
| 1757 |
+
if init_inputs:
|
| 1758 |
+
raise ValueError("`init_inputs` are not supported by `MistralCommonTokenizer.from_pretrained`.")
|
| 1759 |
+
|
| 1760 |
+
# Handle kwargs and AutoTokenizer case
|
| 1761 |
+
if kwargs and not set(kwargs.keys()).issubset({"_from_auto", "trust_remote_code"}):
|
| 1762 |
+
raise ValueError(
|
| 1763 |
+
f"Kwargs {list(kwargs.keys())} are not supported by `MistralCommonTokenizer.from_pretrained`."
|
| 1764 |
+
)
|
| 1765 |
+
|
| 1766 |
+
if not os.path.isdir(pretrained_model_name_or_path):
|
| 1767 |
+
tokenizer_path = download_tokenizer_from_hf_hub(
|
| 1768 |
+
repo_id=pretrained_model_name_or_path,
|
| 1769 |
+
cache_dir=cache_dir,
|
| 1770 |
+
token=token,
|
| 1771 |
+
revision=revision,
|
| 1772 |
+
force_download=force_download,
|
| 1773 |
+
local_files_only=local_files_only,
|
| 1774 |
+
)
|
| 1775 |
+
else:
|
| 1776 |
+
valid_tokenizer_files = []
|
| 1777 |
+
tokenizer_file: str
|
| 1778 |
+
|
| 1779 |
+
instruct_versions = list(TokenizerVersion.__members__)
|
| 1780 |
+
mm_versions = list(MultiModalVersion.__members__) + [""] # allow no mm version
|
| 1781 |
+
sentencepiece_suffixes = [f".model.{v}{m}" for v in instruct_versions for m in mm_versions] + [".model"]
|
| 1782 |
+
|
| 1783 |
+
for path in os.listdir(pretrained_model_name_or_path):
|
| 1784 |
+
pathlib_repo_file = Path(path)
|
| 1785 |
+
file_name = pathlib_repo_file.name
|
| 1786 |
+
suffix = "".join(pathlib_repo_file.suffixes)
|
| 1787 |
+
if file_name == "tekken.json" or suffix in sentencepiece_suffixes:
|
| 1788 |
+
valid_tokenizer_files.append(file_name)
|
| 1789 |
+
|
| 1790 |
+
if len(valid_tokenizer_files) == 0:
|
| 1791 |
+
raise ValueError(f"No tokenizer file found in directory: {pretrained_model_name_or_path}")
|
| 1792 |
+
# If there are multiple tokenizer files, we use tekken.json if it exists, otherwise the versioned one.
|
| 1793 |
+
if len(valid_tokenizer_files) > 1:
|
| 1794 |
+
if "tekken.json" in valid_tokenizer_files:
|
| 1795 |
+
tokenizer_file = "tekken.json"
|
| 1796 |
+
else:
|
| 1797 |
+
tokenizer_file = max(valid_tokenizer_files)
|
| 1798 |
+
logger.warning(
|
| 1799 |
+
f"Multiple tokenizer files found in directory: {pretrained_model_name_or_path}. Using {tokenizer_file}."
|
| 1800 |
+
)
|
| 1801 |
+
else:
|
| 1802 |
+
tokenizer_file = valid_tokenizer_files[0]
|
| 1803 |
+
|
| 1804 |
+
tokenizer_path = os.path.join(pretrained_model_name_or_path, tokenizer_file)
|
| 1805 |
+
|
| 1806 |
+
return cls(
|
| 1807 |
+
tokenizer_path=tokenizer_path,
|
| 1808 |
+
mode=mode,
|
| 1809 |
+
model_max_length=model_max_length,
|
| 1810 |
+
padding_side=padding_side,
|
| 1811 |
+
truncation_side=truncation_side,
|
| 1812 |
+
model_input_names=model_input_names,
|
| 1813 |
+
clean_up_tokenization_spaces=clean_up_tokenization_spaces,
|
| 1814 |
+
)
|
| 1815 |
+
|
| 1816 |
+
def save_pretrained(
|
| 1817 |
+
self,
|
| 1818 |
+
save_directory: Union[str, os.PathLike, Path],
|
| 1819 |
+
push_to_hub: bool = False,
|
| 1820 |
+
token: Optional[Union[str, bool]] = None,
|
| 1821 |
+
commit_message: Optional[str] = None,
|
| 1822 |
+
repo_id: Optional[str] = None,
|
| 1823 |
+
private: Optional[bool] = None,
|
| 1824 |
+
repo_url: Optional[str] = None,
|
| 1825 |
+
organization: Optional[str] = None,
|
| 1826 |
+
**kwargs,
|
| 1827 |
+
) -> tuple[str, ...]:
|
| 1828 |
+
"""
|
| 1829 |
+
Save the full tokenizer state.
|
| 1830 |
+
|
| 1831 |
+
|
| 1832 |
+
This method make sure the full tokenizer can then be re-loaded using the
|
| 1833 |
+
[`~MistralCommonTokenizer.tokenization_mistral_common.from_pretrained`] class method.
|
| 1834 |
+
|
| 1835 |
+
Args:
|
| 1836 |
+
save_directory (`str` or `os.PathLike`): The path to a directory where the tokenizer will be saved.
|
| 1837 |
+
push_to_hub (`bool`, *optional*, defaults to `False`):
|
| 1838 |
+
Whether or not to push your model to the Hugging Face model hub after saving it. You can specify the
|
| 1839 |
+
repository you want to push to with `repo_id` (will default to the name of `save_directory` in your
|
| 1840 |
+
namespace).
|
| 1841 |
+
token (`str` or *bool*, *optional*, defaults to `None`):
|
| 1842 |
+
The token to use to push to the model hub. If `True`, will use the token in the `HF_TOKEN` environment
|
| 1843 |
+
variable.
|
| 1844 |
+
commit_message (`str`, *optional*): The commit message to use when pushing to the hub.
|
| 1845 |
+
repo_id (`str`, *optional*): The name of the repository to which push to the Hub.
|
| 1846 |
+
private (`bool`, *optional*): Whether the model repository is private or not.
|
| 1847 |
+
repo_url (`str`, *optional*): The URL to the Git repository to which push to the Hub.
|
| 1848 |
+
organization (`str`, *optional*): The name of the organization in which you would like to push your model.
|
| 1849 |
+
kwargs (`Dict[str, Any]`, *optional*):
|
| 1850 |
+
Not supported by `MistralCommonTokenizer.save_pretrained`.
|
| 1851 |
+
Will raise an error if used.
|
| 1852 |
+
|
| 1853 |
+
Returns:
|
| 1854 |
+
A tuple of `str`: The files saved.
|
| 1855 |
+
"""
|
| 1856 |
+
# `save_jinja_files`` must be skipped to be able to save from a processor
|
| 1857 |
+
kwargs.pop("save_jinja_files", None)
|
| 1858 |
+
if kwargs:
|
| 1859 |
+
raise ValueError(
|
| 1860 |
+
f"Kwargs {list(kwargs.keys())} are not supported by `MistralCommonTokenizer.save_pretrained`."
|
| 1861 |
+
)
|
| 1862 |
+
|
| 1863 |
+
save_directory = Path(save_directory)
|
| 1864 |
+
save_directory.mkdir(parents=True, exist_ok=True)
|
| 1865 |
+
|
| 1866 |
+
shutil.copy(self._tokenizer_path, save_directory)
|
| 1867 |
+
|
| 1868 |
+
if push_to_hub:
|
| 1869 |
+
repo_id = repo_id or str(save_directory).split(os.path.sep)[-1]
|
| 1870 |
+
repo_id = self._create_repo(
|
| 1871 |
+
repo_id, token=token, private=private, repo_url=repo_url, organization=organization
|
| 1872 |
+
)
|
| 1873 |
+
files_timestamps = self._get_files_timestamps(save_directory)
|
| 1874 |
+
|
| 1875 |
+
self._upload_modified_files(
|
| 1876 |
+
save_directory,
|
| 1877 |
+
repo_id,
|
| 1878 |
+
files_timestamps,
|
| 1879 |
+
commit_message=commit_message,
|
| 1880 |
+
token=token,
|
| 1881 |
+
)
|
| 1882 |
+
|
| 1883 |
+
return (str(save_directory / self._tokenizer_path.name),)
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/transformers/trainer_pt_utils.py
ADDED
|
@@ -0,0 +1,1406 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2020-present the HuggingFace Inc. team.
|
| 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 |
+
"""
|
| 15 |
+
Torch utilities for the Trainer class.
|
| 16 |
+
"""
|
| 17 |
+
|
| 18 |
+
import copy
|
| 19 |
+
import datetime
|
| 20 |
+
import io
|
| 21 |
+
import json
|
| 22 |
+
import math
|
| 23 |
+
import os
|
| 24 |
+
import re
|
| 25 |
+
import sys
|
| 26 |
+
import warnings
|
| 27 |
+
from collections.abc import Iterator, Mapping
|
| 28 |
+
from contextlib import contextmanager
|
| 29 |
+
from dataclasses import dataclass, field
|
| 30 |
+
from itertools import chain
|
| 31 |
+
from logging import StreamHandler
|
| 32 |
+
from typing import Any, Optional, Union
|
| 33 |
+
|
| 34 |
+
import numpy as np
|
| 35 |
+
import torch
|
| 36 |
+
import torch.distributed as dist
|
| 37 |
+
from torch import nn
|
| 38 |
+
from torch.utils.data import Dataset, IterableDataset, RandomSampler, Sampler
|
| 39 |
+
from torch.utils.data.distributed import DistributedSampler
|
| 40 |
+
|
| 41 |
+
from .integrations.deepspeed import is_deepspeed_zero3_enabled
|
| 42 |
+
from .tokenization_utils_base import BatchEncoding
|
| 43 |
+
from .utils import (
|
| 44 |
+
is_sagemaker_mp_enabled,
|
| 45 |
+
is_torch_available,
|
| 46 |
+
is_torch_xla_available,
|
| 47 |
+
is_training_run_on_sagemaker,
|
| 48 |
+
logging,
|
| 49 |
+
)
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
if is_training_run_on_sagemaker():
|
| 53 |
+
logging.add_handler(StreamHandler(sys.stdout))
|
| 54 |
+
|
| 55 |
+
if is_torch_xla_available():
|
| 56 |
+
import torch_xla.runtime as xr
|
| 57 |
+
|
| 58 |
+
if is_torch_available():
|
| 59 |
+
from torch.optim.lr_scheduler import LRScheduler
|
| 60 |
+
|
| 61 |
+
|
| 62 |
+
logger = logging.get_logger(__name__)
|
| 63 |
+
|
| 64 |
+
|
| 65 |
+
def get_dataloader_sampler(dataloader):
|
| 66 |
+
if hasattr(dataloader, "batch_sampler") and dataloader.batch_sampler is not None:
|
| 67 |
+
return get_dataloader_sampler(dataloader.batch_sampler)
|
| 68 |
+
elif hasattr(dataloader, "sampler"):
|
| 69 |
+
return dataloader.sampler
|
| 70 |
+
|
| 71 |
+
|
| 72 |
+
def atleast_1d(tensor_or_array: Union[torch.Tensor, np.ndarray]):
|
| 73 |
+
if isinstance(tensor_or_array, torch.Tensor):
|
| 74 |
+
if hasattr(torch, "atleast_1d"):
|
| 75 |
+
tensor_or_array = torch.atleast_1d(tensor_or_array)
|
| 76 |
+
elif tensor_or_array.ndim < 1:
|
| 77 |
+
tensor_or_array = tensor_or_array[None]
|
| 78 |
+
else:
|
| 79 |
+
tensor_or_array = np.atleast_1d(tensor_or_array)
|
| 80 |
+
return tensor_or_array
|
| 81 |
+
|
| 82 |
+
|
| 83 |
+
def torch_pad_and_concatenate(tensor1, tensor2, padding_index=-100):
|
| 84 |
+
"""Concatenates `tensor1` and `tensor2` on first axis, applying padding on the second if necessary."""
|
| 85 |
+
tensor1 = atleast_1d(tensor1)
|
| 86 |
+
tensor2 = atleast_1d(tensor2)
|
| 87 |
+
|
| 88 |
+
if len(tensor1.shape) == 1 or tensor1.shape[1] == tensor2.shape[1]:
|
| 89 |
+
return torch.cat((tensor1, tensor2), dim=0)
|
| 90 |
+
|
| 91 |
+
# Let's figure out the new shape
|
| 92 |
+
new_shape = (tensor1.shape[0] + tensor2.shape[0], max(tensor1.shape[1], tensor2.shape[1])) + tensor1.shape[2:]
|
| 93 |
+
|
| 94 |
+
# Now let's fill the result tensor
|
| 95 |
+
result = tensor1.new_full(new_shape, padding_index)
|
| 96 |
+
result[: tensor1.shape[0], : tensor1.shape[1]] = tensor1
|
| 97 |
+
result[tensor1.shape[0] :, : tensor2.shape[1]] = tensor2
|
| 98 |
+
return result
|
| 99 |
+
|
| 100 |
+
|
| 101 |
+
def numpy_pad_and_concatenate(array1, array2, padding_index=-100):
|
| 102 |
+
"""Concatenates `array1` and `array2` on first axis, applying padding on the second if necessary."""
|
| 103 |
+
array1 = atleast_1d(array1)
|
| 104 |
+
array2 = atleast_1d(array2)
|
| 105 |
+
|
| 106 |
+
if len(array1.shape) == 1 or array1.shape[1] == array2.shape[1]:
|
| 107 |
+
return np.concatenate((array1, array2), axis=0)
|
| 108 |
+
|
| 109 |
+
# Let's figure out the new shape
|
| 110 |
+
new_shape = (array1.shape[0] + array2.shape[0], max(array1.shape[1], array2.shape[1])) + array1.shape[2:]
|
| 111 |
+
|
| 112 |
+
# Now let's fill the result tensor
|
| 113 |
+
result = np.full_like(array1, padding_index, shape=new_shape)
|
| 114 |
+
result[: array1.shape[0], : array1.shape[1]] = array1
|
| 115 |
+
result[array1.shape[0] :, : array2.shape[1]] = array2
|
| 116 |
+
return result
|
| 117 |
+
|
| 118 |
+
|
| 119 |
+
def nested_concat(tensors, new_tensors, padding_index=-100):
|
| 120 |
+
"""
|
| 121 |
+
Concat the `new_tensors` to `tensors` on the first dim and pad them on the second if needed. Works for tensors or
|
| 122 |
+
nested list/tuples/dict of tensors.
|
| 123 |
+
"""
|
| 124 |
+
if not (isinstance(tensors, torch.Tensor) and isinstance(new_tensors, torch.Tensor)):
|
| 125 |
+
assert type(tensors) is type(new_tensors), (
|
| 126 |
+
f"Expected `tensors` and `new_tensors` to have the same type but found {type(tensors)} and {type(new_tensors)}."
|
| 127 |
+
)
|
| 128 |
+
if isinstance(tensors, (list, tuple)):
|
| 129 |
+
return type(tensors)(nested_concat(t, n, padding_index=padding_index) for t, n in zip(tensors, new_tensors))
|
| 130 |
+
elif isinstance(tensors, torch.Tensor):
|
| 131 |
+
return torch_pad_and_concatenate(tensors, new_tensors, padding_index=padding_index)
|
| 132 |
+
elif isinstance(tensors, Mapping):
|
| 133 |
+
return type(tensors)(
|
| 134 |
+
{k: nested_concat(t, new_tensors[k], padding_index=padding_index) for k, t in tensors.items()}
|
| 135 |
+
)
|
| 136 |
+
elif isinstance(tensors, np.ndarray):
|
| 137 |
+
return numpy_pad_and_concatenate(tensors, new_tensors, padding_index=padding_index)
|
| 138 |
+
else:
|
| 139 |
+
raise TypeError(f"Unsupported type for concatenation: got {type(tensors)}")
|
| 140 |
+
|
| 141 |
+
|
| 142 |
+
def find_batch_size(tensors):
|
| 143 |
+
"""
|
| 144 |
+
Find the first dimension of a tensor in a nested list/tuple/dict of tensors.
|
| 145 |
+
"""
|
| 146 |
+
if isinstance(tensors, (list, tuple)):
|
| 147 |
+
for t in tensors:
|
| 148 |
+
result = find_batch_size(t)
|
| 149 |
+
if result is not None:
|
| 150 |
+
return result
|
| 151 |
+
elif isinstance(tensors, Mapping):
|
| 152 |
+
for value in tensors.values():
|
| 153 |
+
result = find_batch_size(value)
|
| 154 |
+
if result is not None:
|
| 155 |
+
return result
|
| 156 |
+
elif isinstance(tensors, (torch.Tensor, np.ndarray)):
|
| 157 |
+
return tensors.shape[0] if len(tensors.shape) >= 1 else None
|
| 158 |
+
|
| 159 |
+
|
| 160 |
+
def nested_numpify(tensors):
|
| 161 |
+
"Numpify `tensors` (even if it's a nested list/tuple/dict of tensors)."
|
| 162 |
+
if isinstance(tensors, (list, tuple)):
|
| 163 |
+
return type(tensors)(nested_numpify(t) for t in tensors)
|
| 164 |
+
if isinstance(tensors, Mapping):
|
| 165 |
+
return type(tensors)({k: nested_numpify(t) for k, t in tensors.items()})
|
| 166 |
+
|
| 167 |
+
t = tensors.cpu()
|
| 168 |
+
if t.dtype == torch.bfloat16:
|
| 169 |
+
# As of Numpy 1.21.4, NumPy does not support bfloat16 (see
|
| 170 |
+
# https://github.com/numpy/numpy/blob/a47ecdea856986cd60eabbd53265c2ca5916ad5d/doc/source/user/basics.types.rst ).
|
| 171 |
+
# Until Numpy adds bfloat16, we must convert float32.
|
| 172 |
+
t = t.to(torch.float32)
|
| 173 |
+
return t.numpy()
|
| 174 |
+
|
| 175 |
+
|
| 176 |
+
def nested_detach(tensors):
|
| 177 |
+
"Detach `tensors` (even if it's a nested list/tuple/dict of tensors)."
|
| 178 |
+
if isinstance(tensors, (list, tuple)):
|
| 179 |
+
return type(tensors)(nested_detach(t) for t in tensors)
|
| 180 |
+
elif isinstance(tensors, Mapping):
|
| 181 |
+
return type(tensors)({k: nested_detach(t) for k, t in tensors.items()})
|
| 182 |
+
return tensors.detach() if isinstance(tensors, torch.Tensor) else tensors
|
| 183 |
+
|
| 184 |
+
|
| 185 |
+
def nested_xla_mesh_reduce(tensors, name):
|
| 186 |
+
if is_torch_xla_available():
|
| 187 |
+
import torch_xla.core.xla_model as xm
|
| 188 |
+
|
| 189 |
+
if isinstance(tensors, (list, tuple)):
|
| 190 |
+
return type(tensors)(nested_xla_mesh_reduce(t, f"{name}_{i}") for i, t in enumerate(tensors))
|
| 191 |
+
if isinstance(tensors, Mapping):
|
| 192 |
+
return type(tensors)(
|
| 193 |
+
{k: nested_xla_mesh_reduce(t, f"{name}_{i}") for i, (k, t) in enumerate(tensors.items())}
|
| 194 |
+
)
|
| 195 |
+
|
| 196 |
+
tensors = atleast_1d(tensors)
|
| 197 |
+
return xm.mesh_reduce(name, tensors, torch.cat)
|
| 198 |
+
else:
|
| 199 |
+
raise ImportError("Torch xla must be installed to use `nested_xla_mesh_reduce`")
|
| 200 |
+
|
| 201 |
+
|
| 202 |
+
def distributed_concat(tensor: Any, num_total_examples: Optional[int] = None) -> Any:
|
| 203 |
+
try:
|
| 204 |
+
if isinstance(tensor, (tuple, list)):
|
| 205 |
+
return type(tensor)(distributed_concat(t, num_total_examples) for t in tensor)
|
| 206 |
+
if isinstance(tensor, Mapping):
|
| 207 |
+
return type(tensor)({k: distributed_concat(t, num_total_examples) for k, t in tensor.items()})
|
| 208 |
+
tensor = atleast_1d(tensor).contiguous()
|
| 209 |
+
output_tensors = [tensor.clone() for _ in range(dist.get_world_size())]
|
| 210 |
+
dist.all_gather(output_tensors, tensor)
|
| 211 |
+
concat = torch.cat(output_tensors, dim=0)
|
| 212 |
+
|
| 213 |
+
# truncate the dummy elements added by SequentialDistributedSampler
|
| 214 |
+
if num_total_examples is not None:
|
| 215 |
+
concat = concat[:num_total_examples]
|
| 216 |
+
return concat
|
| 217 |
+
except AssertionError:
|
| 218 |
+
raise AssertionError("Not currently using distributed training")
|
| 219 |
+
|
| 220 |
+
|
| 221 |
+
def distributed_broadcast_scalars(
|
| 222 |
+
scalars: list[Union[int, float]],
|
| 223 |
+
num_total_examples: Optional[int] = None,
|
| 224 |
+
device: Optional[torch.device] = torch.device("cuda"),
|
| 225 |
+
) -> torch.Tensor:
|
| 226 |
+
try:
|
| 227 |
+
tensorized_scalar = torch.tensor(scalars, device=device)
|
| 228 |
+
output_tensors = [tensorized_scalar.clone() for _ in range(dist.get_world_size())]
|
| 229 |
+
dist.all_gather(output_tensors, tensorized_scalar)
|
| 230 |
+
concat = torch.cat(output_tensors, dim=0)
|
| 231 |
+
|
| 232 |
+
# truncate the dummy elements added by SequentialDistributedSampler
|
| 233 |
+
if num_total_examples is not None:
|
| 234 |
+
concat = concat[:num_total_examples]
|
| 235 |
+
return concat
|
| 236 |
+
except AssertionError:
|
| 237 |
+
raise AssertionError("Not currently using distributed training")
|
| 238 |
+
|
| 239 |
+
|
| 240 |
+
def reissue_pt_warnings(caught_warnings):
|
| 241 |
+
# Reissue warnings
|
| 242 |
+
if len(caught_warnings) > 1:
|
| 243 |
+
for w in caught_warnings:
|
| 244 |
+
if w.category is not UserWarning:
|
| 245 |
+
warnings.warn(w.message, w.category)
|
| 246 |
+
|
| 247 |
+
|
| 248 |
+
@contextmanager
|
| 249 |
+
def torch_distributed_zero_first(local_rank: int):
|
| 250 |
+
"""
|
| 251 |
+
Decorator to make all processes in distributed training wait for each local_master to do something.
|
| 252 |
+
|
| 253 |
+
Args:
|
| 254 |
+
local_rank (`int`): The rank of the local process.
|
| 255 |
+
"""
|
| 256 |
+
if local_rank not in [-1, 0]:
|
| 257 |
+
dist.barrier()
|
| 258 |
+
yield
|
| 259 |
+
if local_rank == 0:
|
| 260 |
+
dist.barrier()
|
| 261 |
+
|
| 262 |
+
|
| 263 |
+
class DistributedSamplerWithLoop(DistributedSampler):
|
| 264 |
+
"""
|
| 265 |
+
Like a torch.utils.data.distributed.DistributedSampler` but loops at the end back to the beginning of the shuffled
|
| 266 |
+
samples to make each process have a round multiple of batch_size samples.
|
| 267 |
+
|
| 268 |
+
Args:
|
| 269 |
+
dataset (`torch.utils.data.Dataset`):
|
| 270 |
+
Dataset used for sampling.
|
| 271 |
+
batch_size (`int`):
|
| 272 |
+
The batch size used with this sampler
|
| 273 |
+
kwargs (`dict[str, Any]`, *optional*):
|
| 274 |
+
All other keyword arguments passed to `DistributedSampler`.
|
| 275 |
+
"""
|
| 276 |
+
|
| 277 |
+
def __init__(self, dataset, batch_size, **kwargs):
|
| 278 |
+
super().__init__(dataset, **kwargs)
|
| 279 |
+
self.batch_size = batch_size
|
| 280 |
+
|
| 281 |
+
def __iter__(self):
|
| 282 |
+
indices = list(super().__iter__())
|
| 283 |
+
remainder = 0 if len(indices) % self.batch_size == 0 else self.batch_size - len(indices) % self.batch_size
|
| 284 |
+
# DistributedSampler already added samples from the beginning to make the number of samples a round multiple
|
| 285 |
+
# of the world size, so we skip those.
|
| 286 |
+
start_remainder = 1 if self.rank < len(self.dataset) % self.num_replicas else 0
|
| 287 |
+
indices += indices[start_remainder : start_remainder + remainder]
|
| 288 |
+
return iter(indices)
|
| 289 |
+
|
| 290 |
+
|
| 291 |
+
class EvalLoopContainer:
|
| 292 |
+
"""
|
| 293 |
+
Container to store intermediate results of evaluation loop.
|
| 294 |
+
|
| 295 |
+
Args:
|
| 296 |
+
do_nested_concat (`bool`, *optional*, defaults to `True`):
|
| 297 |
+
If set to `True`, each iteration will recursively concatenate a new object containing tensors to
|
| 298 |
+
the existing stored tensors, provided that the structure of the existing object and the new one
|
| 299 |
+
are identical. If set to `False`, all newly added tensors will be stored in a list.
|
| 300 |
+
padding_index (`int`, *optional*, defaults to -100):
|
| 301 |
+
Value used to pad tensors of different shapes when `do_nested_concat=True`.
|
| 302 |
+
"""
|
| 303 |
+
|
| 304 |
+
def __init__(self, do_nested_concat: bool = True, padding_index: int = -100):
|
| 305 |
+
self.do_nested_concat = do_nested_concat
|
| 306 |
+
self.padding_index = padding_index
|
| 307 |
+
self.tensors = None
|
| 308 |
+
self.arrays = None
|
| 309 |
+
|
| 310 |
+
def add(self, tensors) -> None:
|
| 311 |
+
"""Add tensors to the stored objects. If `do_nested_concat=True`, the tensors will be concatenated recursively."""
|
| 312 |
+
if self.tensors is None:
|
| 313 |
+
self.tensors = tensors if self.do_nested_concat else [tensors]
|
| 314 |
+
elif self.do_nested_concat:
|
| 315 |
+
self.tensors = nested_concat(self.tensors, tensors, padding_index=self.padding_index)
|
| 316 |
+
else:
|
| 317 |
+
self.tensors.append(tensors)
|
| 318 |
+
|
| 319 |
+
def to_cpu_and_numpy(self) -> None:
|
| 320 |
+
"""Move tensors in stored objects to CPU and convert them to numpy arrays."""
|
| 321 |
+
|
| 322 |
+
# Check if we have something to add, if not just return
|
| 323 |
+
if self.tensors is None:
|
| 324 |
+
return
|
| 325 |
+
|
| 326 |
+
new_arrays = nested_numpify(self.tensors)
|
| 327 |
+
if self.arrays is None:
|
| 328 |
+
self.arrays = new_arrays
|
| 329 |
+
elif self.do_nested_concat:
|
| 330 |
+
self.arrays = nested_concat(self.arrays, new_arrays, padding_index=self.padding_index)
|
| 331 |
+
else:
|
| 332 |
+
self.arrays.extend(new_arrays)
|
| 333 |
+
|
| 334 |
+
# reset device tensors after adding to cpu
|
| 335 |
+
self.tensors = None
|
| 336 |
+
|
| 337 |
+
def get_arrays(self):
|
| 338 |
+
"""Returns the numpified and moved to CPU stored objects."""
|
| 339 |
+
self.to_cpu_and_numpy()
|
| 340 |
+
return self.arrays
|
| 341 |
+
|
| 342 |
+
|
| 343 |
+
class SequentialDistributedSampler(Sampler):
|
| 344 |
+
"""
|
| 345 |
+
Distributed Sampler that subsamples indices sequentially, making it easier to collate all results at the end.
|
| 346 |
+
|
| 347 |
+
Even though we only use this sampler for eval and predict (no training), which means that the model params won't
|
| 348 |
+
have to be synced (i.e. will not hang for synchronization even if varied number of forward passes), we still add
|
| 349 |
+
extra samples to the sampler to make it evenly divisible (like in `DistributedSampler`) to make it easy to `gather`
|
| 350 |
+
or `reduce` resulting tensors at the end of the loop.
|
| 351 |
+
"""
|
| 352 |
+
|
| 353 |
+
def __init__(self, dataset, num_replicas=None, rank=None, batch_size=None):
|
| 354 |
+
warnings.warn(
|
| 355 |
+
"SequentialDistributedSampler is deprecated and will be removed in v5 of Transformers.",
|
| 356 |
+
FutureWarning,
|
| 357 |
+
)
|
| 358 |
+
if num_replicas is None:
|
| 359 |
+
if not dist.is_available():
|
| 360 |
+
raise RuntimeError("Requires distributed package to be available")
|
| 361 |
+
num_replicas = dist.get_world_size()
|
| 362 |
+
if rank is None:
|
| 363 |
+
if not dist.is_available():
|
| 364 |
+
raise RuntimeError("Requires distributed package to be available")
|
| 365 |
+
rank = dist.get_rank()
|
| 366 |
+
self.dataset = dataset
|
| 367 |
+
self.num_replicas = num_replicas
|
| 368 |
+
self.rank = rank
|
| 369 |
+
num_samples = len(self.dataset)
|
| 370 |
+
# Add extra samples to make num_samples a multiple of batch_size if passed
|
| 371 |
+
if batch_size is not None:
|
| 372 |
+
self.num_samples = int(math.ceil(num_samples / (batch_size * num_replicas))) * batch_size
|
| 373 |
+
else:
|
| 374 |
+
self.num_samples = int(math.ceil(num_samples / num_replicas))
|
| 375 |
+
self.total_size = self.num_samples * self.num_replicas
|
| 376 |
+
self.batch_size = batch_size
|
| 377 |
+
|
| 378 |
+
def __iter__(self):
|
| 379 |
+
indices = list(range(len(self.dataset)))
|
| 380 |
+
|
| 381 |
+
# add extra samples to make it evenly divisible
|
| 382 |
+
indices += indices[: (self.total_size - len(indices))]
|
| 383 |
+
assert len(indices) == self.total_size, (
|
| 384 |
+
f"Indices length {len(indices)} and total size {self.total_size} mismatched"
|
| 385 |
+
)
|
| 386 |
+
|
| 387 |
+
# subsample
|
| 388 |
+
indices = indices[self.rank * self.num_samples : (self.rank + 1) * self.num_samples]
|
| 389 |
+
assert len(indices) == self.num_samples, (
|
| 390 |
+
f"Indices length {len(indices)} and sample number {self.num_samples} mismatched"
|
| 391 |
+
)
|
| 392 |
+
|
| 393 |
+
return iter(indices)
|
| 394 |
+
|
| 395 |
+
def __len__(self):
|
| 396 |
+
return self.num_samples
|
| 397 |
+
|
| 398 |
+
|
| 399 |
+
def get_tpu_sampler(dataset: torch.utils.data.Dataset, batch_size: int):
|
| 400 |
+
if xr.world_size() <= 1:
|
| 401 |
+
return RandomSampler(dataset)
|
| 402 |
+
return DistributedSampler(dataset, num_replicas=xr.world_size(), rank=xr.global_ordinal())
|
| 403 |
+
|
| 404 |
+
|
| 405 |
+
def nested_new_like(arrays, num_samples, padding_index=-100):
|
| 406 |
+
"""Create the same nested structure as `arrays` with a first dimension always at `num_samples`."""
|
| 407 |
+
if isinstance(arrays, (list, tuple)):
|
| 408 |
+
return type(arrays)(nested_new_like(x, num_samples) for x in arrays)
|
| 409 |
+
return np.full_like(arrays, padding_index, shape=(num_samples, *arrays.shape[1:]))
|
| 410 |
+
|
| 411 |
+
|
| 412 |
+
def expand_like(arrays, new_seq_length, padding_index=-100):
|
| 413 |
+
"""Expand the `arrays` so that the second dimension grows to `new_seq_length`. Uses `padding_index` for padding."""
|
| 414 |
+
result = np.full_like(arrays, padding_index, shape=(arrays.shape[0], new_seq_length) + arrays.shape[2:])
|
| 415 |
+
result[:, : arrays.shape[1]] = arrays
|
| 416 |
+
return result
|
| 417 |
+
|
| 418 |
+
|
| 419 |
+
def nested_truncate(tensors, limit):
|
| 420 |
+
"Truncate `tensors` at `limit` (even if it's a nested list/tuple/dict of tensors)."
|
| 421 |
+
if isinstance(tensors, (list, tuple)):
|
| 422 |
+
return type(tensors)(nested_truncate(t, limit) for t in tensors)
|
| 423 |
+
if isinstance(tensors, Mapping):
|
| 424 |
+
return type(tensors)({k: nested_truncate(t, limit) for k, t in tensors.items()})
|
| 425 |
+
|
| 426 |
+
return tensors[:limit]
|
| 427 |
+
|
| 428 |
+
|
| 429 |
+
class DistributedTensorGatherer:
|
| 430 |
+
"""
|
| 431 |
+
A class responsible for properly gathering tensors (or nested list/tuple of tensors) on the CPU by chunks.
|
| 432 |
+
|
| 433 |
+
If our dataset has 16 samples with a batch size of 2 on 3 processes and we gather then transfer on CPU at every
|
| 434 |
+
step, our sampler will generate the following indices:
|
| 435 |
+
|
| 436 |
+
`[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1]`
|
| 437 |
+
|
| 438 |
+
to get something of size a multiple of 3 (so that each process gets the same dataset length). Then process 0, 1 and
|
| 439 |
+
2 will be responsible of making predictions for the following samples:
|
| 440 |
+
|
| 441 |
+
- P0: `[0, 1, 2, 3, 4, 5]`
|
| 442 |
+
- P1: `[6, 7, 8, 9, 10, 11]`
|
| 443 |
+
- P2: `[12, 13, 14, 15, 0, 1]`
|
| 444 |
+
|
| 445 |
+
The first batch treated on each process will be:
|
| 446 |
+
|
| 447 |
+
- P0: `[0, 1]`
|
| 448 |
+
- P1: `[6, 7]`
|
| 449 |
+
- P2: `[12, 13]`
|
| 450 |
+
|
| 451 |
+
So if we gather at the end of the first batch, we will get a tensor (nested list/tuple of tensor) corresponding to
|
| 452 |
+
the following indices:
|
| 453 |
+
|
| 454 |
+
`[0, 1, 6, 7, 12, 13]`
|
| 455 |
+
|
| 456 |
+
If we directly concatenate our results without taking any precautions, the user will then get the predictions for
|
| 457 |
+
the indices in this order at the end of the prediction loop:
|
| 458 |
+
|
| 459 |
+
`[0, 1, 6, 7, 12, 13, 2, 3, 8, 9, 14, 15, 4, 5, 10, 11, 0, 1]`
|
| 460 |
+
|
| 461 |
+
For some reason, that's not going to roll their boat. This class is there to solve that problem.
|
| 462 |
+
|
| 463 |
+
Args:
|
| 464 |
+
world_size (`int`):
|
| 465 |
+
The number of processes used in the distributed training.
|
| 466 |
+
num_samples (`int`):
|
| 467 |
+
The number of samples in our dataset.
|
| 468 |
+
make_multiple_of (`int`, *optional*):
|
| 469 |
+
If passed, the class assumes the datasets passed to each process are made to be a multiple of this argument
|
| 470 |
+
(by adding samples).
|
| 471 |
+
padding_index (`int`, *optional*, defaults to -100):
|
| 472 |
+
The padding index to use if the arrays don't all have the same sequence length.
|
| 473 |
+
"""
|
| 474 |
+
|
| 475 |
+
def __init__(self, world_size, num_samples, make_multiple_of=None, padding_index=-100):
|
| 476 |
+
warnings.warn(
|
| 477 |
+
"DistributedTensorGatherer is deprecated and will be removed in v5 of Transformers.",
|
| 478 |
+
FutureWarning,
|
| 479 |
+
)
|
| 480 |
+
self.world_size = world_size
|
| 481 |
+
self.num_samples = num_samples
|
| 482 |
+
total_size = world_size if make_multiple_of is None else world_size * make_multiple_of
|
| 483 |
+
self.total_samples = int(np.ceil(num_samples / total_size)) * total_size
|
| 484 |
+
self.process_length = self.total_samples // world_size
|
| 485 |
+
self._storage = None
|
| 486 |
+
self._offsets = None
|
| 487 |
+
self.padding_index = padding_index
|
| 488 |
+
|
| 489 |
+
def add_arrays(self, arrays):
|
| 490 |
+
"""
|
| 491 |
+
Add `arrays` to the internal storage, Will initialize the storage to the full size at the first arrays passed
|
| 492 |
+
so that if we're bound to get an OOM, it happens at the beginning.
|
| 493 |
+
"""
|
| 494 |
+
if arrays is None:
|
| 495 |
+
return
|
| 496 |
+
if self._storage is None:
|
| 497 |
+
self._storage = nested_new_like(arrays, self.total_samples, padding_index=self.padding_index)
|
| 498 |
+
self._offsets = list(range(0, self.total_samples, self.process_length))
|
| 499 |
+
|
| 500 |
+
slice_len, self._storage = self._nested_set_tensors(self._storage, arrays)
|
| 501 |
+
for i in range(self.world_size):
|
| 502 |
+
self._offsets[i] += slice_len
|
| 503 |
+
|
| 504 |
+
def _nested_set_tensors(self, storage, arrays):
|
| 505 |
+
if isinstance(arrays, (list, tuple)):
|
| 506 |
+
result = [self._nested_set_tensors(x, y) for x, y in zip(storage, arrays)]
|
| 507 |
+
return result[0][0], type(arrays)(r[1] for r in result)
|
| 508 |
+
assert arrays.shape[0] % self.world_size == 0, (
|
| 509 |
+
f"Arrays passed should all have a first dimension multiple of {self.world_size}, found {arrays.shape[0]}."
|
| 510 |
+
)
|
| 511 |
+
|
| 512 |
+
slice_len = arrays.shape[0] // self.world_size
|
| 513 |
+
for i in range(self.world_size):
|
| 514 |
+
if len(arrays.shape) == 1:
|
| 515 |
+
storage[self._offsets[i] : self._offsets[i] + slice_len] = arrays[i * slice_len : (i + 1) * slice_len]
|
| 516 |
+
else:
|
| 517 |
+
# Expand the array on the fly if needed.
|
| 518 |
+
if len(storage.shape) > 1 and storage.shape[1] < arrays.shape[1]:
|
| 519 |
+
storage = expand_like(storage, arrays.shape[1], padding_index=self.padding_index)
|
| 520 |
+
storage[self._offsets[i] : self._offsets[i] + slice_len, : arrays.shape[1]] = arrays[
|
| 521 |
+
i * slice_len : (i + 1) * slice_len
|
| 522 |
+
]
|
| 523 |
+
return slice_len, storage
|
| 524 |
+
|
| 525 |
+
def finalize(self):
|
| 526 |
+
"""
|
| 527 |
+
Return the properly gathered arrays and truncate to the number of samples (since the sampler added some extras
|
| 528 |
+
to get each process a dataset of the same length).
|
| 529 |
+
"""
|
| 530 |
+
if self._storage is None:
|
| 531 |
+
return
|
| 532 |
+
if self._offsets[0] != self.process_length:
|
| 533 |
+
logger.warning("Not all data has been set. Are you sure you passed all values?")
|
| 534 |
+
return nested_truncate(self._storage, self.num_samples)
|
| 535 |
+
|
| 536 |
+
|
| 537 |
+
@dataclass
|
| 538 |
+
class LabelSmoother:
|
| 539 |
+
"""
|
| 540 |
+
Adds label-smoothing on a pre-computed output from a Transformers model.
|
| 541 |
+
|
| 542 |
+
Args:
|
| 543 |
+
epsilon (`float`, *optional*, defaults to 0.1):
|
| 544 |
+
The label smoothing factor.
|
| 545 |
+
ignore_index (`int`, *optional*, defaults to -100):
|
| 546 |
+
The index in the labels to ignore when computing the loss.
|
| 547 |
+
"""
|
| 548 |
+
|
| 549 |
+
epsilon: float = 0.1
|
| 550 |
+
ignore_index: int = -100
|
| 551 |
+
|
| 552 |
+
def __call__(self, model_output, labels, shift_labels=False):
|
| 553 |
+
logits = model_output["logits"] if isinstance(model_output, dict) else model_output[0]
|
| 554 |
+
if shift_labels:
|
| 555 |
+
logits = logits[..., :-1, :].contiguous()
|
| 556 |
+
labels = labels[..., 1:].contiguous()
|
| 557 |
+
|
| 558 |
+
log_probs = -nn.functional.log_softmax(logits, dim=-1)
|
| 559 |
+
if labels.dim() == log_probs.dim() - 1:
|
| 560 |
+
labels = labels.unsqueeze(-1)
|
| 561 |
+
|
| 562 |
+
padding_mask = labels.eq(self.ignore_index)
|
| 563 |
+
# In case the ignore_index is -100, the gather will fail, so we replace labels by 0. The padding_mask
|
| 564 |
+
# will ignore them in any case.
|
| 565 |
+
labels = torch.clamp(labels, min=0)
|
| 566 |
+
nll_loss = log_probs.gather(dim=-1, index=labels)
|
| 567 |
+
# works for fp16 input tensor too, by internally upcasting it to fp32
|
| 568 |
+
smoothed_loss = log_probs.sum(dim=-1, keepdim=True, dtype=torch.float32)
|
| 569 |
+
|
| 570 |
+
nll_loss.masked_fill_(padding_mask, 0.0)
|
| 571 |
+
smoothed_loss.masked_fill_(padding_mask, 0.0)
|
| 572 |
+
|
| 573 |
+
# Take the mean over the label dimensions, then divide by the number of active elements (i.e. not-padded):
|
| 574 |
+
num_active_elements = padding_mask.numel() - padding_mask.long().sum()
|
| 575 |
+
nll_loss = nll_loss.sum() / num_active_elements
|
| 576 |
+
smoothed_loss = smoothed_loss.sum() / (num_active_elements * log_probs.shape[-1])
|
| 577 |
+
return (1 - self.epsilon) * nll_loss + self.epsilon * smoothed_loss
|
| 578 |
+
|
| 579 |
+
|
| 580 |
+
def get_length_grouped_indices(lengths, batch_size, mega_batch_mult=None, generator=None):
|
| 581 |
+
"""
|
| 582 |
+
Return a list of indices so that each slice of `batch_size` consecutive indices correspond to elements of similar
|
| 583 |
+
lengths. To do this, the indices are:
|
| 584 |
+
|
| 585 |
+
- randomly permuted
|
| 586 |
+
- grouped in mega-batches of size `mega_batch_mult * batch_size`
|
| 587 |
+
- sorted by length in each mega-batch
|
| 588 |
+
|
| 589 |
+
The result is the concatenation of all mega-batches, with the batch of `batch_size` containing the element of
|
| 590 |
+
maximum length placed first, so that an OOM happens sooner rather than later.
|
| 591 |
+
"""
|
| 592 |
+
# Default for mega_batch_mult: 50 or the number to get 4 megabatches, whichever is smaller.
|
| 593 |
+
if mega_batch_mult is None:
|
| 594 |
+
mega_batch_mult = min(len(lengths) // (batch_size * 4), 50)
|
| 595 |
+
# Just in case, for tiny datasets
|
| 596 |
+
if mega_batch_mult == 0:
|
| 597 |
+
mega_batch_mult = 1
|
| 598 |
+
|
| 599 |
+
# We need to use torch for the random part as a distributed sampler will set the random seed for torch.
|
| 600 |
+
indices = torch.randperm(len(lengths), generator=generator)
|
| 601 |
+
megabatch_size = mega_batch_mult * batch_size
|
| 602 |
+
megabatches = [indices[i : i + megabatch_size].tolist() for i in range(0, len(lengths), megabatch_size)]
|
| 603 |
+
megabatches = [sorted(megabatch, key=lambda i: lengths[i], reverse=True) for megabatch in megabatches]
|
| 604 |
+
|
| 605 |
+
# The rest is to get the biggest batch first.
|
| 606 |
+
# Since each megabatch is sorted by descending length, the longest element is the first
|
| 607 |
+
megabatch_maximums = [lengths[megabatch[0]] for megabatch in megabatches]
|
| 608 |
+
max_idx = torch.argmax(torch.tensor(megabatch_maximums)).item()
|
| 609 |
+
# Switch to put the longest element in first position
|
| 610 |
+
megabatches[0][0], megabatches[max_idx][0] = megabatches[max_idx][0], megabatches[0][0]
|
| 611 |
+
|
| 612 |
+
return [i for megabatch in megabatches for i in megabatch]
|
| 613 |
+
|
| 614 |
+
|
| 615 |
+
class LengthGroupedSampler(Sampler):
|
| 616 |
+
r"""
|
| 617 |
+
Sampler that samples indices in a way that groups together features of the dataset of roughly the same length while
|
| 618 |
+
keeping a bit of randomness.
|
| 619 |
+
"""
|
| 620 |
+
|
| 621 |
+
def __init__(
|
| 622 |
+
self,
|
| 623 |
+
batch_size: int,
|
| 624 |
+
dataset: Optional[Dataset] = None,
|
| 625 |
+
lengths: Optional[list[int]] = None,
|
| 626 |
+
model_input_name: Optional[str] = None,
|
| 627 |
+
generator=None,
|
| 628 |
+
):
|
| 629 |
+
if dataset is None and lengths is None:
|
| 630 |
+
raise ValueError("One of dataset and lengths must be provided.")
|
| 631 |
+
|
| 632 |
+
self.batch_size = batch_size
|
| 633 |
+
if lengths is None:
|
| 634 |
+
model_input_name = model_input_name if model_input_name is not None else "input_ids"
|
| 635 |
+
if not isinstance(dataset[0], (dict, BatchEncoding)) or model_input_name not in dataset[0]:
|
| 636 |
+
raise ValueError(
|
| 637 |
+
"Can only automatically infer lengths for datasets whose items are dictionaries with an "
|
| 638 |
+
f"'{model_input_name}' key."
|
| 639 |
+
)
|
| 640 |
+
lengths = [len(feature[model_input_name]) for feature in dataset]
|
| 641 |
+
elif isinstance(lengths, torch.Tensor):
|
| 642 |
+
logger.info(
|
| 643 |
+
"If lengths is a torch.Tensor, LengthGroupedSampler will be slow. Converting lengths to list[int]..."
|
| 644 |
+
)
|
| 645 |
+
lengths = lengths.tolist()
|
| 646 |
+
|
| 647 |
+
self.lengths = lengths
|
| 648 |
+
self.generator = generator
|
| 649 |
+
|
| 650 |
+
def __len__(self):
|
| 651 |
+
return len(self.lengths)
|
| 652 |
+
|
| 653 |
+
def __iter__(self):
|
| 654 |
+
indices = get_length_grouped_indices(self.lengths, self.batch_size, generator=self.generator)
|
| 655 |
+
return iter(indices)
|
| 656 |
+
|
| 657 |
+
|
| 658 |
+
class DistributedLengthGroupedSampler(DistributedSampler):
|
| 659 |
+
r"""
|
| 660 |
+
Distributed Sampler that samples indices in a way that groups together features of the dataset of roughly the same
|
| 661 |
+
length while keeping a bit of randomness.
|
| 662 |
+
"""
|
| 663 |
+
|
| 664 |
+
# Copied and adapted from PyTorch DistributedSampler.
|
| 665 |
+
def __init__(
|
| 666 |
+
self,
|
| 667 |
+
batch_size: int,
|
| 668 |
+
dataset: Optional[Dataset] = None,
|
| 669 |
+
num_replicas: Optional[int] = None,
|
| 670 |
+
rank: Optional[int] = None,
|
| 671 |
+
seed: int = 0,
|
| 672 |
+
drop_last: bool = False,
|
| 673 |
+
lengths: Optional[list[int]] = None,
|
| 674 |
+
model_input_name: Optional[str] = None,
|
| 675 |
+
):
|
| 676 |
+
if dataset is None and lengths is None:
|
| 677 |
+
raise ValueError("One of dataset and lengths must be provided.")
|
| 678 |
+
if num_replicas is None:
|
| 679 |
+
if not dist.is_available():
|
| 680 |
+
raise RuntimeError("Requires distributed package to be available")
|
| 681 |
+
num_replicas = dist.get_world_size()
|
| 682 |
+
if rank is None:
|
| 683 |
+
if not dist.is_available():
|
| 684 |
+
raise RuntimeError("Requires distributed package to be available")
|
| 685 |
+
rank = dist.get_rank()
|
| 686 |
+
|
| 687 |
+
self.batch_size = batch_size
|
| 688 |
+
self.num_replicas = num_replicas
|
| 689 |
+
self.rank = rank
|
| 690 |
+
self.epoch = 0
|
| 691 |
+
self.drop_last = drop_last
|
| 692 |
+
|
| 693 |
+
if lengths is None:
|
| 694 |
+
model_input_name = model_input_name if model_input_name is not None else "input_ids"
|
| 695 |
+
if not isinstance(dataset[0], (dict, BatchEncoding)) or model_input_name not in dataset[0]:
|
| 696 |
+
raise ValueError(
|
| 697 |
+
"Can only automatically infer lengths for datasets whose items are dictionaries with an "
|
| 698 |
+
f"'{model_input_name}' key."
|
| 699 |
+
)
|
| 700 |
+
lengths = [len(feature[model_input_name]) for feature in dataset]
|
| 701 |
+
elif isinstance(lengths, torch.Tensor):
|
| 702 |
+
logger.info(
|
| 703 |
+
"If lengths is a torch.Tensor, DistributedLengthGroupedSampler will be slow. Converting lengths to"
|
| 704 |
+
" list[int]..."
|
| 705 |
+
)
|
| 706 |
+
lengths = lengths.tolist()
|
| 707 |
+
|
| 708 |
+
self.lengths = lengths
|
| 709 |
+
|
| 710 |
+
# If the dataset length is evenly divisible by # of replicas, then there
|
| 711 |
+
# is no need to drop any data, since the dataset will be split equally.
|
| 712 |
+
if self.drop_last and len(self.lengths) % self.num_replicas != 0:
|
| 713 |
+
# Split to nearest available length that is evenly divisible.
|
| 714 |
+
# This is to ensure each rank receives the same amount of data when
|
| 715 |
+
# using this Sampler.
|
| 716 |
+
self.num_samples = math.ceil((len(self.lengths) - self.num_replicas) / self.num_replicas)
|
| 717 |
+
else:
|
| 718 |
+
self.num_samples = math.ceil(len(self.lengths) / self.num_replicas)
|
| 719 |
+
self.total_size = self.num_samples * self.num_replicas
|
| 720 |
+
self.seed = seed
|
| 721 |
+
|
| 722 |
+
def __iter__(self) -> Iterator:
|
| 723 |
+
# Deterministically shuffle based on epoch and seed
|
| 724 |
+
g = torch.Generator()
|
| 725 |
+
g.manual_seed(self.seed + self.epoch)
|
| 726 |
+
indices = get_length_grouped_indices(self.lengths, self.batch_size, generator=g)
|
| 727 |
+
|
| 728 |
+
if not self.drop_last:
|
| 729 |
+
# add extra samples to make it evenly divisible
|
| 730 |
+
indices += indices[: (self.total_size - len(indices))]
|
| 731 |
+
else:
|
| 732 |
+
# remove tail of data to make it evenly divisible
|
| 733 |
+
indices = indices[: self.total_size]
|
| 734 |
+
assert len(indices) == self.total_size
|
| 735 |
+
|
| 736 |
+
# subsample
|
| 737 |
+
indices = indices[self.rank : self.total_size : self.num_replicas]
|
| 738 |
+
assert len(indices) == self.num_samples
|
| 739 |
+
|
| 740 |
+
return iter(indices)
|
| 741 |
+
|
| 742 |
+
|
| 743 |
+
class ShardSampler(Sampler):
|
| 744 |
+
"""
|
| 745 |
+
Sampler that shards batches between several processes. Dispatches indices batch by batch: on 2 processes with batch
|
| 746 |
+
size 4, the first two batches are `[0, 1, 2, 3, 4, 5, 6, 7]` and `[8, 9, 10, 11, 12, 13, 14, 15]`, which shard into
|
| 747 |
+
`[0, 1, 2, 3]` and `[8, 9, 10, 11]` for GPU-0 and `[4, 5, 6, 7]` and `[12, 13, 14, 15]` for GPU-1.
|
| 748 |
+
|
| 749 |
+
The sampler thus yields `[0, 1, 2, 3, 8, 9, 10, 11]` on GPU-0 and `[4, 5, 6, 7, 12, 13, 14, 15]` on GPU-1.
|
| 750 |
+
"""
|
| 751 |
+
|
| 752 |
+
def __init__(
|
| 753 |
+
self,
|
| 754 |
+
dataset: Dataset,
|
| 755 |
+
batch_size: int = 1,
|
| 756 |
+
drop_last: bool = False,
|
| 757 |
+
num_processes: int = 1,
|
| 758 |
+
process_index: int = 0,
|
| 759 |
+
):
|
| 760 |
+
self.dataset = dataset
|
| 761 |
+
self.batch_size = batch_size
|
| 762 |
+
self.drop_last = drop_last
|
| 763 |
+
self.num_processes = num_processes
|
| 764 |
+
self.process_index = process_index
|
| 765 |
+
|
| 766 |
+
self.total_batch_size = total_batch_size = batch_size * num_processes
|
| 767 |
+
|
| 768 |
+
num_batches = len(dataset) // total_batch_size if drop_last else math.ceil(len(dataset) / total_batch_size)
|
| 769 |
+
self.total_num_samples = num_batches * total_batch_size
|
| 770 |
+
|
| 771 |
+
def __iter__(self):
|
| 772 |
+
indices = list(range(len(self.dataset)))
|
| 773 |
+
|
| 774 |
+
# Add extra samples to make it evenly divisible. While loop is there in the edge case we have a tiny dataset
|
| 775 |
+
# and it needs to be done several times.
|
| 776 |
+
while len(indices) < self.total_num_samples:
|
| 777 |
+
indices += indices[: (self.total_num_samples - len(indices))]
|
| 778 |
+
|
| 779 |
+
result = []
|
| 780 |
+
for batch_start in range(self.batch_size * self.process_index, self.total_num_samples, self.total_batch_size):
|
| 781 |
+
result += indices[batch_start : batch_start + self.batch_size]
|
| 782 |
+
|
| 783 |
+
return iter(result)
|
| 784 |
+
|
| 785 |
+
def __len__(self):
|
| 786 |
+
# Each shard only sees a fraction of total_num_samples.
|
| 787 |
+
return self.total_num_samples // self.num_processes
|
| 788 |
+
|
| 789 |
+
|
| 790 |
+
class IterableDatasetShard(IterableDataset):
|
| 791 |
+
"""
|
| 792 |
+
Wraps a PyTorch `IterableDataset` to generate samples for one of the processes only. Instances of this class will
|
| 793 |
+
always yield a number of samples that is a round multiple of the actual batch size (which is `batch_size x
|
| 794 |
+
num_processes`). Depending on the value of the `drop_last` attribute, it will either stop the iteration at the
|
| 795 |
+
first batch that would be too small or loop with indices from the beginning.
|
| 796 |
+
|
| 797 |
+
On two processes with an iterable dataset yielding of `[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]` with a batch size of
|
| 798 |
+
2:
|
| 799 |
+
|
| 800 |
+
- the shard on process 0 will yield `[0, 1, 4, 5, 8, 9]` so will see batches `[0, 1]`, `[4, 5]`, `[8, 9]`
|
| 801 |
+
- the shard on process 1 will yield `[2, 3, 6, 7, 10, 11]` so will see batches `[2, 3]`, `[6, 7]`, `[10, 11]`
|
| 802 |
+
|
| 803 |
+
<Tip warning={true}>
|
| 804 |
+
|
| 805 |
+
If your IterableDataset implements some randomization that needs to be applied the same way on all processes
|
| 806 |
+
(for instance, a shuffling), you should use a `torch.Generator` in a `generator` attribute of the `dataset` to
|
| 807 |
+
generate your random numbers and call the [`~trainer_pt_utils.IterableDatasetShard.set_epoch`] method of this
|
| 808 |
+
object. It will set the seed of this `generator` to `seed + epoch` on all processes before starting the
|
| 809 |
+
iteration. Alternatively, you can also implement a `set_epoch()` method in your iterable dataset to deal with
|
| 810 |
+
this.
|
| 811 |
+
|
| 812 |
+
</Tip>
|
| 813 |
+
|
| 814 |
+
Args:
|
| 815 |
+
dataset (`torch.utils.data.IterableDataset`):
|
| 816 |
+
The batch sampler to split in several shards.
|
| 817 |
+
batch_size (`int`, *optional*, defaults to 1):
|
| 818 |
+
The size of the batches per shard.
|
| 819 |
+
drop_last (`bool`, *optional*, defaults to `False`):
|
| 820 |
+
Whether or not to drop the last incomplete batch or complete the last batches by using the samples from the
|
| 821 |
+
beginning.
|
| 822 |
+
num_processes (`int`, *optional*, defaults to 1):
|
| 823 |
+
The number of processes running concurrently.
|
| 824 |
+
process_index (`int`, *optional*, defaults to 0):
|
| 825 |
+
The index of the current process.
|
| 826 |
+
seed (`int`, *optional*, defaults to 0):
|
| 827 |
+
A random seed that will be used for the random number generation in
|
| 828 |
+
[`~trainer_pt_utils.IterableDatasetShard.set_epoch`].
|
| 829 |
+
"""
|
| 830 |
+
|
| 831 |
+
def __init__(
|
| 832 |
+
self,
|
| 833 |
+
dataset: IterableDataset,
|
| 834 |
+
batch_size: int = 1,
|
| 835 |
+
drop_last: bool = False,
|
| 836 |
+
num_processes: int = 1,
|
| 837 |
+
process_index: int = 0,
|
| 838 |
+
seed: int = 0,
|
| 839 |
+
):
|
| 840 |
+
self.dataset = dataset
|
| 841 |
+
self.batch_size = batch_size
|
| 842 |
+
self.drop_last = drop_last
|
| 843 |
+
self.num_processes = num_processes
|
| 844 |
+
self.process_index = process_index
|
| 845 |
+
self.seed = seed
|
| 846 |
+
self.epoch = 0
|
| 847 |
+
self.num_examples = 0
|
| 848 |
+
|
| 849 |
+
def set_epoch(self, epoch):
|
| 850 |
+
self.epoch = epoch
|
| 851 |
+
if hasattr(self.dataset, "set_epoch"):
|
| 852 |
+
self.dataset.set_epoch(epoch)
|
| 853 |
+
|
| 854 |
+
def __iter__(self):
|
| 855 |
+
self.num_examples = 0
|
| 856 |
+
if (
|
| 857 |
+
not hasattr(self.dataset, "set_epoch")
|
| 858 |
+
and hasattr(self.dataset, "generator")
|
| 859 |
+
and isinstance(self.dataset.generator, torch.Generator)
|
| 860 |
+
):
|
| 861 |
+
self.dataset.generator.manual_seed(self.seed + self.epoch)
|
| 862 |
+
real_batch_size = self.batch_size * self.num_processes
|
| 863 |
+
process_slice = range(self.process_index * self.batch_size, (self.process_index + 1) * self.batch_size)
|
| 864 |
+
|
| 865 |
+
first_batch = None
|
| 866 |
+
current_batch = []
|
| 867 |
+
for element in self.dataset:
|
| 868 |
+
self.num_examples += 1
|
| 869 |
+
current_batch.append(element)
|
| 870 |
+
# Wait to have a full batch before yielding elements.
|
| 871 |
+
if len(current_batch) == real_batch_size:
|
| 872 |
+
for i in process_slice:
|
| 873 |
+
yield current_batch[i]
|
| 874 |
+
if first_batch is None:
|
| 875 |
+
first_batch = current_batch.copy()
|
| 876 |
+
current_batch = []
|
| 877 |
+
|
| 878 |
+
# Finished if drop_last is True, otherwise complete the last batch with elements from the beginning.
|
| 879 |
+
if not self.drop_last and len(current_batch) > 0:
|
| 880 |
+
if first_batch is None:
|
| 881 |
+
first_batch = current_batch.copy()
|
| 882 |
+
while len(current_batch) < real_batch_size:
|
| 883 |
+
current_batch += first_batch
|
| 884 |
+
for i in process_slice:
|
| 885 |
+
yield current_batch[i]
|
| 886 |
+
|
| 887 |
+
def __len__(self):
|
| 888 |
+
# Will raise an error if the underlying dataset is not sized.
|
| 889 |
+
if self.drop_last:
|
| 890 |
+
return (len(self.dataset) // (self.batch_size * self.num_processes)) * self.batch_size
|
| 891 |
+
else:
|
| 892 |
+
return math.ceil(len(self.dataset) / (self.batch_size * self.num_processes)) * self.batch_size
|
| 893 |
+
|
| 894 |
+
|
| 895 |
+
# In order to keep `trainer.py` compact and easy to understand, place any secondary PT Trainer
|
| 896 |
+
# helper methods here
|
| 897 |
+
|
| 898 |
+
|
| 899 |
+
def _get_learning_rate(self):
|
| 900 |
+
if self.is_deepspeed_enabled:
|
| 901 |
+
# with deepspeed's fp16 and dynamic loss scale enabled the optimizer/scheduler steps may
|
| 902 |
+
# not run for the first few dozen steps while loss scale is too large, and thus during
|
| 903 |
+
# that time `get_last_lr` will fail if called during that warm up stage, so work around it:
|
| 904 |
+
try:
|
| 905 |
+
last_lr = self.lr_scheduler.get_last_lr()[0]
|
| 906 |
+
except AssertionError as e:
|
| 907 |
+
if "need to call step" in str(e):
|
| 908 |
+
logger.warning("tried to get lr value before scheduler/optimizer started stepping, returning lr=0")
|
| 909 |
+
last_lr = 0
|
| 910 |
+
else:
|
| 911 |
+
raise
|
| 912 |
+
else:
|
| 913 |
+
if isinstance(self.lr_scheduler, torch.optim.lr_scheduler.ReduceLROnPlateau):
|
| 914 |
+
last_lr = self.optimizer.param_groups[0]["lr"]
|
| 915 |
+
else:
|
| 916 |
+
last_lr = self.lr_scheduler.get_last_lr()[0]
|
| 917 |
+
|
| 918 |
+
if torch.is_tensor(last_lr):
|
| 919 |
+
last_lr = last_lr.item()
|
| 920 |
+
return last_lr
|
| 921 |
+
|
| 922 |
+
|
| 923 |
+
def _secs2timedelta(secs):
|
| 924 |
+
"""
|
| 925 |
+
Convert seconds to hh:mm:ss.msec, msecs rounded to 2 decimal places.
|
| 926 |
+
"""
|
| 927 |
+
|
| 928 |
+
msec = int(abs(secs - int(secs)) * 100)
|
| 929 |
+
return f"{datetime.timedelta(seconds=int(secs))}.{msec:02d}"
|
| 930 |
+
|
| 931 |
+
|
| 932 |
+
def metrics_format(metrics: dict[str, float]) -> dict[str, float]:
|
| 933 |
+
"""
|
| 934 |
+
Reformat Trainer metrics values to a human-readable format.
|
| 935 |
+
|
| 936 |
+
Args:
|
| 937 |
+
metrics (`dict[str, float]`):
|
| 938 |
+
The metrics returned from train/evaluate/predict
|
| 939 |
+
|
| 940 |
+
Returns:
|
| 941 |
+
metrics (`dict[str, float]`): The reformatted metrics
|
| 942 |
+
"""
|
| 943 |
+
|
| 944 |
+
metrics_copy = metrics.copy()
|
| 945 |
+
for k, v in metrics_copy.items():
|
| 946 |
+
if "_mem_" in k:
|
| 947 |
+
metrics_copy[k] = f"{v >> 20}MB"
|
| 948 |
+
elif "_runtime" in k:
|
| 949 |
+
metrics_copy[k] = _secs2timedelta(v)
|
| 950 |
+
elif k == "total_flos":
|
| 951 |
+
metrics_copy[k] = f"{int(v) >> 30}GF"
|
| 952 |
+
elif isinstance(metrics_copy[k], float):
|
| 953 |
+
metrics_copy[k] = round(v, 4)
|
| 954 |
+
|
| 955 |
+
return metrics_copy
|
| 956 |
+
|
| 957 |
+
|
| 958 |
+
def log_metrics(self, split, metrics):
|
| 959 |
+
"""
|
| 960 |
+
Log metrics in a specially formatted way.
|
| 961 |
+
|
| 962 |
+
Under distributed environment this is done only for a process with rank 0.
|
| 963 |
+
|
| 964 |
+
Args:
|
| 965 |
+
split (`str`):
|
| 966 |
+
Mode/split name: one of `train`, `eval`, `test`
|
| 967 |
+
metrics (`dict[str, float]`):
|
| 968 |
+
The metrics returned from train/evaluate/predictmetrics: metrics dict
|
| 969 |
+
|
| 970 |
+
Notes on memory reports:
|
| 971 |
+
|
| 972 |
+
In order to get memory usage report you need to install `psutil`. You can do that with `pip install psutil`.
|
| 973 |
+
|
| 974 |
+
Now when this method is run, you will see a report that will include:
|
| 975 |
+
|
| 976 |
+
```
|
| 977 |
+
init_mem_cpu_alloc_delta = 1301MB
|
| 978 |
+
init_mem_cpu_peaked_delta = 154MB
|
| 979 |
+
init_mem_gpu_alloc_delta = 230MB
|
| 980 |
+
init_mem_gpu_peaked_delta = 0MB
|
| 981 |
+
train_mem_cpu_alloc_delta = 1345MB
|
| 982 |
+
train_mem_cpu_peaked_delta = 0MB
|
| 983 |
+
train_mem_gpu_alloc_delta = 693MB
|
| 984 |
+
train_mem_gpu_peaked_delta = 7MB
|
| 985 |
+
```
|
| 986 |
+
|
| 987 |
+
**Understanding the reports:**
|
| 988 |
+
|
| 989 |
+
- the first segment, e.g., `train__`, tells you which stage the metrics are for. Reports starting with `init_`
|
| 990 |
+
will be added to the first stage that gets run. So that if only evaluation is run, the memory usage for the
|
| 991 |
+
`__init__` will be reported along with the `eval_` metrics.
|
| 992 |
+
- the third segment, is either `cpu` or `gpu`, tells you whether it's the general RAM or the gpu0 memory
|
| 993 |
+
metric.
|
| 994 |
+
- `*_alloc_delta` - is the difference in the used/allocated memory counter between the end and the start of the
|
| 995 |
+
stage - it can be negative if a function released more memory than it allocated.
|
| 996 |
+
- `*_peaked_delta` - is any extra memory that was consumed and then freed - relative to the current allocated
|
| 997 |
+
memory counter - it is never negative. When you look at the metrics of any stage you add up `alloc_delta` +
|
| 998 |
+
`peaked_delta` and you know how much memory was needed to complete that stage.
|
| 999 |
+
|
| 1000 |
+
The reporting happens only for process of rank 0 and gpu 0 (if there is a gpu). Typically this is enough since the
|
| 1001 |
+
main process does the bulk of work, but it could be not quite so if model parallel is used and then other GPUs may
|
| 1002 |
+
use a different amount of gpu memory. This is also not the same under DataParallel where gpu0 may require much more
|
| 1003 |
+
memory than the rest since it stores the gradient and optimizer states for all participating GPUs. Perhaps in the
|
| 1004 |
+
future these reports will evolve to measure those too.
|
| 1005 |
+
|
| 1006 |
+
The CPU RAM metric measures RSS (Resident Set Size) includes both the memory which is unique to the process and the
|
| 1007 |
+
memory shared with other processes. It is important to note that it does not include swapped out memory, so the
|
| 1008 |
+
reports could be imprecise.
|
| 1009 |
+
|
| 1010 |
+
The CPU peak memory is measured using a sampling thread. Due to python's GIL it may miss some of the peak memory if
|
| 1011 |
+
that thread didn't get a chance to run when the highest memory was used. Therefore this report can be less than
|
| 1012 |
+
reality. Using `tracemalloc` would have reported the exact peak memory, but it doesn't report memory allocations
|
| 1013 |
+
outside of python. So if some C++ CUDA extension allocated its own memory it won't be reported. And therefore it
|
| 1014 |
+
was dropped in favor of the memory sampling approach, which reads the current process memory usage.
|
| 1015 |
+
|
| 1016 |
+
The GPU allocated and peak memory reporting is done with `torch.cuda.memory_allocated()` and
|
| 1017 |
+
`torch.cuda.max_memory_allocated()`. This metric reports only "deltas" for pytorch-specific allocations, as
|
| 1018 |
+
`torch.cuda` memory management system doesn't track any memory allocated outside of pytorch. For example, the very
|
| 1019 |
+
first cuda call typically loads CUDA kernels, which may take from 0.5 to 2GB of GPU memory.
|
| 1020 |
+
|
| 1021 |
+
Note that this tracker doesn't account for memory allocations outside of [`Trainer`]'s `__init__`, `train`,
|
| 1022 |
+
`evaluate` and `predict` calls.
|
| 1023 |
+
|
| 1024 |
+
Because `evaluation` calls may happen during `train`, we can't handle nested invocations because
|
| 1025 |
+
`torch.cuda.max_memory_allocated` is a single counter, so if it gets reset by a nested eval call, `train`'s tracker
|
| 1026 |
+
will report incorrect info. If this [pytorch issue](https://github.com/pytorch/pytorch/issues/16266) gets resolved
|
| 1027 |
+
it will be possible to change this class to be re-entrant. Until then we will only track the outer level of
|
| 1028 |
+
`train`, `evaluate` and `predict` methods. Which means that if `eval` is called during `train`, it's the latter
|
| 1029 |
+
that will account for its memory usage and that of the former.
|
| 1030 |
+
|
| 1031 |
+
This also means that if any other tool that is used along the [`Trainer`] calls
|
| 1032 |
+
`torch.cuda.reset_peak_memory_stats`, the gpu peak memory stats could be invalid. And the [`Trainer`] will disrupt
|
| 1033 |
+
the normal behavior of any such tools that rely on calling `torch.cuda.reset_peak_memory_stats` themselves.
|
| 1034 |
+
|
| 1035 |
+
For best performance you may want to consider turning the memory profiling off for production runs.
|
| 1036 |
+
"""
|
| 1037 |
+
if not self.is_world_process_zero():
|
| 1038 |
+
return
|
| 1039 |
+
|
| 1040 |
+
print(f"***** {split} metrics *****")
|
| 1041 |
+
metrics_formatted = metrics_format(metrics)
|
| 1042 |
+
k_width = max(len(str(x)) for x in metrics_formatted)
|
| 1043 |
+
v_width = max(len(str(x)) for x in metrics_formatted.values())
|
| 1044 |
+
for key in sorted(metrics_formatted.keys()):
|
| 1045 |
+
print(f" {key: <{k_width}} = {metrics_formatted[key]:>{v_width}}")
|
| 1046 |
+
|
| 1047 |
+
|
| 1048 |
+
def save_metrics(self, split, metrics, combined=True):
|
| 1049 |
+
"""
|
| 1050 |
+
Save metrics into a json file for that split, e.g. `train_results.json`.
|
| 1051 |
+
|
| 1052 |
+
Under distributed environment this is done only for a process with rank 0.
|
| 1053 |
+
|
| 1054 |
+
Args:
|
| 1055 |
+
split (`str`):
|
| 1056 |
+
Mode/split name: one of `train`, `eval`, `test`, `all`
|
| 1057 |
+
metrics (`dict[str, float]`):
|
| 1058 |
+
The metrics returned from train/evaluate/predict
|
| 1059 |
+
combined (`bool`, *optional*, defaults to `True`):
|
| 1060 |
+
Creates combined metrics by updating `all_results.json` with metrics of this call
|
| 1061 |
+
|
| 1062 |
+
To understand the metrics please read the docstring of [`~Trainer.log_metrics`]. The only difference is that raw
|
| 1063 |
+
unformatted numbers are saved in the current method.
|
| 1064 |
+
|
| 1065 |
+
"""
|
| 1066 |
+
if not self.is_world_process_zero():
|
| 1067 |
+
return
|
| 1068 |
+
|
| 1069 |
+
path = os.path.join(self.args.output_dir, f"{split}_results.json")
|
| 1070 |
+
with open(path, "w") as f:
|
| 1071 |
+
json.dump(metrics, f, indent=4, sort_keys=True)
|
| 1072 |
+
|
| 1073 |
+
if combined:
|
| 1074 |
+
path = os.path.join(self.args.output_dir, "all_results.json")
|
| 1075 |
+
if os.path.exists(path):
|
| 1076 |
+
with open(path) as f:
|
| 1077 |
+
all_metrics = json.load(f)
|
| 1078 |
+
else:
|
| 1079 |
+
all_metrics = {}
|
| 1080 |
+
|
| 1081 |
+
all_metrics.update(metrics)
|
| 1082 |
+
with open(path, "w") as f:
|
| 1083 |
+
json.dump(all_metrics, f, indent=4, sort_keys=True)
|
| 1084 |
+
|
| 1085 |
+
|
| 1086 |
+
def save_state(self):
|
| 1087 |
+
"""
|
| 1088 |
+
Saves the Trainer state, since Trainer.save_model saves only the tokenizer with the model.
|
| 1089 |
+
|
| 1090 |
+
Under distributed environment this is done only for a process with rank 0.
|
| 1091 |
+
"""
|
| 1092 |
+
if not self.is_world_process_zero():
|
| 1093 |
+
return
|
| 1094 |
+
|
| 1095 |
+
path = os.path.join(self.args.output_dir, "trainer_state.json")
|
| 1096 |
+
self.state.save_to_json(path)
|
| 1097 |
+
|
| 1098 |
+
|
| 1099 |
+
def get_model_param_count(model, trainable_only=False):
|
| 1100 |
+
"""
|
| 1101 |
+
Calculate model's total param count. If trainable_only is True then count only those requiring grads.
|
| 1102 |
+
"""
|
| 1103 |
+
if is_deepspeed_zero3_enabled():
|
| 1104 |
+
|
| 1105 |
+
def numel(p):
|
| 1106 |
+
return p.ds_numel if hasattr(p, "ds_numel") else p.numel()
|
| 1107 |
+
|
| 1108 |
+
else:
|
| 1109 |
+
|
| 1110 |
+
def numel(p):
|
| 1111 |
+
return p.numel()
|
| 1112 |
+
|
| 1113 |
+
return sum(numel(p) for p in model.parameters() if not trainable_only or p.requires_grad)
|
| 1114 |
+
|
| 1115 |
+
|
| 1116 |
+
def get_parameter_names(model, forbidden_layer_types, forbidden_layer_names=None):
|
| 1117 |
+
"""
|
| 1118 |
+
Returns the names of the model parameters that are not inside a forbidden layer.
|
| 1119 |
+
"""
|
| 1120 |
+
forbidden_layer_patterns = (
|
| 1121 |
+
[re.compile(pattern) for pattern in forbidden_layer_names] if forbidden_layer_names is not None else []
|
| 1122 |
+
)
|
| 1123 |
+
result = []
|
| 1124 |
+
for name, child in model.named_children():
|
| 1125 |
+
child_params = get_parameter_names(child, forbidden_layer_types, forbidden_layer_names)
|
| 1126 |
+
result += [
|
| 1127 |
+
f"{name}.{n}"
|
| 1128 |
+
for n in child_params
|
| 1129 |
+
if not isinstance(child, tuple(forbidden_layer_types))
|
| 1130 |
+
and not any(pattern.search(f"{name}.{n}".lower()) for pattern in forbidden_layer_patterns)
|
| 1131 |
+
]
|
| 1132 |
+
# Add model specific parameters that are not in any child
|
| 1133 |
+
result += [
|
| 1134 |
+
k for k in model._parameters if not any(pattern.search(k.lower()) for pattern in forbidden_layer_patterns)
|
| 1135 |
+
]
|
| 1136 |
+
|
| 1137 |
+
return result
|
| 1138 |
+
|
| 1139 |
+
|
| 1140 |
+
def get_module_class_from_name(module, name):
|
| 1141 |
+
"""
|
| 1142 |
+
Gets a class from a module by its name.
|
| 1143 |
+
|
| 1144 |
+
Args:
|
| 1145 |
+
module (`torch.nn.Module`): The module to get the class from.
|
| 1146 |
+
name (`str`): The name of the class.
|
| 1147 |
+
"""
|
| 1148 |
+
modules_children = list(module.children())
|
| 1149 |
+
if module.__class__.__name__ == name:
|
| 1150 |
+
return module.__class__
|
| 1151 |
+
elif len(modules_children) == 0:
|
| 1152 |
+
return
|
| 1153 |
+
else:
|
| 1154 |
+
for child_module in modules_children:
|
| 1155 |
+
module_class = get_module_class_from_name(child_module, name)
|
| 1156 |
+
if module_class is not None:
|
| 1157 |
+
return module_class
|
| 1158 |
+
|
| 1159 |
+
|
| 1160 |
+
def remove_dummy_checkpoint(is_main_process, output_dir, filenames):
|
| 1161 |
+
if is_main_process:
|
| 1162 |
+
for filename in filenames:
|
| 1163 |
+
file = os.path.join(output_dir, filename)
|
| 1164 |
+
if os.path.isfile(file):
|
| 1165 |
+
os.remove(file)
|
| 1166 |
+
|
| 1167 |
+
|
| 1168 |
+
if is_sagemaker_mp_enabled():
|
| 1169 |
+
import smdistributed.modelparallel.torch as smp
|
| 1170 |
+
|
| 1171 |
+
@smp.step()
|
| 1172 |
+
def smp_forward_backward(model, inputs, gradient_accumulation_steps=1):
|
| 1173 |
+
outputs = model(**inputs)
|
| 1174 |
+
loss = outputs["loss"] if isinstance(outputs, dict) else outputs[0]
|
| 1175 |
+
loss /= gradient_accumulation_steps
|
| 1176 |
+
model.backward(loss)
|
| 1177 |
+
return loss
|
| 1178 |
+
|
| 1179 |
+
@smp.step()
|
| 1180 |
+
def smp_forward_only(model, inputs):
|
| 1181 |
+
return model(**inputs)
|
| 1182 |
+
|
| 1183 |
+
def smp_gather(tensor):
|
| 1184 |
+
if isinstance(tensor, (list, tuple)):
|
| 1185 |
+
return type(tensor)(smp_gather(t) for t in tensor)
|
| 1186 |
+
elif isinstance(tensor, dict):
|
| 1187 |
+
return type(tensor)({k: smp_gather(v) for k, v in tensor.items()})
|
| 1188 |
+
elif not isinstance(tensor, torch.Tensor):
|
| 1189 |
+
raise TypeError(
|
| 1190 |
+
f"Can't gather the values of type {type(tensor)}, only of nested list/tuple/dicts of tensors."
|
| 1191 |
+
)
|
| 1192 |
+
all_tensors = smp.allgather(tensor, smp.CommGroup.DP_GROUP)
|
| 1193 |
+
all_tensors = [atleast_1d(t) for t in all_tensors]
|
| 1194 |
+
return torch.cat([t.cpu() for t in all_tensors], dim=0)
|
| 1195 |
+
|
| 1196 |
+
def smp_nested_concat(tensor):
|
| 1197 |
+
if isinstance(tensor, (list, tuple)):
|
| 1198 |
+
return type(tensor)(smp_nested_concat(t) for t in tensor)
|
| 1199 |
+
elif isinstance(tensor, dict):
|
| 1200 |
+
return type(tensor)({k: smp_nested_concat(v) for k, v in tensor.items()})
|
| 1201 |
+
# It doesn't seem possible to check here if `tensor` is a StepOutput because StepOutput lives in `smp.step`
|
| 1202 |
+
# which is also the name of the decorator so Python is confused.
|
| 1203 |
+
return tensor.detach().concat().cpu()
|
| 1204 |
+
|
| 1205 |
+
|
| 1206 |
+
@dataclass
|
| 1207 |
+
class AcceleratorConfig:
|
| 1208 |
+
"""
|
| 1209 |
+
A subset of arguments relating to the underlying [`accelerate.Accelerator`]
|
| 1210 |
+
implementation utilized in the `Trainer` that can be customized.
|
| 1211 |
+
Mostly relating to data.
|
| 1212 |
+
|
| 1213 |
+
Parameters:
|
| 1214 |
+
split_batches (`bool`, *optional*, defaults to `False`):
|
| 1215 |
+
Whether or not the accelerator should split the batches yielded by the dataloaders across the devices. If
|
| 1216 |
+
`True` the actual batch size used will be the same on any kind of distributed processes, but it must be a
|
| 1217 |
+
round multiple of the `num_processes` you are using. If `False`, actual batch size used will be the one set
|
| 1218 |
+
in your script multiplied by the number of processes.
|
| 1219 |
+
dispatch_batches (`bool`, *optional*):
|
| 1220 |
+
If set to `True`, the dataloader prepared by the Accelerator is only iterated through on the main process
|
| 1221 |
+
and then the batches are split and broadcast to each process. Will default to `True` for `DataLoader` whose
|
| 1222 |
+
underlying dataset is an `IterableDataset`, `False` otherwise.
|
| 1223 |
+
even_batches (`bool`, *optional*, defaults to `True`):
|
| 1224 |
+
If set to `True`, in cases where the total batch size across all processes does not exactly divide the
|
| 1225 |
+
dataset, samples at the start of the dataset will be duplicated so the batch can be divided equally among
|
| 1226 |
+
all workers.
|
| 1227 |
+
use_seedable_sampler (`bool`, *optional*, defaults to `True`):
|
| 1228 |
+
Whether or not use a fully seedable random sampler ([`accelerate.data_loader.SeedableRandomSampler`]). Ensures
|
| 1229 |
+
training results are fully reproducible using a different sampling technique. While seed-to-seed results
|
| 1230 |
+
may differ, on average the differences are negligible when using multiple different seeds to compare. Should
|
| 1231 |
+
also be ran with [`~utils.set_seed`] for the best results.
|
| 1232 |
+
gradient_accumulation_kwargs (`dict`, *optional*):
|
| 1233 |
+
Additional kwargs to configure gradient accumulation, see [`accelerate.utils.GradientAccumulationPlugin`].
|
| 1234 |
+
Any of the following (optional) keys are acceptable:
|
| 1235 |
+
num_steps (`int`): Will take precedence over [`~.TrainingArguments.gradient_accumulation_steps`] if
|
| 1236 |
+
the latter is set to 1, otherwise an exception will be raised.
|
| 1237 |
+
adjust_scheduler (`bool`): Whether to adjust the scheduler steps to account for [`~.TrainingArguments.gradient_accumulation_steps`].
|
| 1238 |
+
The [`accelerate.utils.GradientAccumulationPlugin`] default is `True`.
|
| 1239 |
+
sync_each_batch (`bool`): Whether to synchronize the gradients at each data batch.
|
| 1240 |
+
The [`accelerate.utils.GradientAccumulationPlugin`] default is `False`.
|
| 1241 |
+
non_blocking (`bool`, *optional*, defaults to `False`):
|
| 1242 |
+
Whether to use non-blocking CUDA calls to help minimize synchronization during
|
| 1243 |
+
distributed training with prepared `DataLoader` inputs being moved to device.
|
| 1244 |
+
Best if used with `pin_memory=True` in the `TrainingArguments`.
|
| 1245 |
+
use_configured_state (`bool*, *optional*, defaults to `False`):
|
| 1246 |
+
Whether or not to use a pre-configured `AcceleratorState` or `PartialState` defined
|
| 1247 |
+
before calling `TrainingArguments`. If `True`, an `Accelerator` or `PartialState`
|
| 1248 |
+
must be initialized. May lead to issues using sweeps or hyperparameter tuning.
|
| 1249 |
+
|
| 1250 |
+
"""
|
| 1251 |
+
|
| 1252 |
+
# Data related arguments
|
| 1253 |
+
split_batches: bool = field(
|
| 1254 |
+
default=False,
|
| 1255 |
+
metadata={
|
| 1256 |
+
"help": "Whether or not the accelerator should split the batches yielded by the dataloaders across the devices. If"
|
| 1257 |
+
" `True` the actual batch size used will be the same on any kind of distributed processes, but it must be a"
|
| 1258 |
+
" round multiple of the `num_processes` you are using. If `False`, actual batch size used will be the one set"
|
| 1259 |
+
" in your script multiplied by the number of processes."
|
| 1260 |
+
},
|
| 1261 |
+
)
|
| 1262 |
+
dispatch_batches: Optional[bool] = field(
|
| 1263 |
+
default=None,
|
| 1264 |
+
metadata={
|
| 1265 |
+
"help": "If set to `True`, the dataloader prepared by the Accelerator is only iterated through on the main process"
|
| 1266 |
+
" and then the batches are split and broadcast to each process. Will default to `True` for `DataLoader` whose"
|
| 1267 |
+
" underlying dataset is an `IterableDataslet`, `False` otherwise."
|
| 1268 |
+
},
|
| 1269 |
+
)
|
| 1270 |
+
even_batches: bool = field(
|
| 1271 |
+
default=True,
|
| 1272 |
+
metadata={
|
| 1273 |
+
"help": "If set to `True`, in cases where the total batch size across all processes does not exactly divide the"
|
| 1274 |
+
" dataset, samples at the start of the dataset will be duplicated so the batch can be divided equally among"
|
| 1275 |
+
" all workers."
|
| 1276 |
+
},
|
| 1277 |
+
)
|
| 1278 |
+
use_seedable_sampler: bool = field(
|
| 1279 |
+
default=True,
|
| 1280 |
+
metadata={
|
| 1281 |
+
"help": "Whether or not use a fully seedable random sampler ([`accelerate.data_loader.SeedableRandomSampler`])."
|
| 1282 |
+
"Ensures training results are fully reproducible using a different sampling technique. "
|
| 1283 |
+
"While seed-to-seed results may differ, on average the differences are negligible when using"
|
| 1284 |
+
"multiple different seeds to compare. Should also be ran with [`~utils.set_seed`] for the best results."
|
| 1285 |
+
},
|
| 1286 |
+
)
|
| 1287 |
+
|
| 1288 |
+
non_blocking: bool = field(
|
| 1289 |
+
default=False,
|
| 1290 |
+
metadata={
|
| 1291 |
+
"help": "Whether to use non-blocking CUDA calls to help minimize synchronization during "
|
| 1292 |
+
"distributed training with prepared `DataLoader` inputs being moved to device. "
|
| 1293 |
+
"Best if used with `pin_memory=True` in the `TrainingArguments`. Requires accelerate "
|
| 1294 |
+
"v0.30.0."
|
| 1295 |
+
},
|
| 1296 |
+
)
|
| 1297 |
+
|
| 1298 |
+
gradient_accumulation_kwargs: Optional[dict] = field(
|
| 1299 |
+
default=None,
|
| 1300 |
+
metadata={
|
| 1301 |
+
"help": "Additional kwargs to configure gradient accumulation, see [`accelerate.utils.GradientAccumulationPlugin`]. "
|
| 1302 |
+
"Any of the following (optional) keys are acceptable: "
|
| 1303 |
+
" num_steps (`int`): Will take precedence over [`~.TrainingArguments.gradient_accumulation_steps`] if "
|
| 1304 |
+
" the latter is set to 1, otherwise an exception will be raised. "
|
| 1305 |
+
" adjust_scheduler (`bool`): Whether to adjust the scheduler steps to account for [`~.TrainingArguments.gradient_accumulation_steps`]. "
|
| 1306 |
+
" The [`accelerate.utils.GradientAccumulationPlugin`] default is `True`. "
|
| 1307 |
+
" sync_each_batch (`bool`): Whether to synchronize the gradients at each data batch. "
|
| 1308 |
+
" The [`accelerate.utils.GradientAccumulationPlugin`] default is `False`."
|
| 1309 |
+
},
|
| 1310 |
+
)
|
| 1311 |
+
use_configured_state: bool = field(
|
| 1312 |
+
default=False,
|
| 1313 |
+
metadata={
|
| 1314 |
+
"help": "Whether or not to use a pre-configured `AcceleratorState` or `PartialState` defined before calling `TrainingArguments`."
|
| 1315 |
+
"If `True`, an `Accelerator` or `PartialState` must be initialized. May lead to issues using sweeps or hyperparameter tuning."
|
| 1316 |
+
},
|
| 1317 |
+
)
|
| 1318 |
+
|
| 1319 |
+
@classmethod
|
| 1320 |
+
def from_json_file(cls, json_file):
|
| 1321 |
+
# Check if exists
|
| 1322 |
+
open_file = io.open if os.path.exists(json_file) else open
|
| 1323 |
+
with open_file(json_file, "r", encoding="utf-8") as f:
|
| 1324 |
+
config_dict = json.load(f)
|
| 1325 |
+
# Check for keys and load sensible defaults
|
| 1326 |
+
extra_keys = sorted(key for key in config_dict if key not in cls.__dataclass_fields__)
|
| 1327 |
+
if len(extra_keys) > 0:
|
| 1328 |
+
raise ValueError(
|
| 1329 |
+
f"The config file at {json_file} had unknown keys ({extra_keys}), please try upgrading your `transformers`"
|
| 1330 |
+
" version or fix (and potentially remove these keys) from your config file."
|
| 1331 |
+
)
|
| 1332 |
+
return cls(**config_dict)
|
| 1333 |
+
|
| 1334 |
+
def to_dict(self):
|
| 1335 |
+
return copy.deepcopy(self.__dict__)
|
| 1336 |
+
|
| 1337 |
+
def pop(self, key, default=None):
|
| 1338 |
+
return self.__dict__.pop(key, default)
|
| 1339 |
+
|
| 1340 |
+
|
| 1341 |
+
class LayerWiseDummyOptimizer(torch.optim.Optimizer):
|
| 1342 |
+
"""
|
| 1343 |
+
For Layer-wise optimizers such as GaLoRE optimizer, the optimization
|
| 1344 |
+
step is already done through the post gradient hooks. Therefore
|
| 1345 |
+
the trick is to create a dummy optimizer that can take arbitrary
|
| 1346 |
+
args and kwargs and return a no-op during training.
|
| 1347 |
+
|
| 1348 |
+
Initial idea from @hiyouga in LLaMA-Factory:
|
| 1349 |
+
https://github.com/hiyouga/LLaMA-Factory/commit/8664262cde3919e10eaecbd66e8c5d356856362e#diff-ebe08ab14496dfb9e06075f0fdd36799ef6d1535cc4dd4715b74c4e3e06fe3ba
|
| 1350 |
+
"""
|
| 1351 |
+
|
| 1352 |
+
def __init__(self, optimizer_dict=None, **kwargs):
|
| 1353 |
+
dummy_tensor = torch.randn(1, 1)
|
| 1354 |
+
self.optimizer_dict = optimizer_dict
|
| 1355 |
+
super().__init__([dummy_tensor], {"lr": kwargs.get("lr", 1e-03)})
|
| 1356 |
+
|
| 1357 |
+
def zero_grad(self, set_to_none: bool = True) -> None:
|
| 1358 |
+
pass
|
| 1359 |
+
|
| 1360 |
+
def step(self, closure=None) -> Optional[float]:
|
| 1361 |
+
pass
|
| 1362 |
+
|
| 1363 |
+
|
| 1364 |
+
class LayerWiseDummyScheduler(LRScheduler):
|
| 1365 |
+
"""
|
| 1366 |
+
For Layer-wise optimizers such as GaLoRE optimizer, the optimization and scheduling step
|
| 1367 |
+
are already done through the post gradient hooks. Therefore
|
| 1368 |
+
the trick is to create a dummy scheduler that can take arbitrary
|
| 1369 |
+
args and kwargs and return a no-op during training.
|
| 1370 |
+
"""
|
| 1371 |
+
|
| 1372 |
+
def __init__(self, *args, **kwargs):
|
| 1373 |
+
self.default_lr = kwargs["lr"]
|
| 1374 |
+
optimizer = LayerWiseDummyOptimizer(**kwargs)
|
| 1375 |
+
last_epoch = -1
|
| 1376 |
+
super().__init__(optimizer, last_epoch)
|
| 1377 |
+
|
| 1378 |
+
def get_lr(self):
|
| 1379 |
+
# default value
|
| 1380 |
+
lrs = [self.default_lr]
|
| 1381 |
+
|
| 1382 |
+
# we take each lr in the parameters if they exist, assumes the optimizer to be the `LayerWiseDummyOptimizer`
|
| 1383 |
+
if self.optimizer is not None:
|
| 1384 |
+
param_wise_lrs = [
|
| 1385 |
+
[group["lr"] for group in optim.param_groups] for optim in self.optimizer.optimizer_dict.values()
|
| 1386 |
+
]
|
| 1387 |
+
lrs = list(chain(*param_wise_lrs))
|
| 1388 |
+
|
| 1389 |
+
return lrs
|
| 1390 |
+
|
| 1391 |
+
def _get_closed_form_lr(self):
|
| 1392 |
+
return self.base_lrs
|
| 1393 |
+
|
| 1394 |
+
|
| 1395 |
+
def set_rng_state_for_device(device_name, device_module, checkpoint_rng_state, is_distributed):
|
| 1396 |
+
"""Helper to set RNG state for a specific device type (CUDA, NPU, MLU, MUSA)"""
|
| 1397 |
+
device_state_key = device_name.lower()
|
| 1398 |
+
err_template = "Didn't manage to set back the RNG states of the {backend} because of the following error:\n {exception}\nThis won't yield the same results as if the training had not been interrupted."
|
| 1399 |
+
try:
|
| 1400 |
+
if is_distributed:
|
| 1401 |
+
device_module.random.set_rng_state_all(checkpoint_rng_state[device_state_key])
|
| 1402 |
+
else:
|
| 1403 |
+
device_module.random.set_rng_state(checkpoint_rng_state[device_state_key])
|
| 1404 |
+
except Exception as e:
|
| 1405 |
+
# Log error if setting RNG state fails
|
| 1406 |
+
logger.error(err_template.format(backend=device_name, exception=e))
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/transformers/trainer_seq2seq.py
ADDED
|
@@ -0,0 +1,386 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2020 The HuggingFace 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 |
+
|
| 15 |
+
import contextlib
|
| 16 |
+
from copy import deepcopy
|
| 17 |
+
from pathlib import Path
|
| 18 |
+
from typing import TYPE_CHECKING, Any, Callable, Optional, Union
|
| 19 |
+
|
| 20 |
+
import torch
|
| 21 |
+
from torch import nn
|
| 22 |
+
from torch.distributed.fsdp import FullyShardedDataParallel
|
| 23 |
+
from torch.utils.data import Dataset
|
| 24 |
+
|
| 25 |
+
from .generation.configuration_utils import GenerationConfig
|
| 26 |
+
from .integrations.deepspeed import is_deepspeed_zero3_enabled
|
| 27 |
+
from .integrations.fsdp import is_fsdp_managed_module
|
| 28 |
+
from .trainer import Trainer
|
| 29 |
+
from .utils import is_datasets_available, logging
|
| 30 |
+
from .utils.deprecation import deprecate_kwarg
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
if is_datasets_available():
|
| 34 |
+
import datasets
|
| 35 |
+
|
| 36 |
+
if TYPE_CHECKING:
|
| 37 |
+
from torch.utils.data import IterableDataset
|
| 38 |
+
|
| 39 |
+
from .data.data_collator import DataCollator
|
| 40 |
+
from .feature_extraction_utils import FeatureExtractionMixin
|
| 41 |
+
from .image_processing_utils import BaseImageProcessor
|
| 42 |
+
from .modeling_utils import PreTrainedModel
|
| 43 |
+
from .processing_utils import ProcessorMixin
|
| 44 |
+
from .tokenization_utils_base import PreTrainedTokenizerBase
|
| 45 |
+
from .trainer_callback import TrainerCallback
|
| 46 |
+
from .trainer_utils import EvalPrediction, PredictionOutput
|
| 47 |
+
from .training_args import TrainingArguments
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
logger = logging.get_logger(__name__)
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
class Seq2SeqTrainer(Trainer):
|
| 54 |
+
@deprecate_kwarg("tokenizer", new_name="processing_class", version="5.0.0", raise_if_both_names=True)
|
| 55 |
+
def __init__(
|
| 56 |
+
self,
|
| 57 |
+
model: Optional[Union["PreTrainedModel", nn.Module]] = None,
|
| 58 |
+
args: Optional["TrainingArguments"] = None,
|
| 59 |
+
data_collator: Optional["DataCollator"] = None,
|
| 60 |
+
train_dataset: Optional[Union[Dataset, "IterableDataset", "datasets.Dataset"]] = None,
|
| 61 |
+
eval_dataset: Optional[Union[Dataset, dict[str, Dataset]]] = None,
|
| 62 |
+
processing_class: Optional[
|
| 63 |
+
Union["PreTrainedTokenizerBase", "BaseImageProcessor", "FeatureExtractionMixin", "ProcessorMixin"]
|
| 64 |
+
] = None,
|
| 65 |
+
model_init: Optional[Callable[[], "PreTrainedModel"]] = None,
|
| 66 |
+
compute_loss_func: Optional[Callable] = None,
|
| 67 |
+
compute_metrics: Optional[Callable[["EvalPrediction"], dict]] = None,
|
| 68 |
+
callbacks: Optional[list["TrainerCallback"]] = None,
|
| 69 |
+
optimizers: tuple[Optional[torch.optim.Optimizer], Optional[torch.optim.lr_scheduler.LambdaLR]] = (None, None),
|
| 70 |
+
preprocess_logits_for_metrics: Optional[Callable[[torch.Tensor, torch.Tensor], torch.Tensor]] = None,
|
| 71 |
+
):
|
| 72 |
+
super().__init__(
|
| 73 |
+
model=model,
|
| 74 |
+
args=args,
|
| 75 |
+
data_collator=data_collator,
|
| 76 |
+
train_dataset=train_dataset,
|
| 77 |
+
eval_dataset=eval_dataset,
|
| 78 |
+
processing_class=processing_class,
|
| 79 |
+
model_init=model_init,
|
| 80 |
+
compute_loss_func=compute_loss_func,
|
| 81 |
+
compute_metrics=compute_metrics,
|
| 82 |
+
callbacks=callbacks,
|
| 83 |
+
optimizers=optimizers,
|
| 84 |
+
preprocess_logits_for_metrics=preprocess_logits_for_metrics,
|
| 85 |
+
)
|
| 86 |
+
|
| 87 |
+
# Override self.model.generation_config if a GenerationConfig is specified in args.
|
| 88 |
+
# Priority: args.generation_config > model.generation_config > default GenerationConfig.
|
| 89 |
+
if self.args.generation_config is not None:
|
| 90 |
+
gen_config = self.load_generation_config(self.args.generation_config)
|
| 91 |
+
self.model.generation_config = gen_config
|
| 92 |
+
|
| 93 |
+
@staticmethod
|
| 94 |
+
def load_generation_config(gen_config_arg: Union[str, GenerationConfig]) -> GenerationConfig:
|
| 95 |
+
"""
|
| 96 |
+
Loads a `~generation.GenerationConfig` from the `Seq2SeqTrainingArguments.generation_config` arguments.
|
| 97 |
+
|
| 98 |
+
Args:
|
| 99 |
+
gen_config_arg (`str` or [`~generation.GenerationConfig]`):
|
| 100 |
+
`Seq2SeqTrainingArguments.generation_config` argument.
|
| 101 |
+
|
| 102 |
+
Returns:
|
| 103 |
+
A `~generation.GenerationConfig`.
|
| 104 |
+
"""
|
| 105 |
+
|
| 106 |
+
# GenerationConfig provided, nothing to do
|
| 107 |
+
if isinstance(gen_config_arg, GenerationConfig):
|
| 108 |
+
gen_config = deepcopy(gen_config_arg)
|
| 109 |
+
else:
|
| 110 |
+
# str or Path
|
| 111 |
+
pretrained_model_name = Path(gen_config_arg) if isinstance(gen_config_arg, str) else gen_config_arg
|
| 112 |
+
config_file_name = None
|
| 113 |
+
|
| 114 |
+
# Figuring if it is path pointing to a file, pointing to a directory or else a model id or URL
|
| 115 |
+
# This step is required in order to determine config_file_name
|
| 116 |
+
if pretrained_model_name.is_file():
|
| 117 |
+
config_file_name = pretrained_model_name.name
|
| 118 |
+
pretrained_model_name = pretrained_model_name.parent
|
| 119 |
+
# dir path
|
| 120 |
+
elif pretrained_model_name.is_dir():
|
| 121 |
+
pass
|
| 122 |
+
# model id or URL
|
| 123 |
+
else:
|
| 124 |
+
pretrained_model_name = gen_config_arg
|
| 125 |
+
|
| 126 |
+
gen_config = GenerationConfig.from_pretrained(pretrained_model_name, config_file_name)
|
| 127 |
+
|
| 128 |
+
# Strict validation to fail early. `GenerationConfig.save_pretrained()`, run at the end of training, throws
|
| 129 |
+
# an exception if there are warnings at validation time.
|
| 130 |
+
try:
|
| 131 |
+
gen_config.validate(strict=True)
|
| 132 |
+
except ValueError as exc:
|
| 133 |
+
raise ValueError(str(exc) + "\n\nFix these issues to train your model.")
|
| 134 |
+
|
| 135 |
+
return gen_config
|
| 136 |
+
|
| 137 |
+
def evaluate(
|
| 138 |
+
self,
|
| 139 |
+
eval_dataset: Optional[Dataset] = None,
|
| 140 |
+
ignore_keys: Optional[list[str]] = None,
|
| 141 |
+
metric_key_prefix: str = "eval",
|
| 142 |
+
**gen_kwargs,
|
| 143 |
+
) -> dict[str, float]:
|
| 144 |
+
"""
|
| 145 |
+
Run evaluation and returns metrics.
|
| 146 |
+
|
| 147 |
+
The calling script will be responsible for providing a method to compute metrics, as they are task-dependent
|
| 148 |
+
(pass it to the init `compute_metrics` argument).
|
| 149 |
+
|
| 150 |
+
You can also subclass and override this method to inject custom behavior.
|
| 151 |
+
|
| 152 |
+
Args:
|
| 153 |
+
eval_dataset (`Dataset`, *optional*):
|
| 154 |
+
Pass a dataset if you wish to override `self.eval_dataset`. If it is an [`~datasets.Dataset`], columns
|
| 155 |
+
not accepted by the `model.forward()` method are automatically removed. It must implement the `__len__`
|
| 156 |
+
method.
|
| 157 |
+
ignore_keys (`list[str]`, *optional*):
|
| 158 |
+
A list of keys in the output of your model (if it is a dictionary) that should be ignored when
|
| 159 |
+
gathering predictions.
|
| 160 |
+
metric_key_prefix (`str`, *optional*, defaults to `"eval"`):
|
| 161 |
+
An optional prefix to be used as the metrics key prefix. For example the metrics "bleu" will be named
|
| 162 |
+
"eval_bleu" if the prefix is `"eval"` (default)
|
| 163 |
+
max_length (`int`, *optional*):
|
| 164 |
+
The maximum target length to use when predicting with the generate method.
|
| 165 |
+
num_beams (`int`, *optional*):
|
| 166 |
+
Number of beams for beam search that will be used when predicting with the generate method. 1 means no
|
| 167 |
+
beam search.
|
| 168 |
+
gen_kwargs:
|
| 169 |
+
Additional `generate` specific kwargs.
|
| 170 |
+
|
| 171 |
+
Returns:
|
| 172 |
+
A dictionary containing the evaluation loss and the potential metrics computed from the predictions. The
|
| 173 |
+
dictionary also contains the epoch number which comes from the training state.
|
| 174 |
+
"""
|
| 175 |
+
|
| 176 |
+
gen_kwargs = gen_kwargs.copy()
|
| 177 |
+
|
| 178 |
+
# Use legacy argument setting if a) the option is not explicitly passed; and b) the argument is set in the
|
| 179 |
+
# training args
|
| 180 |
+
if (
|
| 181 |
+
gen_kwargs.get("max_length") is None
|
| 182 |
+
and gen_kwargs.get("max_new_tokens") is None
|
| 183 |
+
and self.args.generation_max_length is not None
|
| 184 |
+
):
|
| 185 |
+
gen_kwargs["max_length"] = self.args.generation_max_length
|
| 186 |
+
if gen_kwargs.get("num_beams") is None and self.args.generation_num_beams is not None:
|
| 187 |
+
gen_kwargs["num_beams"] = self.args.generation_num_beams
|
| 188 |
+
# We don't want to drop samples in general
|
| 189 |
+
self.gather_function = self.accelerator.gather
|
| 190 |
+
self._gen_kwargs = gen_kwargs
|
| 191 |
+
return super().evaluate(eval_dataset, ignore_keys=ignore_keys, metric_key_prefix=metric_key_prefix)
|
| 192 |
+
|
| 193 |
+
def predict(
|
| 194 |
+
self,
|
| 195 |
+
test_dataset: Dataset,
|
| 196 |
+
ignore_keys: Optional[list[str]] = None,
|
| 197 |
+
metric_key_prefix: str = "test",
|
| 198 |
+
**gen_kwargs,
|
| 199 |
+
) -> "PredictionOutput":
|
| 200 |
+
"""
|
| 201 |
+
Run prediction and returns predictions and potential metrics.
|
| 202 |
+
|
| 203 |
+
Depending on the dataset and your use case, your test dataset may contain labels. In that case, this method
|
| 204 |
+
will also return metrics, like in `evaluate()`.
|
| 205 |
+
|
| 206 |
+
Args:
|
| 207 |
+
test_dataset (`Dataset`):
|
| 208 |
+
Dataset to run the predictions on. If it is a [`~datasets.Dataset`], columns not accepted by the
|
| 209 |
+
`model.forward()` method are automatically removed. Has to implement the method `__len__`
|
| 210 |
+
ignore_keys (`list[str]`, *optional*):
|
| 211 |
+
A list of keys in the output of your model (if it is a dictionary) that should be ignored when
|
| 212 |
+
gathering predictions.
|
| 213 |
+
metric_key_prefix (`str`, *optional*, defaults to `"eval"`):
|
| 214 |
+
An optional prefix to be used as the metrics key prefix. For example the metrics "bleu" will be named
|
| 215 |
+
"eval_bleu" if the prefix is `"eval"` (default)
|
| 216 |
+
max_length (`int`, *optional*):
|
| 217 |
+
The maximum target length to use when predicting with the generate method.
|
| 218 |
+
num_beams (`int`, *optional*):
|
| 219 |
+
Number of beams for beam search that will be used when predicting with the generate method. 1 means no
|
| 220 |
+
beam search.
|
| 221 |
+
gen_kwargs:
|
| 222 |
+
Additional `generate` specific kwargs.
|
| 223 |
+
|
| 224 |
+
<Tip>
|
| 225 |
+
|
| 226 |
+
If your predictions or labels have different sequence lengths (for instance because you're doing dynamic
|
| 227 |
+
padding in a token classification task) the predictions will be padded (on the right) to allow for
|
| 228 |
+
concatenation into one array. The padding index is -100.
|
| 229 |
+
|
| 230 |
+
</Tip>
|
| 231 |
+
|
| 232 |
+
Returns: *NamedTuple* A namedtuple with the following keys:
|
| 233 |
+
|
| 234 |
+
- predictions (`np.ndarray`): The predictions on `test_dataset`.
|
| 235 |
+
- label_ids (`np.ndarray`, *optional*): The labels (if the dataset contained some).
|
| 236 |
+
- metrics (`dict[str, float]`, *optional*): The potential dictionary of metrics (if the dataset contained
|
| 237 |
+
labels).
|
| 238 |
+
"""
|
| 239 |
+
|
| 240 |
+
gen_kwargs = gen_kwargs.copy()
|
| 241 |
+
|
| 242 |
+
# Use legacy argument setting if a) the option is not explicitly passed; and b) the argument is set in the
|
| 243 |
+
# training args
|
| 244 |
+
if (
|
| 245 |
+
gen_kwargs.get("max_length") is None
|
| 246 |
+
and gen_kwargs.get("max_new_tokens") is None
|
| 247 |
+
and self.args.generation_max_length is not None
|
| 248 |
+
):
|
| 249 |
+
gen_kwargs["max_length"] = self.args.generation_max_length
|
| 250 |
+
if gen_kwargs.get("num_beams") is None and self.args.generation_num_beams is not None:
|
| 251 |
+
gen_kwargs["num_beams"] = self.args.generation_num_beams
|
| 252 |
+
self.gather_function = self.accelerator.gather
|
| 253 |
+
self._gen_kwargs = gen_kwargs
|
| 254 |
+
|
| 255 |
+
return super().predict(test_dataset, ignore_keys=ignore_keys, metric_key_prefix=metric_key_prefix)
|
| 256 |
+
|
| 257 |
+
def prediction_step(
|
| 258 |
+
self,
|
| 259 |
+
model: nn.Module,
|
| 260 |
+
inputs: dict[str, Union[torch.Tensor, Any]],
|
| 261 |
+
prediction_loss_only: bool,
|
| 262 |
+
ignore_keys: Optional[list[str]] = None,
|
| 263 |
+
**gen_kwargs,
|
| 264 |
+
) -> tuple[Optional[float], Optional[torch.Tensor], Optional[torch.Tensor]]:
|
| 265 |
+
"""
|
| 266 |
+
Perform an evaluation step on `model` using `inputs`.
|
| 267 |
+
|
| 268 |
+
Subclass and override to inject custom behavior.
|
| 269 |
+
|
| 270 |
+
Args:
|
| 271 |
+
model (`nn.Module`):
|
| 272 |
+
The model to evaluate.
|
| 273 |
+
inputs (`dict[str, Union[torch.Tensor, Any]]`):
|
| 274 |
+
The inputs and targets of the model.
|
| 275 |
+
|
| 276 |
+
The dictionary will be unpacked before being fed to the model. Most models expect the targets under the
|
| 277 |
+
argument `labels`. Check your model's documentation for all accepted arguments.
|
| 278 |
+
prediction_loss_only (`bool`):
|
| 279 |
+
Whether or not to return the loss only.
|
| 280 |
+
gen_kwargs:
|
| 281 |
+
Additional `generate` specific kwargs.
|
| 282 |
+
|
| 283 |
+
Return:
|
| 284 |
+
tuple[Optional[float], Optional[torch.Tensor], Optional[torch.Tensor]]: A tuple with the loss, logits and
|
| 285 |
+
labels (each being optional).
|
| 286 |
+
"""
|
| 287 |
+
|
| 288 |
+
if not self.args.predict_with_generate or prediction_loss_only:
|
| 289 |
+
return super().prediction_step(
|
| 290 |
+
model, inputs, prediction_loss_only=prediction_loss_only, ignore_keys=ignore_keys
|
| 291 |
+
)
|
| 292 |
+
|
| 293 |
+
has_labels = "labels" in inputs
|
| 294 |
+
inputs = self._prepare_inputs(inputs)
|
| 295 |
+
|
| 296 |
+
# Priority (handled in generate):
|
| 297 |
+
# non-`None` gen_kwargs > model.generation_config > default GenerationConfig()
|
| 298 |
+
if len(gen_kwargs) == 0 and hasattr(self, "_gen_kwargs"):
|
| 299 |
+
gen_kwargs = self._gen_kwargs.copy()
|
| 300 |
+
if "num_beams" in gen_kwargs and gen_kwargs["num_beams"] is None:
|
| 301 |
+
gen_kwargs.pop("num_beams")
|
| 302 |
+
if "max_length" in gen_kwargs and gen_kwargs["max_length"] is None:
|
| 303 |
+
gen_kwargs.pop("max_length")
|
| 304 |
+
|
| 305 |
+
default_synced_gpus = is_deepspeed_zero3_enabled() or is_fsdp_managed_module(self.model)
|
| 306 |
+
gen_kwargs["synced_gpus"] = gen_kwargs.get("synced_gpus", default_synced_gpus)
|
| 307 |
+
|
| 308 |
+
generation_inputs = inputs.copy()
|
| 309 |
+
# If the `decoder_input_ids` was created from `labels`, evict the former, so that the model can freely generate
|
| 310 |
+
# (otherwise, it would continue generating from the padded `decoder_input_ids`)
|
| 311 |
+
if (
|
| 312 |
+
"labels" in generation_inputs
|
| 313 |
+
and "decoder_input_ids" in generation_inputs
|
| 314 |
+
and generation_inputs["labels"].shape == generation_inputs["decoder_input_ids"].shape
|
| 315 |
+
):
|
| 316 |
+
generation_inputs = {
|
| 317 |
+
k: v for k, v in inputs.items() if k not in ("decoder_input_ids", "decoder_attention_mask")
|
| 318 |
+
}
|
| 319 |
+
|
| 320 |
+
summon_full_params_context = (
|
| 321 |
+
FullyShardedDataParallel.summon_full_params(self.model)
|
| 322 |
+
if isinstance(self.model, FullyShardedDataParallel)
|
| 323 |
+
else contextlib.nullcontext()
|
| 324 |
+
)
|
| 325 |
+
|
| 326 |
+
with summon_full_params_context:
|
| 327 |
+
generated_tokens = self.model.generate(**generation_inputs, **gen_kwargs)
|
| 328 |
+
|
| 329 |
+
# Temporary hack to ensure the generation config is not initialized for each iteration of the evaluation loop
|
| 330 |
+
# TODO: remove this hack when the legacy code that initializes generation_config from a model config is
|
| 331 |
+
# removed in https://github.com/huggingface/transformers/blob/98d88b23f54e5a23e741833f1e973fdf600cc2c5/src/transformers/generation/utils.py#L1183
|
| 332 |
+
if self.model.generation_config._from_model_config:
|
| 333 |
+
self.model.generation_config._from_model_config = False
|
| 334 |
+
|
| 335 |
+
# Retrieves GenerationConfig from model.generation_config
|
| 336 |
+
gen_config = self.model.generation_config
|
| 337 |
+
# in case the batch is shorter than max length, the output should be padded
|
| 338 |
+
if generated_tokens.shape[-1] < gen_config.max_length:
|
| 339 |
+
generated_tokens = self._pad_tensors_to_max_len(generated_tokens, gen_config.max_length)
|
| 340 |
+
elif gen_config.max_new_tokens is not None and generated_tokens.shape[-1] < gen_config.max_new_tokens + 1:
|
| 341 |
+
generated_tokens = self._pad_tensors_to_max_len(generated_tokens, gen_config.max_new_tokens + 1)
|
| 342 |
+
|
| 343 |
+
with torch.no_grad():
|
| 344 |
+
if has_labels:
|
| 345 |
+
with self.compute_loss_context_manager():
|
| 346 |
+
outputs = model(**inputs)
|
| 347 |
+
if self.label_smoother is not None:
|
| 348 |
+
loss = self.label_smoother(outputs, inputs["labels"]).detach().mean()
|
| 349 |
+
else:
|
| 350 |
+
loss = (outputs["loss"] if isinstance(outputs, dict) else outputs[0]).detach().mean()
|
| 351 |
+
else:
|
| 352 |
+
loss = None
|
| 353 |
+
|
| 354 |
+
if self.args.prediction_loss_only:
|
| 355 |
+
return loss, None, None
|
| 356 |
+
|
| 357 |
+
if has_labels:
|
| 358 |
+
labels = inputs["labels"]
|
| 359 |
+
if labels.shape[-1] < gen_config.max_length:
|
| 360 |
+
labels = self._pad_tensors_to_max_len(labels, gen_config.max_length)
|
| 361 |
+
elif gen_config.max_new_tokens is not None and labels.shape[-1] < gen_config.max_new_tokens + 1:
|
| 362 |
+
labels = self._pad_tensors_to_max_len(labels, gen_config.max_new_tokens + 1)
|
| 363 |
+
else:
|
| 364 |
+
labels = None
|
| 365 |
+
|
| 366 |
+
return loss, generated_tokens, labels
|
| 367 |
+
|
| 368 |
+
def _pad_tensors_to_max_len(self, tensor, max_length):
|
| 369 |
+
if self.processing_class is not None and hasattr(self.processing_class, "pad_token_id"):
|
| 370 |
+
# If PAD token is not defined at least EOS token has to be defined
|
| 371 |
+
pad_token_id = (
|
| 372 |
+
self.processing_class.pad_token_id
|
| 373 |
+
if self.processing_class.pad_token_id is not None
|
| 374 |
+
else self.processing_class.eos_token_id
|
| 375 |
+
)
|
| 376 |
+
else:
|
| 377 |
+
if self.model.config.pad_token_id is not None:
|
| 378 |
+
pad_token_id = self.model.config.pad_token_id
|
| 379 |
+
else:
|
| 380 |
+
raise ValueError("Pad_token_id must be set in the configuration of the model, in order to pad tensors")
|
| 381 |
+
|
| 382 |
+
padded_tensor = pad_token_id * torch.ones(
|
| 383 |
+
(tensor.shape[0], max_length), dtype=tensor.dtype, device=tensor.device
|
| 384 |
+
)
|
| 385 |
+
padded_tensor[:, : tensor.shape[-1]] = tensor
|
| 386 |
+
return padded_tensor
|