341 lines
12 KiB
Python
341 lines
12 KiB
Python
import inspect
|
|
import logging
|
|
import sys
|
|
|
|
import transformers
|
|
from packaging.version import Version
|
|
|
|
from mlflow.transformers import _PEFT_PIPELINE_ERROR_MSG, _try_import_conversational_pipeline
|
|
from mlflow.utils.logging_utils import suppress_logs
|
|
|
|
from tests.helper_functions import flaky
|
|
from tests.transformers.version import (
|
|
IS_NEW_FEATURE_EXTRACTION_API,
|
|
IS_TRANSFORMERS_V5_OR_LATER,
|
|
transformers_version,
|
|
)
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
CHAT_TEMPLATE = "{% for message in messages %}{{ message.content }}{{ eos_token }}{% endfor %}"
|
|
|
|
|
|
def prefetch(func):
|
|
"""
|
|
Annotation decorator for marking model loading functions to run before testing.
|
|
"""
|
|
func.is_prefetch = True
|
|
return func
|
|
|
|
|
|
@prefetch
|
|
@flaky()
|
|
def load_small_qa_pipeline():
|
|
if IS_TRANSFORMERS_V5_OR_LATER:
|
|
_logger.info("Skipping question-answering pipeline prefetch: removed in transformers 5.x")
|
|
return None
|
|
architecture = "csarron/mobilebert-uncased-squad-v2"
|
|
tokenizer = transformers.AutoTokenizer.from_pretrained(architecture, low_cpu_mem_usage=True)
|
|
model = transformers.MobileBertForQuestionAnswering.from_pretrained(
|
|
architecture, low_cpu_mem_usage=True
|
|
)
|
|
return transformers.pipeline(task="question-answering", model=model, tokenizer=tokenizer)
|
|
|
|
|
|
@prefetch
|
|
@flaky()
|
|
def load_small_vision_model():
|
|
architecture = "google/mobilenet_v2_1.0_224"
|
|
model = transformers.MobileNetV2ForImageClassification.from_pretrained(
|
|
architecture, low_cpu_mem_usage=True
|
|
)
|
|
if IS_NEW_FEATURE_EXTRACTION_API:
|
|
image_processor = transformers.AutoImageProcessor.from_pretrained(
|
|
architecture, low_cpu_mem_usage=True
|
|
)
|
|
return transformers.pipeline(
|
|
task="image-classification", model=model, image_processor=image_processor
|
|
)
|
|
else:
|
|
feature_extractor = transformers.AutoFeatureExtractor.from_pretrained(
|
|
architecture, low_cpu_mem_usage=True
|
|
)
|
|
return transformers.pipeline(
|
|
task="image-classification", model=model, feature_extractor=feature_extractor
|
|
)
|
|
|
|
|
|
@prefetch
|
|
@flaky()
|
|
def load_small_multi_modal_pipeline():
|
|
if IS_TRANSFORMERS_V5_OR_LATER:
|
|
_logger.info(
|
|
"Skipping visual-question-answering pipeline prefetch: removed in transformers 5.x"
|
|
)
|
|
return None
|
|
architecture = "dandelin/vilt-b32-finetuned-vqa"
|
|
return transformers.pipeline(model=architecture)
|
|
|
|
|
|
@prefetch
|
|
@flaky()
|
|
def load_component_multi_modal():
|
|
if IS_TRANSFORMERS_V5_OR_LATER:
|
|
_logger.info("Skipping VQA component model prefetch: removed in transformers 5.x")
|
|
return None
|
|
architecture = "dandelin/vilt-b32-finetuned-vqa"
|
|
tokenizer = transformers.BertTokenizerFast.from_pretrained(architecture, low_cpu_mem_usage=True)
|
|
processor = transformers.ViltProcessor.from_pretrained(architecture, low_cpu_mem_usage=True)
|
|
image_processor = transformers.ViltImageProcessor.from_pretrained(
|
|
architecture, low_cpu_mem_usage=True
|
|
)
|
|
model = transformers.ViltForQuestionAnswering.from_pretrained(
|
|
architecture, low_cpu_mem_usage=True
|
|
)
|
|
transformers_model = {"model": model, "tokenizer": tokenizer}
|
|
if IS_NEW_FEATURE_EXTRACTION_API:
|
|
transformers_model["image_processor"] = image_processor
|
|
else:
|
|
transformers_model["feature_extractor"] = processor
|
|
return transformers_model
|
|
|
|
|
|
@prefetch
|
|
@flaky()
|
|
def load_small_conversational_model():
|
|
if _try_import_conversational_pipeline():
|
|
tokenizer = transformers.AutoTokenizer.from_pretrained(
|
|
"microsoft/DialoGPT-small", low_cpu_mem_usage=True
|
|
)
|
|
model = transformers.AutoModelForCausalLM.from_pretrained(
|
|
"satvikag/chatbot", low_cpu_mem_usage=True
|
|
)
|
|
return transformers.pipeline(task="conversational", model=model, tokenizer=tokenizer)
|
|
|
|
|
|
@prefetch
|
|
@flaky()
|
|
def load_fill_mask_pipeline():
|
|
architecture = "distilroberta-base"
|
|
model = transformers.AutoModelForMaskedLM.from_pretrained(architecture, low_cpu_mem_usage=True)
|
|
tokenizer = transformers.AutoTokenizer.from_pretrained(architecture)
|
|
return transformers.pipeline(task="fill-mask", model=model, tokenizer=tokenizer)
|
|
|
|
|
|
@prefetch
|
|
@flaky()
|
|
def load_text2text_generation_pipeline():
|
|
if IS_TRANSFORMERS_V5_OR_LATER:
|
|
_logger.info("Skipping text2text-generation pipeline prefetch: removed in transformers 5.x")
|
|
return None
|
|
task = "text2text-generation"
|
|
architecture = "mrm8488/t5-small-finetuned-common_gen"
|
|
model = transformers.T5ForConditionalGeneration.from_pretrained(architecture)
|
|
tokenizer = transformers.T5TokenizerFast.from_pretrained(architecture)
|
|
return transformers.pipeline(task=task, tokenizer=tokenizer, model=model)
|
|
|
|
|
|
@prefetch
|
|
@flaky()
|
|
def load_text_generation_pipeline():
|
|
task = "text-generation"
|
|
architecture = "distilgpt2"
|
|
model = transformers.AutoModelForCausalLM.from_pretrained(architecture)
|
|
tokenizer = transformers.AutoTokenizer.from_pretrained(
|
|
architecture, chat_template=CHAT_TEMPLATE
|
|
)
|
|
return transformers.pipeline(task=task, model=model, tokenizer=tokenizer)
|
|
|
|
|
|
@prefetch
|
|
@flaky()
|
|
def load_translation_pipeline():
|
|
if IS_TRANSFORMERS_V5_OR_LATER:
|
|
_logger.info("Skipping translation pipeline prefetch: removed in transformers 5.x")
|
|
return None
|
|
return transformers.pipeline(
|
|
task="translation_en_to_de",
|
|
model=transformers.T5ForConditionalGeneration.from_pretrained("t5-small"),
|
|
tokenizer=transformers.T5TokenizerFast.from_pretrained("t5-small", model_max_length=100),
|
|
)
|
|
|
|
|
|
@prefetch
|
|
@flaky()
|
|
def load_summarizer_pipeline():
|
|
if IS_TRANSFORMERS_V5_OR_LATER:
|
|
_logger.info("Skipping summarizer pipeline prefetch: removed in transformers 5.x")
|
|
return None
|
|
task = "summarization"
|
|
architecture = "sshleifer/distilbart-cnn-6-6"
|
|
model = transformers.BartForConditionalGeneration.from_pretrained(architecture)
|
|
tokenizer = transformers.AutoTokenizer.from_pretrained(architecture)
|
|
return transformers.pipeline(task=task, tokenizer=tokenizer, model=model)
|
|
|
|
|
|
@prefetch
|
|
@flaky()
|
|
def load_text_classification_pipeline():
|
|
task = "text-classification"
|
|
architecture = "distilbert-base-uncased-finetuned-sst-2-english"
|
|
model = transformers.AutoModelForSequenceClassification.from_pretrained(architecture)
|
|
tokenizer = transformers.AutoTokenizer.from_pretrained(architecture)
|
|
return transformers.pipeline(
|
|
task=task,
|
|
tokenizer=tokenizer,
|
|
model=model,
|
|
)
|
|
|
|
|
|
@prefetch
|
|
@flaky()
|
|
def load_zero_shot_pipeline():
|
|
task = "zero-shot-classification"
|
|
architecture = "typeform/distilbert-base-uncased-mnli"
|
|
model = transformers.AutoModelForSequenceClassification.from_pretrained(architecture)
|
|
tokenizer = transformers.AutoTokenizer.from_pretrained(architecture)
|
|
return transformers.pipeline(task=task, tokenizer=tokenizer, model=model)
|
|
|
|
|
|
@prefetch
|
|
@flaky()
|
|
def load_table_question_answering_pipeline():
|
|
return transformers.pipeline(
|
|
task="table-question-answering", model="google/tapas-tiny-finetuned-sqa"
|
|
)
|
|
|
|
|
|
@prefetch
|
|
@flaky()
|
|
def load_ner_pipeline():
|
|
return transformers.pipeline(
|
|
task="token-classification", model="vblagoje/bert-english-uncased-finetuned-pos"
|
|
)
|
|
|
|
|
|
@prefetch
|
|
@flaky()
|
|
def load_ner_pipeline_aggregation():
|
|
return transformers.pipeline(
|
|
task="token-classification",
|
|
model="vblagoje/bert-english-uncased-finetuned-pos",
|
|
aggregation_strategy="average",
|
|
)
|
|
|
|
|
|
@prefetch
|
|
@flaky()
|
|
def load_conversational_pipeline():
|
|
if _try_import_conversational_pipeline():
|
|
return transformers.pipeline(
|
|
model="AVeryRealHuman/DialoGPT-small-TonyStark", task="conversational"
|
|
)
|
|
|
|
|
|
@prefetch
|
|
@flaky()
|
|
def load_whisper_pipeline():
|
|
task = "automatic-speech-recognition"
|
|
architecture = "openai/whisper-tiny"
|
|
model = transformers.WhisperForConditionalGeneration.from_pretrained(architecture)
|
|
tokenizer = transformers.WhisperTokenizer.from_pretrained(architecture)
|
|
feature_extractor = transformers.WhisperFeatureExtractor.from_pretrained(architecture)
|
|
model.generation_config.alignment_heads = [[2, 2], [3, 0], [3, 2], [3, 3], [3, 4], [3, 5]]
|
|
if transformers_version > Version("4.49.0"):
|
|
# forced_decoder_ids is not allowed
|
|
# ref: https://github.com/huggingface/transformers/blob/6a2627918d84f25422b931507a8fb9146106ca20/src/transformers/generation/utils.py#L1083
|
|
model.generation_config.forced_decoder_ids = None
|
|
return transformers.pipeline(
|
|
task=task, model=model, tokenizer=tokenizer, feature_extractor=feature_extractor
|
|
)
|
|
|
|
|
|
@prefetch
|
|
@flaky()
|
|
def load_audio_classification_pipeline():
|
|
return transformers.pipeline("audio-classification", model="superb/wav2vec2-base-superb-ks")
|
|
|
|
|
|
@prefetch
|
|
@flaky()
|
|
def load_feature_extraction_pipeline():
|
|
st_arch = "sentence-transformers/all-MiniLM-L6-v2"
|
|
model = transformers.AutoModel.from_pretrained(st_arch)
|
|
tokenizer = transformers.AutoTokenizer.from_pretrained(st_arch)
|
|
return transformers.pipeline(model=model, tokenizer=tokenizer, task="feature-extraction")
|
|
|
|
|
|
@prefetch
|
|
@flaky()
|
|
def load_peft_pipeline():
|
|
try:
|
|
from peft import LoraConfig, TaskType, get_peft_model
|
|
except ImportError:
|
|
# Do nothing if PEFT is not installed
|
|
return
|
|
|
|
base_model_id = "Elron/bleurt-tiny-512"
|
|
base_model = transformers.AutoModelForSequenceClassification.from_pretrained(base_model_id)
|
|
tokenizer = transformers.AutoTokenizer.from_pretrained(base_model_id)
|
|
|
|
peft_config = LoraConfig(
|
|
task_type=TaskType.SEQ_CLS, inference_mode=False, r=8, lora_alpha=32, lora_dropout=0.1
|
|
)
|
|
peft_model = get_peft_model(base_model, peft_config)
|
|
with suppress_logs("transformers.pipelines.base", filter_regex=_PEFT_PIPELINE_ERROR_MSG):
|
|
return transformers.pipeline(
|
|
task="text-classification", model=peft_model, tokenizer=tokenizer
|
|
)
|
|
|
|
|
|
@prefetch
|
|
@flaky()
|
|
def load_custom_code_pipeline():
|
|
model = transformers.AutoModel.from_pretrained(
|
|
"hf-internal-testing/test_dynamic_model_with_util", trust_remote_code=True
|
|
)
|
|
tokenizer = transformers.AutoTokenizer.from_pretrained("google-bert/bert-base-uncased")
|
|
return transformers.pipeline(
|
|
task="feature-extraction",
|
|
model=model,
|
|
tokenizer=tokenizer,
|
|
)
|
|
|
|
|
|
@prefetch
|
|
@flaky()
|
|
def load_custom_components_pipeline():
|
|
model = transformers.AutoModel.from_pretrained(
|
|
"hf-internal-testing/test_dynamic_model_with_tokenizer", trust_remote_code=True
|
|
)
|
|
tokenizer = transformers.AutoTokenizer.from_pretrained(
|
|
"hf-internal-testing/test_dynamic_processor", trust_remote_code=True
|
|
)
|
|
feature_extractor = transformers.AutoFeatureExtractor.from_pretrained(
|
|
"hf-internal-testing/test_dynamic_processor",
|
|
trust_remote_code=True,
|
|
)
|
|
return transformers.pipeline(
|
|
task="feature-extraction",
|
|
model=model,
|
|
tokenizer=tokenizer,
|
|
feature_extractor=feature_extractor,
|
|
)
|
|
|
|
|
|
def prefetch_models():
|
|
"""
|
|
Prefetches models used in the test suite to avoid downloading them during the test run.
|
|
Fetching model weights from the HuggingFace Hub has been proven to be flaky in the past, so
|
|
we want to avoid doing it in the middle of the test run, instead, failing fast.
|
|
"""
|
|
# Get all model loading functions that are marked as @prefetch
|
|
for _, func in inspect.getmembers(sys.modules[__name__]):
|
|
if inspect.isfunction(func) and hasattr(func, "is_prefetch") and func.is_prefetch:
|
|
# Call the function to download the model to HuggingFace cache
|
|
func()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
prefetch_models()
|