Skip to content

Commit

Permalink
Integrate PEFT LoRA with HuggingFaceModel (mosaicml#2829)
Browse files Browse the repository at this point in the history
  • Loading branch information
dakinggg authored and ShashankMosaicML committed Feb 3, 2024
1 parent 44e691a commit 3fc2efe
Show file tree
Hide file tree
Showing 7 changed files with 658 additions and 65 deletions.
2 changes: 1 addition & 1 deletion composer/datasets/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ def __init__(
self.stop_sequence_id_len = len(self.stop_sequence_ids) + 2
self.tokenizer = tokenizer

def __call__(self, input_ids: torch.Tensor, scores: Optional[torch.FloatTensor] = None, **kwargs) -> bool:
def __call__(self, input_ids: torch.LongTensor, scores: Optional[torch.FloatTensor] = None, **kwargs) -> bool:
# For efficiency, we compare the last n tokens where n is the number of tokens in the stop_sequence
lookback_ids_batch = input_ids[:, :][:, -self.stop_sequence_id_len:]

Expand Down
271 changes: 234 additions & 37 deletions composer/models/huggingface.py

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,10 @@ def package_files(prefix: str, directory: str, extension: str):
'datasets>=2.4,<3',
]

extra_deps['peft'] = [
'peft>=0.7.0,<0.8',
]

extra_deps['sentencepiece'] = [
'protobuf<3.21',
'sentencepiece==0.1.99',
Expand Down
102 changes: 80 additions & 22 deletions tests/common/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"""Contains commonly used models that are shared across the test suite."""
import copy
from functools import partial
from typing import Any, Dict, Optional, Tuple, Union
from typing import TYPE_CHECKING, Any, Dict, Optional, Tuple, Union

import pytest
import torch
Expand All @@ -14,6 +14,9 @@
from composer.metrics.nlp import LanguageCrossEntropy, MaskedAccuracy
from composer.models import ComposerClassifier, HuggingFaceModel

if TYPE_CHECKING:
from transformers import PretrainedConfig, PreTrainedModel, PreTrainedTokenizer, PreTrainedTokenizerFast


class EmptyModel(ComposerClassifier):
"""Always predict 0 with no parameters."""
Expand Down Expand Up @@ -443,105 +446,160 @@ def forward(self, batch: Tuple[torch.Tensor, Any]) -> torch.Tensor:
# As a workaround, we inject objects into the PyTest namespace. Tests should not directly
# use pytest.{var}, but instead should import and use these helper copy methods so the
# objects in the PyTest namespace do not change.
def configure_tiny_bert_model():
def configure_tiny_bert_model() -> 'PreTrainedModel':
try:
from transformers import PreTrainedModel
assert isinstance(pytest.tiny_bert_model, PreTrainedModel)
return copy.deepcopy(pytest.tiny_bert_model)
except AttributeError:
pytest.skip('Composer installed without NLP support')


def configure_tiny_bert_tokenizer():
def configure_tiny_bert_tokenizer() -> Union['PreTrainedTokenizer', 'PreTrainedTokenizerFast']:
try:
from transformers import PreTrainedTokenizer, PreTrainedTokenizerFast
assert isinstance(pytest.tiny_bert_tokenizer, (PreTrainedTokenizer, PreTrainedTokenizerFast))
return copy.deepcopy(pytest.tiny_bert_tokenizer)
except AttributeError:
pytest.skip('Composer installed without NLP support')


def configure_tiny_bert_config():
def configure_tiny_bert_config() -> 'PretrainedConfig':
try:
from transformers import PretrainedConfig
assert isinstance(pytest.tiny_bert_config, PretrainedConfig)
return copy.deepcopy(pytest.tiny_bert_config)
except AttributeError:
pytest.skip('Composer installed without NLP support')


def configure_tiny_bert_hf_model(use_logits=True):
return HuggingFaceModel(configure_tiny_bert_model(), configure_tiny_bert_tokenizer(), use_logits) # type: ignore
def configure_tiny_bert_hf_model(use_logits: bool = True) -> HuggingFaceModel:
return HuggingFaceModel(configure_tiny_bert_model(), configure_tiny_bert_tokenizer(), use_logits)


def configure_tiny_deberta_model():
def configure_tiny_deberta_model() -> 'PreTrainedModel':
try:
from transformers import PreTrainedModel
assert isinstance(pytest.tiny_deberta_model, PreTrainedModel)
return copy.deepcopy(pytest.tiny_deberta_model)
except AttributeError:
pytest.skip('Composer installed without NLP support')


def configure_tiny_deberta_tokenizer():
def configure_tiny_deberta_tokenizer() -> Union['PreTrainedTokenizer', 'PreTrainedTokenizerFast']:
try:
from transformers import PreTrainedTokenizer, PreTrainedTokenizerFast
assert isinstance(pytest.tiny_deberta_tokenizer, (PreTrainedTokenizer, PreTrainedTokenizerFast))
return copy.deepcopy(pytest.tiny_deberta_tokenizer)
except AttributeError:
pytest.skip('Composer installed without NLP support')


def configure_tiny_deberta_config():
def configure_tiny_deberta_config() -> 'PretrainedConfig':
try:
from transformers import PretrainedConfig
assert isinstance(pytest.tiny_deberta_config, PretrainedConfig)
return copy.deepcopy(pytest.tiny_deberta_config)
except AttributeError:
pytest.skip('Composer installed without NLP support')


def configure_tiny_deberta_hf_model(use_logits=True):
def configure_tiny_deberta_hf_model(use_logits: bool = True) -> HuggingFaceModel:
return HuggingFaceModel(
configure_tiny_deberta_model(), # type: ignore
configure_tiny_deberta_tokenizer(), # type: ignore
configure_tiny_deberta_model(),
configure_tiny_deberta_tokenizer(),
use_logits,
)


def configure_tiny_gpt2_model():
def configure_tiny_gpt2_model() -> 'PreTrainedModel':
try:
from transformers import PreTrainedModel
assert isinstance(pytest.tiny_gpt2_model, PreTrainedModel)
return copy.deepcopy(pytest.tiny_gpt2_model)
except AttributeError:
pytest.skip('Composer installed without NLP support')


def configure_tiny_gpt2_tokenizer():
def configure_tiny_gpt2_tokenizer() -> Union['PreTrainedTokenizer', 'PreTrainedTokenizerFast']:
try:
from transformers import PreTrainedTokenizer, PreTrainedTokenizerFast
assert isinstance(pytest.tiny_gpt2_tokenizer, (PreTrainedTokenizer, PreTrainedTokenizerFast))
return copy.deepcopy(pytest.tiny_gpt2_tokenizer)
except AttributeError:
pytest.skip('Composer installed without NLP support')


def configure_tiny_gpt2_config():
def configure_tiny_gpt2_config() -> 'PretrainedConfig':
try:
from transformers import PretrainedConfig
assert isinstance(pytest.tiny_gpt2_config, PretrainedConfig)
return copy.deepcopy(pytest.tiny_gpt2_config)
except AttributeError:
pytest.skip('Composer installed without NLP support')


def configure_tiny_gpt2_hf_model(use_logits=True):
return HuggingFaceModel(configure_tiny_gpt2_model(), configure_tiny_gpt2_tokenizer(), use_logits) # type: ignore
def configure_tiny_gpt2_hf_model(use_logits: bool = True) -> HuggingFaceModel:
return HuggingFaceModel(configure_tiny_gpt2_model(), configure_tiny_gpt2_tokenizer(), use_logits)


def configure_tiny_t5_model():
def configure_tiny_t5_model() -> 'PreTrainedModel':
try:
from transformers import PreTrainedModel
assert isinstance(pytest.tiny_t5_model, PreTrainedModel)
return copy.deepcopy(pytest.tiny_t5_model)
except AttributeError:
pytest.skip('Composer installed without NLP support')


def configure_tiny_t5_tokenizer():
def configure_tiny_t5_tokenizer() -> Union['PreTrainedTokenizer', 'PreTrainedTokenizerFast']:
try:
from transformers import PreTrainedTokenizer, PreTrainedTokenizerFast
assert isinstance(pytest.tiny_t5_tokenizer, (PreTrainedTokenizer, PreTrainedTokenizerFast))
return copy.deepcopy(pytest.tiny_t5_tokenizer)
except AttributeError:
pytest.skip('Composer installed without NLP support')


def configure_tiny_t5_config():
def configure_tiny_t5_config() -> 'PretrainedConfig':
try:
from transformers import PretrainedConfig
assert isinstance(pytest.tiny_t5_config, PretrainedConfig)
return copy.deepcopy(pytest.tiny_t5_config)
except AttributeError:
pytest.skip('Composer installed without NLP support')


def configure_tiny_t5_hf_model(use_logits=True):
return HuggingFaceModel(configure_tiny_t5_model(), configure_tiny_t5_tokenizer(), use_logits) # type: ignore
def configure_tiny_t5_hf_model(use_logits: bool = True) -> HuggingFaceModel:
return HuggingFaceModel(configure_tiny_t5_model(), configure_tiny_t5_tokenizer(), use_logits)


def configure_tiny_mistral_model() -> 'PreTrainedModel':
try:
from transformers import PreTrainedModel
assert isinstance(pytest.tiny_mistral_model, PreTrainedModel)
return copy.deepcopy(pytest.tiny_mistral_model)
except AttributeError:
pytest.skip('Composer installed without NLP support')


def configure_tiny_mistral_tokenizer() -> Union['PreTrainedTokenizer', 'PreTrainedTokenizerFast']:
try:
from transformers import PreTrainedTokenizer, PreTrainedTokenizerFast
assert isinstance(pytest.tiny_mistral_tokenizer, (PreTrainedTokenizer, PreTrainedTokenizerFast))
return copy.deepcopy(pytest.tiny_mistral_tokenizer)
except AttributeError:
pytest.skip('Composer installed without NLP support')


def configure_tiny_mistral_config() -> 'PretrainedConfig':
try:
from transformers import PretrainedConfig
assert isinstance(pytest.tiny_mistral_config, PretrainedConfig)
return copy.deepcopy(pytest.tiny_mistral_config)
except AttributeError:
pytest.skip('Composer installed without NLP support')


def configure_tiny_mistral_hf_model(use_logits: bool = True) -> HuggingFaceModel:
return HuggingFaceModel(configure_tiny_mistral_model(), configure_tiny_mistral_tokenizer(), use_logits)
7 changes: 6 additions & 1 deletion tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,9 @@ def pytest_configure():
if TRANSFORMERS_INSTALLED:
from tests.fixtures.fixtures import (tiny_bert_config_helper, tiny_bert_model_helper,
tiny_bert_tokenizer_helper, tiny_gpt2_config_helper,
tiny_gpt2_model_helper, tiny_gpt2_tokenizer_helper, tiny_opt_config_helper,
tiny_gpt2_model_helper, tiny_gpt2_tokenizer_helper,
tiny_mistral_config_helper, tiny_mistral_model_helper,
tiny_mistral_tokenizer_helper, tiny_opt_config_helper,
tiny_opt_model_helper, tiny_opt_tokenizer_helper, tiny_t5_config_helper,
tiny_t5_model_helper, tiny_t5_tokenizer_helper)
pytest.tiny_bert_config = tiny_bert_config_helper() # type: ignore
Expand All @@ -126,6 +128,9 @@ def pytest_configure():
pytest.tiny_t5_config = tiny_t5_config_helper() # type: ignore
pytest.tiny_t5_model = tiny_t5_model_helper(pytest.tiny_t5_config) # type: ignore
pytest.tiny_t5_tokenizer = tiny_t5_tokenizer_helper() # type: ignore
pytest.tiny_mistral_config = tiny_mistral_config_helper() # type: ignore
pytest.tiny_mistral_model = tiny_mistral_model_helper(pytest.tiny_mistral_config) # type: ignore
pytest.tiny_mistral_tokenizer = tiny_mistral_tokenizer_helper() # type: ignore


def pytest_sessionfinish(session: pytest.Session, exitstatus: int):
Expand Down
56 changes: 56 additions & 0 deletions tests/fixtures/fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,47 @@ def _session_tiny_t5_model(_session_tiny_t5_config): # type: ignore
return tiny_t5_model_helper(_session_tiny_t5_config)


def tiny_mistral_config_helper():
transformers = pytest.importorskip('transformers')

tiny_overrides = {
'hidden_size': 128,
'intermediate_size': 256,
'num_attention_heads': 8,
'num_hidden_layers': 2,
'num_kv_heads': 4
}
return transformers.AutoConfig.from_pretrained('mistralai/Mistral-7B-v0.1', **tiny_overrides)


@pytest.fixture(scope='session')
def _session_tiny_mistral_config(): # type: ignore
return tiny_mistral_config_helper()


def tiny_mistral_tokenizer_helper():
transformers = pytest.importorskip('transformers')

hf_tokenizer = transformers.AutoTokenizer.from_pretrained('mistralai/Mistral-7B-v0.1', model_max_length=512)
return hf_tokenizer


@pytest.fixture(scope='session')
def _session_tiny_mistral_tokenizer(): # type: ignore
return tiny_mistral_tokenizer_helper()


def tiny_mistral_model_helper(config):
transformers = pytest.importorskip('transformers')

return transformers.AutoModelForCausalLM.from_config(config)


@pytest.fixture(scope='session')
def _session_tiny_t5_model(_session_tiny_t5_config): # type: ignore
return tiny_t5_model_helper(_session_tiny_t5_config)


@pytest.fixture
def tiny_bert_model(_session_tiny_bert_model):
return copy.deepcopy(_session_tiny_bert_model)
Expand Down Expand Up @@ -393,3 +434,18 @@ def tiny_t5_tokenizer(_session_tiny_t5_tokenizer):
@pytest.fixture
def tiny_t5_model(_session_tiny_t5_model):
return copy.deepcopy(_session_tiny_t5_model)


@pytest.fixture
def tiny_mistral_config(_session_tiny_mistral_config):
return copy.deepcopy(_session_tiny_mistral_config)


@pytest.fixture
def tiny_mistral_tokenizer(_session_tiny_mistral_tokenizer):
return copy.deepcopy(_session_tiny_mistral_tokenizer)


@pytest.fixture
def tiny_mistral_model(_session_tiny_mistral_model):
return copy.deepcopy(_session_tiny_mistral_model)
Loading

0 comments on commit 3fc2efe

Please sign in to comment.