Flash Attention enables efficient handling of long contexts in models like Llama3.1-8B by reducing memory usage and improving throughput. This tutorial shows how to serve Llama3.1-8B with Flash Attention using RBLN vLLM and NVIDIA Triton Inference Server.
You can check out the actual commands required to compile the model and initialize triton vllm_backend on the model zoo.
Note
This tutorial assumes that you are familiar with compiling and running inference using the RBLN SDK. If you are not familiar with RBLN SDK, refer to RBLN Optimum tutorials and the API Documentation.
importosfromoptimum.rblnimportRBLNLlamaForCausalLMmodel_id="meta-llama/Llama-3.1-8B-Instruct"# Compile and exportmodel=RBLNLlamaForCausalLM.from_pretrained(model_id=model_id,export=True,# Export a PyTorch model to RBLN model with Optimumrbln_batch_size=1,# Batch sizerbln_max_seq_len=131_072,# Maximum sequence lengthrbln_num_devices=1,# Number of NPUsrbln_kvcache_partition_len=8_192,# Length of KV cache partitions for flash attention)# Save compiled results to diskmodel.save_pretrained(os.path.basename(model_id))
Note
Choose an appropriate batch size for your serving needs. Here, it is set to 1.
importosfromoptimum.rblnimportRBLNLlamaForCausalLMmodel_id="meta-llama/Llama-3.1-8B-Instruct"# Compile and exportmodel=RBLNLlamaForCausalLM.from_pretrained(model_id=model_id,export=True,# Export a PyTorch model to RBLN model with Optimumrbln_batch_size=1,# Batch sizerbln_max_seq_len=131_072,# Maximum sequence lengthrbln_num_devices=8,# Number of NPUsrbln_kvcache_partition_len=16_384,# Length of KV cache partitions for flash attention)# Save compiled results to diskmodel.save_pretrained(os.path.basename(model_id))
Note
Choose an appropriate batch size for your serving needs. Here, it is set to 1. The Llama3.1-8B model requires 8 RBLN NPUs, and you can find the recommended number of NPUs for each model in RBLN Optimum Multi-NPUs Supported Models.
+-- vllm_backend/ # Main directory for Triton vLLM backend
| +-- samples/ # Application example directory
| | +-- model_repository/ # Triton model repository (model_repositories)
| | | +-- vllm_model/ # Individual model for Triton serving
| | | | +-- config.pbtxt # Triton model configuration file
| | | | +-- 1/ # Version directory
| | | | | +-- model.json # Model configuration for vLLM serving
| | | | | +-- Llama-3.1-8B-Instruct/ # rbln compiled model files
| | | | | | +-- decoder.rbln
| | | | | | +-- prefill.rbln
| | | | | | +-- config.json
| | | | | | +-- (other model files)
| | +-- (other example files)
| +-- (other backend files)
Note
The vLLM backend for NVIDIA Triton Server doesn't need a model.py file unlike other vision model backends. All model processing logic is pre-included in the Docker container at backends/vllm/model.py, so you only need model.json for configuration.
You can either use the default config.pbtxt from the repository or create a new one using the template below. Note that input and output formats must match exactly as shown, since they're required by the vLLM backend (see Step 4: gRPC Client Inference Request).
The vLLM backend of the Triton inference server defines its own model.py, which is different from the model.py defined in the Resnet50 tutorial in terms of input/output signature. The input parameter was called INPUT__0 and the output was called OUTPUT__0. But the input parameter of vLLM has the name text_input and the output is called text_output. The client should be modified accordingly. Refer to vLLM model.py for more details.
The following shows the client code for vLLM backend. This client also requires tritonclient and grpcio packages.
Note
You need to appropriately apply a chat template for proper functioning. The chat template must be formatted with system, user, and assistant roles. Additionally, you must configure the sampling parameters like this:
importasyncioimportjsonimportnumpyasnpimporttritonclient.grpc.aioasgrpcclient# Define a simple chat message classclassChatMessage:def__init__(self,role,content):self.role=roleself.content=content# Apply a simple chat template to the messagesdefapply_chat_template(messages):lines=[]system_msg=ChatMessage(role="system",content="You are a helpful assistant.")formsgin[system_msg,*messages,ChatMessage(role="assistant",content="")]:lines.append(f"[{msg.role.capitalize()}]\n{msg.content}")return"\n".join(lines)asyncdeftry_request():url=("<host and port number of the triton inference server>"# e.g. "localhost:8001")client=grpcclient.InferenceServerClient(url=url,verbose=False)model_name="vllm_model"defcreate_request(messages,request_id):prompt=apply_chat_template(messages)print(f"prompt:\n{prompt}\n---")# print promptinput=grpcclient.InferInput("text_input",[1],"BYTES")prompt_data=np.array([prompt.encode("utf-8")])input.set_data_from_numpy(prompt_data)stream_setting=grpcclient.InferInput("stream",[1],"BOOL")stream_setting.set_data_from_numpy(np.array([True]))sampling_params={"temperature":0.0,"stop":["[User]","[System]","[Assistant]"],# add stop tokens}sampling_parameters=grpcclient.InferInput("sampling_parameters",[1],"BYTES")sampling_parameters.set_data_from_numpy(np.array([json.dumps(sampling_params).encode("utf-8")],dtype=object))inputs=[input,stream_setting,sampling_parameters]output=grpcclient.InferRequestedOutput("text_output")outputs=[output]return{"model_name":model_name,"inputs":inputs,"outputs":outputs,"request_id":request_id,}messages=[ChatMessage(role="user",content="What is the first letter of English alphabets?")]request_id="req-0"asyncdefrequests_gen():yieldcreate_request(messages,request_id)response_stream=client.stream_infer(requests_gen())prompt=apply_chat_template(messages)is_first_response=Trueasyncforresponseinresponse_stream:result,error=responseiferror:print("Error occurred!")else:output=result.as_numpy("text_output")foriinoutput:decoded=i.decode("utf-8")ifis_first_response:ifdecoded.startswith(prompt):decoded=decoded[len(prompt):]is_first_response=Falseprint(decoded,end="",flush=True)print("\n")# end of streamasyncio.run(try_request())
If the request works properly, the output is similar to the following.