From 5b55c322d8c2e6bda140f7814c149b1261c39b69 Mon Sep 17 00:00:00 2001 From: Dhiraj Kumar Sah Date: Wed, 24 Sep 2025 13:31:38 +0000 Subject: [PATCH 1/3] Example walk through on how to onboard a Causal LM on Qefficient Transformers. Signed-off-by: Dhiraj Kumar Sah --- examples/dummy_onboarding/causallm/README.md | 60 ++ .../causallm/dummy_pytorch_transforms.py | 659 ++++++++++++++++++ .../causallm/modeling_dummy.py | 396 +++++++++++ 3 files changed, 1115 insertions(+) create mode 100644 examples/dummy_onboarding/causallm/README.md create mode 100644 examples/dummy_onboarding/causallm/dummy_pytorch_transforms.py create mode 100644 examples/dummy_onboarding/causallm/modeling_dummy.py diff --git a/examples/dummy_onboarding/causallm/README.md b/examples/dummy_onboarding/causallm/README.md new file mode 100644 index 000000000..dc8e1b5f7 --- /dev/null +++ b/examples/dummy_onboarding/causallm/README.md @@ -0,0 +1,60 @@ +# Onboarding a CausalLM Model + +## Prerequisites + +Before beginning the onboarding process, ensure you have `qefficient-transformers` library installed in editable mode. + + +## Introduction + +This README provides a step-by-step guide on how to on-board a CausalLM model. The process includes setting up the environment, modifying configuration files, and running the model. +We will use a dummy model named `Blueprint` as an example and walk through the changes that have to be provided in the `qefficient_transformers` library to enable such a model. + + +## Step 1: Checking the classes in the modeling file from `transformers`library + +1. **Look into the original modelling files in the `transformers` library:** + - Locate the original model in the `transformers` library. + - `/src/transformers/models/blueprint/modeling_blueprint.py` has all the modeling classes used to construct the model. + - Locate the `pytorch_transforms.py` file in `qefficient_transformers` to see if the corresponding classes are already implemented in `qefficient_transformers`. + - It's a good reference point to see if some functionalities have already been used in a prior model. + - Check the architecture class of the model that you want to on-board. + - If it is not in `pytorch_transforms.py`, you will need to implement them and then map the class along with the other required classes in the `pytorch_transforms.py` file. + +## Step 2: Creating the custom modeling file and mappings in pytorch_tranforms.py + +1. **Adding the required modified modeling file in the `qefficient-transformers` library:** + - For our example we will create the following directory : + `/QEfficient/transformers/models/blueprint` + - Then we will add the modeling and __init__ files in this directory. + - The modeling file 'modeling_blueprint.py` will have all the necessary modified modeling classes. + - The file has been annotated to explain why the changes are required for the model. + +2. **Add the mapping to the corresponding classes in `pytorch_transforms.py` file:** + - You will need to map the classes of the model to the ones in the `pytorch_transforms.py` file. + - If you look into `dummy_pytorch_transforms.py` file, you can see an example case for our `Blueprint` model. + - Every Mapping Class serves a specific purpose :- + - **CustomOpsTransform** + - This class has mapping for the RMSNorm class that we use for a model. + - Most of the models have the same RMSNorm, in case you need to change the RMSNorm classes, you will need to make changes in this class as we do for Gemma models. + - To add your own custom RMSNorm class when required, you can add it in `QEfficient.customop` file. + - **KVCacheTransform** + - This class handles mappings for almost all models that use a KV cache and thus generate text. + - All the custom classes that we define for a model, we add the mappings with the corresponding transformers class in this section. + - For the exception of models that don't have their modeling files in transformers library, we create this mapping via a different mapping class called **KVCacheExternalModuleMapperTransform** + - **KVCacheExternalModuleMapperTransform** + - This class is used to map to a class that is not in the transformers library. + - Here we don't perform a class replacement as we do in other mapping classes. + - We simply map the class name of the original model and then we map the methods of those classes with the custom methods that we had defined in our custom modeling file in qefficient. + +3. **Testing the implementation:** + - Once the implementation is complete, you can test it via the following instructions + - Go to the file `/efficient-transformers/tests/transformers/models/test_causal_lm_models.py` and add the appropriate model card for your model. + - For example, for `Blueprint` model, we might have a model card like `Blueprint/Blueprint-70B` on huggingface. + - Add the model card in the list `test_models_causal` and then run the test to ensure that the classes are mapped correctly. + + +## References +- [Hugging Face Transformers GitHub Repository](https://github.com/huggingface/transformers) +- [Qefficient Transformers GitHub Repository](https://github.com/quic/efficient-transformers) + diff --git a/examples/dummy_onboarding/causallm/dummy_pytorch_transforms.py b/examples/dummy_onboarding/causallm/dummy_pytorch_transforms.py new file mode 100644 index 000000000..a67264198 --- /dev/null +++ b/examples/dummy_onboarding/causallm/dummy_pytorch_transforms.py @@ -0,0 +1,659 @@ +# ----------------------------------------------------------------------------- +# +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +# SPDX-License-Identifier: BSD-3-Clause +# +# ----------------------------------------------------------------------------- + +import warnings +from types import MethodType +from typing import Callable, Optional, Tuple, Union + +from torch import nn + +# from transformers.models.codegen.modeling_codegen import ( +# CodeGenAttention, +# CodeGenBlock, +# CodeGenForCausalLM, +# CodeGenModel, +# ) +# from transformers.models.falcon.modeling_falcon import ( +# FalconAttention, +# FalconDecoderLayer, +# FalconForCausalLM, +# FalconModel, +# ) +# from transformers.models.gemma.modeling_gemma import ( +# GemmaAttention, +# GemmaDecoderLayer, +# GemmaForCausalLM, +# GemmaModel, +# GemmaRMSNorm, +# ) +# from transformers.models.gemma2.modeling_gemma2 import ( +# Gemma2Attention, +# Gemma2DecoderLayer, +# Gemma2ForCausalLM, +# Gemma2Model, +# Gemma2RMSNorm, +# ) +# from transformers.models.gemma3.modeling_gemma3 import ( +# Gemma3Attention, +# Gemma3DecoderLayer, +# Gemma3ForCausalLM, +# Gemma3ForConditionalGeneration, +# Gemma3RMSNorm, +# Gemma3TextModel, +# ) +# from transformers.models.gpt2.modeling_gpt2 import GPT2Attention, GPT2Block, GPT2LMHeadModel, GPT2Model +# from transformers.models.gpt_bigcode.modeling_gpt_bigcode import ( +# GPTBigCodeAttention, +# GPTBigCodeBlock, +# GPTBigCodeForCausalLM, +# GPTBigCodeModel, +# ) +# from transformers.models.gptj.modeling_gptj import GPTJAttention, GPTJBlock, GPTJForCausalLM, GPTJModel +# from transformers.models.granite.modeling_granite import ( +# GraniteAttention, +# GraniteForCausalLM, +# GraniteModel, +# GraniteRMSNorm, +# ) +# from transformers.models.granitemoe.modeling_granitemoe import ( +# GraniteMoeAttention, +# GraniteMoeForCausalLM, +# GraniteMoeModel, +# GraniteMoeMoE, +# GraniteMoeParallelExperts, +# GraniteMoeRMSNorm, +# GraniteMoeRotaryEmbedding, +# GraniteMoeTopKGating, +# ) +# from transformers.models.llama.modeling_llama import ( +# LlamaAttention, +# LlamaDecoderLayer, +# LlamaForCausalLM, +# LlamaModel, +# LlamaRMSNorm, +# ) +# from transformers.models.llama4.modeling_llama4 import ( +# Llama4ForCausalLM, +# Llama4ForConditionalGeneration, +# Llama4TextAttention, +# Llama4TextDecoderLayer, +# Llama4TextExperts, +# Llama4TextModel, +# Llama4TextMoe, +# Llama4TextRMSNorm, +# Llama4VisionAttention, +# Llama4VisionModel, +# ) +# from transformers.models.llava.modeling_llava import ( +# LlavaForConditionalGeneration, +# ) +# from transformers.models.llava_next.modeling_llava_next import ( +# LlavaNextForConditionalGeneration, +# ) +# from transformers.models.mistral.modeling_mistral import ( +# MistralAttention, +# MistralDecoderLayer, +# MistralForCausalLM, +# MistralModel, +# MistralRMSNorm, +# ) +# from transformers.models.mixtral.modeling_mixtral import ( +# MixtralAttention, +# MixtralDecoderLayer, +# MixtralForCausalLM, +# MixtralModel, +# MixtralRMSNorm, +# MixtralSparseMoeBlock, +# ) +# from transformers.models.mllama.modeling_mllama import ( +# MllamaCrossAttentionDecoderLayer, +# MllamaForCausalLM, +# MllamaForConditionalGeneration, +# MllamaRotaryEmbedding, +# MllamaSelfAttentionDecoderLayer, +# MllamaTextCrossAttention, +# MllamaTextModel, +# MllamaTextRMSNorm, +# MllamaTextSelfAttention, +# MllamaVisionModel, +# ) +# from transformers.models.mpt.modeling_mpt import MptAttention, MptBlock, MptForCausalLM, MptModel +# from transformers.models.phi.modeling_phi import PhiAttention, PhiDecoderLayer, PhiForCausalLM, PhiModel +# from transformers.models.phi3.modeling_phi3 import ( +# Phi3Attention, +# Phi3DecoderLayer, +# Phi3ForCausalLM, +# Phi3Model, +# Phi3RMSNorm, +# ) +# from transformers.models.qwen2.modeling_qwen2 import ( +# Qwen2Attention, +# Qwen2DecoderLayer, +# Qwen2ForCausalLM, +# Qwen2Model, +# Qwen2RMSNorm, +# ) +from transformers.models.blueprint.modeling_blueprint import ( + BlueprintAttention, + BlueprintDecoderLayer, + BlueprintForCausalLM, + BlueprintModel, + BlueprintRMSNorm, +) + +# from transformers.models.starcoder2.modeling_starcoder2 import ( +# Starcoder2Attention, +# Starcoder2DecoderLayer, +# Starcoder2ForCausalLM, +# Starcoder2Model, +# ) +# from transformers.models.whisper.modeling_whisper import ( +# WhisperAttention, +# WhisperDecoder, +# WhisperDecoderLayer, +# WhisperEncoder, +# WhisperForConditionalGeneration, +# WhisperModel, +# WhisperPositionalEmbedding, +# ) +from QEfficient.base.pytorch_transforms import ExternalModuleMapperTransform, ModuleMappingTransform +from QEfficient.customop import CustomRMSNormAIC +from QEfficient.transformers.embeddings.embedding_utils import POOLING_MAP, PooledModel, validate_user_pooling_function + +# from QEfficient.transformers.models.codegen.modeling_codegen import ( +# QEffCodeGenAttention, +# QeffCodeGenBlock, +# QEffCodeGenForCausalLM, +# QEffCodeGenModel, +# ) +# from QEfficient.transformers.models.falcon.modeling_falcon import ( +# QEffFalconAttention, +# QEffFalconDecoderLayer, +# QEffFalconForCausalLM, +# QEffFalconModel, +# ) +# from QEfficient.transformers.models.gemma.modeling_gemma import ( +# QEffGemmaAttention, +# QEffGemmaDecoderLayer, +# QEffGemmaForCausalLM, +# QEffGemmaModel, +# ) +# from QEfficient.transformers.models.gemma2.modeling_gemma2 import ( +# QEffGemma2Attention, +# QEffGemma2DecoderLayer, +# QEffGemma2ForCausalLM, +# QEffGemma2Model, +# ) +# from QEfficient.transformers.models.gemma3.modeling_gemma3 import ( +# QEffGemma3Attention, +# QEffGemma3CustomRMSNormAIC, +# QEffGemma3DecoderLayer, +# QEffGemma3ForCausalLMModel, +# QEffGemma3ForConditionalGeneration, +# QEffGemma3TextModel, +# ) +# from QEfficient.transformers.models.gpt2.modeling_gpt2 import ( +# QEffGPT2Attention, +# QEffGPT2Block, +# QEffGPT2LMHeadModel, +# QEffGPT2Model, +# ) +# from QEfficient.transformers.models.gpt_bigcode.modeling_gpt_bigcode import ( +# QEffGPTBigCodeAttention, +# QEffGPTBigCodeBlock, +# QEffGPTBigCodeForCausalLM, +# QEffGPTBigCodeModel, +# ) +# from QEfficient.transformers.models.gptj.modeling_gptj import ( +# QEffGPTJAttention, +# QEffGPTJBlock, +# QEffGPTJForCausalLM, +# QEffGPTJModel, +# ) +# from QEfficient.transformers.models.granite.modeling_granite import ( +# QEffGraniteAttention, +# QEffGraniteForCausalLM, +# QEffGraniteModel, +# ) +# from QEfficient.transformers.models.granitemoe.modeling_granitemoe import ( +# QEffGraniteMoeAttention, +# QEffGraniteMoeForCausalLM, +# QEffGraniteMoeModel, +# QEffGraniteMoeMoE, +# QEffGraniteMoeParallelExperts, +# QEffGraniteMoeRotaryEmbedding, +# QEffGraniteMoeTopKGating, +# ) +# from QEfficient.transformers.models.grok_1.modeling_grok1 import ( +# QEFFGrok1CustomRMSNormAIC, +# QEffGrok1DecoderLayer, +# QEffGrok1Model, +# QEffGrok1ModelForCausalLM, +# QEffGrok1MoeBlock, +# QEffGrok1MultiHeadAttention, +# ) +# from QEfficient.transformers.models.internvl.modeling_internvl import ( +# QEffInternVisionEmbeddings, +# QEffInternVLModel, +# ) +# from QEfficient.transformers.models.llama.modeling_llama import ( +# QEffLlamaAttention, +# QEffLlamaDecoderLayer, +# QEffLlamaForCausalLM, +# QEffLlamaModel, +# ) +# from QEfficient.transformers.models.llama4.modeling_llama4 import ( +# QEffLlama4ForCausalLM, +# QEffLlama4ForConditionalGeneration, +# QEffLlama4TextAttention, +# QEffLlama4TextDecoderLayer, +# QEffLlama4TextExperts, +# QEffLlama4TextModel, +# QEffLlama4TextMoe, +# QEffLlama4VisionAttention, +# QEffLlama4VisionModel, +# ) +# from QEfficient.transformers.models.llava.modeling_llava import ( +# QEffLlavaForConditionalGeneration, +# ) +# from QEfficient.transformers.models.llava_next.modeling_llava_next import ( +# QEffLlavaNextForConditionalGeneration, +# ) +# from QEfficient.transformers.models.mistral.modeling_mistral import ( +# QEffMistralAttention, +# QEffMistralDecoderLayer, +# QEffMistralForCausalLM, +# QEffMistralModel, +# ) +# from QEfficient.transformers.models.mixtral_moe.modeling_mixtral import ( +# QEffMixtralAttention, +# QeffMixtralDecoderLayer, +# QEffMixtralForCausalLM, +# QEffMixtralModel, +# QEffMixtralSparseMoeBlock, +# ) +# from QEfficient.transformers.models.mllama.modeling_mllama import ( +# QEffMllamaCrossAttentionDecoderLayer, +# QEffMllamaForCausalLM, +# QEffMllamaForConditionalGeneration, +# QEffMllamaRotaryEmbedding, +# QEffMllamaSelfAttentionDecoderLayer, +# QEffMllamaTextCrossAttentionSingleQPC, +# QEffMllamaTextCrossAttentionTwoQPC, +# QEffMllamaTextModel, +# QEffMllamaTextSelfAttention, +# QEffMllamaVisionModel, +# ) +# from QEfficient.transformers.models.mpt.modeling_mpt import ( +# QEffMptAttention, +# QEffMptBlock, +# QEffMptForCausalLM, +# QEFfMptModel, +# ) +# from QEfficient.transformers.models.phi.modeling_phi import ( +# QEffPhiAttention, +# QEffPhiDecoderLayer, +# QEffPhiForCausalLM, +# QEffPhiModel, +# ) +# from QEfficient.transformers.models.phi3.modeling_phi3 import ( +# QEffPhi3Attention, +# QEffPhi3DecoderLayer, +# QEffPhi3ForCausalLM, +# QEffPhi3Model, +# ) +# from QEfficient.transformers.models.qwen2.modeling_qwen2 import ( +# QEffQwen2Attention, +# QEffQwen2DecoderLayer, +# QEffQwen2ForCausalLM, +# QEffQwen2Model, +# ) +from QEfficient.transformers.models.blueprint.modeling_blueprint import ( + QEffBlueprintAttention, + QEffBlueprintDecoderLayer, + QEffBlueprintForCausalLM, + QEffBlueprintModel, +) + +# from QEfficient.transformers.models.starcoder2.modeling_starcoder2 import ( +# QEffStarcoder2Attention, +# QEFFStarcoder2DecoderLayer, +# QEffStarcoder2ForCausalLM, +# QEffStarcoder2Model, +# ) +# from QEfficient.transformers.models.whisper.modeling_whisper import ( +# QEffWhisperAttention, +# QEffWhisperDecoder, +# QEffWhisperDecoderLayer, +# QEffWhisperEncoder, +# QEffWhisperForConditionalGeneration, +# QEffWhisperModel, +# QEffWhisperPositionalEmbedding, +# ) +from QEfficient.transformers.post_processing import build_and_attach_mlp, model_type_registry +from QEfficient.transformers.sampler.sampler import sampler_forward +from QEfficient.transformers.spd.spd_transform_forward import tlm_forward + +SPD_TARGET = "target" + + +class CustomOpsTransform(ModuleMappingTransform): + _module_mapping = { + # GemmaRMSNorm: GemmaCustomRMSNormAIC, + # Gemma2RMSNorm: GemmaCustomRMSNormAIC, + # LlamaRMSNorm: CustomRMSNormAIC, + # Llama4TextRMSNorm: CustomRMSNormAIC, + # MistralRMSNorm: CustomRMSNormAIC, + # MixtralRMSNorm: CustomRMSNormAIC, + # Phi3RMSNorm: CustomRMSNormAIC, + # Qwen2RMSNorm: CustomRMSNormAIC, + BlueprintRMSNorm: CustomRMSNormAIC, + # MllamaTextRMSNorm: CustomRMSNormAIC, + # GraniteRMSNorm: CustomRMSNormAIC, + # GraniteMoeRMSNorm: CustomRMSNormAIC, + # Gemma3RMSNorm: QEffGemma3CustomRMSNormAIC, + } + + +class KVCacheTransform(ModuleMappingTransform): + _module_mapping = { + # # CodeGen + # CodeGenAttention: QEffCodeGenAttention, + # CodeGenBlock: QeffCodeGenBlock, + # CodeGenModel: QEffCodeGenModel, + # CodeGenForCausalLM: QEffCodeGenForCausalLM, + # # Falcon + # FalconAttention: QEffFalconAttention, + # FalconDecoderLayer: QEffFalconDecoderLayer, + # FalconModel: QEffFalconModel, + # FalconForCausalLM: QEffFalconForCausalLM, + # # GPT2 + # GPT2Attention: QEffGPT2Attention, + # GPT2Block: QEffGPT2Block, + # GPT2Model: QEffGPT2Model, + # GPT2LMHeadModel: QEffGPT2LMHeadModel, + # # GPTJ + # GPTJAttention: QEffGPTJAttention, + # GPTJBlock: QEffGPTJBlock, + # GPTJModel: QEffGPTJModel, + # GPTJForCausalLM: QEffGPTJForCausalLM, + # # Llama + # LlamaAttention: QEffLlamaAttention, + # LlamaDecoderLayer: QEffLlamaDecoderLayer, + # LlamaModel: QEffLlamaModel, + # LlamaForCausalLM: QEffLlamaForCausalLM, + # # Llama4 + # Llama4TextAttention: QEffLlama4TextAttention, + # Llama4ForCausalLM: QEffLlama4ForCausalLM, + # Llama4TextDecoderLayer: QEffLlama4TextDecoderLayer, + # Llama4TextModel: QEffLlama4TextModel, + # Llama4TextMoe: QEffLlama4TextMoe, + # Llama4ForConditionalGeneration: QEffLlama4ForConditionalGeneration, + # Llama4VisionAttention: QEffLlama4VisionAttention, + # Llama4VisionModel: QEffLlama4VisionModel, + # Llama4TextExperts: QEffLlama4TextExperts, + # # Llava + # LlavaForConditionalGeneration: QEffLlavaForConditionalGeneration, + # # Llava Next + # LlavaNextForConditionalGeneration: QEffLlavaNextForConditionalGeneration, + # # Gemma + # GemmaAttention: QEffGemmaAttention, + # GemmaDecoderLayer: QEffGemmaDecoderLayer, + # GemmaModel: QEffGemmaModel, + # GemmaForCausalLM: QEffGemmaForCausalLM, + # # Gemma2 + # Gemma2Attention: QEffGemma2Attention, + # Gemma2DecoderLayer: QEffGemma2DecoderLayer, + # Gemma2Model: QEffGemma2Model, + # Gemma2ForCausalLM: QEffGemma2ForCausalLM, + # # Gemma3 + # Gemma3Attention: QEffGemma3Attention, + # Gemma3DecoderLayer: QEffGemma3DecoderLayer, + # Gemma3TextModel: QEffGemma3TextModel, + # Gemma3ForCausalLM: QEffGemma3ForCausalLMModel, + # Gemma3ForConditionalGeneration: QEffGemma3ForConditionalGeneration, + # # Granite + # GraniteModel: QEffGraniteModel, + # GraniteForCausalLM: QEffGraniteForCausalLM, + # GraniteAttention: QEffGraniteAttention, + # # GraniteMoe + # GraniteMoeModel: QEffGraniteMoeModel, + # GraniteMoeForCausalLM: QEffGraniteMoeForCausalLM, + # GraniteMoeAttention: QEffGraniteMoeAttention, + # GraniteMoeRotaryEmbedding: QEffGraniteMoeRotaryEmbedding, + # GraniteMoeParallelExperts: QEffGraniteMoeParallelExperts, + # GraniteMoeTopKGating: QEffGraniteMoeTopKGating, + # GraniteMoeMoE: QEffGraniteMoeMoE, + # # mllama + # MllamaTextRMSNorm: CustomRMSNormAIC, + # MllamaTextSelfAttention: QEffMllamaTextSelfAttention, + # MllamaSelfAttentionDecoderLayer: QEffMllamaSelfAttentionDecoderLayer, + # MllamaCrossAttentionDecoderLayer: QEffMllamaCrossAttentionDecoderLayer, + # MllamaRotaryEmbedding: QEffMllamaRotaryEmbedding, + # MllamaVisionModel: QEffMllamaVisionModel, + # MllamaTextModel: QEffMllamaTextModel, + # MllamaForCausalLM: QEffMllamaForCausalLM, + # MllamaForConditionalGeneration: QEffMllamaForConditionalGeneration, + # # Mistral + # MistralAttention: QEffMistralAttention, + # MistralDecoderLayer: QEffMistralDecoderLayer, + # MistralModel: QEffMistralModel, + # MistralForCausalLM: QEffMistralForCausalLM, + # # Mixtral + # MixtralAttention: QEffMixtralAttention, + # MixtralSparseMoeBlock: QEffMixtralSparseMoeBlock, + # MixtralDecoderLayer: QeffMixtralDecoderLayer, + # MixtralModel: QEffMixtralModel, + # MixtralForCausalLM: QEffMixtralForCausalLM, + # # Mpt + # MptAttention: QEffMptAttention, + # MptBlock: QEffMptBlock, + # MptModel: QEFfMptModel, + # MptForCausalLM: QEffMptForCausalLM, + # # Phi3 + # Phi3Attention: QEffPhi3Attention, + # Phi3DecoderLayer: QEffPhi3DecoderLayer, + # Phi3Model: QEffPhi3Model, + # Phi3ForCausalLM: QEffPhi3ForCausalLM, + # # Phi + # PhiAttention: QEffPhiAttention, + # PhiDecoderLayer: QEffPhiDecoderLayer, + # PhiModel: QEffPhiModel, + # PhiForCausalLM: QEffPhiForCausalLM, + # # Qwen2 + # Qwen2Attention: QEffQwen2Attention, + # Qwen2DecoderLayer: QEffQwen2DecoderLayer, + # Qwen2Model: QEffQwen2Model, + # Qwen2ForCausalLM: QEffQwen2ForCausalLM, + # Blueprint + BlueprintAttention: QEffBlueprintAttention, + BlueprintDecoderLayer: QEffBlueprintDecoderLayer, + BlueprintModel: QEffBlueprintModel, + BlueprintForCausalLM: QEffBlueprintForCausalLM, + # # Starcoder2 + # Starcoder2Attention: QEffStarcoder2Attention, + # Starcoder2DecoderLayer: QEFFStarcoder2DecoderLayer, + # Starcoder2Model: QEffStarcoder2Model, + # Starcoder2ForCausalLM: QEffStarcoder2ForCausalLM, + # # GptBigcode + # GPTBigCodeAttention: QEffGPTBigCodeAttention, + # GPTBigCodeBlock: QEffGPTBigCodeBlock, + # GPTBigCodeModel: QEffGPTBigCodeModel, + # GPTBigCodeForCausalLM: QEffGPTBigCodeForCausalLM, + # # Whisper encoder and decoder layers + # WhisperPositionalEmbedding: QEffWhisperPositionalEmbedding, + # WhisperAttention: QEffWhisperAttention, + # WhisperDecoderLayer: QEffWhisperDecoderLayer, + # WhisperEncoder: QEffWhisperEncoder, + # WhisperDecoder: QEffWhisperDecoder, + # WhisperModel: QEffWhisperModel, + # WhisperForConditionalGeneration: QEffWhisperForConditionalGeneration, + } + + @classmethod + def apply(cls, model: nn.Module) -> Tuple[nn.Module, bool]: + model, transformed = super().apply(model) + return model, transformed + + +class SpDTransform: + """ + Apply generic QEffForCausalLM forward pass to extract `num_speculative_tokens+1` hidden states before computing logits during decode phase and extract last predicted token during prefill. + This is only needed if user is exporting Target Language Model (TLM) for Speculative Decoding to validate output logits + against the speculated tokens from a smaller model. + Other than the computed logits, there should be no difference between the SpD Transformed model and its corresponding cunterpart. + + ``Mandatory`` Args: + :model (nn.Module): PyTorch model. + + Returns: + :model (nn.Module): PyTorch model. + :transformed (bool): whether transformation was applied successfully. + """ + + # supported architectures + _module_mapping = { + # Llama + # QEffLlamaForCausalLM, + # QEffQwen2ForCausalLM, + QEffBlueprintForCausalLM, + } + + @classmethod + def apply(cls, model: nn.Module, qaic_config: Optional[dict] = None, **kwargs) -> Tuple[nn.Module, bool]: + transformed = False + pretrained_model_name_or_path_temp = kwargs.pop("pretrained_model_name_or_path", None) + if qaic_config is None or (speculative_model_type := qaic_config.get("speculative_model_type")) is None: + return model, transformed + elif speculative_model_type not in ( + supported_spd_model_types := [SPD_TARGET] + list(model_type_registry.keys()) + ): + raise ValueError( + f"Specualtive model type {speculative_model_type} is not supported. we currently only support {supported_spd_model_types}" + ) + elif (model_class := model.__class__) in cls._module_mapping: + model.forward = MethodType(tlm_forward, model) + if speculative_model_type != SPD_TARGET: + # build and attach draft mlp + pretrained_model_name_or_path = qaic_config["pretrained_model_name_or_path"] + model = build_and_attach_mlp( + model, pretrained_model_name_or_path, speculative_model_type=speculative_model_type, **kwargs + ) + transformed = True + else: + raise NotImplementedError( + f"model class {model_class} does not yet support returning multiple logits to keep." + ) + kwargs["pretrained_model_name_or_path"] = pretrained_model_name_or_path_temp + return model, transformed + + +class SamplerTransform: + """ + Add nodes at the output of any generic QEffForCausalLM model to enable the + sampling of next tokens at the device (instead of the host) and return the + next tokens and/or probability distributions. + + Note: To achieve this, the generic QEffForCausalLM model must provide the + logits as output. + + ``Mandatory`` Args: + :model (nn.Module): PyTorch model. + + Returns: + :model (nn.Module): PyTorch model. + :transformed (bool): whether transformation was applied successfully. + """ + + # supported architectures + _module_mapping = { + # Llama + # QEffLlamaForCausalLM, + } + + @classmethod + def apply(cls, model: nn.Module, qaic_config: Optional[dict] = None, **kwargs) -> Tuple[nn.Module, bool]: + transformed = False + if qaic_config is None or not qaic_config.get("include_sampler", False): + return model, transformed + elif (model_class := model.__class__) in cls._module_mapping: + model.old_forward = model.forward + model.forward = MethodType(sampler_forward, model) + transformed = True + else: + raise NotImplementedError(f"Model class {model_class} does not support on device sampling.") + return model, transformed + + +class VlmKVOffloadTransform(ModuleMappingTransform): + # supported architectures + _module_mapping = { + # # Llama + # MllamaTextCrossAttention: QEffMllamaTextCrossAttentionTwoQPC, + } + + +class VlmNoKVOffloadTransform(ModuleMappingTransform): + # supported architectures + _module_mapping = { + # # Llama + # MllamaTextCrossAttention: QEffMllamaTextCrossAttentionSingleQPC, + } + + +class KVCacheExternalModuleMapperTransform(ExternalModuleMapperTransform): + _match_string_replace_method = { + # "InternVLChatModel": { + # "forward": QEffInternVLModel.forward, + # "get_blueprint_inputs": QEffInternVLModel.get_blueprint_inputs, + # "get_specializations": QEffInternVLModel.get_specializations, + # "get_onnx_dynamic_axes": QEffInternVLModel.get_onnx_dynamic_axes, + # "get_output_names": QEffInternVLModel.get_output_names, + # "get_inputs_info": QEffInternVLModel.get_inputs_info, + # "get_qeff_vision_encoder": QEffInternVLModel.get_qeff_vision_encoder, + # "get_qeff_language_decoder": QEffInternVLModel.get_qeff_language_decoder, + # }, + # "InternVisionEmbeddings": {"forward": QEffInternVisionEmbeddings.forward}, + # # Mapping for grok1 model + # "Grok1ModelForCausalLM": {"forward": QEffGrok1ModelForCausalLM.forward}, + # "Grok1Model": { + # "forward": QEffGrok1Model.forward, + # "__qeff_init__": QEffGrok1Model.__qeff_init__, + # }, + # "DecoderLayer": { + # "forward": QEffGrok1DecoderLayer.forward, + # "__qeff_init__": QEffGrok1DecoderLayer.__qeff_init__, + # }, + # "MoeBlock": {"forward": QEffGrok1MoeBlock.forward}, + # "MultiHeadAttention": { + # "forward": QEffGrok1MultiHeadAttention.forward, + # }, + # "RMSNorm": { + # "forward": QEFFGrok1CustomRMSNormAIC.forward, + # }, + } + + _match_class_replace_method = {} + + +class PoolingTransform: + """ + Apply a pooling transformation to the model. This transformation appends a pooling layer to the model, allowing for the reduction of spatial dimensions in the output. + The pooling layer can be configured to use different pooling methods, such as max pooling or average pooling. + """ + + @classmethod + def apply(cls, model: nn.Module, pooling: Union[str, Callable]) -> Tuple[nn.Module, bool]: + transformed = False + pooling_method = ( + POOLING_MAP[pooling] + if isinstance(pooling, str) and pooling in POOLING_MAP + else validate_user_pooling_function(pooling) + ) + model = PooledModel(model, pooling_method) + warnings.warn("Pooling is applied to the model.") + return model, transformed diff --git a/examples/dummy_onboarding/causallm/modeling_dummy.py b/examples/dummy_onboarding/causallm/modeling_dummy.py new file mode 100644 index 000000000..d9093e46c --- /dev/null +++ b/examples/dummy_onboarding/causallm/modeling_dummy.py @@ -0,0 +1,396 @@ +# ----------------------------------------------------------------------------- +# +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +# SPDX-License-Identifier: BSD-3-Clause +# +# ----------------------------------------------------------------------------- + +"""PyTorch Blueprint model.""" + +from typing import Callable, List, Optional, Tuple, Union + +import torch +import torch.utils.checkpoint +from torch import nn +from transformers.cache_utils import Cache +from transformers.modeling_outputs import ( + BaseModelOutputWithPast, + CausalLMOutputWithPast, +) +from transformers.models.blueprint.modeling_blueprint import ( + BlueprintAttention, + BlueprintConfig, + BlueprintDecoderLayer, + BlueprintForCausalLM, + BlueprintModel, + BlueprintRotaryEmbedding, + repeat_kv, + rotate_half, +) + +from QEfficient.transformers.cache_utils import QEffDynamicCache +from QEfficient.transformers.modeling_attn_mask_utils import _create_causal_mask +from QEfficient.utils.constants import MIN_MASKED_ATTENTION_VALUE + + +class QEffBlueprintRotaryEmbedding(BlueprintRotaryEmbedding): + """ + Add the required Rotary Embedding functionality to the model based on the Class in the transformers modeling file. + The purpose of this class is to precompute sin and cos values for the rotary embedding and cache it for faster inference. + """ + + def __init__(self, config: BlueprintConfig, device=None): + super().__init__(config=config) + # Build here to make `torch.jit.trace` work. + self._set_cos_sin_cache( + seq_len=self.original_max_seq_len, device=self.inv_freq.device, dtype=torch.get_default_dtype() + ) + + def _set_cos_sin_cache(self, seq_len, device, dtype): + self.max_seq_len_cached = seq_len + t = torch.arange(self.max_seq_len_cached, device=device, dtype=torch.int64).type_as(self.inv_freq) + + freqs = torch.outer(t, self.inv_freq) + + emb = torch.cat((freqs, freqs), dim=-1) + self.register_buffer("cos_cached", emb.cos().to(dtype), persistent=False) + self.register_buffer("sin_cached", emb.sin().to(dtype), persistent=False) + + def forward(self, x, seq_len=None): + # x: [bs, num_attention_heads, seq_len, head_size] + if seq_len > self.max_seq_len_cached: + self._set_cos_sin_cache(seq_len=seq_len, device=x.device, dtype=x.dtype) + + return ( + self.cos_cached[:seq_len].to(dtype=x.dtype) * self.attention_scaling, + self.sin_cached[:seq_len].to(dtype=x.dtype) * self.attention_scaling, + ) + + +def qeff_apply_rotary_pos_emb(q, k, cos, sin, position_ids, unsqueeze_dim=1): + """Applies Rotary Position Embedding with Multimodal Sections to the query and key tensors. + + We modify this method to enable the application of the rotary embedding based on position_ids + instead of seq_len. This is needed as our modified modelling accepts position_ids and not + the attention_mask as an input. + """ + + cos = cos[position_ids].unsqueeze(unsqueeze_dim) + sin = sin[position_ids].unsqueeze(unsqueeze_dim) + + q_embed = (q * cos) + (rotate_half(q) * sin) + k_embed = (k * cos) + (rotate_half(k) * sin) + + return q_embed.to(q.dtype), k_embed.to(k.dtype) + + +def eager_attention_forward( + module: nn.Module, + query: torch.Tensor, + key: torch.Tensor, + value: torch.Tensor, + attention_mask: Optional[torch.Tensor], + scaling: float, + **kwargs, +): + """ + Implements the forward pass of Eager Attention for the model. + We explicitly support Eager mode based attention on our device. + The method would mostly be generic so we don't expect it to have much changes. + MIN_MASKED_ATTENTION_VALUE is a special value which helps our compiler know what -inf should be represented by. + """ + key_states = repeat_kv(key, module.num_key_value_groups) + value_states = repeat_kv(value, module.num_key_value_groups) + + attn_weights = torch.matmul(query, key_states.transpose(2, 3)) * scaling + if attention_mask is not None: + attn_weights = torch.where( + attention_mask, torch.tensor(MIN_MASKED_ATTENTION_VALUE, dtype=torch.float32), attn_weights + ) + + attn_weights = nn.functional.softmax(attn_weights, dim=-1, dtype=torch.float32).to(query.dtype) + attn_output = torch.matmul(attn_weights, value_states) + attn_output = attn_output.transpose(1, 2).contiguous() + + return attn_output, attn_weights + + +class QEffBlueprintAttention(BlueprintAttention): + """ + Here we'll setup the forward pass of the Attention module as implemented in the original model. + We initialize our own RotaryEmbedding module via __qeff_init__ method call. + + """ + + def __qeff_init__(self): + self.rotary_emb = QEffBlueprintRotaryEmbedding(config=self.config) + + def forward( + self, + hidden_states: torch.Tensor, + attention_mask: Optional[torch.Tensor], + position_ids: Optional[torch.LongTensor] = None, + past_key_value: Optional[Cache] = None, + batch_index: Optional[torch.LongTensor] = None, + cache_position: Optional[torch.LongTensor] = None, + **kwargs, + ) -> Tuple[torch.Tensor, Optional[torch.Tensor], Optional[Tuple[torch.Tensor]]]: + """ + Most of the implementation remains the same as original forward method. + The parts where difference occurs are the way we apply the rotary embeddings. + Also, we return the past_key_values instead of storing it in the default transformers cache. + """ + input_shape = hidden_states.shape[:-1] + hidden_shape = (*input_shape, -1, self.head_dim) + + query_states = self.q_norm(self.q_proj(hidden_states).view(hidden_shape)).transpose(1, 2) + key_states = self.k_norm(self.k_proj(hidden_states).view(hidden_shape)).transpose(1, 2) + value_states = self.v_proj(hidden_states).view(hidden_shape).transpose(1, 2) + + kv_seq_len = key_states.shape[-2] + + # We build the rotary embeddings different from the transformers method. + kv_seq_len = past_key_value.get_usable_length(kv_seq_len, self.layer_idx) + cos, sin = self.rotary_emb(value_states, seq_len=kv_seq_len) + # Apllication of the rotary embeddings requires position_ids as well. + query_states, key_states = qeff_apply_rotary_pos_emb(query_states, key_states, cos, sin, position_ids) + + if past_key_value is not None: + # sin and cos are specific to RoPE models; cache_position needed for the static cache + cache_kwargs = {"sin": sin, "cos": cos, "batch_index": batch_index, "position_ids": position_ids} + key_states, value_states = past_key_value.update(key_states, value_states, self.layer_idx, cache_kwargs) + + attention_interface: Callable = eager_attention_forward + + attn_output, attn_weights = attention_interface( + self, + query_states, + key_states, + value_states, + attention_mask, + scaling=self.scaling, + **kwargs, + ) + + attn_output = attn_output.reshape(*input_shape, -1).contiguous() + attn_output = self.o_proj(attn_output) + return attn_output, attn_weights, past_key_value + + +class QEffBlueprintDecoderLayer(BlueprintDecoderLayer): + """ + Overrides the forward method of the original BlueprintDecoderLayer. + Only changes being that the past_key_value is returned and `self.self_attn` method + is now an object of QEffBlueprintAttention instead. + """ + + def forward( + self, + hidden_states: torch.Tensor, + attention_mask: Optional[torch.Tensor] = None, + position_ids: Optional[torch.LongTensor] = None, + past_key_value: Optional[Cache] = None, + batch_index: Optional[torch.LongTensor] = None, + output_attentions: Optional[bool] = False, + use_cache: Optional[bool] = False, + cache_position: Optional[torch.LongTensor] = None, + **kwargs, + ) -> Tuple[torch.FloatTensor, Optional[Tuple[torch.FloatTensor, torch.FloatTensor]]]: + """ + The modified forward function also stores and returns the past_key_value. + Every other operation remains the same. + """ + + residual = hidden_states + + hidden_states = self.input_layernorm(hidden_states) + + # Self Attention + hidden_states, self_attn_weights, present_key_value = self.self_attn( + hidden_states=hidden_states, + attention_mask=attention_mask, + position_ids=position_ids, + past_key_value=past_key_value, + batch_index=batch_index, + output_attentions=output_attentions, + use_cache=use_cache, + cache_position=cache_position, + **kwargs, + ) + hidden_states = residual + hidden_states + + # Fully Connected + residual = hidden_states + hidden_states = self.post_attention_layernorm(hidden_states) + hidden_states = self.mlp(hidden_states) + hidden_states = residual + hidden_states + + outputs = (hidden_states,) + + if output_attentions: + outputs += (self_attn_weights,) + + if use_cache: + outputs += (present_key_value,) + + return outputs + + +class QEffBlueprintModel(BlueprintModel): + """ + Replaces the original BlueprintModel with a modified version. + We initialize the custom `QEffDynamicCache` for past_key_values here instead of the DynamicCache class. + This custom Cache class has all the required custom ops to perform CtxScatter/CtxGather as well as other required operations. + This enables us to cache the past key values in the way we want for AIC. The component won't require any changes mostly. + """ + + def forward( + self, + input_ids: torch.LongTensor = None, + attention_mask: Optional[torch.Tensor] = None, + position_ids: Optional[torch.LongTensor] = None, + past_key_values: Optional[Cache] = None, + batch_index: Optional[torch.LongTensor] = None, + inputs_embeds: Optional[torch.FloatTensor] = None, + use_cache: Optional[bool] = None, + output_attentions: Optional[bool] = None, + output_hidden_states: Optional[bool] = None, + return_dict: Optional[bool] = None, + cache_position: Optional[torch.LongTensor] = None, + **kwargs, + ) -> Union[Tuple, BaseModelOutputWithPast]: + output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions + output_hidden_states = ( + output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states + ) + use_cache = use_cache if use_cache is not None else self.config.use_cache + + return_dict = return_dict if return_dict is not None else self.config.use_return_dict + + if (input_ids is None) ^ (inputs_embeds is not None): + raise ValueError( + "You cannot specify both input_ids and inputs_embeds at the same time, and must specify either one" + ) + + return_legacy_cache = False + if use_cache and not isinstance(past_key_values, Cache): + return_legacy_cache = True + past_key_values = QEffDynamicCache.from_legacy_cache(past_key_values) + + if inputs_embeds is None: + inputs_embeds = self.embed_tokens(input_ids) + + if cache_position is None: + past_seen_tokens = past_key_values.get_seq_length() if past_key_values is not None else 0 + cache_position = torch.arange( + past_seen_tokens, past_seen_tokens + inputs_embeds.shape[1], device=inputs_embeds.device + ) + if position_ids is None: + position_ids = cache_position.unsqueeze(0) + + target_length = attention_mask.shape[-1] if isinstance(attention_mask, torch.Tensor) else past_seen_tokens + causal_mask = _create_causal_mask( + position_ids=position_ids, target_length=target_length, sliding_window=self.config.sliding_window + ) + + hidden_states = inputs_embeds + + # decoder layers + all_hidden_states = () if output_hidden_states else None + all_self_attns = () if output_attentions else None + + for decoder_layer in self.layers: + if output_hidden_states: + all_hidden_states += (hidden_states,) + + layer_outputs = decoder_layer( + hidden_states, + attention_mask=causal_mask, + position_ids=position_ids, + past_key_value=past_key_values, + batch_index=batch_index, + output_attentions=output_attentions, + use_cache=use_cache, + cache_position=cache_position, + ) + + hidden_states = layer_outputs[0] + + if output_attentions: + all_self_attns += (layer_outputs[1],) + + hidden_states = self.norm(hidden_states) + + # add hidden states from the last decoder layer + if output_hidden_states: + all_hidden_states += (hidden_states,) + + if return_legacy_cache: + past_key_values = past_key_values.to_legacy_cache() + + output = BaseModelOutputWithPast( + last_hidden_state=hidden_states, + past_key_values=past_key_values if use_cache else None, + hidden_states=all_hidden_states, + attentions=all_self_attns, + ) + return output if return_dict else output.to_tuple() + + +class QEffBlueprintForCausalLM(BlueprintForCausalLM): + """ + No major changes are needed in the forward method of this class, it is the entry point for the model during inference. + We add the additionally required parameters and pass those down the line as well. + """ + + def forward( + self, + input_ids: torch.LongTensor = None, + attention_mask: Optional[torch.Tensor] = None, + position_ids: Optional[torch.LongTensor] = None, + past_key_values: Optional[Union[Cache, List[torch.FloatTensor]]] = None, + batch_index: Optional[torch.LongTensor] = None, + inputs_embeds: Optional[torch.FloatTensor] = None, + labels: Optional[torch.LongTensor] = None, + use_cache: Optional[bool] = None, + output_attentions: Optional[bool] = None, + output_hidden_states: Optional[bool] = None, + return_dict: Optional[bool] = None, + cache_position: Optional[torch.LongTensor] = None, + logits_to_keep: Union[int, torch.Tensor] = 0, + **kwargs, + ) -> Union[Tuple, CausalLMOutputWithPast]: + output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions + output_hidden_states = ( + output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states + ) + return_dict = return_dict if return_dict is not None else self.config.use_return_dict + + # decoder outputs consists of (dec_features, layer_state, dec_hidden, dec_attn) + outputs = self.model( + input_ids=input_ids, + attention_mask=attention_mask, + position_ids=position_ids, + past_key_values=past_key_values, + batch_index=batch_index, + inputs_embeds=inputs_embeds, + use_cache=use_cache, + output_attentions=output_attentions, + output_hidden_states=output_hidden_states, + return_dict=return_dict, + ) + + # Cast to INT32 to avoid issue while running in ONNXRT + logit_index = position_ids.to(torch.int32).argmax(1, keepdim=True) + hidden_states = outputs[0][torch.arange(position_ids.shape[0]).view(-1, 1), logit_index] + + logits = self.lm_head(hidden_states) + logits = logits.float() + + return CausalLMOutputWithPast( + loss=None, + logits=logits, + past_key_values=outputs.past_key_values, + hidden_states=outputs.hidden_states, + attentions=outputs.attentions, + ) From 48ce9fcf75cf7f29abf6f04ea274d8b6dee02434 Mon Sep 17 00:00:00 2001 From: Dhiraj Kumar Sah Date: Thu, 25 Sep 2025 06:25:40 +0000 Subject: [PATCH 2/3] Edited to add more comments and remove some of the forward method bodies for more readability Signed-off-by: Dhiraj Kumar Sah --- examples/dummy_onboarding/causallm/README.md | 14 ++++--- .../causallm/modeling_dummy.py | 42 +++++++++---------- 2 files changed, 29 insertions(+), 27 deletions(-) diff --git a/examples/dummy_onboarding/causallm/README.md b/examples/dummy_onboarding/causallm/README.md index dc8e1b5f7..52dfafcf6 100644 --- a/examples/dummy_onboarding/causallm/README.md +++ b/examples/dummy_onboarding/causallm/README.md @@ -2,8 +2,12 @@ ## Prerequisites -Before beginning the onboarding process, ensure you have `qefficient-transformers` library installed in editable mode. - +Install `qefficient-transformers` library in editable mode. +```sh +git clone https://github.com/quic/efficient-transformers.git +cd efficient-transformers +pip install -e . +``` ## Introduction @@ -16,7 +20,7 @@ We will use a dummy model named `Blueprint` as an example and walk through the c 1. **Look into the original modelling files in the `transformers` library:** - Locate the original model in the `transformers` library. - `/src/transformers/models/blueprint/modeling_blueprint.py` has all the modeling classes used to construct the model. - - Locate the `pytorch_transforms.py` file in `qefficient_transformers` to see if the corresponding classes are already implemented in `qefficient_transformers`. + - Locate the `pytorch_transforms.py` file in `efficient-transformers/QEfficient/transformers/models/` to see if the corresponding classes are already implemented in `qefficient_transformers`. - It's a good reference point to see if some functionalities have already been used in a prior model. - Check the architecture class of the model that you want to on-board. - If it is not in `pytorch_transforms.py`, you will need to implement them and then map the class along with the other required classes in the `pytorch_transforms.py` file. @@ -27,8 +31,8 @@ We will use a dummy model named `Blueprint` as an example and walk through the c - For our example we will create the following directory : `/QEfficient/transformers/models/blueprint` - Then we will add the modeling and __init__ files in this directory. - - The modeling file 'modeling_blueprint.py` will have all the necessary modified modeling classes. - - The file has been annotated to explain why the changes are required for the model. + - The modeling file `modeling_blueprint.py` will have all the necessary modified modeling classes. + - The file has been annotated to explain where and why the changes are required for the model. 2. **Add the mapping to the corresponding classes in `pytorch_transforms.py` file:** - You will need to map the classes of the model to the ones in the `pytorch_transforms.py` file. diff --git a/examples/dummy_onboarding/causallm/modeling_dummy.py b/examples/dummy_onboarding/causallm/modeling_dummy.py index d9093e46c..195c9d7db 100644 --- a/examples/dummy_onboarding/causallm/modeling_dummy.py +++ b/examples/dummy_onboarding/causallm/modeling_dummy.py @@ -24,19 +24,18 @@ BlueprintForCausalLM, BlueprintModel, BlueprintRotaryEmbedding, - repeat_kv, rotate_half, ) from QEfficient.transformers.cache_utils import QEffDynamicCache from QEfficient.transformers.modeling_attn_mask_utils import _create_causal_mask -from QEfficient.utils.constants import MIN_MASKED_ATTENTION_VALUE class QEffBlueprintRotaryEmbedding(BlueprintRotaryEmbedding): """ Add the required Rotary Embedding functionality to the model based on the Class in the transformers modeling file. The purpose of this class is to precompute sin and cos values for the rotary embedding and cache it for faster inference. + This class is more or less the same for all models that are onboarded. """ def __init__(self, config: BlueprintConfig, device=None): @@ -74,7 +73,7 @@ def qeff_apply_rotary_pos_emb(q, k, cos, sin, position_ids, unsqueeze_dim=1): instead of seq_len. This is needed as our modified modelling accepts position_ids and not the attention_mask as an input. """ - + # cos = cos[position_ids].unsqueeze(unsqueeze_dim) sin = sin[position_ids].unsqueeze(unsqueeze_dim) @@ -99,20 +98,7 @@ def eager_attention_forward( The method would mostly be generic so we don't expect it to have much changes. MIN_MASKED_ATTENTION_VALUE is a special value which helps our compiler know what -inf should be represented by. """ - key_states = repeat_kv(key, module.num_key_value_groups) - value_states = repeat_kv(value, module.num_key_value_groups) - - attn_weights = torch.matmul(query, key_states.transpose(2, 3)) * scaling - if attention_mask is not None: - attn_weights = torch.where( - attention_mask, torch.tensor(MIN_MASKED_ATTENTION_VALUE, dtype=torch.float32), attn_weights - ) - - attn_weights = nn.functional.softmax(attn_weights, dim=-1, dtype=torch.float32).to(query.dtype) - attn_output = torch.matmul(attn_weights, value_states) - attn_output = attn_output.transpose(1, 2).contiguous() - - return attn_output, attn_weights + pass class QEffBlueprintAttention(BlueprintAttention): @@ -122,6 +108,10 @@ class QEffBlueprintAttention(BlueprintAttention): """ + # < We load our own custom class for the rotary embedding to enable supporting position_ids> + # Since we map the custom classes to the original classes, __init__ method wouldn't work as expected, + # Hence we use __qeff_init__ method to initialize something while the mapping happens. + def __qeff_init__(self): self.rotary_emb = QEffBlueprintRotaryEmbedding(config=self.config) @@ -143,23 +133,28 @@ def forward( input_shape = hidden_states.shape[:-1] hidden_shape = (*input_shape, -1, self.head_dim) - query_states = self.q_norm(self.q_proj(hidden_states).view(hidden_shape)).transpose(1, 2) - key_states = self.k_norm(self.k_proj(hidden_states).view(hidden_shape)).transpose(1, 2) - value_states = self.v_proj(hidden_states).view(hidden_shape).transpose(1, 2) + query_states = self.q_proj(hidden_states, **kwargs) + key_states = self.k_proj(hidden_states, **kwargs) + value_states = self.v_proj(hidden_states, **kwargs) + + query_states = query_states.view(hidden_shape).transpose(1, 2) + key_states = key_states.view(hidden_shape).transpose(1, 2) + value_states = value_states.view(hidden_shape).transpose(1, 2) kv_seq_len = key_states.shape[-2] # We build the rotary embeddings different from the transformers method. kv_seq_len = past_key_value.get_usable_length(kv_seq_len, self.layer_idx) cos, sin = self.rotary_emb(value_states, seq_len=kv_seq_len) - # Apllication of the rotary embeddings requires position_ids as well. + # Application of the rotary embeddings requires position_ids as well. query_states, key_states = qeff_apply_rotary_pos_emb(query_states, key_states, cos, sin, position_ids) if past_key_value is not None: - # sin and cos are specific to RoPE models; cache_position needed for the static cache + # < We add all the required items for cache kwargs which would enable updating QEffDynamicCache > cache_kwargs = {"sin": sin, "cos": cos, "batch_index": batch_index, "position_ids": position_ids} key_states, value_states = past_key_value.update(key_states, value_states, self.layer_idx, cache_kwargs) + # < We override the attention_interface method with our own to enable Eager Attention> attention_interface: Callable = eager_attention_forward attn_output, attn_weights = attention_interface( @@ -205,6 +200,7 @@ def forward( hidden_states = self.input_layernorm(hidden_states) + # < Self attention would also have to return the past_key_value as well and we capture it here> # Self Attention hidden_states, self_attn_weights, present_key_value = self.self_attn( hidden_states=hidden_states, @@ -272,6 +268,7 @@ def forward( "You cannot specify both input_ids and inputs_embeds at the same time, and must specify either one" ) + # < We create the custom QEffDynamicCache here to be used during the AIC execution> return_legacy_cache = False if use_cache and not isinstance(past_key_values, Cache): return_legacy_cache = True @@ -366,6 +363,7 @@ def forward( ) return_dict = return_dict if return_dict is not None else self.config.use_return_dict + # < We add the additional parameters that we use for our models here and pass them down the line > # decoder outputs consists of (dec_features, layer_state, dec_hidden, dec_attn) outputs = self.model( input_ids=input_ids, From 8abdca3537fcd07df9ed9879cb01cd1265d0e112 Mon Sep 17 00:00:00 2001 From: Rishin Raj Date: Wed, 12 Nov 2025 12:42:45 +0000 Subject: [PATCH 3/3] Updated readme and contributing.md Signed-off-by: Rishin Raj --- CONTRIBUTING.md | 158 ++++- examples/dummy_onboarding/causallm/README.md | 64 -- .../causallm/dummy_pytorch_transforms.py | 659 ------------------ .../onboarding_guide/causallm/Onboarding.png | Bin 0 -> 231305 bytes examples/onboarding_guide/causallm/README.md | 196 ++++++ .../causallm/example_pytorch_transforms.py | 291 ++++++++ .../causallm/modeling_example.py} | 0 7 files changed, 635 insertions(+), 733 deletions(-) delete mode 100644 examples/dummy_onboarding/causallm/README.md delete mode 100644 examples/dummy_onboarding/causallm/dummy_pytorch_transforms.py create mode 100644 examples/onboarding_guide/causallm/Onboarding.png create mode 100644 examples/onboarding_guide/causallm/README.md create mode 100644 examples/onboarding_guide/causallm/example_pytorch_transforms.py rename examples/{dummy_onboarding/causallm/modeling_dummy.py => onboarding_guide/causallm/modeling_example.py} (100%) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 260a32f1d..424e9fc4c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,22 +1,160 @@ ## Contributing to PROJECT Hi there! -We’re thrilled that you’d like to contribute to this project. +We're thrilled that you'd like to contribute to this project. Your help is essential for keeping this project great and for making it better. -## Branching Strategy -In general, contributors should develop on branches based off of `main` and pull requests should be made against `main`. +## Submitting Your Contribution -## Submitting a pull request +Follow these steps to submit your example to the QEfficient repository: 1. Please read our [code of conduct](CODE-OF-CONDUCT.md) and [license](LICENSE). -1. Fork and clone the repository. -1. Create a new branch based on `main`: `git checkout -b main`. -1. Make your changes, add tests, and make sure the tests still pass. -1. Commit your changes using the [DCO](http://developercertificate.org/). You can attest to the DCO by commiting with the **-s** or **--signoff** options or manually adding the "Signed-off-by". -1. Push to your fork and submit a pull request from your branch to `main`. -1. Pat yourself on the back and wait for your pull request to be reviewed. + +### 1. Fork and Clone the Repository + +First, fork the repository to your GitHub account, then clone your fork: + +```bash +# Fork the repository on GitHub (click the "Fork" button) +# Then clone your fork +git clone git@github.com:YOUR_USERNAME/efficient-transformers.git +cd efficient-transformers + +# Add upstream remote to keep your fork in sync +git remote add upstream git@github.com:quic/efficient-transformers.git +``` + +### 2. Create a Feature Branch + +Create a descriptive branch for your changes: + +```bash +# Update your main branch +git checkout main +git pull upstream main + +# Create a new branch +git checkout -b +``` + +### 3. Make Your Changes + +When making changes to the codebase: + +- **Follow Existing Design Patterns** + - Review similar implementations before creating new code + - Maintain consistency with the project's architecture and coding style + - Reuse existing utilities and base classes where applicable + +- **Onboarding New Models** + - For adding new model support, refer to the comprehensive guide: `examples/onboarding_guide/causallm/` + - Follow the step-by-step process with code examples provided + +- **Testing is Mandatory** + - Add tests for all new features in the appropriate `tests/` subdirectory + - Run tests locally before pushing: `pytest tests/path/to/your/test.py -v` + - For model additions, verify all 4 pipeline stages (PyTorch HF → KV → ORT → AI 100) and make sure tokens are matching with refernce PyTorch HF + +- **Documentation** + - **For New Features/Flags:** + - Document usage in `docs/source/` with feature description and usage examples + - Ensure documentation is clear enough for others to understand and use the feature + - **For New Models:** + - Test with basic inference scripts in the `examples/` folder + - If specific changes are needed, create a dedicated example file + - Update `docs/source/validate.md` with the model's HuggingFace card name and relevant details + + +- **Code Quality Checks** + - Pre-commit hooks, DCO sign-off, and CI checks are covered in the following steps + - Ensure you complete steps 4-8 before finalizing your PR + +### 4. Run Pre-commit Checks + +Before committing, ensure your code passes all quality checks: + +```bash +# Install pre-commit and ruff if not already installed +pip install pre-commit +pip install ruff + +# Run pre-commit on your changed files +pre-commit run --files path/to/your/file1.py path/to/your/file2.py + +# Run Ruff check +ruff check +``` + +**Important:** If pre-commit reports any failures: +- Some issues will be auto-fixed (formatting, trailing whitespace, etc.) +- For issues that aren't auto-fixed, manually correct them +- Re-run `pre-commit run --files ` or `ruff check` until all checks pass + +### 5. Commit with Sign-off (DCO) + +All commits must be signed off to comply with the Developer Certificate of Origin (DCO): + +```bash +# Stage your changes +git add examples/your_domain/your_example.py +git add examples/your_domain/README.md + +# Commit with sign-off +git commit -s --author "Your Name " -m "Add [model-name] support + +- Implements inference for [model-name] +- Includes documentation and usage examples +- Tested with [specific configurations]" +``` + +**Commit Message Guidelines:** +- Use a clear, descriptive title +- Add a blank line, then detailed description if needed +- Always include the `-s` flag for DCO sign-off + +### 6. Push to Your Fork + +Push your branch to your forked repository: + +```bash +git push origin +``` + +### 7. Create a Pull Request + +1. Go to your fork on GitHub +2. Click "Compare & pull request" for your branch +3. Fill out the PR template with: + - **Title:** Clear, descriptive title (e.g., "Add Llama-3.2-Vision Support" or "Fix memory leak in KV cache") + - **Description:** + - What changes were made and why + - What problem it solves or feature it adds + - Any special considerations or breaking changes + - Links to relevant documentation, issues, or model cards (if applicable) + - **Testing:** Describe how you tested your changes + +### 8. Ensure CI Checks Pass + +After creating the PR, verify that all automated checks pass: + +- ✅ **DCO Check:** Ensures all commits are signed off +- ✅ **Lint Check:** Code style and formatting validation +- ✅ **Tests:** Automated test suite (if applicable) + +If any checks fail: +1. Review the error messages in the PR +2. Make necessary fixes in your local branch +3. Commit and push the fixes (with sign-off) +4. The PR will automatically update and re-run checks + +### 9. Address Review Feedback + +Maintainers will review your PR and may request changes: +- Make requested changes in your local branch +- Commit with sign-off and push to update the PR +- Respond to comments to facilitate discussion + Here are a few things you can do that will increase the likelihood of your pull request to be accepted: diff --git a/examples/dummy_onboarding/causallm/README.md b/examples/dummy_onboarding/causallm/README.md deleted file mode 100644 index 52dfafcf6..000000000 --- a/examples/dummy_onboarding/causallm/README.md +++ /dev/null @@ -1,64 +0,0 @@ -# Onboarding a CausalLM Model - -## Prerequisites - -Install `qefficient-transformers` library in editable mode. -```sh -git clone https://github.com/quic/efficient-transformers.git -cd efficient-transformers -pip install -e . -``` - -## Introduction - -This README provides a step-by-step guide on how to on-board a CausalLM model. The process includes setting up the environment, modifying configuration files, and running the model. -We will use a dummy model named `Blueprint` as an example and walk through the changes that have to be provided in the `qefficient_transformers` library to enable such a model. - - -## Step 1: Checking the classes in the modeling file from `transformers`library - -1. **Look into the original modelling files in the `transformers` library:** - - Locate the original model in the `transformers` library. - - `/src/transformers/models/blueprint/modeling_blueprint.py` has all the modeling classes used to construct the model. - - Locate the `pytorch_transforms.py` file in `efficient-transformers/QEfficient/transformers/models/` to see if the corresponding classes are already implemented in `qefficient_transformers`. - - It's a good reference point to see if some functionalities have already been used in a prior model. - - Check the architecture class of the model that you want to on-board. - - If it is not in `pytorch_transforms.py`, you will need to implement them and then map the class along with the other required classes in the `pytorch_transforms.py` file. - -## Step 2: Creating the custom modeling file and mappings in pytorch_tranforms.py - -1. **Adding the required modified modeling file in the `qefficient-transformers` library:** - - For our example we will create the following directory : - `/QEfficient/transformers/models/blueprint` - - Then we will add the modeling and __init__ files in this directory. - - The modeling file `modeling_blueprint.py` will have all the necessary modified modeling classes. - - The file has been annotated to explain where and why the changes are required for the model. - -2. **Add the mapping to the corresponding classes in `pytorch_transforms.py` file:** - - You will need to map the classes of the model to the ones in the `pytorch_transforms.py` file. - - If you look into `dummy_pytorch_transforms.py` file, you can see an example case for our `Blueprint` model. - - Every Mapping Class serves a specific purpose :- - - **CustomOpsTransform** - - This class has mapping for the RMSNorm class that we use for a model. - - Most of the models have the same RMSNorm, in case you need to change the RMSNorm classes, you will need to make changes in this class as we do for Gemma models. - - To add your own custom RMSNorm class when required, you can add it in `QEfficient.customop` file. - - **KVCacheTransform** - - This class handles mappings for almost all models that use a KV cache and thus generate text. - - All the custom classes that we define for a model, we add the mappings with the corresponding transformers class in this section. - - For the exception of models that don't have their modeling files in transformers library, we create this mapping via a different mapping class called **KVCacheExternalModuleMapperTransform** - - **KVCacheExternalModuleMapperTransform** - - This class is used to map to a class that is not in the transformers library. - - Here we don't perform a class replacement as we do in other mapping classes. - - We simply map the class name of the original model and then we map the methods of those classes with the custom methods that we had defined in our custom modeling file in qefficient. - -3. **Testing the implementation:** - - Once the implementation is complete, you can test it via the following instructions - - Go to the file `/efficient-transformers/tests/transformers/models/test_causal_lm_models.py` and add the appropriate model card for your model. - - For example, for `Blueprint` model, we might have a model card like `Blueprint/Blueprint-70B` on huggingface. - - Add the model card in the list `test_models_causal` and then run the test to ensure that the classes are mapped correctly. - - -## References -- [Hugging Face Transformers GitHub Repository](https://github.com/huggingface/transformers) -- [Qefficient Transformers GitHub Repository](https://github.com/quic/efficient-transformers) - diff --git a/examples/dummy_onboarding/causallm/dummy_pytorch_transforms.py b/examples/dummy_onboarding/causallm/dummy_pytorch_transforms.py deleted file mode 100644 index a67264198..000000000 --- a/examples/dummy_onboarding/causallm/dummy_pytorch_transforms.py +++ /dev/null @@ -1,659 +0,0 @@ -# ----------------------------------------------------------------------------- -# -# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -# SPDX-License-Identifier: BSD-3-Clause -# -# ----------------------------------------------------------------------------- - -import warnings -from types import MethodType -from typing import Callable, Optional, Tuple, Union - -from torch import nn - -# from transformers.models.codegen.modeling_codegen import ( -# CodeGenAttention, -# CodeGenBlock, -# CodeGenForCausalLM, -# CodeGenModel, -# ) -# from transformers.models.falcon.modeling_falcon import ( -# FalconAttention, -# FalconDecoderLayer, -# FalconForCausalLM, -# FalconModel, -# ) -# from transformers.models.gemma.modeling_gemma import ( -# GemmaAttention, -# GemmaDecoderLayer, -# GemmaForCausalLM, -# GemmaModel, -# GemmaRMSNorm, -# ) -# from transformers.models.gemma2.modeling_gemma2 import ( -# Gemma2Attention, -# Gemma2DecoderLayer, -# Gemma2ForCausalLM, -# Gemma2Model, -# Gemma2RMSNorm, -# ) -# from transformers.models.gemma3.modeling_gemma3 import ( -# Gemma3Attention, -# Gemma3DecoderLayer, -# Gemma3ForCausalLM, -# Gemma3ForConditionalGeneration, -# Gemma3RMSNorm, -# Gemma3TextModel, -# ) -# from transformers.models.gpt2.modeling_gpt2 import GPT2Attention, GPT2Block, GPT2LMHeadModel, GPT2Model -# from transformers.models.gpt_bigcode.modeling_gpt_bigcode import ( -# GPTBigCodeAttention, -# GPTBigCodeBlock, -# GPTBigCodeForCausalLM, -# GPTBigCodeModel, -# ) -# from transformers.models.gptj.modeling_gptj import GPTJAttention, GPTJBlock, GPTJForCausalLM, GPTJModel -# from transformers.models.granite.modeling_granite import ( -# GraniteAttention, -# GraniteForCausalLM, -# GraniteModel, -# GraniteRMSNorm, -# ) -# from transformers.models.granitemoe.modeling_granitemoe import ( -# GraniteMoeAttention, -# GraniteMoeForCausalLM, -# GraniteMoeModel, -# GraniteMoeMoE, -# GraniteMoeParallelExperts, -# GraniteMoeRMSNorm, -# GraniteMoeRotaryEmbedding, -# GraniteMoeTopKGating, -# ) -# from transformers.models.llama.modeling_llama import ( -# LlamaAttention, -# LlamaDecoderLayer, -# LlamaForCausalLM, -# LlamaModel, -# LlamaRMSNorm, -# ) -# from transformers.models.llama4.modeling_llama4 import ( -# Llama4ForCausalLM, -# Llama4ForConditionalGeneration, -# Llama4TextAttention, -# Llama4TextDecoderLayer, -# Llama4TextExperts, -# Llama4TextModel, -# Llama4TextMoe, -# Llama4TextRMSNorm, -# Llama4VisionAttention, -# Llama4VisionModel, -# ) -# from transformers.models.llava.modeling_llava import ( -# LlavaForConditionalGeneration, -# ) -# from transformers.models.llava_next.modeling_llava_next import ( -# LlavaNextForConditionalGeneration, -# ) -# from transformers.models.mistral.modeling_mistral import ( -# MistralAttention, -# MistralDecoderLayer, -# MistralForCausalLM, -# MistralModel, -# MistralRMSNorm, -# ) -# from transformers.models.mixtral.modeling_mixtral import ( -# MixtralAttention, -# MixtralDecoderLayer, -# MixtralForCausalLM, -# MixtralModel, -# MixtralRMSNorm, -# MixtralSparseMoeBlock, -# ) -# from transformers.models.mllama.modeling_mllama import ( -# MllamaCrossAttentionDecoderLayer, -# MllamaForCausalLM, -# MllamaForConditionalGeneration, -# MllamaRotaryEmbedding, -# MllamaSelfAttentionDecoderLayer, -# MllamaTextCrossAttention, -# MllamaTextModel, -# MllamaTextRMSNorm, -# MllamaTextSelfAttention, -# MllamaVisionModel, -# ) -# from transformers.models.mpt.modeling_mpt import MptAttention, MptBlock, MptForCausalLM, MptModel -# from transformers.models.phi.modeling_phi import PhiAttention, PhiDecoderLayer, PhiForCausalLM, PhiModel -# from transformers.models.phi3.modeling_phi3 import ( -# Phi3Attention, -# Phi3DecoderLayer, -# Phi3ForCausalLM, -# Phi3Model, -# Phi3RMSNorm, -# ) -# from transformers.models.qwen2.modeling_qwen2 import ( -# Qwen2Attention, -# Qwen2DecoderLayer, -# Qwen2ForCausalLM, -# Qwen2Model, -# Qwen2RMSNorm, -# ) -from transformers.models.blueprint.modeling_blueprint import ( - BlueprintAttention, - BlueprintDecoderLayer, - BlueprintForCausalLM, - BlueprintModel, - BlueprintRMSNorm, -) - -# from transformers.models.starcoder2.modeling_starcoder2 import ( -# Starcoder2Attention, -# Starcoder2DecoderLayer, -# Starcoder2ForCausalLM, -# Starcoder2Model, -# ) -# from transformers.models.whisper.modeling_whisper import ( -# WhisperAttention, -# WhisperDecoder, -# WhisperDecoderLayer, -# WhisperEncoder, -# WhisperForConditionalGeneration, -# WhisperModel, -# WhisperPositionalEmbedding, -# ) -from QEfficient.base.pytorch_transforms import ExternalModuleMapperTransform, ModuleMappingTransform -from QEfficient.customop import CustomRMSNormAIC -from QEfficient.transformers.embeddings.embedding_utils import POOLING_MAP, PooledModel, validate_user_pooling_function - -# from QEfficient.transformers.models.codegen.modeling_codegen import ( -# QEffCodeGenAttention, -# QeffCodeGenBlock, -# QEffCodeGenForCausalLM, -# QEffCodeGenModel, -# ) -# from QEfficient.transformers.models.falcon.modeling_falcon import ( -# QEffFalconAttention, -# QEffFalconDecoderLayer, -# QEffFalconForCausalLM, -# QEffFalconModel, -# ) -# from QEfficient.transformers.models.gemma.modeling_gemma import ( -# QEffGemmaAttention, -# QEffGemmaDecoderLayer, -# QEffGemmaForCausalLM, -# QEffGemmaModel, -# ) -# from QEfficient.transformers.models.gemma2.modeling_gemma2 import ( -# QEffGemma2Attention, -# QEffGemma2DecoderLayer, -# QEffGemma2ForCausalLM, -# QEffGemma2Model, -# ) -# from QEfficient.transformers.models.gemma3.modeling_gemma3 import ( -# QEffGemma3Attention, -# QEffGemma3CustomRMSNormAIC, -# QEffGemma3DecoderLayer, -# QEffGemma3ForCausalLMModel, -# QEffGemma3ForConditionalGeneration, -# QEffGemma3TextModel, -# ) -# from QEfficient.transformers.models.gpt2.modeling_gpt2 import ( -# QEffGPT2Attention, -# QEffGPT2Block, -# QEffGPT2LMHeadModel, -# QEffGPT2Model, -# ) -# from QEfficient.transformers.models.gpt_bigcode.modeling_gpt_bigcode import ( -# QEffGPTBigCodeAttention, -# QEffGPTBigCodeBlock, -# QEffGPTBigCodeForCausalLM, -# QEffGPTBigCodeModel, -# ) -# from QEfficient.transformers.models.gptj.modeling_gptj import ( -# QEffGPTJAttention, -# QEffGPTJBlock, -# QEffGPTJForCausalLM, -# QEffGPTJModel, -# ) -# from QEfficient.transformers.models.granite.modeling_granite import ( -# QEffGraniteAttention, -# QEffGraniteForCausalLM, -# QEffGraniteModel, -# ) -# from QEfficient.transformers.models.granitemoe.modeling_granitemoe import ( -# QEffGraniteMoeAttention, -# QEffGraniteMoeForCausalLM, -# QEffGraniteMoeModel, -# QEffGraniteMoeMoE, -# QEffGraniteMoeParallelExperts, -# QEffGraniteMoeRotaryEmbedding, -# QEffGraniteMoeTopKGating, -# ) -# from QEfficient.transformers.models.grok_1.modeling_grok1 import ( -# QEFFGrok1CustomRMSNormAIC, -# QEffGrok1DecoderLayer, -# QEffGrok1Model, -# QEffGrok1ModelForCausalLM, -# QEffGrok1MoeBlock, -# QEffGrok1MultiHeadAttention, -# ) -# from QEfficient.transformers.models.internvl.modeling_internvl import ( -# QEffInternVisionEmbeddings, -# QEffInternVLModel, -# ) -# from QEfficient.transformers.models.llama.modeling_llama import ( -# QEffLlamaAttention, -# QEffLlamaDecoderLayer, -# QEffLlamaForCausalLM, -# QEffLlamaModel, -# ) -# from QEfficient.transformers.models.llama4.modeling_llama4 import ( -# QEffLlama4ForCausalLM, -# QEffLlama4ForConditionalGeneration, -# QEffLlama4TextAttention, -# QEffLlama4TextDecoderLayer, -# QEffLlama4TextExperts, -# QEffLlama4TextModel, -# QEffLlama4TextMoe, -# QEffLlama4VisionAttention, -# QEffLlama4VisionModel, -# ) -# from QEfficient.transformers.models.llava.modeling_llava import ( -# QEffLlavaForConditionalGeneration, -# ) -# from QEfficient.transformers.models.llava_next.modeling_llava_next import ( -# QEffLlavaNextForConditionalGeneration, -# ) -# from QEfficient.transformers.models.mistral.modeling_mistral import ( -# QEffMistralAttention, -# QEffMistralDecoderLayer, -# QEffMistralForCausalLM, -# QEffMistralModel, -# ) -# from QEfficient.transformers.models.mixtral_moe.modeling_mixtral import ( -# QEffMixtralAttention, -# QeffMixtralDecoderLayer, -# QEffMixtralForCausalLM, -# QEffMixtralModel, -# QEffMixtralSparseMoeBlock, -# ) -# from QEfficient.transformers.models.mllama.modeling_mllama import ( -# QEffMllamaCrossAttentionDecoderLayer, -# QEffMllamaForCausalLM, -# QEffMllamaForConditionalGeneration, -# QEffMllamaRotaryEmbedding, -# QEffMllamaSelfAttentionDecoderLayer, -# QEffMllamaTextCrossAttentionSingleQPC, -# QEffMllamaTextCrossAttentionTwoQPC, -# QEffMllamaTextModel, -# QEffMllamaTextSelfAttention, -# QEffMllamaVisionModel, -# ) -# from QEfficient.transformers.models.mpt.modeling_mpt import ( -# QEffMptAttention, -# QEffMptBlock, -# QEffMptForCausalLM, -# QEFfMptModel, -# ) -# from QEfficient.transformers.models.phi.modeling_phi import ( -# QEffPhiAttention, -# QEffPhiDecoderLayer, -# QEffPhiForCausalLM, -# QEffPhiModel, -# ) -# from QEfficient.transformers.models.phi3.modeling_phi3 import ( -# QEffPhi3Attention, -# QEffPhi3DecoderLayer, -# QEffPhi3ForCausalLM, -# QEffPhi3Model, -# ) -# from QEfficient.transformers.models.qwen2.modeling_qwen2 import ( -# QEffQwen2Attention, -# QEffQwen2DecoderLayer, -# QEffQwen2ForCausalLM, -# QEffQwen2Model, -# ) -from QEfficient.transformers.models.blueprint.modeling_blueprint import ( - QEffBlueprintAttention, - QEffBlueprintDecoderLayer, - QEffBlueprintForCausalLM, - QEffBlueprintModel, -) - -# from QEfficient.transformers.models.starcoder2.modeling_starcoder2 import ( -# QEffStarcoder2Attention, -# QEFFStarcoder2DecoderLayer, -# QEffStarcoder2ForCausalLM, -# QEffStarcoder2Model, -# ) -# from QEfficient.transformers.models.whisper.modeling_whisper import ( -# QEffWhisperAttention, -# QEffWhisperDecoder, -# QEffWhisperDecoderLayer, -# QEffWhisperEncoder, -# QEffWhisperForConditionalGeneration, -# QEffWhisperModel, -# QEffWhisperPositionalEmbedding, -# ) -from QEfficient.transformers.post_processing import build_and_attach_mlp, model_type_registry -from QEfficient.transformers.sampler.sampler import sampler_forward -from QEfficient.transformers.spd.spd_transform_forward import tlm_forward - -SPD_TARGET = "target" - - -class CustomOpsTransform(ModuleMappingTransform): - _module_mapping = { - # GemmaRMSNorm: GemmaCustomRMSNormAIC, - # Gemma2RMSNorm: GemmaCustomRMSNormAIC, - # LlamaRMSNorm: CustomRMSNormAIC, - # Llama4TextRMSNorm: CustomRMSNormAIC, - # MistralRMSNorm: CustomRMSNormAIC, - # MixtralRMSNorm: CustomRMSNormAIC, - # Phi3RMSNorm: CustomRMSNormAIC, - # Qwen2RMSNorm: CustomRMSNormAIC, - BlueprintRMSNorm: CustomRMSNormAIC, - # MllamaTextRMSNorm: CustomRMSNormAIC, - # GraniteRMSNorm: CustomRMSNormAIC, - # GraniteMoeRMSNorm: CustomRMSNormAIC, - # Gemma3RMSNorm: QEffGemma3CustomRMSNormAIC, - } - - -class KVCacheTransform(ModuleMappingTransform): - _module_mapping = { - # # CodeGen - # CodeGenAttention: QEffCodeGenAttention, - # CodeGenBlock: QeffCodeGenBlock, - # CodeGenModel: QEffCodeGenModel, - # CodeGenForCausalLM: QEffCodeGenForCausalLM, - # # Falcon - # FalconAttention: QEffFalconAttention, - # FalconDecoderLayer: QEffFalconDecoderLayer, - # FalconModel: QEffFalconModel, - # FalconForCausalLM: QEffFalconForCausalLM, - # # GPT2 - # GPT2Attention: QEffGPT2Attention, - # GPT2Block: QEffGPT2Block, - # GPT2Model: QEffGPT2Model, - # GPT2LMHeadModel: QEffGPT2LMHeadModel, - # # GPTJ - # GPTJAttention: QEffGPTJAttention, - # GPTJBlock: QEffGPTJBlock, - # GPTJModel: QEffGPTJModel, - # GPTJForCausalLM: QEffGPTJForCausalLM, - # # Llama - # LlamaAttention: QEffLlamaAttention, - # LlamaDecoderLayer: QEffLlamaDecoderLayer, - # LlamaModel: QEffLlamaModel, - # LlamaForCausalLM: QEffLlamaForCausalLM, - # # Llama4 - # Llama4TextAttention: QEffLlama4TextAttention, - # Llama4ForCausalLM: QEffLlama4ForCausalLM, - # Llama4TextDecoderLayer: QEffLlama4TextDecoderLayer, - # Llama4TextModel: QEffLlama4TextModel, - # Llama4TextMoe: QEffLlama4TextMoe, - # Llama4ForConditionalGeneration: QEffLlama4ForConditionalGeneration, - # Llama4VisionAttention: QEffLlama4VisionAttention, - # Llama4VisionModel: QEffLlama4VisionModel, - # Llama4TextExperts: QEffLlama4TextExperts, - # # Llava - # LlavaForConditionalGeneration: QEffLlavaForConditionalGeneration, - # # Llava Next - # LlavaNextForConditionalGeneration: QEffLlavaNextForConditionalGeneration, - # # Gemma - # GemmaAttention: QEffGemmaAttention, - # GemmaDecoderLayer: QEffGemmaDecoderLayer, - # GemmaModel: QEffGemmaModel, - # GemmaForCausalLM: QEffGemmaForCausalLM, - # # Gemma2 - # Gemma2Attention: QEffGemma2Attention, - # Gemma2DecoderLayer: QEffGemma2DecoderLayer, - # Gemma2Model: QEffGemma2Model, - # Gemma2ForCausalLM: QEffGemma2ForCausalLM, - # # Gemma3 - # Gemma3Attention: QEffGemma3Attention, - # Gemma3DecoderLayer: QEffGemma3DecoderLayer, - # Gemma3TextModel: QEffGemma3TextModel, - # Gemma3ForCausalLM: QEffGemma3ForCausalLMModel, - # Gemma3ForConditionalGeneration: QEffGemma3ForConditionalGeneration, - # # Granite - # GraniteModel: QEffGraniteModel, - # GraniteForCausalLM: QEffGraniteForCausalLM, - # GraniteAttention: QEffGraniteAttention, - # # GraniteMoe - # GraniteMoeModel: QEffGraniteMoeModel, - # GraniteMoeForCausalLM: QEffGraniteMoeForCausalLM, - # GraniteMoeAttention: QEffGraniteMoeAttention, - # GraniteMoeRotaryEmbedding: QEffGraniteMoeRotaryEmbedding, - # GraniteMoeParallelExperts: QEffGraniteMoeParallelExperts, - # GraniteMoeTopKGating: QEffGraniteMoeTopKGating, - # GraniteMoeMoE: QEffGraniteMoeMoE, - # # mllama - # MllamaTextRMSNorm: CustomRMSNormAIC, - # MllamaTextSelfAttention: QEffMllamaTextSelfAttention, - # MllamaSelfAttentionDecoderLayer: QEffMllamaSelfAttentionDecoderLayer, - # MllamaCrossAttentionDecoderLayer: QEffMllamaCrossAttentionDecoderLayer, - # MllamaRotaryEmbedding: QEffMllamaRotaryEmbedding, - # MllamaVisionModel: QEffMllamaVisionModel, - # MllamaTextModel: QEffMllamaTextModel, - # MllamaForCausalLM: QEffMllamaForCausalLM, - # MllamaForConditionalGeneration: QEffMllamaForConditionalGeneration, - # # Mistral - # MistralAttention: QEffMistralAttention, - # MistralDecoderLayer: QEffMistralDecoderLayer, - # MistralModel: QEffMistralModel, - # MistralForCausalLM: QEffMistralForCausalLM, - # # Mixtral - # MixtralAttention: QEffMixtralAttention, - # MixtralSparseMoeBlock: QEffMixtralSparseMoeBlock, - # MixtralDecoderLayer: QeffMixtralDecoderLayer, - # MixtralModel: QEffMixtralModel, - # MixtralForCausalLM: QEffMixtralForCausalLM, - # # Mpt - # MptAttention: QEffMptAttention, - # MptBlock: QEffMptBlock, - # MptModel: QEFfMptModel, - # MptForCausalLM: QEffMptForCausalLM, - # # Phi3 - # Phi3Attention: QEffPhi3Attention, - # Phi3DecoderLayer: QEffPhi3DecoderLayer, - # Phi3Model: QEffPhi3Model, - # Phi3ForCausalLM: QEffPhi3ForCausalLM, - # # Phi - # PhiAttention: QEffPhiAttention, - # PhiDecoderLayer: QEffPhiDecoderLayer, - # PhiModel: QEffPhiModel, - # PhiForCausalLM: QEffPhiForCausalLM, - # # Qwen2 - # Qwen2Attention: QEffQwen2Attention, - # Qwen2DecoderLayer: QEffQwen2DecoderLayer, - # Qwen2Model: QEffQwen2Model, - # Qwen2ForCausalLM: QEffQwen2ForCausalLM, - # Blueprint - BlueprintAttention: QEffBlueprintAttention, - BlueprintDecoderLayer: QEffBlueprintDecoderLayer, - BlueprintModel: QEffBlueprintModel, - BlueprintForCausalLM: QEffBlueprintForCausalLM, - # # Starcoder2 - # Starcoder2Attention: QEffStarcoder2Attention, - # Starcoder2DecoderLayer: QEFFStarcoder2DecoderLayer, - # Starcoder2Model: QEffStarcoder2Model, - # Starcoder2ForCausalLM: QEffStarcoder2ForCausalLM, - # # GptBigcode - # GPTBigCodeAttention: QEffGPTBigCodeAttention, - # GPTBigCodeBlock: QEffGPTBigCodeBlock, - # GPTBigCodeModel: QEffGPTBigCodeModel, - # GPTBigCodeForCausalLM: QEffGPTBigCodeForCausalLM, - # # Whisper encoder and decoder layers - # WhisperPositionalEmbedding: QEffWhisperPositionalEmbedding, - # WhisperAttention: QEffWhisperAttention, - # WhisperDecoderLayer: QEffWhisperDecoderLayer, - # WhisperEncoder: QEffWhisperEncoder, - # WhisperDecoder: QEffWhisperDecoder, - # WhisperModel: QEffWhisperModel, - # WhisperForConditionalGeneration: QEffWhisperForConditionalGeneration, - } - - @classmethod - def apply(cls, model: nn.Module) -> Tuple[nn.Module, bool]: - model, transformed = super().apply(model) - return model, transformed - - -class SpDTransform: - """ - Apply generic QEffForCausalLM forward pass to extract `num_speculative_tokens+1` hidden states before computing logits during decode phase and extract last predicted token during prefill. - This is only needed if user is exporting Target Language Model (TLM) for Speculative Decoding to validate output logits - against the speculated tokens from a smaller model. - Other than the computed logits, there should be no difference between the SpD Transformed model and its corresponding cunterpart. - - ``Mandatory`` Args: - :model (nn.Module): PyTorch model. - - Returns: - :model (nn.Module): PyTorch model. - :transformed (bool): whether transformation was applied successfully. - """ - - # supported architectures - _module_mapping = { - # Llama - # QEffLlamaForCausalLM, - # QEffQwen2ForCausalLM, - QEffBlueprintForCausalLM, - } - - @classmethod - def apply(cls, model: nn.Module, qaic_config: Optional[dict] = None, **kwargs) -> Tuple[nn.Module, bool]: - transformed = False - pretrained_model_name_or_path_temp = kwargs.pop("pretrained_model_name_or_path", None) - if qaic_config is None or (speculative_model_type := qaic_config.get("speculative_model_type")) is None: - return model, transformed - elif speculative_model_type not in ( - supported_spd_model_types := [SPD_TARGET] + list(model_type_registry.keys()) - ): - raise ValueError( - f"Specualtive model type {speculative_model_type} is not supported. we currently only support {supported_spd_model_types}" - ) - elif (model_class := model.__class__) in cls._module_mapping: - model.forward = MethodType(tlm_forward, model) - if speculative_model_type != SPD_TARGET: - # build and attach draft mlp - pretrained_model_name_or_path = qaic_config["pretrained_model_name_or_path"] - model = build_and_attach_mlp( - model, pretrained_model_name_or_path, speculative_model_type=speculative_model_type, **kwargs - ) - transformed = True - else: - raise NotImplementedError( - f"model class {model_class} does not yet support returning multiple logits to keep." - ) - kwargs["pretrained_model_name_or_path"] = pretrained_model_name_or_path_temp - return model, transformed - - -class SamplerTransform: - """ - Add nodes at the output of any generic QEffForCausalLM model to enable the - sampling of next tokens at the device (instead of the host) and return the - next tokens and/or probability distributions. - - Note: To achieve this, the generic QEffForCausalLM model must provide the - logits as output. - - ``Mandatory`` Args: - :model (nn.Module): PyTorch model. - - Returns: - :model (nn.Module): PyTorch model. - :transformed (bool): whether transformation was applied successfully. - """ - - # supported architectures - _module_mapping = { - # Llama - # QEffLlamaForCausalLM, - } - - @classmethod - def apply(cls, model: nn.Module, qaic_config: Optional[dict] = None, **kwargs) -> Tuple[nn.Module, bool]: - transformed = False - if qaic_config is None or not qaic_config.get("include_sampler", False): - return model, transformed - elif (model_class := model.__class__) in cls._module_mapping: - model.old_forward = model.forward - model.forward = MethodType(sampler_forward, model) - transformed = True - else: - raise NotImplementedError(f"Model class {model_class} does not support on device sampling.") - return model, transformed - - -class VlmKVOffloadTransform(ModuleMappingTransform): - # supported architectures - _module_mapping = { - # # Llama - # MllamaTextCrossAttention: QEffMllamaTextCrossAttentionTwoQPC, - } - - -class VlmNoKVOffloadTransform(ModuleMappingTransform): - # supported architectures - _module_mapping = { - # # Llama - # MllamaTextCrossAttention: QEffMllamaTextCrossAttentionSingleQPC, - } - - -class KVCacheExternalModuleMapperTransform(ExternalModuleMapperTransform): - _match_string_replace_method = { - # "InternVLChatModel": { - # "forward": QEffInternVLModel.forward, - # "get_blueprint_inputs": QEffInternVLModel.get_blueprint_inputs, - # "get_specializations": QEffInternVLModel.get_specializations, - # "get_onnx_dynamic_axes": QEffInternVLModel.get_onnx_dynamic_axes, - # "get_output_names": QEffInternVLModel.get_output_names, - # "get_inputs_info": QEffInternVLModel.get_inputs_info, - # "get_qeff_vision_encoder": QEffInternVLModel.get_qeff_vision_encoder, - # "get_qeff_language_decoder": QEffInternVLModel.get_qeff_language_decoder, - # }, - # "InternVisionEmbeddings": {"forward": QEffInternVisionEmbeddings.forward}, - # # Mapping for grok1 model - # "Grok1ModelForCausalLM": {"forward": QEffGrok1ModelForCausalLM.forward}, - # "Grok1Model": { - # "forward": QEffGrok1Model.forward, - # "__qeff_init__": QEffGrok1Model.__qeff_init__, - # }, - # "DecoderLayer": { - # "forward": QEffGrok1DecoderLayer.forward, - # "__qeff_init__": QEffGrok1DecoderLayer.__qeff_init__, - # }, - # "MoeBlock": {"forward": QEffGrok1MoeBlock.forward}, - # "MultiHeadAttention": { - # "forward": QEffGrok1MultiHeadAttention.forward, - # }, - # "RMSNorm": { - # "forward": QEFFGrok1CustomRMSNormAIC.forward, - # }, - } - - _match_class_replace_method = {} - - -class PoolingTransform: - """ - Apply a pooling transformation to the model. This transformation appends a pooling layer to the model, allowing for the reduction of spatial dimensions in the output. - The pooling layer can be configured to use different pooling methods, such as max pooling or average pooling. - """ - - @classmethod - def apply(cls, model: nn.Module, pooling: Union[str, Callable]) -> Tuple[nn.Module, bool]: - transformed = False - pooling_method = ( - POOLING_MAP[pooling] - if isinstance(pooling, str) and pooling in POOLING_MAP - else validate_user_pooling_function(pooling) - ) - model = PooledModel(model, pooling_method) - warnings.warn("Pooling is applied to the model.") - return model, transformed diff --git a/examples/onboarding_guide/causallm/Onboarding.png b/examples/onboarding_guide/causallm/Onboarding.png new file mode 100644 index 0000000000000000000000000000000000000000..8c83b0ac006e90f18f66f3e1282db782048c32ce GIT binary patch literal 231305 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%0An&YkC15OKz+TsI3f5?{Y^rX^Qq|5kpQT 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

*JT*5x3*2)NO}IFKX{6-y#>blAknww+r3d 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

(0}Yh- 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%0AKW=0Bw>2JsHFUz&0Yg4HrZW>CcPF*vgjk| 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 e`UEFSTNA54>DxYRfWr~Dt1_|EPC literal 0 HcmV?d00001 diff --git a/examples/onboarding_guide/causallm/README.md b/examples/onboarding_guide/causallm/README.md new file mode 100644 index 000000000..5a000eade --- /dev/null +++ b/examples/onboarding_guide/causallm/README.md @@ -0,0 +1,196 @@ +# Onboarding a CausalLM Model + +## Prerequisites + +Install `qefficient-transformers` library in editable mode: +```sh +git clone https://github.com/quic/efficient-transformers.git +cd efficient-transformers +pip install -e . +``` + +## Introduction + +This guide walks you through onboarding a new CausalLM model to QEfficient-transformers. We use an example model named `Blueprint` to demonstrate the required changes. + +--- + +## Onboarding Process + +![Onboarding Flowchart](./Onboarding.png) + +--- + +## Step 1: Check Transformers Library + +1. **Locate the model** in the transformers library: + - Path: `/src/transformers/models//modeling_.py` + - Example: `/src/transformers/models/blueprint/modeling_blueprint.py` + +2. **Identify required classes**: + - Attention Layer + - Decoder Layer + - Model (main class) + - ForCausalLM (top-level) + - RMSNorm/LayerNorm + - RotaryEmbedding (if applicable) + +3. **Check existing implementations** in `QEfficient/transformers/models/`: + - If similar classes exist → Reuse patterns + - If not → Create custom implementations + +--- + +## Step 2: Create Custom Files & Mappings + +### 2.1 Create Custom Modeling File + +Create directory structure: +``` +QEfficient/transformers/models/blueprint/ +├── __init__.py +└── modeling_blueprint.py +``` + +**Key modifications in `modeling_blueprint.py`:** +- `QEffBlueprintRotaryEmbedding`: Precompute sin/cos for rotary embeddings +- `QEffBlueprintAttention`: Use `position_ids`, return `past_key_value`, implement `__qeff_init__` +- `QEffBlueprintDecoderLayer`: Return `past_key_value` from forward pass +- `QEffBlueprintModel`: Use `QEffDynamicCache` instead of standard cache +- `QEffBlueprintForCausalLM`: Entry point with additional parameters + +See `modeling_example.py` for detailed implementation examples. + +### 2.2 Add Mappings in pytorch_transforms.py + +**CustomOpsTransform** (RMSNorm mapping): +```python +class CustomOpsTransform(ModuleMappingTransform): + _module_mapping = { + BlueprintRMSNorm: CustomRMSNormAIC, + } +``` + +**KVCacheTransform** (all model classes): +```python +class KVCacheTransform(ModuleMappingTransform): + _module_mapping = { + BlueprintAttention: QEffBlueprintAttention, + BlueprintDecoderLayer: QEffBlueprintDecoderLayer, + BlueprintModel: QEffBlueprintModel, + BlueprintForCausalLM: QEffBlueprintForCausalLM, + } +``` + +See `example_pytorch_transforms.py` for complete example. + +--- + +## Step 3: Testing (4-Stage Pipeline) + +Your implementation is validated through four stages: + +| Stage | Description | Validation | +|-------|-------------|------------| +| **1. PyTorch HF** | Original transformers model | Baseline tokens | +| **2. PyTorch KV** | After QEff transforms | Tokens match Stage 1 | +| **3. ONNX/ORT** | After export to ONNX | Tokens match Stage 2 | +| **4. Cloud AI 100** | Hardware execution | Tokens match Stage 3 | + +**Test function:** `check_causal_lm_pytorch_vs_kv_vs_ort_vs_ai100` in `tests/transformers/models/test_causal_lm_models.py` + +### Common Issues + +**Token mismatch (Stage 1→2):** +- Check all classes are mapped in `KVCacheTransform` +- Verify `__qeff_init__` methods exist +- Ensure `position_ids` are correctly passed + +**ONNX export failure (Stage 2→3):** +- Check for unsupported PyTorch operations +- Verify dynamic shapes are defined + +**Compilation failure (Stage 3→4):** +- Reduce `num_cores` or model size +- Check device availability: `get_available_device_id()` + +--- + +## Step 4: Add to Test Suite + +Edit `tests/transformers/models/test_causal_lm_models.py`: + +```python +test_models_causal = [ + "TinyLlama/TinyLlama-1.1B-Chat-v1.0", + "gpt2", + # ... existing models ... + "YourOrg/YourModel-7B", # Add your model here +] +``` + +**Run tests:** +```bash +# Test your specific model +pytest tests/transformers/models/test_causal_lm_models.py::test_custom_causal_lm_pytorch_vs_kv_vs_ort_vs_ai100 -k "YourModel" -v + +# Run all regular tests +pytest tests/transformers/models/test_causal_lm_models.py -m regular +``` + +--- + +## Step 5: Validation Checklist + +Before submitting PR: + +**Implementation:** +- [ ] Created `QEfficient/transformers/models//` directory +- [ ] Implemented all required custom classes +- [ ] Added mappings in `CustomOpsTransform` and `KVCacheTransform` +- [ ] Added imports at top of `pytorch_transforms.py` + +**Testing:** +- [ ] Model added to `test_models_causal` list +- [ ] All 4 stages pass (PyTorch HF → KV → ORT → AI 100) +- [ ] Continuous batching tests pass +- [ ] `qconfig.json` generated successfully + +**Code Quality:** +- [ ] Code follows project style guidelines +- [ ] Commits use DCO sign-off (`git commit -s`) +- [ ] Branch created from `main` + +--- + +## Step 6: Submit Pull Request + +Follow guidelines in [CONTRIBUTING.md](../../../CONTRIBUTING.md): + +1. Create feature branch: `git checkout -b add-yourmodel-support main` +2. Commit with DCO: `git commit -s -m "Add support for YourModel"` +3. Push and create PR targeting `main` branch +4. Include test results in PR description + +--- + +## Troubleshooting Quick Reference + +| Issue | Solution | +|-------|----------| +| Token mismatch between stages | Check class mappings, verify `position_ids` handling | +| Shape errors | Verify KV cache dimensions, check `past_key_value` returns | +| ONNX export fails | Replace unsupported ops, define dynamic shapes | +| Compilation fails | Reduce `num_cores`, check device availability | +| Runtime errors | Verify input shapes match specializations | + +**Debug tip:** Start with `n_layer=1` and short prompts, then gradually increase complexity. + +--- + +## References + +- [Hugging Face Transformers](https://github.com/huggingface/transformers) +- [QEfficient Transformers](https://github.com/quic/efficient-transformers) +- [Contributing Guidelines](../../../CONTRIBUTING.md) +- [Test Suite](../../../tests/transformers/models/test_causal_lm_models.py) diff --git a/examples/onboarding_guide/causallm/example_pytorch_transforms.py b/examples/onboarding_guide/causallm/example_pytorch_transforms.py new file mode 100644 index 000000000..ff62588f9 --- /dev/null +++ b/examples/onboarding_guide/causallm/example_pytorch_transforms.py @@ -0,0 +1,291 @@ +# ----------------------------------------------------------------------------- +# +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +# SPDX-License-Identifier: BSD-3-Clause +# +# ----------------------------------------------------------------------------- + +""" +Example pytorch_transforms.py showing common model onboarding patterns. + +This file demonstrates three representative patterns: +1. Blueprint - Standard decoder-only model (example for onboarding) +2. Llama - Most common architecture pattern +3. Mixtral - Mixture of Experts (MoE) model + +For more examples and patterns, see: +- Production transforms: QEfficient/base/pytorch_transforms.py +- All model implementations: QEfficient/transformers/models/ +- Specific patterns: + * Gemma (custom RMSNorm): QEfficient/transformers/models/gemma/ + * Multimodal (Llama4, Mllama): QEfficient/transformers/models/llama4/ + * External models (Grok): QEfficient/transformers/models/grok_1/ + * Vision-Language models: QEfficient/transformers/models/mllama/ +""" + +import warnings +from types import MethodType +from typing import Callable, Optional, Tuple, Union + +from QEfficient.transformers.models.blueprint.modeling_blueprint import ( + QEffBlueprintAttention, + QEffBlueprintDecoderLayer, + QEffBlueprintForCausalLM, + QEffBlueprintModel, +) +from torch import nn + +# Example imports for three representative models +from transformers.models.blueprint.modeling_blueprint import ( + BlueprintAttention, + BlueprintDecoderLayer, + BlueprintForCausalLM, + BlueprintModel, + BlueprintRMSNorm, +) +from transformers.models.llama.modeling_llama import ( + LlamaAttention, + LlamaDecoderLayer, + LlamaForCausalLM, + LlamaModel, + LlamaRMSNorm, +) +from transformers.models.mixtral.modeling_mixtral import ( + MixtralAttention, + MixtralDecoderLayer, + MixtralForCausalLM, + MixtralModel, + MixtralRMSNorm, + MixtralSparseMoeBlock, +) + +from QEfficient.base.pytorch_transforms import ExternalModuleMapperTransform, ModuleMappingTransform +from QEfficient.customop import CustomRMSNormAIC +from QEfficient.transformers.embeddings.embedding_utils import POOLING_MAP, PooledModel, validate_user_pooling_function +from QEfficient.transformers.models.llama.modeling_llama import ( + QEffLlamaAttention, + QEffLlamaDecoderLayer, + QEffLlamaForCausalLM, + QEffLlamaModel, +) +from QEfficient.transformers.models.mixtral_moe.modeling_mixtral import ( + QEffMixtralAttention, + QeffMixtralDecoderLayer, + QEffMixtralForCausalLM, + QEffMixtralModel, + QEffMixtralSparseMoeBlock, +) +from QEfficient.transformers.post_processing import build_and_attach_mlp, model_type_registry +from QEfficient.transformers.sampler.sampler import sampler_forward +from QEfficient.transformers.spd.spd_transform_forward import tlm_forward + +SPD_TARGET = "target" + + +class CustomOpsTransform(ModuleMappingTransform): + """ + Maps RMSNorm classes to custom implementations optimized for Cloud AI 100. + + Most models use the standard CustomRMSNormAIC. For special cases (like Gemma), + you can create custom RMSNorm in QEfficient.customop. + """ + + _module_mapping = { + # Blueprint - Example model for onboarding + BlueprintRMSNorm: CustomRMSNormAIC, + # Llama - Most common pattern + LlamaRMSNorm: CustomRMSNormAIC, + # Mixtral - MoE model pattern + MixtralRMSNorm: CustomRMSNormAIC, + # TODO: Add your model's RMSNorm mapping here: + # YourModelRMSNorm: CustomRMSNormAIC, + } + + +class KVCacheTransform(ModuleMappingTransform): + """ + Maps model classes to their QEfficient counterparts with KV cache support. + + This is the most critical transform for enabling efficient inference. + All model classes (Attention, DecoderLayer, Model, ForCausalLM) must be mapped. + """ + + _module_mapping = { + # Blueprint - Example model for onboarding + BlueprintAttention: QEffBlueprintAttention, + BlueprintDecoderLayer: QEffBlueprintDecoderLayer, + BlueprintModel: QEffBlueprintModel, + BlueprintForCausalLM: QEffBlueprintForCausalLM, + # Llama - Most common pattern (standard decoder-only) + LlamaAttention: QEffLlamaAttention, + LlamaDecoderLayer: QEffLlamaDecoderLayer, + LlamaModel: QEffLlamaModel, + LlamaForCausalLM: QEffLlamaForCausalLM, + # Mixtral - MoE model pattern (includes SparseMoeBlock) + MixtralAttention: QEffMixtralAttention, + MixtralSparseMoeBlock: QEffMixtralSparseMoeBlock, + MixtralDecoderLayer: QeffMixtralDecoderLayer, + MixtralModel: QEffMixtralModel, + MixtralForCausalLM: QEffMixtralForCausalLM, + # TODO: Add your model's class mappings here: + # YourModelAttention: QEffYourModelAttention, + # YourModelDecoderLayer: QEffYourModelDecoderLayer, + # YourModelModel: QEffYourModelModel, + # YourModelForCausalLM: QEffYourModelForCausalLM, + } + + @classmethod + def apply(cls, model: nn.Module) -> Tuple[nn.Module, bool]: + model, transformed = super().apply(model) + return model, transformed + + +class SpDTransform: + """ + Apply generic QEffForCausalLM forward pass to extract `num_speculative_tokens+1` hidden states before computing logits during decode phase and extract last predicted token during prefill. + This is only needed if user is exporting Target Language Model (TLM) for Speculative Decoding to validate output logits + against the speculated tokens from a smaller model. + Other than the computed logits, there should be no difference between the SpD Transformed model and its corresponding cunterpart. + + ``Mandatory`` Args: + :model (nn.Module): PyTorch model. + + Returns: + :model (nn.Module): PyTorch model. + :transformed (bool): whether transformation was applied successfully. + """ + + # supported architectures + _module_mapping = { + QEffBlueprintForCausalLM, + # TODO: Add your model's ForCausalLM class here if using Speculative Decoding: + # QEffYourModelForCausalLM, + } + + @classmethod + def apply(cls, model: nn.Module, qaic_config: Optional[dict] = None, **kwargs) -> Tuple[nn.Module, bool]: + transformed = False + pretrained_model_name_or_path_temp = kwargs.pop("pretrained_model_name_or_path", None) + + if qaic_config is None or (speculative_model_type := qaic_config.get("speculative_model_type")) is None: + return model, transformed + + if speculative_model_type not in (supported_spd_model_types := [SPD_TARGET] + list(model_type_registry.keys())): + raise ValueError( + f"Speculative model type {speculative_model_type} is not supported. " + f"Currently only support {supported_spd_model_types}" + ) + + if (model_class := model.__class__) in cls._module_mapping: + model.forward = MethodType(tlm_forward, model) + if speculative_model_type != SPD_TARGET: + pretrained_model_name_or_path = qaic_config["pretrained_model_name_or_path"] + model = build_and_attach_mlp( + model, pretrained_model_name_or_path, speculative_model_type=speculative_model_type, **kwargs + ) + transformed = True + else: + raise NotImplementedError( + f"Model class {model_class} does not yet support returning multiple logits to keep." + ) + + kwargs["pretrained_model_name_or_path"] = pretrained_model_name_or_path_temp + return model, transformed + + +class SamplerTransform: + """ + Add nodes at the output of any generic QEffForCausalLM model to enable the + sampling of next tokens at the device (instead of the host) and return the + next tokens and/or probability distributions. + + Note: To achieve this, the generic QEffForCausalLM model must provide the + logits as output. + + ``Mandatory`` Args: + :model (nn.Module): PyTorch model. + + Returns: + :model (nn.Module): PyTorch model. + :transformed (bool): whether transformation was applied successfully. + """ + + # supported architectures + _module_mapping = { + # TODO: Add your model's ForCausalLM class here if using on-device sampling: + # QEffYourModelForCausalLM, + } + + @classmethod + def apply(cls, model: nn.Module, qaic_config: Optional[dict] = None, **kwargs) -> Tuple[nn.Module, bool]: + transformed = False + if qaic_config is None or not qaic_config.get("include_sampler", False): + return model, transformed + + if (model_class := model.__class__) in cls._module_mapping: + model.old_forward = model.forward + model.forward = MethodType(sampler_forward, model) + transformed = True + else: + raise NotImplementedError(f"Model class {model_class} does not support on device sampling.") + + return model, transformed + + +class VlmKVOffloadTransform(ModuleMappingTransform): + """ + Vision-Language Model transform with KV offloading (two QPC setup). + + Used for multimodal models where vision and text processing are separated. + See QEfficient/transformers/models/mllama/ for implementation examples. + """ + + _module_mapping = { + # TODO: Add VLM models with KV offloading here: + # YourVLMTextCrossAttention: QEffYourVLMTextCrossAttentionTwoQPC, + } + + +class VlmNoKVOffloadTransform(ModuleMappingTransform): + """ + Vision-Language Model transform without KV offloading (single QPC setup). + + Used for multimodal models in single QPC configuration. + See QEfficient/transformers/models/mllama/ for implementation examples. + """ + + _module_mapping = { + # TODO: Add VLM models without KV offloading here: + # YourVLMTextCrossAttention: QEffYourVLMTextCrossAttentionSingleQPC, + } + + +class KVCacheExternalModuleMapperTransform(ExternalModuleMapperTransform): + _match_string_replace_method = { + # TODO: Add external model mappings here (for models not in transformers library): + # "YourExternalModelClass": { + # "forward": QEffYourExternalModel.forward, + # "__qeff_init__": QEffYourExternalModel.__qeff_init__, + # }, + } + + _match_class_replace_method = {} + + +class PoolingTransform: + """ + Apply a pooling transformation to the model. This transformation appends a pooling layer to the model, allowing for the reduction of spatial dimensions in the output. + The pooling layer can be configured to use different pooling methods, such as max pooling or average pooling. + """ + + @classmethod + def apply(cls, model: nn.Module, pooling: Union[str, Callable]) -> Tuple[nn.Module, bool]: + transformed = False + pooling_method = ( + POOLING_MAP[pooling] + if isinstance(pooling, str) and pooling in POOLING_MAP + else validate_user_pooling_function(pooling) + ) + model = PooledModel(model, pooling_method) + warnings.warn("Pooling is applied to the model.") + return model, transformed diff --git a/examples/dummy_onboarding/causallm/modeling_dummy.py b/examples/onboarding_guide/causallm/modeling_example.py similarity index 100% rename from examples/dummy_onboarding/causallm/modeling_dummy.py rename to examples/onboarding_guide/causallm/modeling_example.py