PhiMoE (#33363)
* onboard phimoe model * removed debug code * added unit tests * updated docs * formatted * fixed unit tests * fixed test case * fixed format * refactored code * fixed expected outputs in the integration tests * Added a warning msg * Addressed comments * Addressed comments * fixed test cases * added paper link * Addressed comments * Refactored PhimoeForCausalLM forward fn * Refactored PhimoeRotaryEmbedding class * fixed test cases * fixed testcase * fixed test case * Addressed comments * fixed test cases * fixed testcases * Used cache position instead to get the seq len
This commit is contained in:
@@ -522,6 +522,8 @@
|
|||||||
title: Phi
|
title: Phi
|
||||||
- local: model_doc/phi3
|
- local: model_doc/phi3
|
||||||
title: Phi-3
|
title: Phi-3
|
||||||
|
- local: model_doc/phimoe
|
||||||
|
title: PhiMoE
|
||||||
- local: model_doc/phobert
|
- local: model_doc/phobert
|
||||||
title: PhoBERT
|
title: PhoBERT
|
||||||
- local: model_doc/plbart
|
- local: model_doc/plbart
|
||||||
|
|||||||
@@ -256,6 +256,7 @@ Flax), PyTorch, and/or TensorFlow.
|
|||||||
| [Persimmon](model_doc/persimmon) | ✅ | ❌ | ❌ |
|
| [Persimmon](model_doc/persimmon) | ✅ | ❌ | ❌ |
|
||||||
| [Phi](model_doc/phi) | ✅ | ❌ | ❌ |
|
| [Phi](model_doc/phi) | ✅ | ❌ | ❌ |
|
||||||
| [Phi3](model_doc/phi3) | ✅ | ❌ | ❌ |
|
| [Phi3](model_doc/phi3) | ✅ | ❌ | ❌ |
|
||||||
|
| [Phimoe](model_doc/phimoe) | ✅ | ❌ | ❌ |
|
||||||
| [PhoBERT](model_doc/phobert) | ✅ | ✅ | ✅ |
|
| [PhoBERT](model_doc/phobert) | ✅ | ✅ | ✅ |
|
||||||
| [Pix2Struct](model_doc/pix2struct) | ✅ | ❌ | ❌ |
|
| [Pix2Struct](model_doc/pix2struct) | ✅ | ❌ | ❌ |
|
||||||
| [Pixtral](model_doc/pixtral) | ✅ | ❌ | ❌ |
|
| [Pixtral](model_doc/pixtral) | ✅ | ❌ | ❌ |
|
||||||
|
|||||||
118
docs/source/en/model_doc/phimoe.md
Normal file
118
docs/source/en/model_doc/phimoe.md
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
<!--Copyright 2024 The HuggingFace Team. All rights reserved.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||||
|
the License. You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||||
|
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
⚠️ Note that this file is in Markdown but contains specific syntax for our doc-builder (similar to MDX) that may not be
|
||||||
|
rendered properly in your Markdown viewer.
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
||||||
|
# PhiMoE
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
The PhiMoE model was proposed in [Phi-3 Technical Report: A Highly Capable Language Model Locally on Your Phone](https://arxiv.org/abs/2404.14219) by Microsoft.
|
||||||
|
|
||||||
|
### Summary
|
||||||
|
|
||||||
|
The abstract from the Phi-3 paper is the following:
|
||||||
|
|
||||||
|
We introduce phi-3-mini, a 3.8 billion parameter language model trained on 3.3 trillion tokens, whose overall performance, as measured by both academic benchmarks and internal testing, rivals that of models such as Mixtral 8x7B and GPT-3.5 (e.g., phi-3-mini achieves 69% on MMLU and 8.38 on MT-bench), despite being small enough to be deployed on a phone. Our training dataset is a scaled-up version of the one used for phi-2, composed of heavily filtered publicly available web data and synthetic data. The model is also further aligned for robustness, safety, and chat format. We also provide parameter-scaling results with a 7B, 14B models trained for 4.8T tokens, called phi-3-small, phi-3-medium, both significantly more capable than phi-3-mini (e.g., respectively 75%, 78% on MMLU, and 8.7, 8.9 on MT-bench). To enhance multilingual, multimodal, and long-context capabilities, we introduce three models in the phi-3.5 series: phi-3.5-mini, phi-3.5-MoE, and phi-3.5-Vision. The phi-3.5-MoE, a 16 x 3.8B MoE model with 6.6 billion active parameters, achieves superior performance in language reasoning, math, and code tasks compared to other open-source models of similar scale, such as Llama 3.1 and the Mixtral series, and on par with Gemini-1.5-Flash and GPT-4o-mini. Meanwhile, phi-3.5-Vision, a 4.2 billion parameter model derived from phi-3.5-mini, excels in reasoning tasks and is adept at handling both single-image and text prompts, as well as multi-image and text prompts.
|
||||||
|
|
||||||
|
The original code for PhiMoE can be found [here](https://huggingface.co/microsoft/Phi-3.5-MoE-instruct).
|
||||||
|
|
||||||
|
## Usage tips
|
||||||
|
|
||||||
|
- This model is very similar to `Mixtral` with the main difference of [`Phi3LongRoPEScaledRotaryEmbedding`], where they are used to extend the context of the rotary embeddings. The query, key and values are fused, and the MLP's up and gate projection layers are also fused.
|
||||||
|
- The tokenizer used for this model is identical to the [`LlamaTokenizer`], with the exception of additional tokens.
|
||||||
|
|
||||||
|
## How to use PhiMoE
|
||||||
|
|
||||||
|
<Tip warning={true}>
|
||||||
|
|
||||||
|
Phi-3.5-MoE-instruct has been integrated in the development version (4.44.2.dev) of `transformers`. Until the official version is released through `pip`, ensure that you are doing the following:
|
||||||
|
* When loading the model, ensure that `trust_remote_code=True` is passed as an argument of the `from_pretrained()` function.
|
||||||
|
|
||||||
|
The current `transformers` version can be verified with: `pip list | grep transformers`.
|
||||||
|
|
||||||
|
Examples of required packages:
|
||||||
|
```
|
||||||
|
flash_attn==2.5.8
|
||||||
|
torch==2.3.1
|
||||||
|
accelerate==0.31.0
|
||||||
|
transformers==4.43.0
|
||||||
|
```
|
||||||
|
|
||||||
|
</Tip>
|
||||||
|
|
||||||
|
```python
|
||||||
|
import torch
|
||||||
|
from transformers import AutoModelForCausalLM, AutoTokenizer, pipeline
|
||||||
|
|
||||||
|
torch.random.manual_seed(0)
|
||||||
|
|
||||||
|
model = AutoModelForCausalLM.from_pretrained(
|
||||||
|
"microsoft/Phi-3.5-MoE-instruct",
|
||||||
|
device_map="cuda",
|
||||||
|
torch_dtype="auto",
|
||||||
|
trust_remote_code=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
tokenizer = AutoTokenizer.from_pretrained("microsoft/Phi-3.5-MoE-instruct")
|
||||||
|
|
||||||
|
messages = [
|
||||||
|
{"role": "system", "content": "You are a helpful AI assistant."},
|
||||||
|
{"role": "user", "content": "Can you provide ways to eat combinations of bananas and dragonfruits?"},
|
||||||
|
{"role": "assistant", "content": "Sure! Here are some ways to eat bananas and dragonfruits together: 1. Banana and dragonfruit smoothie: Blend bananas and dragonfruits together with some milk and honey. 2. Banana and dragonfruit salad: Mix sliced bananas and dragonfruits together with some lemon juice and honey."},
|
||||||
|
{"role": "user", "content": "What about solving an 2x + 3 = 7 equation?"},
|
||||||
|
]
|
||||||
|
|
||||||
|
pipe = pipeline(
|
||||||
|
"text-generation",
|
||||||
|
model=model,
|
||||||
|
tokenizer=tokenizer,
|
||||||
|
)
|
||||||
|
|
||||||
|
generation_args = {
|
||||||
|
"max_new_tokens": 500,
|
||||||
|
"return_full_text": False,
|
||||||
|
"temperature": 0.0,
|
||||||
|
"do_sample": False,
|
||||||
|
}
|
||||||
|
|
||||||
|
output = pipe(messages, **generation_args)
|
||||||
|
print(output[0]['generated_text'])
|
||||||
|
```
|
||||||
|
|
||||||
|
## PhimoeConfig
|
||||||
|
|
||||||
|
[[autodoc]] PhimoeConfig
|
||||||
|
|
||||||
|
<frameworkcontent>
|
||||||
|
<pt>
|
||||||
|
|
||||||
|
## PhimoeModel
|
||||||
|
|
||||||
|
[[autodoc]] PhimoeModel
|
||||||
|
- forward
|
||||||
|
|
||||||
|
## PhimoeForCausalLM
|
||||||
|
|
||||||
|
[[autodoc]] PhimoeForCausalLM
|
||||||
|
- forward
|
||||||
|
- generate
|
||||||
|
|
||||||
|
## PhimoeForSequenceClassification
|
||||||
|
|
||||||
|
[[autodoc]] PhimoeForSequenceClassification
|
||||||
|
- forward
|
||||||
|
|
||||||
|
</pt>
|
||||||
|
</frameworkcontent>
|
||||||
@@ -79,6 +79,7 @@ FlashAttention-2 is currently supported for the following architectures:
|
|||||||
* [OPT](https://huggingface.co/docs/transformers/model_doc/opt#transformers.OPTModel)
|
* [OPT](https://huggingface.co/docs/transformers/model_doc/opt#transformers.OPTModel)
|
||||||
* [Phi](https://huggingface.co/docs/transformers/model_doc/phi#transformers.PhiModel)
|
* [Phi](https://huggingface.co/docs/transformers/model_doc/phi#transformers.PhiModel)
|
||||||
* [Phi3](https://huggingface.co/docs/transformers/model_doc/phi3#transformers.Phi3Model)
|
* [Phi3](https://huggingface.co/docs/transformers/model_doc/phi3#transformers.Phi3Model)
|
||||||
|
* [PhiMoE](https://huggingface.co/docs/transformers/model_doc/phimoe#transformers.PhimoeModel)
|
||||||
* [StableLm](https://huggingface.co/docs/transformers/model_doc/stablelm#transformers.StableLmModel)
|
* [StableLm](https://huggingface.co/docs/transformers/model_doc/stablelm#transformers.StableLmModel)
|
||||||
* [Starcoder2](https://huggingface.co/docs/transformers/model_doc/starcoder2#transformers.Starcoder2Model)
|
* [Starcoder2](https://huggingface.co/docs/transformers/model_doc/starcoder2#transformers.Starcoder2Model)
|
||||||
* [Qwen2](https://huggingface.co/docs/transformers/model_doc/qwen2#transformers.Qwen2Model)
|
* [Qwen2](https://huggingface.co/docs/transformers/model_doc/qwen2#transformers.Qwen2Model)
|
||||||
@@ -248,6 +249,7 @@ For now, Transformers supports SDPA inference and training for the following arc
|
|||||||
* [PaliGemma](https://huggingface.co/docs/transformers/model_doc/paligemma#transformers.PaliGemmaForConditionalGeneration)
|
* [PaliGemma](https://huggingface.co/docs/transformers/model_doc/paligemma#transformers.PaliGemmaForConditionalGeneration)
|
||||||
* [Phi](https://huggingface.co/docs/transformers/model_doc/phi#transformers.PhiModel)
|
* [Phi](https://huggingface.co/docs/transformers/model_doc/phi#transformers.PhiModel)
|
||||||
* [Phi3](https://huggingface.co/docs/transformers/model_doc/phi3#transformers.Phi3Model)
|
* [Phi3](https://huggingface.co/docs/transformers/model_doc/phi3#transformers.Phi3Model)
|
||||||
|
* [PhiMoE](https://huggingface.co/docs/transformers/model_doc/phimoe#transformers.PhimoeModel)
|
||||||
* [Idefics](https://huggingface.co/docs/transformers/model_doc/idefics#transformers.IdeficsModel)
|
* [Idefics](https://huggingface.co/docs/transformers/model_doc/idefics#transformers.IdeficsModel)
|
||||||
* [Whisper](https://huggingface.co/docs/transformers/model_doc/whisper#transformers.WhisperModel)
|
* [Whisper](https://huggingface.co/docs/transformers/model_doc/whisper#transformers.WhisperModel)
|
||||||
* [mBart](https://huggingface.co/docs/transformers/model_doc/mbart#transformers.MBartModel)
|
* [mBart](https://huggingface.co/docs/transformers/model_doc/mbart#transformers.MBartModel)
|
||||||
|
|||||||
@@ -654,6 +654,7 @@ _import_structure = {
|
|||||||
"models.persimmon": ["PersimmonConfig"],
|
"models.persimmon": ["PersimmonConfig"],
|
||||||
"models.phi": ["PhiConfig"],
|
"models.phi": ["PhiConfig"],
|
||||||
"models.phi3": ["Phi3Config"],
|
"models.phi3": ["Phi3Config"],
|
||||||
|
"models.phimoe": ["PhimoeConfig"],
|
||||||
"models.phobert": ["PhobertTokenizer"],
|
"models.phobert": ["PhobertTokenizer"],
|
||||||
"models.pix2struct": [
|
"models.pix2struct": [
|
||||||
"Pix2StructConfig",
|
"Pix2StructConfig",
|
||||||
@@ -3022,6 +3023,14 @@ else:
|
|||||||
"Phi3PreTrainedModel",
|
"Phi3PreTrainedModel",
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
_import_structure["models.phimoe"].extend(
|
||||||
|
[
|
||||||
|
"PhimoeForCausalLM",
|
||||||
|
"PhimoeForSequenceClassification",
|
||||||
|
"PhimoeModel",
|
||||||
|
"PhimoePreTrainedModel",
|
||||||
|
]
|
||||||
|
)
|
||||||
_import_structure["models.pix2struct"].extend(
|
_import_structure["models.pix2struct"].extend(
|
||||||
[
|
[
|
||||||
"Pix2StructForConditionalGeneration",
|
"Pix2StructForConditionalGeneration",
|
||||||
@@ -5495,6 +5504,7 @@ if TYPE_CHECKING:
|
|||||||
)
|
)
|
||||||
from .models.phi import PhiConfig
|
from .models.phi import PhiConfig
|
||||||
from .models.phi3 import Phi3Config
|
from .models.phi3 import Phi3Config
|
||||||
|
from .models.phimoe import PhimoeConfig
|
||||||
from .models.phobert import PhobertTokenizer
|
from .models.phobert import PhobertTokenizer
|
||||||
from .models.pix2struct import (
|
from .models.pix2struct import (
|
||||||
Pix2StructConfig,
|
Pix2StructConfig,
|
||||||
@@ -7545,6 +7555,12 @@ if TYPE_CHECKING:
|
|||||||
Phi3Model,
|
Phi3Model,
|
||||||
Phi3PreTrainedModel,
|
Phi3PreTrainedModel,
|
||||||
)
|
)
|
||||||
|
from .models.phimoe import (
|
||||||
|
PhimoeForCausalLM,
|
||||||
|
PhimoeForSequenceClassification,
|
||||||
|
PhimoeModel,
|
||||||
|
PhimoePreTrainedModel,
|
||||||
|
)
|
||||||
from .models.pix2struct import (
|
from .models.pix2struct import (
|
||||||
Pix2StructForConditionalGeneration,
|
Pix2StructForConditionalGeneration,
|
||||||
Pix2StructPreTrainedModel,
|
Pix2StructPreTrainedModel,
|
||||||
|
|||||||
@@ -251,7 +251,7 @@ def _compute_longrope_parameters(
|
|||||||
device (`torch.device`):
|
device (`torch.device`):
|
||||||
The device to use for initialization of the inverse frequencies.
|
The device to use for initialization of the inverse frequencies.
|
||||||
seq_len (`int`, *optional*):
|
seq_len (`int`, *optional*):
|
||||||
The current sequence length. Unused for this type of RoPE.
|
The current sequence length.
|
||||||
rope_kwargs (`Dict`, *optional*):
|
rope_kwargs (`Dict`, *optional*):
|
||||||
BC compatibility with the previous RoPE class instantiation, will be removed in v4.45.
|
BC compatibility with the previous RoPE class instantiation, will be removed in v4.45.
|
||||||
Returns:
|
Returns:
|
||||||
@@ -279,8 +279,11 @@ def _compute_longrope_parameters(
|
|||||||
# `original_max_position_embeddings` field containing the pretrained value. They use the ratio between these two
|
# `original_max_position_embeddings` field containing the pretrained value. They use the ratio between these two
|
||||||
# values to compute the default attention scaling factor, instead of using `factor`.
|
# values to compute the default attention scaling factor, instead of using `factor`.
|
||||||
if hasattr(config, "original_max_position_embeddings"):
|
if hasattr(config, "original_max_position_embeddings"):
|
||||||
|
if seq_len and seq_len < config.original_max_position_embeddings:
|
||||||
|
expanded_max_position_embeddings = config.original_max_position_embeddings
|
||||||
|
else:
|
||||||
|
expanded_max_position_embeddings = config.max_position_embeddings
|
||||||
max_position_embeddings = config.original_max_position_embeddings
|
max_position_embeddings = config.original_max_position_embeddings
|
||||||
expanded_max_position_embeddings = config.max_position_embeddings
|
|
||||||
factor = expanded_max_position_embeddings / max_position_embeddings
|
factor = expanded_max_position_embeddings / max_position_embeddings
|
||||||
else:
|
else:
|
||||||
max_position_embeddings = config.max_position_embeddings
|
max_position_embeddings = config.max_position_embeddings
|
||||||
|
|||||||
@@ -190,6 +190,7 @@ from . import (
|
|||||||
persimmon,
|
persimmon,
|
||||||
phi,
|
phi,
|
||||||
phi3,
|
phi3,
|
||||||
|
phimoe,
|
||||||
phobert,
|
phobert,
|
||||||
pix2struct,
|
pix2struct,
|
||||||
pixtral,
|
pixtral,
|
||||||
|
|||||||
@@ -210,6 +210,7 @@ CONFIG_MAPPING_NAMES = OrderedDict(
|
|||||||
("persimmon", "PersimmonConfig"),
|
("persimmon", "PersimmonConfig"),
|
||||||
("phi", "PhiConfig"),
|
("phi", "PhiConfig"),
|
||||||
("phi3", "Phi3Config"),
|
("phi3", "Phi3Config"),
|
||||||
|
("phimoe", "PhimoeConfig"),
|
||||||
("pix2struct", "Pix2StructConfig"),
|
("pix2struct", "Pix2StructConfig"),
|
||||||
("pixtral", "PixtralVisionConfig"),
|
("pixtral", "PixtralVisionConfig"),
|
||||||
("plbart", "PLBartConfig"),
|
("plbart", "PLBartConfig"),
|
||||||
@@ -520,6 +521,7 @@ MODEL_NAMES_MAPPING = OrderedDict(
|
|||||||
("persimmon", "Persimmon"),
|
("persimmon", "Persimmon"),
|
||||||
("phi", "Phi"),
|
("phi", "Phi"),
|
||||||
("phi3", "Phi3"),
|
("phi3", "Phi3"),
|
||||||
|
("phimoe", "Phimoe"),
|
||||||
("phobert", "PhoBERT"),
|
("phobert", "PhoBERT"),
|
||||||
("pix2struct", "Pix2Struct"),
|
("pix2struct", "Pix2Struct"),
|
||||||
("pixtral", "Pixtral"),
|
("pixtral", "Pixtral"),
|
||||||
|
|||||||
@@ -198,6 +198,7 @@ MODEL_MAPPING_NAMES = OrderedDict(
|
|||||||
("persimmon", "PersimmonModel"),
|
("persimmon", "PersimmonModel"),
|
||||||
("phi", "PhiModel"),
|
("phi", "PhiModel"),
|
||||||
("phi3", "Phi3Model"),
|
("phi3", "Phi3Model"),
|
||||||
|
("phimoe", "PhimoeModel"),
|
||||||
("pixtral", "PixtralVisionModel"),
|
("pixtral", "PixtralVisionModel"),
|
||||||
("plbart", "PLBartModel"),
|
("plbart", "PLBartModel"),
|
||||||
("poolformer", "PoolFormerModel"),
|
("poolformer", "PoolFormerModel"),
|
||||||
@@ -518,6 +519,7 @@ MODEL_FOR_CAUSAL_LM_MAPPING_NAMES = OrderedDict(
|
|||||||
("persimmon", "PersimmonForCausalLM"),
|
("persimmon", "PersimmonForCausalLM"),
|
||||||
("phi", "PhiForCausalLM"),
|
("phi", "PhiForCausalLM"),
|
||||||
("phi3", "Phi3ForCausalLM"),
|
("phi3", "Phi3ForCausalLM"),
|
||||||
|
("phimoe", "PhimoeForCausalLM"),
|
||||||
("plbart", "PLBartForCausalLM"),
|
("plbart", "PLBartForCausalLM"),
|
||||||
("prophetnet", "ProphetNetForCausalLM"),
|
("prophetnet", "ProphetNetForCausalLM"),
|
||||||
("qdqbert", "QDQBertLMHeadModel"),
|
("qdqbert", "QDQBertLMHeadModel"),
|
||||||
@@ -948,6 +950,7 @@ MODEL_FOR_SEQUENCE_CLASSIFICATION_MAPPING_NAMES = OrderedDict(
|
|||||||
("persimmon", "PersimmonForSequenceClassification"),
|
("persimmon", "PersimmonForSequenceClassification"),
|
||||||
("phi", "PhiForSequenceClassification"),
|
("phi", "PhiForSequenceClassification"),
|
||||||
("phi3", "Phi3ForSequenceClassification"),
|
("phi3", "Phi3ForSequenceClassification"),
|
||||||
|
("phimoe", "PhimoeForSequenceClassification"),
|
||||||
("plbart", "PLBartForSequenceClassification"),
|
("plbart", "PLBartForSequenceClassification"),
|
||||||
("qdqbert", "QDQBertForSequenceClassification"),
|
("qdqbert", "QDQBertForSequenceClassification"),
|
||||||
("qwen2", "Qwen2ForSequenceClassification"),
|
("qwen2", "Qwen2ForSequenceClassification"),
|
||||||
|
|||||||
@@ -389,6 +389,7 @@ else:
|
|||||||
),
|
),
|
||||||
("phi", ("CodeGenTokenizer", "CodeGenTokenizerFast" if is_tokenizers_available() else None)),
|
("phi", ("CodeGenTokenizer", "CodeGenTokenizerFast" if is_tokenizers_available() else None)),
|
||||||
("phi3", ("LlamaTokenizer", "LlamaTokenizerFast" if is_tokenizers_available() else None)),
|
("phi3", ("LlamaTokenizer", "LlamaTokenizerFast" if is_tokenizers_available() else None)),
|
||||||
|
("phimoe", ("LlamaTokenizer", "LlamaTokenizerFast" if is_tokenizers_available() else None)),
|
||||||
("phobert", ("PhobertTokenizer", None)),
|
("phobert", ("PhobertTokenizer", None)),
|
||||||
("pix2struct", ("T5Tokenizer", "T5TokenizerFast" if is_tokenizers_available() else None)),
|
("pix2struct", ("T5Tokenizer", "T5TokenizerFast" if is_tokenizers_available() else None)),
|
||||||
("pixtral", (None, "PreTrainedTokenizerFast" if is_tokenizers_available() else None)),
|
("pixtral", (None, "PreTrainedTokenizerFast" if is_tokenizers_available() else None)),
|
||||||
|
|||||||
28
src/transformers/models/phimoe/__init__.py
Normal file
28
src/transformers/models/phimoe/__init__.py
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
# Copyright 2024 Microsoft and The HuggingFace Inc. team. All rights reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
from ...utils import _LazyModule
|
||||||
|
from ...utils.import_utils import define_import_structure
|
||||||
|
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from .configuration_phimoe import *
|
||||||
|
from .modeling_phimoe import *
|
||||||
|
|
||||||
|
else:
|
||||||
|
import sys
|
||||||
|
|
||||||
|
_file = globals()["__file__"]
|
||||||
|
sys.modules[__name__] = _LazyModule(__name__, _file, define_import_structure(_file), module_spec=__spec__)
|
||||||
203
src/transformers/models/phimoe/configuration_phimoe.py
Normal file
203
src/transformers/models/phimoe/configuration_phimoe.py
Normal file
@@ -0,0 +1,203 @@
|
|||||||
|
# coding=utf-8
|
||||||
|
# Copyright 2024 Microsoft and the HuggingFace Inc. team. All rights reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
"""PyTorch Phi-MoE model."""
|
||||||
|
|
||||||
|
from ...configuration_utils import PretrainedConfig
|
||||||
|
from ...modeling_rope_utils import rope_config_validation
|
||||||
|
from ...utils import logging
|
||||||
|
|
||||||
|
|
||||||
|
logger = logging.get_logger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class PhimoeConfig(PretrainedConfig):
|
||||||
|
r"""
|
||||||
|
This is the configuration class to store the configuration of a [`PhimoeModel`]. It is used to instantiate a Phi-moe
|
||||||
|
model according to the specified arguments, defining the model architecture. Instantiating a configuration with the
|
||||||
|
defaults will yield a similar configuration to that of the
|
||||||
|
[microsoft/Phi-3.5-MoE-instruct](https://huggingface.co/microsoft/Phi-3.5-MoE-instruct).
|
||||||
|
Configuration objects inherit from [`PretrainedConfig`] and can be used to control the model outputs. Read the
|
||||||
|
documentation from [`PretrainedConfig`] for more information.
|
||||||
|
Args:
|
||||||
|
vocab_size (`int`, *optional*, defaults to 32064):
|
||||||
|
Vocabulary size of the Phimoe model. Defines the number of different tokens that can be represented by the
|
||||||
|
`inputs_ids` passed when calling [`PhimoeModel`]
|
||||||
|
hidden_size (`int`, *optional*, defaults to 4096):
|
||||||
|
Dimension of the hidden representations.
|
||||||
|
intermediate_size (`int`, *optional*, defaults to 6400):
|
||||||
|
Dimension of the MLP representations.
|
||||||
|
num_hidden_layers (`int`, *optional*, defaults to 32):
|
||||||
|
Number of hidden layers in the Transformer encoder.
|
||||||
|
num_attention_heads (`int`, *optional*, defaults to 32):
|
||||||
|
Number of attention heads for each attention layer in the Transformer encoder.
|
||||||
|
num_key_value_heads (`int`, *optional*, defaults to 8):
|
||||||
|
This is the number of key_value heads that should be used to implement Grouped Query Attention. If
|
||||||
|
`num_key_value_heads=num_attention_heads`, the model will use Multi Head Attention (MHA), if
|
||||||
|
`num_key_value_heads=1` the model will use Multi Query Attention (MQA) otherwise GQA is used. When
|
||||||
|
converting a multi-head checkpoint to a GQA checkpoint, each group key and value head should be constructed
|
||||||
|
by meanpooling all the original heads within that group. For more details checkout [this
|
||||||
|
paper](https://arxiv.org/pdf/2305.13245.pdf). If it is not specified, will default to `8`.
|
||||||
|
hidden_act (`str` or `function`, *optional*, defaults to `"silu"`):
|
||||||
|
The non-linear activation function (function or string) in the decoder.
|
||||||
|
max_position_embeddings (`int`, *optional*, defaults to `4096*32`):
|
||||||
|
The maximum sequence length that this model might ever be used with. Mixtral's sliding window attention
|
||||||
|
allows sequence of up to 4096*32 tokens.
|
||||||
|
initializer_range (`float`, *optional*, defaults to 0.02):
|
||||||
|
The standard deviation of the truncated_normal_initializer for initializing all weight matrices.
|
||||||
|
rms_norm_eps (`float`, *optional*, defaults to 1e-05):
|
||||||
|
The epsilon used by the rms normalization layers.
|
||||||
|
use_cache (`bool`, *optional*, defaults to `True`):
|
||||||
|
Whether or not the model should return the last key/values attentions (not used by all models). Only
|
||||||
|
relevant if `config.is_decoder=True`.
|
||||||
|
pad_token_id (`int`, *optional*):
|
||||||
|
The id of the padding token.
|
||||||
|
bos_token_id (`int`, *optional*, defaults to 1):
|
||||||
|
The id of the "beginning-of-sequence" token.
|
||||||
|
eos_token_id (`int`, *optional*, defaults to 2):
|
||||||
|
The id of the "end-of-sequence" token.
|
||||||
|
tie_word_embeddings (`bool`, *optional*, defaults to `False`):
|
||||||
|
Whether the model's input and output word embeddings should be tied.
|
||||||
|
rope_theta (`float`, *optional*, defaults to 1000000.0):
|
||||||
|
The base period of the RoPE embeddings.
|
||||||
|
rope_scaling (`dict`, *optional*):
|
||||||
|
The scaling strategy for the RoPE embeddings. If `None`, no scaling is applied. If a dictionary, it must
|
||||||
|
contain the following keys: `type`, `short_factor`, `long_factor`, `short_mscale`, `long_mscale` and
|
||||||
|
`original_max_position_embeddings`. The `type` must be `longrope`, the `short_mscale` and `long_scale` must
|
||||||
|
be numbers, the `short_factor` and `long_factor` must be lists of numbers with the same length as half of
|
||||||
|
the attention head size and the `original_max_position_embeddings` must be an integer.
|
||||||
|
sliding_window (`int`, *optional*):
|
||||||
|
Sliding window attention window size. If not specified, will default to `262144`.
|
||||||
|
attention_dropout (`float`, *optional*, defaults to 0.0):
|
||||||
|
The dropout ratio for the attention probabilities.
|
||||||
|
num_experts_per_tok (`int`, *optional*, defaults to 2):
|
||||||
|
The number of experts to root per-token, can be also interpreted as the `top-p` routing
|
||||||
|
parameter
|
||||||
|
num_local_experts (`int`, *optional*, defaults to 16):
|
||||||
|
Number of experts per Sparse MLP layer.
|
||||||
|
output_router_logits (`bool`, *optional*, defaults to `False`):
|
||||||
|
Whether or not the router logits should be returned by the model. Enabeling this will also
|
||||||
|
allow the model to output the auxiliary loss. See [here]() for more details
|
||||||
|
router_aux_loss_coef (`float`, *optional*, defaults to 0.001):
|
||||||
|
The aux loss factor for the total loss.
|
||||||
|
router_jitter_noise (`float`, *optional*, defaults to 0.01):
|
||||||
|
Amount of noise to add to the router.
|
||||||
|
input_jitter_noise (`float`, *optional*, defaults to 0.0): Input jitter noise
|
||||||
|
attention_bias (`bool`, *optional*, defaults to `False`): Attention bias
|
||||||
|
lm_head_bias (`bool`, *optional*, defaults to `False`): LM head bias
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```python
|
||||||
|
>>> from transformers import PhimoeModel, PhimoeConfig
|
||||||
|
>>> # Initializing a Phi-3 style configuration
|
||||||
|
>>> configuration = PhimoeConfig.from_pretrained("microsoft/Phi-3.5-MoE-instruct")
|
||||||
|
>>> # Initializing a model from the configuration
|
||||||
|
>>> model = PhimoeModel(configuration)
|
||||||
|
>>> # Accessing the model configuration
|
||||||
|
>>> configuration = model.config
|
||||||
|
```"""
|
||||||
|
|
||||||
|
model_type = "phimoe"
|
||||||
|
keys_to_ignore_at_inference = ["past_key_values"]
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
vocab_size=32064,
|
||||||
|
hidden_size=4096,
|
||||||
|
intermediate_size=6400,
|
||||||
|
num_hidden_layers=32,
|
||||||
|
num_attention_heads=32,
|
||||||
|
num_key_value_heads=8,
|
||||||
|
hidden_act="silu",
|
||||||
|
max_position_embeddings=4096 * 32,
|
||||||
|
initializer_range=0.02,
|
||||||
|
rms_norm_eps=1e-5,
|
||||||
|
use_cache=True,
|
||||||
|
pad_token_id=None,
|
||||||
|
bos_token_id=1,
|
||||||
|
eos_token_id=2,
|
||||||
|
tie_word_embeddings=False,
|
||||||
|
rope_theta=1e6,
|
||||||
|
rope_scaling=None,
|
||||||
|
sliding_window=None,
|
||||||
|
attention_dropout=0.0,
|
||||||
|
num_experts_per_tok=2,
|
||||||
|
num_local_experts=16,
|
||||||
|
output_router_logits=False,
|
||||||
|
router_aux_loss_coef=0.001,
|
||||||
|
router_jitter_noise=0.01,
|
||||||
|
input_jitter_noise=0.0,
|
||||||
|
attention_bias=False,
|
||||||
|
lm_head_bias=False,
|
||||||
|
**kwargs,
|
||||||
|
):
|
||||||
|
self.vocab_size = vocab_size
|
||||||
|
self.max_position_embeddings = max_position_embeddings
|
||||||
|
self.hidden_size = hidden_size
|
||||||
|
self.intermediate_size = intermediate_size
|
||||||
|
self.num_hidden_layers = num_hidden_layers
|
||||||
|
self.num_attention_heads = num_attention_heads
|
||||||
|
self.sliding_window = sliding_window
|
||||||
|
self.attention_bias = attention_bias
|
||||||
|
self.lm_head_bias = lm_head_bias
|
||||||
|
# for backward compatibility
|
||||||
|
if num_key_value_heads is None:
|
||||||
|
num_key_value_heads = num_attention_heads
|
||||||
|
|
||||||
|
self.num_key_value_heads = num_key_value_heads
|
||||||
|
self.hidden_act = hidden_act
|
||||||
|
self.initializer_range = initializer_range
|
||||||
|
self.rms_norm_eps = rms_norm_eps
|
||||||
|
self.use_cache = use_cache
|
||||||
|
self.rope_theta = rope_theta
|
||||||
|
self.attention_dropout = attention_dropout
|
||||||
|
|
||||||
|
self.num_experts_per_tok = num_experts_per_tok
|
||||||
|
self.num_local_experts = num_local_experts
|
||||||
|
self.output_router_logits = output_router_logits
|
||||||
|
self.router_aux_loss_coef = router_aux_loss_coef
|
||||||
|
self.router_jitter_noise = router_jitter_noise
|
||||||
|
self.input_jitter_noise = input_jitter_noise
|
||||||
|
|
||||||
|
self.rope_scaling = rope_scaling
|
||||||
|
if isinstance(self.rope_scaling, dict):
|
||||||
|
if "rope_type" not in self.rope_scaling:
|
||||||
|
self.rope_scaling["rope_type"] = self.rope_scaling.get("type", None)
|
||||||
|
if "original_max_position_embeddings" in self.rope_scaling:
|
||||||
|
self.original_max_position_embeddings = self.rope_scaling["original_max_position_embeddings"]
|
||||||
|
rope_scaling_short_mscale = self.rope_scaling.get("short_mscale", None)
|
||||||
|
rope_scaling_long_mscale = self.rope_scaling.get("long_mscale", None)
|
||||||
|
if not isinstance(rope_scaling_short_mscale, (int, float)):
|
||||||
|
raise ValueError(
|
||||||
|
f"`rope_scaling`'s short_mscale field must be a number, got {rope_scaling_short_mscale}"
|
||||||
|
)
|
||||||
|
if not isinstance(rope_scaling_long_mscale, (int, float)):
|
||||||
|
raise ValueError(
|
||||||
|
f"`rope_scaling`'s long_mscale field must be a number, got {rope_scaling_long_mscale}"
|
||||||
|
)
|
||||||
|
|
||||||
|
rope_config_validation(self)
|
||||||
|
|
||||||
|
super().__init__(
|
||||||
|
pad_token_id=pad_token_id,
|
||||||
|
bos_token_id=bos_token_id,
|
||||||
|
eos_token_id=eos_token_id,
|
||||||
|
tie_word_embeddings=tie_word_embeddings,
|
||||||
|
**kwargs,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = ["PhimoeConfig"]
|
||||||
1706
src/transformers/models/phimoe/modeling_phimoe.py
Normal file
1706
src/transformers/models/phimoe/modeling_phimoe.py
Normal file
File diff suppressed because it is too large
Load Diff
@@ -7158,6 +7158,34 @@ class Phi3PreTrainedModel(metaclass=DummyObject):
|
|||||||
requires_backends(self, ["torch"])
|
requires_backends(self, ["torch"])
|
||||||
|
|
||||||
|
|
||||||
|
class PhimoeForCausalLM(metaclass=DummyObject):
|
||||||
|
_backends = ["torch"]
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
requires_backends(self, ["torch"])
|
||||||
|
|
||||||
|
|
||||||
|
class PhimoeForSequenceClassification(metaclass=DummyObject):
|
||||||
|
_backends = ["torch"]
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
requires_backends(self, ["torch"])
|
||||||
|
|
||||||
|
|
||||||
|
class PhimoeModel(metaclass=DummyObject):
|
||||||
|
_backends = ["torch"]
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
requires_backends(self, ["torch"])
|
||||||
|
|
||||||
|
|
||||||
|
class PhimoePreTrainedModel(metaclass=DummyObject):
|
||||||
|
_backends = ["torch"]
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
requires_backends(self, ["torch"])
|
||||||
|
|
||||||
|
|
||||||
class Pix2StructForConditionalGeneration(metaclass=DummyObject):
|
class Pix2StructForConditionalGeneration(metaclass=DummyObject):
|
||||||
_backends = ["torch"]
|
_backends = ["torch"]
|
||||||
|
|
||||||
|
|||||||
0
tests/models/phimoe/__init__.py
Normal file
0
tests/models/phimoe/__init__.py
Normal file
566
tests/models/phimoe/test_modeling_phimoe.py
Normal file
566
tests/models/phimoe/test_modeling_phimoe.py
Normal file
@@ -0,0 +1,566 @@
|
|||||||
|
# coding=utf-8
|
||||||
|
# Copyright 2024 Microsoft and the HuggingFace Inc. team. All rights reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
"""Testing suite for the PyTorch PhiMoE model."""
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
from parameterized import parameterized
|
||||||
|
|
||||||
|
from transformers import PhimoeConfig, StaticCache, is_torch_available, set_seed
|
||||||
|
from transformers.testing_utils import (
|
||||||
|
require_torch,
|
||||||
|
slow,
|
||||||
|
torch_device,
|
||||||
|
)
|
||||||
|
|
||||||
|
from ...generation.test_utils import GenerationTesterMixin
|
||||||
|
from ...test_configuration_common import ConfigTester
|
||||||
|
from ...test_modeling_common import ModelTesterMixin, ids_tensor
|
||||||
|
from ...test_pipeline_mixin import PipelineTesterMixin
|
||||||
|
|
||||||
|
|
||||||
|
if is_torch_available():
|
||||||
|
import torch
|
||||||
|
|
||||||
|
from transformers import (
|
||||||
|
AutoTokenizer,
|
||||||
|
PhimoeForCausalLM,
|
||||||
|
PhimoeForSequenceClassification,
|
||||||
|
PhimoeModel,
|
||||||
|
)
|
||||||
|
|
||||||
|
end_of_text_token = 32000
|
||||||
|
|
||||||
|
class PhimoeMiniWithStaticCache(torch.nn.Module):
|
||||||
|
def __init__(self, model: PhimoeForCausalLM, batch_size: int, max_seq_len: int):
|
||||||
|
super().__init__()
|
||||||
|
self.model = model
|
||||||
|
self.cache = StaticCache(
|
||||||
|
config=model.config,
|
||||||
|
batch_size=batch_size,
|
||||||
|
max_cache_len=max_seq_len,
|
||||||
|
device=self.model.device,
|
||||||
|
dtype=self.model.dtype,
|
||||||
|
)
|
||||||
|
|
||||||
|
def forward(
|
||||||
|
self,
|
||||||
|
input_ids: torch.LongTensor = None,
|
||||||
|
) -> torch.FloatTensor:
|
||||||
|
return self.model.forward(
|
||||||
|
input_ids=input_ids,
|
||||||
|
use_cache=True,
|
||||||
|
return_dict=True,
|
||||||
|
past_key_values=self.cache,
|
||||||
|
).logits
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def generate(model: PhimoeForCausalLM, prompt_tokens: torch.LongTensor, max_seq_len: int) -> List[int]:
|
||||||
|
model = PhimoeMiniWithStaticCache(model, 1, max_seq_len + prompt_tokens.shape[-1])
|
||||||
|
|
||||||
|
response_tokens = []
|
||||||
|
|
||||||
|
for input_pos in range(prompt_tokens.shape[-1]):
|
||||||
|
result = model.forward(
|
||||||
|
input_ids=prompt_tokens[:, input_pos : input_pos + 1],
|
||||||
|
)
|
||||||
|
response_tokens.append(prompt_tokens[0][input_pos].item())
|
||||||
|
|
||||||
|
current_token = torch.argmax(result[:, -1, :], dim=-1).item()
|
||||||
|
response_tokens.append(current_token)
|
||||||
|
|
||||||
|
while current_token != end_of_text_token and len(response_tokens) < max_seq_len:
|
||||||
|
result = model.forward(
|
||||||
|
input_ids=torch.tensor([[current_token]], dtype=torch.long),
|
||||||
|
)
|
||||||
|
current_token = torch.argmax(result[:, -1, :], dim=-1).item()
|
||||||
|
response_tokens.append(current_token)
|
||||||
|
|
||||||
|
return response_tokens
|
||||||
|
|
||||||
|
|
||||||
|
class PhimoeModelTester:
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
parent,
|
||||||
|
batch_size=13,
|
||||||
|
seq_length=7,
|
||||||
|
is_training=True,
|
||||||
|
use_input_mask=True,
|
||||||
|
use_token_type_ids=False,
|
||||||
|
use_labels=True,
|
||||||
|
vocab_size=99,
|
||||||
|
hidden_size=32,
|
||||||
|
num_hidden_layers=2,
|
||||||
|
num_attention_heads=4,
|
||||||
|
num_key_value_heads=4,
|
||||||
|
intermediate_size=37,
|
||||||
|
hidden_act="gelu",
|
||||||
|
hidden_dropout_prob=0.1,
|
||||||
|
attention_probs_dropout_prob=0.1,
|
||||||
|
max_position_embeddings=131072,
|
||||||
|
type_vocab_size=16,
|
||||||
|
type_sequence_label_size=2,
|
||||||
|
initializer_range=0.02,
|
||||||
|
num_labels=3,
|
||||||
|
num_choices=4,
|
||||||
|
pad_token_id=0,
|
||||||
|
scope=None,
|
||||||
|
original_max_position_embeddings=4096,
|
||||||
|
):
|
||||||
|
self.parent = parent
|
||||||
|
self.batch_size = batch_size
|
||||||
|
self.seq_length = seq_length
|
||||||
|
self.is_training = is_training
|
||||||
|
self.use_input_mask = use_input_mask
|
||||||
|
self.use_token_type_ids = use_token_type_ids
|
||||||
|
self.use_labels = use_labels
|
||||||
|
self.vocab_size = vocab_size
|
||||||
|
self.hidden_size = hidden_size
|
||||||
|
self.num_hidden_layers = num_hidden_layers
|
||||||
|
self.num_attention_heads = num_attention_heads
|
||||||
|
self.num_key_value_heads = num_key_value_heads
|
||||||
|
self.intermediate_size = intermediate_size
|
||||||
|
self.hidden_act = hidden_act
|
||||||
|
self.hidden_dropout_prob = hidden_dropout_prob
|
||||||
|
self.attention_probs_dropout_prob = attention_probs_dropout_prob
|
||||||
|
self.max_position_embeddings = max_position_embeddings
|
||||||
|
self.type_vocab_size = type_vocab_size
|
||||||
|
self.type_sequence_label_size = type_sequence_label_size
|
||||||
|
self.initializer_range = initializer_range
|
||||||
|
self.num_labels = num_labels
|
||||||
|
self.num_choices = num_choices
|
||||||
|
self.pad_token_id = pad_token_id
|
||||||
|
self.scope = scope
|
||||||
|
self.original_max_position_embeddings = original_max_position_embeddings
|
||||||
|
|
||||||
|
# Copied from tests.models.llama.test_modeling_llama.LlamaModelTester.prepare_config_and_inputs
|
||||||
|
def prepare_config_and_inputs(self):
|
||||||
|
input_ids = ids_tensor([self.batch_size, self.seq_length], self.vocab_size)
|
||||||
|
|
||||||
|
input_mask = None
|
||||||
|
if self.use_input_mask:
|
||||||
|
input_mask = torch.tril(torch.ones(self.batch_size, self.seq_length)).to(torch_device)
|
||||||
|
|
||||||
|
token_type_ids = None
|
||||||
|
if self.use_token_type_ids:
|
||||||
|
token_type_ids = ids_tensor([self.batch_size, self.seq_length], self.type_vocab_size)
|
||||||
|
|
||||||
|
sequence_labels = None
|
||||||
|
token_labels = None
|
||||||
|
choice_labels = None
|
||||||
|
if self.use_labels:
|
||||||
|
sequence_labels = ids_tensor([self.batch_size], self.type_sequence_label_size)
|
||||||
|
token_labels = ids_tensor([self.batch_size, self.seq_length], self.num_labels)
|
||||||
|
choice_labels = ids_tensor([self.batch_size], self.num_choices)
|
||||||
|
|
||||||
|
config = self.get_config()
|
||||||
|
|
||||||
|
return config, input_ids, token_type_ids, input_mask, sequence_labels, token_labels, choice_labels
|
||||||
|
|
||||||
|
def get_config(self):
|
||||||
|
return PhimoeConfig(
|
||||||
|
vocab_size=self.vocab_size,
|
||||||
|
hidden_size=self.hidden_size,
|
||||||
|
num_hidden_layers=self.num_hidden_layers,
|
||||||
|
num_attention_heads=self.num_attention_heads,
|
||||||
|
num_key_value_heads=self.num_key_value_heads,
|
||||||
|
intermediate_size=self.intermediate_size,
|
||||||
|
hidden_act=self.hidden_act,
|
||||||
|
hidden_dropout_prob=self.hidden_dropout_prob,
|
||||||
|
attention_probs_dropout_prob=self.attention_probs_dropout_prob,
|
||||||
|
max_position_embeddings=self.max_position_embeddings,
|
||||||
|
type_vocab_size=self.type_vocab_size,
|
||||||
|
is_decoder=False,
|
||||||
|
initializer_range=self.initializer_range,
|
||||||
|
pad_token_id=self.pad_token_id,
|
||||||
|
num_experts_per_tok=2,
|
||||||
|
num_local_experts=2,
|
||||||
|
original_max_position_embeddings=self.original_max_position_embeddings,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Copied from tests.models.llama.test_modeling_llama.LlamaModelTester.create_and_check_model with Llama->Phimoe
|
||||||
|
def create_and_check_model(
|
||||||
|
self, config, input_ids, token_type_ids, input_mask, sequence_labels, token_labels, choice_labels
|
||||||
|
):
|
||||||
|
model = PhimoeModel(config=config)
|
||||||
|
model.to(torch_device)
|
||||||
|
model.eval()
|
||||||
|
result = model(input_ids, attention_mask=input_mask)
|
||||||
|
result = model(input_ids)
|
||||||
|
self.parent.assertEqual(result.last_hidden_state.shape, (self.batch_size, self.seq_length, self.hidden_size))
|
||||||
|
|
||||||
|
# Copied from tests.models.llama.test_modeling_llama.LlamaModelTester.create_and_check_model_as_decoder with Llama->Phimoe
|
||||||
|
def create_and_check_model_as_decoder(
|
||||||
|
self,
|
||||||
|
config,
|
||||||
|
input_ids,
|
||||||
|
token_type_ids,
|
||||||
|
input_mask,
|
||||||
|
sequence_labels,
|
||||||
|
token_labels,
|
||||||
|
choice_labels,
|
||||||
|
encoder_hidden_states,
|
||||||
|
encoder_attention_mask,
|
||||||
|
):
|
||||||
|
config.add_cross_attention = True
|
||||||
|
model = PhimoeModel(config)
|
||||||
|
model.to(torch_device)
|
||||||
|
model.eval()
|
||||||
|
result = model(
|
||||||
|
input_ids,
|
||||||
|
attention_mask=input_mask,
|
||||||
|
encoder_hidden_states=encoder_hidden_states,
|
||||||
|
encoder_attention_mask=encoder_attention_mask,
|
||||||
|
)
|
||||||
|
result = model(
|
||||||
|
input_ids,
|
||||||
|
attention_mask=input_mask,
|
||||||
|
encoder_hidden_states=encoder_hidden_states,
|
||||||
|
)
|
||||||
|
result = model(input_ids, attention_mask=input_mask)
|
||||||
|
self.parent.assertEqual(result.last_hidden_state.shape, (self.batch_size, self.seq_length, self.hidden_size))
|
||||||
|
|
||||||
|
# Copied from tests.models.llama.test_modeling_llama.LlamaModelTester.create_and_check_for_causal_lm with Llama->Phimoe
|
||||||
|
def create_and_check_for_causal_lm(
|
||||||
|
self,
|
||||||
|
config,
|
||||||
|
input_ids,
|
||||||
|
token_type_ids,
|
||||||
|
input_mask,
|
||||||
|
sequence_labels,
|
||||||
|
token_labels,
|
||||||
|
choice_labels,
|
||||||
|
encoder_hidden_states,
|
||||||
|
encoder_attention_mask,
|
||||||
|
):
|
||||||
|
model = PhimoeForCausalLM(config=config)
|
||||||
|
model.to(torch_device)
|
||||||
|
model.eval()
|
||||||
|
result = model(input_ids, attention_mask=input_mask, labels=token_labels)
|
||||||
|
self.parent.assertEqual(result.logits.shape, (self.batch_size, self.seq_length, self.vocab_size))
|
||||||
|
|
||||||
|
# Copied from tests.models.llama.test_modeling_llama.LlamaModelTester.create_and_check_decoder_model_past_large_inputs with Llama->Phimoe
|
||||||
|
def create_and_check_decoder_model_past_large_inputs(
|
||||||
|
self,
|
||||||
|
config,
|
||||||
|
input_ids,
|
||||||
|
token_type_ids,
|
||||||
|
input_mask,
|
||||||
|
sequence_labels,
|
||||||
|
token_labels,
|
||||||
|
choice_labels,
|
||||||
|
encoder_hidden_states,
|
||||||
|
encoder_attention_mask,
|
||||||
|
):
|
||||||
|
config.is_decoder = True
|
||||||
|
config.add_cross_attention = True
|
||||||
|
model = PhimoeForCausalLM(config=config)
|
||||||
|
model.to(torch_device)
|
||||||
|
model.eval()
|
||||||
|
|
||||||
|
# first forward pass
|
||||||
|
outputs = model(
|
||||||
|
input_ids,
|
||||||
|
attention_mask=input_mask,
|
||||||
|
encoder_hidden_states=encoder_hidden_states,
|
||||||
|
encoder_attention_mask=encoder_attention_mask,
|
||||||
|
use_cache=True,
|
||||||
|
)
|
||||||
|
past_key_values = outputs.past_key_values
|
||||||
|
|
||||||
|
# create hypothetical multiple next token and extent to next_input_ids
|
||||||
|
next_tokens = ids_tensor((self.batch_size, 3), config.vocab_size)
|
||||||
|
next_mask = ids_tensor((self.batch_size, 3), vocab_size=2)
|
||||||
|
|
||||||
|
# append to next input_ids and
|
||||||
|
next_input_ids = torch.cat([input_ids, next_tokens], dim=-1)
|
||||||
|
next_attention_mask = torch.cat([input_mask, next_mask], dim=-1)
|
||||||
|
|
||||||
|
output_from_no_past = model(
|
||||||
|
next_input_ids,
|
||||||
|
attention_mask=next_attention_mask,
|
||||||
|
encoder_hidden_states=encoder_hidden_states,
|
||||||
|
encoder_attention_mask=encoder_attention_mask,
|
||||||
|
output_hidden_states=True,
|
||||||
|
)["hidden_states"][0]
|
||||||
|
output_from_past = model(
|
||||||
|
next_tokens,
|
||||||
|
attention_mask=next_attention_mask,
|
||||||
|
encoder_hidden_states=encoder_hidden_states,
|
||||||
|
encoder_attention_mask=encoder_attention_mask,
|
||||||
|
past_key_values=past_key_values,
|
||||||
|
output_hidden_states=True,
|
||||||
|
)["hidden_states"][0]
|
||||||
|
|
||||||
|
# select random slice
|
||||||
|
random_slice_idx = ids_tensor((1,), output_from_past.shape[-1]).item()
|
||||||
|
output_from_no_past_slice = output_from_no_past[:, -3:, random_slice_idx].detach()
|
||||||
|
output_from_past_slice = output_from_past[:, :, random_slice_idx].detach()
|
||||||
|
|
||||||
|
self.parent.assertTrue(output_from_past_slice.shape[1] == next_tokens.shape[1])
|
||||||
|
|
||||||
|
# test that outputs are equal for slice
|
||||||
|
self.parent.assertTrue(torch.allclose(output_from_past_slice, output_from_no_past_slice, atol=1e-3))
|
||||||
|
|
||||||
|
# Copied from tests.models.llama.test_modeling_llama.LlamaModelTester.prepare_config_and_inputs_for_common
|
||||||
|
def prepare_config_and_inputs_for_common(self):
|
||||||
|
config_and_inputs = self.prepare_config_and_inputs()
|
||||||
|
(
|
||||||
|
config,
|
||||||
|
input_ids,
|
||||||
|
token_type_ids,
|
||||||
|
input_mask,
|
||||||
|
sequence_labels,
|
||||||
|
token_labels,
|
||||||
|
choice_labels,
|
||||||
|
) = config_and_inputs
|
||||||
|
inputs_dict = {"input_ids": input_ids, "attention_mask": input_mask}
|
||||||
|
return config, inputs_dict
|
||||||
|
|
||||||
|
|
||||||
|
@require_torch
|
||||||
|
class PhimoeModelTest(ModelTesterMixin, GenerationTesterMixin, PipelineTesterMixin, unittest.TestCase):
|
||||||
|
all_model_classes = (
|
||||||
|
(PhimoeModel, PhimoeForCausalLM, PhimoeForSequenceClassification) if is_torch_available() else ()
|
||||||
|
)
|
||||||
|
all_generative_model_classes = (PhimoeForCausalLM,) if is_torch_available() else ()
|
||||||
|
pipeline_model_mapping = (
|
||||||
|
{
|
||||||
|
"feature-extraction": PhimoeModel,
|
||||||
|
"text-classification": PhimoeForSequenceClassification,
|
||||||
|
"text-generation": PhimoeForCausalLM,
|
||||||
|
"zero-shot": PhimoeForSequenceClassification,
|
||||||
|
}
|
||||||
|
if is_torch_available()
|
||||||
|
else {}
|
||||||
|
)
|
||||||
|
|
||||||
|
test_headmasking = False
|
||||||
|
test_pruning = False
|
||||||
|
|
||||||
|
# TODO (ydshieh): Check this. See https://app.circleci.com/pipelines/github/huggingface/transformers/79292/workflows/fa2ba644-8953-44a6-8f67-ccd69ca6a476/jobs/1012905
|
||||||
|
def is_pipeline_test_to_skip(
|
||||||
|
self, pipeline_test_casse_name, config_class, model_architecture, tokenizer_name, processor_name
|
||||||
|
):
|
||||||
|
return True
|
||||||
|
|
||||||
|
# Copied from tests.models.llama.test_modeling_llama.LlamaModelTest.setUp with Llama->Phimoe
|
||||||
|
def setUp(self):
|
||||||
|
self.model_tester = PhimoeModelTester(self)
|
||||||
|
self.config_tester = ConfigTester(self, config_class=PhimoeConfig, hidden_size=37)
|
||||||
|
|
||||||
|
# Copied from tests.models.llama.test_modeling_llama.LlamaModelTest.test_config
|
||||||
|
def test_config(self):
|
||||||
|
self.config_tester.run_common_tests()
|
||||||
|
|
||||||
|
# Copied from tests.models.llama.test_modeling_llama.LlamaModelTest.test_model
|
||||||
|
def test_model(self):
|
||||||
|
config_and_inputs = self.model_tester.prepare_config_and_inputs()
|
||||||
|
self.model_tester.create_and_check_model(*config_and_inputs)
|
||||||
|
|
||||||
|
# Copied from tests.models.llama.test_modeling_llama.LlamaModelTest.test_llama_sequence_classification_model with Llama->Phimoe,llama->phimoe
|
||||||
|
def test_phimoe_sequence_classification_model(self):
|
||||||
|
config, input_dict = self.model_tester.prepare_config_and_inputs_for_common()
|
||||||
|
config.num_labels = 3
|
||||||
|
input_ids = input_dict["input_ids"]
|
||||||
|
attention_mask = input_ids.ne(1).to(torch_device)
|
||||||
|
sequence_labels = ids_tensor([self.model_tester.batch_size], self.model_tester.type_sequence_label_size)
|
||||||
|
model = PhimoeForSequenceClassification(config)
|
||||||
|
model.to(torch_device)
|
||||||
|
model.eval()
|
||||||
|
result = model(input_ids, attention_mask=attention_mask, labels=sequence_labels)
|
||||||
|
self.assertEqual(result.logits.shape, (self.model_tester.batch_size, self.model_tester.num_labels))
|
||||||
|
|
||||||
|
# Copied from tests.models.llama.test_modeling_llama.LlamaModelTest.test_llama_sequence_classification_model_for_single_label with Llama->Phimoe,llama->phimoe
|
||||||
|
def test_phimoe_sequence_classification_model_for_single_label(self):
|
||||||
|
config, input_dict = self.model_tester.prepare_config_and_inputs_for_common()
|
||||||
|
config.num_labels = 3
|
||||||
|
config.problem_type = "single_label_classification"
|
||||||
|
input_ids = input_dict["input_ids"]
|
||||||
|
attention_mask = input_ids.ne(1).to(torch_device)
|
||||||
|
sequence_labels = ids_tensor([self.model_tester.batch_size], self.model_tester.type_sequence_label_size)
|
||||||
|
model = PhimoeForSequenceClassification(config)
|
||||||
|
model.to(torch_device)
|
||||||
|
model.eval()
|
||||||
|
result = model(input_ids, attention_mask=attention_mask, labels=sequence_labels)
|
||||||
|
self.assertEqual(result.logits.shape, (self.model_tester.batch_size, self.model_tester.num_labels))
|
||||||
|
|
||||||
|
# Copied from tests.models.llama.test_modeling_llama.LlamaModelTest.test_llama_sequence_classification_model_for_multi_label with Llama->Phimoe,llama->phimoe
|
||||||
|
def test_phimoe_sequence_classification_model_for_multi_label(self):
|
||||||
|
config, input_dict = self.model_tester.prepare_config_and_inputs_for_common()
|
||||||
|
config.num_labels = 3
|
||||||
|
config.problem_type = "multi_label_classification"
|
||||||
|
input_ids = input_dict["input_ids"]
|
||||||
|
attention_mask = input_ids.ne(1).to(torch_device)
|
||||||
|
sequence_labels = ids_tensor(
|
||||||
|
[self.model_tester.batch_size, config.num_labels], self.model_tester.type_sequence_label_size
|
||||||
|
).to(torch.float)
|
||||||
|
model = PhimoeForSequenceClassification(config)
|
||||||
|
model.to(torch_device)
|
||||||
|
model.eval()
|
||||||
|
result = model(input_ids, attention_mask=attention_mask, labels=sequence_labels)
|
||||||
|
self.assertEqual(result.logits.shape, (self.model_tester.batch_size, self.model_tester.num_labels))
|
||||||
|
|
||||||
|
@parameterized.expand([("longrope",)])
|
||||||
|
def test_model_rope_scaling_from_config(self, scaling_type):
|
||||||
|
config, _ = self.model_tester.prepare_config_and_inputs_for_common()
|
||||||
|
short_input = ids_tensor([1, 10], config.vocab_size)
|
||||||
|
long_input = ids_tensor([1, int(config.original_max_position_embeddings * 1.5)], config.vocab_size)
|
||||||
|
|
||||||
|
set_seed(42) # Fixed seed at init time so the two models get the same random weights
|
||||||
|
original_model = PhimoeModel(config)
|
||||||
|
original_model.to(torch_device)
|
||||||
|
original_model.eval()
|
||||||
|
original_short_output = original_model(short_input).last_hidden_state
|
||||||
|
original_long_output = original_model(long_input).last_hidden_state
|
||||||
|
|
||||||
|
set_seed(42) # Fixed seed at init time so the two models get the same random weights
|
||||||
|
n_factors = config.hidden_size // config.num_attention_heads // 2
|
||||||
|
config.rope_scaling = {
|
||||||
|
"type": scaling_type,
|
||||||
|
"short_factor": [3.0 for _ in range(n_factors)],
|
||||||
|
"long_factor": [5.0 for _ in range(n_factors)],
|
||||||
|
"short_mscale": 1.243163121016122,
|
||||||
|
"long_mscale": 1.243163121016122,
|
||||||
|
"original_max_position_embeddings": 4096,
|
||||||
|
}
|
||||||
|
scaled_model = PhimoeModel(config)
|
||||||
|
scaled_model.to(torch_device)
|
||||||
|
scaled_model.eval()
|
||||||
|
scaled_short_output = scaled_model(short_input).last_hidden_state
|
||||||
|
scaled_long_output = scaled_model(long_input).last_hidden_state
|
||||||
|
|
||||||
|
# Scaling changes the RoPE embeddings, both for the short and long outputs
|
||||||
|
self.assertFalse(torch.allclose(original_short_output, scaled_short_output, atol=1e-5))
|
||||||
|
self.assertFalse(torch.allclose(original_long_output, scaled_long_output, atol=1e-5))
|
||||||
|
|
||||||
|
@parameterized.expand([("longrope",)])
|
||||||
|
def test_model_rope_scaling_short_long_factor(self, scaling_type):
|
||||||
|
config, _ = self.model_tester.prepare_config_and_inputs_for_common()
|
||||||
|
n_factors = config.hidden_size // config.num_key_value_heads // 2
|
||||||
|
config.rope_scaling = {
|
||||||
|
"type": scaling_type,
|
||||||
|
"short_factor": [3.0 for _ in range(n_factors)],
|
||||||
|
"long_factor": [5.0 for _ in range(n_factors)],
|
||||||
|
"short_mscale": 1.243163121016122,
|
||||||
|
"long_mscale": 1.243163121016122,
|
||||||
|
"original_max_position_embeddings": 4096,
|
||||||
|
}
|
||||||
|
input_tensor = ids_tensor([1, 4090], config.vocab_size)
|
||||||
|
model = PhimoeForCausalLM(config)
|
||||||
|
model.to(torch_device)
|
||||||
|
model.eval()
|
||||||
|
generation_args_short = {
|
||||||
|
"max_length": config.original_max_position_embeddings,
|
||||||
|
"temperature": 0.0,
|
||||||
|
"use_cache": True,
|
||||||
|
"do_sample": False,
|
||||||
|
"return_dict_in_generate": True,
|
||||||
|
}
|
||||||
|
output_with_short_factor = model.generate(input_tensor, **generation_args_short)
|
||||||
|
keys_with_short_factor = output_with_short_factor.past_key_values[0][0]
|
||||||
|
generation_args_long = {
|
||||||
|
"max_length": config.original_max_position_embeddings + 5,
|
||||||
|
"temperature": 0.0,
|
||||||
|
"use_cache": True,
|
||||||
|
"do_sample": False,
|
||||||
|
"return_dict_in_generate": True,
|
||||||
|
"output_logits": True,
|
||||||
|
}
|
||||||
|
output_with_long_factor = model.generate(input_tensor, **generation_args_long)
|
||||||
|
keys_with_long_factor = output_with_long_factor.past_key_values[0][0]
|
||||||
|
last_token_logits = output_with_long_factor.logits[-1][-1]
|
||||||
|
regenerated_last_token_logits = model(output_with_long_factor.sequences[:, :-1]).logits[0][-1]
|
||||||
|
keys_with_long_factor = keys_with_long_factor[:, :, : config.original_max_position_embeddings - 1, :]
|
||||||
|
|
||||||
|
# KV cache is re-computed after reaching the (`config.original_max_position_embeddings`+1)th token position
|
||||||
|
self.assertFalse(torch.allclose(keys_with_short_factor, keys_with_long_factor, atol=1e-3, rtol=1e-3))
|
||||||
|
# Last token generated using long factor
|
||||||
|
self.assertTrue(torch.allclose(last_token_logits, regenerated_last_token_logits, atol=1e-2, rtol=1e-2))
|
||||||
|
|
||||||
|
|
||||||
|
@slow
|
||||||
|
@require_torch
|
||||||
|
class PhimoeIntegrationTest(unittest.TestCase):
|
||||||
|
def test_model_phimoe_instruct_logits(self):
|
||||||
|
input_ids = {
|
||||||
|
"input_ids": torch.tensor(
|
||||||
|
[[1212, 318, 281, 1672, 2643, 290, 428, 318, 257, 1332]], dtype=torch.long, device=torch_device
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
model = PhimoeForCausalLM.from_pretrained("microsoft/Phi-3.5-MoE-instruct").to(torch_device)
|
||||||
|
model.eval()
|
||||||
|
|
||||||
|
output = model(**input_ids).logits
|
||||||
|
|
||||||
|
EXPECTED_OUTPUT = torch.tensor([[-3.5312, -2.5000, -1.2734, 0.3555, -0.7578, -0.4727, 0.5977, -0.4316,
|
||||||
|
0.2256, -1.2188, -1.6797, 0.9961, 3.7656, 11.3125, -1.3828, -4.8438,
|
||||||
|
-5.7500, -1.9375, 0.7227, -0.3438, -0.2100, -0.4277, -0.0444, -0.5352,
|
||||||
|
-0.6406, -0.1016, -0.4258, -1.0234, 0.4297, -0.6250],
|
||||||
|
[-0.9883, 0.1455, -0.4902, 2.3594, 0.7031, 3.1406, 0.4375, 0.2559,
|
||||||
|
0.6172, -2.1094, -1.3359, 2.5938, 4.9062, 10.8125, -0.1094, 1.5781,
|
||||||
|
-4.9375, 0.7148, -0.0972, 1.7656, -0.0801, 0.2217, 0.1875, -0.4629,
|
||||||
|
1.5781, 0.3535, 0.0874, 0.6836, -0.0518, -1.2969]]).to(torch_device) # fmt: skip
|
||||||
|
|
||||||
|
self.assertTrue(torch.allclose(EXPECTED_OUTPUT, output[0, :2, :30], atol=1e-4, rtol=1e-4))
|
||||||
|
|
||||||
|
def test_phimoe_instruct_generation(self):
|
||||||
|
model = PhimoeForCausalLM.from_pretrained("microsoft/Phi-3.5-MoE-instruct")
|
||||||
|
tokenizer = AutoTokenizer.from_pretrained("microsoft/Phi-3.5-MoE-instruct")
|
||||||
|
|
||||||
|
messages = [
|
||||||
|
{
|
||||||
|
"role": "system",
|
||||||
|
"content": "You are a helpful digital assistant. Please provide safe, ethical and accurate information to the user.",
|
||||||
|
},
|
||||||
|
{"role": "user", "content": "Can you provide ways to eat combinations of bananas and dragonfruits?"},
|
||||||
|
]
|
||||||
|
inputs = tokenizer.apply_chat_template(messages, add_generation_prompt=True, return_tensors="pt")
|
||||||
|
|
||||||
|
outputs = model.generate(inputs, max_new_tokens=32)
|
||||||
|
output_text = tokenizer.batch_decode(outputs)
|
||||||
|
|
||||||
|
EXPECTED_OUTPUT = [
|
||||||
|
"<|system|> You are a helpful digital assistant. Please provide safe, ethical and accurate information to the user.<|end|><|user|> Can you provide ways to eat combinations of bananas and dragonfruits?<|end|><|assistant|> Certainly! Bananas and dragonfruits are both delicious and nutritious fruits that can be combined in various ways to create tast"
|
||||||
|
]
|
||||||
|
|
||||||
|
self.assertListEqual(output_text, EXPECTED_OUTPUT)
|
||||||
|
|
||||||
|
def test_phimoe_instruct_with_static_cache(self):
|
||||||
|
model = PhimoeForCausalLM.from_pretrained("microsoft/Phi-3.5-MoE-instruct")
|
||||||
|
tokenizer = AutoTokenizer.from_pretrained("microsoft/Phi-3.5-MoE-instruct")
|
||||||
|
|
||||||
|
messages = [
|
||||||
|
{
|
||||||
|
"role": "system",
|
||||||
|
"content": "You are a helpful digital assistant. Please provide safe, ethical and accurate information to the user.",
|
||||||
|
},
|
||||||
|
{"role": "user", "content": "Can you provide ways to eat combinations of bananas and dragonfruits?"},
|
||||||
|
]
|
||||||
|
inputs = tokenizer.apply_chat_template(messages, add_generation_prompt=True, return_tensors="pt")
|
||||||
|
|
||||||
|
response_tokens = PhimoeMiniWithStaticCache.generate(model, inputs, 64)
|
||||||
|
|
||||||
|
output_text = tokenizer.batch_decode(torch.tensor([response_tokens], dtype=torch.long, device=torch_device))
|
||||||
|
|
||||||
|
EXPECTED_OUTPUT = [
|
||||||
|
"<|system|> You are a helpful digital assistant. Please provide safe, ethical and accurate information to the user.<|end|><|user|> Can you provide ways to eat combinations of bananas and dragonfruits?<|end|><|assistant|> Certainly! Bananas and dragonfruits are both delicious and nutritious fruits that can"
|
||||||
|
]
|
||||||
|
|
||||||
|
self.assertListEqual(output_text, EXPECTED_OUTPUT)
|
||||||
Reference in New Issue
Block a user